--- /dev/null
+VERSION=4.1.36
+
+SHELL = /bin/sh
+
+# This variable makes it possible to move the installation root to another
+# directory. This is useful when you're creating a binary distribution of mc.
+# If empty, normal root will be used.
+# You can run e.g. 'make install DESTDIR=/packages/mc/3.0' to accomplish
+# that.
+# DESTDIR = /opt/apps/mc/$(VERSION)
+
+# Installation target directories & other installation stuff
+prefix = /usr/local
+exec_prefix = $(prefix)
+binprefix =
+manprefix =
+
+builddir = /cygdrive/c/user/src/local/mc-4.1.36-mingw
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib/mc
+suppbindir = $(libdir)/bin
+tidir = $(libdir)/term
+extfsdir = $(libdir)/extfs
+icondir = $(prefix)/share/icons/mc
+mandir = $(prefix)/man/man1
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+manext = 1
+man8dir = $(prefix)/man/man8
+man8ext = 8
+xv_bindir =
+
+# Tools & program stuff
+SEDCMD = sed 's/-man/-mandoc/'
+SEDCMD2 = sed 's%@prefix@%$(prefix)%'
+STRIP = @STRIP@
+
+CC = gcc
+CPP = gcc -E
+AR = /usr/bin/ar
+RANLIB = ranlib
+RM = /usr/bin/rm
+RMF = /usr/bin/rm -f
+MV = /usr/bin/mv
+CP = /usr/bin/cp
+LN_S = ln -s
+AWK = gawk
+AWK_VAR_OPTION = -v
+
+# Flags & libs
+# No way, to make make happy (except GNU), we cannot use := to append
+# something to these, so that's why there is a leading _
+XCFLAGS = -g
+XCPPFLAGS = -I.. -I$(vfsdir) -I$(rootdir) -I$(slangdir) -I.. -DBINDIR=\""$(bindir)/"\" -DLIBDIR=\""$(libdir)/"\" -DICONDIR=\""$(icondir)/"\" $(XINC) -DLOCALEDIR=\""$(localedir)/"\"
+XLDFLAGS =
+XDEFS = -DHAVE_CONFIG_H
+XLIBS = -lintl -lcrypt
+
+# Where do we have the sources?
+# You shouldn't have to edit this :)
+mcsrcdir = $(rootdir)/src
+docdir = $(rootdir)/doc
+mclibdir = $(rootdir)/lib
+slangdir = $(rootdir)/slang
+vfsdir = $(rootdir)/vfs
+xvdir = $(rootdir)/xv
+tkdir = $(rootdir)/tk
+gnomedir = $(rootdir)/gnome
+icodir = $(rootdir)/icons
+
+hpath = -I$(mcsrcdir) -I$(slangdir) -I$(vfsdir) -I$(xvdir) -I$(xvdir)/support/xview_private -I$(tkdir)
+
+# Rules
+first_rule: all
+
+.PHONY: all check cross TAGS clean install uninstall distcopy depend dep
+.PHONY: fastdep fastdepslang fastdepvfs fastdeploc slowdep
+
+../slang/%.o : ../slang/%.c
+ cd ../slang; $(MAKE) libmcslang.a
+
+../vfs/%.o : ../vfs/%.c
+ cd ../vfs; $(MAKE) libvfs.a
+
+fastdep: dummy
+ if test x"`echo $(srcdir)/*.[ch]`" != x'$(srcdir)/*.[ch]'; then { cd $(srcdir); $(AWK) -f $(mcsrcdir)/depend.awk $(AWK_VAR_OPTION) hpath="$(hpath)" $(AWK_VAR_OPTION) srcdir="$(srcdir)" *.[ch];} > .depend; fi
+ -$(MAKE) fastdeploc
+ :
+
+fastdepslang:
+ { { { cd ../slang; $(MAKE) showlibdep;} | grep OBJS; cat .depend;} | { cd $(slangdir); $(AWK) -f $(mcsrcdir)/depend.awk $(AWK_VAR_OPTION) dolib="../slang libmcslang.a" $(AWK_VAR_OPTION) hpath="$(hpath)" $(AWK_VAR_OPTION) srcdir="$(slangdir)";};} >> .depend
+
+fastdepvfs:
+ { { { cd ../vfs; $(MAKE) showlibdep;} | grep OBJS; cat .depend;} | { cd $(vfsdir); $(AWK) -f $(mcsrcdir)/depend.awk $(AWK_VAR_OPTION) dolib="../vfs libvfs.a" $(AWK_VAR_OPTION) hpath="$(hpath)" $(AWK_VAR_OPTION) srcdir="$(vfsdir)";};} >> .depend
+
+slowdep: dummy
+ if test x"`echo $(srcdir)/*.[ch]`" != x'$(srcdir)/*.[ch]'; then \
+ $(CPP) -M $(CPPFLAGS) $(DEFS) $(CFLAGS) $(srcdir)/*.c > .depend; fi
+ :
+
+mcdep: fastdep
+
+dummy:
+
+# End of Make.common
--- /dev/null
+TARGET_OS=NT
+
+CC=gcc
+LINK=gcc -s
+OBJ_SUFFIX=o
+OBJ_PLACE=-o
+EXE_PLACE=-o
+
+# ---- Compiler-specific optional stuff
+MC_MISC_CFLAGS=
+OBJS_DIR=release
+EXTRA_MC_SRCS=
+SPECIFIC_DEFINES=
+SPECIFIC_MC_CFLAGS=-O2 $(MC_MISC_CFLAGS)
+SPECIFIC_MC_LFLAGS_EXTRA=
+SPECIFIC_SLANG_CFLAGS=$(SPECIFIC_MC_CFLAGS)
+SPECIFIC_MCEDIT_CFLAGS=$(SPECIFIC_MC_CFLAGS)
+
+# ---- Compiler independent defines
+include Makefile.PC
+
+# ---- Linkers are very compiler-specific
+
+SPECIFIC_MC_LFLAGS=$(SPECIFIC_MC_LFLAGS_EXTRA)
+MC_LIBS= # -lintl
+
+$(MC_EXE): $(OBJS) $(MCEDIT_OBJS) $(SLANG_OBJS)
+ $(LINK) $(EXE_PLACE) $(MC_EXE) $(SPECIFIC_MC_LFLAGS) $+ $(MC_LIBS)
--- /dev/null
+# Makefile.PC
+#
+# This is the Makefile for Midnight Commander under OS/2 and Windows NT
+#
+# Written by Dan Nicolaescu
+# 970423 hacked by Juan f. Grigera
+# 970525 hacked again by jfg to add internal editor
+# 971127 hacked by Pavel Roskin to make it work with mc-4.1.11
+# 980206 hacked by Pavel Roskin to make it work with GNU make
+# 980329 changed by Pavel Roskin to make it common for OS/2 and NT
+#
+# Supported Compilers:
+#
+# For Windows NT:
+# Makefile.VC4: Microsoft Visual C++ 4.0 and above
+# Makefile.BC5: Borland C++ 5.x
+# Makefile.MIN: MinGW
+# Makefile.RSX: RSX
+# For OS/2:
+# Makefile.EMX: EMX/GCC
+# Makefile.BC2: Borland C++ 2.x
+# Makefile.IBM: IBM CSet or Visual Age C++
+# ...
+
+# ---- Directories
+MC_PC_DIR=./pc
+MC_SRC_DIR=./src
+VFS_DIR=./vfs
+MCEDIT_SRC_DIR=./edit
+MCEDIT_OBJS_DIR=$(OBJS_DIR)/edit
+SLANG_SRC_DIR=./slang
+SLANG_OBJS_DIR=$(OBJS_DIR)/slang
+MC_EXE=$(OBJS_DIR)/mc.exe
+
+# --- Midnight Defines
+COMMON_DEFINES=-DMC_$(TARGET_OS) $(SPECIFIC_DEFINES)
+MC_DEFINES=$(COMMON_DEFINES) -DHAVE_CONFIG_H
+MC_INCLUDES=-I$(MC_PC_DIR) -I$(SLANG_SRC_DIR)
+SLANG_DEFINES=$(COMMON_DEFINES)
+SLANG_INCLUDES=-I$(MC_PC_DIR) -I$(SLANG_SRC_DIR)
+MCEDIT_DEFINES=$(COMMON_DEFINES) -DHAVE_CONFIG_H
+MCEDIT_INCLUDES=-I$(MC_PC_DIR) -I$(SLANG_SRC_DIR)
+
+CFLAGS=$(SPECIFIC_MC_CFLAGS) $(MC_INCLUDES) $(MC_DEFINES) -c
+SLANG_CFLAGS=$(SPECIFIC_SLANG_CFLAGS) $(SLANG_INCLUDES) $(SLANG_DEFINES) -c
+MCEDIT_CFLAGS=$(SPECIFIC_MCEDIT_CFLAGS) $(MCEDIT_INCLUDES) $(MCEDIT_DEFINES) -c
+
+
+all: object-dirs mc
+object-dirs: $(OBJS_DIR) $(SLANG_OBJS_DIR) $(MCEDIT_OBJS_DIR)
+
+mc: $(MC_EXE)
+
+clean:
+ "../../reactos/tools/rdel" "slang/*.o"
+ "../../reactos/tools/rdel" "edit/*.o"
+ "../../reactos/tools/rdel" "src/*.o"
+ "../../reactos/tools/rdel" "pc/*.o"
+ "../../reactos/tools/rdel" "release"
+
+$(OBJS_DIR):
+ mkdir "$@"
+
+$(SLANG_OBJS_DIR):
+ mkdir "$@"
+
+$(MCEDIT_OBJS_DIR):
+ mkdir "$@"
+
+$(OBJS_DIR)/%.$(OBJ_SUFFIX): $(MC_PC_DIR)/%.c
+ $(CC) $(CFLAGS) $(OBJ_PLACE)$@ $<
+
+$(OBJS_DIR)/%.$(OBJ_SUFFIX): $(MC_SRC_DIR)/%.c
+ $(CC) $(CFLAGS) $(OBJ_PLACE)$@ $<
+
+$(SLANG_OBJS_DIR)/%.$(OBJ_SUFFIX): $(SLANG_SRC_DIR)/%.c
+ $(CC) $(SLANG_CFLAGS) $(OBJ_PLACE)$@ $<
+
+$(MCEDIT_OBJS_DIR)/%.$(OBJ_SUFFIX): $(MCEDIT_SRC_DIR)/%.c
+ $(CC) $(MCEDIT_CFLAGS) $(OBJ_PLACE)$@ $<
+
+MC_SRCS= \
+ terms.c \
+ user.c \
+ file.c \
+ listmode.c \
+ cmd.c \
+ command.c \
+ help.c \
+ menu.c \
+ view.c \
+ dir.c \
+ info.c \
+ widget.c \
+ option.c \
+ dlg.c \
+ panelize.c \
+ profile.c \
+ util.c \
+ dialog.c \
+ ext.c \
+ color.c \
+ layout.c \
+ setup.c \
+ regex.c \
+ hotlist.c \
+ tree.c \
+ win.c \
+ complete.c \
+ find.c \
+ wtools.c \
+ boxes.c \
+ background.c \
+ main.c \
+ popt.c \
+ text.c \
+ screen.c
+
+PC_SRCS= \
+ slint_pc.c \
+ chmod.c \
+ drive.c
+
+NT_SRCS= \
+ cons_nt.c \
+ dirent_nt.c \
+ key_nt.c \
+ util_win32.c \
+ util_winnt.c \
+ util_nt.c
+
+OS2_SRCS= \
+ cons_os2.c \
+ dirent_os2.c \
+ key_os2.c \
+ util_os2.c
+
+SLANG_NT=slw32tty.c
+SLANG_OS2=slos2tty.c
+
+SLANG_SRCS= \
+ slerr.c \
+ slgetkey.c \
+ slsmg.c \
+ slvideo.c \
+ $(SLANG_$(TARGET_OS))
+
+MCEDIT_SRCS= \
+ edit.c \
+ editcmd.c \
+ editdraw.c \
+ editmenu.c \
+ editoptions.c \
+ editwidget.c \
+ syntax.c \
+ wordproc.c
+
+SRCS=$(MC_SRCS) $(PC_SRCS) $($(TARGET_OS)_SRCS) $(EXTRA_MC_SRCS)
+
+OBJS=$(addprefix $(OBJS_DIR)/, \
+ $(patsubst %.c,%.$(OBJ_SUFFIX),$(SRCS)))
+SLANG_OBJS=$(addprefix $(SLANG_OBJS_DIR)/, \
+ $(patsubst %.c,%.$(OBJ_SUFFIX),$(SLANG_SRCS)))
+MCEDIT_OBJS=$(addprefix $(MCEDIT_OBJS_DIR)/, \
+ $(patsubst %.c,%.$(OBJ_SUFFIX),$(MCEDIT_SRCS)))
+
+ifdef RSC
+
+ifndef RES_SUFFIX
+RES_SUFFIX=res
+endif # RES_SUFFIX
+
+MC_RES=$(OBJS_DIR)/mc.$(RES_SUFFIX)
+
+$(MC_RES): $(MC_PC_DIR)/mc.rc $(MC_PC_DIR)/mc_nt.ico $(MC_PC_DIR)/config.h ../VERSION
+ $(RSC) $(RES_PLACE)$(MC_RES) $(RC_DEFINES) $(MC_PC_DIR)/mc.rc
+
+else
+MC_RES=
+endif # !RSC
--- /dev/null
+#define VERSION "4.1.36"
--- /dev/null
+Notes on the Free Translation Project
+*************************************
+
+ Free software is going international! The Free Translation Project
+is a way to get maintainers of free software, translators, and users all
+together, so that will gradually become able to speak many languages.
+A few packages already provide translations for their messages.
+
+ If you found this `ABOUT-NLS' file inside a distribution, you may
+assume that the distributed package does use GNU `gettext' internally,
+itself available at your nearest GNU archive site. But you do *not*
+need to install GNU `gettext' prior to configuring, installing or using
+this package with messages translated.
+
+ Installers will find here some useful hints. These notes also
+explain how users should proceed for getting the programs to use the
+available translations. They tell how people wanting to contribute and
+work at translations should contact the appropriate team.
+
+ When reporting bugs in the `intl/' directory or bugs which may be
+related to internationalization, you should tell about the version of
+`gettext' which is used. The information can be found in the
+`intl/VERSION' file, in internationalized packages.
+
+One advise in advance
+=====================
+
+ If you want to exploit the full power of internationalization, you
+should configure it using
+
+ ./configure --with-included-gettext
+
+to force usage of internationalizing routines provided within this
+package, despite the existence of internationalizing capabilities in the
+operating system where this package is being installed. So far, only
+the `gettext' implementation in the GNU C library version 2 provides as
+many features (such as locale alias or message inheritance) as the
+implementation here. It is also not possible to offer this additional
+functionality on top of a `catgets' implementation. Future versions of
+GNU `gettext' will very likely convey even more functionality. So it
+might be a good idea to change to GNU `gettext' as soon as possible.
+
+ So you need not provide this option if you are using GNU libc 2 or
+you have installed a recent copy of the GNU gettext package with the
+included `libintl'.
+
+INSTALL Matters
+===============
+
+ Some packages are "localizable" when properly installed; the
+programs they contain can be made to speak your own native language.
+Most such packages use GNU `gettext'. Other packages have their own
+ways to internationalization, predating GNU `gettext'.
+
+ By default, this package will be installed to allow translation of
+messages. It will automatically detect whether the system provides
+usable `catgets' (if using this is selected by the installer) or
+`gettext' functions. If neither is available, the GNU `gettext' own
+library will be used. This library is wholly contained within this
+package, usually in the `intl/' subdirectory, so prior installation of
+the GNU `gettext' package is *not* required. Installers may use
+special options at configuration time for changing the default
+behaviour. The commands:
+
+ ./configure --with-included-gettext
+ ./configure --with-catgets
+ ./configure --disable-nls
+
+will respectively bypass any pre-existing `catgets' or `gettext' to use
+the internationalizing routines provided within this package, enable
+the use of the `catgets' functions (if found on the locale system), or
+else, *totally* disable translation of messages.
+
+ When you already have GNU `gettext' installed on your system and run
+configure without an option for your new package, `configure' will
+probably detect the previously built and installed `libintl.a' file and
+will decide to use this. This might be not what is desirable. You
+should use the more recent version of the GNU `gettext' library. I.e.
+if the file `intl/VERSION' shows that the library which comes with this
+package is more recent, you should use
+
+ ./configure --with-included-gettext
+
+to prevent auto-detection.
+
+ By default the configuration process will not test for the `catgets'
+function and therefore they will not be used. The reasons are already
+given above: the emulation on top of `catgets' cannot provide all the
+extensions provided by the GNU `gettext' library. If you nevertheless
+want to use the `catgets' functions use
+
+ ./configure --with-catgets
+
+to enable the test for `catgets' (this causes no harm if `catgets' is
+not available on your system). If you really select this option we
+would like to hear about the reasons because we cannot think of any
+good one ourself.
+
+ Internationalized packages have usually many `po/LL.po' files, where
+LL gives an ISO 639 two-letter code identifying the language. Unless
+translations have been forbidden at `configure' time by using the
+`--disable-nls' switch, all available translations are installed
+together with the package. However, the environment variable `LINGUAS'
+may be set, prior to configuration, to limit the installed set.
+`LINGUAS' should then contain a space separated list of two-letter
+codes, stating which languages are allowed.
+
+Using This Package
+==================
+
+ As a user, if your language has been installed for this package, you
+only have to set the `LANG' environment variable to the appropriate
+ISO 639 `LL' two-letter code prior to using the programs in the
+package. For example, let's suppose that you speak German. At the
+shell prompt, merely execute `setenv LANG de' (in `csh'),
+`export LANG; LANG=de' (in `sh') or `export LANG=de' (in `bash'). This
+can be done from your `.login' or `.profile' file, once and for all.
+
+ An operating system might already offer message localization for
+many of its programs, while other programs have been installed locally
+with the full capabilities of GNU `gettext'. Just using `gettext'
+extended syntax for `LANG' would break proper localization of already
+available operating system programs. In this case, users should set
+both `LANGUAGE' and `LANG' variables in their environment, as programs
+using GNU `gettext' give preference to `LANGUAGE'. For example, some
+Swedish users would rather read translations in German than English for
+when Swedish is not available. This is easily accomplished by setting
+`LANGUAGE' to `sv:de' while leaving `LANG' to `sv'.
+
+Translating Teams
+=================
+
+ For the Free Translation Project to be a success, we need interested
+people who like their own language and write it well, and who are also
+able to synergize with other translators speaking the same language.
+Each translation team has its own mailing list, courtesy of Linux
+International. You may reach your translation team at the address
+`LL@li.org', replacing LL by the two-letter ISO 639 code for your
+language. Language codes are *not* the same as the country codes given
+in ISO 3166. The following translation teams exist, as of August 1997:
+
+ Chinese `zh', Czech `cs', Danish `da', Dutch `nl', English `en',
+ Esperanto `eo', Finnish `fi', French `fr', German `de', Hungarian
+ `hu', Irish `ga', Italian `it', Indonesian `id', Japanese `ja',
+ Korean `ko', Latin `la', Norwegian `no', Persian `fa', Polish
+ `pl', Portuguese `pt', Russian `ru', Slovenian `sl', Spanish `es',
+ Swedish `sv', and Turkish `tr'.
+
+For example, you may reach the Chinese translation team by writing to
+`zh@li.org'.
+
+ If you'd like to volunteer to *work* at translating messages, you
+should become a member of the translating team for your own language.
+The subscribing address is *not* the same as the list itself, it has
+`-request' appended. For example, speakers of Swedish can send a
+message to `sv-request@li.org', having this message body:
+
+ subscribe
+
+ Keep in mind that team members are expected to participate
+*actively* in translations, or at solving translational difficulties,
+rather than merely lurking around. If your team does not exist yet and
+you want to start one, or if you are unsure about what to do or how to
+get started, please write to `translation@iro.umontreal.ca' to reach the
+coordinator for all translator teams.
+
+ The English team is special. It works at improving and uniformizing
+the terminology in use. Proven linguistic skill are praised more than
+programming skill, here.
+
+Available Packages
+==================
+
+ Languages are not equally supported in all packages. The following
+matrix shows the current state of internationalization, as of August
+1997. The matrix shows, in regard of each package, for which languages
+PO files have been submitted to translation coordination.
+
+ Ready PO files cs da de en es fi fr it ja ko nl no pl pt sl sv
+ .-------------------------------------------------.
+ bash | [] [] [] | 3
+ bison | [] [] [] | 3
+ clisp | [] [] [] [] | 4
+ cpio | [] [] [] [] [] | 5
+ diffutils | [] [] [] [] [] | 5
+ enscript | [] [] [] [] [] [] | 6
+ fileutils | [] [] [] [] [] [] [] [] [] [] | 10
+ findutils | [] [] [] [] [] [] [] [] | 8
+ flex | [] [] [] [] | 4
+ gcal | [] [] [] [] [] | 5
+ gettext | [] [] [] [] [] [] [] [] [] [] | 11
+ grep | [] [] [] [] [] [] [] [] [] | 9
+ hello | [] [] [] [] [] [] [] [] [] [] | 10
+ id-utils | [] [] [] | 3
+ indent | [] [] [] [] | 4
+ libc | [] [] [] [] [] [] [] | 7
+ m4 | [] [] [] [] [] | 5
+ make | [] [] [] [] [] [] | 6
+ music | [] [] | 2
+ ptx | [] [] [] [] [] [] [] [] | 8
+ recode | [] [] [] [] [] [] [] [] [] | 9
+ sh-utils | [] [] [] [] [] [] [] | 7
+ sharutils | [] [] [] [] [] | 5
+ tar | [] [] [] [] [] [] [] [] [] [] | 10
+ texinfo | [] | 1
+ textutils | [] [] [] [] [] [] [] [] [] | 9
+ wdiff | [] [] [] [] [] [] [] [] | 8
+ `-------------------------------------------------'
+ 16 languages cs da de en es fi fr it ja ko nl no pl pt sl sv
+ 27 packages 3 2 24 1 17 1 26 2 1 11 20 9 19 7 7 17 167
+
+ Some counters in the preceding matrix are higher than the number of
+visible blocks let us expect. This is because a few extra PO files are
+used for implementing regional variants of languages, or language
+dialects.
+
+ For a PO file in the matrix above to be effective, the package to
+which it applies should also have been internationalized and
+distributed as such by its maintainer. There might be an observable
+lag between the mere existence a PO file and its wide availability in a
+distribution.
+
+ If August 1997 seems to be old, you may fetch a more recent copy of
+this `ABOUT-NLS' file on most GNU archive sites.
+
--- /dev/null
+/* This is the configuration file for the Midnight Commander. It was generated
+ by autoconf's configure.
+
+ Configure for Midnight Commander
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+ Copyright (C) 1994, 1995 Miguel de Icaza
+ Copyright (C) 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <VERSION>
+
+
+@TOP@
+
+#undef PACKAGE
+
+/* Always defined */
+#undef D_INO_IN_DIRENT
+#undef IS_AIX
+#undef MOUNTED_FREAD
+#undef MOUNTED_FREAD_FSTYP
+#undef MOUNTED_GETFSSTAT
+#undef MOUNTED_GETMNT
+#undef MOUNTED_GETMNTENT1
+#undef MOUNTED_GETMNTENT2
+#undef MOUNTED_GETMNTINFO
+#undef MOUNTED_VMOUNT
+#undef STAT_STATFS2_BSIZE
+#undef STAT_STATFS2_FSIZE
+#undef STAT_STATFS2_FS_DATA
+#undef STAT_STATFS3_OSF1
+#undef STAT_STATFS4
+#undef STAT_STATVFS
+
+/* Define umode_t if your system does not provide it */
+#undef umode_t
+
+/* Define nlink_t if your system does not provide it */
+#undef nlink_t
+
+/* Does the file command accepts the -L option */
+#undef FILE_L
+
+/* Does the file command work well with - option for stdin? */
+#undef FILE_STDIN
+
+/* Does the grep command work well with - option for stdin? */
+#undef GREP_STDIN
+
+/* Is the program using the GPM library? */
+#undef HAVE_LIBGPM
+
+/* Is the program using the distributed slang library? */
+#undef HAVE_SLANG
+
+/* Is the program using a system-installed slang library? */
+#undef HAVE_SYSTEM_SLANG
+
+/* Define if the slang.h header file is inside a directory slang
+** in the standard directories
+*/
+#undef SLANG_H_INSIDE_SLANG_DIR
+
+/* Does the program have subshell support? */
+#undef HAVE_SUBSHELL_SUPPORT
+
+/* If you don't have gcc, define this */
+#undef OLD_TOOLS
+
+/* Are you using other type of curses? */
+#undef OTHER_CURSES
+
+/* Is the subshell the default or optional? */
+#undef SUBSHELL_OPTIONAL
+
+/* Use SunOS SysV curses? */
+#undef SUNOS_CURSES
+
+/* Use old BSD curses? */
+#undef USE_BSD_CURSES
+
+/* Use SystemV curses? */
+#undef USE_SYSV_CURSES
+
+/* Use Ncurses? */
+#undef USE_NCURSES
+
+/* If you Curses does not have color define this one */
+#undef NO_COLOR_SUPPORT
+
+/* Support the Midnight Commander Virtual File System? */
+#undef USE_VFS
+
+/* Support for the Memory Allocation Debugger */
+#undef HAVE_MAD
+
+/* Extra Debugging */
+#undef MCDEBUG
+
+/* If the Slang library will be using it's own terminfo instead of termcap */
+#undef SLANG_TERMINFO
+
+/* If Slang library should use termcap */
+#undef USE_TERMCAP
+
+/* If you have socket and the rest of the net functions use this */
+#undef USE_NETCODE
+
+/* If defined, use .netrc for FTP connections */
+#undef USE_NETRC
+
+/* If your operating system does not have enough space for a file name
+ * in a struct dirent, then define this
+ */
+#undef NEED_EXTRA_DIRENT_BUFFER
+
+/* Define if you want the du -s summary */
+#undef HAVE_DUSUM
+
+/* Define if your du does handle -b correctly */
+#undef DUSUM_USEB
+
+/* Define to size of chunks du is displaying its information.
+ * If DUSUM_USEB is defined, this should be 1
+ */
+#define DUSUM_FACTOR 512
+
+/* Define this one if you want termnet support */
+#undef USE_TERMNET
+
+/* Defined if you have the file command */
+#undef HAVE_FILECMD
+
+/* Defined if you have libXpm, <X11/xpm.h>, libXext, <X11/extensions/shape.h> */
+#undef HAVE_XPM_SHAPE
+
+/* Defined if you have shadow passwords on Linux */
+#undef LINUX_SHADOW
+
+/* Defined if you have the crypt prototype in neither unistd.h nor crypt.h */
+#undef NEED_CRYPT_PROTOTYPE
+
+/* Defined if your CPP understands ## macro token pasting method */
+#undef HAVE_PORTABLE_TOKEN_PASTING
+
+/* Define if you want to turn on SCO-specific code */
+#undef SCO_FLAVOR
+
+/* Define if your system has struct linger */
+#undef HAVE_STRUCT_LINGER
+
+/* Define if your curses has this one (AIX, OSF/1) */
+#undef USE_SETUPTERM
+
+/* Link in ext2fs code for delfs experimental file system */
+#undef USE_EXT2FSLIB
+
+/* Define if you have putenv routine */
+#undef HAVE_PUTENV
+
+/* Define if you have isascii */
+#undef HAVE_ISASCII
+
+/* Define if you want to use the HSC firewall */
+#undef HSC_PROXY
+
+/* Define if your system uses PAM for auth stuff */
+#undef HAVE_PAM
+
+/* Define if you have the pmap_getmaps function */
+#undef HAVE_PMAP_GETMAPS
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the get_process_stats function and have to use that instead of gettimeofday */
+#undef HAVE_GET_PROCESS_STATS
+
+/* Define if you want to call the internal routine edit() for the editor */
+#undef USE_INTERNAL_EDIT
+
+/* Define if your system has socketpair */
+#undef HAVE_SOCKETPAIR
+
+/* Do we have posix signals? */
+#undef HAVE_SIGACTION
+#undef HAVE_SIGPROCMASK
+#undef HAVE_SIGEMPTYSET
+#undef HAVE_SIGADDSET
+
+/* Version of ncurses */
+#undef NCURSES_970530
+
+#undef HAVE_STPCPY
+
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_LC_MESSAGES
+
+@BOTTOM@
+
+#ifdef HAVE_LIBPT
+# define HAVE_GRANTPT
+#endif
+
+#if defined(HAVE_LIBCRYPT) || defined(HAVE_LIBCRYPT_I)
+# define HAVE_CRYPT
+#endif
+
+#ifdef HAVE_XVIEW
+# include <xvmain.h>
+#endif
+
+#if defined(HAVE_SIGADDSET) && defined(HAVE_SIGEMPTYSET)
+# if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define SLANG_POSIX_SIGNALS
+# endif
+#endif
+
+#ifdef __os2__
+# define OS2_NT 1
+# define S_ISFIFO(x) 0
+#endif
+
+#ifdef _OS_NT
+# define OS2_NT 1
+#endif
+
+#ifndef OS2_NT
+/* some Unices do not define this, and slang requires it: */
+#ifndef unix
+# define unix
+#endif
+#endif
+
--- /dev/null
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+(
+cd $srcdir
+cat macros/gnome.m4 mc-aclocal.m4 gettext.m4 > aclocal.m4
+autoheader
+autoconf
+)
+
+$srcdir/configure $*
--- /dev/null
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+ac_cv_header_sys_statfs_h=${ac_cv_header_sys_statfs_h='no'}
+ac_cv_header_sys_dustat_h=${ac_cv_header_sys_dustat_h='no'}
+ac_cv_type_size_t=${ac_cv_type_size_t='yes'}
+ac_cv_path_CHMOD=${ac_cv_path_CHMOD='/usr/bin/chmod'}
+ac_cv_prog_cc_works=${ac_cv_prog_cc_works='yes'}
+ac_cv_header_sys_statvfs_h=${ac_cv_header_sys_statvfs_h='no'}
+ac_cv_header_crypt_h=${ac_cv_header_crypt_h='yes'}
+ac_cv_path_XGETTEXT=${ac_cv_path_XGETTEXT='/usr/bin/xgettext'}
+ac_cv_func_getcwd=${ac_cv_func_getcwd='yes'}
+ac_cv_lib_nsl_t_accept=${ac_cv_lib_nsl_t_accept='no'}
+ac_cv_lib_sun_getmntent=${ac_cv_lib_sun_getmntent='no'}
+ac_cv_func_tcsetattr=${ac_cv_func_tcsetattr='yes'}
+ac_cv_header_grp_h=${ac_cv_header_grp_h='yes'}
+ac_cv_lib_ipc_shmat=${ac_cv_lib_ipc_shmat='no'}
+ac_cv_func_crypt=${ac_cv_func_crypt='no'}
+ac_cv_func_sigaddset=${ac_cv_func_sigaddset='yes'}
+ac_cv_func_initgroups=${ac_cv_func_initgroups='yes'}
+ac_cv_header_stdlib_h=${ac_cv_header_stdlib_h='yes'}
+ac_cv_make_with_percent_rules=${ac_cv_make_with_percent_rules='yes'}
+ac_cv_func_sigprocmask=${ac_cv_func_sigprocmask='yes'}
+ac_cv_func_memmove=${ac_cv_func_memmove='yes'}
+ac_cv_func_strncasecmp=${ac_cv_func_strncasecmp='yes'}
+ac_cv_header_sys_filsys_h=${ac_cv_header_sys_filsys_h='no'}
+ac_cv_header_nl_types_h=${ac_cv_header_nl_types_h='no'}
+ac_cv_prog_cc_g=${ac_cv_prog_cc_g='yes'}
+ac_cv_path_install=${ac_cv_path_install='/usr/bin/install -c'}
+ac_cv_header_mnttab_h=${ac_cv_header_mnttab_h='no'}
+ac_cv_header_dirent_dirent_h=${ac_cv_header_dirent_dirent_h='yes'}
+ac_cv_func_setlocale=${ac_cv_func_setlocale='yes'}
+ac_cv_lib_ext2fs_ext2fs_close=${ac_cv_lib_ext2fs_ext2fs_close='no'}
+ac_cv_func_statlstat=${ac_cv_func_statlstat='no'}
+gt_cv_func_gettext_libintl=${gt_cv_func_gettext_libintl='no'}
+ac_cv_func_mmap_fixed_mapped=${ac_cv_func_mmap_fixed_mapped='no'}
+nls_cv_use_catgets=${nls_cv_use_catgets='no'}
+ac_cv_header_sys_wait_h=${ac_cv_header_sys_wait_h='yes'}
+ac_cv_prog_RANLIB=${ac_cv_prog_RANLIB='ranlib'}
+ac_cv_func_socketpair=${ac_cv_func_socketpair='yes'}
+ac_cv_func_pwdauth=${ac_cv_func_pwdauth='no'}
+ac_cv_func_strcasecmp=${ac_cv_func_strcasecmp='yes'}
+ac_cv_header_minix_config_h=${ac_cv_header_minix_config_h='no'}
+ac_cv_mandoc=${ac_cv_mandoc='-mandoc'}
+ac_cv_func_socket=${ac_cv_func_socket='yes'}
+ac_cv_func_sigaction=${ac_cv_func_sigaction='yes'}
+ac_cv_header_fcntl_h=${ac_cv_header_fcntl_h='yes'}
+ac_cv_lib_gen_getmntent=${ac_cv_lib_gen_getmntent='no'}
+ac_cv_func___argz_count=${ac_cv_func___argz_count='no'}
+ac_cv_prog_system=${ac_cv_prog_system='CYGWIN_98-4.10'}
+ac_cv_lib_intl_tolower=${ac_cv_lib_intl_tolower='yes'}
+ac_cv_func_grantpt=${ac_cv_func_grantpt='yes'}
+ac_cv_func_memcpy=${ac_cv_func_memcpy='yes'}
+ac_cv_func_memset=${ac_cv_func_memset='yes'}
+ac_cv_path_GMSGFMT=${ac_cv_path_GMSGFMT='/usr/bin/msgfmt'}
+ac_cv_c_const=${ac_cv_c_const='yes'}
+ac_cv_lib_socket_socket=${ac_cv_lib_socket_socket='no'}
+ac_cv_header_termios_h=${ac_cv_header_termios_h='yes'}
+ac_cv_lib_rpc_pmap_set=${ac_cv_lib_rpc_pmap_set='no'}
+ac_cv_prog_CC=${ac_cv_prog_CC='gcc'}
+ac_cv_func_pmap_getmaps=${ac_cv_func_pmap_getmaps='no'}
+ac_cv_func_remove=${ac_cv_func_remove='yes'}
+ac_cv_lib_dnet_stub_dnet_ntoa=${ac_cv_lib_dnet_stub_dnet_ntoa='no'}
+ac_cv_type_umode_t=${ac_cv_type_umode_t='no'}
+ac_cv_type_mode_t=${ac_cv_type_mode_t='yes'}
+ac_cv_func_getmntinfo=${ac_cv_func_getmntinfo='no'}
+ac_cv_func_cfgetospeed=${ac_cv_func_cfgetospeed='yes'}
+ac_cv_func_munmap=${ac_cv_func_munmap='yes'}
+ac_cv_header_values_h=${ac_cv_header_values_h='no'}
+ac_cv_header_sys_select_h=${ac_cv_header_sys_select_h='yes'}
+ac_cv_path_AR=${ac_cv_path_AR='/usr/bin/ar'}
+ac_cv_path_CP=${ac_cv_path_CP='/usr/bin/cp'}
+ac_cv_type_nlink_t=${ac_cv_type_nlink_t='yes'}
+ac_cv_header_sys_mount_h=${ac_cv_header_sys_mount_h='yes'}
+ac_cv_func_sysconf=${ac_cv_func_sysconf='yes'}
+ac_cv_func_getwd=${ac_cv_func_getwd='yes'}
+gt_cv_func_gettext_libc=${gt_cv_func_gettext_libc='no'}
+ac_cv_header_limits_h=${ac_cv_header_limits_h='yes'}
+ac_cv_prog_gnu_make=${ac_cv_prog_gnu_make='yes'}
+ac_cv_prog_LN_S=${ac_cv_prog_LN_S='ln -s'}
+fu_cv_sys_stat_statfs3_osf1=${fu_cv_sys_stat_statfs3_osf1='no'}
+ac_cv_struct_st_rdev=${ac_cv_struct_st_rdev='yes'}
+ac_cv_func_alloca_works=${ac_cv_func_alloca_works='yes'}
+ac_cv_header_alloca_h=${ac_cv_header_alloca_h='no'}
+ac_cv_prog_cc_stdc=${ac_cv_prog_cc_stdc=''}
+ac_cv_func_shmat=${ac_cv_func_shmat='no'}
+ac_cv_have_x=${ac_cv_have_x='have_x=yes ac_x_includes=/usr/X11R6/include ac_x_libraries=/usr/X11R6/lib'}
+ac_cv_header_sys_fs_types_h=${ac_cv_header_sys_fs_types_h='no'}
+ac_cv_path_MSGFMT=${ac_cv_path_MSGFMT='/usr/bin/msgfmt'}
+ac_cv_header_stdc=${ac_cv_header_stdc='yes'}
+ac_cv_dusum=${ac_cv_dusum='dusum_useb=yes; dusum_factor=1'}
+ac_cv_lib_dnet_dnet_ntoa=${ac_cv_lib_dnet_dnet_ntoa='no'}
+ac_cv_header_sys_fstyp_h=${ac_cv_header_sys_fstyp_h='no'}
+ac_cv_func___argz_stringify=${ac_cv_func___argz_stringify='no'}
+ac_cv_header_mntent_h=${ac_cv_header_mntent_h='yes'}
+ac_cv_lib_dir_opendir=${ac_cv_lib_dir_opendir='no'}
+ac_cv_header_sys_sysmacros_h=${ac_cv_header_sys_sysmacros_h='yes'}
+ac_cv_prog_make_make_set=${ac_cv_prog_make_make_set='yes'}
+ac_cv_lib_seq_get_process_stats=${ac_cv_lib_seq_get_process_stats='no'}
+ac_cv_func_gethostbyname=${ac_cv_func_gethostbyname='yes'}
+ac_cv_func_statfs=${ac_cv_func_statfs='yes'}
+nls_cv_header_intl=${nls_cv_header_intl='intl/libintl.h'}
+ac_cv_func___argz_next=${ac_cv_func___argz_next='no'}
+ac_cv_func_setenv=${ac_cv_func_setenv='yes'}
+ac_cv_header_sys_param_h=${ac_cv_header_sys_param_h='yes'}
+ac_cv_header_string_h=${ac_cv_header_string_h='yes'}
+ac_cv_header_locale_h=${ac_cv_header_locale_h='yes'}
+ac_cv_header_unistd_h=${ac_cv_header_unistd_h='yes'}
+ac_cv_c_inline=${ac_cv_c_inline='inline'}
+ac_cv_func_pmap_set=${ac_cv_func_pmap_set='no'}
+ac_cv_func_statvfs=${ac_cv_func_statvfs='no'}
+fu_cv_sys_d_ino_in_dirent=${fu_cv_sys_d_ino_in_dirent='yes'}
+ac_cv_header_sys_vfs_h=${ac_cv_header_sys_vfs_h='yes'}
+ac_cv_func_strchr=${ac_cv_func_strchr='yes'}
+ac_cv_header_utime_h=${ac_cv_header_utime_h='yes'}
+ac_cv_header_memory_h=${ac_cv_header_memory_h='yes'}
+ac_cv_func_keyok=${ac_cv_func_keyok='no'}
+ac_cv_filel=${ac_cv_filel='yes'}
+ac_cv_func_rresvport=${ac_cv_func_rresvport='yes'}
+fu_cv_sys_stat_statfs2_bsize=${fu_cv_sys_stat_statfs2_bsize='yes'}
+ac_cv_prog_gcc=${ac_cv_prog_gcc='yes'}
+ac_cv_prog_cc_cross=${ac_cv_prog_cc_cross='no'}
+ac_cv_lib_curses_setupterm=${ac_cv_lib_curses_setupterm='yes'}
+ac_cv_grep_stdin=${ac_cv_grep_stdin='yes'}
+ac_cv_prog_HAVE_FILECMD=${ac_cv_prog_HAVE_FILECMD='true'}
+ac_cv_prog_HAVE_nroff=${ac_cv_prog_HAVE_nroff='true'}
+ac_cv_lib_seq_getmntent=${ac_cv_lib_seq_getmntent='no'}
+ac_cv_func_strerror=${ac_cv_func_strerror='yes'}
+am_cv_val_LC_MESSAGES=${am_cv_val_LC_MESSAGES='yes'}
+ac_cv_type_off_t=${ac_cv_type_off_t='yes'}
+ac_cv_func_tcgetattr=${ac_cv_func_tcgetattr='yes'}
+nls_cv_force_use_gnu_gettext=${nls_cv_force_use_gnu_gettext='no'}
+ac_cv_type_pid_t=${ac_cv_type_pid_t='yes'}
+ac_cv_struct_st_blocks=${ac_cv_struct_st_blocks='yes'}
+ac_cv_lib_intl_bindtextdomain=${ac_cv_lib_intl_bindtextdomain='yes'}
+ac_cv_path_RM=${ac_cv_path_RM='/usr/bin/rm'}
+ac_cv_header_sys_mkdev_h=${ac_cv_header_sys_mkdev_h='no'}
+ac_cv_header_sys_types_h_makedev=${ac_cv_header_sys_types_h_makedev='no'}
+ac_cv_func_connect=${ac_cv_func_connect='yes'}
+fu_cv_sys_mounted_getmntent1=${fu_cv_sys_mounted_getmntent1='yes'}
+ac_cv_func_sigemptyset=${ac_cv_func_sigemptyset='yes'}
+ac_cv_struct_st_blksize=${ac_cv_struct_st_blksize='yes'}
+nls_cv_use_gnu_gettext=${nls_cv_use_gnu_gettext='yes'}
+ac_cv_header_argz_h=${ac_cv_header_argz_h='no'}
+ac_cv_prog_AWK=${ac_cv_prog_AWK='gawk'}
+ac_cv_prog_CPP=${ac_cv_prog_CPP='gcc -E'}
+ac_cv_func_resizeterm=${ac_cv_func_resizeterm='no'}
+fu_cv_sys_mounted_getmntent2=${fu_cv_sys_mounted_getmntent2='no'}
+ac_cv_header_malloc_h=${ac_cv_header_malloc_h='yes'}
+ac_cv_func_getpagesize=${ac_cv_func_getpagesize='yes'}
+ac_cv_nroff_tascii=${ac_cv_nroff_tascii=' -Tascii'}
+ac_cv_func_getmntent=${ac_cv_func_getmntent='yes'}
+ac_cv_header_libintl_h=${ac_cv_header_libintl_h='yes'}
+ac_cv_dnamesize=${ac_cv_dnamesize='yes'}
+ac_cv_path_MV=${ac_cv_path_MV='/usr/bin/mv'}
+ac_cv_lib_slang_SLang_init_tty=${ac_cv_lib_slang_SLang_init_tty='no'}
+ac_cv_type_uid_t=${ac_cv_type_uid_t='yes'}
+ac_cv_filestdin=${ac_cv_filestdin='yes'}
+ac_cv_lib_crypt_crypt=${ac_cv_lib_crypt_crypt='yes'}
+ac_cv_lib_gpm_Gpm_Repeat=${ac_cv_lib_gpm_Gpm_Repeat='no'}
+ac_cv_header_rpc_pmap_clnt_h=${ac_cv_header_rpc_pmap_clnt_h='no'}
+ac_cv_func_pmap_getport=${ac_cv_func_pmap_getport='no'}
+ac_cv_lib_ICE_IceConnectionNumber=${ac_cv_lib_ICE_IceConnectionNumber='yes'}
+ac_cv_func_strdup=${ac_cv_func_strdup='yes'}
+nls_cv_header_libgt=${nls_cv_header_libgt='intl/libgettext.h'}
+ac_cv_func_putenv=${ac_cv_func_putenv='yes'}
+ac_cv_func_truncate=${ac_cv_func_truncate='yes'}
+ac_cv_func_stpcpy=${ac_cv_func_stpcpy='no'}
--- /dev/null
+/* config.h. Generated automatically by configure. */
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* This is the configuration file for the Midnight Commander. It was generated
+ by autoconf's configure.
+
+ Configure for Midnight Commander
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+ Copyright (C) 1994, 1995 Miguel de Icaza
+ Copyright (C) 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <VERSION>
+
+
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* #undef _ALL_SOURCE */
+#endif
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define if you have alloca, as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+/* #undef HAVE_ALLOCA_H */
+
+/* Define if you have the getmntent function. */
+#define HAVE_GETMNTENT 1
+
+/* Define if you have a working `mmap' system call. */
+/* #undef HAVE_MMAP */
+
+/* Define if your struct stat has st_blksize. */
+#define HAVE_ST_BLKSIZE 1
+
+/* Define if your struct stat has st_blocks. */
+#define HAVE_ST_BLOCKS 1
+
+/* Define if your struct stat has st_rdev. */
+#define HAVE_ST_RDEV 1
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define as __inline if that's what the C compiler calls it. */
+/* #undef inline */
+
+/* Define if major, minor, and makedev are declared in <mkdev.h>. */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define if major, minor, and makedev are declared in <sysmacros.h>. */
+#define MAJOR_IN_SYSMACROS 1
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define if the X Window System is missing or not being used. */
+/* #undef X_DISPLAY_MISSING */
+
+#define PACKAGE "mc"
+
+/* Always defined */
+#define D_INO_IN_DIRENT 1
+/* #undef IS_AIX */
+/* #undef MOUNTED_FREAD */
+/* #undef MOUNTED_FREAD_FSTYP */
+/* #undef MOUNTED_GETFSSTAT */
+/* #undef MOUNTED_GETMNT */
+#define MOUNTED_GETMNTENT1 1
+/* #undef MOUNTED_GETMNTENT2 */
+/* #undef MOUNTED_GETMNTINFO */
+/* #undef MOUNTED_VMOUNT */
+#define STAT_STATFS2_BSIZE 1
+/* #undef STAT_STATFS2_FSIZE */
+/* #undef STAT_STATFS2_FS_DATA */
+/* #undef STAT_STATFS3_OSF1 */
+/* #undef STAT_STATFS4 */
+/* #undef STAT_STATVFS */
+
+/* Define umode_t if your system does not provide it */
+#define umode_t int
+
+/* Define nlink_t if your system does not provide it */
+/* #undef nlink_t */
+
+/* Does the file command accepts the -L option */
+#define FILE_L 1
+
+/* Does the file command work well with - option for stdin? */
+#define FILE_STDIN 1
+
+/* Does the grep command work well with - option for stdin? */
+#define GREP_STDIN 1
+
+/* Is the program using the GPM library? */
+/* #undef HAVE_LIBGPM */
+
+/* Is the program using the distributed slang library? */
+#define HAVE_SLANG 1
+
+/* Is the program using a system-installed slang library? */
+/* #undef HAVE_SYSTEM_SLANG */
+
+/* Define if the slang.h header file is inside a directory slang
+** in the standard directories
+*/
+/* #undef SLANG_H_INSIDE_SLANG_DIR */
+
+/* Does the program have subshell support? */
+#define HAVE_SUBSHELL_SUPPORT 1
+
+/* If you don't have gcc, define this */
+/* #undef OLD_TOOLS */
+
+/* Is the subshell the default or optional? */
+/* #undef SUBSHELL_OPTIONAL */
+
+/* Use SunOS SysV curses? */
+/* #undef SUNOS_CURSES */
+
+/* Use SystemV curses? */
+/* #undef USE_SYSV_CURSES */
+
+/* Use Ncurses? */
+/* #undef USE_NCURSES */
+
+/* If you Curses does not have color define this one */
+/* #undef NO_COLOR_SUPPORT */
+
+/* Support the Midnight Commander Virtual File System? */
+#define USE_VFS 1
+
+/* Support for the Memory Allocation Debugger */
+/* #undef HAVE_MAD */
+
+/* Extra Debugging */
+/* #undef MCDEBUG */
+
+/* If the Slang library will be using it's own terminfo instead of termcap */
+#define SLANG_TERMINFO 1
+
+/* If Slang library should use termcap */
+/* #undef USE_TERMCAP */
+
+/* If you have socket and the rest of the net functions use this */
+#define USE_NETCODE 1
+
+/* If defined, use .netrc for FTP connections */
+/* #undef USE_NETRC */
+
+/* If your operating system does not have enough space for a file name
+ * in a struct dirent, then define this
+ */
+/* #undef NEED_EXTRA_DIRENT_BUFFER */
+
+/* Define if you want the du -s summary */
+#define HAVE_DUSUM 1
+
+/* Define if your du does handle -b correctly */
+#define DUSUM_USEB 1
+
+/* Define to size of chunks du is displaying its information.
+ * If DUSUM_USEB is defined, this should be 1
+ */
+#define DUSUM_FACTOR 1
+
+/* Define this one if you want termnet support */
+/* #undef USE_TERMNET */
+
+/* Defined if you have libXpm, <X11/xpm.h>, libXext, <X11/extensions/shape.h> */
+/* #undef HAVE_XPM_SHAPE */
+
+/* Defined if you have shadow passwords on Linux */
+/* #undef LINUX_SHADOW */
+
+/* Defined if you have the crypt prototype in neither unistd.h nor crypt.h */
+#define NEED_CRYPT_PROTOTYPE 1
+
+/* Define if you want to turn on SCO-specific code */
+/* #undef SCO_FLAVOR */
+
+/* Define if your system has struct linger */
+#define HAVE_STRUCT_LINGER 1
+
+/* Define if your curses has this one (AIX, OSF/1) */
+/* #undef USE_SETUPTERM */
+
+/* Link in ext2fs code for delfs experimental file system */
+/* #undef USE_EXT2FSLIB */
+
+/* Define if you want to use the HSC firewall */
+/* #undef HSC_PROXY */
+
+/* Define if your system uses PAM for auth stuff */
+/* #undef HAVE_PAM */
+
+/* Define if you have the get_process_stats function and have to use that instead of gettimeofday */
+/* #undef HAVE_GET_PROCESS_STATS */
+
+/* Define if you want to call the internal routine edit() for the editor */
+#define USE_INTERNAL_EDIT 1
+
+/* Define if your system has socketpair */
+#define HAVE_SOCKETPAIR 1
+
+/* Version of ncurses */
+/* #undef NCURSES_970530 */
+
+/* #undef HAVE_STPCPY */
+
+#define ENABLE_NLS 1
+/* #undef HAVE_CATGETS */
+/* #undef HAVE_GETTEXT */
+#define HAVE_LC_MESSAGES 1
+
+/* Define if you have the __argz_count function. */
+/* #undef HAVE___ARGZ_COUNT */
+
+/* Define if you have the __argz_next function. */
+/* #undef HAVE___ARGZ_NEXT */
+
+/* Define if you have the __argz_stringify function. */
+/* #undef HAVE___ARGZ_STRINGIFY */
+
+/* Define if you have the cfgetospeed function. */
+#define HAVE_CFGETOSPEED 1
+
+/* Define if you have the crypt function. */
+/* #undef HAVE_CRYPT */
+
+/* Define if you have the dcgettext function. */
+/* #undef HAVE_DCGETTEXT */
+
+/* Define if you have the getcwd function. */
+#define HAVE_GETCWD 1
+
+/* Define if you have the getmntinfo function. */
+/* #undef HAVE_GETMNTINFO */
+
+/* Define if you have the getpagesize function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the getwd function. */
+#define HAVE_GETWD 1
+
+/* Define if you have the grantpt function. */
+#define HAVE_GRANTPT 1
+
+/* Define if you have the initgroups function. */
+#define HAVE_INITGROUPS 1
+
+/* Define if you have the keyok function. */
+/* #undef HAVE_KEYOK */
+
+/* Define if you have the memcpy function. */
+#define HAVE_MEMCPY 1
+
+/* Define if you have the memmove function. */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the memset function. */
+#define HAVE_MEMSET 1
+
+/* Define if you have the munmap function. */
+#define HAVE_MUNMAP 1
+
+/* Define if you have the pmap_getmaps function. */
+/* #undef HAVE_PMAP_GETMAPS */
+
+/* Define if you have the pmap_getport function. */
+/* #undef HAVE_PMAP_GETPORT */
+
+/* Define if you have the pmap_set function. */
+/* #undef HAVE_PMAP_SET */
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the pwdauth function. */
+/* #undef HAVE_PWDAUTH */
+
+/* Define if you have the resizeterm function. */
+/* #undef HAVE_RESIZETERM */
+
+/* Define if you have the rresvport function. */
+#define HAVE_RRESVPORT 1
+
+/* Define if you have the setenv function. */
+#define HAVE_SETENV 1
+
+/* Define if you have the setlocale function. */
+#define HAVE_SETLOCALE 1
+
+/* Define if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define if you have the sigaddset function. */
+#define HAVE_SIGADDSET 1
+
+/* Define if you have the sigemptyset function. */
+#define HAVE_SIGEMPTYSET 1
+
+/* Define if you have the sigprocmask function. */
+#define HAVE_SIGPROCMASK 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the socketpair function. */
+#define HAVE_SOCKETPAIR 1
+
+/* Define if you have the statfs function. */
+#define HAVE_STATFS 1
+
+/* Define if you have the statlstat function. */
+/* #undef HAVE_STATLSTAT */
+
+/* Define if you have the statvfs function. */
+/* #undef HAVE_STATVFS */
+
+/* Define if you have the stpcpy function. */
+/* #undef HAVE_STPCPY */
+
+/* Define if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define if you have the strchr function. */
+#define HAVE_STRCHR 1
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define if you have the sysconf function. */
+#define HAVE_SYSCONF 1
+
+/* Define if you have the tcgetattr function. */
+#define HAVE_TCGETATTR 1
+
+/* Define if you have the tcsetattr function. */
+#define HAVE_TCSETATTR 1
+
+/* Define if you have the truncate function. */
+#define HAVE_TRUNCATE 1
+
+/* Define if you have the <argz.h> header file. */
+/* #undef HAVE_ARGZ_H */
+
+/* Define if you have the <crypt.h> header file. */
+#define HAVE_CRYPT_H 1
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <ext2fs/ext2fs.h> header file. */
+/* #undef HAVE_EXT2FS_EXT2FS_H */
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <grp.h> header file. */
+#define HAVE_GRP_H 1
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <linux/ext2_fs.h> header file. */
+/* #undef HAVE_LINUX_EXT2_FS_H */
+
+/* Define if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <mntent.h> header file. */
+#define HAVE_MNTENT_H 1
+
+/* Define if you have the <mnttab.h> header file. */
+/* #undef HAVE_MNTTAB_H */
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <nl_types.h> header file. */
+/* #undef HAVE_NL_TYPES_H */
+
+/* Define if you have the <rpc/pmap_clnt.h> header file. */
+/* #undef HAVE_RPC_PMAP_CLNT_H */
+
+/* Define if you have the <shadow.h> header file. */
+/* #undef HAVE_SHADOW_H */
+
+/* Define if you have the <shadow/shadow.h> header file. */
+/* #undef HAVE_SHADOW_SHADOW_H */
+
+/* Define if you have the <slang.h> header file. */
+/* #undef HAVE_SLANG_H */
+
+/* Define if you have the <slang/slang.h> header file. */
+/* #undef HAVE_SLANG_SLANG_H */
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/dustat.h> header file. */
+/* #undef HAVE_SYS_DUSTAT_H */
+
+/* Define if you have the <sys/filsys.h> header file. */
+/* #undef HAVE_SYS_FILSYS_H */
+
+/* Define if you have the <sys/fs_types.h> header file. */
+/* #undef HAVE_SYS_FS_TYPES_H */
+
+/* Define if you have the <sys/fstyp.h> header file. */
+/* #undef HAVE_SYS_FSTYP_H */
+
+/* Define if you have the <sys/mount.h> header file. */
+#define HAVE_SYS_MOUNT_H 1
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/statfs.h> header file. */
+/* #undef HAVE_SYS_STATFS_H */
+
+/* Define if you have the <sys/statvfs.h> header file. */
+/* #undef HAVE_SYS_STATVFS_H */
+
+/* Define if you have the <sys/vfs.h> header file. */
+#define HAVE_SYS_VFS_H 1
+
+/* Define if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define if you have the <values.h> header file. */
+/* #undef HAVE_VALUES_H */
+
+/* Define if you have the i library (-li). */
+/* #undef HAVE_LIBI */
+
+/* Define if you have the intl library (-lintl). */
+#define HAVE_LIBINTL 1
+
+/* Define if you have the nsl library (-lnsl). */
+/* #undef HAVE_LIBNSL */
+
+/* Define if you have the pt library (-lpt). */
+/* #undef HAVE_LIBPT */
+
+/* Define if you have the socket library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+#ifdef HAVE_LIBPT
+# define HAVE_GRANTPT
+#endif
+
+#if defined(HAVE_LIBCRYPT) || defined(HAVE_LIBCRYPT_I)
+# define HAVE_CRYPT
+#endif
+
+#ifdef HAVE_XVIEW
+# include <xvmain.h>
+#endif
+
+#if defined(HAVE_SIGADDSET) && defined(HAVE_SIGEMPTYSET)
+# if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define SLANG_POSIX_SIGNALS
+# endif
+#endif
+
+#ifdef __os2__
+# define OS2_NT 1
+# define S_ISFIFO(x) 0
+#endif
+
+#ifdef _OS_NT
+# define OS2_NT 1
+#endif
+
+#ifndef OS2_NT
+/* some Unices do not define this, and slang requires it: */
+#ifndef unix
+# define unix
+#endif
+#endif
+
--- /dev/null
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+/* This is the configuration file for the Midnight Commander. It was generated
+ by autoconf's configure.
+
+ Configure for Midnight Commander
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+ Copyright (C) 1994, 1995 Miguel de Icaza
+ Copyright (C) 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <VERSION>
+
+
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+#undef _ALL_SOURCE
+#endif
+
+/* Define if using alloca.c. */
+#undef C_ALLOCA
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+#undef CRAY_STACKSEG_END
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef gid_t
+
+/* Define if you have alloca, as a function or macro. */
+#undef HAVE_ALLOCA
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if you have the getmntent function. */
+#undef HAVE_GETMNTENT
+
+/* Define if you have a working `mmap' system call. */
+#undef HAVE_MMAP
+
+/* Define if your struct stat has st_blksize. */
+#undef HAVE_ST_BLKSIZE
+
+/* Define if your struct stat has st_blocks. */
+#undef HAVE_ST_BLOCKS
+
+/* Define if your struct stat has st_rdev. */
+#undef HAVE_ST_RDEV
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#undef HAVE_SYS_WAIT_H
+
+/* Define as __inline if that's what the C compiler calls it. */
+#undef inline
+
+/* Define if major, minor, and makedev are declared in <mkdev.h>. */
+#undef MAJOR_IN_MKDEV
+
+/* Define if major, minor, and makedev are declared in <sysmacros.h>. */
+#undef MAJOR_IN_SYSMACROS
+
+/* Define if on MINIX. */
+#undef _MINIX
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef mode_t
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+#undef off_t
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef pid_t
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define if you need to in order for stat and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+#undef STACK_DIRECTION
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#undef uid_t
+
+/* Define if the X Window System is missing or not being used. */
+#undef X_DISPLAY_MISSING
+
+#undef PACKAGE
+
+/* Always defined */
+#undef D_INO_IN_DIRENT
+#undef IS_AIX
+#undef MOUNTED_FREAD
+#undef MOUNTED_FREAD_FSTYP
+#undef MOUNTED_GETFSSTAT
+#undef MOUNTED_GETMNT
+#undef MOUNTED_GETMNTENT1
+#undef MOUNTED_GETMNTENT2
+#undef MOUNTED_GETMNTINFO
+#undef MOUNTED_VMOUNT
+#undef STAT_STATFS2_BSIZE
+#undef STAT_STATFS2_FSIZE
+#undef STAT_STATFS2_FS_DATA
+#undef STAT_STATFS3_OSF1
+#undef STAT_STATFS4
+#undef STAT_STATVFS
+
+/* Define umode_t if your system does not provide it */
+#undef umode_t
+
+/* Define nlink_t if your system does not provide it */
+#undef nlink_t
+
+/* Does the file command accepts the -L option */
+#undef FILE_L
+
+/* Does the file command work well with - option for stdin? */
+#undef FILE_STDIN
+
+/* Does the grep command work well with - option for stdin? */
+#undef GREP_STDIN
+
+/* Is the program using the GPM library? */
+#undef HAVE_LIBGPM
+
+/* Is the program using the distributed slang library? */
+#undef HAVE_SLANG
+
+/* Is the program using a system-installed slang library? */
+#undef HAVE_SYSTEM_SLANG
+
+/* Define if the slang.h header file is inside a directory slang
+** in the standard directories
+*/
+#undef SLANG_H_INSIDE_SLANG_DIR
+
+/* Does the program have subshell support? */
+#undef HAVE_SUBSHELL_SUPPORT
+
+/* If you don't have gcc, define this */
+#undef OLD_TOOLS
+
+/* Is the subshell the default or optional? */
+#undef SUBSHELL_OPTIONAL
+
+/* Use SunOS SysV curses? */
+#undef SUNOS_CURSES
+
+/* Use SystemV curses? */
+#undef USE_SYSV_CURSES
+
+/* Use Ncurses? */
+#undef USE_NCURSES
+
+/* If you Curses does not have color define this one */
+#undef NO_COLOR_SUPPORT
+
+/* Support the Midnight Commander Virtual File System? */
+#undef USE_VFS
+
+/* Support for the Memory Allocation Debugger */
+#undef HAVE_MAD
+
+/* Extra Debugging */
+#undef MCDEBUG
+
+/* If the Slang library will be using it's own terminfo instead of termcap */
+#undef SLANG_TERMINFO
+
+/* If Slang library should use termcap */
+#undef USE_TERMCAP
+
+/* If you have socket and the rest of the net functions use this */
+#undef USE_NETCODE
+
+/* If defined, use .netrc for FTP connections */
+#undef USE_NETRC
+
+/* If your operating system does not have enough space for a file name
+ * in a struct dirent, then define this
+ */
+#undef NEED_EXTRA_DIRENT_BUFFER
+
+/* Define if you want the du -s summary */
+#undef HAVE_DUSUM
+
+/* Define if your du does handle -b correctly */
+#undef DUSUM_USEB
+
+/* Define to size of chunks du is displaying its information.
+ * If DUSUM_USEB is defined, this should be 1
+ */
+#define DUSUM_FACTOR 512
+
+/* Define this one if you want termnet support */
+#undef USE_TERMNET
+
+/* Defined if you have libXpm, <X11/xpm.h>, libXext, <X11/extensions/shape.h> */
+#undef HAVE_XPM_SHAPE
+
+/* Defined if you have shadow passwords on Linux */
+#undef LINUX_SHADOW
+
+/* Defined if you have the crypt prototype in neither unistd.h nor crypt.h */
+#undef NEED_CRYPT_PROTOTYPE
+
+/* Define if you want to turn on SCO-specific code */
+#undef SCO_FLAVOR
+
+/* Define if your system has struct linger */
+#undef HAVE_STRUCT_LINGER
+
+/* Define if your curses has this one (AIX, OSF/1) */
+#undef USE_SETUPTERM
+
+/* Link in ext2fs code for delfs experimental file system */
+#undef USE_EXT2FSLIB
+
+/* Define if you want to use the HSC firewall */
+#undef HSC_PROXY
+
+/* Define if your system uses PAM for auth stuff */
+#undef HAVE_PAM
+
+/* Define if you have the get_process_stats function and have to use that instead of gettimeofday */
+#undef HAVE_GET_PROCESS_STATS
+
+/* Define if you want to call the internal routine edit() for the editor */
+#undef USE_INTERNAL_EDIT
+
+/* Define if your system has socketpair */
+#undef HAVE_SOCKETPAIR
+
+/* Version of ncurses */
+#undef NCURSES_970530
+
+#undef HAVE_STPCPY
+
+#undef ENABLE_NLS
+#undef HAVE_CATGETS
+#undef HAVE_GETTEXT
+#undef HAVE_LC_MESSAGES
+
+/* Define if you have the __argz_count function. */
+#undef HAVE___ARGZ_COUNT
+
+/* Define if you have the __argz_next function. */
+#undef HAVE___ARGZ_NEXT
+
+/* Define if you have the __argz_stringify function. */
+#undef HAVE___ARGZ_STRINGIFY
+
+/* Define if you have the cfgetospeed function. */
+#undef HAVE_CFGETOSPEED
+
+/* Define if you have the crypt function. */
+#undef HAVE_CRYPT
+
+/* Define if you have the dcgettext function. */
+#undef HAVE_DCGETTEXT
+
+/* Define if you have the getcwd function. */
+#undef HAVE_GETCWD
+
+/* Define if you have the getmntinfo function. */
+#undef HAVE_GETMNTINFO
+
+/* Define if you have the getpagesize function. */
+#undef HAVE_GETPAGESIZE
+
+/* Define if you have the getwd function. */
+#undef HAVE_GETWD
+
+/* Define if you have the grantpt function. */
+#undef HAVE_GRANTPT
+
+/* Define if you have the initgroups function. */
+#undef HAVE_INITGROUPS
+
+/* Define if you have the keyok function. */
+#undef HAVE_KEYOK
+
+/* Define if you have the memcpy function. */
+#undef HAVE_MEMCPY
+
+/* Define if you have the memmove function. */
+#undef HAVE_MEMMOVE
+
+/* Define if you have the memset function. */
+#undef HAVE_MEMSET
+
+/* Define if you have the munmap function. */
+#undef HAVE_MUNMAP
+
+/* Define if you have the pmap_getmaps function. */
+#undef HAVE_PMAP_GETMAPS
+
+/* Define if you have the pmap_getport function. */
+#undef HAVE_PMAP_GETPORT
+
+/* Define if you have the pmap_set function. */
+#undef HAVE_PMAP_SET
+
+/* Define if you have the putenv function. */
+#undef HAVE_PUTENV
+
+/* Define if you have the pwdauth function. */
+#undef HAVE_PWDAUTH
+
+/* Define if you have the resizeterm function. */
+#undef HAVE_RESIZETERM
+
+/* Define if you have the rresvport function. */
+#undef HAVE_RRESVPORT
+
+/* Define if you have the setenv function. */
+#undef HAVE_SETENV
+
+/* Define if you have the setlocale function. */
+#undef HAVE_SETLOCALE
+
+/* Define if you have the sigaction function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the sigaddset function. */
+#undef HAVE_SIGADDSET
+
+/* Define if you have the sigemptyset function. */
+#undef HAVE_SIGEMPTYSET
+
+/* Define if you have the sigprocmask function. */
+#undef HAVE_SIGPROCMASK
+
+/* Define if you have the socket function. */
+#undef HAVE_SOCKET
+
+/* Define if you have the socketpair function. */
+#undef HAVE_SOCKETPAIR
+
+/* Define if you have the statfs function. */
+#undef HAVE_STATFS
+
+/* Define if you have the statlstat function. */
+#undef HAVE_STATLSTAT
+
+/* Define if you have the statvfs function. */
+#undef HAVE_STATVFS
+
+/* Define if you have the stpcpy function. */
+#undef HAVE_STPCPY
+
+/* Define if you have the strcasecmp function. */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the strchr function. */
+#undef HAVE_STRCHR
+
+/* Define if you have the strdup function. */
+#undef HAVE_STRDUP
+
+/* Define if you have the strerror function. */
+#undef HAVE_STRERROR
+
+/* Define if you have the strncasecmp function. */
+#undef HAVE_STRNCASECMP
+
+/* Define if you have the sysconf function. */
+#undef HAVE_SYSCONF
+
+/* Define if you have the tcgetattr function. */
+#undef HAVE_TCGETATTR
+
+/* Define if you have the tcsetattr function. */
+#undef HAVE_TCSETATTR
+
+/* Define if you have the truncate function. */
+#undef HAVE_TRUNCATE
+
+/* Define if you have the <argz.h> header file. */
+#undef HAVE_ARGZ_H
+
+/* Define if you have the <crypt.h> header file. */
+#undef HAVE_CRYPT_H
+
+/* Define if you have the <dirent.h> header file. */
+#undef HAVE_DIRENT_H
+
+/* Define if you have the <ext2fs/ext2fs.h> header file. */
+#undef HAVE_EXT2FS_EXT2FS_H
+
+/* Define if you have the <fcntl.h> header file. */
+#undef HAVE_FCNTL_H
+
+/* Define if you have the <grp.h> header file. */
+#undef HAVE_GRP_H
+
+/* Define if you have the <limits.h> header file. */
+#undef HAVE_LIMITS_H
+
+/* Define if you have the <linux/ext2_fs.h> header file. */
+#undef HAVE_LINUX_EXT2_FS_H
+
+/* Define if you have the <locale.h> header file. */
+#undef HAVE_LOCALE_H
+
+/* Define if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <mntent.h> header file. */
+#undef HAVE_MNTENT_H
+
+/* Define if you have the <mnttab.h> header file. */
+#undef HAVE_MNTTAB_H
+
+/* Define if you have the <ndir.h> header file. */
+#undef HAVE_NDIR_H
+
+/* Define if you have the <nl_types.h> header file. */
+#undef HAVE_NL_TYPES_H
+
+/* Define if you have the <rpc/pmap_clnt.h> header file. */
+#undef HAVE_RPC_PMAP_CLNT_H
+
+/* Define if you have the <shadow.h> header file. */
+#undef HAVE_SHADOW_H
+
+/* Define if you have the <shadow/shadow.h> header file. */
+#undef HAVE_SHADOW_SHADOW_H
+
+/* Define if you have the <slang.h> header file. */
+#undef HAVE_SLANG_H
+
+/* Define if you have the <slang/slang.h> header file. */
+#undef HAVE_SLANG_SLANG_H
+
+/* Define if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/dir.h> header file. */
+#undef HAVE_SYS_DIR_H
+
+/* Define if you have the <sys/dustat.h> header file. */
+#undef HAVE_SYS_DUSTAT_H
+
+/* Define if you have the <sys/filsys.h> header file. */
+#undef HAVE_SYS_FILSYS_H
+
+/* Define if you have the <sys/fs_types.h> header file. */
+#undef HAVE_SYS_FS_TYPES_H
+
+/* Define if you have the <sys/fstyp.h> header file. */
+#undef HAVE_SYS_FSTYP_H
+
+/* Define if you have the <sys/mount.h> header file. */
+#undef HAVE_SYS_MOUNT_H
+
+/* Define if you have the <sys/ndir.h> header file. */
+#undef HAVE_SYS_NDIR_H
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/statfs.h> header file. */
+#undef HAVE_SYS_STATFS_H
+
+/* Define if you have the <sys/statvfs.h> header file. */
+#undef HAVE_SYS_STATVFS_H
+
+/* Define if you have the <sys/vfs.h> header file. */
+#undef HAVE_SYS_VFS_H
+
+/* Define if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define if you have the <utime.h> header file. */
+#undef HAVE_UTIME_H
+
+/* Define if you have the <values.h> header file. */
+#undef HAVE_VALUES_H
+
+/* Define if you have the i library (-li). */
+#undef HAVE_LIBI
+
+/* Define if you have the intl library (-lintl). */
+#undef HAVE_LIBINTL
+
+/* Define if you have the nsl library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the pt library (-lpt). */
+#undef HAVE_LIBPT
+
+/* Define if you have the socket library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+#ifdef HAVE_LIBPT
+# define HAVE_GRANTPT
+#endif
+
+#if defined(HAVE_LIBCRYPT) || defined(HAVE_LIBCRYPT_I)
+# define HAVE_CRYPT
+#endif
+
+#ifdef HAVE_XVIEW
+# include <xvmain.h>
+#endif
+
+#if defined(HAVE_SIGADDSET) && defined(HAVE_SIGEMPTYSET)
+# if defined(HAVE_SIGACTION) && defined(HAVE_SIGPROCMASK)
+# define SLANG_POSIX_SIGNALS
+# endif
+#endif
+
+#ifdef __os2__
+# define OS2_NT 1
+# define S_ISFIFO(x) 0
+#endif
+
+#ifdef _OS_NT
+# define OS2_NT 1
+#endif
+
+#ifndef OS2_NT
+/* some Unices do not define this, and slang requires it: */
+#ifndef unix
+# define unix
+#endif
+#endif
+
--- /dev/null
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host ROSBOX:
+#
+# ./configure --build=mingw32 --host=mingw32 --target=mingw32
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: ./config.status [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running ${CONFIG_SHELL-/bin/sh} ./configure --build=mingw32 --host=mingw32 --target=mingw32 --no-create --no-recursion"
+ exec ${CONFIG_SHELL-/bin/sh} ./configure --build=mingw32 --host=mingw32 --target=mingw32 --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "./config.status generated by autoconf version 2.12"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "$ac_cs_usage"; exit 0 ;;
+ *) echo "$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=.
+ac_given_INSTALL="/usr/bin/install -c"
+
+trap 'rm -fr
+Make.common
+Makefile
+doc/Makefile
+vfs/Makefile
+lib/Makefile
+tk/Makefile
+gnome/Makefile
+xv/Makefile
+src/Makefile
+slang/Makefile
+edit/Makefile
+icons/Makefile
+
+lib/mc.ext
+mcfn_install
+vfs/extfs/ftplist vfs/extfs/zip vfs/extfs/zoo vfs/extfs/lslR
+vfs/extfs/lha vfs/extfs/cpio vfs/extfs/deb vfs/extfs/rar
+
+doc/mc.1 doc/mcedit.1 doc/mcserv.8
+
+intl/Makefile po/Makefile.in
+ config.h conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\&%]/\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+/^[ ]*VPATH[ ]*=[^:]*$/d
+
+s%@CFLAGS@%-g%g
+s%@CPPFLAGS@%-I.. -I$(vfsdir) -I$(rootdir) -I$(slangdir)%g
+s%@CXXFLAGS@%%g
+s%@DEFS@%-DHAVE_CONFIG_H%g
+s%@LDFLAGS@%%g
+s%@LIBS@%-lintl -lcrypt %g
+s%@exec_prefix@%${prefix}%g
+s%@prefix@%/usr/local%g
+s%@program_transform_name@%s,x,x,%g
+s%@bindir@%${exec_prefix}/bin%g
+s%@sbindir@%${exec_prefix}/sbin%g
+s%@libexecdir@%${exec_prefix}/libexec%g
+s%@datadir@%${prefix}/share%g
+s%@sysconfdir@%${prefix}/etc%g
+s%@sharedstatedir@%${prefix}/com%g
+s%@localstatedir@%${prefix}/var%g
+s%@libdir@%${exec_prefix}/lib%g
+s%@includedir@%${prefix}/include%g
+s%@oldincludedir@%/usr/include%g
+s%@infodir@%${prefix}/info%g
+s%@mandir@%${prefix}/man%g
+s%@MC@%%g
+s%@SET_MAKE@%%g
+s%@CC@%gcc%g
+s%@CPP@%gcc -E%g
+s%@RANLIB@%ranlib%g
+s%@LN_S@%ln -s%g
+s%@AWK@%gawk%g
+s%@AWK_VAR_OPTION@%-v%g
+s%@dep@%fastdep%g
+s%@GNU_MAKE@%GNU_MAKE=yes%g
+s%@MV@%/usr/bin/mv%g
+s%@CP@%/usr/bin/cp%g
+s%@RM@%/usr/bin/rm%g
+s%@CHMOD@%/usr/bin/chmod%g
+s%@AR@%/usr/bin/ar%g
+s%@system@%CYGWIN_98-4.10%g
+s%@X11_WWW@%lynx%g
+s%@ALLOCA@%%g
+s%@USE_NLS@%yes%g
+s%@MSGFMT@%/usr/bin/msgfmt%g
+s%@GMSGFMT@%/usr/bin/msgfmt%g
+s%@XGETTEXT@%/usr/bin/xgettext%g
+s%@GENCAT@%%g
+s%@USE_INCLUDED_LIBINTL@%yes%g
+s%@CATALOGS@% es.gmo fr.gmo ru.gmo ko.gmo it.gmo%g
+s%@CATOBJEXT@%.gmo%g
+s%@DATADIRNAME@%share%g
+s%@GMOFILES@% es.gmo fr.gmo ru.gmo ko.gmo it.gmo%g
+s%@INSTOBJEXT@%.mo%g
+s%@INTLDEPS@%$(top_builddir)/intl/libintl.a%g
+s%@INTLLIBS@%$(top_builddir)/intl/libintl.a%g
+s%@INTLOBJS@%$(GETTOBJS)%g
+s%@POFILES@% es.po fr.po ru.po ko.po it.po%g
+s%@POSUB@%po%g
+s%@INCLUDE_LOCALE_H@%#include <locale.h>%g
+s%@GT_NO@%%g
+s%@GT_YES@%#YES#%g
+s%@MKINSTALLDIRS@%$(top_srcdir)/mkinstalldirs%g
+s%@l@%%g
+s%@INSTALL_PROGRAM@%${INSTALL}%g
+s%@INSTALL_DATA@%${INSTALL} -m 644%g
+s%@REGEX_O@%regex.o%g
+s%@LIBOBJS@%%g
+s%@SHADOWLIB@%%g
+s%@X_CFLAGS@% -I/usr/X11R6/include%g
+s%@X_PRE_LIBS@% -lSM -lICE%g
+s%@X_LIBS@% -L/usr/X11R6/lib%g
+s%@X_EXTRA_LIBS@%%g
+s%@XVIEW_CFLAGS@% -DXVIEW_MISSING%g
+s%@XVIEW_CPPFLAGS@%%g
+s%@XVIEW_LIBS@%%g
+s%@HAVE_XVIEW@%no%g
+s%@HAVE_XVIEW_PRIVATE_HEADERS@%yes%g
+s%@insticons@%%g
+s%@mxc@%%g
+s%@xvdep@%%g
+s%@ac_my_xp@%%g
+s%@xv_bindir@%%g
+s%@NETFILES@%$(NETFILES)%g
+s%@XCURSES@%%g
+s%@tkmc@%%g
+s%@tkdep@%%g
+s%@tk_includes@%%g
+s%@tk_libs@%%g
+s%@GNOME_LIBS@%%g
+s%@GNOMEUI_LIBS@%%g
+s%@GTKXMHTML_LIBS@%%g
+s%@GNOME_LIBDIR@%%g
+s%@GNOME_INCLUDEDIR@%%g
+s%@gmc@%%g
+s%@gmcdep@%%g
+s%@HAVE_nroff@%true%g
+s%@MANDOC@%-mandoc%g
+s%@TROFFASCII@% -Tascii%g
+s%@HAVE_FILECMD@%true%g
+s%@INTLSUB@%intl%g
+s%@LINTL@%%g
+s%@LIBSLANG@%libmcslang.a%g
+s%@LSLANG@%-lmcslang%g
+s%@fastdepslang@%fastdepslang%g
+s%@TERMNET@%%g
+s%@LIBVFS@%libvfs.a%g
+s%@LVFS@%-lvfs%g
+s%@fastdepvfs@%fastdepvfs%g
+s%@mcserv@%mcserv%g
+s%@LIBEDIT_A@%libedit.a%g
+s%@MCEDIT@%mcedit%g
+s%@LEDIT@%-ledit%g
+s%@undelfs_o@%%g
+s%@saver_target@%%g
+s%@saver@%%g
+s%@vcs@%%g
+s%@PAMLIBS@%%g
+s%@SEDCMD@%sed 's/-man/-mandoc/'%g
+s%@SEDCMD2@%sed 's%@prefix@%$(prefix)%'%g
+s%@XPM_LIB@%%g
+s%@XEXT_LIB@%%g
+s%@PHONY@%.PHONY:%g
+s%@WRITEDEP@%:%g
+s%@MCFG@%include ../Make.common%g
+s%@MCFGR@%include ./Make.common%g
+s%@DOTDEPEND@%ifeq (.depend,$(wildcard .depend)) \
+include .depend \
+endif%g
+/@MCF@/r /dev/null
+s%@MCF@%%g
+s%@PCENTRULE@%%g
+s%@builddir@%/cygdrive/c/user/src/local/mc-4.1.36-mingw%g
+
+CEOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+
+CONFIG_FILES=${CONFIG_FILES-"Make.common
+Makefile
+doc/Makefile
+vfs/Makefile
+lib/Makefile
+tk/Makefile
+gnome/Makefile
+xv/Makefile
+src/Makefile
+slang/Makefile
+edit/Makefile
+icons/Makefile
+
+lib/mc.ext
+mcfn_install
+vfs/extfs/ftplist vfs/extfs/zip vfs/extfs/zoo vfs/extfs/lslR
+vfs/extfs/lha vfs/extfs/cpio vfs/extfs/deb vfs/extfs/rar
+
+doc/mc.1 doc/mcedit.1 doc/mcserv.8
+
+intl/Makefile po/Makefile.in
+"}
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+ CONFIG_HEADERS="config.h"
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}PACKAGE${ac_dB}PACKAGE${ac_dC}"mc"${ac_dD}
+${ac_uA}PACKAGE${ac_uB}PACKAGE${ac_uC}"mc"${ac_uD}
+${ac_eA}PACKAGE${ac_eB}PACKAGE${ac_eC}"mc"${ac_eD}
+${ac_dA}VERSION${ac_dB}VERSION${ac_dC}"dummy"${ac_dD}
+${ac_uA}VERSION${ac_uB}VERSION${ac_uC}"dummy"${ac_uD}
+${ac_eA}VERSION${ac_eB}VERSION${ac_eC}"dummy"${ac_eD}
+${ac_dA}MAJOR_IN_SYSMACROS${ac_dB}MAJOR_IN_SYSMACROS${ac_dC}1${ac_dD}
+${ac_uA}MAJOR_IN_SYSMACROS${ac_uB}MAJOR_IN_SYSMACROS${ac_uC}1${ac_uD}
+${ac_eA}MAJOR_IN_SYSMACROS${ac_eB}MAJOR_IN_SYSMACROS${ac_eC}1${ac_eD}
+${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD}
+${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD}
+${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_ALLOCA${ac_dB}HAVE_ALLOCA${ac_dC}1${ac_dD}
+${ac_uA}HAVE_ALLOCA${ac_uB}HAVE_ALLOCA${ac_uC}1${ac_uD}
+${ac_eA}HAVE_ALLOCA${ac_eB}HAVE_ALLOCA${ac_eC}1${ac_eD}
+${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GETPAGESIZE${ac_dB}HAVE_GETPAGESIZE${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETPAGESIZE${ac_uB}HAVE_GETPAGESIZE${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETPAGESIZE${ac_eB}HAVE_GETPAGESIZE${ac_eC}1${ac_eD}
+${ac_dA}HAVE_LIMITS_H${ac_dB}HAVE_LIMITS_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_LIMITS_H${ac_uB}HAVE_LIMITS_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_LIMITS_H${ac_eB}HAVE_LIMITS_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_LOCALE_H${ac_dB}HAVE_LOCALE_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_LOCALE_H${ac_uB}HAVE_LOCALE_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_LOCALE_H${ac_eB}HAVE_LOCALE_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_MALLOC_H${ac_dB}HAVE_MALLOC_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MALLOC_H${ac_uB}HAVE_MALLOC_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MALLOC_H${ac_eB}HAVE_MALLOC_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRING_H${ac_dB}HAVE_STRING_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRING_H${ac_uB}HAVE_STRING_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRING_H${ac_eB}HAVE_STRING_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_SYS_PARAM_H${ac_dB}HAVE_SYS_PARAM_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_PARAM_H${ac_uB}HAVE_SYS_PARAM_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_PARAM_H${ac_eB}HAVE_SYS_PARAM_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GETCWD${ac_dB}HAVE_GETCWD${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETCWD${ac_uB}HAVE_GETCWD${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETCWD${ac_eB}HAVE_GETCWD${ac_eC}1${ac_eD}
+${ac_dA}HAVE_MUNMAP${ac_dB}HAVE_MUNMAP${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MUNMAP${ac_uB}HAVE_MUNMAP${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MUNMAP${ac_eB}HAVE_MUNMAP${ac_eC}1${ac_eD}
+${ac_dA}HAVE_PUTENV${ac_dB}HAVE_PUTENV${ac_dC}1${ac_dD}
+${ac_uA}HAVE_PUTENV${ac_uB}HAVE_PUTENV${ac_uC}1${ac_uD}
+${ac_eA}HAVE_PUTENV${ac_eB}HAVE_PUTENV${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_SETENV${ac_dB}HAVE_SETENV${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SETENV${ac_uB}HAVE_SETENV${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SETENV${ac_eB}HAVE_SETENV${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SETLOCALE${ac_dB}HAVE_SETLOCALE${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SETLOCALE${ac_uB}HAVE_SETLOCALE${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SETLOCALE${ac_eB}HAVE_SETLOCALE${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRCHR${ac_dB}HAVE_STRCHR${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRCHR${ac_uB}HAVE_STRCHR${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRCHR${ac_eB}HAVE_STRCHR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRCASECMP${ac_dB}HAVE_STRCASECMP${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRCASECMP${ac_uB}HAVE_STRCASECMP${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRCASECMP${ac_eB}HAVE_STRCASECMP${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_LC_MESSAGES${ac_dB}HAVE_LC_MESSAGES${ac_dC}1${ac_dD}
+${ac_uA}HAVE_LC_MESSAGES${ac_uB}HAVE_LC_MESSAGES${ac_uC}1${ac_uD}
+${ac_eA}HAVE_LC_MESSAGES${ac_eB}HAVE_LC_MESSAGES${ac_eC}1${ac_eD}
+${ac_dA}ENABLE_NLS${ac_dB}ENABLE_NLS${ac_dC}1${ac_dD}
+${ac_uA}ENABLE_NLS${ac_uB}ENABLE_NLS${ac_uC}1${ac_uD}
+${ac_eA}ENABLE_NLS${ac_eB}ENABLE_NLS${ac_eC}1${ac_eD}
+${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRING_H${ac_dB}HAVE_STRING_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRING_H${ac_uB}HAVE_STRING_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRING_H${ac_eB}HAVE_STRING_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_MEMORY_H${ac_dB}HAVE_MEMORY_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MEMORY_H${ac_uB}HAVE_MEMORY_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MEMORY_H${ac_eB}HAVE_MEMORY_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_CRYPT_H${ac_dB}HAVE_CRYPT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_CRYPT_H${ac_uB}HAVE_CRYPT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_CRYPT_H${ac_eB}HAVE_CRYPT_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GRP_H${ac_dB}HAVE_GRP_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GRP_H${ac_uB}HAVE_GRP_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GRP_H${ac_eB}HAVE_GRP_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_LIMITS_H${ac_dB}HAVE_LIMITS_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_LIMITS_H${ac_uB}HAVE_LIMITS_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_LIMITS_H${ac_eB}HAVE_LIMITS_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_MALLOC_H${ac_dB}HAVE_MALLOC_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MALLOC_H${ac_uB}HAVE_MALLOC_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MALLOC_H${ac_eB}HAVE_MALLOC_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STDLIB_H${ac_dB}HAVE_STDLIB_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STDLIB_H${ac_uB}HAVE_STDLIB_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STDLIB_H${ac_eB}HAVE_STDLIB_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_TERMIOS_H${ac_dB}HAVE_TERMIOS_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_TERMIOS_H${ac_uB}HAVE_TERMIOS_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_TERMIOS_H${ac_eB}HAVE_TERMIOS_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SYS_WAIT_H${ac_dB}HAVE_SYS_WAIT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_WAIT_H${ac_uB}HAVE_SYS_WAIT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_WAIT_H${ac_eB}HAVE_SYS_WAIT_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_DIRENT_H${ac_dB}HAVE_DIRENT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_DIRENT_H${ac_uB}HAVE_DIRENT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_DIRENT_H${ac_eB}HAVE_DIRENT_H${ac_eC}1${ac_eD}
+${ac_dA}STDC_HEADERS${ac_dB}STDC_HEADERS${ac_dC}1${ac_dD}
+${ac_uA}STDC_HEADERS${ac_uB}STDC_HEADERS${ac_uC}1${ac_uD}
+${ac_eA}STDC_HEADERS${ac_eB}STDC_HEADERS${ac_eC}1${ac_eD}
+${ac_dA}HAVE_ST_BLKSIZE${ac_dB}HAVE_ST_BLKSIZE${ac_dC}1${ac_dD}
+${ac_uA}HAVE_ST_BLKSIZE${ac_uB}HAVE_ST_BLKSIZE${ac_uC}1${ac_uD}
+${ac_eA}HAVE_ST_BLKSIZE${ac_eB}HAVE_ST_BLKSIZE${ac_eC}1${ac_eD}
+${ac_dA}HAVE_ST_BLOCKS${ac_dB}HAVE_ST_BLOCKS${ac_dC}1${ac_dD}
+${ac_uA}HAVE_ST_BLOCKS${ac_uB}HAVE_ST_BLOCKS${ac_uC}1${ac_uD}
+${ac_eA}HAVE_ST_BLOCKS${ac_eB}HAVE_ST_BLOCKS${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_ST_RDEV${ac_dB}HAVE_ST_RDEV${ac_dC}1${ac_dD}
+${ac_uA}HAVE_ST_RDEV${ac_uB}HAVE_ST_RDEV${ac_uC}1${ac_uD}
+${ac_eA}HAVE_ST_RDEV${ac_eB}HAVE_ST_RDEV${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRERROR${ac_dB}HAVE_STRERROR${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRERROR${ac_uB}HAVE_STRERROR${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRERROR${ac_eB}HAVE_STRERROR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STATFS${ac_dB}HAVE_STATFS${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STATFS${ac_uB}HAVE_STATFS${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STATFS${ac_eB}HAVE_STATFS${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GETWD${ac_dB}HAVE_GETWD${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETWD${ac_uB}HAVE_GETWD${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETWD${ac_eB}HAVE_GETWD${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_STRCASECMP${ac_dB}HAVE_STRCASECMP${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRCASECMP${ac_uB}HAVE_STRCASECMP${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRCASECMP${ac_eB}HAVE_STRCASECMP${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRNCASECMP${ac_dB}HAVE_STRNCASECMP${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRNCASECMP${ac_uB}HAVE_STRNCASECMP${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRNCASECMP${ac_eB}HAVE_STRNCASECMP${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRDUP${ac_dB}HAVE_STRDUP${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRDUP${ac_uB}HAVE_STRDUP${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRDUP${ac_eB}HAVE_STRDUP${ac_eC}1${ac_eD}
+${ac_dA}HAVE_MEMMOVE${ac_dB}HAVE_MEMMOVE${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MEMMOVE${ac_uB}HAVE_MEMMOVE${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MEMMOVE${ac_eB}HAVE_MEMMOVE${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_TRUNCATE${ac_dB}HAVE_TRUNCATE${ac_dC}1${ac_dD}
+${ac_uA}HAVE_TRUNCATE${ac_uB}HAVE_TRUNCATE${ac_uC}1${ac_uD}
+${ac_eA}HAVE_TRUNCATE${ac_eB}HAVE_TRUNCATE${ac_eC}1${ac_eD}
+${ac_dA}HAVE_INITGROUPS${ac_dB}HAVE_INITGROUPS${ac_dC}1${ac_dD}
+${ac_uA}HAVE_INITGROUPS${ac_uB}HAVE_INITGROUPS${ac_uC}1${ac_uD}
+${ac_eA}HAVE_INITGROUPS${ac_eB}HAVE_INITGROUPS${ac_eC}1${ac_eD}
+${ac_dA}HAVE_PUTENV${ac_dB}HAVE_PUTENV${ac_dC}1${ac_dD}
+${ac_uA}HAVE_PUTENV${ac_uB}HAVE_PUTENV${ac_uC}1${ac_uD}
+${ac_eA}HAVE_PUTENV${ac_eB}HAVE_PUTENV${ac_eC}1${ac_eD}
+${ac_dA}HAVE_MEMSET${ac_dB}HAVE_MEMSET${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MEMSET${ac_uB}HAVE_MEMSET${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MEMSET${ac_eB}HAVE_MEMSET${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_MEMCPY${ac_dB}HAVE_MEMCPY${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MEMCPY${ac_uB}HAVE_MEMCPY${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MEMCPY${ac_eB}HAVE_MEMCPY${ac_eC}1${ac_eD}
+${ac_dA}HAVE_TCSETATTR${ac_dB}HAVE_TCSETATTR${ac_dC}1${ac_dD}
+${ac_uA}HAVE_TCSETATTR${ac_uB}HAVE_TCSETATTR${ac_uC}1${ac_uD}
+${ac_eA}HAVE_TCSETATTR${ac_eB}HAVE_TCSETATTR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_TCGETATTR${ac_dB}HAVE_TCGETATTR${ac_dC}1${ac_dD}
+${ac_uA}HAVE_TCGETATTR${ac_uB}HAVE_TCGETATTR${ac_uC}1${ac_uD}
+${ac_eA}HAVE_TCGETATTR${ac_eB}HAVE_TCGETATTR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_CFGETOSPEED${ac_dB}HAVE_CFGETOSPEED${ac_dC}1${ac_dD}
+${ac_uA}HAVE_CFGETOSPEED${ac_uB}HAVE_CFGETOSPEED${ac_uC}1${ac_uD}
+${ac_eA}HAVE_CFGETOSPEED${ac_eB}HAVE_CFGETOSPEED${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_SIGACTION${ac_dB}HAVE_SIGACTION${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SIGACTION${ac_uB}HAVE_SIGACTION${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SIGACTION${ac_eB}HAVE_SIGACTION${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SIGEMPTYSET${ac_dB}HAVE_SIGEMPTYSET${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SIGEMPTYSET${ac_uB}HAVE_SIGEMPTYSET${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SIGEMPTYSET${ac_eB}HAVE_SIGEMPTYSET${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SIGPROCMASK${ac_dB}HAVE_SIGPROCMASK${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SIGPROCMASK${ac_uB}HAVE_SIGPROCMASK${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SIGPROCMASK${ac_eB}HAVE_SIGPROCMASK${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SIGADDSET${ac_dB}HAVE_SIGADDSET${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SIGADDSET${ac_uB}HAVE_SIGADDSET${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SIGADDSET${ac_eB}HAVE_SIGADDSET${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_SYSCONF${ac_dB}HAVE_SYSCONF${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYSCONF${ac_uB}HAVE_SYSCONF${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYSCONF${ac_eB}HAVE_SYSCONF${ac_eC}1${ac_eD}
+${ac_dA}NEED_CRYPT_PROTOTYPE${ac_dB}NEED_CRYPT_PROTOTYPE${ac_dC}1${ac_dD}
+${ac_uA}NEED_CRYPT_PROTOTYPE${ac_uB}NEED_CRYPT_PROTOTYPE${ac_uC}1${ac_uD}
+${ac_eA}NEED_CRYPT_PROTOTYPE${ac_eB}NEED_CRYPT_PROTOTYPE${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SYS_SELECT_H${ac_dB}HAVE_SYS_SELECT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_SELECT_H${ac_uB}HAVE_SYS_SELECT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_SELECT_H${ac_eB}HAVE_SYS_SELECT_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GRANTPT${ac_dB}HAVE_GRANTPT${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GRANTPT${ac_uB}HAVE_GRANTPT${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GRANTPT${ac_eB}HAVE_GRANTPT${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_LIBINTL${ac_dB}HAVE_LIBINTL${ac_dC}1${ac_dD}
+${ac_uA}HAVE_LIBINTL${ac_uB}HAVE_LIBINTL${ac_uC}1${ac_uD}
+${ac_eA}HAVE_LIBINTL${ac_eB}HAVE_LIBINTL${ac_eC}1${ac_eD}
+${ac_dA}HAVE_FCNTL_H${ac_dB}HAVE_FCNTL_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_FCNTL_H${ac_uB}HAVE_FCNTL_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_FCNTL_H${ac_eB}HAVE_FCNTL_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SYS_PARAM_H${ac_dB}HAVE_SYS_PARAM_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_PARAM_H${ac_uB}HAVE_SYS_PARAM_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_PARAM_H${ac_eB}HAVE_SYS_PARAM_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_MNTENT_H${ac_dB}HAVE_MNTENT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_MNTENT_H${ac_uB}HAVE_MNTENT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_MNTENT_H${ac_eB}HAVE_MNTENT_H${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_UTIME_H${ac_dB}HAVE_UTIME_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_UTIME_H${ac_uB}HAVE_UTIME_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_UTIME_H${ac_eB}HAVE_UTIME_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SYS_VFS_H${ac_dB}HAVE_SYS_VFS_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_VFS_H${ac_uB}HAVE_SYS_VFS_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_VFS_H${ac_eB}HAVE_SYS_VFS_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SYS_MOUNT_H${ac_dB}HAVE_SYS_MOUNT_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SYS_MOUNT_H${ac_uB}HAVE_SYS_MOUNT_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SYS_MOUNT_H${ac_eB}HAVE_SYS_MOUNT_H${ac_eC}1${ac_eD}
+${ac_dA}D_INO_IN_DIRENT${ac_dB}D_INO_IN_DIRENT${ac_dC}1${ac_dD}
+${ac_uA}D_INO_IN_DIRENT${ac_uB}D_INO_IN_DIRENT${ac_uC}1${ac_uD}
+${ac_eA}D_INO_IN_DIRENT${ac_eB}D_INO_IN_DIRENT${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_GETMNTENT${ac_dB}HAVE_GETMNTENT${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETMNTENT${ac_uB}HAVE_GETMNTENT${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETMNTENT${ac_eB}HAVE_GETMNTENT${ac_eC}1${ac_eD}
+${ac_dA}MOUNTED_GETMNTENT1${ac_dB}MOUNTED_GETMNTENT1${ac_dC}1${ac_dD}
+${ac_uA}MOUNTED_GETMNTENT1${ac_uB}MOUNTED_GETMNTENT1${ac_uC}1${ac_uD}
+${ac_eA}MOUNTED_GETMNTENT1${ac_eB}MOUNTED_GETMNTENT1${ac_eC}1${ac_eD}
+${ac_dA}STAT_STATFS2_BSIZE${ac_dB}STAT_STATFS2_BSIZE${ac_dC}1${ac_dD}
+${ac_uA}STAT_STATFS2_BSIZE${ac_uB}STAT_STATFS2_BSIZE${ac_uC}1${ac_uD}
+${ac_eA}STAT_STATFS2_BSIZE${ac_eB}STAT_STATFS2_BSIZE${ac_eC}1${ac_eD}
+${ac_dA}umode_t${ac_dB}umode_t${ac_dC}int${ac_dD}
+${ac_uA}umode_t${ac_uB}umode_t${ac_uC}int${ac_uD}
+${ac_eA}umode_t${ac_eB}umode_t${ac_eC}int${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_UNISTD_H${ac_dB}HAVE_UNISTD_H${ac_dC}1${ac_dD}
+${ac_uA}HAVE_UNISTD_H${ac_uB}HAVE_UNISTD_H${ac_uC}1${ac_uD}
+${ac_eA}HAVE_UNISTD_H${ac_eB}HAVE_UNISTD_H${ac_eC}1${ac_eD}
+${ac_dA}HAVE_GETPAGESIZE${ac_dB}HAVE_GETPAGESIZE${ac_dC}1${ac_dD}
+${ac_uA}HAVE_GETPAGESIZE${ac_uB}HAVE_GETPAGESIZE${ac_uC}1${ac_uD}
+${ac_eA}HAVE_GETPAGESIZE${ac_eB}HAVE_GETPAGESIZE${ac_eC}1${ac_eD}
+${ac_dA}HAVE_ALLOCA${ac_dB}HAVE_ALLOCA${ac_dC}1${ac_dD}
+${ac_uA}HAVE_ALLOCA${ac_uB}HAVE_ALLOCA${ac_uC}1${ac_uD}
+${ac_eA}HAVE_ALLOCA${ac_eB}HAVE_ALLOCA${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SOCKET${ac_dB}HAVE_SOCKET${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SOCKET${ac_uB}HAVE_SOCKET${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SOCKET${ac_eB}HAVE_SOCKET${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}HAVE_SOCKETPAIR${ac_dB}HAVE_SOCKETPAIR${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SOCKETPAIR${ac_uB}HAVE_SOCKETPAIR${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SOCKETPAIR${ac_eB}HAVE_SOCKETPAIR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_STRUCT_LINGER${ac_dB}HAVE_STRUCT_LINGER${ac_dC}1${ac_dD}
+${ac_uA}HAVE_STRUCT_LINGER${ac_uB}HAVE_STRUCT_LINGER${ac_uC}1${ac_uD}
+${ac_eA}HAVE_STRUCT_LINGER${ac_eB}HAVE_STRUCT_LINGER${ac_eC}1${ac_eD}
+${ac_dA}HAVE_RRESVPORT${ac_dB}HAVE_RRESVPORT${ac_dC}1${ac_dD}
+${ac_uA}HAVE_RRESVPORT${ac_uB}HAVE_RRESVPORT${ac_uC}1${ac_uD}
+${ac_eA}HAVE_RRESVPORT${ac_eB}HAVE_RRESVPORT${ac_eC}1${ac_eD}
+${ac_dA}FILE_STDIN${ac_dB}FILE_STDIN${ac_dC}1${ac_dD}
+${ac_uA}FILE_STDIN${ac_uB}FILE_STDIN${ac_uC}1${ac_uD}
+${ac_eA}FILE_STDIN${ac_eB}FILE_STDIN${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}FILE_L${ac_dB}FILE_L${ac_dC}1${ac_dD}
+${ac_uA}FILE_L${ac_uB}FILE_L${ac_uC}1${ac_uD}
+${ac_eA}FILE_L${ac_eB}FILE_L${ac_eC}1${ac_eD}
+${ac_dA}GREP_STDIN${ac_dB}GREP_STDIN${ac_dC}1${ac_dD}
+${ac_uA}GREP_STDIN${ac_uB}GREP_STDIN${ac_uC}1${ac_uD}
+${ac_eA}GREP_STDIN${ac_eB}GREP_STDIN${ac_eC}1${ac_eD}
+${ac_dA}HAVE_DUSUM${ac_dB}HAVE_DUSUM${ac_dC}1${ac_dD}
+${ac_uA}HAVE_DUSUM${ac_uB}HAVE_DUSUM${ac_uC}1${ac_uD}
+${ac_eA}HAVE_DUSUM${ac_eB}HAVE_DUSUM${ac_eC}1${ac_eD}
+${ac_dA}DUSUM_USEB${ac_dB}DUSUM_USEB${ac_dC}1${ac_dD}
+${ac_uA}DUSUM_USEB${ac_uB}DUSUM_USEB${ac_uC}1${ac_uD}
+${ac_eA}DUSUM_USEB${ac_eB}DUSUM_USEB${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}DUSUM_FACTOR${ac_dB}DUSUM_FACTOR${ac_dC}1${ac_dD}
+${ac_uA}DUSUM_FACTOR${ac_uB}DUSUM_FACTOR${ac_uC}1${ac_uD}
+${ac_eA}DUSUM_FACTOR${ac_eB}DUSUM_FACTOR${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SUBSHELL_SUPPORT${ac_dB}HAVE_SUBSHELL_SUPPORT${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SUBSHELL_SUPPORT${ac_uB}HAVE_SUBSHELL_SUPPORT${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SUBSHELL_SUPPORT${ac_eB}HAVE_SUBSHELL_SUPPORT${ac_eC}1${ac_eD}
+${ac_dA}USE_VFS${ac_dB}USE_VFS${ac_dC}1${ac_dD}
+${ac_uA}USE_VFS${ac_uB}USE_VFS${ac_uC}1${ac_uD}
+${ac_eA}USE_VFS${ac_eB}USE_VFS${ac_eC}1${ac_eD}
+${ac_dA}USE_NETCODE${ac_dB}USE_NETCODE${ac_dC}1${ac_dD}
+${ac_uA}USE_NETCODE${ac_uB}USE_NETCODE${ac_uC}1${ac_uD}
+${ac_eA}USE_NETCODE${ac_eB}USE_NETCODE${ac_eC}1${ac_eD}
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ cat > conftest.frag <<CEOF
+${ac_dA}USE_INTERNAL_EDIT${ac_dB}USE_INTERNAL_EDIT${ac_dC}1${ac_dD}
+${ac_uA}USE_INTERNAL_EDIT${ac_uB}USE_INTERNAL_EDIT${ac_uC}1${ac_uD}
+${ac_eA}USE_INTERNAL_EDIT${ac_eB}USE_INTERNAL_EDIT${ac_eC}1${ac_eD}
+${ac_dA}HAVE_SLANG${ac_dB}HAVE_SLANG${ac_dC}1${ac_dD}
+${ac_uA}HAVE_SLANG${ac_uB}HAVE_SLANG${ac_uC}1${ac_uD}
+${ac_eA}HAVE_SLANG${ac_eB}HAVE_SLANG${ac_eC}1${ac_eD}
+${ac_dA}SLANG_TERMINFO${ac_dB}SLANG_TERMINFO${ac_dC}1${ac_dD}
+${ac_uA}SLANG_TERMINFO${ac_uB}SLANG_TERMINFO${ac_uC}1${ac_uD}
+${ac_eA}SLANG_TERMINFO${ac_eB}SLANG_TERMINFO${ac_eC}1${ac_eD}
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+ac_sources="intl/libgettext.h"
+ac_dests="intl/libintl.h"
+srcdir=$ac_given_srcdir
+while test -n "$ac_sources"; do
+ set $ac_dests; ac_dest=$1; shift; ac_dests=$*
+ set $ac_sources; ac_source=$1; shift; ac_sources=$*
+
+ echo "linking $srcdir/$ac_source to $ac_dest"
+
+ if test ! -r $srcdir/$ac_source; then
+ { echo "configure: error: $srcdir/$ac_source: File not found" 1>&2; exit 1; }
+ fi
+ rm -f $ac_dest
+
+ # Make relative symlinks.
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dest_dir=`echo $ac_dest|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dest_dir" != "$ac_dest" && test "$ac_dest_dir" != .; then
+ # The dest file is in a subdirectory.
+ test ! -d "$ac_dest_dir" && mkdir "$ac_dest_dir"
+ ac_dest_dir_suffix="/`echo $ac_dest_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dest_dir_suffix.
+ ac_dots=`echo $ac_dest_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dest_dir_suffix= ac_dots=
+ fi
+
+ case "$srcdir" in
+ [/$]*) ac_rel_source="$srcdir/$ac_source" ;;
+ *) ac_rel_source="$ac_dots$srcdir/$ac_source" ;;
+ esac
+
+ # Make a symlink if possible; otherwise try a hard link.
+ if ln -s $ac_rel_source $ac_dest 2>/dev/null ||
+ ln $srcdir/$ac_source $ac_dest; then :
+ else
+ { echo "configure: error: can not link $ac_dest to $srcdir/$ac_source" 1>&2; exit 1; }
+ fi
+done
+
+sed -e "/POTFILES =/r po/POTFILES" po/Makefile.in > po/Makefile
+exit 0
--- /dev/null
+#!/bin/sh
+#
+# Script by Jakub Jelinek
+#
+if test -e /dev/vcs0
+then
+ exit
+fi
+
+I=0
+while [ $I -lt 64 ]
+do
+ mknod /dev/vcs$I c 7 $I
+ chmod 622 /dev/vcs$I
+ chown root.tty /dev/vcs$I
+ mknod /dev/vcsa$I c 7 `expr $I + 128`
+ chmod 622 /dev/vcsa$I
+ chown root.tty /dev/vcsa$I
+ I=`expr $I + 1`
+done
--- /dev/null
+
+ Midnight Commander
+ Questions and Answers
+
+ The newest version of this document is available at
+ http://mc.blackdown.org/mc/answers0.html
+
+ * 1 Getting started
+ + 1.1 What is Midnight Commander?
+ + 1.2 [UPDATED] Does it run on my machine?
+ + 1.3 Does it work with my terminal?
+ + 1.4 What else do I need to run MC?
+ + 1.5 Is Midnight Commander PD? Copyrighted?
+ + 1.6 Where can I get Midnight Commander?
+ + 1.7 I don't have FTP access. Where can I get MC?
+ * 2 Keyboard
+ + 2.1 What does documentation mean with the C-?, M-? and F?
+ keys?
+ + 2.2 [UPDATED] Why don't function keys (or some other key)
+ work?
+ + 2.3 How do I use function keys F11 to F20?
+ + 2.4 Why does the ESC key behave funny?
+ + 2.5 How can I add the plus sign (+) on the command line?
+ * 3 Mouse
+ + 3.1 How do I enable mouse support?
+ + 3.2 How do I cut and paste text with mouse?
+ * 4 Display
+ + 4.1 Why do I keep getting "Terminal not powerful enough for
+ SLang"?
+ + 4.2 [UPDATED] Why don't line drawing characters work?
+ + 4.3 Can one use latin-1 characters without losing the lines?
+ + 4.4 I have problems with entering/viewing national
+ characters!
+ + 4.5 How can I get colors?
+ + 4.6 My color_xterm goes completely (or partially) black!
+ + 4.7 Where can I get color_xterm?
+ + 4.8 I got colors working with MC but the other programs don't
+ work at all anymore!
+ + 4.9 Why are there both terminfo and termcap? Wouldn't one
+ database be enough?
+ * 5 Graphical user interface
+ + 5.1 Xview and Tk editions?
+ * 6 Command line problems
+ + 6.1 How do I stay in the last directory when I exit Midnight
+ Commander?
+ + 6.2 How can I access command line history?
+ + 6.3 How can I complete commands, file names, variable names
+ and so on?
+ + 6.4 [NEW] I am using ksh. Can I use functions defined in the
+ .kshrc within MC?
+ + 6.5 [NEW] Is there any way to include additional options or
+ hot keys to MC?
+ * 7 Virtual file systems
+ + 7.1 How can I see the contents of a tar archive?
+ + 7.2 How do I get out of a tar archive?
+ + 7.3 How do I do anonymous ftp with MC?
+ + 7.4 How do I do non-anonymous ftp with MC?
+ + 7.5 How do I close an ftp connection?
+ + 7.6 Why aren't the contents of ftp panel updated?
+ + 7.7 [NEW] What kind of proxy server works with Midnight
+ Commander?
+ * 8 Other common problems
+ + 8.1 [UPDATED] How do I get the internal editor to work?
+ + 8.2 Why doesn't "mcedit newfile" work?
+ + 8.3 [UPDATED] Is there any way to 'bookmark' favourite ftp-fs
+ links?
+ + 8.4 When copying the directories lose their original date,
+ uid and gid!
+ + 8.5 [UPDATED] Why I keep getting: "There is no disk in the
+ drive. Please insert a disk into drive D:"?
+ + 8.6 [NEW] When I start Midnight Commander, nothing happens!
+ + 8.7 [NEW] When I try to view a file MC hangs!
+ * 9 Development
+ + 9.1 Who has written Midnight Commander?
+ + 9.2 Do I dare to use a development version?
+ + 9.3 How can I report a bug/request for a feature?
+ + 9.4 How can I join the development?
+ * 10 More information
+ + 10.1 [UPDATED] This document didn't answer my question. Where
+ else can I look for an answer?
+ + 10.2 What mailing lists are there for Midnight Commander?
+ + 10.3 Where should I look on the World Wide Web for MC stuff?
+ + 10.4 Are the mailing lists archived anywhere?
+ * 11 Administrivia
+ + 11.1 Authorship
+ + 11.2 [UPDATED] File formats
+ + 11.3 Feedback is invited
+ + 11.4 Disclaimer and copyright
+
+1 Getting started
+
+ 1.1 What is Midnight Commander?
+
+ The Midnight Commander is a user-friendly yet powerful file manager
+ and visual shell, useful to novice and guru alike. It provides a
+ clear, user-friendly, and somewhat protected interface to a Unix
+ system while making many frequent file operations more efficient and
+ preserving the full power of the command prompt. You will wonder how
+ you could ever live without it.
+
+ For more thorough description take a look at the announcement of
+ Midnight Commander 4.0.
+
+ 1.2 [UPDATED] Does it run on my machine?
+
+ Yes, Midnight Commander can run on almost any machine, including Unix
+ clones, Windows 95/NT and OS/2. Midnight Commander does not run on
+ Macintosh.
+
+ Midnight Commander uses GNU autoconfigure which can automatically
+ configure Midnight Commander for use on almost any (if not every) Unix
+ clone. Following configurations have been tested:
+ * i386-*-linux1.x, 2.x
+ * alpha-linux-linux2
+ * sparc-linux-linux2.x
+ * sparc64-linux-linux2.1
+ * mips-sgi-irix5.x, 6.x
+ * mips-dec-ultrix4.3
+ * rs6000-ibm-aix3.2.5
+ * sparc-sun-sunos4.1
+ * sparc-sun-solaris2.3, 2.4, 2.5
+ * sparc-sun-netbsd1.0
+ * hppa-hp-hpux9
+ * hppa-hp-hpux7
+ * m68k-apple-aux
+ * unixware
+ * mc88110-aviion-dgux5.4R2.01
+ * i386-*-sco3.2v4.2
+ * i386-*-sco3.2v5
+ * i386-*-windows-nt-3.51, 4.0
+ * i386-*-windows95
+ * i386-*-os2
+
+ See http://mc.blackdown.org/mc/download.html.
+
+ There is also a preliminary Ms-Dos port at
+ http://mc.blackdown.org/cgi-mc/download/DOS/.html (but no Ms-Dos
+ binary).
+
+ Windows 95/NT port is compiled with Microsoft Visual C++ but it might
+ be possible to use cygwin32 or djgpp instead.
+
+ 1.3 Does it work with my terminal?
+
+ Yes, it does.
+
+ Because Midnight Commander is a full screen program it doesn't run on
+ dummy terminals but anything more advanced will do (like vt100). If
+ your terminal works with vi, emacs, elm or pine it will work with
+ Midnight Commander.
+
+ The XView and Tk editions currently under development will require an
+ X terminal.
+
+ 1.4 What else do I need to run MC?
+
+ You need an Unix compatible operating system or Windows 95/NT or OS/2.
+
+ If you want to use mouse on the Linux console you need General Purpose
+ Mouse server from iride.unipv.it: /pub/gpm/. You need nothing extra to
+ use mouse on xterm.
+
+ To compile the XView edition (currently under development) you need
+ XView library. Xpm library and X11 non-rectangular shape extensions
+ are recommended.
+
+ To compile the Tk edition (currently under development) you need
+ Tk-4.0 libraries. Compilation of the Tk version won't be easy. Contact
+ Miguel for details.
+
+ If you do not want to use the slang library you could try using
+ ncurses (we recommend only version 4.1 and above).
+
+ You can get it along with other curses libraries, too, but results may
+ not be pretty or even usable.
+
+ 1.5 Is Midnight Commander PD? Copyrighted?
+
+ Midnight Commander is under GNU Public License which basically means
+ that you may freely copy, change and distribute it, but that you may
+ not impose any restrictions on further distribution, and that you must
+ make the source code available. This is not the same as Public Domain.
+ For details, the GNU license is included in the Midnight Commander
+ source distribution (the COPYING file).
+
+ Midnight Commander is nowadays officially a part of GNU project. All
+ the authors of the Midnight Commander have given all their rights on
+ the program to the Free Software Foundation.
+
+ 1.6 Where can I get Midnight Commander?
+
+ See http://mc.blackdown.org/mc/download.html. There are about seventy
+ download sites. Note that the newest files might not be present on all
+ the download sites yet.
+
+ In short: the main site is ftp://ftp.nuclecu.unam.mx/linux/local/ and
+ the sunsite.unc.edu mirrors have MC in the
+ /pub/Linux/utils/file/managers/mc directory.
+
+ 1.7 I don't have FTP access. Where can I get MC?
+
+ Most Linux CD-ROMs include Midnight Commander. For example, Slackware,
+ Yggdrasil, S.U.S.E., Jurix, RedHat, Caldera and Debian.
+
+2 Keyboard
+
+ 2.1 What does documentation mean with the C-?, M-? and F? keys?
+
+ Midnight Commander documentation uses emacs style names for keyboard
+ keys.
+
+ C stands for the Ctrl key. For example, C-f means that you should hold
+ down the Ctrl key and press the f key.
+
+ M stands for the Meta key. Your terminal might call it Alt or Compose
+ instead of Meta. For example, M-f means that you should hold down the
+ Meta/Alt/Compose key and press the f key. If your terminal doesn't
+ have Meta, Alt or Compose or they don't work you can use Esc. For M-f
+ press the Esc key and then press the f key.
+
+ F? stands for a function key. If your terminal doesn't have function
+ keys or they don't work you can use Esc. For example, for F3 press the
+ Esc key and then press the 3 key.
+
+ 2.2 [UPDATED] Why don't function keys (or some other key) work?
+
+ Your terminfo or termcap database has missing or incorrect definations
+ for function keys. Type "mc -V" to see what terminal database is being
+ used. If the result is "using the S-Lang library with terminfo
+ database" you should install one of the enhanced terminfo databases
+ included in the Midnight Commander source distribution. For example,
+ if you are using xterm type "tic xterm.ti".
+
+ If the result is "using the S-Lang library with termcap database" you
+ should fix your /etc/termcap database.
+
+ Best terminfo database is bundled with ncurses 4.2
+
+ You can select whether Midnight Commander will use terminfo or termcap
+ database by giving --with-terminfo or --with-termcap option to the
+ configure. Default is terminfo if found, otherwise termcap.
+
+ If you don't have permissions to edit terminal databases you can use
+ Learn keys feature of Midnight Commander instead. Press Esc 9 o k and
+ follow instructions.
+
+ If all else fails you can emulate function keys by first pressing the
+ ESC key and then one of the number keys. For example, if you want to
+ produce F9, press ESC, then 9. If you don't have a ESC key on your
+ keyboard you can try alt-9 or meta-9.
+
+ 2.3 How do I use function keys F11 to F20?
+
+ These can mapped to function keys F1 to F10 with Shift held. eg.
+ function key F13 can be activated by pressing Shift-F3. You can define
+ the keys this way in the Options menu. The convention for PC keyboards
+ is that F11-20 always means Shift with F1-10
+
+ Note! Windows 95/NT and OS/2 ports use F11 and F12 keys to change the
+ current disk drive. In this case F11 and F12 mean the real F11 and F12
+ keys, not shift-F1 and shift-F2.
+
+ 2.4 Why does the ESC key behave funny?
+
+ Midnight Commander uses the ESC key as a prefix for simulating the
+ Meta and Alt keys (for terminals which don't have Meta or Alt, see the
+ three previous questions). For example, pressing ESC-a is the same as
+ pressing Meta-a. In addition most terminals use ESC for internal
+ representation of arrow keys, function keys and other enhanced keys.
+ If you want to use ESC to cancel things you have to press it twice i.
+ e. ESC-ESC. If you find this cumbersome you can generally use F10 to
+ cancel. Alternatively turn on the old_esc_mode setting in the
+ ~/.mc.ini file. The old_esc_mode setting makes ESC work as a prefix
+ only if another key is pressed within 0.5 seconds. After 0.5 seconds
+ the ESC key cancels. There is no way to make ESC cancel immediately
+ (if we want to be able to use arrows keys and function keys).
+
+ X terminals allow more control over keyboard, so these ESC limitations
+ might not concern the forthcoming XView and Tk editions of the
+ Midnight Commander.
+
+ 2.5 How can I add the plus sign (+) on the command line?
+
+ Press C-q first, then press the + sign.
+
+ The plus key is the hotkey for the select files command. If you want
+ to add a literal plus on to the command line you must quote it by
+ pressing C-q first.
+
+ Another common key which needs the C-q prefix is backslash "\".
+
+3 Mouse
+
+ 3.1 How do I enable mouse support?
+
+ Invoke mc like this (without quotes): "mc -x". If this doesn't work
+ upgrade to a terminal which compatible with the Xterm mouse sequences.
+
+ Alternatively, on Linux console you can use GPM.
+
+ 3.2 How do I cut and paste text with mouse?
+
+ Hold down shift key while using mouse to cut'n'paste.
+
+4 Display
+
+ 4.1 Why do I keep getting "Terminal not powerful enough for SLang"?
+
+ This means that your terminfo databases do not contain the correct
+ definitions for your terminal.
+
+ You could try using a different terminal setting. If you use csh or
+ tcsh:
+
+ setenv TERM vt100
+
+ or if you use sh, bash, ksh or zsh:
+
+ export TERM=vt100
+
+ If this doesn't help you can recompile MC to use termcap instead of
+ terminfo:
+
+ ./configure --with-termcap
+ make
+
+ 4.2 [UPDATED] Why don't line drawing characters work?
+
+ Since version 4.0.13 there's the commandline option -a to force use of
+ +, |, - for line drawing (only available when compiled with SLang).
+ Use this -a option if any of the suggestions below doesn't help.
+
+ In general, there are three subcases:
+ * Lines are shown as ASCII characters like this
+
+ +---------+
+ | |
+ +---------+
+ This also happens when you use the -a option. Other than that possible
+ reason is 1, 2 or 3 (see below).
+ * Lines are shown as lower case characters like this
+
+ lqqqqqqqqqk
+ x x
+ mqqqqqqqqqj
+ Possible reason is 2 or 3 (see below).
+ * Lines are shown as blanks or missing characters. Possible reason
+ is 3 or 4 (see below).
+
+ The reason for the problem is one of following:
+ 1. Your curses library might not support line drawing characters.
+ Slang, Ncurses and System V curses do support them, BSD curses
+ doesn't. MC uses Slang by default so this is not usually a
+ problem.
+ 2. Your terminal might not support line drawing characters. Vt100
+ compatible terminals, rxvt, xterm and color_xterm do support them.
+ 3. Your terminfo or termcap database might have missing or incorrect
+ definations for line drawing characters. Set the acsc variable in
+ the terminfo database like this:
+ acsc=a\376k\277l\332m\300j\331n\305w\302v\301u\264t\303q\304x\263h
+ \2600\333
+ Don't forget issue 'tic' command. This supposes you are using pc
+ character set. The octal values might be different for other
+ character sets. If you are using termcap instead of terminfo, you
+ should modify above solution appropriately.
+ 4. Your terminal font might not support line drawing characters. Try
+ changing the font.
+
+ Here is Miguel's answer to Torben on this subject.
+
+ Torben:
+
+ When I load consolefonts/iso01.f16, I get perfectly right national
+ characters, but the line drawing characters in mc get wrong. Is it
+ a mc problem, or is it a problem with the font? (I guess it is).
+
+ Is there a trick?
+
+ Miguel:
+
+ First of all, we should determine whether the font has line drawing
+ characters or not.
+
+ If it has line drawing characters, then a new terminfo entry should
+ be written for this specific case. Let's call this linux-iso01. The
+ acsc variable should be modified to reflect which characters are
+ used to do the line drawing.
+
+ If it does not have line drawing characters, then we should get rid
+ of the switch to acsc sequences and make the acsc sequence be just
+ a mapping to the ugly +, -, |, - characters.
+
+ You can get your terminfo definition by running the infocmp
+ program, making the proper changes and running the tic program to
+ compile your new terminfo database.
+
+ 4.3 Can one use latin-1 characters without losing the lines?
+
+ Yes, you need a correct font and a correct termcap/terminfo database.
+
+ For font, if you use xterm try "xterm -fn fixed".
+
+ For termcap/terminfo database, change the acsc capability in the
+ database.
+
+ 4.4 I have problems with entering/viewing national characters!
+
+ Upgrade to version 4.0.12 or newer.
+
+ From the Options - Display Bits dialog select Full 8 bits or ISO
+ 8859-1. In addition, select 8 bit input from the same dialog.
+
+ 4.5 How can I get colors?
+
+ Invoke mc like this (without quotes): "mc -c".
+
+ If you get colors, be happy.
+
+ If your terminal stays black and white, your terminal doesn't support
+ color. You might want to upgrade to a terminal which compatible with
+ the ANSI color sequences.
+
+ If your terminal goes compelety black, see the next question.
+
+ More detailed answer:
+
+ First, check that your terminal supports color. Color_xterm, rxvt and
+ Linux console do support, most other terminals don't. You can test
+ color support with following simple C program:
+
+ #include <stdio.h>
+
+ int main (void){
+ printf ("\033[32m Hello world! \033[m\n");
+ return 0;
+ }
+
+ Compile and run it. If you see "Hello world!" text in green your
+ terminal supports color, otherwise not (however, for color_xterm see
+ also the next question).
+
+ Second, check that you are using Ncurses or the Slang library (type
+ "mc -V" to find out), in addition some System V curses implementations
+ do support color, most don't.
+
+ With Slang library you can force color support by setting the
+ environment variable COLORTERM to any value.
+
+ Third, if you use ncurses library, check that your terminfo database
+ supports color. If not you should install one of the enhanced terminfo
+ databases included in the Midnight Commander source distribution.
+
+ Fourth, you might want to set the TERM environment variable so that
+ you use the correct terminfo database or termcap entry.
+
+ If you use color_xterm (or rxvt) the correct value might be
+ xterm-color, xtermc or simply xterm.
+
+ If you use Linux console the correct value for TERM is linux or
+ console.
+
+ 4.6 My color_xterm goes completely (or partially) black!
+
+ Some color_xterm terminals define all colors as black instead of the
+ standard ANSI colors. This makes them go completely black when you try
+ to use Midnight Commander with colors.
+
+ You will have to override the defaults. Create a file "color.defaults"
+ which has the following contents:
+
+ color_xterm*color0: Black
+ color_xterm*color1: Red
+ color_xterm*color2: Green
+ color_xterm*color3: Yellow
+ color_xterm*color4: Blue
+ color_xterm*color5: Magenta
+ color_xterm*color6: Cyan
+ color_xterm*color7: White
+ color_xterm*background: White
+ color_xterm*foreground: Black
+
+ (replace color_xterm with the name of your color_xterm, color_xterm
+ mentions its name in its title bar)
+
+ Now type:
+
+ xrdb -merge color.defaults
+
+ Alternatively you can add the suggested contents of the color.defaults
+ file to your .Xdefaults or .Xresources file (or what ever the name of
+ your X configuration file is). Or you can replace your non-ANSI
+ color_xterm with an ANSI color_xterm.
+
+ 4.7 Where can I get color_xterm?
+
+ Try ftp.x.org: /contrib/utilities/colour_xterm.tar.gz.
+
+ Alternatively, rxvt is a better choice, see
+ http://mc.blackdown.org/cgi-mc/download/rxvt/.html
+
+ 4.8 I got colors working with MC but the other programs don't work at all
+ anymore!
+
+ Midnight Commander uses terminfo database (if available) but many
+ other programs use termcap database. If you set the TERM environment
+ variable to a value which has no corresponding entry in termcap
+ database those programs stop working. You should add the new value of
+ TERM to the termcap database.
+
+ Example: If you have set TERM to xterm-color locate from /etc/termcap
+ the line which starts:
+
+ xterm|vs100|xterm terminal emulator
+
+ Change it to start:
+
+ xterm|xterm-color|vs100|xterm terminal emulator
+
+ 4.9 Why are there both terminfo and termcap? Wouldn't one database be enough?
+
+ You might want to read the Unix-haters handbook at
+ http://www.digital.de/people/jmh/Unix_Haters/unix-haters.html. It
+ lists many more reasons why Unix sucks.
+
+ You can configure which terminal database you want to use with the
+ "--with-termcap" and "--with-terminfo" flags of configure. If you
+ don't specify them, the configure script will try to use terminfo if
+ available otherwise it will use termcap.
+
+5 Graphical user interface
+
+ 5.1 Xview and Tk editions?
+
+ Get the newest development version, give the "--with-xview" or
+ "--with-tk" option to the configure and otherwise compile as usual.
+ See Download.
+
+ Xview and Tk editions are work in progress, they are not as robust as
+ the text mode edition.
+
+6 Command line problems
+
+ 6.1 How do I stay in the last directory when I exit Midnight Commander?
+
+ See the description of the -P option in the Options section of the
+ manual.
+
+ 6.2 How can I access command line history?
+
+ You can browse previous commands with M-p and M-n. Alternatively, you
+ can summon the command history listbox by pressing F9 c h.
+
+ 6.3 How can I complete commands, file names, variable names and so on?
+
+ Just press M-Tab. Press M-Tab again to get a listbox if there are
+ multiple possible completions.
+
+ 6.4 [NEW] I am using ksh. Can I use functions defined in the .kshrc within
+ MC?
+
+ Sorry, MC only supports bash, tcsh and zsh functions. Ksh functions
+ are not supported because ksh lacks the necessary hooks needed for
+ subshell integration.
+
+ Switch to bash or zsh. They are both quite compatible with ksh. Your
+ ksh functions should work as such or after minimal changes.
+
+ 6.5 [NEW] Is there any way to include additional options or hot keys to MC?
+
+ Yes, F2 invokes an user menu which fully configurable. You can add any
+ shell commands to the user menu. See
+ http://mc.blackdown.org/mc/manual-d.html#8 for more info.
+
+ Another way to add functionality is the external panelize feature. See
+ http://mc.blackdown.org/mc/manual-d.html#4 for more info.
+
+ And finally, you can code any feature you want yourself. MC source
+ code is free which means you can change it anyway you want. There are
+ some limitations to make sure MC stays free. See GNU General Public
+ License for details.
+
+7 Virtual file systems
+
+ Note! Virtual file systems are supported by Unix ports only. The
+ Windows 95/NT and OS/2 ports do NOT support virtual file systems. This
+ means you haven't got ftp, zip or tar support on Windows 95/NT and
+ OS/2.
+
+ 7.1 How can I see the contents of a tar archive?
+
+ If you use keyboard just move the selection bar on the tar file and
+ press enter.
+
+ If you use mouse just doubleclick on the tar file.
+
+ If these procedures don't work, your .mc.ext file is faulty. Replace
+ it with one from the MC source distribution.
+
+ You can also enter a tar archive by typing "cd tar:filename.tar.gz"
+ where filename.tar.gz is the name of the archive.
+
+ The recognized suffixes for tar archives are .tar, .tar.gz and .tgz.
+ If your tar archive uses different suffix you have to rename it.
+
+ 7.2 How do I get out of a tar archive?
+
+ Just press enter on the toplevel ".." file or chdir to a non-tar
+ directory. Just typing "cd" with no parameters is enough (it will take
+ you to your home directory).
+
+ 7.3 How do I do anonymous ftp with MC?
+
+ Just type "cd ftp://hostname" where hostname is the name of the host
+ you want to connect. Alternatively, select FTP link from the Left or
+ Right menu and type the name of the host you want to connect.
+
+ 7.4 How do I do non-anonymous ftp with MC?
+
+ Non-anonymous ftp works just like the anonymous ftp but you give the
+ login name with the host name. For example, type "cd
+ ftp://username@hostname".
+
+ 7.5 How do I close an ftp connection?
+
+ Just chdir to a non-ftp directory. Just typing "cd" with no parameters
+ is enough (it will take you to your home directory).
+
+ Internally Midnight Commander closes ftp connection only after a
+ timeout. This isn't visible to the end user.
+
+ 7.6 Why aren't the contents of ftp panel updated?
+
+ Update is skipped because there would be a serious performance
+ penalty. Constantly updating directory panels through a ftp connection
+ would take too much time.
+
+ You can use C-r to force an update.
+
+ 7.7 [NEW] What kind of proxy server works with Midnight Commander?
+
+ Midnight Commander only supports ftp-like ftp proxies. Common WWW
+ proxies (like Squid) are not supported yet because they make ftp
+ connections look like http connections.
+
+8 Other common problems
+
+ 8.1 [UPDATED] How do I get the internal editor to work?
+
+ The F4 key defaults to an external editor because thats what most
+ people are used to. To use the internal editor, select Configuration
+ from the Options menu and check the 'use internal edit' option.
+
+ Alternatively add the line
+ use_internal_edit=1
+
+ under the [Midnight-Commander] section in your .mc.ini file (which is
+ in your home directory).
+
+ To make the editor work all the time, go to the default/* section in
+ the file lib/mc/mc.ext file and remove the line
+
+ Edit=%var{EDITOR:vi} %f
+
+ The internal editor will now be invoked for anything not specified
+ elsewhere in the mc.ext file.
+
+ Make sure that you edit the correct mc.ext file. The Midnight
+ Commander first checks the existance of $HOME/.mc.ext. If this file is
+ missing MC will use $prefix/lib/mc/mc.ext instead ($prefix can be
+ changed with configure before compilation and it defaults to
+ /usr/local).
+
+ When you run `F9/Command/Extension file edit' for the very first time
+ Midnight Commander copies the system-wide mc.ext from $prefix/lib/mc
+ into your home directory because you need write access in order to
+ change it.
+
+ And please don't forget that "make install" overwrites
+ $prefix/lib/mc/mc.ext.
+
+ 8.2 Why doesn't "mcedit newfile" work?
+
+ This is a known bug.
+
+ If the newfile doesn't exist, mcedit fails.
+
+ Start mcedit with no parameters, this will create a blank file. Then
+ save the file with whatever name you like.
+
+ 8.3 [UPDATED] Is there any way to 'bookmark' favourite ftp-fs links?
+
+ Use the directory hotlist. Just press control-backslash. If your
+ national keyboard layout doesn't have backslash key, just press the
+ control key with the key which is the backslash key in the English
+ keyboard layout.
+
+ 8.4 When copying the directories lose their original date, uid and gid!
+
+ This is a known bug. At moment only files preserve their original
+ settings when copying, not directories.
+
+ Uid and gid is fixed since 4.0.1. "Preserve UIDs/GIDs" in the copy
+ dialog needs to be checked and you must be root.
+
+ Date problem is supposed to be fixed with 4.0.13.
+
+ 8.5 [UPDATED] Why I keep getting: "There is no disk in the drive. Please
+ insert a disk into drive D:"?
+
+ This is a known bug of the Windows 95/NT and OS/2 ports. MC looks its
+ configuration files from the D:\MC directory and if the D: drive is a
+ removable drive (like a CD ROM drive) and there is no disk in drive
+ you get this message everytime you try to do anything.
+
+ Since version 4.0.6 you can specify the actual location of the
+ Midnight Commander configuration files with the MCHOME environment
+ variable.
+
+ 8.6 [NEW] When I start Midnight Commander, nothing happens!
+
+ First, invoke MC without subshell support: "mc -u". If this helps
+ check the shell you are using. Subshell support works best with bash
+ although tcsh and zsh are also supported. You might want to upgrade
+ your shell to a newer version. If you use something else than bash,
+ tcsh or zsh, subshell support is disabled automatically.
+
+ If disabling subshell doesn't help, try to reconfigure MC with
+ "--with-our-slang" and "--with-termcap" options and recompile. If this
+ helps, there is something wrong with your terminfo database or shared
+ slang library. For better terminfo databases see chapter 4. For a
+ better slang library, upgrade to a newer version or keep using the
+ "--with-our-slang" option.
+
+ 8.7 [NEW] When I try to view a file MC hangs!
+
+ This is known bug. A quick fix is "chmod 666 /dev/tty". For a more
+ complete fix, see http://mc.blackdown.org/mc/maillist/97-10/98.html.
+
+ This bug will probably be fixed in 4.1.6.
+
+9 Development
+
+ 9.1 Who has written Midnight Commander?
+
+ Midnight Commander was started by Miguel de Icaza and he is the
+ maintainer of the package. Other authors have joined the project
+ later:
+ * Mauricio Plaza (early releases, retired)
+ * Janne Kukonlehto (joined Sep 27 1994, retired Mar 8 1995, nowadays
+ Janne is the webmaster of the Midnight Commander web site)
+ * Radek Doulik (joined Oct 30 1994)
+ * Fred Leeflang (joined Nov 2 1994)
+ * Dugan Porter (joined Dec 1 1994)
+ * Jakub Jelinek (joined Feb 8 1995)
+ * Ching Hui (joined Jun 27 1995)
+ * Andrej Borsenkow (joined Jul 1996)
+ * Paul Sheer (joined Nov 1 1996)
+ * Norbert Warmuth
+ * Alex I. Tkachenko
+
+ Alessandro Rubini has been specially helpful with debugging and
+ enhancing of the mouse support. John Davis has made his S-Lang library
+ available to us and answered many questions about it.
+
+ The photographs of the authors are available as:
+
+ http://mc.blackdown.org/mc/about.html
+
+ Many people have contributed bug reports, feature suggestions and
+ small code bits (alphabetical order):
+ * Thomasz Cholewo
+ * Juan Jose Ciarlante
+ * Alexander Dong (OS/2 port, NT port updates)
+ * Erwin van Eijk
+ * Torben Fjerdingstad
+ * Massimo Fontanelli
+ * Juan Grigera (NT port)
+ * Gerd Knorr
+ * Sergey Ya. Korshunoff
+ * Jean-Daniel Luiset
+ * Wim Osterholt
+ * Antonio Palama (old DOS port)
+ * Thomas Pundt
+ * Marcelo Roccasalva
+ * Ilya Rybkin
+ * Vadim Sinolits
+ * Jon Stevens
+ * Adam Tla/lka
+
+ 9.2 Do I dare to use a development version?
+
+ I am afraid you have to answer to this question yourself. Development
+ versions seldom cause data loss but they have usually got many bugs.
+ It's up to you to judge whether new features outweight the bugs.
+
+ 9.3 How can I report a bug/request for a feature?
+
+ You might first want to get the newest development version to see if
+ the bug is fixed or the feature is added already.
+
+ Send your report/request to mc-devel@roxanne.nuclecu.unam.mx or
+ mc@roxanne.nuclecu.unam.mx. These mailing lists are the most certain
+ way to contact the developers. Remember to mention if you are not on
+ the mailing list to make sure that you will receive a copy of replies.
+
+ Give as much details as possible. A too long message is a lot better
+ than a too short message.
+
+ For segmentation faults a stack backtrace is appreciated. You can
+ produce stack backtrace as follows:
+ * If segmentation fault produced a core file:
+ 1. Load the core file by typing "gdb mc core" or "dbx mc core".
+ 2. Type "where".
+ 3. Cut and paste the results to your message.
+ * If segmentation fault didn't produce a core file:
+ 1. Load mc by typing "gdb mc" or "dbx mc".
+ 2. Start mc by typing "run".
+ 3. Try to reproduce the segmentation fault by doing whatever you
+ did last time when the segmentation fault occurred.
+ 4. Type "where".
+ 5. Cut and paste the results to your message.
+ 6. For the future you might want to check out what is the
+ command in your shell to allow producing of the core files.
+ Usually it is "limit coredumpsize unlimited" or "ulimit
+ coredumpsize" or "ulimit -c unlimited".
+
+ 9.4 How can I join the development?
+
+ To join the development just code the feature you want to add and send
+ your patch for inclusion. Email address is mc-devel@nuclecu.unam.mx.
+ Before you start coding check the latest development version. It might
+ be that your feature has already been implemented.
+
+ Note that the authors of the Midnight Commander have given all their
+ rights on the program to the Free Software Foundation. You will have
+ to do the same if you contribute non-trivial patches. Otherwise we
+ have to reject your patches in order to avoid copyright problems.
+
+10 More information
+
+ 10.1 [UPDATED] This document didn't answer my question. Where else can I look
+ for an answer?
+
+ Read messages from the Discussion (mailing list archive), search the
+ web site or read the Manual.
+
+ Upgrade to a newer version of Midnight Commander. Many problems are
+ fixed in the new versions.
+
+ If you still can't find an answer, post your question to the Midnight
+ Commander mailing list. Its address is mc@nuclecu.unam.mx.
+
+ 10.2 What mailing lists are there for Midnight Commander?
+
+ Following mailing lists discuss about Midnight Commander:
+
+ mc
+ General discussion of the Midnight Commander
+
+ mc-digest
+ The mc list, in digest format
+
+ mc-announce
+ Major announcements about the Commander
+
+ mc-patch
+ The latest Commander patches
+
+ mc-devel
+ Technical development discussion
+
+ mc-chat
+ Non-MC related chatting by the developers (contact Miguel to
+ subscribe)
+
+ To subscribe, send e-mail to majordomo@roxanne.nuclecu.unam.mx with
+ the following line in the body of the message:
+
+ subscribe <list-name> [optional-address]
+
+ Replace <list-name> with the name of the list you want to subscribe
+ and [optional-address] with your email address.
+
+ 10.3 Where should I look on the World Wide Web for MC stuff?
+
+ There is a WWW page for Midnight Commander. The URL is:
+
+ http://mc.blackdown.org/mc/
+
+ The WWW page features MC screen shots, photographs of the authors,
+ mailing list archive and a few other things.
+
+ 10.4 Are the mailing lists archived anywhere?
+
+ The mc and mc-devel lists are archived on the World Wide Web page (see
+ the previous question). Other lists are not currently archived though
+ Miguel keeps a private archive. Contact him if you want copies of past
+ messages.
+
+11 Administrivia
+
+ 11.1 Authorship
+
+ Questions and Answers is written by Janne Kukonlehto. Parts of it
+ originate from Ian Jackson, Miguel de Icaza, Dugan Porter, Norbert
+ Warmuth and Paul Sheer.
+
+ 11.2 [UPDATED] File formats
+
+ This document is available in HTML, postscript and PDF formats at
+ http://mc.blackdown.org/mc/answers0.html.
+
+ This document is available in ASCII format in the Midnight Commander
+ source package.
+
+ 11.3 Feedback is invited
+
+ Send your comments about this document to janne@mc.blackdown.org
+
+ Send your comments about the Midnight Commander to mc@nuclecu.unam.mx
+
+ 11.4 Disclaimer and copyright
+
+ Note that this document is provided as is. The information in it is
+ not warranted to be correct; you use it at your own risk.
+
+ You can use Questions and Answers according to GNU Public License (see
+ the COPYING file in the Midnight Commander source distribution).
+ Questions and Answers is not public domain.
+ __________________________________________________________________
+
+ This document is maintained by Janne Kukonlehto
+ <janne@mc.blackdown.org>.
+
--- /dev/null
+-*-text-*-
+
+This file contains:
+
+- Installation instructions and notes for the Midnight Commander
+- Where to get more information on the Midnight Commander
+- Common problems
+- Information on porting the program
+- Obtaining the missing pieces of the Midnight Commander
+
+
+Installation instructions for the Midnight Commander
+----------------------------------------------------
+
+ The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation, and creates
+the Makefile. It also creates a file `config.status' that you can run
+in the future to recreate the current configuration.
+
+(Nextstep users, make sure you read the "Compiling under Nextstep"
+section)
+
+To compile this package:
+
+1. Configure the package for your system.
+
+ Normally, you just `cd' to the directory containing the package's
+source code and type `./configure'. If you're using `csh' on an old
+version of System V, you might need to type `sh configure' instead to
+prevent `csh' from trying to execute `configure' itself (under AIX,
+you may need to use ksh instead of sh).
+
+ Running `configure' takes a while. While it is running, it
+prints some messages that tell what it is doing. If you don't want to
+see any messages, run `configure' with its standard output redirected
+to `/dev/null'; for example, `./configure >/dev/null'.
+
+ To compile the package in a different directory from the one
+containing the source code, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'. `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script. `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'. If
+for some reason `configure' is not in the source code directory that
+you are configuring, then it will report that it can't find the source
+code. In that case, run `configure' with the option `--srcdir=DIR',
+where DIR is the directory that contains the source code.
+
+ By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc. You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'. Alternately, you can do so by consistently
+giving a value for the `prefix' variable when you run `make', e.g.,
+ make prefix=/usr/gnu
+ make prefix=/usr/gnu install
+
+ You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If
+you give `configure' the option `--exec-prefix=PATH' or set the `make'
+variable `exec_prefix' to PATH, the package will use PATH as the
+prefix for installing programs and libraries. Data files and
+documentation will still use the regular prefix. Normally, all files
+are installed using the same prefix.
+
+ The program detects if you have the gpm library installed. If you
+installed the gpm mouse library in a non-standard place, you will need
+to use the --with-gpm-mouse flag with the directory base where you
+installed the gpm package.
+
+ `configure' also recognizes the following options:
+
+`--help'
+ Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+ Do not print messages saying which checks are being made.
+
+`--verbose'
+ Print the results of the checks.
+
+`--version'
+ Print the version of Autoconf used to generate the `configure'
+ script, and exit.
+
+`--with-debug'
+ Enables the built-in memory allocation debugger and forces
+ compilation with -Wall. This is an option intended to be used by
+ the program developers.
+
+`--without-edit'
+ Configures the program to be compiled without the built-in file
+ editor. The built-in editor is compiled in by default.
+
+`--with-ext2undel[=PATH]'
+ On systems that use the Extended 2 file system and have the
+ libext2fs.a library available, this compiles into the Midnight
+ Commander the support code for recovering deleted files (the
+ undel virtual file system).
+ Use =PATH if libext2fs.a is installed in a non-standard place.
+ The configure will append `lib' and `include' to find the ext2fs
+ libraries and include files respectively.
+
+`--with-gpm-mouse[=PATH]'
+ Use this flag if your GPM mouse package cannot be detected by the
+ configure. Use =PATH if it is installed in a non-standard place.
+ The configure will append `lib' and `include' to find the libgpm.a
+ and gpm.h files respectively.
+
+`--without-gpm-mouse'
+ Use this flag to disable GPM mouse support (e.g. if you want to
+ use mouse only on X terminals).
+
+`--with-hsc'
+ Compiles support into the ftp virtual file system to support the
+ HSC firewall.
+
+`--with-mmap'
+ Needed when compiling under AIX if you want the fast viewer.
+
+`--with-sco'
+ This option is used to compile on SCO: it turns on SCO-specific
+ code, i.e. disables the terminal resizing mechanism, uses the
+ BSD-like pseudoterminal handling, adds screen-saving capabilities
+ on console, etc.
+
+`--with-subshell[=optional]', `--without-subshell'
+ The subshell support is by default turned on, you can disable
+ this by using the --without-subshell option. If you pass the
+ =optional parameter, then the subshell support is turned off by
+ default, to turn it on, you have to specify the `-U' flag when
+ running the program.
+
+`--with-termnet'
+ Enables the network support with the Term package.
+
+`--with-tk' [WARNING: X code is not released]
+ This option enables including the Tcl/Tk version.
+
+`--with-tk-includes=DIR' [WARNING: X code is not released]
+ Lets you specify the place where you have your Tcl/Tk headers installed.
+ It should be a directory containing tcl.h and tk.h.
+
+`--with-tk-libraries=DIR' [WARNING: X code is not released]
+ Lets you specify the place where you have your Tcl/Tk libraries -
+ libtcl and libtk.
+
+`--with-xview' [WARNING: X code is not released]
+ This option enables including the XView version.
+
+`--with-xview-includes=DIR' [WARNING: X code is not released]
+ Lets you specify the place where you have your xview headers installed.
+ It should be the directory, which has subdirectories xview and
+ hopefuly xview_private.
+
+`--with-xview-libraries=DIR' [WARNING: X code is not released]
+ Lets you specify the place where you have your xview libraries -
+ libolgx and libxview.
+
+`--with-xv-bindir=DIR' [WARNING: X code is not released]
+ Lets you specify the place where program mxc will be installed.
+ Default is somewhere in your XView binaries directory,
+ $OPENWINHOME/bin.
+
+`--without-dusum'
+ This option disables a feature of the Midnight Commander, which is
+ forking the du command with the -s option when you want to calculate
+ directory sizes.
+
+`--without-vfs'
+ This option disables the Virtual File System switch code in the
+ Midnight Commander and uses the standard file system calls for
+ file access. If you specify this option you will not get the
+ transparent tar File system manipulation as well nor the
+ networked Midnight Commander file system.
+
+You may also tell configure which display manager you want to use with
+the Midnight Commander. The configure script will use SLang as default,
+but you can override this by using any of the following flags (please
+note that slang is included as part of the distribution),
+
+`--with-slang' (default)
+ This is used to configure the program to use the SLang screen
+ manager. This is included as part of the Midnight Commander,
+ you don't need it installed on your system. If SLang is installed
+ on your system it will be used if possible. You can force usage of
+ the included SLang with the `--with-included-slang' option.
+ Slang is the only library that will let you resize the Midnight
+ Commander window on an xterm.
+
+ This option will usually try to use the terminfo database if it
+ is available, otherwise it will use the termcap database. At
+ compile time, you may force the use the terminal database with
+ the `--with-termcap' and `--with-terminfo' options (both options
+ automaticly turn `--with-included-slang' on).
+
+`--with-ncurses[=directory]'
+ Use this flag (either with or without the =directory part), if
+ you want to compile with ncurses instead of the default SLang.
+
+ Use the =directory part if your ncurses is not installed in any of the
+ places configure will check (/usr/include, /usr/include/ncurses,
+ /usr/local/include and /usr/local/include/ncurses).
+ The argument to this flag is the base directory where the ncurses
+ files are located. The configure will append lib and include to
+ find the libncurses.a and ncurses.h file respectively. For
+ example, if you have installed ncurses under /gnu/lib and
+ /gnu/include, you specify: --with-ncurses=/gnu
+
+ You will need the ncurses package only if your system does not
+ provide a compatible curses. If after compiling, the program
+ says that it can't resolve the has_colors function, then you need
+ the ncurses package or you may always go back to the included SLang
+ screen manager.
+
+`--with-vcurses[=directory]'
+ Use this flag to force the Midnight Commander to use a SystemV
+ type ncurses, the optional directory specifies where should
+ the C compiler find the include files.
+
+`--with-sunos-curses'
+ You use this flag on SunOS machines if you want to use SunOS 4.x
+ curses instead of ncurses. You don't need this flag if you don't
+ have ncurses installed: it's only needed to force the usage of
+ SunOS curses over ncurses.
+
+ `configure' also accepts and ignores some other options.
+
+ On systems that require unusual options for compilation or linking
+that the package's `configure' script does not know about, you can give
+`configure' initial values for variables by setting them in the
+environment. In Bourne-compatible shells, you can do that on the
+command line like this:
+
+ CC='gcc -traditional' LIBS=-lposix ./configure
+
+On systems that have the `env' program, you can do it like this:
+
+ env CC='gcc -traditional' LIBS=-lposix ./configure
+
+ Here are the `make' variables that you might want to override with
+environment variables when running `configure'.
+
+ For these variables, any value given in the environment overrides the
+value that `configure' would choose:
+
+ - Variable: CC
+ C compiler program. The default is `cc'.
+
+ - Variable: CFLAGS
+ The default flags used to build the program.
+
+ - Variable: INSTALL
+ Program to use to install files. The default is `install' if you
+ have it, `cp' otherwise.
+
+ For these variables, any value given in the environment is added to
+the value that `configure' chooses:
+
+ - Variable: LIBS
+ Libraries to link with, in the form `-lfoo -lbar...'.
+
+ If you need to do unusual things to compile the package, we encourage
+you to figure out how `configure' could check whether to do them, and
+mail diffs or instructions to the address given in the README so we
+can include them in the next release.
+
+2. Type `make' to compile the package.
+
+3. If the package comes with self-tests and you want to run them,
+type `make check'. If you're not sure whether there are any, try it;
+if `make' responds with something like
+ make: *** No way to make target `check'. Stop.
+then the package does not come with self-tests.
+
+4. Type `make install' to install programs, data files, and
+documentation.
+If your system is Linux, then install installs the Linux console screen
+saver as well.
+
+5. You can remove the program binaries and object files from the
+source directory by typing `make clean'. To also remove the
+Makefile(s), the header file containing system-dependent definitions
+(if the package uses one), and `config.status' (all the files that
+`configure' created), type `make realclean'. If you want to clean the source
+tree completely, so that it contains only those files that should be
+packaged in the archive, issue `make distclean'. If you've run configure in
+a different directory than the source tree, distclean won't remove your *.o
+and linked programs in that directory.
+
+6. The Midnight Commander allows you to be kept on the directory you
+were when you quit the program, this is done with a shell function,
+the man page has more information about this. If you want to let the
+install program make the change to your /etc/profile or your
+~/.profile or ~/.bashrc, then type: `make mcfninstall'.
+
+ The file `configure.in' is used to create `configure' by a program
+called `autoconf'. You only need it if you want to regenerate
+`configure' using a newer version of `autoconf'.
+
+Compiling under NeXTStep
+------------------------
+
+These instructions were provided by Gregor Hoffleit
+<flight@mathi.uni-heidelberg.DE>, he recommends configuring the
+program like this:
+
+
+export CC="cc -posix"
+configure --without-subshell --with-termcap
+Edie config.h and make sure you have #undef HAVE_GETWD
+make
+
+
+\f
+- Where to get more information on the Midnight Commander
+---------------------------------------------------------
+
+Janne Kukonlehto set up a WWW page, here is the URL:
+http://mc.blackdown.org/mc/
+
+We also a set of mailing lists for the program:
+
+mc-announce: Announcements of new version of the Midnight Commander.
+mc-digest: Digest version of the mc list.
+mc-patches: Patches by mail (also on the ftp site).
+mc: Discussion on the Midnight Commander file manager.
+mc-devel: For discussion between the developers of the program.
+
+to subscribe to the mailing lists, send a message to:
+
+majordomo@roxanne.nuclecu.unam.mx
+
+with the following text in the body of the message:
+
+subscribe <list-name> [address]
+
+The address is optional and list-name is one of the above list names
+(mc, mc-announce, mc-patches or mc-digest).
+
+\f
+Notes about the Midnight Commander installation
+------------------------------------------------
+
+The Midnight Commander has been run in the following configurations:
+
+i386-*-linux
+sparc-*-linux
+alpha-*-linux
+mips-dec-ultrix4.3
+mips-dec-{open,net}bsd1.0
+mips-sgi-irix5.2
+mips-sgi-irix5.3
+rs6000-ibm-aix3.2.5
+sparc-sun-sunos4.1
+sparc-sun-netbsd1.0
+sparc-sun-solaris2.3
+hppa-hp-hpux9
+hppa-hp-hpux7
+m68k-apple-aux
+mc88110-aviion-dgux5.4
+i386-*-{bsdi2,freebsd}
+
+Since the Midnight Commander is configured via the GNU autoconf
+program, it's not difficult to run it in other operating systems.
+
+If you're using AIX, with the cc6000 compiler, you have to specify the
+`--with-mmap' command line option.
+
+You will need GNU C (or an ANSI C Compiler) and optionally a color
+curses library (ncurses is a good choice). The Midnight Commander now
+comes with the Slang screen manager, a fast screen manager, so ncurses
+is not required anymore unless you want to use it.
+
+Many Linux systems ship with ncurses version 1.9.9e, however, we recommend
+ncurses 4.1 or above, since the former version does not support resizing
+of the xterm window.
+
+Since version 0.9 the Midnight Commander comes with mouse support on
+xterms and in the Linux console. In order to take advantage of the
+mouse support on the Linux console you will need the gpm mouse server
+(see the section "Obtaining the Missing Pieces" in this file).
+
+Once you get the Mouse Server, compile it and install it, then you
+will have to specify the `--with-gpm-mouse' flag to the configure
+program if you installed it in a non-standard directory. If you
+installed the gpm package under /usr or /usr/local, you don't need to
+specify this flag; configure will find gpm for you. The support for
+mice on xterms is always compiled in.
+
+We are working on further enhancements to the program, but we're not
+sure which ones must go first. If you would like to point us in the
+Right Direction we will be glad to hear from you (you could check the
+file TODO included with this distribution for the current projects).
+
+If you happen to find an undocumented feature that doesn't do what you
+expected, please drop us a note telling us as much as you can about
+the problem you're experiencing (to miguel@roxanne.nuclecu.unam.mx).
+
+\f
+Porting the program
+-------------------
+
+Random notes on porting to other architectures.
+
+The Midnight Commander uses now by default the Slang library for
+handling the display. If you can't port Slang (which should be a
+pretty trivial job), you may want to attempt using ncurses (the
+Midnight Commander can use ncurses as well as the display engine).
+
+If you don't want to install ncurses and your OS is a SystemV Release
+4 variant, maybe the curses supplied with your system will do the
+work. If you experience display problems, then it means that we are
+dealing with a buggy implementation of curses. You have two options:
+one, download ncurses and recompile with ncurses or recompile all your
+source code with the symbol BUGGY_CURSES defined. But you can always
+switch to the default SLang screen manager.
+
+The fast way to do this is to:
+
+make clean; make XINC=-DBUGGY_CURSES
+
+\f
+Obtaining the missing pieces of the Midnight Commander
+------------------------------------------------------
+
+The Midnight Commander will build without requiring you to get any
+other software packages, however, you may be interested in enhancing
+the Midnight Commander environment with some of these:
+
+o Terminal database
+
+ There are many incomplete terminal databases out there, however, a
+ complete terminfo is bundled with ncurses. (It is simple to generate
+ the termcap database using the infocmp utility in ncurses).
+
+ Some terminfo data are included with the mc distribution (lib/*.ti).
+ Particularly linux, xterm and vt100. Use e.g. ''tic linux.ti'' to
+ use them.
+
+ If you want to run mc on xterm/color_xterm/ansi_xterm (not rxvt), then
+ you might read lib/README.xterm for further information.
+
+o In the past the Midnight Commander required the NCurses library to
+ build, now it's optional. You can get Ncurses from
+
+ ftp.gnu.org:/pub/gnu
+ ftp.clark.net:/pub/dickey/ncurses
+
+o The GPM Mouse Server is available at:
+
+ iride.unipv.it:/pub/gpm
+
+o The X Windows System libraries are only used if you are going to
+ build the X11 versions of the program. Please note that this code
+ is not finished, so it's only useful if you want to look at what we
+ are doing or want to help in one of the two X11 versions.
+
+o The XView library can be obtained from (currently the newest is
+ XView3.2p1-X11R6.tar.gz):
+
+ ftp.nuclecu.unam.mx:/Midnight/devel/XView.libs
+ ftp.x.org:/contrib/libraries
+ ftp.cvut.cz:/pub/x11/contrib/libraries
+
+ - Linux/ELF shared binaries:
+
+ sunsite.unc.edu:/pub/Linux/libs/X/xview
+ ftp.cvut.cz:/pub/linux/sunsite/libs/X/xview
+
+o The Tcl/Tk libraries can be obtained from:
+
+ ftp.smli.com:/pub/tcl
+ ftp.aud.alcatel.com:/tcl/ftp.smli.com
+ ftp.cvut.cz:/pub/tcl/ftp.smli.com
+
+ - Linux/ELF shared binaries:
+
+ ftp.ods.com:/pub/linux
+ ftp.cvut.cz:/pub/linux/ods
+
+o The Xpm library (used by the XView version) can be obtained from
+ (currently xpm-3.4f.tar.gz):
+
+ koala.inria.fr:/pub/xpm
+ ftp.x.org:/contrib/libraries
+ ftp.cvut.cz:/pub/x11/contrib/libraries
+
+ - Linux/ELF shared binaries:
+
+ ftp.ctd.comsat.com:/pub/linux/ELF
+ ftp.cvut.cz:/pub/linux/comsat
+
+To get the mouse support working on the Linux console:
+
+If you're using Linux version >= 1.1.34, then you will have to choose yes
+to selection when you compile your kernel. If your Linux version is
+older than this one, you may try to apply one of the patches included in
+the gpm package.
+
+And the GNU C Compiler may be obtained from the following sites:
+
+ ASIA: ftp.cs.titech.ac.jp, utsun.s.u-tokyo.ac.jp:/ftpsync/prep,
+ cair.kaist.ac.kr:/pub/gnu
+ AUSTRALIA: archie.au:/gnu (archie.oz or archie.oz.au for ACSnet)
+ AFRICA: ftp.sun.ac.za:/pub/gnu
+ MIDDLE-EAST: ftp.technion.ac.il:/pub/unsupported/gnu
+ EUROPE: ftp.cvut.cz:/pub/gnu, irisa.irisa.fr:/pub/gnu,
+ ftp.univ-lyon1.fr:pub/gnu, ftp.mcc.ac.uk,
+ unix.hensa.ac.uk:/pub/uunet/systems/gnu,
+ src.doc.ic.ac.uk:/gnu, ftp.win.tue.nl, ugle.unit.no,
+ ftp.denet.dk, ftp.informatik.rwth-aachen.de:/pub/gnu,
+ ftp.informatik.tu-muenchen.de, ftp.eunet.ch,
+ nic.switch.ch:/mirror/gnu, nic.funet.fi:/pub/gnu, isy.liu.se,
+ ftp.stacken.kth.se, ftp.luth.se:/pub/unix/gnu, archive.eu.net
+ CANADA: ftp.cs.ubc.ca:/mirror2/gnu
+ USA: wuarchive.wustl.edu:/mirrors/gnu, labrea.stanford.edu,
+ ftp.kpc.com:/pub/mirror/gnu, ftp.cs.widener.edu, uxc.cso.uiuc.edu,
+ col.hp.com:/mirrors/gnu, ftp.cs.columbia.edu:/archives/gnu/prep,
+ gatekeeper.dec.com:/pub/GNU, ftp.uu.net:/systems/gnu
+
+
+Unsupported options to configure:
+---------------------------------
+`--with-bsd-curses'
+ If you don't want to use ncurses and are using an Ultrix box, you
+ can use this switch. Be aware that ncurses is a better option
+ than the curses included in Ultrix.
+
--- /dev/null
+-*-text-*-
+
+Read the INSTALL file for the complete instructions.
+
+ The Midnight Commander by default will use the Slang screen
+manager, if something fails with the Slang screen manager, you may
+compile the program with your system curses (You will need a SysV
+compatible curses, in case you don't have such, read the README file
+for directions on getting the ncurses package, a freely available
+replacement for SysV curses).
+
+1. Configure the package for your system.
+
+ Normally, you just `cd' to the package main directory and type
+`./configure'.
+
+ The most often needed options to configure are following:
+
+`--prefix=PATH'
+ By default, `make install' will install the package's files in
+ `/usr/local/bin', `/usr/local/man', etc. or to `/usr/bin',
+ `/usr/man', etc. depending on the location of an old mc binary.
+ If you have none in your system, default will be `/usr/local'.
+ You can specify an installation prefix other than default by giving
+ `configure' the option `--prefix=PATH'.
+
+`--with-slang' (default)
+ The easy way to get the Commander running: Slang is part of
+ the distribution. This is the default screen manager, if you run
+ configure without any --with-*curses parameter.
+
+`--with-ncurses[=PATH]'
+ Use the flag without =PATH if you want to compile with ncurses
+ (default is in version 3.0 the SLang screen manager included
+ in the distribution).
+ Use this flag with =PATH part, if you want to compile with ncurses
+ and your ncurses is not installed in any of the
+ places configure checks (/usr/include, /usr/include/ncurses,
+ /usr/local/include and /usr/local/include/ncurses). The
+ configure script will append `lib' and `include' to find the
+ libncurses.a and ncurses.h files respectively.
+
+`--with-gpm-mouse[=PATH]'
+ Use this flag if your GPM mouse package cannot be detected by the
+ configure. Use =PATH if it is installed in a non-standard place.
+ The configure will append `lib' and `include' to find the libgpm.a
+ and gpm.h files respectively.
+
+`--with-sco'
+ If you are compiling on a SCO machine.
+
+ You may also want to specify CFLAGS for the compiler, even if it finds
+ itself some defaults by typing e.g.
+
+ `CFLAGS=-O2 ./configure'
+
+2. Type `make' to compile the package.
+
+3. Type `make install' (as root) to install programs, data files, and
+documentation. If you're on a Linux system, this will install the
+`cons.saver' utility, which allows the Midnight Commander to save and
+restore the screen contents. If you're making a mc binary distribution for
+other people and want to tar the whole binary later, you may want to specify
+`make install DESTDIR=PATH', which will make PATH the root for installation
+(but in the installed stuff will be still stored only --prefix).
+
+3a. Type `make mcfninstall' to get an interactive program check if you
+want to define an useful alias for the Midnight Commander.
+
+4. Type `mc' and enjoy!
--- /dev/null
+
+Version 3.5
+
+- New hotlist code.
+ - The bookmark code has been completely revamped and now it supports
+ folders. New format for the hot list file.
+ - It is possible to copy a selected path name into the input line
+ (C-Enter).
+
+- Tk enhancements.
+ - New built in GUI designer to help developers modify the look
+ of the program at run time (no penaly for users).
+ - Many dialog boxes now work.
+ - Right button now pops up a context sensitive action menu.
+ - Added many visual enhancements.
+ - The Tk edition is not yet finished though.
+
+- File management.
+ - Now we do background copy and move operations.
+ (you can ftp your files in the background now, for example).
+
+- Built in text editor
+ - This is an easy to use text editor with pull-down menus.
+ The features it presently supports are: Block copy, move,
+ delete, cut, paste; key for key undo; file insertion; macro
+ definition; regular expression search and replace (and our
+ own scanf-printf search and replace); shift-arrow MSW-MAC
+ text highlighting (for the linux console only);
+ insert-overwrite toggle; and an option to pipe text blocks
+ through shell commands like indent.
+
+ Comes with Emacs keybindings as well.
+
+ mcedit is a link to mc which bring it up in editor mode.
+
+- FTP File system
+ - Many fixes and enhacements, better support for proxy
+ machines.
+ - Now we support both active and passive opens.
+ - Estimated time of arrival for ftp transfers.
+ - stalled detection.
+ - Much better support for proxies.
+ - ftp URL's now allow a password to be provided.
+
+- ext2fs Undelete File system
+ - Minor enhancements.
+
+- TAR File system
+ - Now we flush the tarfs if the tar file has been modified
+
+- External File systems:
+ - Speeded up RPM file system.
+ - New LHA file system.
+ - New ARC file system.
+ - New DEB file system (for those users of Debian).
+ - New RAR file system.
+ - Fixed problems with different zipfs.
+
+- MC file system:
+ - We get can use a mc file system by using either mc: or mc:// prefixes.
+
+- Viewer changes:
+ - Now we include a program that preprocesses mail if you view it
+ so, you get colored mails in the viewer.
+ - A simple ruler has been implemented (press Alt-r to enable it).
+
+- New hex editor
+ - Now you can do hex editions in your files with a single keystroke.
+ (invoke it by using the hex-viewer and then clicking on edit).
+
+- Find file command:
+ - Now we can search inside files using a piped grep (particularly
+ interesting to search inside virtual file system: tar files,
+ tar files on remote ftp sites, or searching information on an
+ ftp site)
+
+- Widgets:
+ - Input lines now support control-left, control-right movement on the
+ Linux console.
+
+- Extension file:
+ - We now support extra entries in a given rule with the Include=
+ tag.
+
+- Ports:
+ - Windows NT, Windows 95 by Juan Grigera
+ - OS/2 by Alexander Dong.
+
+
+- Many many many bug fixes and memory leaks have been fixed.
+
+
+Version 3.2
+
+- External File system:
+ - Mtools file system works.
+ - New Cpio file system.
+ - New RPM file system.
+
+- FTP file system:
+ - support for HSC firewall
+
+- Lots of subshell fixes
+
+- Regexp-extension:
+ - Editing of non-local files works now.
+
+- Bunch of bug fixes.
+
+- Panelize now works properly.
+
+- Can work on Nextstep now.
+
+- Windows NT port by Juan Grigera.
+
+- Midnight Commander file system server:
+ - Fixed errno handling in the server.
+ - Fixed time handling in the server.
+ - Better caching.
+ - Works with PAM if supported on the system.
+
+Version 3.1
+
+This has been finished:
+
+- Enhanced ftpfs:
+ - Displays progress bars.
+ - Supports netware and windows nt servers
+ - Better support for symlinked files.
+ - Handles those warez sites file names.
+ - Increase the directory cache timeout.
+ - Cache flushing (C-r)
+ - If you append a /~ to the directory, you will log into your home
+ directory (this is done by default if you use the menus to connect).
+ - More robust.
+- Subshell fixes (it should not hang any longer).
+ - Fixes prompt handling for zsh and tcsh users.
+ - Fixes variable expansion for tcsh (now you may edit files).
+ - Rewrote the sync code between the parend and child, should not hang
+ any longer.
+- Better command completion.
+- Keypad handling enhanced:
+ - Special key treatment for +, -, \ and now may be configure to
+ only take place if you do not have a command typed in.
+ - Now the + and \ bindings when ran on the Linux console work
+ may use the keypad and M-+ and M-\ and leave the + and \ keys
+ free.
+- Better handling of the line drawing chars on OSF/1 and AIX.
+- Enhanced tar/compressed tar file systems.
+- Global kill ring.
+- Added undelete feature for Linux systems: now you may recover deleted files
+ on ext2 file systems with the Undelete file system.
+- Symlink commands (for symlink lovers).
+ see the docs on C-x C-r, C-x C-l, C-x C-s keystrokes.
+- New macros:
+ %b and %B return the basename of the selected filename
+ %var{ENV-VAR} expands to the contents of ENV-VAR variable.
+- MC may be invoked as a viewer (mc -f flag).
+- Added Unicode support on the Linux console (run with mc -N)
+- Tons of bug fixes, the code is cleaner and hopefully
+- Allow a vfs pathname to be passed as a startup directory.
+
+This is a list of people that put their effort into making the 3.1
+release:
+
+Adam Tla/lka, Antonio Palama, Carl Thompson, Ching Hui, Dugan Porter, Gerd
+Knorr, Ilya Rybkin, Jakub Jelinek, Janne Kikonlehto, Juan Grigera, Juan Jose
+Ciarlante, John Davis, Marcelo Fabian Roccasalva, Perry Francis Nguyen,
+Sergey Ya Korshunoff Steven Hirsch, Thanh Ma and Torben Fjerdingstad.
+
+Version 3.0
+
+This has been finished:
+
+- Virtual File System: You now can browse tar, compressed tar and
+ file systems over the network as if they were local subdirectories;
+- Slang support, you don't need ncurses anymore (but you can still compile
+ with ncurses, if you want).
+- New mc.ext format, for details see the sample mc.ext file provided.
+- Append option if you try to copy/move a file onto already existing one.
+- Internal cd command uses CDPATH variable if set (like in BASH).
+- Find file command is much faster.
+- External panelize command - finding files using unlimited number of
+ criteria - actually spawns an external command and it can be find, awk,
+ grep -l or anything else.
+- Learn keys makes setting up of mc on terminals with broken
+ terminfo/termcap databases easier. It just asks you to press keys which
+ are not working.
+- Advanced chown command.
+- C-PgUp and C-PgDn takes you to the previous and currently selected
+ directory respectively on the Linux console.
+- You can choose between 7 data bits, iso-latin-1 (0-127+160-255) or
+ other (0-255).
+- Confirmation for overwriting, deleting and exiting added.
+- Viewer has growing buffers.
+- Filename, username, hostname and variable completion (M-Tab) on all
+ input lines plus command completion on appropriate places of command
+ line.
+- Following of symlinks at changing directory.
+- Viewer now supports bold faces and underlines, and it fits the
+ information on the screen better. Now you can also specify the starting
+ mode for the viewer depending on the contents of the viewed file.
+- Mask rename and copy.
+- Colors now let you specify the intensity of the colors you want.
+
+This is being worked on:
+- Virtual File System: FTP file system.
+- Tcl/Tk and XView versions of the program (preliminary versions are
+ up and running).
+
+
+Version 2.0
+
+Now users are able to define their own display
+
+- User defined display formats.
+
+ Now you can configure the file display to suit your needs.
+ For example, you can say which information you want to see displayed
+ instead of our defaults.
+
+- User definable program layout.
+
+ Panels could be shown vertically or horizontally;
+ panels could be different sizes, you can hide or show most
+ program windows (command line, keybar or menubar).
+
+- Output window.
+
+ Now, it's possible to see part of the last program output on the Linux
+ console without having to switch screens via an option in the layout
+ menu.
+
+- New View modes:
+
+ Quick view: as you browse your files, each one is displayed on
+ the other panel on the idle time.
+
+ Tree view: let's you browse your directories by traveling a tree.
+ We have two traveling modes available. And the tree does
+ not take your precious time: it's build on the fly, as you
+ browse your disk (you can always loose your time if you
+ want to :-).
+
+ Info view: Gives you information on the currently select file and
+ the current file system as you move.
+
+ User view: Let's you define a directory listing and the format you
+ want to use.
+
+- New subshell support (concurrent shell execution)
+
+ The Midnight Commander will now spawn one copy of the shell, so you
+ get better performance and you can use shell functions, define variables
+ and execute complete shell commands. Supported shells: bash, zsh and
+ tcsh. If your shell is not supported, then the old mode is still
+ available.
+
+- Dialog box manager
+
+ Almost all the new configuration options are configured with this
+ new dialog manager, easy to use if you are familiar with dialog boxes
+ in DOS and Windows.
+
+ Available widgets: check buttons, buttons, radio buttons,
+ input lines and list boxes (So you can take our code and use it on
+ your applications).
+
+- New option configuration.
+
+ Now the program options are configured with a dialog box.
+
+- Chmod and Chown commands:
+
+ For changing permissions as well as ownership of files and
+ directories, uses our new dialog manager.
+
+- Color customization support
+
+ Now you can change the default color of the program with any of
+ these:
+ environment variable, Colors section in the init file (colors per
+ terminal type) and command line.
+
+- User menu and extension enhancements:
+
+ Execution understand the %t macro (tagged files).
+
+ User menu also has a new macro to let the user specify options.
+
+ You can hide and show entries in the user menus by using conditions.
+
+ Auto detect best match depending on a regexp.
+
+- Viewer:
+ Goto line command,
+ horizontal scrolling,
+ on the fly uncompression (and we don't eat unneeded cycles of CPU),
+ allow non gunzip operation.
+
+- Internal move command:
+
+ Now, we don't rely anymore on system commands in /bin, so the
+ program is more robust and is much faster. Bunchs of code come
+ from the GNU fileutils.
+
+- The Tree view and normal views allows wrapped incremental searchs of
+ file names.
+
+- Mask rename:
+
+ Now it's possible to do things like rename *.pas in *.bak
+
+- Compare directories command
+
+- Allow panels to be in Long mode without forcing the user to a single panel.
+
+ (You can even have two long panels).
+
+- F10, C-g cancels as well as ESC ESC.
+
+- Improved help system.
+
+ We updated and spelled the help system and added a lots of links.
+ The Web page is constructed with the same tools.
+
+- Allows tagging of directories:
+
+ Now you can copy, rename, move and delete complete directories. You
+ are not limited anymore to files.
+
+- View output (screen save/restore) on Linux console.
+
+ On old Linux systems, only b&w is supported, on newer Linux systems
+ (1.1.67 and newer), we also support color screen save/restore and
+ cursos positions.
+
+- 8 bit clean support.
+
+- Visual feedback while i-searching files.
+
+- Much more intuitive, you have to use it.
+
+- It's better than aspirin.
+
+- New memory allocation debugger.
+
+ During testing time, we used a powerfull memory allocation debugger,
+ so the program will not eat all your memory, and will make a good use of
+ your memory.
+
+- Now it also runs on hppa-hp-hpux9, hppa-hp-hpux7, m68k-apple-aux and
+ sparc-sun-netbsd1.0. The best platform to run it is Linux, of course,
+ since that's where most of us develop it.
+
+- Inode sort option.
+
+- Nice progress status indicator.
+
+ We have two of them: a moving dash indicator and a progress bar
+ indicator for file operations.
+
+Version 0.15
+
+- Uses GNU autoconf.
+ Currently, it has been ported to this configurations:
+ i386-*-linux1.0
+ i386-*-linux1.1
+ mips-sgi-irix5.2
+ mips-dec-ultrix4.3
+ rs6000-ibm-aix3.2.5
+ sparc-sun-sunos4.1
+ sparc-sun-solaris2.3
+
+- Improvements to the internal file viewer:
+ Wrap/Unwrap mode.
+ Hex mode.
+ Hex searches.
+ Now you can view compressed files (gzip, compress, zip, pack and lzh).
+ Performance enhancements, now it's much faster.
+ Works on systems without mmap.
+
+- Mouse Support now also works on xterms.
+ If you run in the Linux console, you will still need the gpm mouse server
+ to use the mouse support, but if you use xterms, then you're lucky
+ and can use the mouse support when using xterms.
+
+- Help system and man page.
+ Both were updated and has many more hypertext links inside, the
+ help system can also be used with a mouse.
+
+- If running on xterms, now you can see the output of the last program
+ you ran by using the C-o key combination.
+
+- Switch panels command (C-u)
+- With filter command per panel.
+- With auto mounting/umounting on chdir feature.
+- cd now expands tildes (~, ~user).
+- Much more portable.
+- Many bugs were fixed.
+
+Version 0.14
+
+- Now can handle directories with an unlimited number of files.
+- New link and symlink commands (C-x l, C-x s).
+- New insert tagged files or selection command (C-x t).
+
+Version 0.13
+
+- Behave more like the Norton Commander.
+- Added menu file edit.
+- If there is no permission to load a directory, now it loads a dummy
+ directory.
+- When a panel is re-sorted, keep the selected file selected.
+- forward_word and backward_word command on the input line now skip
+ over letters and numbers.
+- Fixed backward scrolling in the internal viewer.
+- The internal viewer now computes the percentage in a more natural
+ way.
+- Added handling of the Home and End keys to the internal viewer
+- Bug fixes.
+
+Version 0.12
+
+- Preliminary support for System V compilation.
+- Bug fix: didn't call closedir in all cases.
+- bug fixes.
+
+Version 0.11
+
+- Support cd -.
+- Corrected Makefile.
+
+Version 0.10
+
+- Added new Alt-G, Alt-H, Alt-J to select the top file, middle file
+ and bottom file in the current panel.
+- Now it's allowed to select option in query boxes by the first initial
+- Fixed mouse repeat rate.
+- Fixed a bug that prevent copying individual files to another file.
+- Some minor bug fixes.
+
+Version 0.9
+
+- Mouse Support.
+- Internal Copy command (it no longer uses cp).
+- Verbose Copying of files.
+- Confirmation on Overwrite and on Delete.
+- Support reverse sorting.
+- Many visual enhancements.
+- Per panel options are saved and restored.
+- New truncation of names in the panels.
+- History in Input Lines (M-p and M-n).
+- Input line enhancements.
+- Dialog boxes are nicer than before.
+- Cache in gid and uid translators.
+- More keybindings for the Input lines.
+- Better kill management in Input Lines.
+- Bug fixes.
+
+Version 0.8
+
+- The online help now comes with the complete man page.
+- Input lines now support M-b and M-f for movement by word.
+- Unlimited input lines (command line).
+- Filename searches now must be started with C-s or M-s.
+- Many bug fixes.
+
+Version 0.7
+
+- The stat() reloading optimization is now a configuration option.
+- Many bug fixes went to the find file command.
+- New history in the hypertext viewer.
+- ESC-Tab will copy the name of the other-panel selected file to the
+ input line.
+- Now it's possible to display files and directories mixed together or
+ separated (like the Norton Commander).
+- Many bug fixes, see the ChangeLog for details.
+
+Version 0.6
+
+- Extension dependent execution implemented (now you can execute
+ things like tar tzvf over compressed tar files, just a tap in the
+ Enter key).
+- Added simple expansion of useful variables in the user menu.
+- Avoid unnecessary reloading of subdirectories using stat (suggested
+ by Torben Fjerdingstad <tfj@olivia.ping.dk>).
+- Added options to disable colors and display version number.
+- Allow start up directory specification (ex: mc /usr/local/bin /tmp).
+- Fixed bug that operated on the selection instead of the tagged file
+(when only one file was tagged).
+- Some cosmetic changes.
+- Bug fixes.
+
+Version 0.5
+
+- Fixed bug in the help browser that crashed the program.
+- New internal viewer.
+- New long directory listing format.
+- some bug fixes.
+
+Version 0.4
+
+- User Menus (F2 key).
+- Quick search of files in a panel (Alt-filename takes you to that file).
+- Char quoting (C-q).
+- exec() enhancements.
+- now you can suspend the program (C-z).
+- The find file command now seems to be very stable.
+- misc bug fixes.
+
+Version 0.3
+
+- Setup loading/saving.
+- Support for any size screen.
+- Many, many bug fixes.
--- /dev/null
+-*-Text-*-
+
+Contents:
+---------
+ Intro text
+ Midnight Commander editions
+ Where to get more information
+ The Midnight Commander
+ Mini-docs
+ Obtaining the Midnight Commander
+ Reporting problems.
+
+This is version 4 of the Midnight Commander, a free Norton Commander
+Clone with many useful features. The Midnight Commander comes with
+mouse support on xterms and optionally on the Linux console.
+
+The Midnight Commander is a directory browsing tool which bears a
+certain remote resemblance to John Socha's Norton Commander for DOS.
+It is feature packed:
+
+ o Built in Virtual File System: manipulate remote files
+ systems through the ftp protocol or Midnight Commander's own
+ mcfs protocol. Browse tar, compressed tar files, rpm, zip,
+ cpio, lha and rar files with a single click.
+
+ o All of the Midnight Commander operations work with the virtual
+ file system, enabling you to do complex tasks.
+
+ o Mouse support on the Linux console and under X11's xterms.
+
+ o Learn Keys: The Midnight Commander may be configured at run
+ time to support any kind of input keys for a given terminal,
+ making its operation even on the most wierd terminals a
+ breeze.
+
+ o Text and hex editors are available for you to use.
+
+ o Hotlist allows you to keep a list of common visited
+ locations (including ftp sites).
+
+ o Command completion: By pressing Alt-Tab in any place where a
+ filename or an executable are expected, the Midnight Commander
+ will complete for you the name. If you quickly press Alt-Tab
+ twice you can get a listbox with the possible completions
+ available.
+
+ o Subshell support: Run your commands by a real shell
+ interpreter. The Midnight Commander interacts with bash, tcsh
+ and zsh to provide you with all of the facilities available in
+ your shell.
+
+ o Find file command can now search inside the contents of
+ files.
+
+ o Background operations allows you to copy or move files from
+ any virtual file system while you do other tasks (ie, you can
+ do background ftp copies).
+
+ o Proxy support with our ftpfs.
+
+ o Linux file recovery: If you are using Linux system, you can
+ recover deleted files from an ext2fs partition with the
+ undelete file system. This is a low level file recovery
+ function that will recover files deleted by any program in
+ Linux.
+
+ Please note that the undelete file system can only recover
+ 12 file system blocks if the file was deleted with a kernel
+ in the 2.0.x series. The 2.1.x series have fixed this and you
+ can recover all of the file contents there.
+
+ o External panelization: You can run any arbitrary external
+ command and the Midnight Commander will display the output
+ generated as a file listing that can be manipulated as a
+ regular directory.
+
+ o Emacs like key bindings in all of our widgets.
+
+ o Powerfull context dependant actions are available.
+
+ o Powerfull built-in file viewer: The file viewer, together
+ with the context dependant actions is used to format man pages
+ on the fly, coloring mail messages and more.
+
+
+Midnight Commander editions:
+----------------------------
+
+The Midnight Commander may be compiled into three different editions:
+the text mode edition, the Tk edition and the XView edition. Please
+note that currently the only supported edition is the text mode
+edition. The Tk and XView editions are included with the tar file but
+are not finished and thus not supported.
+
+
+Where to get more information:
+------------------------------
+
+There is a mailing list for discussion on enhancing the program, future
+directions and announcements; if you want to subscribe, send mail to:
+
+majordomo@roxanne.nuclecu.unam.mx
+
+There is a WWW page for the Midnight Commander with the URL:
+<http://mc.blackdown.org/mc/>.
+
+
+The Midnight Commander:
+-----------------------
+
+The Midnight Commander is released under the GNU General Public License
+version 2.0 or any later version. A copy of the file is included with
+this distribution package.
+
+If you have comments, you can send them to me:
+
+miguel@roxanne.nuclecu.unam.mx
+
+or if it would benefit more people, to the mailing list:
+
+mc@roxanne.nuclecu.unam.mx
+
+Help develop and enhance free software.
+
+
+Mini-documentation:
+-------------------
+
+o Use the F-Keys for invoking the commands in the function key bar.
+ If your terminal doesn't support F-keys, you can use the <ESC digit>
+ sequence to invoke the corresponding F-digit key.
+
+o Tab changes the current panel.
+
+o All input lines have emacs-like key-bindings (command history is
+ accessed through the M-p and M-n keys).
+
+o The panels accept C-n, C-p for browsing the panel (like in emacs).
+
+o M-Enter copies the currently selected file name to the input line.
+
+o M-Tab completes the current word (or tries to).
+
+o The Virtual File System is a cute addition to the project, you may
+ browse in tar and compressed tar files as well as browsing remote
+ machines with the mcfs file system.
+
+o Please read the manual page.
+
+o Read the file src/TODO for the current projects.
+
+You can access the whole documentation online with the F1 key,
+although it's not as nice as the groff printed manual page :-)
+
+
+Where you may obtain the Midnight Commander
+-------------------------------------------
+
+The software should be available by anonymous ftp at sunsite.unc.edu
+in the directory /pub/Linux/utils/file and at ftp.nuclecu.unam.mx
+in the directory /linux/local.
+
+The last alpha versions are available at ftp.nuclecu.unam.mx in the
+directory /linux/local/devel.
+
+European mirrors of both version 3.1 and alpha versions are available
+at sunsite.mff.cuni.cz in the directory /GNU/mc and at ftp.teuto.de
+in the directory /lmb/mc.
+
+
+Reporting problems
+------------------
+
+Please, send a detailed description of your problem to the
+mc-bugs@roxanne.nuclecu.unam.mx address.
+
+Include the version of the program, the operating system that you are
+using, the compiler and compiler flags used to compile the program (if
+you know them), what kind of distribution you are using (if a
+GNU/Linux system).
+
+If the program crashed and produces a core dump, please provide a
+stack trace of the program.
+
+You can do this by running dbx or gdb like this:
+
+gdb mc core
+(gdb) where
+
+
+
--- /dev/null
+
+Midnight Commander for Windows NT and Windows '95
+-------------------------------------------------
+
+0. Hello
+1. Compiling
+2. Changes made
+
+0. Hello
+--------
+Hello, this is the Midnight Commander port to Win32. It has many bugs, but is
+quite stable now. Maybe you can help as an beta tester or as a programmer. In
+either case you would like subscribe to mc-devel list
+(see readme files in main doc on how to do this) and contact us.
+
+1. Compiling
+------------
+
+1.1. Compiler
+----------------
+Microsoft Visual C++ for Windows NT (all versions, including 4.x) are supported.
+In nt/makefile you can find an external makefile, and in nt/makefile.vc1.nt, vc4.nt
+projects for the visual IDE. Two makefiles are add since the version 3.5.39. They
+are produced from MS VC 4.x and are named as ntaxp.mak (for Windows NT AXP)
+and ntint.mak (for Windows NT Intel). If you want to use them, you will have to
+change the path coded in these two files.
+
+Other compilers such as Watcom, or Borland tools should be quite
+straightforward, but has not been tested.
+
+Under Cygnus tools, apparently everything works just fine.
+
+1.2. General issues
+--------------------
+Preprocessor
+ Define:
+ LIBDIR
+ _OS_NT - OS flag
+ OS2_NT - Flag for OS/2 and NT
+ HAVE_CONFIG_H - config.h flag
+
+ Includes:
+ So as to avoid chaos in include files, I decided to create some
+ fake includes for UNIX counterparts. The empty files you need to create are:
+ pwd.h grp.h
+ sys/param.h sys/time.h
+
+1.3 Windowing Library
+--------------------------------
+Currently only support for S-lang windowing library is given. I know no curses
+public library ported to Win32 consoles, and I think it is useless to port
+it now. You may want to download the complete distribution it from
+ftp://space.mit.edu/pub/davis.
+
+
+2. Changes made
+---------------
+
+2.1. Changes to main code
+-------------------------
+They are enclosed in #ifdef _OS_NT or OS2_NT blocks.
+
+Wrote something similar to statfs in UTIL.C
+Wrote truncate.
+Changed (almost) all references to "/" path slash with PATH_CHAR and strPATH_CHAR.
+Changed name of CONTROL_FILE.
+Changed name of shell and call to shell.
+
+In some cases we supressed code. This is temporal (so that mc can compile). In
+the future we will provide fake or true interfaces for these features.
+ - Links: creation and information on links are not supported in NT. We
+ should provide a fake interface for the local filesystem and
+ a true one for networked.
+ - GID/UID queries (get_user, owner, preserve UID/GID on copy, ...).
+ - TERMinals: all the code directly done with terminals must be supressed.
+ - Signals: deleted. Should support the native ones.
+ - pipes: had some trouble in ext.c and with error_pipes but soon will be fixed.
+ - Chown command: Not supported yet.
+
+2.2. Files rewritten
+--------------------
+There are 3 files with so many changes that they have been moved to independent
+archives (or OS dependent).
+ - Chmod.nt.c: this command will query and change attributes (hidden, system,
+ archive,...). Maybe we should write a real chmod (and also a
+ chown). It is not finished, but works almost fine. Look that
+ the stat st_mode member is filled with attributes, not modes.
+ - Cons.handler.nt.c: Supports same API as linux cons.handler.c. It allocates
+ a new console buffer and switches between the two when doing a
+ shell. The new allocated one is the used by Midnight commander.
+ (look that to make this we should also redirect standard handles)
+ - Key.nt.c: a static table maps Virtual Key codes to Curses-like Key codes.
+ Also mouse events are supported.
+ still preliminar.
+ - utilnt.c: Contains utilunix.c functions, with Win32 implementation
+
+2.3. New files
+--------------
+ - drive.nt.c: A Change Drive command has been implemented. Two lines
+ in main.c were included (in the left/right panel menus).
+ The funcs drive_cmd_a/b are implemented in this new file.
+ It will build a dialog with available drives as buttons.
+ bug: too many drives are not supported (think just 7). have
+ to rewrite to support more than one line.
+
+ - util.debug.c: developers-only utilities to trace Win32 API call error codes
+ - util.WinNT.c: Windows NT specific functions:
+ getuid(): Will check your priviledges and return 0 (root)
+ if you have Administrator priviledges.
+ - util.Win32.c: Windows NT & 95 utilities: (specific to Win32, no UNIX counterpart)
+ getEXEtype(): check if executable is CUI or GUI.
+
+2.4. Changes made from me (Alexander Dong, ado@software-ag.de)
+--------------------
+
+I have hacked some codes for Windows NT AXP and NT Intel.
+Drive.nt.c was rewritten for a beautiful Drive_Change dialog window.
+
+All main source changed from me are marked with the comment /* .ado */.
+
+I have also included two own Makefiles:
+ ntaxp.mak (for Windows NT Alpha) and
+ ntint.mak (for Windows 95/NT Intel).
+You will have to change the path in these files before use them. They
+are both for Microsoft Visual C++ 4.x.
+
--- /dev/null
+# Generated automatically from Makefile.in by configure.
+srcdir = .
+
+rootdir = $(srcdir)/..
+include ../Make.common
+
+CFLAGS = $(XCFLAGS)
+CPPFLAGS = $(XCPPFLAGS)
+LDFLAGS = $(XLDFLAGS)
+DEFS = $(XDEFS)
+LIBS = $(XLIBS) $(XLIB)
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+AR = /usr/bin/ar
+
+#
+# Distribution variables
+#
+
+EDITSRC = edit.c editcmd.c editwidget.c edit_key_translator.c editdraw.c \
+ edit.h editmenu.c editcmddef.h wordproc.c syntax.c editoptions.c
+
+EDITOBJS = edit.o editcmd.o editwidget.o editdraw.o editmenu.o wordproc.o \
+ syntax.o editoptions.o
+
+DIST = Makefile.in README.edit $(EDITSRC)
+
+all: libedit.a
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DMIDNIGHT $<
+
+check:
+ @echo no tests are supplied.
+
+libedit.a: $(EDITOBJS)
+ $(RMF) $@
+ $(AR) cr $@ $(EDITOBJS)
+ -$(RANLIB) $@
+
+mcedit:
+ -$(RMF) $(DESTDIR)$(bindir)/$(binprefix)mcedit
+ $(LN_S) mc $(DESTDIR)$(bindir)/$(binprefix)mcedit
+
+showlibdep:
+ @echo 'OBJS="$(EDITOBJS)"'
+
+cross:
+ $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \
+ CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses "
+
+TAGS: $(EDITSRC)
+ etags $(EDITSRC)
+
+clean:
+ $(RMF) *.o core a.out libedit.a
+
+realclean: clean
+ $(RMF) .depend
+ $(RMF) TAGS
+ $(RMF) *~
+
+distclean:
+ -$(RMF) $(srcdir)/*~ $(srcdir)/*.o $(srcdir)/a.out
+ -$(RMF) $(srcdir)/core $(srcdir)/libedit.a
+ -if test $(srcdir) = .; then $(MAKE) realclean; fi
+ -$(RMF) $(srcdir)/Makefile
+
+install: mcedit
+
+uninstall:
+ -$(RMF) $(DESTDIR)$(bindir)/$(binprefix)mcedit
+
+distcopy:
+ $(CP) $(DIST) ../../mc-$(VERSION)/edit
+
+depend dep: mcdep
+
+fastdeploc:
+
+# ***Dependencies***Do not edit***
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+# ***End of dependencies***
--- /dev/null
+/* editor low level data handling and cursor fundamentals.
+
+ Copyright (C) 1996, 1997 the Free Software Foundation
+
+ Authors: 1996, 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#define _EDIT_C THIS_IS
+
+#include <config.h>
+#if defined(OS2_NT)
+# include <io.h>
+# include <fcntl.h>
+# define CR_LF_TRANSLATION
+#endif
+#include "edit.h"
+
+#ifdef SCO_FLAVOR
+# include <sys/timeb.h>
+#endif /* SCO_FLAVOR */
+#include <time.h> /* for ctime() */
+
+/*
+ *
+ * here's a quick sketch of the layout: (don't run this through indent.)
+ *
+ * (b1 is buffers1 and b2 is buffers2)
+ *
+ * |
+ * \0\0\0\0\0m e _ f i l e . \nf i n . \n|T h i s _ i s _ s o\0\0\0\0\0\0\0\0\0
+ * ______________________________________|______________________________________
+ * |
+ * ... | b2[2] | b2[1] | b2[0] | b1[0] | b1[1] | b1[2] | ...
+ * |-> |-> |-> |-> |-> |-> |
+ * |
+ * _<------------------------->|<----------------->_
+ * WEdit->curs2 | WEdit->curs1
+ * ^ | ^
+ * | ^|^ |
+ * cursor ||| cursor
+ * |||
+ * file end|||file beginning
+ * |
+ * |
+ *
+ * _
+ * This_is_some_file
+ * fin.
+ *
+ *
+ */
+
+/*
+ returns a byte from any location in the file.
+ Returns '\n' if out of bounds.
+ */
+int edit_get_byte (WEdit * edit, long byte_index)
+{
+ unsigned long p;
+ if (byte_index >= (edit->curs1 + edit->curs2) || byte_index < 0)
+ return '\n';
+
+ if (byte_index >= edit->curs1) {
+ p = edit->curs1 + edit->curs2 - byte_index - 1;
+ return edit->buffers2[p >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (p & M_EDIT_BUF_SIZE) - 1];
+ } else {
+ return edit->buffers1[byte_index >> S_EDIT_BUF_SIZE][byte_index & M_EDIT_BUF_SIZE];
+ }
+}
+
+char *edit_get_buffer_as_text (WEdit * e)
+{
+ int l, i;
+ char *t;
+ l = e->curs1 + e->curs2;
+ t = CMalloc (l + 1);
+ for (i = 0; i < l; i++)
+ t[i] = edit_get_byte (e, i);
+ t[l] = 0;
+ return t;
+}
+
+/* Initialisation routines */
+
+/* returns 1 on error */
+/* loads file OR text into buffers. Only one must be none-NULL. */
+/* cursor set to start of file */
+int init_dynamic_edit_buffers (WEdit * edit, const char *filename, const char *text)
+{
+
+#if defined CR_LF_TRANSLATION
+ /* Variables needed for safe handling of Translation from Microsoft CR/LF EOL to
+ Unix Style LF EOL - Franco */
+ long bytes_wanted,bytes_read,bytes_missing;
+ char *p;
+#endif
+
+ long buf;
+ int j, file = 0, buf2;
+
+ for (j = 0; j <= MAXBUFF; j++) {
+ edit->buffers1[j] = NULL;
+ edit->buffers2[j] = NULL;
+ }
+
+ if (filename)
+ if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT)) == -1) {
+/* The file-name is printed after the ':' */
+ edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename, " ", 0)));
+ return 1;
+ }
+ edit->curs2 = edit->last_byte;
+
+ buf2 = edit->curs2 >> S_EDIT_BUF_SIZE;
+
+ edit->buffers2[buf2] = CMalloc (EDIT_BUF_SIZE);
+
+/*
+_read returns the number of bytes read,
+which may be less than count if there are fewer than count bytes left in the file
+or if the file was opened in text mode,
+in which case each carriage return\96linefeed (CR-LF) pair is replaced
+with a single linefeed character. Only the single linefeed character is counted
+in the return value. The replacement does not affect the file pointer.
+
+_eof returns 1 if the current position is end of file, or 0 if it is not.
+A return value of -1 indicates an error; in this case, errno is set to EBADF,
+which indicates an invalid file handle.
+*/
+ if (filename){
+
+#if defined CR_LF_TRANSLATION
+ bytes_wanted=edit->curs2 & M_EDIT_BUF_SIZE;
+ p = (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
+ bytes_read = read (file, p , edit->curs2 & M_EDIT_BUF_SIZE);
+ bytes_missing = bytes_wanted - bytes_read ;
+ while(bytes_missing ){
+ p += bytes_read;
+ bytes_read = read(file,p,bytes_missing);
+ if(bytes_read <= 0) break;
+ bytes_missing -= bytes_read ;
+ }
+#else
+ read (file, (char *) edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), edit->curs2 & M_EDIT_BUF_SIZE);
+#endif
+ }
+ else {
+ memcpy (edit->buffers2[buf2] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE), text, edit->curs2 & M_EDIT_BUF_SIZE);
+ text += edit->curs2 & M_EDIT_BUF_SIZE;
+ }
+
+ for (buf = buf2 - 1; buf >= 0; buf--) {
+ edit->buffers2[buf] = CMalloc (EDIT_BUF_SIZE);
+ if (filename){
+#if defined CR_LF_TRANSLATION
+ bytes_wanted = EDIT_BUF_SIZE;
+ p = (char *) edit->buffers2[buf];
+ bytes_read = read (file, p, EDIT_BUF_SIZE);
+ bytes_missing = bytes_wanted - bytes_read ;
+ while(bytes_missing ){
+ p += bytes_read;
+ bytes_read = read(file,p,bytes_missing);
+ if(bytes_read <= 0) break;
+ bytes_missing -= bytes_read ;
+ }
+#else
+ read (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
+#endif
+ }
+ else {
+ memcpy (edit->buffers2[buf], text, EDIT_BUF_SIZE);
+ text += EDIT_BUF_SIZE;
+ }
+ }
+
+ edit->curs1 = 0;
+ if (filename)
+ close (file);
+
+ return 0;
+}
+
+/* returns 1 on error */
+int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size)
+{
+ struct stat s;
+ int file;
+
+/* VARS for Lastbyte calculation in TEXT mode FRANCO */
+#if defined CR_LF_TRANSLATION
+ char tmp_buf[1024];
+ long real_size,bytes_read;
+#endif
+
+ if (text) {
+ edit->last_byte = text_size;
+ filename = NULL;
+ } else {
+#if defined(MIDNIGHT) || defined(GTK)
+ if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0)
+ {
+ close(creat((char *) filename, 0666));
+ if ((file = open ((char *) filename, O_RDONLY | MY_O_TEXT )) < 0) {
+ edit_error_dialog (_(" Error "), get_sys_error (catstrs (" Fail trying to open the file, ", filename, ", for reading ", 0)));
+ return 1;
+ }
+ edit->delete_file = 1;
+ }
+#else
+ if ((file = open ((char *) filename, O_RDONLY)) < 0) {
+ edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Fail trying to open file for reading: "), filename, " ", 0)));
+ return 1;
+ }
+#endif
+ if (stat ((char *) filename, &s) < 0) {
+ close (file);
+/* The file-name is printed after the ':' */
+ edit_error_dialog (_(" Error "), get_sys_error (catstrs (_(" Cannot get size/permissions info on file: "), filename, " ", 0)));
+ return 1;
+ }
+ if (S_ISDIR (s.st_mode) || S_ISSOCK (s.st_mode)
+ || S_ISFIFO (s.st_mode)) {
+ close (file);
+/* The file-name is printed after the ':' */
+ edit_error_dialog (_(" Error "), catstrs (_(" Not an ordinary file: "), filename, " ", 0));
+ return 1;
+ }
+ if (s.st_size >= SIZE_LIMIT) {
+ close (file);
+/* The file-name is printed after the ':' */
+ edit_error_dialog (_(" Error "), catstrs (_(" File is too large: "), \
+ filename, _(" \n Increase edit.h:MAXBUF and recompile the editor. "), 0));
+ return 1;
+ }
+
+/* Lastbyte calculation in TEXT mode FRANCO */
+#if defined CR_LF_TRANSLATION
+ if(file && (!text)){
+ real_size=0;
+ tmp_buf[1024]=0;
+ while((bytes_read = read(file,tmp_buf,1024)) > 0){
+ real_size += bytes_read;
+ }
+ s.st_size = real_size;
+ }
+
+#endif
+
+ close (file);
+ edit->last_byte = s.st_size;
+ edit->stat = s;
+ }
+
+ return init_dynamic_edit_buffers (edit, filename, text);
+}
+
+#ifdef MIDNIGHT
+#define space_width 1
+#else
+int space_width;
+extern int option_long_whitespace;
+extern unsigned char per_char[256];
+
+void edit_set_space_width (int s)
+{
+ space_width = s;
+}
+
+#endif
+
+/* fills in the edit struct. returns 0 on fail. Pass edit as NULL for this function to do an malloc for you */
+WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size)
+{
+ char *f;
+#ifndef MIDNIGHT
+ if (option_long_whitespace)
+ edit_set_space_width (per_char[' '] * 2);
+ else
+ edit_set_space_width (per_char[' ']);
+#endif
+ if (!edit)
+ edit = malloc (sizeof (WEdit));
+ if (!edit) {
+ edit_error_dialog (_(" Error "), _(" Error allocating memory "));
+ return 0;
+ }
+ memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
+#ifndef MIDNIGHT
+ edit->max_column = columns * FONT_MEAN_WIDTH;
+#endif
+ edit->num_widget_lines = lines;
+ edit->num_widget_columns = columns;
+ edit->stat.st_mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+ edit->stat.st_uid = getuid ();
+ edit->stat.st_gid = getgid ();
+ edit->bracket = -1;
+ if (!dir)
+ dir = "";
+ f = (char *) filename;
+ if (filename)
+ f = catstrs (dir, filename, 0);
+ if (edit_load_file (edit, f, text, text_size)) {
+/* edit_load_file already gives an error message */
+ free (edit);
+ return 0;
+ }
+ edit->force |= REDRAW_PAGE;
+ if (filename) {
+ filename = catstrs (dir, filename, 0);
+ edit_split_filename (edit, (char *) filename);
+ } else {
+ edit->filename = strdup ("");
+ edit->dir = strdup(dir);
+ }
+ edit->stack_size = START_STACK_SIZE;
+ edit->stack_size_mask = START_STACK_SIZE - 1;
+ edit->undo_stack = malloc ((edit->stack_size + 10) * sizeof (long));
+ if (!edit->undo_stack) {
+ edit_error_dialog (_(" Error "), _(" Error allocating memory "));
+ free (edit);
+ return 0;
+ }
+ edit->total_lines = edit_count_lines (edit, 0, edit->last_byte);
+ edit_load_syntax (edit, 0, 0);
+ {
+ int fg, bg;
+ edit_get_syntax_color (edit, -1, &fg, &bg);
+ }
+ return edit;
+}
+
+
+/* clear the edit struct, freeing everything in it. returns 1 on success */
+int edit_clean (WEdit * edit)
+{
+ if (edit) {
+ int j = 0;
+ edit_free_syntax_rules (edit);
+ for (; j <= MAXBUFF; j++) {
+ if (edit->buffers1[j] != NULL)
+ free (edit->buffers1[j]);
+ if (edit->buffers2[j] != NULL)
+ free (edit->buffers2[j]);
+ }
+
+ if (edit->undo_stack)
+ free (edit->undo_stack);
+ if (edit->filename)
+ free (edit->filename);
+ if (edit->dir)
+ free (edit->dir);
+/* we don't want to clear the widget */
+ memset (&(edit->from_here), 0, (unsigned long) &(edit->to_here) - (unsigned long) &(edit->from_here));
+ return 1;
+ }
+ return 0;
+}
+
+
+/* returns 1 on success */
+int edit_renew (WEdit * edit)
+{
+ int lines = edit->num_widget_lines;
+ int columns = edit->num_widget_columns;
+ char *dir;
+
+ if (edit->dir)
+ dir = strdup (edit->dir);
+ else
+ dir = 0;
+
+ edit_clean (edit);
+ if (!edit_init (edit, lines, columns, 0, "", dir, 0))
+ return 0;
+ return 1;
+}
+
+/* returns 1 on success */
+int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size)
+{
+ int lines = edit->num_widget_lines;
+ int columns = edit->num_widget_columns;
+ edit_clean (edit);
+ if (!edit_init (edit, lines, columns, filename, text, dir, text_size)) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/*
+ Recording stack for undo:
+ The following is an implementation of a compressed stack. Identical
+ pushes are recorded by a negative prefix indicating the number of times the
+ same char was pushed. This saves space for repeated curs-left or curs-right
+ delete etc.
+
+ eg:
+
+ pushed: stored:
+
+ a
+ b a
+ b -3
+ b b
+ c --> -4
+ c c
+ c d
+ c
+ d
+
+ If the stack long int is 0-255 it represents a normal insert (from a backspace),
+ 256-512 is an insert ahead (from a delete), If it is betwen 600 and 700 it is one
+ of the cursor functions #define'd in edit.h. 1000 through 700'000'000 is to
+ set edit->mark1 position. 700'000'000 through 1400'000'000 is to set edit->mark2
+ position.
+
+ The only way the curser moves or the buffer is changed is through the routines:
+ insert, backspace, insert_ahead, delete, and cursor_move.
+ These record the reverse undo movements onto the stack each time they are
+ called.
+
+ Each key press results in a set of actions (insert; delete ...). So each time
+ a key is pressed the current position of start_display is pushed as
+ KEY_PRESS + start_display. Then for undoing, we pop until we get to a number
+ over KEY_PRESS. We then assign this number less KEY_PRESS to start_display. So undo
+ tracks scrolling and key actions exactly. (KEY_PRESS is about (2^31) * (2/3) = 1400'000'000)
+
+*/
+
+static int push_action_disabled = 0;
+
+void edit_push_action (WEdit * edit, long c,...)
+{
+ unsigned long sp = edit->stack_pointer;
+ unsigned long spm1;
+ long *t;
+/* first enlarge the stack if necessary */
+ if (sp > edit->stack_size - 10) { /* say */
+ if (option_max_undo < 256)
+ option_max_undo = 256;
+ if (edit->stack_size < option_max_undo) {
+ t = malloc ((edit->stack_size * 2 + 10) * sizeof (long));
+ if (t) {
+ memcpy (t, edit->undo_stack, sizeof (long) * edit->stack_size);
+ free (edit->undo_stack);
+ edit->undo_stack = t;
+ edit->stack_size <<= 1;
+ edit->stack_size_mask = edit->stack_size - 1;
+ }
+ }
+ }
+ spm1 = (edit->stack_pointer - 1) & edit->stack_size_mask;
+ if (push_action_disabled)
+ return;
+
+#ifdef FAST_MOVE_CURSOR
+ if (c == CURS_LEFT_LOTS || c == CURS_RIGHT_LOTS) {
+ va_list ap;
+ edit->undo_stack[sp] = c == CURS_LEFT_LOTS ? CURS_LEFT : CURS_RIGHT;
+ edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
+ va_start (ap, c);
+ c = -(va_arg (ap, int));
+ va_end (ap);
+ } else
+#endif /* ! FAST_MOVE_CURSOR */
+ if (spm1 != edit->stack_bottom && ((sp - 2) & edit->stack_size_mask) != edit->stack_bottom) {
+ int d;
+ if (edit->undo_stack[spm1] < 0) {
+ d = edit->undo_stack[(sp - 2) & edit->stack_size_mask];
+ if (d == c) {
+ if (edit->undo_stack[spm1] > -1000000000) {
+ if (c < KEY_PRESS) /* --> no need to push multiple do-nothings */
+ edit->undo_stack[spm1]--;
+ return;
+ }
+ }
+/* #define NO_STACK_CURSMOVE_ANIHILATION */
+#ifndef NO_STACK_CURSMOVE_ANIHILATION
+ else if ((c == CURS_LEFT && d == CURS_RIGHT)
+ || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
+ if (edit->undo_stack[spm1] == -2)
+ edit->stack_pointer = spm1;
+ else
+ edit->undo_stack[spm1]++;
+ return;
+ }
+#endif
+ } else {
+ d = edit->undo_stack[spm1];
+ if (d == c) {
+ if (c >= KEY_PRESS)
+ return; /* --> no need to push multiple do-nothings */
+ edit->undo_stack[sp] = -2;
+ goto check_bottom;
+ }
+#ifndef NO_STACK_CURSMOVE_ANIHILATION
+ else if ((c == CURS_LEFT && d == CURS_RIGHT)
+ || (c == CURS_RIGHT && d == CURS_LEFT)) { /* a left then a right anihilate each other */
+ edit->stack_pointer = spm1;
+ return;
+ }
+#endif
+ }
+ }
+ edit->undo_stack[sp] = c;
+ check_bottom:
+
+ edit->stack_pointer = (edit->stack_pointer + 1) & edit->stack_size_mask;
+
+/*if the sp wraps round and catches the stack_bottom then erase the first set of actions on the stack to make space - by moving stack_bottom forward one "key press" */
+ c = (edit->stack_pointer + 2) & edit->stack_size_mask;
+ if (c == edit->stack_bottom || ((c + 1) & edit->stack_size_mask) == edit->stack_bottom)
+ do {
+ edit->stack_bottom = (edit->stack_bottom + 1) & edit->stack_size_mask;
+ } while (edit->undo_stack[edit->stack_bottom] < KEY_PRESS && edit->stack_bottom != edit->stack_pointer);
+
+/*If a single key produced enough pushes to wrap all the way round then we would notice that the [stack_bottom] does not contain KEY_PRESS. The stack is then initialised: */
+ if (edit->stack_pointer != edit->stack_bottom && edit->undo_stack[edit->stack_bottom] < KEY_PRESS)
+ edit->stack_bottom = edit->stack_pointer = 0;
+}
+
+/*
+ TODO: if the user undos until the stack bottom, and the stack has not wrapped,
+ then the file should be as it was when he loaded up. Then set edit->modified to 0.
+ */
+long pop_action (WEdit * edit)
+{
+ long c;
+ unsigned long sp = edit->stack_pointer;
+ if (sp == edit->stack_bottom) {
+ return STACK_BOTTOM;
+ }
+ sp = (sp - 1) & edit->stack_size_mask;
+ if ((c = edit->undo_stack[sp]) >= 0) {
+/* edit->undo_stack[sp] = '@'; */
+ edit->stack_pointer = (edit->stack_pointer - 1) & edit->stack_size_mask;
+ return c;
+ }
+ if (sp == edit->stack_bottom) {
+ return STACK_BOTTOM;
+ }
+ c = edit->undo_stack[(sp - 1) & edit->stack_size_mask];
+ if (edit->undo_stack[sp] == -2) {
+/* edit->undo_stack[sp] = '@'; */
+ edit->stack_pointer = sp;
+ } else
+ edit->undo_stack[sp]++;
+
+ return c;
+}
+
+
+/* is called whenever a modification is made by one of the four routines below */
+static inline void edit_modification (WEdit * edit)
+{
+ edit->modified = 1;
+}
+
+
+/*
+ Basic low level single character buffer alterations and movements at the cursor.
+ Returns char passed over, inserted or removed.
+ */
+
+void edit_insert (WEdit * edit, int c)
+{
+/* check if file has grown to large */
+ if (edit->last_byte >= SIZE_LIMIT)
+ return;
+
+/* first we must update the position of the display window */
+ if (edit->curs1 < edit->start_display) {
+ edit->start_display++;
+ if (c == '\n')
+ edit->start_line++;
+ }
+/* now we must update some info on the file and check if a redraw is required */
+ if (c == '\n') {
+ edit->curs_line++;
+ edit->total_lines++;
+ edit->force |= REDRAW_LINE_ABOVE | REDRAW_AFTER_CURSOR;
+ }
+/* tell that we've modified the file */
+ edit_modification (edit);
+
+/* save the reverse command onto the undo stack */
+ edit_push_action (edit, BACKSPACE);
+
+/* update markers */
+ edit->mark1 += (edit->mark1 > edit->curs1);
+ edit->mark2 += (edit->mark2 > edit->curs1);
+ edit->last_get_rule += (edit->last_get_rule > edit->curs1);
+
+/* add a new buffer if we've reached the end of the last one */
+ if (!(edit->curs1 & M_EDIT_BUF_SIZE))
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
+
+/* perfprm the insertion */
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = (unsigned char) c;
+
+/* update file length */
+ edit->last_byte++;
+
+/* update cursor position */
+ edit->curs1++;
+}
+
+
+/* same as edit_insert and move left */
+void edit_insert_ahead (WEdit * edit, int c)
+{
+ if (edit->last_byte >= SIZE_LIMIT)
+ return;
+ if (edit->curs1 < edit->start_display) {
+ edit->start_display++;
+ if (c == '\n')
+ edit->start_line++;
+ }
+ if (c == '\n') {
+ edit->total_lines++;
+ edit->force |= REDRAW_AFTER_CURSOR;
+ }
+ edit_modification (edit);
+ edit_push_action (edit, DELETE);
+
+ edit->mark1 += (edit->mark1 >= edit->curs1);
+ edit->mark2 += (edit->mark2 >= edit->curs1);
+ edit->last_get_rule += (edit->last_get_rule >= edit->curs1);
+
+ if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
+ edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
+
+ edit->last_byte++;
+ edit->curs2++;
+}
+
+
+int edit_delete (WEdit * edit)
+{
+ int p;
+ if (!edit->curs2)
+ return 0;
+
+ edit->mark1 -= (edit->mark1 > edit->curs1);
+ edit->mark2 -= (edit->mark2 > edit->curs1);
+ edit->last_get_rule -= (edit->last_get_rule > edit->curs1);
+
+ p = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
+
+ if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
+ free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = NULL;
+ }
+ edit->last_byte--;
+ edit->curs2--;
+
+ if (p == '\n') {
+ edit->total_lines--;
+ edit->force |= REDRAW_AFTER_CURSOR;
+ }
+ edit_push_action (edit, p + 256);
+ if (edit->curs1 < edit->start_display) {
+ edit->start_display--;
+ if (p == '\n')
+ edit->start_line--;
+ }
+ edit_modification (edit);
+
+ return p;
+}
+
+
+int edit_backspace (WEdit * edit)
+{
+ int p;
+ if (!edit->curs1)
+ return 0;
+
+ edit->mark1 -= (edit->mark1 >= edit->curs1);
+ edit->mark2 -= (edit->mark2 >= edit->curs1);
+ edit->last_get_rule -= (edit->last_get_rule >= edit->curs1);
+
+ p = *(edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE] + ((edit->curs1 - 1) & M_EDIT_BUF_SIZE));
+ if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
+ free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
+ }
+ edit->last_byte--;
+ edit->curs1--;
+
+ if (p == '\n') {
+ edit->curs_line--;
+ edit->total_lines--;
+ edit->force |= REDRAW_AFTER_CURSOR;
+ }
+ edit_push_action (edit, p);
+
+ if (edit->curs1 < edit->start_display) {
+ edit->start_display--;
+ if (p == '\n')
+ edit->start_line--;
+ }
+ edit_modification (edit);
+
+ return p;
+}
+
+#ifdef FAST_MOVE_CURSOR
+
+#define memqcpy(edit,d,s,i) \
+ { \
+ unsigned long next; \
+ char *dest = d; \
+ char *src = s; \
+ int n = i; \
+ while ((next = \
+ (unsigned long) memccpy (dest, src, '\n', n))) { \
+ edit->curs_line--; \
+ next -= (unsigned long) dest; \
+ n -= next; \
+ src += next; \
+ dest += next; \
+ } \
+ }
+
+int edit_move_backward_lots (WEdit * edit, long increment)
+{
+ int r, s, t;
+ char *p;
+
+ if (increment > edit->curs1)
+ increment = edit->curs1;
+ if (increment <= 0)
+ return -1;
+ edit_push_action (edit, CURS_RIGHT_LOTS, increment);
+
+ t = r = EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE);
+ if (r > increment)
+ r = increment;
+ s = edit->curs1 & M_EDIT_BUF_SIZE;
+
+ p = 0;
+ if (s > r) {
+ memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - r, r);
+ } else {
+ if (s) {
+ memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - s,
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE], s);
+ p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
+ }
+ memqcpy (edit, edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + t - r,
+ edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s), r - s);
+ }
+ increment -= r;
+ edit->curs1 -= r;
+ edit->curs2 += r;
+ if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
+ if (p)
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
+ else
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
+ } else {
+ if (p)
+ free (p);
+ }
+
+ s = edit->curs1 & M_EDIT_BUF_SIZE;
+ while (increment) {
+ p = 0;
+ r = EDIT_BUF_SIZE;
+ if (r > increment)
+ r = increment;
+ t = s;
+ if (r < t)
+ t = r;
+ memqcpy (edit,
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - t,
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] + s - t,
+ t);
+ if (r >= s) {
+ if (t) {
+ p = edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE];
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = 0;
+ }
+ memqcpy (edit,
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] + EDIT_BUF_SIZE - r,
+ edit->buffers1[(edit->curs1 >> S_EDIT_BUF_SIZE) - 1] + EDIT_BUF_SIZE - (r - s),
+ r - s);
+ }
+ increment -= r;
+ edit->curs1 -= r;
+ edit->curs2 += r;
+ if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
+ if (p)
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = p;
+ else
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
+ } else {
+ if (p)
+ free (p);
+ }
+ }
+ return edit_get_byte (edit, edit->curs1);
+}
+
+#endif /* ! FAST_MOVE_CURSOR */
+
+/* moves the curser right or left: increment positive or negative respectively */
+int edit_cursor_move (WEdit * edit, long increment)
+{
+/* this is the same as a combination of two of the above routines, with only one push onto the undo stack */
+ int c;
+
+#ifdef FAST_MOVE_CURSOR
+ if (increment < -256) {
+ edit->force |= REDRAW_PAGE;
+ return edit_move_backward_lots (edit, -increment);
+ }
+#endif /* ! FAST_MOVE_CURSOR */
+
+ if (increment < 0) {
+ for (; increment < 0; increment++) {
+ if (!edit->curs1)
+ return -1;
+
+ edit_push_action (edit, CURS_RIGHT);
+
+ c = edit_get_byte (edit, edit->curs1 - 1);
+ if (!((edit->curs2 + 1) & M_EDIT_BUF_SIZE))
+ edit->buffers2[(edit->curs2 + 1) >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1] = c;
+ edit->curs2++;
+ c = edit->buffers1[(edit->curs1 - 1) >> S_EDIT_BUF_SIZE][(edit->curs1 - 1) & M_EDIT_BUF_SIZE];
+ if (!((edit->curs1 - 1) & M_EDIT_BUF_SIZE)) {
+ free (edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE]);
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = NULL;
+ }
+ edit->curs1--;
+ if (c == '\n') {
+ edit->curs_line--;
+ edit->force |= REDRAW_LINE_BELOW;
+ }
+ }
+
+ return c;
+ } else if (increment > 0) {
+ for (; increment > 0; increment--) {
+ if (!edit->curs2)
+ return -2;
+
+ edit_push_action (edit, CURS_LEFT);
+
+ c = edit_get_byte (edit, edit->curs1);
+ if (!(edit->curs1 & M_EDIT_BUF_SIZE))
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE] = malloc (EDIT_BUF_SIZE);
+ edit->buffers1[edit->curs1 >> S_EDIT_BUF_SIZE][edit->curs1 & M_EDIT_BUF_SIZE] = c;
+ edit->curs1++;
+ c = edit->buffers2[(edit->curs2 - 1) >> S_EDIT_BUF_SIZE][EDIT_BUF_SIZE - ((edit->curs2 - 1) & M_EDIT_BUF_SIZE) - 1];
+ if (!(edit->curs2 & M_EDIT_BUF_SIZE)) {
+ free (edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE]);
+ edit->buffers2[edit->curs2 >> S_EDIT_BUF_SIZE] = 0;
+ }
+ edit->curs2--;
+ if (c == '\n') {
+ edit->curs_line++;
+ edit->force |= REDRAW_LINE_ABOVE;
+ }
+ }
+ return c;
+ } else
+ return -3;
+}
+
+/* These functions return positions relative to lines */
+
+/* returns index of last char on line + 1 */
+long edit_eol (WEdit * edit, long current)
+{
+ if (current < edit->last_byte) {
+ for (;; current++)
+#if 0
+ if (current == edit->last_byte || edit_get_byte (edit, current) == '\n')
+#else
+ if (edit_get_byte (edit, current) == '\n')
+#endif
+ break;
+ } else
+ return edit->last_byte;
+ return current;
+}
+
+/* returns index of first char on line */
+long edit_bol (WEdit * edit, long current)
+{
+ if (current > 0) {
+ for (;; current--)
+#if 0
+ if (current == 0 || edit_get_byte (edit, current - 1) == '\n')
+#else
+ if (edit_get_byte (edit, current - 1) == '\n')
+#endif
+ break;
+ } else
+ return 0;
+ return current;
+}
+
+
+int edit_count_lines (WEdit * edit, long current, int upto)
+{
+ int lines = 0;
+ if (upto > edit->last_byte)
+ upto = edit->last_byte;
+ if (current < 0)
+ current = 0;
+ while (current < upto)
+ if (edit_get_byte (edit, current++) == '\n')
+ lines++;
+ return lines;
+}
+
+
+/* If lines is zero this returns the count of lines from current to upto. */
+/* If upto is zero returns index of lines forward current. */
+long edit_move_forward (WEdit * edit, long current, int lines, long upto)
+{
+ if (upto) {
+ return edit_count_lines (edit, current, upto);
+ } else {
+ int next;
+ if (lines < 0)
+ lines = 0;
+ while (lines--) {
+ next = edit_eol (edit, current) + 1;
+ if (next > edit->last_byte)
+ break;
+ else
+ current = next;
+ }
+ return current;
+ }
+}
+
+
+/* Returns offset of 'lines' lines up from current */
+long edit_move_backward (WEdit * edit, long current, int lines)
+{
+ if (lines < 0)
+ lines = 0;
+ current = edit_bol (edit, current);
+ while((lines--) && current != 0)
+ current = edit_bol (edit, current - 1);
+ return current;
+}
+
+#ifdef MIDNIGHT
+/* If cols is zero this returns the count of columns from current to upto. */
+/* If upto is zero returns index of cols across from current. */
+long edit_move_forward3 (WEdit * edit, long current, int cols, long upto)
+{
+ long p, q;
+ int col = 0;
+
+ if (upto) {
+ q = upto;
+ cols = -10;
+ } else
+ q = edit->last_byte + 2;
+
+ for (col = 0, p = current; p < q; p++) {
+ int c;
+ if (cols != -10) {
+ if (col == cols)
+ return p;
+ if (col > cols)
+ return p - 1;
+ }
+ c = edit_get_byte (edit, p);
+ if (c == '\r')
+ continue;
+ else
+ if (c == '\t')
+ col += TAB_SIZE - col % TAB_SIZE;
+ else
+ col++;
+ /*if(edit->nroff ... */
+ if (c == '\n') {
+ if (upto)
+ return col;
+ else
+ return p;
+ }
+ }
+ return (float) col;
+}
+#endif
+
+/* returns the current column position of the cursor */
+int edit_get_col (WEdit * edit)
+{
+ return edit_move_forward3 (edit, edit_bol (edit, edit->curs1), 0, edit->curs1);
+}
+
+
+/* Scrolling functions */
+
+void edit_update_curs_row (WEdit * edit)
+{
+ edit->curs_row = edit->curs_line - edit->start_line;
+}
+
+void edit_update_curs_col (WEdit * edit)
+{
+ edit->curs_col = edit_move_forward3(edit, edit_bol(edit, edit->curs1), 0, edit->curs1);
+}
+
+/*moves the display start position up by i lines */
+void edit_scroll_upward (WEdit * edit, unsigned long i)
+{
+ int lines_above = edit->start_line;
+ if (i > lines_above)
+ i = lines_above;
+ if (i) {
+ edit->start_line -= i;
+ edit->start_display = edit_move_backward (edit, edit->start_display, i);
+ edit->force |= REDRAW_PAGE;
+ edit->force &= (0xfff - REDRAW_CHAR_ONLY);
+ }
+ edit_update_curs_row(edit);
+}
+
+
+/* returns 1 if could scroll, 0 otherwise */
+void edit_scroll_downward (WEdit * edit, int i)
+{
+ int lines_below;
+ lines_below = edit->total_lines - edit->start_line - (edit->num_widget_lines - 1);
+ if (lines_below > 0) {
+ if (i > lines_below)
+ i = lines_below;
+ edit->start_line += i;
+ edit->start_display = edit_move_forward (edit, edit->start_display, i, 0);
+ edit->force |= REDRAW_PAGE;
+ edit->force &= (0xfff - REDRAW_CHAR_ONLY);
+ }
+ edit_update_curs_row(edit);
+}
+
+void edit_scroll_right (WEdit * edit, int i)
+{
+ edit->force |= REDRAW_PAGE;
+ edit->force &= (0xfff - REDRAW_CHAR_ONLY);
+ edit->start_col -= i;
+}
+
+void edit_scroll_left (WEdit * edit, int i)
+{
+ if (edit->start_col) {
+ edit->start_col += i;
+ if (edit->start_col > 0)
+ edit->start_col = 0;
+ edit->force |= REDRAW_PAGE;
+ edit->force &= (0xfff - REDRAW_CHAR_ONLY);
+ }
+}
+
+/* high level cursor movement commands */
+
+static int is_in_indent (WEdit *edit)
+{
+ long p = edit_bol (edit, edit->curs1);
+ while (p < edit->curs1)
+ if (!strchr (" \t", edit_get_byte (edit, p++)))
+ return 0;
+ return 1;
+}
+
+static int left_of_four_spaces (WEdit *edit);
+
+static void edit_move_to_prev_col (WEdit * edit, long p)
+{
+ edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->prev_col, 0) - edit->curs1);
+
+ if (is_in_indent (edit) && option_fake_half_tabs) {
+ edit_update_curs_col (edit);
+ if (edit->curs_col % (HALF_TAB_SIZE * space_width)) {
+ int q = edit->curs_col;
+ edit->curs_col -= (edit->curs_col % (HALF_TAB_SIZE * space_width));
+ p = edit_bol (edit, edit->curs1);
+ edit_cursor_move (edit, edit_move_forward3 (edit, p, edit->curs_col, 0) - edit->curs1);
+ if (!left_of_four_spaces (edit))
+ edit_cursor_move (edit, edit_move_forward3 (edit, p, q, 0) - edit->curs1);
+ }
+ }
+}
+
+
+/* move i lines */
+static void edit_move_up (WEdit * edit, unsigned long i, int scroll)
+{
+ long p, l = edit->curs_line;
+
+ if (i > l)
+ i = l;
+ if (i) {
+ if (i > 1)
+ edit->force |= REDRAW_PAGE;
+ if (scroll)
+ edit_scroll_upward (edit, i);
+
+ p = edit_bol (edit, edit->curs1);
+ edit_cursor_move (edit, (p = edit_move_backward (edit, p, i)) - edit->curs1);
+ edit_move_to_prev_col (edit, p);
+
+ edit->search_start = edit->curs1;
+ edit->found_len = 0;
+ }
+}
+
+int is_blank (WEdit * edit, long offset)
+{
+ long s, f;
+ int c;
+ s = edit_bol (edit, offset);
+ f = edit_eol (edit, offset) - 1;
+ while (s <= f) {
+ c = edit_get_byte (edit, s++);
+ if ((c > ' ' && c <= '~') || c >= 160) /* non-printables on a line are considered "blank" */
+ return 0;
+ }
+ return 1;
+}
+
+int line_is_blank (WEdit * edit, long line)
+{
+ static long p = -1, l = 0;
+ if (p == -1 || abs (l - line) > abs (edit->curs_line - line)) {
+ l = edit->curs_line;
+ p = edit->curs1;
+ }
+ if (line < l)
+ p = edit_move_backward (edit, p, l - line);
+ else if (line > l)
+ p = edit_move_forward (edit, p, line - l, 0);
+ l = line;
+ return is_blank (edit, p);
+}
+
+/* moves up until a blank line is reached, or until just
+ before a non-blank line is reached */
+static void edit_move_up_paragraph (WEdit * edit, int scroll)
+{
+ int i;
+ if (edit->curs_line <= 1) {
+ i = 0;
+ } else {
+ if (line_is_blank (edit, edit->curs_line)) {
+ if (line_is_blank (edit, edit->curs_line - 1)) {
+ for (i = edit->curs_line - 1; i; i--)
+ if (!line_is_blank (edit, i)) {
+ i++;
+ break;
+ }
+ } else {
+ for (i = edit->curs_line - 1; i; i--)
+ if (line_is_blank (edit, i))
+ break;
+ }
+ } else {
+ for (i = edit->curs_line - 1; i; i--)
+ if (line_is_blank (edit, i))
+ break;
+ }
+ }
+ edit_move_up (edit, edit->curs_line - i, scroll);
+}
+
+/* move i lines */
+static void edit_move_down (WEdit * edit, int i, int scroll)
+{
+ long p, l = edit->total_lines - edit->curs_line;
+
+ if (i > l)
+ i = l;
+ if (i) {
+ if (i > 1)
+ edit->force |= REDRAW_PAGE;
+ if (scroll)
+ edit_scroll_downward (edit, i);
+ p = edit_bol (edit, edit->curs1);
+ edit_cursor_move (edit, (p = edit_move_forward (edit, p, i, 0)) - edit->curs1);
+ edit_move_to_prev_col (edit, p);
+
+ edit->search_start = edit->curs1;
+ edit->found_len = 0;
+ }
+}
+
+/* moves down until a blank line is reached, or until just
+ before a non-blank line is reached */
+static void edit_move_down_paragraph (WEdit * edit, int scroll)
+{
+ int i;
+ if (edit->curs_line >= edit->total_lines - 1) {
+ i = edit->total_lines;
+ } else {
+ if (line_is_blank (edit, edit->curs_line)) {
+ if (line_is_blank (edit, edit->curs_line + 1)) {
+ for (i = edit->curs_line + 1; i; i++)
+ if (!line_is_blank (edit, i) || i > edit->total_lines) {
+ i--;
+ break;
+ }
+ } else {
+ for (i = edit->curs_line + 1; i; i++)
+ if (line_is_blank (edit, i) || i >= edit->total_lines)
+ break;
+ }
+ } else {
+ for (i = edit->curs_line + 1; i; i++)
+ if (line_is_blank (edit, i) || i >= edit->total_lines)
+ break;
+ }
+ }
+ edit_move_down (edit, i - edit->curs_line, scroll);
+}
+
+static void edit_begin_page (WEdit *edit)
+{
+ edit_update_curs_row (edit);
+ edit_move_up (edit, edit->curs_row, 0);
+}
+
+static void edit_end_page (WEdit *edit)
+{
+ edit_update_curs_row (edit);
+ edit_move_down (edit, edit->num_widget_lines - edit->curs_row - 1, 0);
+}
+
+
+/* goto beginning of text */
+static void edit_move_to_top (WEdit * edit)
+{
+ if (edit->curs_line) {
+ edit_cursor_move (edit, -edit->curs1);
+ edit_move_to_prev_col (edit, 0);
+ edit->force |= REDRAW_PAGE;
+ edit->search_start = 0;
+ edit_update_curs_row(edit);
+ }
+}
+
+
+/* goto end of text */
+static void edit_move_to_bottom (WEdit * edit)
+{
+ if (edit->curs_line < edit->total_lines) {
+ edit_cursor_move (edit, edit->curs2);
+ edit->start_display = edit->last_byte;
+ edit->start_line = edit->total_lines;
+ edit_update_curs_row(edit);
+ edit_scroll_upward (edit, edit->num_widget_lines - 1);
+ edit->force |= REDRAW_PAGE;
+ }
+}
+
+/* goto beginning of line */
+static void edit_cursor_to_bol (WEdit * edit)
+{
+ edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
+ edit->search_start = edit->curs1;
+ edit->prev_col = edit_get_col (edit);
+}
+
+/* goto end of line */
+static void edit_cursor_to_eol (WEdit * edit)
+{
+ edit_cursor_move (edit, edit_eol (edit, edit->curs1) - edit->curs1);
+ edit->search_start = edit->curs1;
+ edit->prev_col = edit_get_col (edit);
+}
+
+/* move cursor to line 'line' */
+void edit_move_to_line (WEdit * e, long line)
+{
+ if(line < e->curs_line)
+ edit_move_up (e, e->curs_line - line, 0);
+ else
+ edit_move_down (e, line - e->curs_line, 0);
+ edit_scroll_screen_over_cursor (e);
+}
+
+/* scroll window so that first visible line is 'line' */
+void edit_move_display (WEdit * e, long line)
+{
+ if(line < e->start_line)
+ edit_scroll_upward (e, e->start_line - line);
+ else
+ edit_scroll_downward (e, line - e->start_line);
+}
+
+/* save markers onto undo stack */
+void edit_push_markers (WEdit * edit)
+{
+ edit_push_action (edit, MARK_1 + edit->mark1);
+ edit_push_action (edit, MARK_2 + edit->mark2);
+}
+
+void free_selections (void)
+{
+ int i;
+ for (i = 0; i < NUM_SELECTION_HISTORY; i++)
+ if (selection_history[i].text) {
+ free (selection_history[i].text);
+ selection_history[i].text = 0;
+ selection_history[i].len = 0;
+ }
+ current_selection = 0;
+}
+
+/* return -1 on nothing to store or error, zero otherwise */
+void edit_get_selection (WEdit * edit)
+{
+ long start_mark, end_mark;
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return;
+ if (selection_history[current_selection].len < 4096) /* large selections should not be held -- to save memory */
+ current_selection = (current_selection + 1) % NUM_SELECTION_HISTORY;
+ selection_history[current_selection].len = end_mark - start_mark;
+ if (selection_history[current_selection].text)
+ free (selection_history[current_selection].text);
+ selection_history[current_selection].text = malloc (selection_history[current_selection].len + 1);
+ if (!selection_history[current_selection].text) {
+ selection_history[current_selection].text = malloc (1);
+ *selection_history[current_selection].text = 0;
+ selection_history[current_selection].len = 0;
+ } else {
+ unsigned char *p = selection_history[current_selection].text;
+ for (; start_mark < end_mark; start_mark++)
+ *p++ = edit_get_byte (edit, start_mark);
+ *p = 0;
+ }
+ selection.text = selection_history[current_selection].text;
+ selection.len = selection_history[current_selection].len;
+}
+
+void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2)
+{
+ edit->mark1 = m1;
+ edit->mark2 = m2;
+ edit->column1 = c1;
+ edit->column2 = c2;
+}
+
+
+/* highlight marker toggle */
+void edit_mark_cmd (WEdit * edit, int unmark)
+{
+ edit_push_markers (edit);
+ if (unmark) {
+ edit_set_markers (edit, 0, 0, 0, 0);
+ edit->force |= REDRAW_PAGE;
+ } else {
+ if (edit->mark2 >= 0) {
+ edit_set_markers (edit, edit->curs1, -1, edit->curs_col, edit->curs_col);
+ edit->force |= REDRAW_PAGE;
+ } else
+ edit_set_markers (edit, edit->mark1, edit->curs1, edit->column1, edit->curs_col);
+ }
+}
+
+int my_type_of (int c)
+{
+ if (c < ' ' && c > 0)
+ return 1;
+ if (strchr ("+_-.", c))
+ if (strchr (option_whole_chars_move, c))
+ return 3;
+ if (!strcasechr (option_whole_chars_move, c))
+ return 2;
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c >= 160)
+ return 3;
+ return c;
+}
+
+void edit_left_word_move (WEdit * edit)
+{
+ do {
+ edit_cursor_move (edit, -1);
+ if (!edit->curs1)
+ break;
+ } while (my_type_of (edit_get_byte (edit, edit->curs1))
+ ==
+ my_type_of (edit_get_byte (edit, edit->curs1 - 1)));
+}
+
+static void edit_left_word_move_cmd (WEdit * edit)
+{
+ edit_left_word_move (edit);
+ if (strchr (option_whole_chars_move, ' '))
+ if (strchr ("\t ", edit_get_byte (edit, edit->curs1)))
+ edit_left_word_move (edit);
+ edit->force |= REDRAW_PAGE;
+}
+
+void edit_right_word_move (WEdit * edit)
+{
+ do {
+ edit_cursor_move (edit, 1);
+ if (edit->curs1 >= edit->last_byte)
+ break;
+ } while (my_type_of (edit_get_byte (edit, edit->curs1 - 1))
+ ==
+ my_type_of (edit_get_byte (edit, edit->curs1)));
+}
+
+static void edit_right_word_move_cmd (WEdit * edit)
+{
+ edit_right_word_move (edit);
+ if (strchr (option_whole_chars_move, ' '))
+ if (strchr ("\t ", edit_get_byte (edit, edit->curs1)))
+ edit_right_word_move (edit);
+ edit->force |= REDRAW_PAGE;
+}
+
+
+static void edit_right_delete_word (WEdit * edit)
+{
+ int c;
+ do {
+ c = edit_delete (edit);
+ } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1)));
+}
+
+static void edit_left_delete_word (WEdit * edit)
+{
+ int c;
+ do {
+ c = edit_backspace (edit);
+ } while (my_type_of (c) == my_type_of (edit_get_byte (edit, edit->curs1 - 1)));
+}
+
+
+/*
+ the start column position is not recorded, and hence does not
+ undo as it happed. But who would notice.
+ */
+void edit_do_undo (WEdit * edit)
+{
+ long ac;
+ long count = 0;
+
+ push_action_disabled = 1; /* don't record undo's onto undo stack! */
+
+ while ((ac = pop_action (edit)) < KEY_PRESS) {
+ switch ((int) ac) {
+ case STACK_BOTTOM:
+ goto done_undo;
+ case CURS_RIGHT:
+ edit_cursor_move (edit, 1);
+ break;
+ case CURS_LEFT:
+ edit_cursor_move (edit, -1);
+ break;
+ case BACKSPACE:
+ edit_backspace (edit);
+ break;
+ case DELETE:
+ edit_delete (edit);
+ break;
+ }
+ if (ac >= 256 && ac < 512)
+ edit_insert_ahead (edit, ac - 256);
+ if (ac >= 0 && ac < 256)
+ edit_insert (edit, ac);
+
+ if (ac >= MARK_1 - 2 && ac < MARK_2 - 2) {
+ edit->mark1 = ac - MARK_1;
+ } else if (ac >= MARK_2 - 2 && ac < KEY_PRESS) {
+ edit->mark2 = ac - MARK_2;
+ }
+ if (count++)
+ edit->force |= REDRAW_PAGE; /* more than one pop usually means something big */
+ }
+
+ if (edit->start_display > ac - KEY_PRESS) {
+ edit->start_line -= edit_count_lines (edit, ac - KEY_PRESS, edit->start_display);
+ edit->force |= REDRAW_PAGE;
+ } else if (edit->start_display < ac - KEY_PRESS) {
+ edit->start_line += edit_count_lines (edit, edit->start_display, ac - KEY_PRESS);
+ edit->force |= REDRAW_PAGE;
+ }
+ edit->start_display = ac - KEY_PRESS; /* see push and pop above */
+ edit_update_curs_row(edit);
+
+ done_undo:;
+ push_action_disabled = 0;
+}
+
+static void edit_delete_to_line_end (WEdit * edit)
+{
+ for (;;) {
+ if (edit_get_byte (edit, edit->curs1) == '\n')
+ break;
+ if (!edit->curs2)
+ break;
+ edit_delete (edit);
+ }
+}
+
+static void edit_delete_to_line_begin (WEdit * edit)
+{
+ for (;;) {
+ if (edit_get_byte (edit, edit->curs1 - 1) == '\n')
+ break;
+ if (!edit->curs1)
+ break;
+ edit_backspace (edit);
+ }
+}
+
+static void edit_delete_line (WEdit * edit)
+{
+ int c;
+ do {
+ c = edit_delete (edit);
+ } while (c != '\n' && c);
+ do {
+ c = edit_backspace (edit);
+ } while (c != '\n' && c);
+ if (c)
+ edit_insert (edit, '\n');
+}
+
+static void insert_spaces_tab (WEdit * edit)
+{
+ int i = option_tab_spacing;
+ while (i--)
+ edit_insert (edit, ' ');
+}
+
+static int is_aligned_on_a_tab (WEdit * edit)
+{
+ edit_update_curs_col (edit);
+ if ((edit->curs_col % (TAB_SIZE * space_width)) && edit->curs_col % (TAB_SIZE * space_width) != (HALF_TAB_SIZE * space_width))
+ return 0; /* not alligned on a tab */
+ return 1;
+}
+
+static int right_of_four_spaces (WEdit *edit)
+{
+ int i, ch = 0;
+ for (i = 1; i <= HALF_TAB_SIZE; i++)
+ ch |= edit_get_byte (edit, edit->curs1 - i);
+ if (ch == ' ')
+ return is_aligned_on_a_tab (edit);
+ return 0;
+}
+
+static int left_of_four_spaces (WEdit *edit)
+{
+ int i, ch = 0;
+ for (i = 0; i < HALF_TAB_SIZE; i++)
+ ch |= edit_get_byte (edit, edit->curs1 + i);
+ if (ch == ' ')
+ return is_aligned_on_a_tab (edit);
+ return 0;
+}
+
+int edit_indent_width (WEdit * edit, long p)
+{
+ long q = p;
+ while (strchr ("\t ", edit_get_byte (edit, q)) && q < edit->last_byte - 1) /* move to the end of the leading whitespace of the line */
+ q++;
+ return edit_move_forward3 (edit, p, 0, q); /* count the number of columns of indentation */
+}
+
+void edit_insert_indent (WEdit * edit, int indent)
+{
+#ifndef MIDNIGHT
+ indent /= space_width;
+#endif
+ if (!option_fill_tabs_with_spaces) {
+ while (indent >= TAB_SIZE) {
+ edit_insert (edit, '\t');
+ indent -= TAB_SIZE;
+ }
+ }
+ while (indent--)
+ edit_insert (edit, ' ');
+}
+
+static void edit_auto_indent (WEdit * edit, int always)
+{
+ long p;
+ int indent;
+ p = edit->curs1;
+ while (strchr ("\t\n\r ", edit_get_byte (edit, p - 1)) && p > 0) /* move back/up to a line with text */
+ p--;
+ indent = edit_indent_width (edit, edit_bol (edit, p));
+ if (edit->curs_col < indent)
+ indent = edit->curs_col;
+ edit_insert_indent (edit, indent);
+}
+
+static void edit_double_newline (WEdit * edit)
+{
+ edit_insert (edit, '\n');
+ if (edit_get_byte (edit, edit->curs1) == '\n')
+ return;
+ if (edit_get_byte (edit, edit->curs1 - 2) == '\n')
+ return;
+ edit->force |= REDRAW_PAGE;
+ edit_insert (edit, '\n');
+}
+
+static void edit_tab_cmd (WEdit * edit)
+{
+ int i;
+
+ if (option_fake_half_tabs) {
+ if (is_in_indent (edit)) {
+ /*insert a half tab (usually four spaces) unless there is a
+ half tab already behind, then delete it and insert a
+ full tab. */
+ if (right_of_four_spaces (edit)) {
+ for (i = 1; i <= HALF_TAB_SIZE; i++)
+ edit_backspace (edit);
+ if (option_fill_tabs_with_spaces) {
+ insert_spaces_tab (edit);
+ } else {
+ edit_insert (edit, '\t');
+ }
+ } else {
+ for (i = 1; i <= HALF_TAB_SIZE; i++)
+ edit_insert (edit, ' ');
+ }
+ return;
+ }
+ }
+ if (option_fill_tabs_with_spaces) {
+ insert_spaces_tab (edit);
+ } else {
+ edit_insert (edit, '\t');
+ }
+ return;
+}
+
+void format_paragraph (WEdit * edit, int force);
+
+static void check_and_wrap_line (WEdit * edit)
+{
+ int curs, c;
+ if (!option_typewriter_wrap)
+ return;
+ edit_update_curs_col (edit);
+#ifdef MIDNIGHT
+ if (edit->curs_col < option_word_wrap_line_length)
+#else
+ if (edit->curs_col < option_word_wrap_line_length * FONT_MEAN_WIDTH)
+#endif
+ return;
+ curs = edit->curs1;
+ for (;;) {
+ curs--;
+ c = edit_get_byte (edit, curs);
+ if (c == '\n' || curs <= 0) {
+ edit_insert (edit, '\n');
+ return;
+ }
+ if (c == ' ' || c == '\t') {
+ int current = edit->curs1;
+ edit_cursor_move (edit, curs - edit->curs1 + 1);
+ edit_insert (edit, '\n');
+ edit_cursor_move (edit, current - edit->curs1 + 1);
+ return;
+ }
+ }
+}
+
+void edit_execute_macro (WEdit * edit, struct macro macro[], int n);
+
+/* either command or char_for_insertion must be passed as -1 */
+int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
+
+#ifdef MIDNIGHT
+int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch)
+{
+ int command = -1;
+ int char_for_insertion = -1;
+
+#include "edit_key_translator.c"
+
+ *cmd = command;
+ *ch = char_for_insertion;
+
+ if((command == -1 || command == 0) && char_for_insertion == -1) /* unchanged, key has no function here */
+ return 0;
+ return 1;
+}
+#endif
+
+void edit_push_key_press (WEdit * edit)
+{
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+ if (edit->mark2 == -1)
+ edit_push_action (edit, MARK_1 + edit->mark1);
+}
+
+/* this find the matching bracket in either direction, and sets edit->bracket */
+void edit_find_bracket (WEdit * edit)
+{
+ if (option_find_bracket) {
+ const char *b = "{}{[][()(", *p;
+ static int last_bracket = -1;
+ int i = 1, a, inc = -1, c, d, n = 0, j = 0;
+ long q;
+
+ edit->bracket = -1;
+ c = edit_get_byte (edit, edit->curs1);
+ p = strchr (b, c);
+ edit_update_curs_row (edit);
+ if (p) {
+ d = p[1];
+ if (strchr ("{[(", c))
+ inc = 1;
+ for (q = edit->curs1 + inc;; q += inc) {
+ if (q >= edit->last_byte || q < edit->start_display || j++ > 10000)
+ break;
+ a = edit_get_byte (edit, q);
+ if (inc > 0 && a == '\n')
+ n++;
+ if (n >= edit->num_widget_lines - edit->curs_row) /* out of screen */
+ break;
+ i += (a == c) - (a == d);
+ if (!i) {
+ edit->bracket = q;
+ break;
+ }
+ }
+ }
+ if (last_bracket != edit->bracket)
+ edit->force |= REDRAW_PAGE;
+ last_bracket = edit->bracket;
+ }
+}
+
+
+/* this executes a command as though the user initiated it through a key press. */
+/* callback with WIDGET_KEY as a message calls this after translating the key
+ press */
+/* this can be used to pass any command to the editor. Same as sendevent with
+ msg = WIDGET_COMMAND and par = command except the screen wouldn't update */
+/* one of command or char_for_insertion must be passed as -1 */
+/* commands are executed, and char_for_insertion is inserted at the cursor */
+/* returns 0 if the command is a macro that was not found, 1 otherwise */
+int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion)
+{
+ int r;
+ if (command == CK_Begin_Record_Macro) {
+ edit->macro_i = 0;
+ edit->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
+ return command;
+ }
+ if (command == CK_End_Record_Macro && edit->macro_i != -1) {
+ edit->force |= REDRAW_COMPLETELY;
+ edit_save_macro_cmd (edit, edit->macro, edit->macro_i);
+ edit->macro_i = -1;
+ return command;
+ }
+ if (edit->macro_i >= 0 && edit->macro_i < MAX_MACRO_LENGTH - 1) {
+ edit->macro[edit->macro_i].command = command;
+ edit->macro[edit->macro_i++].ch = char_for_insertion;
+ }
+/* record the beginning of a set of editing actions initiated by a key press */
+ if (command != CK_Undo)
+ edit_push_key_press (edit);
+
+ r = edit_execute_cmd (edit, command, char_for_insertion);
+
+ return r;
+}
+
+#ifdef MIDNIGHT
+static const char *shell_cmd[] = SHELL_COMMANDS_i
+#else
+static void (*user_commamd) (WEdit *, int) = 0;
+void edit_set_user_command (void (*func) (WEdit *, int))
+{
+ user_commamd = func;
+}
+
+#endif
+
+void edit_mail_dialog (WEdit * edit);
+
+/*
+ This executes a command at a lower level than macro recording.
+ It also does not push a key_press onto the undo stack. This means
+ that if it is called many times, a single undo command will undo
+ all of them. It also does not check for the Undo command.
+ Returns 0 if the command is a macro that was not found, 1
+ otherwise.
+ */
+int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion)
+{
+ int result = 1;
+ edit->force |= REDRAW_LINE;
+ if (edit->found_len)
+/* the next key press will unhighlight the found string, so update whole page */
+ edit->force |= REDRAW_PAGE;
+
+ if (command / 100 == 6) { /* a highlight command like shift-arrow */
+ if (!edit->highlight || (edit->mark2 != -1 && edit->mark1 != edit->mark2)) {
+ edit_mark_cmd (edit, 1); /* clear */
+ edit_mark_cmd (edit, 0); /* marking on */
+ }
+ edit->highlight = 1;
+ } else { /* any other command */
+ if (edit->highlight)
+ edit_mark_cmd (edit, 0); /* clear */
+ edit->highlight = 0;
+ }
+
+/* first check for undo */
+ if (command == CK_Undo) {
+ edit_do_undo (edit);
+ edit->found_len = 0;
+ edit->prev_col = edit_get_col (edit);
+ edit->search_start = edit->curs1;
+ return 1;
+ }
+/* An ordinary key press */
+ if (char_for_insertion >= 0) {
+ if (edit->overwrite) {
+ if (edit_get_byte (edit, edit->curs1) != '\n')
+ edit_delete (edit);
+ }
+ edit_insert (edit, char_for_insertion);
+ if (option_auto_para_formatting) {
+ format_paragraph (edit, 0);
+ edit->force |= REDRAW_PAGE;
+ } else
+ check_and_wrap_line (edit);
+ edit->found_len = 0;
+ edit->prev_col = edit_get_col (edit);
+ edit->search_start = edit->curs1;
+ edit_find_bracket (edit);
+ return 1;
+ }
+ switch (command) {
+ case CK_Begin_Page:
+ case CK_End_Page:
+ case CK_Begin_Page_Highlight:
+ case CK_End_Page_Highlight:
+ case CK_Word_Left:
+ case CK_Word_Right:
+ case CK_Up:
+ case CK_Down:
+ case CK_Word_Left_Highlight:
+ case CK_Word_Right_Highlight:
+ case CK_Up_Highlight:
+ case CK_Down_Highlight:
+ if (edit->mark2 == -1)
+ break; /*marking is following the cursor: may need to highlight a whole line */
+ case CK_Left:
+ case CK_Right:
+ case CK_Left_Highlight:
+ case CK_Right_Highlight:
+ edit->force |= REDRAW_CHAR_ONLY;
+ }
+
+/* basic cursor key commands */
+ switch (command) {
+ case CK_BackSpace:
+ if (option_backspace_through_tabs && is_in_indent (edit)) {
+ while (edit_get_byte (edit, edit->curs1 - 1) != '\n'
+ && edit->curs1 > 0)
+ edit_backspace (edit);
+ break;
+ } else {
+ if (option_fake_half_tabs) {
+ int i;
+ if (is_in_indent (edit) && right_of_four_spaces (edit)) {
+ for (i = 0; i < HALF_TAB_SIZE; i++)
+ edit_backspace (edit);
+ break;
+ }
+ }
+ }
+ edit_backspace (edit);
+ break;
+ case CK_Delete:
+ if (option_fake_half_tabs) {
+ int i;
+ if (is_in_indent (edit) && left_of_four_spaces (edit)) {
+ for (i = 1; i <= HALF_TAB_SIZE; i++)
+ edit_delete (edit);
+ break;
+ }
+ }
+ edit_delete (edit);
+ break;
+ case CK_Delete_Word_Left:
+ edit_left_delete_word (edit);
+ break;
+ case CK_Delete_Word_Right:
+ edit_right_delete_word (edit);
+ break;
+ case CK_Delete_Line:
+ edit_delete_line (edit);
+ break;
+ case CK_Delete_To_Line_End:
+ edit_delete_to_line_end (edit);
+ break;
+ case CK_Delete_To_Line_Begin:
+ edit_delete_to_line_begin (edit);
+ break;
+ case CK_Enter:
+ if (option_auto_para_formatting) {
+ edit_double_newline (edit);
+ if (option_return_does_auto_indent)
+ edit_auto_indent (edit, 0);
+ format_paragraph (edit, 0);
+ } else if (option_return_does_auto_indent) {
+ edit_insert (edit, '\n');
+ edit_auto_indent (edit, 0);
+ } else {
+ edit_insert (edit, '\n');
+ }
+ break;
+ case CK_Return:
+ edit_insert (edit, '\n');
+ break;
+
+ case CK_Page_Up:
+ case CK_Page_Up_Highlight:
+ edit_move_up (edit, edit->num_widget_lines - 1, 1);
+ break;
+ case CK_Page_Down:
+ case CK_Page_Down_Highlight:
+ edit_move_down (edit, edit->num_widget_lines - 1, 1);
+ break;
+ case CK_Left:
+ case CK_Left_Highlight:
+ if (option_fake_half_tabs) {
+ if (is_in_indent (edit) && right_of_four_spaces (edit)) {
+ edit_cursor_move (edit, -HALF_TAB_SIZE);
+ edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
+ break;
+ }
+ }
+ edit_cursor_move (edit, -1);
+ break;
+ case CK_Right:
+ case CK_Right_Highlight:
+ if (option_fake_half_tabs) {
+ if (is_in_indent (edit) && left_of_four_spaces (edit)) {
+ edit_cursor_move (edit, HALF_TAB_SIZE);
+ edit->force &= (0xFFF - REDRAW_CHAR_ONLY);
+ break;
+ }
+ }
+ edit_cursor_move (edit, 1);
+ break;
+ case CK_Begin_Page:
+ case CK_Begin_Page_Highlight:
+ edit_begin_page (edit);
+ break;
+ case CK_End_Page:
+ case CK_End_Page_Highlight:
+ edit_end_page (edit);
+ break;
+ case CK_Word_Left:
+ case CK_Word_Left_Highlight:
+ edit_left_word_move_cmd (edit);
+ break;
+ case CK_Word_Right:
+ case CK_Word_Right_Highlight:
+ edit_right_word_move_cmd (edit);
+ break;
+ case CK_Up:
+ case CK_Up_Highlight:
+ edit_move_up (edit, 1, 0);
+ break;
+ case CK_Down:
+ case CK_Down_Highlight:
+ edit_move_down (edit, 1, 0);
+ break;
+ case CK_Paragraph_Up:
+ case CK_Paragraph_Up_Highlight:
+ edit_move_up_paragraph (edit, 0);
+ break;
+ case CK_Paragraph_Down:
+ case CK_Paragraph_Down_Highlight:
+ edit_move_down_paragraph (edit, 0);
+ break;
+ case CK_Scroll_Up:
+ case CK_Scroll_Up_Highlight:
+ edit_move_up (edit, 1, 1);
+ break;
+ case CK_Scroll_Down:
+ case CK_Scroll_Down_Highlight:
+ edit_move_down (edit, 1, 1);
+ break;
+ case CK_Home:
+ case CK_Home_Highlight:
+ edit_cursor_to_bol (edit);
+ break;
+ case CK_End:
+ case CK_End_Highlight:
+ edit_cursor_to_eol (edit);
+ break;
+
+ case CK_Tab:
+ edit_tab_cmd (edit);
+ if (option_auto_para_formatting) {
+ format_paragraph (edit, 0);
+ edit->force |= REDRAW_PAGE;
+ } else
+ check_and_wrap_line (edit);
+ break;
+
+ case CK_Toggle_Insert:
+ edit->overwrite = (edit->overwrite == 0);
+#ifndef MIDNIGHT
+ CSetCursorColor (edit->overwrite ? color_palette (24) : color_palette (19));
+#endif
+ break;
+
+ case CK_Mark:
+ edit_mark_cmd (edit, 0);
+ break;
+ case CK_Unmark:
+ edit_mark_cmd (edit, 1);
+ break;
+
+ case CK_Beginning_Of_Text:
+ case CK_Beginning_Of_Text_Highlight:
+ edit_move_to_top (edit);
+ break;
+ case CK_End_Of_Text:
+ case CK_End_Of_Text_Highlight:
+ edit_move_to_bottom (edit);
+ break;
+
+ case CK_Copy:
+ edit_block_copy_cmd (edit);
+ break;
+ case CK_Remove:
+ edit_block_delete_cmd (edit);
+ break;
+ case CK_Move:
+ edit_block_move_cmd (edit);
+ break;
+
+ case CK_XStore:
+ edit_copy_to_X_buf_cmd (edit);
+ break;
+ case CK_XCut:
+ edit_cut_to_X_buf_cmd (edit);
+ break;
+ case CK_XPaste:
+ edit_paste_from_X_buf_cmd (edit);
+ break;
+ case CK_Selection_History:
+ edit_paste_from_history (edit);
+ break;
+
+ case CK_Save_As:
+#ifndef MIDNIGHT
+ if (edit->widget->options & EDITOR_NO_FILE)
+ break;
+#endif
+ edit_save_as_cmd (edit);
+ break;
+ case CK_Save:
+#ifndef MIDNIGHT
+ if (edit->widget->options & EDITOR_NO_FILE)
+ break;
+#endif
+ edit_save_confirm_cmd (edit);
+ break;
+ case CK_Load:
+#ifndef MIDNIGHT
+ if (edit->widget->options & EDITOR_NO_FILE)
+ break;
+#endif
+ edit_load_cmd (edit);
+ break;
+ case CK_Save_Block:
+ edit_save_block_cmd (edit);
+ break;
+ case CK_Insert_File:
+ edit_insert_file_cmd (edit);
+ break;
+
+ case CK_Find:
+ edit_search_cmd (edit, 0);
+ break;
+ case CK_Find_Again:
+ edit_search_cmd (edit, 1);
+ break;
+ case CK_Replace:
+ edit_replace_cmd (edit, 0);
+ break;
+ case CK_Replace_Again:
+ edit_replace_cmd (edit, 1);
+ break;
+
+ case CK_Exit:
+ edit_quit_cmd (edit);
+ break;
+ case CK_New:
+ edit_new_cmd (edit);
+ break;
+
+ case CK_Help:
+ edit_help_cmd (edit);
+ break;
+
+ case CK_Refresh:
+ edit_refresh_cmd (edit);
+ break;
+
+ case CK_Date:{
+ time_t t;
+ time (&t);
+ edit_printf (edit, ctime (&t));
+ edit->force |= REDRAW_PAGE;
+ break;
+ }
+ case CK_Goto:
+ edit_goto_cmd (edit);
+ break;
+ case CK_Paragraph_Format:
+ format_paragraph (edit, 1);
+ edit->force |= REDRAW_PAGE;
+ break;
+ case CK_Delete_Macro:
+ edit_delete_macro_cmd (edit);
+ break;
+#ifdef MIDNIGHT
+ case CK_Sort:
+ edit_sort_cmd (edit);
+ break;
+ case CK_Mail:
+ edit_mail_dialog (edit);
+ break;
+#endif
+
+/* These commands are not handled and must be handled by the user application */
+#ifndef MIDNIGHT
+ case CK_Sort:
+ case CK_Mail:
+#endif
+ case CK_Complete:
+ case CK_Cancel:
+ case CK_Save_Desktop:
+ case CK_New_Window:
+ case CK_Cycle:
+ case CK_Menu:
+ case CK_Save_And_Quit:
+ case CK_Check_Save_And_Quit:
+ case CK_Run_Another:
+ result = 0;
+ break;
+ }
+
+#ifdef MIDNIGHT
+/* CK_Pipe_Block */
+ if ((command / 1000) == 1) /* a shell command */
+ edit_block_process_cmd (edit, shell_cmd[command - 1000], 1);
+#else
+ if ((command / 1000) == 1) /* a user defined command */
+ if (user_commamd)
+ (*user_commamd) (edit, command - 1000);
+#endif
+
+ if (command > CK_Macro (0) && command <= CK_Last_Macro) { /* a macro command */
+ struct macro m[MAX_MACRO_LENGTH];
+ int nm;
+ if ((result = edit_load_macro_cmd (edit, m, &nm, command - 2000)))
+ edit_execute_macro (edit, m, nm);
+ }
+/* keys which must set the col position, and the search vars */
+ switch (command) {
+ case CK_Find:
+ case CK_Find_Again:
+ case CK_Replace:
+ case CK_Replace_Again:
+ edit->prev_col = edit_get_col (edit);
+ return 1;
+ break;
+ case CK_Up:
+ case CK_Up_Highlight:
+ case CK_Down:
+ case CK_Down_Highlight:
+ case CK_Page_Up:
+ case CK_Page_Up_Highlight:
+ case CK_Page_Down:
+ case CK_Page_Down_Highlight:
+ case CK_Beginning_Of_Text:
+ case CK_Beginning_Of_Text_Highlight:
+ case CK_End_Of_Text:
+ case CK_End_Of_Text_Highlight:
+ case CK_Paragraph_Up:
+ case CK_Paragraph_Up_Highlight:
+ case CK_Paragraph_Down:
+ case CK_Paragraph_Down_Highlight:
+ case CK_Scroll_Up:
+ case CK_Scroll_Up_Highlight:
+ case CK_Scroll_Down:
+ case CK_Scroll_Down_Highlight:
+ edit->search_start = edit->curs1;
+ edit->found_len = 0;
+ edit_find_bracket (edit);
+ return 1;
+ break;
+ default:
+ edit->found_len = 0;
+ edit->prev_col = edit_get_col (edit);
+ edit->search_start = edit->curs1;
+ }
+ edit_find_bracket (edit);
+
+ if (option_auto_para_formatting) {
+ switch (command) {
+ case CK_BackSpace:
+ case CK_Delete:
+ case CK_Delete_Word_Left:
+ case CK_Delete_Word_Right:
+ case CK_Delete_To_Line_End:
+ case CK_Delete_To_Line_Begin:
+ format_paragraph (edit, 0);
+ edit->force |= REDRAW_PAGE;
+ }
+ }
+ return result;
+}
+
+
+/* either command or char_for_insertion must be passed as -1 */
+/* returns 0 if command is a macro that was not found, 1 otherwise */
+int edit_execute_command (WEdit * edit, int command, int char_for_insertion)
+{
+ int r;
+ r = edit_execute_cmd (edit, command, char_for_insertion);
+ edit_update_screen (edit);
+ return r;
+}
+
+void edit_execute_macro (WEdit * edit, struct macro macro[], int n)
+{
+ int i = 0;
+ edit->force |= REDRAW_PAGE;
+ for (; i < n; i++) {
+ edit_execute_cmd (edit, macro[i].command, macro[i].ch);
+ }
+ edit_update_screen (edit);
+}
+
--- /dev/null
+#ifndef __EDIT_H
+#define __EDIT_H
+
+#ifdef MIDNIGHT
+
+#ifdef HAVE_SLANG
+#define HAVE_SYNTAXH 1
+#endif
+
+# include <stdio.h>
+# include <stdarg.h>
+# include <sys/types.h>
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+# include <string.h>
+# include "../src/tty.h"
+# include <sys/stat.h>
+# include <errno.h>
+
+# ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+# endif
+
+# include <stdlib.h>
+# include <malloc.h>
+
+#else /* ! MIDNIGHT */
+
+# include "global.h"
+# include <stdio.h>
+# include <stdarg.h>
+# include <sys/types.h>
+
+# ifdef HAVE_UNISTD_H
+# include <unistd.h>
+# endif
+
+# include <my_string.h>
+# include <sys/stat.h>
+
+# ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+# endif
+
+# include <stdlib.h>
+# include <stdarg.h>
+
+# if TIME_WITH_SYS_TIME
+# include <sys/time.h>
+# include <time.h>
+# else
+# if HAVE_SYS_TIME_H
+# include <sys/time.h>
+# else
+# include <time.h>
+# endif
+# endif
+
+# include "regex.h"
+
+#endif
+
+#ifndef MIDNIGHT
+
+# include <signal.h>
+# include <X11/Xlib.h>
+# include <X11/Xutil.h>
+# include <X11/Xresource.h>
+# include "lkeysym.h"
+# include "coolwidget.h"
+# include "app_glob.c"
+# include "coollocal.h"
+# include "stringtools.h"
+
+#else
+
+# include "../src/main.h" /* for char *shell */
+# include "../src/mad.h"
+# include "../src/dlg.h"
+# include "../src/widget.h"
+# include "../src/color.h"
+# include "../src/dialog.h"
+# include "../src/mouse.h"
+# include "../src/global.h"
+# include "../src/help.h"
+# include "../src/key.h"
+# include "../src/wtools.h" /* for QuickWidgets */
+# include "../src/win.h"
+# include "../vfs/vfs.h"
+# include "../src/menu.h"
+# include "../src/regex.h"
+# define WANT_WIDGETS
+
+# define WIDGET_COMMAND (WIDGET_USER + 10)
+# define N_menus 5
+
+#endif
+
+#define SEARCH_DIALOG_OPTION_NO_SCANF 1
+#define SEARCH_DIALOG_OPTION_NO_REGEX 2
+#define SEARCH_DIALOG_OPTION_NO_CASE 4
+#define SEARCH_DIALOG_OPTION_BACKWARDS 8
+
+#define SYNTAX_FILE "/.cedit/syntax"
+#define CLIP_FILE "/.cedit/cooledit.clip"
+#define MACRO_FILE "/.cedit/cooledit.macros"
+#define BLOCK_FILE "/.cedit/cooledit.block"
+#define ERROR_FILE "/.cedit/cooledit.error"
+#define TEMP_FILE "/.cedit/cooledit.temp"
+#define SCRIPT_FILE "/.cedit/cooledit.script"
+#define EDIT_DIR "/.cedit"
+
+#define EDIT_KEY_EMULATION_NORMAL 0
+#define EDIT_KEY_EMULATION_EMACS 1
+
+#define REDRAW_LINE (1 << 0)
+#define REDRAW_LINE_ABOVE (1 << 1)
+#define REDRAW_LINE_BELOW (1 << 2)
+#define REDRAW_AFTER_CURSOR (1 << 3)
+#define REDRAW_BEFORE_CURSOR (1 << 4)
+#define REDRAW_PAGE (1 << 5)
+#define REDRAW_IN_BOUNDS (1 << 6)
+#define REDRAW_CHAR_ONLY (1 << 7)
+#define REDRAW_COMPLETELY (1 << 8)
+
+#define MOD_ABNORMAL (1 << 0)
+#define MOD_UNDERLINED (1 << 1)
+#define MOD_BOLD (1 << 2)
+#define MOD_HIGHLIGHTED (1 << 3)
+#define MOD_MARKED (1 << 4)
+#define MOD_ITALIC (1 << 5)
+#define MOD_CURSOR (1 << 6)
+#define MOD_INVERSE (1 << 7)
+
+#ifndef MIDNIGHT
+# define EDIT_TEXT_HORIZONTAL_OFFSET 4
+# define EDIT_TEXT_VERTICAL_OFFSET 3
+#else
+# define EDIT_TEXT_HORIZONTAL_OFFSET 0
+# define EDIT_TEXT_VERTICAL_OFFSET 1
+# define FONT_OFFSET_X 0
+# define FONT_OFFSET_Y 0
+#endif
+
+#define EDIT_RIGHT_EXTREME option_edit_right_extreme
+#define EDIT_LEFT_EXTREME option_edit_left_extreme
+#define EDIT_TOP_EXTREME option_edit_top_extreme
+#define EDIT_BOTTOM_EXTREME option_edit_bottom_extreme
+
+#define MAX_MACRO_LENGTH 1024
+
+/*there are a maximum of ... */
+#define MAXBUFF 1024
+/*... edit buffers, each of which is ... */
+#define EDIT_BUF_SIZE 16384
+/* ...bytes in size. */
+
+/*x / EDIT_BUF_SIZE equals x >> ... */
+#define S_EDIT_BUF_SIZE 14
+
+/* x % EDIT_BUF_SIZE is equal to x && ... */
+#define M_EDIT_BUF_SIZE 16383
+
+#define SIZE_LIMIT (EDIT_BUF_SIZE * (MAXBUFF - 2))
+/* Note a 16k stack is 64k of data and enough to hold (usually) around 10
+ pages of undo info. */
+
+/* undo stack */
+#define START_STACK_SIZE 32
+
+
+/*some codes that may be pushed onto or returned from the undo stack: */
+#define CURS_LEFT 601
+#define CURS_RIGHT 602
+#define DELETE 603
+#define BACKSPACE 604
+#define STACK_BOTTOM 605
+#define CURS_LEFT_LOTS 606
+#define CURS_RIGHT_LOTS 607
+#define MARK_1 1000
+#define MARK_2 700000000
+#define KEY_PRESS 1400000000
+
+/*Tabs spaces: (sofar only HALF_TAB_SIZE is used: */
+#define TAB_SIZE option_tab_spacing
+#define HALF_TAB_SIZE ((int) option_tab_spacing / 2)
+
+struct macro {
+ short command;
+ short ch;
+};
+
+struct selection {
+ unsigned char * text;
+ int len;
+};
+
+
+#define RULE_CONTEXT 0x00FFF000UL
+#define RULE_CONTEXT_SHIFT 12
+#define RULE_WORD 0x00000FFFUL
+#define RULE_WORD_SHIFT 0
+#define RULE_ON_LEFT_BORDER 0x02000000UL
+#define RULE_ON_RIGHT_BORDER 0x01000000UL
+
+struct key_word {
+ char *keyword;
+ char first;
+ char last;
+ char *whole_word_chars_left;
+ char *whole_word_chars_right;
+#define NO_COLOR ((unsigned long) -1);
+ int line_start;
+ int bg;
+ int fg;
+};
+
+struct context_rule {
+ int rule_number;
+ char *left;
+ char first_left;
+ char last_left;
+ char line_start_left;
+ char *right;
+ char first_right;
+ char last_right;
+ char line_start_right;
+ int single_char;
+ int between_delimiters;
+ char *whole_word_chars_left;
+ char *whole_word_chars_right;
+ unsigned char *conflicts;
+ char *keyword_first_chars;
+ char *keyword_last_chars;
+/* first word is word[1] */
+ struct key_word **keyword;
+};
+
+
+
+struct editor_widget {
+#ifdef MIDNIGHT
+ Widget widget;
+#else
+ struct cool_widget *widget;
+#endif
+#define from_here num_widget_lines
+ int num_widget_lines;
+ int num_widget_columns;
+
+#ifdef MIDNIGHT
+ int have_frame;
+#else
+ int stopped;
+#endif
+
+ char *filename; /* Name of the file */
+ char *dir; /* current directory */
+
+/* dynamic buffers and curser position for editor: */
+ long curs1; /*position of the cursor from the beginning of the file. */
+ long curs2; /*position from the end of the file */
+ unsigned char *buffers1[MAXBUFF + 1]; /*all data up to curs1 */
+ unsigned char *buffers2[MAXBUFF + 1]; /*all data from end of file down to curs2 */
+
+/* search variables */
+ long search_start; /* First character to start searching from */
+ int found_len; /* Length of found string or 0 if none was found */
+ long found_start; /* the found word from a search - start position */
+
+/* display information */
+ long last_byte; /* Last byte of file */
+ long start_display; /* First char displayed */
+ long start_col; /* First displayed column, negative */
+ long max_column; /* The maximum cursor position ever reached used to calc hori scroll bar */
+ long curs_row; /*row position of curser on the screen */
+ long curs_col; /*column position on screen */
+ int force; /* how much of the screen do we redraw? */
+ unsigned char overwrite;
+ unsigned char modified; /*has the file been changed?: 1 if char inserted or
+ deleted at all since last load or save */
+#ifdef MIDNIGHT
+ int delete_file; /* has the file been created in edit_load_file? Delete
+ it at end of editing when it hasn't been modified
+ or saved */
+#endif
+ unsigned char highlight;
+ long prev_col; /*recent column position of the curser - used when moving
+ up or down past lines that are shorter than the current line */
+ long curs_line; /*line number of the cursor. */
+ long start_line; /*line nummber of the top of the page */
+
+/* file info */
+ long total_lines; /*total lines in the file */
+ long mark1; /*position of highlight start */
+ long mark2; /*position of highlight end */
+ int column1; /*position of column highlight start */
+ int column2; /*position of column highlight end */
+ long bracket; /*position of a matching bracket */
+
+/* undo stack and pointers */
+ unsigned long stack_pointer;
+ long *undo_stack;
+ unsigned long stack_size;
+ unsigned long stack_size_mask;
+ unsigned long stack_bottom;
+ struct stat stat;
+
+/* syntax higlighting */
+ struct context_rule **rules;
+ long last_get_rule;
+ unsigned long rule;
+ char *syntax_type; /* description of syntax highlighting type being used */
+ int explicit_syntax; /* have we forced the syntax hi. type in spite of the filename? */
+
+ int to_here; /* dummy marker */
+
+
+/* macro stuff */
+ int macro_i; /* -1 if not recording index to macro[] otherwise */
+ struct macro macro[MAX_MACRO_LENGTH];
+};
+
+typedef struct editor_widget WEdit;
+
+#ifndef MIDNIGHT
+
+void edit_render_expose (WEdit * edit, XExposeEvent * xexpose);
+void edit_render_tidbits (struct cool_widget *w);
+int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent);
+void edit_draw_menus (Window parent, int x, int y);
+void edit_run_make (void);
+void edit_change_directory (void);
+int edit_man_page_cmd (WEdit * edit);
+void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option);
+void edit_search_dialog (WEdit * edit, char **search_text);
+long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data);
+void edit_set_foreground_colors (unsigned long normal, unsigned long bold, unsigned long italic);
+void edit_set_background_colors (unsigned long normal, unsigned long abnormal, unsigned long marked, unsigned long marked_abnormal, unsigned long highlighted);
+void edit_set_cursor_color (unsigned long c);
+void draw_options_dialog (Window parent, int x, int y);
+void CRefreshEditor (WEdit * edit);
+void edit_set_user_command (void (*func) (WEdit *, int));
+void edit_draw_this_line_proportional (WEdit * edit, long b, int curs_row, int start_column, int end_column);
+unsigned char get_international_character (unsigned char key_press);
+void edit_set_user_key_function (int (*user_def_key_func) (unsigned int, unsigned int, KeySym keysym));
+
+#else
+
+int edit_drop_hotkey_menu (WEdit * e, int key);
+void edit_menu_cmd (WEdit * e);
+void edit_init_menu_emacs (void);
+void edit_init_menu_normal (void);
+void edit_done_menu (void);
+int edit_raw_key_query (char *heading, char *query, int cancel);
+char *strcasechr (const unsigned char *s, int c);
+int edit (const char *_file, int line);
+int edit_translate_key (WEdit * edit, unsigned int x_keycode, long x_key, int x_state, int *cmd, int *ch);
+
+#endif
+
+int edit_get_byte (WEdit * edit, long byte_index);
+char *edit_get_buffer_as_text (WEdit * edit);
+int edit_load_file (WEdit * edit, const char *filename, const char *text, unsigned long text_size);
+int edit_count_lines (WEdit * edit, long current, int upto);
+long edit_move_forward (WEdit * edit, long current, int lines, long upto);
+long edit_move_forward3 (WEdit * edit, long current, int cols, long upto);
+long edit_move_backward (WEdit * edit, long current, int lines);
+void edit_scroll_screen_over_cursor (WEdit * edit);
+void edit_render_keypress (WEdit * edit);
+void edit_scroll_upward (WEdit * edit, unsigned long i);
+void edit_scroll_downward (WEdit * edit, int i);
+void edit_scroll_right (WEdit * edit, int i);
+void edit_scroll_left (WEdit * edit, int i);
+int edit_get_col (WEdit * edit);
+long edit_bol (WEdit * edit, long current);
+long edit_eol (WEdit * edit, long current);
+void edit_update_curs_row (WEdit * edit);
+void edit_update_curs_col (WEdit * edit);
+
+void edit_block_copy_cmd (WEdit * edit);
+void edit_block_move_cmd (WEdit * edit);
+int edit_block_delete_cmd (WEdit * edit);
+
+int edit_delete (WEdit * edit);
+void edit_insert (WEdit * edit, int c);
+int edit_cursor_move (WEdit * edit, long increment);
+void edit_push_action (WEdit * edit, long c,...);
+void edit_push_key_press (WEdit * edit);
+void edit_insert_ahead (WEdit * edit, int c);
+int edit_save_file (WEdit * edit, const char *filename);
+int edit_save_cmd (WEdit * edit);
+int edit_save_confirm_cmd (WEdit * edit);
+int edit_save_as_cmd (WEdit * edit);
+WEdit *edit_init (WEdit * edit, int lines, int columns, const char *filename, const char *text, const char *dir, unsigned long text_size);
+int edit_clean (WEdit * edit);
+int edit_renew (WEdit * edit);
+int edit_new_cmd (WEdit * edit);
+int edit_reload (WEdit * edit, const char *filename, const char *text, const char *dir, unsigned long text_size);
+int edit_load_cmd (WEdit * edit);
+void edit_mark_cmd (WEdit * edit, int unmark);
+void edit_set_markers (WEdit * edit, long m1, long m2, int c1, int c2);
+void edit_push_markers (WEdit * edit);
+void edit_quit_cmd (WEdit * edit);
+void edit_replace_cmd (WEdit * edit, int again);
+void edit_search_cmd (WEdit * edit, int again);
+int edit_save_block_cmd (WEdit * edit);
+int edit_insert_file_cmd (WEdit * edit);
+int edit_insert_file (WEdit * edit, const char *filename);
+void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block);
+char *catstrs (const char *first,...);
+void edit_refresh_cmd (WEdit * edit);
+void edit_date_cmd (WEdit * edit);
+void edit_goto_cmd (WEdit * edit);
+int eval_marks (WEdit * edit, long *start_mark, long *end_mark);
+void edit_status (WEdit * edit);
+int edit_execute_command (WEdit * edit, int command, int char_for_insertion);
+int edit_execute_key_command (WEdit * edit, int command, int char_for_insertion);
+void edit_update_screen (WEdit * edit);
+int edit_printf (WEdit * e, const char *fmt,...);
+int edit_print_string (WEdit * e, const char *s);
+void edit_move_to_line (WEdit * e, long line);
+void edit_move_display (WEdit * e, long line);
+void edit_word_wrap (WEdit * edit);
+unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l);
+int edit_sort_cmd (WEdit * edit);
+void edit_help_cmd (WEdit * edit);
+void edit_left_word_move (WEdit * edit);
+void edit_right_word_move (WEdit * edit);
+void edit_get_selection (WEdit * edit);
+
+int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n);
+int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k);
+void edit_delete_macro_cmd (WEdit * edit);
+
+int edit_copy_to_X_buf_cmd (WEdit * edit);
+int edit_cut_to_X_buf_cmd (WEdit * edit);
+void edit_paste_from_X_buf_cmd (WEdit * edit);
+
+void edit_paste_from_history (WEdit *edit);
+
+void edit_split_filename (WEdit * edit, char *name);
+
+#ifdef MIDNIGHT
+#define CWidget Widget
+#endif
+void edit_set_syntax_change_callback (void (*callback) (CWidget *));
+void edit_load_syntax (WEdit * edit, char **names, char *type);
+void edit_free_syntax_rules (WEdit * edit);
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
+
+
+#ifdef MIDNIGHT
+
+/* put OS2/NT/WIN95 defines here */
+
+# ifdef OS2_NT
+# define MY_O_TEXT O_TEXT
+# else
+# define MY_O_TEXT 0
+# endif
+
+# define FONT_PIX_PER_LINE 1
+# define FONT_MEAN_WIDTH 1
+
+# define get_sys_error(s) (s)
+# define open mc_open
+# define close(f) mc_close(f)
+# define read(f,b,c) mc_read(f,b,c)
+# define write(f,b,c) mc_write(f,b,c)
+# define stat(f,s) mc_stat(f,s)
+# define mkdir(s,m) mc_mkdir(s,m)
+# define itoa MY_itoa
+
+# define edit_get_load_file(d,f,h) input_dialog (h, _(" Enter file name: "), f)
+# define edit_get_save_file(d,f,h) input_dialog (h, _(" Enter file name: "), f)
+# define CMalloc(x) malloc(x)
+
+# define set_error_msg(s) edit_init_error_msg = strdup(s)
+
+# ifdef _EDIT_C
+
+# define edit_error_dialog(h,s) set_error_msg(s)
+char *edit_init_error_msg = NULL;
+
+# else /* ! _EDIT_C */
+
+# define edit_error_dialog(h,s) query_dialog (h, s, 0, 1, _("&Dismiss"))
+# define edit_message_dialog(h,s) query_dialog (h, s, 0, 1, _("&Ok"))
+extern char *edit_init_error_msg;
+
+# endif /* ! _EDIT_C */
+
+
+# define get_error_msg(s) edit_init_error_msg
+# define edit_query_dialog2(h,t,a,b) query_dialog(h,t,0,2,a,b)
+# define edit_query_dialog3(h,t,a,b,c) query_dialog(h,t,0,3,a,b,c)
+# define edit_query_dialog4(h,t,a,b,c,d) query_dialog(h,t,0,4,a,b,c,d)
+
+#else /* ! MIDNIGHT */
+
+# define MY_O_TEXT 0
+# define WIN_MESSAGES edit->widget->mainid, 20, 20
+
+# define edit_get_load_file(d,f,h) CGetLoadFile(WIN_MESSAGES,d,f,h)
+# define edit_get_save_file(d,f,h) CGetSaveFile(WIN_MESSAGES,d,f,h)
+# define edit_error_dialog(h,t) CErrorDialog(WIN_MESSAGES,h,"%s",t)
+# define edit_message_dialog(h,t) CMessageDialog(WIN_MESSAGES,0,h,"%s",t)
+# define edit_query_dialog2(h,t,a,b) CQueryDialog(WIN_MESSAGES,h,t,a,b,0)
+# define edit_query_dialog3(h,t,a,b,c) CQueryDialog(WIN_MESSAGES,h,t,a,b,c,0)
+# define edit_query_dialog4(h,t,a,b,c,d) CQueryDialog(WIN_MESSAGES,h,t,a,b,c,d,0)
+
+#endif /* ! MIDNIGHT */
+
+extern char *home_dir;
+
+#define NUM_SELECTION_HISTORY 32
+
+#ifdef _EDIT_C
+
+struct selection selection =
+{0, 0};
+int current_selection = 0;
+/* Note: selection.text = selection_history[current_selection].text */
+struct selection selection_history[NUM_SELECTION_HISTORY] =
+{
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+ {0, 0},
+};
+
+#ifdef MIDNIGHT
+/*
+ what editor are we going to emulate? one of EDIT_KEY_EMULATION_NORMAL
+ or EDIT_KEY_EMULATION_EMACS
+ */
+int edit_key_emulation = EDIT_KEY_EMULATION_NORMAL;
+#endif /* ! MIDNIGHT */
+
+int option_word_wrap_line_length = 72;
+int option_typewriter_wrap = 0;
+int option_auto_para_formatting = 0;
+int option_international_characters = 0;
+int option_tab_spacing = 8;
+int option_fill_tabs_with_spaces = 0;
+int option_return_does_auto_indent = 1;
+int option_backspace_through_tabs = 0;
+int option_fake_half_tabs = 1;
+int option_save_mode = 0;
+int option_backup_ext_int = -1;
+int option_find_bracket = 1;
+int option_max_undo = 8192;
+
+int option_editor_fg_normal = 26;
+int option_editor_fg_bold = 8;
+int option_editor_fg_italic = 10;
+
+int option_edit_right_extreme = 0;
+int option_edit_left_extreme = 0;
+int option_edit_top_extreme = 0;
+int option_edit_bottom_extreme = 0;
+
+int option_editor_bg_normal = 1;
+int option_editor_bg_abnormal = 0;
+int option_editor_bg_marked = 2;
+int option_editor_bg_marked_abnormal = 9;
+int option_editor_bg_highlighted = 12;
+int option_editor_fg_cursor = 18;
+
+char *option_whole_chars_search = "0123456789abcdefghijklmnopqrstuvwxyz_";
+char *option_whole_chars_move = "0123456789abcdefghijklmnopqrstuvwxyz_; ,[](){}";
+char *option_backup_ext = "~";
+
+#else /* ! _EDIT_C */
+
+extern struct selection selection;
+extern struct selection selection_history[];
+extern int current_selection;
+
+#ifdef MIDNIGHT
+/*
+ what editor are we going to emulate? one of EDIT_KEY_EMULATION_NORMAL
+ or EDIT_KEY_EMULATION_EMACS
+ */
+extern int edit_key_emulation;
+#endif /* ! MIDNIGHT */
+
+extern int option_word_wrap_line_length;
+extern int option_typewriter_wrap;
+extern int option_auto_para_formatting;
+extern int option_international_characters;
+extern int option_tab_spacing;
+extern int option_fill_tabs_with_spaces;
+extern int option_return_does_auto_indent;
+extern int option_backspace_through_tabs;
+extern int option_fake_half_tabs;
+extern int option_save_mode;
+extern int option_backup_ext_int;
+extern int option_find_bracket;
+extern int option_max_undo;
+
+extern int option_editor_fg_normal;
+extern int option_editor_fg_bold;
+extern int option_editor_fg_italic;
+
+extern int option_edit_right_extreme;
+extern int option_edit_left_extreme;
+extern int option_edit_top_extreme;
+extern int option_edit_bottom_extreme;
+
+extern int option_editor_bg_normal;
+extern int option_editor_bg_abnormal;
+extern int option_editor_bg_marked;
+extern int option_editor_bg_marked_abnormal;
+extern int option_editor_bg_highlighted;
+extern int option_editor_fg_cursor;
+
+extern char *option_whole_chars_search;
+extern char *option_whole_chars_move;
+extern char *option_backup_ext;
+
+extern int edit_confirm_save;
+
+#endif /* ! _EDIT_C */
+#endif /* __EDIT_H */
--- /dev/null
+/*
+ these #defines are probably the ones most people will be interested in.
+ You can use these two #defines to hard code the key mappings --- just
+ uncomment the one you want. But only if you have trouble with learn
+ keys (which is unlikely).
+*/
+
+ /* KEY_BACKSPACE is the key learned in the learn keys menu : */
+#define OUR_BACKSPACE_KEY KEY_BACKSPACE
+ /* ...otherwise ctrl-h : */
+/* #define OUR_BACKSPACE_KEY XCTRL ('h') */
+ /* ...otherwise 127 or DEL in ascii : */
+/* #define OUR_BACKSPACE_KEY 0177 */
+
+ /* KEY_DC is the key learned in the learn keys menu */
+#define OUR_DELETE_KEY KEY_DC
+ /* ...otherwise ctrl-d : */
+/* #define OUR_DELETE_KEY XCTRL ('d') */
+ /* ...otherwise 127 or DEL in ascii : */
+/* #define OUR_DELETE_KEY 0177 */
+
+
+/*
+ This is #include'd into the function edit_translate_key in edit.c.
+ This sequence of code takes 'x_state' and 'x_key' and translates them
+ into either 'command' or 'char_for_insertion'. 'x_key' holds one of
+ KEY_NPAGE, KEY_HOME etc., and 'x_state' holds a bitwise inclusive OR of
+ CONTROL_PRESSED, ALT_PRESSED or SHIFT_PRESSED, although none may
+ be supported.
+ 'command' is one of the editor commands editcmddef.h.
+
+ Almost any C code can go into this file. The code below is an example
+ that may by appended or modified by the user.
+ */
+
+/* look in this file for the list of commands : */
+#include "editcmddef.h"
+
+#define KEY_NUMLOCK ???
+
+/* ordinary translations. (Some of this may be redundant.) Note that keys listed
+ first take priority when a key is assigned to more than one command */
+ static long *key_map;
+ static long cooledit_key_map[] =
+ {OUR_BACKSPACE_KEY, CK_BackSpace, OUR_DELETE_KEY, CK_Delete,
+ XCTRL ('d'), CK_Delete, '\n', CK_Enter,
+ KEY_PPAGE, CK_Page_Up, KEY_NPAGE, CK_Page_Down, KEY_LEFT, CK_Left,
+ KEY_RIGHT, CK_Right, KEY_UP, CK_Up, KEY_DOWN, CK_Down, ALT ('\t'), CK_Return, ALT ('\n'), CK_Return,
+ KEY_HOME, CK_Home, KEY_END, CK_End, '\t', CK_Tab, XCTRL ('u'), CK_Undo, KEY_IC, CK_Toggle_Insert,
+ XCTRL ('o'), CK_Load, KEY_F (3), CK_Mark, KEY_F (5), CK_Copy,
+ KEY_F (6), CK_Move, KEY_F (8), CK_Remove, KEY_F (12), CK_Save_As,
+ KEY_F (2), CK_Save, XCTRL ('n'), CK_New,
+ XCTRL ('l'), CK_Refresh, ESC_CHAR, CK_Exit, KEY_F (10), CK_Exit,
+ KEY_F (19), /*C formatter */ CK_Pipe_Block (0),
+ XCTRL ('p'), /*spell check */ CK_Pipe_Block (1),
+ KEY_F (15), CK_Insert_File,
+ XCTRL ('f'), CK_Save_Block, KEY_F (1), CK_Help,
+ ALT ('t'), CK_Sort, ALT ('m'), CK_Mail,
+ XCTRL ('z'), CK_Word_Left, XCTRL ('x'), CK_Word_Right,
+ KEY_F (4), CK_Replace, KEY_F (7), CK_Find, KEY_F (14), CK_Replace_Again,
+ XCTRL ('h'), CK_BackSpace, ALT ('l'), CK_Goto, ALT ('L'), CK_Goto, XCTRL ('y'), CK_Delete_Line,
+ KEY_F (17), CK_Find_Again, ALT ('p'), CK_Paragraph_Format, 0};
+
+ static long emacs_key_map[] =
+ {OUR_BACKSPACE_KEY, CK_BackSpace, OUR_DELETE_KEY, CK_Delete, '\n', CK_Enter,
+ KEY_PPAGE, CK_Page_Up, KEY_NPAGE, CK_Page_Down, KEY_LEFT, CK_Left,
+ KEY_RIGHT, CK_Right, KEY_UP, CK_Up, KEY_DOWN, CK_Down, ALT ('\t'), CK_Return, ALT ('\n'), CK_Return,
+ KEY_HOME, CK_Home, KEY_END, CK_End, '\t', CK_Tab, XCTRL ('u'), CK_Undo, KEY_IC, CK_Toggle_Insert,
+ XCTRL ('o'), CK_Load, KEY_F (3), CK_Mark, KEY_F (5), CK_Copy,
+ KEY_F (6), CK_Move, KEY_F (8), CK_Remove, KEY_F (12), CK_Save_As,
+ KEY_F (2), CK_Save, ALT ('p'), CK_Paragraph_Format,
+
+ ALT ('t'), CK_Sort,
+
+ XCTRL ('a'), CK_Home, XCTRL ('e'), CK_End,
+ XCTRL ('b'), CK_Left, XCTRL ('f'), CK_Right,
+ XCTRL ('n'), CK_Down, XCTRL ('p'), CK_Up,
+ XCTRL ('d'), CK_Delete,
+ XCTRL ('v'), CK_Page_Down, ALT ('v'), CK_Page_Up,
+ XCTRL ('@'), CK_Mark,
+ XCTRL ('k'), CK_Delete_To_Line_End,
+ XCTRL ('s'), CK_Find,
+
+ ALT ('b'), CK_Word_Left, ALT ('f'), CK_Word_Right,
+ XCTRL ('w'), CK_XCut,
+ XCTRL ('y'), CK_XPaste,
+ ALT ('w'), CK_XStore,
+
+ XCTRL ('l'), CK_Refresh, ESC_CHAR, CK_Exit, KEY_F (10), CK_Exit,
+ KEY_F (19), /*C formatter */ CK_Pipe_Block (0),
+ ALT ('$'), /*spell check */ CK_Pipe_Block (1),
+ KEY_F (15), CK_Insert_File,
+ KEY_F (1), CK_Help,
+
+ KEY_F (4), CK_Replace, KEY_F (7), CK_Find, KEY_F (14), CK_Replace_Again,
+ XCTRL ('h'), CK_BackSpace, ALT ('l'), CK_Goto, ALT ('L'), CK_Goto,
+ KEY_F (17), CK_Find_Again,
+ ALT ('<'), CK_Beginning_Of_Text,
+ ALT ('>'), CK_End_Of_Text,
+
+ 0, 0};
+
+ static long key_pad_map[10] =
+ {XCTRL ('o'), KEY_END, KEY_DOWN, KEY_NPAGE, KEY_LEFT,
+ KEY_DOWN, KEY_RIGHT, KEY_HOME, KEY_UP, KEY_PPAGE};
+
+
+#define DEFAULT_NUM_LOCK 0
+
+ static int num_lock = DEFAULT_NUM_LOCK;
+ int i = 0;
+
+ switch (edit_key_emulation) {
+ case EDIT_KEY_EMULATION_NORMAL:
+ key_map = cooledit_key_map;
+ break;
+ case EDIT_KEY_EMULATION_EMACS:
+ key_map = emacs_key_map;
+ if (x_key == XCTRL ('x')) {
+ int ext_key;
+ ext_key = edit_raw_key_query (" Ctrl-X ", _(" Emacs key: "), 0);
+ switch (ext_key) {
+ case 's':
+ command = CK_Save;
+ goto fin;
+ case 'x':
+ command = CK_Exit;
+ goto fin;
+ case 'k':
+ command = CK_New;
+ goto fin;
+ case 'e':
+ command = CK_Macro (edit_raw_key_query (_(" Execute Macro "), _(" Press macro hotkey: "), 1));
+ if (command == CK_Macro (0))
+ command = -1;
+ goto fin;
+ }
+ goto fin;
+ }
+ break;
+ }
+
+ if (x_key == XCTRL ('q')) {
+ char_for_insertion = edit_raw_key_query (_(" Insert Literal "), _(" Press any key: "), 0);
+ goto fin;
+ }
+ if (x_key == XCTRL ('a') && edit_key_emulation != EDIT_KEY_EMULATION_EMACS) {
+ command = CK_Macro (edit_raw_key_query (" Execute Macro ", " Press macro hotkey: ", 1));
+ if (command == CK_Macro (0))
+ command = -1;
+ goto fin;
+ }
+/* edit is a pointer to the widget */
+ if (edit)
+ if (x_key == XCTRL ('r')) {
+ command = edit->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
+ goto fin;
+ }
+/* if (x_key == KEY_NUMLOCK) {
+ num_lock = 1 - num_lock;
+ return 1;
+ }
+ */
+
+/* first translate the key-pad */
+ if (num_lock) {
+ if (x_key >= '0' && x_key <= '9') {
+ x_key = key_pad_map[x_key - '0'];
+ }
+ if (x_key == '.') {
+ x_key = KEY_DC;
+ }
+ }
+ if ((x_state & SHIFT_PRESSED) && (x_state & CONTROL_PRESSED)) {
+ switch (x_key) {
+ case KEY_PPAGE:
+ command = CK_Beginning_Of_Text_Highlight;
+ goto fin;
+ case KEY_NPAGE:
+ command = CK_End_Of_Text_Highlight;
+ goto fin;
+ case KEY_LEFT:
+ command = CK_Word_Left_Highlight;
+ goto fin;
+ case KEY_RIGHT:
+ command = CK_Word_Right_Highlight;
+ goto fin;
+ }
+ }
+ if ((x_state & SHIFT_PRESSED) && !(x_state & CONTROL_PRESSED)) {
+ switch (x_key) {
+ case KEY_PPAGE:
+ command = CK_Page_Up_Highlight;
+ goto fin;
+ case KEY_NPAGE:
+ command = CK_Page_Down_Highlight;
+ goto fin;
+ case KEY_LEFT:
+ command = CK_Left_Highlight;
+ goto fin;
+ case KEY_RIGHT:
+ command = CK_Right_Highlight;
+ goto fin;
+ case KEY_UP:
+ command = CK_Up_Highlight;
+ goto fin;
+ case KEY_DOWN:
+ command = CK_Down_Highlight;
+ goto fin;
+ case KEY_HOME:
+ command = CK_Home_Highlight;
+ goto fin;
+ case KEY_END:
+ command = CK_End_Highlight;
+ goto fin;
+ case KEY_IC:
+ command = CK_XPaste;
+ goto fin;
+ case KEY_DC:
+ command = CK_XCut;
+ goto fin;
+ }
+ }
+/* things that need a control key */
+ if (x_state & CONTROL_PRESSED) {
+ switch (x_key) {
+ case KEY_F (2):
+ command = CK_Save_As;
+ goto fin;
+ case KEY_F (4):
+ command = CK_Replace_Again;
+ goto fin;
+ case KEY_F (7):
+ command = CK_Find_Again;
+ goto fin;
+ case KEY_BACKSPACE:
+ command = CK_Undo;
+ goto fin;
+ case KEY_PPAGE:
+ command = CK_Beginning_Of_Text;
+ goto fin;
+ case KEY_NPAGE:
+ command = CK_End_Of_Text;
+ goto fin;
+ case KEY_UP:
+ command = CK_Scroll_Up;
+ goto fin;
+ case KEY_DOWN:
+ command = CK_Scroll_Down;
+ goto fin;
+ case KEY_LEFT:
+ command = CK_Word_Left;
+ goto fin;
+ case KEY_RIGHT:
+ command = CK_Word_Right;
+ goto fin;
+ case KEY_IC:
+ command = CK_XStore;
+ goto fin;
+ case KEY_DC:
+ command = CK_Remove;
+ goto fin;
+ }
+ }
+/* an ordinary insertable character */
+ if (x_key < 256 && is_printable (x_key)) {
+ char_for_insertion = x_key;
+ goto fin;
+ }
+/* other commands */
+ i = 0;
+ while (key_map[i] != x_key && (key_map[i] || key_map[i + 1]))
+ i += 2;
+ command = key_map[i + 1];
+ if (command)
+ goto fin;
+
+/* Function still not found for this key, so try macro's */
+/* This allows the same macro to be
+ enabled by either eg "ALT('f')" or "XCTRL('f')" or "XCTRL('a'), 'f'" */
+
+/* key.h: #define ALT(x) (0x200 | (x)) */
+ if (x_key & ALT (0)) { /* is an alt key ? */
+ command = CK_Macro (x_key - ALT (0));
+ goto fin;
+ }
+/* key.h: #define XCTRL(x) ((x) & 31) */
+ if (x_key < ' ') { /* is a ctrl key ? */
+ command = CK_Macro (x_key);
+ goto fin;
+ }
+ fin:
+
+
--- /dev/null
+/* editor high level editing commands.
+
+ Copyright (C) 1996, 1997 the Free Software Foundation
+
+ Authors: 1996, 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* #define PIPE_BLOCKS_SO_READ_BYTE_BY_BYTE */
+
+#include <config.h>
+#ifdef OS2_NT
+#include <io.h>
+#include <fcntl.h>
+#endif
+#include <ctype.h>
+#include "edit.h"
+#include "editcmddef.h"
+
+#ifndef MIDNIGHT
+#include <X11/Xatom.h>
+#include "loadfile.h"
+#endif
+
+/* globals: */
+
+/* search and replace: */
+int replace_scanf = 0;
+int replace_regexp = 0;
+int replace_all = 0;
+int replace_prompt = 1;
+int replace_whole = 0;
+int replace_case = 0;
+int replace_backwards = 0;
+
+/* queries on a save */
+#ifdef MIDNIGHT
+int edit_confirm_save = 1;
+#else
+int edit_confirm_save = 0;
+#endif
+
+#define NUM_REPL_ARGS 16
+#define MAX_REPL_LEN 1024
+
+#ifdef MIDNIGHT
+
+static inline int my_lower_case (int c)
+{
+ return tolower(c);
+}
+
+char *strcasechr (const unsigned char *s, int c)
+{
+ for (; my_lower_case ((int) *s) != my_lower_case (c); ++s)
+ if (*s == '\0')
+ return 0;
+ return (char *) s;
+}
+
+
+#include "../src/mad.h"
+
+#ifndef HAVE_MEMMOVE
+/* for Christophe */
+static void *memmove (void *dest, const void *src, size_t n)
+{
+ char *t, *s;
+
+ if (dest <= src) {
+ t = (char *) dest;
+ s = (char *) src;
+ while (n--)
+ *t++ = *s++;
+ } else {
+ t = (char *) dest + n;
+ s = (char *) src + n;
+ while (n--)
+ *--t = *--s;
+ }
+ return dest;
+}
+#endif
+
+/* #define itoa MY_itoa <---- this line is now in edit.h */
+char *itoa (int i)
+{
+ static char t[14];
+ char *s = t + 13;
+ int j = i;
+ *s-- = 0;
+ do {
+ *s-- = i % 10 + '0';
+ } while ((i = i / 10));
+ if (j < 0)
+ *s-- = '-';
+ return ++s;
+}
+
+/*
+ This joins strings end on end and allocates memory for the result.
+ The result is later automatically free'd and must not be free'd
+ by the caller.
+ */
+char *catstrs (const char *first,...)
+{
+ static char *stacked[16] =
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ static int i = 0;
+ va_list ap;
+ int len;
+ char *data;
+
+ if (!first)
+ return 0;
+
+ len = strlen (first);
+ va_start (ap, first);
+
+ while ((data = va_arg (ap, char *)) != 0)
+ len += strlen (data);
+
+ len++;
+
+ i = (i + 1) % 16;
+ if (stacked[i])
+ free (stacked[i]);
+
+ stacked[i] = malloc (len);
+ va_end (ap);
+ va_start (ap, first);
+ strcpy (stacked[i], first);
+ while ((data = va_arg (ap, char *)) != 0)
+ strcat (stacked[i], data);
+ va_end (ap);
+
+ return stacked[i];
+}
+#endif
+
+#ifdef MIDNIGHT
+
+void edit_help_cmd (WEdit * edit)
+{
+ char *hlpdir = concat_dir_and_file (mc_home, "mc.hlp");
+ interactive_display (hlpdir, "[Internal File Editor]");
+ free (hlpdir);
+ edit->force |= REDRAW_COMPLETELY;
+}
+
+void edit_refresh_cmd (WEdit * edit)
+{
+#ifndef HAVE_SLANG
+ clr_scr();
+ do_refresh();
+#else
+ {
+ int fg, bg;
+ edit_get_syntax_color (edit, -1, &fg, &bg);
+ }
+ touchwin(stdscr);
+#endif
+ mc_refresh();
+ doupdate();
+}
+
+#else
+
+void edit_help_cmd (WEdit * edit)
+{
+}
+
+void edit_refresh_cmd (WEdit * edit)
+{
+}
+
+void CRefreshEditor (WEdit * edit)
+{
+ edit_refresh_cmd (edit);
+}
+
+#endif
+
+#ifndef MIDNIGHT
+
+/* three argument open */
+int my_open (const char *pathname, int flags,...)
+{
+ int file;
+ va_list ap;
+
+ file = open ((char *) pathname, O_RDONLY);
+ if (file < 0 && (flags & O_CREAT)) { /* must it be created ? */
+ mode_t mode;
+ va_start(ap, flags);
+ mode = va_arg(ap, mode_t);
+ va_end(ap);
+ return creat ((char *) pathname, mode);
+ }
+ close (file);
+ return open ((char *) pathname, flags);
+}
+
+#define open my_open
+
+#endif
+
+/* "Oleg Yu. Repin" <repin@ssd.sscc.ru> added backup filenames
+ ...thanks -paul */
+
+/* If 0 (quick save) then a) create/truncate <filename> file,
+ b) save to <filename>;
+ if 1 (safe save) then a) save to <tempnam>,
+ b) rename <tempnam> to <filename>;
+ if 2 (do backups) then a) save to <tempnam>,
+ b) rename <filename> to <filename.backup_ext>,
+ c) rename <tempnam> to <filename>. */
+
+/* returns 0 on error */
+int edit_save_file (WEdit * edit, const char *filename)
+{
+ long buf;
+ long filelen = 0;
+ int file;
+ char *savename = (char *) filename;
+ int this_save_mode;
+
+ if ((file = open (savename, O_WRONLY)) == -1) {
+ this_save_mode = 0; /* the file does not exists yet, so no safe save or backup necessary */
+ } else {
+ close (file);
+ this_save_mode = option_save_mode;
+ }
+
+ if (this_save_mode > 0) {
+ char *savedir = ".", *slashpos = strrchr (filename, '/');
+ if (slashpos != 0) {
+ savedir = strdup (filename);
+ if (savedir == 0)
+ return 0;
+ savedir[slashpos - filename + 1] = '\0';
+ }
+#ifdef HAVE_MAD
+ savename = strdup (tempnam (savedir, "cooledit"));
+#else
+ savename = tempnam (savedir, "cooledit");
+#endif
+ if (slashpos)
+ free (savedir);
+ if (!savename)
+ return 0;
+ }
+ if ((file = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT, edit->stat.st_mode)) == -1) {
+ if (this_save_mode > 0)
+ free (savename);
+ return 0;
+ }
+ chown (savename, edit->stat.st_uid, edit->stat.st_gid);
+ buf = 0;
+ while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) {
+ filelen += write (file, (char *) edit->buffers1[buf], EDIT_BUF_SIZE);
+ buf++;
+ }
+ filelen += write (file, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE);
+
+ if (edit->curs2) {
+ edit->curs2--;
+ buf = (edit->curs2 >> S_EDIT_BUF_SIZE);
+ filelen += write (file, (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1, 1 + (edit->curs2 & M_EDIT_BUF_SIZE));
+ buf--;
+ while (buf >= 0) {
+ filelen += write (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE);
+ buf--;
+ }
+ edit->curs2++;
+ }
+ close (file);
+
+ if (filelen == edit->last_byte) {
+ if (this_save_mode == 2) {
+ if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1) { /* catstrs free's automatically */
+ free (savename);
+ return 0;
+ }
+ }
+ if (this_save_mode > 0) {
+ if (rename (savename, filename) == -1) {
+ free (savename);
+ return 0;
+ }
+ free (savename);
+ }
+ return 1;
+ } else {
+ if (this_save_mode > 0)
+ free (savename);
+ return 0;
+ }
+}
+
+#ifdef MIDNIGHT
+/*
+ I changed this from Oleg's original routine so
+ that option_backup_ext works with coolwidgets as well. This
+ does mean there is a memory leak - paul.
+ */
+void menu_save_mode_cmd (void)
+{
+#define DLG_X 36
+#define DLG_Y 10
+ static char *str_result;
+ static int save_mode_new;
+ static char *str[] =
+ {
+ "Quick save ",
+ "Safe save ",
+ "Do backups -->"};
+ static QuickWidget widgets[] =
+ {
+ {quick_button, 18, DLG_X, 7, DLG_Y, "&Cancel", 0,
+ B_CANCEL, 0, 0, XV_WLAY_DONTCARE, "c"},
+ {quick_button, 6, DLG_X, 7, DLG_Y, "&Ok", 0,
+ B_ENTER, 0, 0, XV_WLAY_DONTCARE, "o"},
+ {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9,
+ 0, 0, &str_result, XV_WLAY_DONTCARE, "i"},
+ {quick_label, 22, DLG_X, 4, DLG_Y, "Extension:", 0,
+ 0, 0, 0, XV_WLAY_DONTCARE, "savemext"},
+ {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3,
+ 0, &save_mode_new, str, XV_WLAY_DONTCARE, "t"},
+ {0}};
+ static QuickDialog dialog =
+/* NLS ? */
+ {DLG_X, DLG_Y, -1, -1, " Edit Save Mode ", "[Edit Save Mode]",
+ "esm", widgets};
+
+ widgets[2].text = option_backup_ext;
+ widgets[4].value = option_save_mode;
+ if (quick_dialog (&dialog) != B_ENTER)
+ return;
+ option_save_mode = save_mode_new;
+ option_backup_ext = str_result; /* this is a memory leak */
+ option_backup_ext_int = 0;
+ str_result[min (strlen (str_result), sizeof (int))] = '\0';
+ memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext));
+}
+
+#endif
+
+#ifdef MIDNIGHT
+
+void edit_split_filename (WEdit * edit, char *f)
+{
+ if (edit->filename)
+ free (edit->filename);
+ edit->filename = strdup (f);
+ if (edit->dir)
+ free (edit->dir);
+ edit->dir = strdup ("");
+}
+
+#else
+
+void edit_split_filename (WEdit * edit, char *longname)
+{
+ char *exp, *p;
+ exp = canonicalize_pathname (longname); /* this ensures a full path */
+ if (edit->filename)
+ free (edit->filename);
+ if (edit->dir)
+ free (edit->dir);
+ p = strrchr (exp, '/');
+ edit->filename = strdup (++p);
+ *p = 0;
+ edit->dir = strdup (exp);
+ free (exp);
+}
+
+#endif
+
+/* here we want to warn the user of overwriting an existing file, but only if they
+ have made a change to the filename */
+/* returns 1 on success */
+int edit_save_as_cmd (WEdit * edit)
+{
+/* This heads the 'Save As' dialog box */
+ char *exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As "));
+ int different_filename = 0;
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+ edit->force |= REDRAW_COMPLETELY;
+
+ if (exp) {
+ if (!*exp) {
+ free (exp);
+ return 0;
+ } else {
+ if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) {
+ int file;
+ different_filename = 1;
+ if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */
+ close (file);
+ if (edit_query_dialog2 (_(" Warning "),
+ _(" A file already exists with this name. "),
+/* Push buttons to over-write the current file, or cancel the operation */
+ _("Overwrite"), _("Cancel")))
+ return 0;
+ }
+ }
+ if (edit_save_file (edit, exp)) {
+ edit_split_filename (edit, exp);
+ free (exp);
+ edit->modified = 0;
+#ifdef MIDNIGHT
+ edit->delete_file = 0;
+#endif
+ if (different_filename && !edit->explicit_syntax)
+ edit_load_syntax (edit, 0, 0);
+ return 1;
+ } else {
+ free (exp);
+ edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. ")));
+ return 0;
+ }
+ }
+ } else
+ return 0;
+}
+
+/* {{{ Macro stuff starts here */
+
+#ifdef MIDNIGHT
+int raw_callback (struct Dlg_head *h, int key, int Msg)
+{
+ switch (Msg) {
+ case DLG_DRAW:
+ attrset (REVERSE_COLOR);
+ dlg_erase (h);
+ draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 1, 2);
+ printw (h->title);
+ break;
+
+ case DLG_KEY:
+ h->running = 0;
+ h->ret_value = key;
+ return 1;
+ }
+ return 0;
+}
+
+/* gets a raw key from the keyboard. Passing cancel = 1 draws
+ a cancel button thus allowing c-c etc.. Alternatively, cancel = 0
+ will return the next key pressed */
+int edit_raw_key_query (char *heading, char *query, int cancel)
+{
+ int w = strlen (query) + 7;
+ struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors,
+/* NLS ? */
+ raw_callback, "[Raw Key Query]",
+ "raw_key_input",
+ DLG_CENTER | DLG_TRYUP);
+ x_set_dialog_title (raw_dlg, heading);
+ raw_dlg->raw = 1; /* to return even a tab key */
+ if (cancel)
+ add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, "Cancel", 0, 0, 0));
+ add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0));
+ add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0));
+ run_dlg (raw_dlg);
+ w = raw_dlg->ret_value;
+ destroy_dlg (raw_dlg);
+ if (cancel)
+ if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL)
+ return 0;
+/* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */
+ return w;
+}
+
+#else
+
+int edit_raw_key_query (char *heading, char *query, int cancel)
+{
+ return CKeySymMod (CRawkeyQuery (0, 0, 0, heading, query));
+}
+
+#endif
+
+/* creates a macro file if it doesn't exist */
+static FILE *edit_open_macro_file (const char *r)
+{
+ char *filename;
+ int file;
+ filename = catstrs (home_dir, MACRO_FILE, 0);
+ if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
+ return 0;
+ close (file);
+ return fopen (filename, r);
+}
+
+#define MAX_MACROS 1024
+static int saved_macro[MAX_MACROS + 1] =
+{0, 0};
+static int saved_macros_loaded = 0;
+
+/*
+ This is just to stop the macro file be loaded over and over for keys
+ that aren't defined to anything. On slow systems this could be annoying.
+ */
+int macro_exists (int k)
+{
+ int i;
+ for (i = 0; i < MAX_MACROS && saved_macro[i]; i++)
+ if (saved_macro[i] == k)
+ return i;
+ return -1;
+}
+
+/* returns 1 on error */
+int edit_delete_macro (WEdit * edit, int k)
+{
+ struct macro macro[MAX_MACRO_LENGTH];
+ FILE *f, *g;
+ int s, i, n, j = 0;
+
+ if (saved_macros_loaded)
+ if ((j = macro_exists (k)) < 0)
+ return 0;
+ g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w");
+ if (!g) {
+/* This heads the delete macro error dialog box */
+ edit_error_dialog (_(" Delete macro "),
+/* 'Open' = load temp file */
+ get_sys_error (_(" Error trying to open temp file ")));
+ return 1;
+ }
+ f = edit_open_macro_file ("r");
+ if (!f) {
+/* This heads the delete macro error dialog box */
+ edit_error_dialog (_(" Delete macro "),
+/* 'Open' = load temp file */
+ get_sys_error (_(" Error trying to open macro file ")));
+ fclose (g);
+ return 1;
+ }
+ for (;;) {
+ n = fscanf (f, _("key '%d 0': "), &s);
+ if (!n || n == EOF)
+ break;
+ n = 0;
+ while (fscanf (f, "%hd %hd, ", ¯o[n].command, ¯o[n].ch))
+ n++;
+ fscanf (f, ";\n");
+ if (s != k) {
+ fprintf (g, _("key '%d 0': "), s);
+ for (i = 0; i < n; i++)
+ fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch);
+ fprintf (g, ";\n");
+ }
+ };
+ fclose (f);
+ fclose (g);
+ if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) {
+/* This heads the delete macro error dialog box */
+ edit_error_dialog (_(" Delete macro "),
+ get_sys_error (_(" Error trying to overwrite macro file ")));
+ return 1;
+ }
+ if (saved_macros_loaded)
+ memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1));
+ return 0;
+}
+
+/* returns 0 on error */
+int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n)
+{
+ FILE *f;
+ int s, i;
+
+ edit->force |= REDRAW_COMPLETELY;
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+/* This heads the 'Macro' dialog box */
+ s = edit_raw_key_query (_(" Macro "),
+/* Input line for a single key press follows the ':' */
+ _(" Press the macro's new hotkey: "), 1);
+ if (s) {
+ if (edit_delete_macro (edit, s))
+ return 0;
+ f = edit_open_macro_file ("a+");
+ if (f) {
+ fprintf (f, _("key '%d 0': "), s);
+ for (i = 0; i < n; i++)
+ fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch);
+ fprintf (f, ";\n");
+ fclose (f);
+ if (saved_macros_loaded) {
+ for (i = 0; i < MAX_MACROS && saved_macro[i]; i++);
+ saved_macro[i] = s;
+ }
+ return 1;
+ } else
+/* This heads the 'Save Macro' dialog box */
+ edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file ")));
+ }
+ return 0;
+}
+
+void edit_delete_macro_cmd (WEdit * edit)
+{
+ int command;
+
+#ifdef MIDNIGHT
+ command = CK_Macro (edit_raw_key_query (_(" Delete Macro "), _(" Press macro hotkey: "), 1));
+#else
+/* This heads the 'Delete Macro' dialog box */
+ command = CK_Macro (CKeySymMod (CRawkeyQuery (0, 0, 0, _(" Delete Macro "),
+/* Input line for a single key press follows the ':' */
+ _(" Press macro hotkey: "))));
+#endif
+
+ if (command == CK_Macro (0))
+ return;
+
+ edit_delete_macro (edit, command - 2000);
+}
+
+/* return 0 on error */
+int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k)
+{
+ FILE *f;
+ int s, i = 0, found = 0;
+
+ if (saved_macros_loaded)
+ if (macro_exists (k) < 0)
+ return 0;
+
+ if ((f = edit_open_macro_file ("r"))) {
+ struct macro dummy;
+ do {
+ int u;
+ u = fscanf (f, _("key '%d 0': "), &s);
+ if (!u || u == EOF)
+ break;
+ if (!saved_macros_loaded)
+ saved_macro[i++] = s;
+ if (!found) {
+ *n = 0;
+ while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", ¯o[*n].command, ¯o[*n].ch))
+ (*n)++;
+ } else {
+ while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch));
+ }
+ fscanf (f, ";\n");
+ if (s == k)
+ found = 1;
+ } while (!found || !saved_macros_loaded);
+ if (!saved_macros_loaded) {
+ saved_macro[i] = 0;
+ saved_macros_loaded = 1;
+ }
+ fclose (f);
+ return found;
+ } else
+/* This heads the 'Load Macro' dialog box */
+ edit_error_dialog (_(" Load macro "),
+ get_sys_error (_(" Error trying to open macro file ")));
+ return 0;
+}
+
+/* }}} Macro stuff starts here */
+
+/* returns 1 on success */
+int edit_save_confirm_cmd (WEdit * edit)
+{
+ char *f;
+
+ if (edit_confirm_save) {
+#ifdef MIDNIGHT
+ f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0);
+#else
+ f = catstrs (_(" Confirm save file? : "), edit->dir, edit->filename, " ", 0);
+#endif
+/* Buttons to 'Confirm save file' query */
+ if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel")))
+ return 0;
+ }
+ return edit_save_cmd (edit);
+}
+
+
+/* returns 1 on success */
+int edit_save_cmd (WEdit * edit)
+{
+ edit->force |= REDRAW_COMPLETELY;
+ if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0)))
+ return edit_save_as_cmd (edit);
+ edit->modified = 0;
+#ifdef MIDNIGHT
+ edit->delete_file = 0;
+#endif
+
+ return 1;
+}
+
+
+/* returns 1 on success */
+int edit_new_cmd (WEdit * edit)
+{
+ edit->force |= REDRAW_COMPLETELY;
+ if (edit->modified)
+ if (edit_query_dialog2 (_(" Warning "), _(" Current text was modified without a file save. \n Continue discards these changes. "), _("Continue"), _("Cancel")))
+ return 0;
+ edit->modified = 0;
+ return edit_renew (edit); /* if this gives an error, something has really screwed up */
+}
+
+int edit_load_cmd (WEdit * edit)
+{
+ char *exp;
+ edit->force |= REDRAW_COMPLETELY;
+
+ if (edit->modified)
+ if (edit_query_dialog2 (_(" Warning "), _(" Current text was modified without a file save. \n Continue discards these changes. "), _("Continue"), _("Cancel")))
+ return 0;
+
+ exp = edit_get_load_file (edit->dir, edit->filename, _(" Load "));
+
+ if (exp) {
+ if (!*exp) {
+ free (exp);
+ } else {
+ int file;
+ if ((file = open ((char *) exp, O_RDONLY, MY_O_TEXT)) != -1) {
+ close (file);
+ edit_reload (edit, exp, 0, "", 0);
+ edit_split_filename (edit, exp);
+ free (exp);
+ edit->modified = 0;
+ return 1;
+ } else {
+ free (exp);
+/* Heads the 'Load' file dialog box */
+ edit_error_dialog (_(" Load "), get_sys_error (_(" Error trying to open file for reading ")));
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ if mark2 is -1 then marking is from mark1 to the cursor.
+ Otherwise its between the markers. This handles this.
+ Returns 1 if no text is marked.
+ */
+int eval_marks (WEdit * edit, long *start_mark, long *end_mark)
+{
+ if (edit->mark1 != edit->mark2) {
+ if (edit->mark2 >= 0) {
+ *start_mark = min (edit->mark1, edit->mark2);
+ *end_mark = max (edit->mark1, edit->mark2);
+ } else {
+ *start_mark = min (edit->mark1, edit->curs1);
+ *end_mark = max (edit->mark1, edit->curs1);
+ edit->column2 = edit->curs_col;
+ }
+ return 0;
+ } else {
+ *start_mark = *end_mark = 0;
+ edit->column2 = edit->column1 = 0;
+ return 1;
+ }
+}
+
+/*Block copy, move and delete commands */
+
+void edit_block_copy_cmd (WEdit * edit)
+{
+ long start_mark, end_mark, current = edit->curs1;
+ long count;
+ char *copy_buf;
+
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return;
+
+
+ copy_buf = malloc (end_mark - start_mark);
+
+/* all that gets pushed are deletes hence little space is used on the stack */
+
+ edit_push_markers (edit);
+
+ count = start_mark;
+ while (count < end_mark) {
+ copy_buf[end_mark - count - 1] = edit_get_byte (edit, count);
+ count++;
+ }
+ while (count-- > start_mark) {
+ edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
+ }
+ free (copy_buf);
+ edit_scroll_screen_over_cursor (edit);
+
+ if (start_mark < current && end_mark > current)
+ edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0);
+
+ edit->force |= REDRAW_PAGE;
+}
+
+
+void edit_block_move_cmd (WEdit * edit)
+{
+ long count;
+ long current;
+ char *copy_buf;
+ long start_mark, end_mark;
+
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return;
+
+ if (start_mark <= edit->curs1 && end_mark >= edit->curs1)
+ return;
+
+ if ((end_mark - start_mark) > option_max_undo / 2)
+ if (edit_query_dialog2 (_(" Warning "), _(" Block is large, you may not be able to undo this action. "), _("Continue"), _("Cancel")))
+ return;
+
+ copy_buf = malloc (end_mark - start_mark);
+
+ edit_push_markers (edit);
+
+ current = edit->curs1;
+ edit_cursor_move (edit, start_mark - edit->curs1);
+ edit_scroll_screen_over_cursor (edit);
+
+ count = start_mark;
+ while (count < end_mark) {
+ copy_buf[end_mark - count - 1] = edit_delete (edit);
+ count++;
+ }
+ edit_scroll_screen_over_cursor (edit);
+
+ edit_cursor_move (edit, current - edit->curs1
+ - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0));
+ edit_scroll_screen_over_cursor (edit);
+
+ while (count-- > start_mark) {
+ edit_insert_ahead (edit, copy_buf[end_mark - count - 1]);
+ edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0);
+ }
+ edit_scroll_screen_over_cursor (edit);
+
+ free (copy_buf);
+ edit->force |= REDRAW_PAGE;
+}
+
+void edit_cursor_to_bol (WEdit * edit);
+
+extern int column_highlighting;
+
+void edit_delete_column_of_text (WEdit * edit)
+{
+ long p, q, r, m1, m2;
+ int b, c, d, fin;
+
+ eval_marks (edit, &m1, &m2);
+ c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1);
+ d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2);
+
+ b = min (c, d);
+ c = max (c, d);
+
+ fin = 0;
+ while (!fin) {
+ eval_marks (edit, &m1, &m2);
+ r = edit_bol (edit, edit->curs1);
+ p = edit_move_forward3 (edit, r, b, 0);
+ q = edit_move_forward3 (edit, r, c, 0);
+ if (p < m1)
+ p = m1;
+ if (q >= m2) {
+ q = m2;
+ fin = 1;
+ }
+ edit_cursor_move (edit, p - edit->curs1);
+ while (p != q) { /* delete line between margins */
+ if (edit_get_byte (edit, edit->curs1) != '\n')
+ edit_delete (edit);
+ q--;
+ }
+ if (!fin) /* next line */
+ edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1);
+ }
+}
+
+/* returns 1 if canceelled by user */
+int edit_block_delete_cmd (WEdit * edit)
+{
+ long count;
+ long start_mark, end_mark;
+
+ if (eval_marks (edit, &start_mark, &end_mark)) {
+ start_mark = edit_bol (edit, edit->curs1);
+ end_mark = edit_eol (edit, edit->curs1) + 1;
+ }
+ if ((end_mark - start_mark) > option_max_undo / 2)
+/* Warning message with a query to continue or cancel the operation */
+ if (edit_query_dialog2 (_(" Warning "), _(" Block is large, you may not be able to undo this action. "), _(" Continue "), _(" Cancel ")))
+ return 1;
+
+ edit_push_markers (edit);
+
+ edit_cursor_move (edit, start_mark - edit->curs1);
+ edit_scroll_screen_over_cursor (edit);
+
+ count = start_mark;
+ if (start_mark < end_mark) {
+ if (column_highlighting) {
+ edit_delete_column_of_text (edit);
+ } else {
+ while (count < end_mark) {
+ edit_delete (edit);
+ count++;
+ }
+ }
+ }
+ edit_set_markers (edit, 0, 0, 0, 0);
+ edit->force |= REDRAW_PAGE;
+
+ return 0;
+}
+
+
+#ifdef MIDNIGHT
+
+#define INPUT_INDEX 9
+#define SEARCH_DLG_HEIGHT 10
+#define REPLACE_DLG_HEIGHT 15
+#define B_REPLACE_ALL B_USER+1
+#define B_SKIP_REPLACE B_USER+2
+
+int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
+{
+ if (replace_prompt) {
+ QuickWidget quick_widgets[] =
+ {
+/* NLS for hotkeys? */
+ {quick_button, 14, 18, 3, 6, "&Cancel", 0, B_CANCEL, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_button, 9, 18, 3, 6, "Replace &all", 0, B_REPLACE_ALL, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_button, 6, 18, 3, 6, "&Skip", 0, B_SKIP_REPLACE, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_button, 2, 18, 3, 6, "&Replace", 0, B_ENTER, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_label, 2, 50, 2, 6, 0,
+ 0, 0, 0, XV_WLAY_DONTCARE, 0},
+ {0}};
+
+ quick_widgets[4].text = catstrs (_(" Replace with: "), replace_text, 0);
+
+ {
+ QuickDialog Quick_input =
+ {66, 6, 0, 0, N_(" Replace "),
+ "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
+
+ Quick_input.widgets = quick_widgets;
+
+ Quick_input.xpos = xpos;
+ Quick_input.ypos = ypos;
+ return quick_dialog (&Quick_input);
+ }
+ } else
+ return 0;
+}
+
+
+
+void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
+{
+ int treplace_scanf = replace_scanf;
+ int treplace_regexp = replace_regexp;
+ int treplace_all = replace_all;
+ int treplace_prompt = replace_prompt;
+ int treplace_backwards = replace_backwards;
+ int treplace_whole = replace_whole;
+ int treplace_case = replace_case;
+
+ char *tsearch_text;
+ char *treplace_text;
+ char *targ_order;
+ QuickWidget quick_widgets[] =
+ {
+ {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 25, 50, 11, REPLACE_DLG_HEIGHT, "Scanf &expression", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 25, 50, 10, REPLACE_DLG_HEIGHT, "Replace &all", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 25, 50, 9, REPLACE_DLG_HEIGHT, "Pr&ompt on replace", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 11, REPLACE_DLG_HEIGHT, "&Backwards", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 10, REPLACE_DLG_HEIGHT, "&Regular exprssn", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 9, REPLACE_DLG_HEIGHT, "&Whole words only", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 8, REPLACE_DLG_HEIGHT, "Case &sensitive", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_input, 3, 50, 7, REPLACE_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "edit-argord"},
+ {quick_label, 2, 50, 6, REPLACE_DLG_HEIGHT, " Enter replacement argument order eg. 3,2,1,4 ", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, 0},
+ {quick_input, 3, 50, 5, REPLACE_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "edit-replace"},
+ {quick_label, 2, 50, 4, REPLACE_DLG_HEIGHT, " Enter replacement string", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {quick_input, 3, 50, 3, REPLACE_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "edit-search"},
+ {quick_label, 2, 50, 2, REPLACE_DLG_HEIGHT, " Enter search string", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {0}};
+
+ quick_widgets[2].result = &treplace_scanf;
+ quick_widgets[3].result = &treplace_all;
+ quick_widgets[4].result = &treplace_prompt;
+ quick_widgets[5].result = &treplace_backwards;
+ quick_widgets[6].result = &treplace_regexp;
+ quick_widgets[7].result = &treplace_whole;
+ quick_widgets[8].result = &treplace_case;
+ quick_widgets[9].str_result = &targ_order;
+ quick_widgets[9].text = *arg_order;
+ quick_widgets[11].str_result = &treplace_text;
+ quick_widgets[11].text = *replace_text;
+ quick_widgets[13].str_result = &tsearch_text;
+ quick_widgets[13].text = *search_text;
+ {
+ QuickDialog Quick_input =
+ {50, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "),
+ "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
+
+ Quick_input.widgets = quick_widgets;
+
+ if (quick_dialog (&Quick_input) != B_CANCEL) {
+ *arg_order = *(quick_widgets[INPUT_INDEX].str_result);
+ *replace_text = *(quick_widgets[INPUT_INDEX + 2].str_result);
+ *search_text = *(quick_widgets[INPUT_INDEX + 4].str_result);
+ replace_scanf = treplace_scanf;
+ replace_backwards = treplace_backwards;
+ replace_regexp = treplace_regexp;
+ replace_all = treplace_all;
+ replace_prompt = treplace_prompt;
+ replace_whole = treplace_whole;
+ replace_case = treplace_case;
+ return;
+ } else {
+ *arg_order = NULL;
+ *replace_text = NULL;
+ *search_text = NULL;
+ return;
+ }
+ }
+}
+
+
+void edit_search_dialog (WEdit * edit, char **search_text)
+{
+ int treplace_scanf = replace_scanf;
+ int treplace_regexp = replace_regexp;
+ int treplace_whole = replace_whole;
+ int treplace_case = replace_case;
+ int treplace_backwards = replace_backwards;
+
+ char *tsearch_text;
+ QuickWidget quick_widgets[] =
+ {
+ {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 25, 50, 6, SEARCH_DLG_HEIGHT, "Scanf &expression", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL },
+ {quick_checkbox, 25, 50, 5, SEARCH_DLG_HEIGHT, "&Backwards", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 6, SEARCH_DLG_HEIGHT, "&Regular exprssn", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 5, SEARCH_DLG_HEIGHT, "&Whole words only", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_checkbox, 4, 50, 4, SEARCH_DLG_HEIGHT, "Case &sensitive", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {quick_input, 3, 50, 3, SEARCH_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "edit-search"},
+ {quick_label, 2, 50, 2, SEARCH_DLG_HEIGHT, " Enter search string", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {0}};
+
+ quick_widgets[2].result = &treplace_scanf;
+ quick_widgets[3].result = &treplace_backwards;
+ quick_widgets[4].result = &treplace_regexp;
+ quick_widgets[5].result = &treplace_whole;
+ quick_widgets[6].result = &treplace_case;
+ quick_widgets[7].str_result = &tsearch_text;
+ quick_widgets[7].text = *search_text;
+
+ {
+ QuickDialog Quick_input =
+ {50, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "),
+ "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ };
+
+ Quick_input.widgets = quick_widgets;
+
+ if (quick_dialog (&Quick_input) != B_CANCEL) {
+ *search_text = *(quick_widgets[7].str_result);
+ replace_scanf = treplace_scanf;
+ replace_backwards = treplace_backwards;
+ replace_regexp = treplace_regexp;
+ replace_whole = treplace_whole;
+ replace_case = treplace_case;
+ return;
+ } else {
+ *search_text = NULL;
+ return;
+ }
+ }
+}
+
+
+#else
+
+#define B_ENTER 0
+#define B_SKIP_REPLACE 1
+#define B_REPLACE_ALL 2
+#define B_CANCEL 3
+
+extern CWidget *wedit;
+
+void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option)
+{
+ Window win;
+ XEvent xev;
+ CEvent cev;
+ CState s;
+ int xh, yh, h, xb, ys, yc, yb, yr;
+ CWidget *m;
+
+ CBackupState (&s);
+ CDisable ("*");
+
+ win = CDrawHeadedDialog ("replace", parent, x, y, heading);
+ CGetHintPos (&xh, &h);
+
+/* NLS hotkey ? */
+ CIdent ("replace")->position = WINDOW_ALWAYS_RAISED;
+/* An input line comes after the ':' */
+ (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E';
+
+ CGetHintPos (0, &yh);
+ (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *search_text))->hotkey = 'E';
+
+ if (replace_text) {
+ CGetHintPos (0, &yh);
+ (CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n';
+ CGetHintPos (0, &yh);
+ (CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *replace_text))->hotkey = 'n';
+ CGetHintPos (0, &yh);
+ (CDrawText ("replace.t3", win, xh, yh, _(" Enter argument order : ")))->hotkey = 'o';
+ CGetHintPos (0, &yh);
+ (CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o';
+/* Tool hint */
+ CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf format specifiers"));
+ CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf format specifiers"));
+ }
+ CGetHintPos (0, &yh);
+ ys = yh;
+/* The following are check boxes */
+ CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0);
+ CGetHintPos (0, &yh);
+ CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0);
+ yc = yh;
+ CGetHintPos (0, &yh);
+ CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1);
+ CSetToolHint ("replace.reg", _("See the regex man page for how to compose a regular expression"));
+ CSetToolHint ("replace.reg.label", _("See the regex man page for how to compose a regular expression"));
+ yb = yh;
+ CGetHintPos (0, &yh);
+ CGetHintPos (&xb, 0);
+
+ if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
+ CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0);
+/* Tool hint */
+ CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow"));
+ CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow"));
+ yb = yh;
+ }
+ if (replace_text) {
+ if (option & SEARCH_DIALOG_OPTION_BACKWARDS)
+ yr = yc;
+ else
+ yr = ys;
+ } else {
+ yr = yb;
+ }
+
+ if (replace_text) {
+ CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0);
+/* Tool hint */
+ CSetToolHint ("replace.pr", _("Ask before making each replacement"));
+ CGetHintPos (0, &yr);
+ CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0);
+ CGetHintPos (0, &yr);
+ }
+ CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1);
+/* Tool hint */
+ CSetToolHint ("replace.scanf", _("Allows entering of a C format string, see the scanf man page"));
+
+ get_hint_limits (&x, &y);
+ CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK);
+/* Tool hint */
+ CSetToolHint ("replace.ok", _("Begin search, Enter"));
+ CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS);
+/* Tool hint */
+ CSetToolHint ("replace.cancel", _("Abort this dialog, Esc"));
+ CSetSizeHintPos ("replace");
+ CMapDialog ("replace");
+
+ m = CIdent ("replace");
+ CSetWidgetSize ("replace.sinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.sinp"))->height);
+ if (replace_text) {
+ CSetWidgetSize ("replace.rinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.rinp"))->height);
+ CSetWidgetSize ("replace.ainp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.ainp"))->height);
+ }
+ CFocus (CIdent ("replace.sinp"));
+
+ for (;;) {
+ CNextEvent (&xev, &cev);
+ if (!CIdent ("replace")) {
+ *search_text = 0;
+ break;
+ }
+ if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) {
+ *search_text = 0;
+ break;
+ }
+ if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) {
+ if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) {
+ if (!(CIdent ("replace.case")->keypressed)) {
+ CIdent ("replace.case")->keypressed = 1;
+ CExpose ("replace.case");
+ }
+ }
+ }
+ if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) {
+ if (replace_text) {
+ replace_all = CIdent ("replace.all")->keypressed;
+ replace_prompt = CIdent ("replace.pr")->keypressed;
+ *replace_text = strdup (CIdent ("replace.rinp")->text);
+ *arg_order = strdup (CIdent ("replace.ainp")->text);
+ }
+ *search_text = strdup (CIdent ("replace.sinp")->text);
+ replace_whole = CIdent ("replace.ww")->keypressed;
+ replace_case = CIdent ("replace.case")->keypressed;
+ replace_scanf = CIdent ("replace.scanf")->keypressed;
+ replace_regexp = CIdent ("replace.reg")->keypressed;
+
+ if (option & SEARCH_DIALOG_OPTION_BACKWARDS) {
+ replace_backwards = CIdent ("replace.bkwd")->keypressed;
+ } else {
+ replace_backwards = 0;
+ }
+
+ break;
+ }
+ }
+ CDestroyWidget ("replace");
+ CRestoreState (&s);
+}
+
+
+
+void edit_search_dialog (WEdit * edit, char **search_text)
+{
+/* Heads the 'Search' dialog box */
+ edit_search_replace_dialog (WIN_MESSAGES, search_text, 0, 0, _(" Search "), SEARCH_DIALOG_OPTION_BACKWARDS);
+}
+
+void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order)
+{
+/* Heads the 'Replace' dialog box */
+ edit_search_replace_dialog (WIN_MESSAGES, search_text, replace_text, arg_order, _(" Replace "), SEARCH_DIALOG_OPTION_BACKWARDS);
+}
+
+int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos)
+{
+ if (replace_prompt) {
+ int q;
+ char *p, *r = 0;
+ r = p = malloc (strlen (replace_text) + NUM_REPL_ARGS * 2);
+ strcpy (p, replace_text);
+ while ((p = strchr (p, '%'))) { /* convert "%" to "%%" so no convertion is attempted */
+ memmove (p + 2, p + 1, strlen (p) + 1);
+ *(++p) = '%';
+ p++;
+ }
+ edit->force |= REDRAW_COMPLETELY;
+ q = edit_query_dialog4 (_(" Replace "),
+/* This is for the confirm replace dialog box. The replaced string comes after the ':' */
+ catstrs (_(" Replace with: "), r, 0),
+/* Buttons for the confirm replace dialog box. */
+ _("Replace"), _("Skip"), _("Replace all"), _("Cancel"));
+ if (r)
+ free (r);
+ switch (q) {
+ case 0:
+ return B_ENTER;
+ case 1:
+ return B_SKIP_REPLACE;
+ case 2:
+ return B_REPLACE_ALL;
+ case -1:
+ case 3:
+ return B_CANCEL;
+ }
+ }
+ return 0;
+}
+
+
+#endif
+
+long sargs[NUM_REPL_ARGS][256 / sizeof (long)];
+
+#define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \
+ sargs[4], sargs[5], sargs[6], sargs[7], \
+ sargs[8], sargs[9], sargs[10], sargs[11], \
+ sargs[12], sargs[13], sargs[14], sargs[15]
+
+#define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \
+ sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \
+ sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \
+ sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]]
+
+/* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */
+/* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */
+int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len)
+{
+ static regex_t r;
+ regmatch_t pmatch[1];
+ static char *old_pattern = NULL;
+ static int old_type, old_icase;
+
+ if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) {
+ if (old_pattern) {
+ regfree (&r);
+ free (old_pattern);
+ old_pattern = 0;
+ }
+ if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) {
+ *found_len = 0;
+ return -3;
+ }
+ old_pattern = strdup (pattern);
+ old_type = match_type;
+ old_icase = icase;
+ }
+ if (regexec (&r, string, 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) {
+ *found_len = 0;
+ return -1;
+ }
+ *found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
+ return (pmatch[0].rm_so);
+}
+
+/* thanks to Liviu Daia <daia@stoilow.imar.ro> for getting this
+ (and the above) routines to work properly - paul */
+
+long edit_find_string (long start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only)
+{
+ long p, q = 0;
+ long l = strlen ((char *) exp), f = 0;
+ int n = 0;
+
+ for (p = 0; p < l; p++) /* count conversions... */
+ if (exp[p] == '%')
+ if (exp[++p] != '%') /* ...except for "%%" */
+ n++;
+
+ if (replace_scanf || replace_regexp) {
+ int c;
+ unsigned char *buf;
+ unsigned char mbuf[MAX_REPL_LEN * 2 + 3];
+
+ replace_scanf = (!replace_regexp); /* can't have both */
+
+ buf = mbuf;
+
+ if (replace_scanf) {
+ unsigned char e[MAX_REPL_LEN];
+ if (n >= NUM_REPL_ARGS)
+ return -3;
+
+ if (replace_case) {
+ for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++)
+ buf[p - start] = (*get_byte) (data, p);
+ } else {
+ for (p = 0; exp[p] != 0; p++)
+ exp[p] = my_lower_case (exp[p]);
+ for (p = start; p < last_byte && p < start + MAX_REPL_LEN; p++) {
+ c = (*get_byte) (data, p);
+ buf[p - start] = my_lower_case (c);
+ }
+ }
+
+ buf[(q = p - start)] = 0;
+ strcpy ((char *) e, (char *) exp);
+ strcat ((char *) e, "%n");
+ exp = e;
+
+ while (q) {
+ *((int *) sargs[n]) = 0; /* --> here was the problem - now fixed: good */
+ if (n == sscanf ((char *) buf, (char *) exp, SCANF_ARGS)) {
+ if (*((int *) sargs[n])) {
+ *len = *((int *) sargs[n]);
+ return start;
+ }
+ }
+ if (once_only)
+ return -2;
+ if (q + start < last_byte) {
+ if (replace_case) {
+ buf[q] = (*get_byte) (data, q + start);
+ } else {
+ c = (*get_byte) (data, q + start);
+ buf[q] = my_lower_case (c);
+ }
+ q++;
+ }
+ buf[q] = 0;
+ start++;
+ buf++; /* move the window along */
+ if (buf == mbuf + MAX_REPL_LEN) { /* the window is about to go past the end of array, so... */
+ memmove (mbuf, buf, strlen ((char *) buf) + 1); /* reset it */
+ buf = mbuf;
+ }
+ q--;
+ }
+ } else { /* regexp matching */
+ long offset = 0;
+ int found_start, match_bol, move_win = 0;
+
+ while (start + offset < last_byte) {
+ match_bol = (offset == 0 || (*get_byte) (data, start + offset - 1) == '\n');
+ if (!move_win) {
+ p = start + offset;
+ q = 0;
+ }
+ for (; p < last_byte && q < MAX_REPL_LEN; p++, q++) {
+ mbuf[q] = (*get_byte) (data, p);
+ if (mbuf[q] == '\n')
+ break;
+ }
+ q++;
+ offset += q;
+ mbuf[q] = 0;
+
+ buf = mbuf;
+ while (q) {
+ found_start = string_regexp_search ((char *) exp, (char *) buf, q, match_normal, match_bol, !replace_case, len);
+
+ if (found_start <= -2) { /* regcomp/regexec error */
+ *len = 0;
+ return -3;
+ }
+ else if (found_start == -1) /* not found: try next line */
+ break;
+ else if (*len == 0) { /* null pattern: try again at next character */
+ q--;
+ buf++;
+ match_bol = 0;
+ continue;
+ }
+ else /* found */
+ return (start + offset - q + found_start);
+ }
+ if (once_only)
+ return -2;
+
+ if (buf[q - 1] != '\n') { /* incomplete line: try to recover */
+ buf = mbuf + MAX_REPL_LEN / 2;
+ q = strlen ((char *) buf);
+ memmove (mbuf, buf, q);
+ p = start + q;
+ move_win = 1;
+ }
+ else
+ move_win = 0;
+ }
+ }
+ } else {
+ *len = strlen ((char *) exp);
+ if (replace_case) {
+ for (p = start; p <= last_byte - l; p++) {
+ if ((*get_byte) (data, p) == (unsigned char)exp[0]) { /* check if first char matches */
+ for (f = 0, q = 0; q < l && f < 1; q++)
+ if ((*get_byte) (data, q + p) != (unsigned char)exp[q])
+ f = 1;
+ if (f == 0)
+ return p;
+ }
+ if (once_only)
+ return -2;
+ }
+ } else {
+ for (p = 0; exp[p] != 0; p++)
+ exp[p] = my_lower_case (exp[p]);
+
+ for (p = start; p <= last_byte - l; p++) {
+ if (my_lower_case ((*get_byte) (data, p)) == (unsigned char)exp[0]) {
+ for (f = 0, q = 0; q < l && f < 1; q++)
+ if (my_lower_case ((*get_byte) (data, q + p)) != (unsigned char)exp[q])
+ f = 1;
+ if (f == 0)
+ return p;
+ }
+ if (once_only)
+ return -2;
+ }
+ }
+ }
+ return -2;
+}
+
+
+long edit_find_forwards (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data, int once_only)
+{ /*front end to find_string to check for
+ whole words */
+ long p;
+ p = search_start;
+
+ while ((p = edit_find_string (p, exp, len, last_byte, get_byte, data, once_only)) >= 0) {
+ if (replace_whole) {
+/*If the bordering chars are not in option_whole_chars_search then word is whole */
+ if (!strcasechr (option_whole_chars_search, (*get_byte) (data, p - 1))
+ && !strcasechr (option_whole_chars_search, (*get_byte) (data, p + *len)))
+ return p;
+ if (once_only)
+ return -2;
+ } else
+ return p;
+ if (once_only)
+ break;
+ p++; /*not a whole word so continue search. */
+ }
+ return p;
+}
+
+long edit_find (long search_start, unsigned char *exp, int *len, long last_byte, int (*get_byte) (void *, long), void *data)
+{
+ long p;
+ if (replace_backwards) {
+ while (search_start >= 0) {
+ p = edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 1);
+ if (p == search_start)
+ return p;
+ search_start--;
+ }
+ } else {
+ return edit_find_forwards (search_start, exp, len, last_byte, get_byte, data, 0);
+ }
+ return -2;
+}
+
+#define is_digit(x) ((x) >= '0' && (x) <= '9')
+
+#define snprintf(v) { \
+ *p1++ = *p++; \
+ *p1++ = '%'; \
+ *p1++ = 'n'; \
+ *p1 = '\0'; \
+ sprintf(s,q1,v,&n); \
+ s += n; \
+ }
+
+/* this function uses the sprintf command to do a vprintf */
+/* it takes pointers to arguments instead of the arguments themselves */
+int sprintf_p (char *str, const char *fmt,...)
+{
+ va_list ap;
+ int n;
+ char *q, *p, *s = str;
+ char q1[32];
+ char *p1;
+
+ va_start (ap, fmt);
+ p = q = (char *) fmt;
+
+ while ((p = strchr (p, '%'))) {
+ n = (int) ((unsigned long) p - (unsigned long) q);
+ strncpy (s, q, n); /* copy stuff between format specifiers */
+ s += n;
+ *s = 0;
+ q = p;
+ p1 = q1;
+ *p1++ = *p++;
+ if (*p == '%') {
+ p++;
+ *s++ = '%';
+ q = p;
+ continue;
+ }
+ if (*p == 'n') {
+ p++;
+/* do nothing */
+ q = p;
+ continue;
+ }
+ if (*p == '#')
+ *p1++ = *p++;
+ if (*p == '0')
+ *p1++ = *p++;
+ if (*p == '-')
+ *p1++ = *p++;
+ if (*p == '+')
+ *p1++ = *p++;
+ if (*p == '*') {
+ p++;
+ strcpy (p1, itoa (*va_arg (ap, int *))); /* replace field width with a number */
+ p1 += strlen (p1);
+ } else {
+ while (is_digit (*p))
+ *p1++ = *p++;
+ }
+ if (*p == '.')
+ *p1++ = *p++;
+ if (*p == '*') {
+ p++;
+ strcpy (p1, itoa (*va_arg (ap, int *))); /* replace precision with a number */
+ p1 += strlen (p1);
+ } else {
+ while (is_digit (*p))
+ *p1++ = *p++;
+ }
+/* flags done, now get argument */
+ if (*p == 's') {
+ snprintf (va_arg (ap, char *));
+ } else if (*p == 'h') {
+ if (strchr ("diouxX", *p))
+ snprintf (*va_arg (ap, short *));
+ } else if (*p == 'l') {
+ *p1++ = *p++;
+ if (strchr ("diouxX", *p))
+ snprintf (*va_arg (ap, long *));
+ } else if (strchr ("cdiouxX", *p)) {
+ snprintf (*va_arg (ap, int *));
+ } else if (*p == 'L') {
+ *p1++ = *p++;
+ if (strchr ("EefgG", *p))
+ snprintf (*va_arg (ap, double *)); /* should be long double */
+ } else if (strchr ("EefgG", *p)) {
+ snprintf (*va_arg (ap, double *));
+ } else if (strchr ("DOU", *p)) {
+ snprintf (*va_arg (ap, long *));
+ } else if (*p == 'p') {
+ snprintf (*va_arg (ap, void **));
+ }
+ q = p;
+ }
+ va_end (ap);
+ sprintf (s, q); /* print trailing leftover */
+ return (unsigned long) s - (unsigned long) str + strlen (s);
+}
+
+static void regexp_error (WEdit *edit)
+{
+/* "Error: Syntax error in regular expression, or scanf expression contained too many %'s */
+ edit_error_dialog (_(" Error "), _(" Invalid regular expression, or scanf expression with to many conversions "));
+}
+
+/* call with edit = 0 before shutdown to close memory leaks */
+void edit_replace_cmd (WEdit * edit, int again)
+{
+ static char *old1 = NULL;
+ static char *old2 = NULL;
+ static char *old3 = NULL;
+ char *exp1 = "";
+ char *exp2 = "";
+ char *exp3 = "";
+ int replace_yes;
+ int replace_continue;
+ int i = 0;
+ long times_replaced = 0, last_search;
+ char fin_string[32];
+ int argord[NUM_REPL_ARGS];
+
+ if (!edit) {
+ if (old1) {
+ free (old1);
+ old1 = 0;
+ }
+ if (old2) {
+ free (old2);
+ old2 = 0;
+ }
+ if (old3) {
+ free (old3);
+ old3 = 0;
+ }
+ return;
+ }
+
+ last_search = edit->last_byte;
+
+ edit->force |= REDRAW_COMPLETELY;
+
+ exp1 = old1 ? old1 : exp1;
+ exp2 = old2 ? old2 : exp2;
+ exp3 = old3 ? old3 : exp3;
+
+ if (again) {
+ if (!old1 || !old2)
+ return;
+ exp1 = strdup (old1);
+ exp2 = strdup (old2);
+ exp3 = strdup (old3);
+ } else {
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+ edit_replace_dialog (edit, &exp1, &exp2, &exp3);
+ }
+
+ if (!exp1 || !*exp1) {
+ edit->force = REDRAW_COMPLETELY;
+ if (exp1) {
+ free (exp1);
+ free (exp2);
+ free (exp3);
+ }
+ return;
+ }
+ if (old1)
+ free (old1);
+ if (old2)
+ free (old2);
+ if (old3)
+ free (old3);
+ old1 = strdup (exp1);
+ old2 = strdup (exp2);
+ old3 = strdup (exp3);
+
+ {
+ char *s;
+ int ord;
+ while ((s = strchr (exp3, ' ')))
+ memmove (s, s + 1, strlen (s));
+ s = exp3;
+ for (i = 0; i < NUM_REPL_ARGS; i++) {
+ if ((unsigned long) s != 1 && s < exp3 + strlen (exp3)) {
+ if ((ord = atoi (s)))
+ argord[i] = ord - 1;
+ else
+ argord[i] = i;
+ s = strchr (s, ',') + 1;
+ } else
+ argord[i] = i;
+ }
+ }
+
+ replace_continue = replace_all;
+
+ if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
+ edit->search_start--;
+
+ if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
+ edit->search_start++;
+
+ do {
+ int len = 0;
+ long new_start;
+ new_start = edit_find (edit->search_start, (unsigned char *) exp1, &len, last_search,
+ (int (*) (void *, long)) edit_get_byte, (void *) edit);
+ if (new_start == -3) {
+ regexp_error (edit);
+ break;
+ }
+ edit->search_start = new_start;
+ /*returns negative on not found or error in pattern */
+
+ if (edit->search_start >= 0) {
+ edit->found_start = edit->search_start;
+ i = edit->found_len = len;
+
+ edit_cursor_move (edit, edit->search_start - edit->curs1);
+ edit_scroll_screen_over_cursor (edit);
+
+ replace_yes = 1;
+
+ if (replace_prompt) {
+ int l;
+ l = edit->curs_row - edit->num_widget_lines / 3;
+ if (l > 0)
+ edit_scroll_downward (edit, l);
+ if (l < 0)
+ edit_scroll_upward (edit, -l);
+
+ edit_scroll_screen_over_cursor (edit);
+ edit->force |= REDRAW_PAGE;
+ edit_render_keypress (edit);
+
+ /*so that undo stops at each query */
+ edit_push_key_press (edit);
+
+ switch (edit_replace_prompt (edit, exp2, /*and prompt 2/3 down */
+ edit->num_widget_columns / 2 - 33, edit->num_widget_lines * 2 / 3)) {
+ case B_ENTER:
+ break;
+ case B_SKIP_REPLACE:
+ replace_yes = 0;
+ break;
+ case B_REPLACE_ALL:
+ replace_prompt = 0;
+ replace_continue = 1;
+ break;
+ case B_CANCEL:
+ replace_yes = 0;
+ replace_continue = 0;
+ break;
+ }
+ }
+ if (replace_yes) { /* delete then insert new */
+ if (replace_scanf) {
+ char repl_str[MAX_REPL_LEN + 2];
+ if (sprintf_p (repl_str, exp2, PRINTF_ARGS) >= 0) {
+ times_replaced++;
+ while (i--)
+ edit_delete (edit);
+ while (repl_str[++i])
+ edit_insert (edit, repl_str[i]);
+ } else {
+ edit_error_dialog (_(" Replace "),
+/* "Invalid regexp string or scanf string" */
+ _(" Error in replacement format string. "));
+ replace_continue = 0;
+ }
+ } else {
+ times_replaced++;
+ while (i--)
+ edit_delete (edit);
+ while (exp2[++i])
+ edit_insert (edit, exp2[i]);
+ }
+ edit->found_len = i;
+ }
+/* so that we don't find the same string again */
+ if (replace_backwards) {
+ last_search = edit->search_start;
+ edit->search_start--;
+ } else {
+ edit->search_start += i;
+ last_search = edit->last_byte;
+ }
+ edit_scroll_screen_over_cursor (edit);
+ } else {
+ edit->search_start = edit->curs1; /* try and find from right here for next search */
+ edit_update_curs_col (edit);
+
+ edit->force |= REDRAW_PAGE;
+ edit_render_keypress (edit);
+ if (times_replaced) {
+ sprintf (fin_string, _(" %ld replacements made. "), times_replaced);
+ edit_message_dialog (_(" Replace "), fin_string);
+ } else
+ edit_message_dialog (_(" Replace "), _(" Search string not found. "));
+ replace_continue = 0;
+ }
+ } while (replace_continue);
+
+ free (exp1);
+ free (exp2);
+ free (exp3);
+ edit->force = REDRAW_COMPLETELY;
+ edit_scroll_screen_over_cursor (edit);
+}
+
+
+
+
+void edit_search_cmd (WEdit * edit, int again)
+{
+ static char *old = NULL;
+ char *exp = "";
+
+ if (!edit) {
+ if (old) {
+ free (old);
+ old = 0;
+ }
+ return;
+ }
+
+ exp = old ? old : exp;
+ if (again) { /*ctrl-hotkey for search again. */
+ if (!old)
+ return;
+ exp = strdup (old);
+ } else {
+ edit_search_dialog (edit, &exp);
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+ }
+
+ if (exp) {
+ if (*exp) {
+ int len = 0;
+ if (old)
+ free (old);
+ old = strdup (exp);
+
+ if (edit->found_len && edit->search_start == edit->found_start + 1 && replace_backwards)
+ edit->search_start--;
+
+ if (edit->found_len && edit->search_start == edit->found_start - 1 && !replace_backwards)
+ edit->search_start++;
+
+ edit->search_start = edit_find (edit->search_start, (unsigned char *) exp, &len, edit->last_byte,
+ (int (*)(void *, long)) edit_get_byte, (void *) edit);
+
+ if (edit->search_start >= 0) {
+ edit->found_start = edit->search_start;
+ edit->found_len = len;
+
+ edit_cursor_move (edit, edit->search_start - edit->curs1);
+ edit_scroll_screen_over_cursor (edit);
+ if (replace_backwards)
+ edit->search_start--;
+ else
+ edit->search_start++;
+ } else if (edit->search_start == -3) {
+ edit->search_start = edit->curs1;
+ regexp_error (edit);
+ } else {
+ edit->search_start = edit->curs1;
+ edit_error_dialog (_(" Search "), _(" Search string not found. "));
+ }
+ }
+ free (exp);
+ }
+ edit->force |= REDRAW_COMPLETELY;
+ edit_scroll_screen_over_cursor (edit);
+}
+
+
+/* Real edit only */
+void edit_quit_cmd (WEdit * edit)
+{
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+
+ edit->force |= REDRAW_COMPLETELY;
+ if (edit->modified) {
+#ifdef MIDNIGHT
+ switch (edit_query_dialog3 (_(" Quit "), _(" File was modified, Save with exit? "), _("Cancel quit"), _("&Yes"), _("&No"))) {
+#else
+/* Confirm 'Quit' dialog box */
+ switch (edit_query_dialog3 (_(" Quit "),
+ _(" Current text was modified without a file save. \n Save with exit? "), _(" &Cancel quit "), _(" &Yes "), _(" &No "))) {
+#endif
+ case 1:
+ edit_push_markers (edit);
+ edit_set_markers (edit, 0, 0, 0, 0);
+ if (!edit_save_cmd (edit))
+ return;
+ break;
+ case 2:
+#ifdef MIDNIGHT
+ if (edit->delete_file)
+ unlink (catstrs (edit->dir, edit->filename, 0));
+#endif
+ break;
+ case 0:
+ case -1:
+ return;
+ }
+ }
+#ifdef MIDNIGHT
+ else if (edit->delete_file)
+ unlink (catstrs (edit->dir, edit->filename, 0));
+
+ edit->widget.parent->running = 0;
+#else
+ edit->stopped = 1;
+#endif
+}
+
+#define TEMP_BUF_LEN 1024
+
+extern int column_highlighting;
+
+/* returns a null terminated length of text. Result must be free'd */
+unsigned char *edit_get_block (WEdit * edit, long start, long finish, int *l)
+{
+ unsigned char *s, *r;
+ r = s = malloc (finish - start + 1);
+ if (column_highlighting) {
+ *l = 0;
+ while (start < finish) { /* copy from buffer, excluding chars that are out of the column 'margins' */
+ int c, x;
+ x = edit_move_forward3 (edit, edit_bol (edit, start), 0, start);
+ c = edit_get_byte (edit, start);
+ if ((x >= edit->column1 && x < edit->column2)
+ || (x >= edit->column2 && x < edit->column1) || c == '\n') {
+ *s++ = c;
+ (*l)++;
+ }
+ start++;
+ }
+ } else {
+ *l = finish - start;
+ while (start < finish)
+ *s++ = edit_get_byte (edit, start++);
+ }
+ *s = 0;
+ return r;
+}
+
+/* save block, returns 1 on success */
+int edit_save_block (WEdit * edit, const char *filename, long start, long finish)
+{
+ long i = start, end, filelen = finish - start;
+ int file;
+ unsigned char *buf;
+
+ if ((file = open ((char *) filename, O_CREAT | O_WRONLY | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
+ return 0;
+
+ buf = malloc (TEMP_BUF_LEN);
+ while (start != finish) {
+ end = min (finish, start + TEMP_BUF_LEN);
+ for (; i < end; i++)
+ buf[i - start] = edit_get_byte (edit, i);
+ filelen -= write (file, (char *) buf, end - start);
+ start = end;
+ }
+ free (buf);
+ close (file);
+ if (filelen)
+ return 0;
+ return 1;
+}
+
+/* copies a block to clipboard file */
+static int edit_save_block_to_clip_file (WEdit * edit, long start, long finish)
+{
+ return edit_save_block (edit, catstrs (home_dir, CLIP_FILE, 0), start, finish);
+}
+
+#ifndef MIDNIGHT
+
+void paste_text (WEdit * edit, unsigned char *data, unsigned int nitems)
+{
+ if (data) {
+ data += nitems - 1;
+ while (nitems--)
+ edit_insert_ahead (edit, *data--);
+ }
+ edit->force |= REDRAW_COMPLETELY;
+}
+
+char *selection_get_line (void *data, int line)
+{
+ static unsigned char t[1024];
+ struct selection *s;
+ int i = 0;
+ s = (struct selection *) data;
+ line = (current_selection + line + 1) % NUM_SELECTION_HISTORY;
+ if (s[line].text) {
+ unsigned char *p = s[line].text;
+ int c, j;
+ for (j = 0; j < s[line].len; j++) {
+ c = *p++;
+ if ((c < ' ' || (c > '~' && c < 160)) && c != '\t') {
+ t[i++] = '.';
+ t[i++] = '\b';
+ t[i++] = '.';
+ } else
+ t[i++] = c;
+ if (i > 1020)
+ break;
+ }
+ }
+ t[i] = 0;
+ return (char *) t;
+}
+
+void edit_paste_from_history (WEdit * edit)
+{
+ int i, c;
+
+ edit_update_curs_col (edit);
+ edit_update_curs_row (edit);
+
+ c = max (20, edit->num_widget_columns - 5);
+
+ i = CListboxDialog (WIN_MESSAGES, c, 10,
+ 0, NUM_SELECTION_HISTORY - 10, NUM_SELECTION_HISTORY - 1, NUM_SELECTION_HISTORY,
+ selection_get_line, (void *) selection_history);
+
+ if (i < 0)
+ return;
+
+ i = (current_selection + i + 1) % NUM_SELECTION_HISTORY;
+
+ paste_text (edit, selection_history[i].text, selection_history[i].len);
+ edit->force |= REDRAW_COMPLETELY;
+}
+
+/* copies a block to the XWindows buffer */
+static int edit_XStore_block (WEdit * edit, long start, long finish)
+{
+ edit_get_selection (edit);
+ if (selection.len <= 512 * 1024) { /* we don't want to fill up the server */
+ XStoreBytes (CDisplay, (char *) selection.text, (int) selection.len);
+ return 0;
+ } else
+ return 1;
+}
+
+int edit_copy_to_X_buf_cmd (WEdit * edit)
+{
+ long start_mark, end_mark;
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return 0;
+ edit_XStore_block (edit, start_mark, end_mark);
+ if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
+ edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
+ return 1;
+ }
+ XSetSelectionOwner (CDisplay, XA_PRIMARY, edit->widget->winid, CurrentTime);
+ edit_mark_cmd (edit, 1);
+ return 0;
+}
+
+int edit_cut_to_X_buf_cmd (WEdit * edit)
+{
+ long start_mark, end_mark;
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return 0;
+ edit_XStore_block (edit, start_mark, end_mark);
+ if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
+ edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
+ return 1;
+ }
+ edit_block_delete_cmd (edit);
+ XSetSelectionOwner (CDisplay, XA_PRIMARY, edit->widget->winid, CurrentTime);
+ edit_mark_cmd (edit, 1);
+ return 0;
+}
+
+void selection_paste (WEdit * edit, Window win, unsigned prop, int delete);
+
+void edit_paste_from_X_buf_cmd (WEdit * edit)
+{
+ if (selection.text)
+ paste_text (edit, selection.text, selection.len);
+ else if (!XGetSelectionOwner (CDisplay, XA_PRIMARY))
+ selection_paste (edit, CRoot, XA_CUT_BUFFER0, False);
+ else
+ XConvertSelection (CDisplay, XA_PRIMARY, XA_STRING,
+ XInternAtom (CDisplay, "VT_SELECTION", False),
+ edit->widget->winid, CurrentTime);
+ edit->force |= REDRAW_PAGE;
+}
+
+#else /* MIDNIGHT */
+
+void edit_paste_from_history (WEdit *edit)
+{
+}
+
+int edit_copy_to_X_buf_cmd (WEdit * edit)
+{
+ long start_mark, end_mark;
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return 0;
+ if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
+ edit_error_dialog (_(" Copy to clipboard "), get_sys_error (_(" Unable to save to file. ")));
+ return 1;
+ }
+ edit_mark_cmd (edit, 1);
+ return 0;
+}
+
+int edit_cut_to_X_buf_cmd (WEdit * edit)
+{
+ long start_mark, end_mark;
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return 0;
+ if (!edit_save_block_to_clip_file (edit, start_mark, end_mark)) {
+ edit_error_dialog (_(" Cut to clipboard "), _(" Unable to save to file. "));
+ return 1;
+ }
+ edit_block_delete_cmd (edit);
+ edit_mark_cmd (edit, 1);
+ return 0;
+}
+
+void edit_paste_from_X_buf_cmd (WEdit * edit)
+{
+ edit_insert_file (edit, catstrs (home_dir, CLIP_FILE, 0));
+}
+
+#endif /* MIDMIGHT */
+
+void edit_goto_cmd (WEdit *edit)
+{
+ char *f;
+ static int l = 0;
+#ifdef MIDNIGHT
+ char s[12];
+ sprintf (s, "%d", l);
+ f = input_dialog (_(" Goto line "), _(" Enter line: "), l ? s : "");
+#else
+ f = CInputDialog ("goto", WIN_MESSAGES, 150, l ? itoa (l) : "", _(" Goto line "), _(" Enter line: "));
+#endif
+ if (f) {
+ if (*f) {
+ l = atoi (f);
+ edit_move_display (edit, l - edit->num_widget_lines / 2 - 1);
+ edit_move_to_line (edit, l - 1);
+ edit->force |= REDRAW_COMPLETELY;
+ free (f);
+ }
+ }
+}
+
+/*returns 1 on success */
+int edit_save_block_cmd (WEdit * edit) {
+ long start_mark, end_mark;
+ char *exp;
+ if (eval_marks (edit, &start_mark, &end_mark))
+ return 1;
+
+ exp = edit_get_save_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _(" Save Block "));
+
+ edit->force |= REDRAW_COMPLETELY;
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+
+ if (exp) {
+ if (!*exp) {
+ free (exp);
+ return 0;
+ } else {
+ if (edit_save_block (edit, exp, start_mark, end_mark)) {
+ free (exp);
+ edit->force |= REDRAW_COMPLETELY;
+ return 1;
+ } else {
+ free (exp);
+ edit->force |= REDRAW_COMPLETELY;
+ edit_error_dialog (_(" Save Block "), get_sys_error (_(" Error trying to save file. ")));
+ return 0;
+ }
+ }
+ } else
+ return 0;
+}
+
+
+/* inserts a file at the cursor, returns 1 on success */
+int edit_insert_file (WEdit * edit, const char *filename)
+{
+ int i, file, blocklen;
+ long current = edit->curs1;
+ unsigned char *buf;
+
+ if ((file = open ((char *) filename, O_RDONLY)) == -1)
+ return 0;
+ buf = malloc (TEMP_BUF_LEN);
+ while ((blocklen = read (file, (char *) buf, TEMP_BUF_LEN)) > 0) {
+ for (i = 0; i < blocklen; i++)
+ edit_insert (edit, buf[i]);
+ }
+ edit_cursor_move (edit, current - edit->curs1);
+ free (buf);
+ close (file);
+ if (blocklen)
+ return 0;
+ return 1;
+}
+
+
+/* returns 1 on success */
+int edit_insert_file_cmd (WEdit * edit) {
+ char *exp = edit_get_load_file (edit->dir, catstrs (home_dir, CLIP_FILE, 0), _(" Insert File "));
+ edit->force |= REDRAW_COMPLETELY;
+
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+
+ if (exp) {
+ if (!*exp) {
+ free (exp);
+ return 0;
+ } else {
+ if (edit_insert_file (edit, exp)) {
+ free (exp);
+ return 1;
+ } else {
+ free (exp);
+ edit_error_dialog (_(" Insert file "), get_sys_error (_(" Error trying to insert file. ")));
+ return 0;
+ }
+ }
+ } else
+ return 0;
+}
+
+#ifdef MIDNIGHT
+
+/* sorts a block, returns -1 on system fail, 1 on cancel and 0 on success */
+int edit_sort_cmd (WEdit * edit)
+{
+ static char *old = 0;
+ char *exp;
+ long start_mark, end_mark;
+ int e;
+
+ if (eval_marks (edit, &start_mark, &end_mark)) {
+/* Not essential to translate */
+ edit_error_dialog (_(" Sort block "), _(" You must first highlight a block of text. "));
+ return 0;
+ }
+ edit_save_block (edit, catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
+
+ exp = old ? old : "";
+
+ exp = input_dialog (_(" Run Sort "),
+/* Not essential to translate */
+ _(" Enter sort options (see manpage) separated by whitespace: "), "");
+
+ if (!exp)
+ return 1;
+ if (old)
+ free (old);
+ old = exp;
+
+ e = system (catstrs (" sort ", exp, " ", home_dir, BLOCK_FILE, " > ", home_dir, TEMP_FILE, 0));
+ if (e) {
+ if (e == -1 || e == 127) {
+ edit_error_dialog (_(" Sort "),
+/* Not essential to translate */
+ get_sys_error (_(" Error trying to execute sort command ")));
+ } else {
+ char q[8];
+ sprintf (q, "%d ", e);
+ edit_error_dialog (_(" Sort "),
+/* Not essential to translate */
+ catstrs (_(" Sort returned non-zero: "), q, 0));
+ }
+ return -1;
+ }
+
+ edit->force |= REDRAW_COMPLETELY;
+
+ if (edit_block_delete_cmd (edit))
+ return 1;
+ edit_insert_file (edit, catstrs (home_dir, TEMP_FILE, 0));
+ return 0;
+}
+
+/* if block is 1, a block must be highlighted and the shell command
+ processes it. If block is 0 the shell command is a straight system
+ command, that just produces some output which is to be inserted */
+void edit_block_process_cmd (WEdit * edit, const char *shell_cmd, int block)
+{
+ long start_mark, end_mark;
+ struct stat s;
+ char *f = NULL, *b = NULL;
+
+ if (block) {
+ if (eval_marks (edit, &start_mark, &end_mark)) {
+ edit_error_dialog (_(" Process block "),
+/* Not essential to translate */
+ _(" You must first highlight a block of text. "));
+ return;
+ }
+ edit_save_block (edit, b = catstrs (home_dir, BLOCK_FILE, 0), start_mark, end_mark);
+ my_system (0, shell, catstrs (home_dir, shell_cmd, 0));
+ edit_refresh_cmd (edit);
+ } else {
+ my_system (0, shell, shell_cmd);
+ edit_refresh_cmd (edit);
+ }
+
+ edit->force |= REDRAW_COMPLETELY;
+
+ f = catstrs (home_dir, ERROR_FILE, 0);
+
+ if (block) {
+ if (stat (f, &s) == 0) {
+ if (!s.st_size) { /* no error messages */
+ if (edit_block_delete_cmd (edit))
+ return;
+ edit_insert_file (edit, b);
+ return;
+ } else {
+ edit_insert_file (edit, f);
+ return;
+ }
+ } else {
+/* Not essential to translate */
+ edit_error_dialog (_(" Process block "),
+/* Not essential to translate */
+ get_sys_error (_(" Error trying to stat file ")));
+ return;
+ }
+ }
+}
+
+#endif
+
+int edit_execute_cmd (WEdit * edit, int command, int char_for_insertion);
+
+/* prints at the cursor */
+/* returns the number of chars printed */
+int edit_print_string (WEdit * e, const char *s)
+{
+ int i = 0;
+ while (s[i])
+ edit_execute_cmd (e, -1, s[i++]);
+ e->force |= REDRAW_COMPLETELY;
+ edit_update_screen (e);
+ return i;
+}
+
+int edit_printf (WEdit * e, const char *fmt,...)
+{
+ int i;
+ va_list pa;
+ char s[1024];
+ va_start (pa, fmt);
+ sprintf (s, fmt, pa);
+ i = edit_print_string (e, s);
+ va_end (pa);
+ return i;
+}
+
+#ifdef MIDNIGHT
+
+/* FIXME: does this function break NT_OS2 ? */
+
+static void pipe_mail (WEdit *edit, char *to, char *subject, char *cc)
+{
+ FILE *p;
+ char *s;
+ s = malloc (4096);
+ sprintf (s, "mail -s \"%s\" -c \"%s\" \"%s\"", subject, cc, to);
+ p = popen (s, "w");
+ if (!p) {
+ free (s);
+ return;
+ } else {
+ long i;
+ for (i = 0; i < edit->last_byte; i++)
+ fputc (edit_get_byte (edit, i), p);
+ pclose (p);
+ }
+ free (s);
+}
+
+#define MAIL_DLG_HEIGHT 12
+
+void edit_mail_dialog (WEdit * edit)
+{
+ char *tmail_to;
+ char *tmail_subject;
+ char *tmail_cc;
+
+ static char *mail_cc_last = 0;
+ static char *mail_subject_last = 0;
+ static char *mail_to_last = 0;
+
+ QuickDialog Quick_input =
+ {50, MAIL_DLG_HEIGHT, -1, 0, N_(" Mail "),
+/* NLS ? */
+ "[Input Line Keys]", "quick_input", 0};
+
+ QuickWidget quick_widgets[] =
+ {
+/* NLS ? */
+ {quick_button, 6, 10, 9, MAIL_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_button, 2, 10, 9, MAIL_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+ {quick_input, 3, 50, 8, MAIL_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input"},
+ {quick_label, 2, 50, 7, MAIL_DLG_HEIGHT, " Copies to", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {quick_input, 3, 50, 6, MAIL_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input-2"},
+ {quick_label, 2, 50, 5, MAIL_DLG_HEIGHT, " Subject", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {quick_input, 3, 50, 4, MAIL_DLG_HEIGHT, "", 44, 0, 0,
+ 0, XV_WLAY_BELOWCLOSE, "mail-dlg-input-3"},
+ {quick_label, 2, 50, 3, MAIL_DLG_HEIGHT, " To", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {quick_label, 2, 50, 2, MAIL_DLG_HEIGHT, " mail -s <subject> -c <cc> <to>", 0, 0, 0,
+ 0, XV_WLAY_DONTCARE, 0},
+ {0}};
+
+ quick_widgets[2].str_result = &tmail_cc;
+ quick_widgets[2].text = mail_cc_last ? mail_cc_last : "";
+ quick_widgets[4].str_result = &tmail_subject;
+ quick_widgets[4].text = mail_subject_last ? mail_subject_last : "";
+ quick_widgets[6].str_result = &tmail_to;
+ quick_widgets[6].text = mail_to_last ? mail_to_last : "";
+
+ Quick_input.widgets = quick_widgets;
+
+ if (quick_dialog (&Quick_input) != B_CANCEL) {
+ if (mail_cc_last)
+ free (mail_cc_last);
+ if (mail_subject_last)
+ free (mail_subject_last);
+ if (mail_to_last)
+ free (mail_to_last);
+ mail_cc_last = *(quick_widgets[2].str_result);
+ mail_subject_last = *(quick_widgets[4].str_result);
+ mail_to_last = *(quick_widgets[6].str_result);
+ pipe_mail (edit, mail_to_last, mail_subject_last, mail_cc_last);
+ }
+}
+
+#endif
+
--- /dev/null
+#ifndef __EDIT_CMD_DEF_H
+#define __EDIT_CMD_DEF_H
+
+/* in the distant future, keyboards will be invented with a
+ seperate key for each one of these commands *sigh* */
+
+/* cursor movements */
+#define CK_No_Command -1
+#define CK_BackSpace 1
+#define CK_Delete 2
+#define CK_Enter 3
+#define CK_Page_Up 4
+#define CK_Page_Down 5
+#define CK_Left 6
+#define CK_Right 7
+#define CK_Word_Left 8
+#define CK_Word_Right 9
+#define CK_Up 10
+#define CK_Down 11
+#define CK_Home 12
+#define CK_End 13
+#define CK_Tab 14
+#define CK_Undo 15
+#define CK_Beginning_Of_Text 16
+#define CK_End_Of_Text 17
+#define CK_Scroll_Up 18
+#define CK_Scroll_Down 19
+#define CK_Return 20
+#define CK_Begin_Page 21
+#define CK_End_Page 22
+#define CK_Delete_Word_Left 23
+#define CK_Delete_Word_Right 24
+#define CK_Paragraph_Up 25
+#define CK_Paragraph_Down 26
+
+
+/* file commands */
+#define CK_Save 101
+#define CK_Load 102
+#define CK_New 103
+#define CK_Save_As 104
+
+/* block commands */
+#define CK_Mark 201
+#define CK_Copy 202
+#define CK_Move 203
+#define CK_Remove 204
+#define CK_Unmark 206
+#define CK_Save_Block 207
+
+/* search and replace */
+#define CK_Find 301
+#define CK_Find_Again 302
+#define CK_Replace 303
+#define CK_Replace_Again 304
+
+/* misc */
+#define CK_Insert_File 401
+#define CK_Exit 402
+#define CK_Toggle_Insert 403
+#define CK_Help 404
+#define CK_Date 405
+#define CK_Refresh 406
+#define CK_Goto 407
+#define CK_Delete_Line 408
+#define CK_Delete_To_Line_End 409
+#define CK_Delete_To_Line_Begin 410
+#define CK_Man_Page 411
+#define CK_Sort 412
+#define CK_Mail 413
+#define CK_Cancel 414
+#define CK_Complete 415
+#define CK_Paragraph_Format 416
+
+/* application control */
+#define CK_Save_Desktop 451
+#define CK_New_Window 452
+#define CK_Cycle 453
+#define CK_Menu 454
+#define CK_Save_And_Quit 455
+#define CK_Run_Another 456
+#define CK_Check_Save_And_Quit 457
+
+/* macro */
+#define CK_Begin_Record_Macro 501
+#define CK_End_Record_Macro 502
+#define CK_Delete_Macro 503
+
+/* highlight commands */
+#define CK_Page_Up_Highlight 604
+#define CK_Page_Down_Highlight 605
+#define CK_Left_Highlight 606
+#define CK_Right_Highlight 607
+#define CK_Word_Left_Highlight 608
+#define CK_Word_Right_Highlight 609
+#define CK_Up_Highlight 610
+#define CK_Down_Highlight 611
+#define CK_Home_Highlight 612
+#define CK_End_Highlight 613
+#define CK_Beginning_Of_Text_Highlight 614
+#define CK_End_Of_Text_Highlight 615
+#define CK_Begin_Page_Highlight 616
+#define CK_End_Page_Highlight 617
+#define CK_Scroll_Up_Highlight 618
+#define CK_Scroll_Down_Highlight 619
+#define CK_Paragraph_Up_Highlight 620
+#define CK_Paragraph_Down_Highlight 621
+
+/* X clipboard operations */
+
+#define CK_XStore 701
+#define CK_XCut 702
+#define CK_XPaste 703
+#define CK_Selection_History 704
+
+#ifdef MIDNIGHT /* cooledit now has its own full-featured script editor and executor */
+/*
+ Process a block through a shell command: CK_Pipe_Block(i) executes shell_cmd[i].
+ shell_cmd[i] must process the file ~/cooledit.block and output ~/cooledit.block
+ which is then inserted into the text in place of the original block. shell_cmd[i] must
+ also produce a file homedir/cooledit.error . If this file is not empty an error will
+ have been assumed to have occured, and the block will not be replaced.
+ TODO: bring up a viewer to display the error message instead of inserting
+ it into the text, which is annoying.
+ */
+#define CK_Pipe_Block(i) (1000+(i))
+#define SHELL_COMMANDS_i {"/.cedit/edit.indent.rc", "/.cedit/edit.spell.rc", /* and so on */ 0};
+#else
+#define CK_User_Command(i) (1000+(i))
+#endif
+
+/* execute a macro */
+#define CK_Macro(i) (2000+(i))
+#define CK_Last_Macro CK_Macro(0x7FFF)
+
+
+#endif
+
--- /dev/null
+/* editor text drawing.
+
+ Copyright (C) 1996, 1997 the Free Software Foundation
+
+ Authors: 1996, 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "edit.h"
+
+#define MAX_LINE_LEN 1024
+
+#ifndef MIDNIGHT
+#include "app_glob.c"
+#include "coollocal.h"
+#else
+#include "../src/mad.h"
+#endif
+
+
+static void status_string (WEdit * edit, char *s, int w, int fill, int font_width)
+{
+ int i;
+ char t[160]; /* 160 just to be sure */
+/* The field lengths just prevents the status line from shortening to much */
+ sprintf (t, "[%c%c%c%c] %2ld:%3ld+%2ld=%3ld/%3ld - *%-4ld/%4ldb=%3d",
+ edit->mark1 != edit->mark2 ? 'B' : '-',
+ edit->modified ? 'M' : '-', edit->macro_i < 0 ? '-' : 'R',
+ edit->overwrite == 0 ? '-' : 'O',
+ edit->curs_col / font_width, edit->start_line + 1, edit->curs_row,
+ edit->curs_line + 1, edit->total_lines + 1, edit->curs1,
+ edit->last_byte, edit->curs1 < edit->last_byte
+ ? edit_get_byte (edit, edit->curs1) : -1);
+ sprintf (s, "%.*s", w + 1, t);
+ i = strlen (s);
+ s[i] = ' ';
+ i = w;
+ do {
+ if (strchr (" +-*=/:b", s[i])) /* chop off the last word/number */
+ break;
+ s[i] = fill;
+ } while (i--);
+ s[i] = fill;
+ s[w] = 0;
+}
+
+
+#ifdef MIDNIGHT
+
+/* how to get as much onto the status line as is numerically possible :) */
+void edit_status (WEdit * edit)
+{
+ int w, i, t;
+ char *s;
+ w = edit->widget.cols - (edit->have_frame * 2);
+ s = malloc (w + 15);
+ if (w < 4)
+ w = 4;
+ memset (s, ' ', w);
+ attrset (SELECTED_COLOR);
+ if (w > 4) {
+ widget_move (edit, edit->have_frame, edit->have_frame);
+ i = w > 24 ? 18 : w - 6;
+ i = i < 13 ? 13 : i;
+ sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i));
+ i += strlen (s);
+ s[strlen (s)] = ' ';
+ t = w - 20;
+ if (t < 0)
+ t = 0;
+ status_string (edit, s + 20, t, ' ', 1);
+ } else {
+ s[w] = 0;
+ }
+ printw ("%.*s", w, s);
+
+ attrset (NORMAL_COLOR);
+ free (s);
+}
+
+#else
+
+extern int fixed_font;
+
+void rerender_text (CWidget * wdt);
+
+void edit_status (WEdit * edit)
+{
+ if ((edit->widget->options & EDITOR_NO_TEXT)) {
+ return;
+ } else {
+ int w, i, t;
+ CWidget *wdt;
+ char id[33];
+ char s[160];
+ w = edit->num_widget_columns - 1;
+ if (w > 150)
+ w = 150;
+ if (w < 0)
+ w = 0;
+ memset (s, 0, w);
+ if (w > 1) {
+ i = w > 24 ? 18 : w - 6;
+ i = i < 13 ? 13 : i;
+ sprintf (s, "%s", name_trunc (edit->filename ? edit->filename : "", i));
+ i = strlen (s);
+ s[i] = ' ';
+ s[i+1] = ' ';
+ t = w - i - 2;
+ if (t < 0)
+ t = 0;
+ status_string (edit, s + i + 2, t, 0, FONT_MEAN_WIDTH);
+ }
+ s[w] = 0;
+ strcpy (id, edit->widget->ident);
+ strcat (id, ".text");
+ wdt = CIdent (id);
+ free (wdt->text);
+ wdt->text = strdup (s);
+ CSetWidgetSize (id, edit->widget->width, wdt->height);
+ rerender_text (wdt);
+ }
+}
+
+
+#endif
+
+
+/* boolean */
+int cursor_in_screen (WEdit * edit, long row)
+{
+ if (row < 0 || row >= edit->num_widget_lines)
+ return 0;
+ else
+ return 1;
+}
+
+/* returns rows from the first displayed line to the cursor */
+int cursor_from_display_top (WEdit * edit)
+{
+ if (edit->curs1 < edit->start_display)
+ return -edit_move_forward (edit, edit->curs1, 0, edit->start_display);
+ else
+ return edit_move_forward (edit, edit->start_display, 0, edit->curs1);
+}
+
+/* returns how far the cursor is out of the screen */
+int cursor_out_of_screen (WEdit * edit)
+{
+ int row = cursor_from_display_top (edit);
+ if (row >= edit->num_widget_lines)
+ return row - edit->num_widget_lines + 1;
+ if (row < 0)
+ return row;
+ return 0;
+}
+
+#ifndef MIDNIGHT
+extern unsigned char per_char[256];
+int edit_width_of_long_printable (int c);
+#endif
+
+/* this scrolls the text so that cursor is on the screen */
+void edit_scroll_screen_over_cursor (WEdit * edit)
+{
+ int p, l;
+ int outby;
+ p = edit_get_col (edit);
+ edit_update_curs_row (edit);
+#ifdef MIDNIGHT
+ outby = p + edit->start_col - edit->num_widget_columns + 1 + (EDIT_RIGHT_EXTREME + edit->found_len);
+#else
+ outby = p + edit->start_col - edit->widget->width + 7 + (EDIT_RIGHT_EXTREME + edit->found_len) * FONT_MEAN_WIDTH + edit_width_of_long_printable (edit_get_byte (edit, edit->curs1));
+#endif
+ if (outby > 0)
+ edit_scroll_right (edit, outby);
+#ifdef MIDNIGHT
+ outby = EDIT_LEFT_EXTREME - p - edit->start_col;
+#else
+ outby = EDIT_LEFT_EXTREME * FONT_MEAN_WIDTH - p - edit->start_col;
+#endif
+ if (outby > 0)
+ edit_scroll_left (edit, outby);
+ p = edit->curs_row;
+ l = 0;
+ if (edit->found_len != 0)
+ l = edit->num_widget_lines / 5;
+ outby = p - edit->num_widget_lines + 1 + EDIT_BOTTOM_EXTREME + l;
+ if (outby > 0)
+ edit_scroll_downward (edit, outby);
+ outby = EDIT_TOP_EXTREME - p + l;
+ if (outby > 0)
+ edit_scroll_upward (edit, outby);
+ edit_update_curs_row (edit);
+}
+
+
+#ifndef MIDNIGHT
+
+#define CACHE_WIDTH 256
+#define CACHE_HEIGHT 128
+
+int EditExposeRedraw = 0;
+int EditClear = 0;
+
+/* background colors: marked is refers to mouse highlighting, highlighted refers to a found string. */
+unsigned long edit_abnormal_color, edit_marked_abnormal_color;
+unsigned long edit_highlighted_color, edit_marked_color;
+unsigned long edit_normal_background_color;
+
+/* foreground colors */
+unsigned long edit_normal_foreground_color, edit_bold_color;
+unsigned long edit_italic_color;
+
+/* cursor color */
+unsigned long edit_cursor_color;
+
+void edit_set_foreground_colors (unsigned long normal, unsigned long bold, unsigned long italic)
+{
+ edit_normal_foreground_color = normal;
+ edit_bold_color = bold;
+ edit_italic_color = italic;
+}
+
+void edit_set_background_colors (unsigned long normal, unsigned long abnormal, unsigned long marked, unsigned long marked_abnormal, unsigned long highlighted)
+{
+ edit_abnormal_color = abnormal;
+ edit_marked_abnormal_color = marked_abnormal;
+ edit_marked_color = marked;
+ edit_highlighted_color = highlighted;
+ edit_normal_background_color = normal;
+}
+
+void edit_set_cursor_color (unsigned long c)
+{
+ edit_cursor_color = c;
+}
+
+#else
+
+#define BOLD_COLOR MARKED_COLOR
+#define UNDERLINE_COLOR VIEW_UNDERLINED_COLOR
+#define MARK_COLOR SELECTED_COLOR
+#define DEF_COLOR NORMAL_COLOR
+
+static void set_color (int font)
+{
+ attrset (font);
+}
+
+#define edit_move(x,y) widget_move(edit, y, x);
+
+static void print_to_widget (WEdit * edit, long row, int start_col, float start_col_real, long end_col, unsigned int line[])
+{
+ int x = (float) start_col_real + EDIT_TEXT_HORIZONTAL_OFFSET;
+ int x1 = start_col + EDIT_TEXT_HORIZONTAL_OFFSET;
+ int y = row + EDIT_TEXT_VERTICAL_OFFSET;
+
+ set_color (DEF_COLOR);
+ edit_move (x1, y);
+ hline (' ', end_col + 1 - EDIT_TEXT_HORIZONTAL_OFFSET - x1);
+
+ edit_move (x + FONT_OFFSET_X, y + FONT_OFFSET_Y);
+ {
+ unsigned int *p = line;
+ int textchar = ' ';
+ long style;
+
+ while (*p) {
+ style = *p >> 8;
+ textchar = *p & 0xFF;
+#ifdef HAVE_SYNTAXH
+ if (!(style & (0xFF - MOD_ABNORMAL - MOD_CURSOR)))
+ SLsmg_set_color ((*p & 0x007F0000) >> 16);
+#endif
+ if (style & MOD_ABNORMAL)
+ textchar = '.';
+ if (style & MOD_HIGHLIGHTED) {
+ set_color (BOLD_COLOR);
+ } else if (style & MOD_MARKED) {
+ set_color (MARK_COLOR);
+ }
+ if (style & MOD_UNDERLINED) {
+ set_color (UNDERLINE_COLOR);
+ }
+ if (style & MOD_BOLD) {
+ set_color (BOLD_COLOR);
+ }
+ addch (textchar);
+ p++;
+ }
+ }
+}
+
+/* b pointer to begining of line */
+static void edit_draw_this_line (WEdit * edit, long b, long row, long start_col, long end_col)
+{
+ static unsigned int line[MAX_LINE_LEN];
+ unsigned int *p = line;
+ long m1 = 0, m2 = 0, q;
+ int col, start_col_real;
+ unsigned int c;
+ int fg, bg;
+ int i;
+
+ edit_get_syntax_color (edit, b - 1, &fg, &bg);
+ q = edit_move_forward3 (edit, b, start_col - edit->start_col, 0);
+ start_col_real = (col = (int) edit_move_forward3 (edit, b, 0, q)) + edit->start_col;
+
+ if (col + 16 > -edit->start_col) {
+ eval_marks (edit, &m1, &m2);
+
+ if (row <= edit->total_lines - edit->start_line) {
+ while (col <= end_col - edit->start_col) {
+ *p = 0;
+ if (q == edit->curs1)
+ *p |= MOD_CURSOR * 256;
+ if (q >= m1 && q < m2)
+ *p |= MOD_MARKED * 256;
+ if (q == edit->bracket)
+ *p |= MOD_BOLD * 256;
+ if (q >= edit->found_start && q < edit->found_start + edit->found_len)
+ *p |= MOD_HIGHLIGHTED * 256;
+ c = edit_get_byte (edit, q);
+ edit_get_syntax_color (edit, q, &fg, &bg);
+/* we don't use bg for mc - fg contains both */
+ *p |= fg << 16;
+ q++;
+ switch (c) {
+ case '\n':
+ col = end_col - edit->start_col + 1; /* quit */
+ *(p++) |= ' ';
+ break;
+ case '\t':
+ i = TAB_SIZE - ((int) col % TAB_SIZE);
+ *p |= ' ';
+ c = *(p++) & (0xFFFFFFFF - MOD_CURSOR * 256);
+ col += i;
+ while (--i)
+ *(p++) = c;
+ break;
+ case '\r':
+ break;
+ default:
+ if (is_printable (c)) {
+ *(p++) |= c;
+ } else {
+ *(p++) = '.';
+ *p |= (256 * MOD_ABNORMAL);
+ }
+ col++;
+ break;
+ }
+ }
+ }
+ } else {
+ start_col_real = start_col = 0;
+ }
+ *p = 0;
+
+ print_to_widget (edit, row, start_col, start_col_real, end_col, line);
+}
+
+#endif
+
+#ifdef MIDNIGHT
+
+#define key_pending(x) (!is_idle())
+
+#else
+
+int edit_mouse_pending (Window win);
+#define edit_draw_this_line edit_draw_this_line_proportional
+
+static int key_pending (WEdit * edit)
+{
+ if (!(edit->force & REDRAW_COMPLETELY) && !EditExposeRedraw)
+ return CKeyPending ();
+ return 0;
+}
+
+#endif
+
+
+/* b for pointer to begining of line */
+static void edit_draw_this_char (WEdit * edit, long curs, long row)
+{
+ int b = edit_bol (edit, curs);
+#ifdef MIDNIGHT
+ edit_draw_this_line (edit, b, row, 0, edit->num_widget_columns - 1);
+#else
+ edit_draw_this_line (edit, b, row, 0, edit->widget->width);
+#endif
+}
+
+/* cursor must be in screen for other than REDRAW_PAGE passed in force */
+void render_edit_text (WEdit * edit, long start_row, long start_column, long end_row, long end_column)
+{
+ long row = 0, curs_row;
+ static int prev_curs_row = 0;
+ static long prev_start_display = 0;
+ static int prev_start_col = 0;
+ static long prev_curs = 0;
+
+#ifndef MIDNIGHT
+ static Window prev_win = 0;
+#endif
+ int fg, bg;
+
+ int force = edit->force;
+ long b;
+
+/*
+ if the position of the page has not moved then we can draw the cursor character only.
+ This will prevent line flicker when using arrow keys.
+ */
+ if ((!(force & REDRAW_CHAR_ONLY)) || (force & REDRAW_PAGE)
+#ifndef MIDNIGHT
+ || prev_win != edit->widget->winid
+#endif
+ ) {
+ if (!(force & REDRAW_IN_BOUNDS)) { /* !REDRAW_IN_BOUNDS means to ignore bounds and redraw whole rows */
+ start_row = 0;
+ end_row = edit->num_widget_lines - 1;
+ start_column = 0;
+#ifdef MIDNIGHT
+ end_column = edit->num_widget_columns - 1;
+#else
+ end_column = edit->widget->width;
+#endif
+ }
+ if (force & REDRAW_PAGE) {
+ row = start_row;
+ b = edit_move_forward (edit, edit->start_display, start_row, 0);
+ while (row <= end_row) {
+ if (key_pending (edit))
+ goto exit_render;
+ edit_draw_this_line (edit, b, row, start_column, end_column);
+ b = edit_move_forward (edit, b, 1, 0);
+ row++;
+ }
+ } else {
+ curs_row = edit->curs_row;
+
+ if (force & REDRAW_BEFORE_CURSOR) {
+ if (start_row < curs_row) {
+ long upto = curs_row - 1 <= end_row ? curs_row - 1 : end_row;
+ row = start_row;
+ b = edit->start_display;
+ while (row <= upto) {
+ if (key_pending (edit))
+ goto exit_render;
+ edit_draw_this_line (edit, b, row, start_column, end_column);
+ b = edit_move_forward (edit, b, 1, 0);
+ }
+ }
+ }
+/* if (force & REDRAW_LINE) { ---> default */
+ b = edit_bol (edit, edit->curs1);
+ if (curs_row >= start_row && curs_row <= end_row) {
+ if (key_pending (edit))
+ goto exit_render;
+ edit_draw_this_line (edit, b, curs_row, start_column, end_column);
+ }
+ if (force & REDRAW_AFTER_CURSOR) {
+ if (end_row > curs_row) {
+ row = curs_row + 1 < start_row ? start_row : curs_row + 1;
+ b = edit_move_forward (edit, b, 1, 0);
+ while (row <= end_row) {
+ if (key_pending (edit))
+ goto exit_render;
+ edit_draw_this_line (edit, b, row, start_column, end_column);
+ b = edit_move_forward (edit, b, 1, 0);
+ row++;
+ }
+ }
+ }
+ if (force & REDRAW_LINE_ABOVE && curs_row >= 1) {
+ row = curs_row - 1;
+ b = edit_move_backward (edit, edit_bol (edit, edit->curs1), 1);
+ if (row >= start_row && row <= end_row) {
+ if (key_pending (edit))
+ goto exit_render;
+ edit_draw_this_line (edit, b, row, start_column, end_column);
+ }
+ }
+ if (force & REDRAW_LINE_BELOW && row < edit->num_widget_lines - 1) {
+ row = curs_row + 1;
+ b = edit_bol (edit, edit->curs1);
+ b = edit_move_forward (edit, b, 1, 0);
+ if (row >= start_row && row <= end_row) {
+ if (key_pending (edit))
+ goto exit_render;
+ edit_draw_this_line (edit, b, row, start_column, end_column);
+ }
+ }
+ }
+ } else {
+ if (prev_curs_row < edit->curs_row) { /* with the new text highlighting, we must draw from the top down */
+ edit_draw_this_char (edit, prev_curs, prev_curs_row);
+ edit_draw_this_char (edit, edit->curs1, edit->curs_row);
+ } else {
+ edit_draw_this_char (edit, edit->curs1, edit->curs_row);
+ edit_draw_this_char (edit, prev_curs, prev_curs_row);
+ }
+ }
+
+ edit->force = 0;
+
+ prev_curs_row = edit->curs_row;
+ prev_curs = edit->curs1;
+ prev_start_display = edit->start_display;
+ prev_start_col = edit->start_col;
+#ifndef MIDNIGHT
+ prev_win = edit->widget->winid;
+#endif
+ exit_render:
+ edit_get_syntax_color (edit, edit->start_display - 1, &fg, &bg);
+}
+
+
+
+#ifndef MIDNIGHT
+
+void edit_convert_expose_to_area (XExposeEvent * xexpose, int *row1, int *col1, int *row2, int *col2)
+{
+ *col1 = xexpose->x - EDIT_TEXT_HORIZONTAL_OFFSET;
+ *row1 = (xexpose->y - EDIT_TEXT_VERTICAL_OFFSET) / FONT_PIX_PER_LINE;
+ *col2 = xexpose->x + xexpose->width + EDIT_TEXT_HORIZONTAL_OFFSET + 3;
+ *row2 = (xexpose->y + xexpose->height - EDIT_TEXT_VERTICAL_OFFSET) / FONT_PIX_PER_LINE;
+}
+
+void edit_render_tidbits (CWidget * wdt)
+{
+ int isfocussed;
+ int w = wdt->width, h = wdt->height;
+ Window win;
+
+ win = wdt->winid;
+ isfocussed = (win == CGetFocus ());
+
+ CSetColor (COLOR_FLAT);
+
+ if (isfocussed) {
+ render_bevel (win, 0, 0, w - 1, h - 1, 3, 1); /*most outer border bevel */
+ } else {
+ render_bevel (win, 2, 2, w - 3, h - 3, 1, 1); /*border bevel */
+ render_bevel (win, 0, 0, w - 1, h - 1, 2, 0); /*most outer border bevel */
+ }
+}
+
+void edit_set_space_width (int s);
+extern int option_long_whitespace;
+
+#endif
+
+void edit_render (WEdit * edit, int page, int row_start, int col_start, int row_end, int col_end)
+{
+ int f = 0;
+ if (page) /* if it was an expose event, 'page' would be set */
+ edit->force |= REDRAW_PAGE | REDRAW_IN_BOUNDS;
+ f = edit->force & (REDRAW_PAGE | REDRAW_COMPLETELY);
+
+#ifdef MIDNIGHT
+ if (edit->force & REDRAW_COMPLETELY)
+ redraw_labels (edit->widget.parent, (Widget *) edit);
+#else
+ if (option_long_whitespace)
+ edit_set_space_width (per_char[' '] * 2);
+ else
+ edit_set_space_width (per_char[' ']);
+ edit_set_foreground_colors (
+ color_palette (option_editor_fg_normal),
+ color_palette (option_editor_fg_bold),
+ color_palette (option_editor_fg_italic)
+ );
+ edit_set_background_colors (
+ color_palette (option_editor_bg_normal),
+ color_palette (option_editor_bg_abnormal),
+ color_palette (option_editor_bg_marked),
+ color_palette (option_editor_bg_marked_abnormal),
+ color_palette (option_editor_bg_highlighted)
+ );
+ edit_set_cursor_color (
+ color_palette (option_editor_fg_cursor)
+ );
+
+ if (!EditExposeRedraw)
+ set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
+#endif
+
+ render_edit_text (edit, row_start, col_start, row_end, col_end);
+ if (edit->force) /* edit->force != 0 means a key was pending and the redraw
+ was halted, so next time we must redraw everything in case stuff
+ was left undrawn from a previous key press */
+ edit->force |= REDRAW_PAGE;
+#ifndef MIDNIGHT
+ if (f) {
+ edit_render_tidbits (edit->widget);
+ CSetColor (edit_normal_background_color);
+ CLine (edit->widget->winid, 3, 3, 3, edit->widget->height - 4);
+ }
+#endif
+}
+
+#ifndef MIDNIGHT
+void edit_render_expose (WEdit * edit, XExposeEvent * xexpose)
+{
+ int row_start, col_start, row_end, col_end;
+ EditExposeRedraw = 1;
+ edit->num_widget_lines = (edit->widget->height - 6) / FONT_PIX_PER_LINE;
+ edit->num_widget_columns = (edit->widget->width - 7) / FONT_MEAN_WIDTH;
+ if (edit->force & (REDRAW_PAGE | REDRAW_COMPLETELY)) {
+ edit->force |= REDRAW_PAGE | REDRAW_COMPLETELY;
+ edit_render_keypress (edit);
+ } else {
+ edit_convert_expose_to_area (xexpose, &row_start, &col_start, &row_end, &col_end);
+ edit_render (edit, 1, row_start, col_start, row_end, col_end);
+ }
+ EditExposeRedraw = 0;
+}
+
+void edit_render_keypress (WEdit * edit)
+{
+ edit_render (edit, 0, 0, 0, 0, 0);
+}
+
+#else
+
+void edit_render_keypress (WEdit * edit)
+{
+ edit_render (edit, 0, 0, 0, 0, 0);
+}
+
+#endif
--- /dev/null
+/* editor menu definitions and initialisation
+
+ Copyright (C) 1996 the Free Software Foundation
+
+ Authors: 1996, 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <config.h>
+#include "edit.h"
+
+#include "editcmddef.h"
+
+#ifdef MIDNIGHT
+
+#include "../src/mad.h"
+
+extern int edit_key_emulation;
+extern WEdit *wedit;
+extern WButtonBar *edit_bar;
+extern Dlg_head *edit_dlg;
+extern WMenu *edit_menubar;
+
+#undef edit_message_dialog
+#define edit_message_dialog(w,x,y,h,s) query_dialog (h, s, 0, 1, "&Ok")
+#define CFocus(x)
+
+static void menu_cmd (int i)
+{
+ send_message (wedit->widget.parent, (Widget *) wedit, WIDGET_COMMAND, i);
+}
+
+static void menu_key (int i)
+{
+ send_message (wedit->widget.parent, (Widget *) wedit, WIDGET_KEY, i);
+}
+
+void edit_wrap_cmd ()
+{
+ char *f;
+ char s[12];
+ sprintf (s, "%d", option_word_wrap_line_length);
+ f = input_dialog (_(" Word wrap "),
+/* Not essential to translate */
+ _(" Enter line length, 0 for off: "), s);
+ if (f) {
+ if (*f) {
+ option_word_wrap_line_length = atoi (f);
+ free (f);
+ }
+ }
+}
+
+void edit_about_cmd ()
+{
+ edit_message_dialog (wedit->mainid, 20, 20, " About ",
+ "\n"
+ " Cooledit v2.1\n"
+ "\n"
+ " Copyright (C) 1996 the Free Software Foundation\n"
+ "\n"
+ " A user friendly text editor written\n"
+ " for the Midnight Commander.\n"
+ );
+}
+
+void menu_mail_cmd (void) { menu_cmd (CK_Mail); }
+void menu_load_cmd (void) { menu_cmd (CK_Load); }
+void menu_new_cmd (void) { menu_cmd (CK_New); }
+void menu_save_cmd (void) { menu_cmd (CK_Save); }
+void menu_save_as_cmd (void) { menu_cmd (CK_Save_As); }
+void menu_insert_file_cmd (void) { menu_cmd (CK_Insert_File); }
+void menu_quit_cmd (void) { menu_cmd (CK_Exit); }
+void menu_mark_cmd (void) { menu_cmd (CK_Mark); }
+void menu_ins_cmd (void) { menu_cmd (CK_Toggle_Insert); }
+void menu_copy_cmd (void) { menu_cmd (CK_Copy); }
+void menu_move_cmd (void) { menu_cmd (CK_Move); }
+void menu_delete_cmd (void) { menu_cmd (CK_Remove); }
+void menu_cut_cmd (void) { menu_cmd (CK_Save_Block); }
+void menu_search_cmd (void) { menu_cmd (CK_Find); }
+void menu_search_again_cmd (void) { menu_cmd (CK_Find_Again); }
+void menu_replace_cmd (void) { menu_cmd (CK_Replace); }
+void menu_begin_record_cmd (void) { menu_cmd (CK_Begin_Record_Macro); }
+void menu_end_record_cmd (void) { menu_cmd (CK_End_Record_Macro); }
+void menu_wrap_cmd (void) { edit_wrap_cmd (); }
+void menu_exec_macro_cmd (void) { menu_key (XCTRL ('a')); }
+void menu_exec_macro_delete_cmd (void) { menu_cmd (CK_Delete_Macro); }
+void menu_c_form_cmd (void) { menu_key (KEY_F (19)); }
+void menu_ispell_cmd (void) { menu_cmd (CK_Pipe_Block (1)); }
+void menu_sort_cmd (void) { menu_cmd (CK_Sort); }
+void menu_date_cmd (void) { menu_cmd (CK_Date); }
+void menu_undo_cmd (void) { menu_cmd (CK_Undo); }
+void menu_beginning_cmd (void) { menu_cmd (CK_Beginning_Of_Text); }
+void menu_end_cmd (void) { menu_cmd (CK_End_Of_Text); }
+void menu_refresh_cmd (void) { menu_cmd (CK_Refresh); }
+void menu_goto_line (void) { menu_cmd (CK_Goto); }
+void menu_lit_cmd (void) { menu_key (XCTRL ('q')); }
+void menu_format_paragraph (void) { menu_cmd (CK_Paragraph_Format); }
+void edit_options_dialog (void);
+void menu_options (void) { edit_options_dialog (); }
+
+static menu_entry FileMenu[] =
+{
+ {' ', N_("&Open/load... C-o"), 'O', menu_load_cmd},
+ {' ', N_("&New C-n"), 'N', menu_new_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Save F2"), 'S', menu_save_cmd},
+ {' ', N_("save &As... F12"), 'A', menu_save_as_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Insert file... F15"), 'I', menu_insert_file_cmd},
+ {' ', N_("copy to &File... C-f"), 'F', menu_cut_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("a&Bout... "), 'B', edit_about_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Quit F10"), 'Q', menu_quit_cmd}
+ };
+
+static menu_entry FileMenuEmacs[] =
+{
+ {' ', N_("&Open/load... C-o"), 'O', menu_load_cmd},
+ {' ', N_("&New C-x k"), 'N', menu_new_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Save F2"), 'S', menu_save_cmd},
+ {' ', N_("save &As... F12"), 'A', menu_save_as_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Insert file... F15"), 'I', menu_insert_file_cmd},
+ {' ', N_("copy to &File... "), 'F', menu_cut_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("a&Bout... "), 'B', edit_about_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Quit F10"), 'Q', menu_quit_cmd}
+};
+
+static menu_entry EditMenu[] =
+{
+ {' ', N_("&Toggle Mark F3"), 'T', menu_mark_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("toggle &Ins/overw Ins"), 'I', menu_ins_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Copy F5"), 'C', menu_copy_cmd},
+ {' ', N_("&Move F6"), 'M', menu_move_cmd},
+ {' ', N_("&Delete F8"), 'D', menu_delete_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Undo C-u"), 'U', menu_undo_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Beginning C-PgUp"), 'B', menu_beginning_cmd},
+ {' ', N_("&End C-PgDn"), 'E', menu_end_cmd}
+};
+
+static menu_entry EditMenuEmacs[] =
+{
+ {' ', N_("&Toggle Mark F3"), 'T', menu_mark_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("toggle &Ins/overw Ins"), 'I', menu_ins_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Copy F5"), 'C', menu_copy_cmd},
+ {' ', N_("&Move F6"), 'M', menu_move_cmd},
+ {' ', N_("&Delete F8"), 'D', menu_delete_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Undo C-u"), 'U', menu_undo_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Beginning C-PgUp"), 'B', menu_beginning_cmd},
+ {' ', N_("&End C-PgDn"), 'E', menu_end_cmd}
+};
+
+static menu_entry SearReplMenu[] =
+{
+ {' ', N_("&Search... F7"), 'S', menu_search_cmd},
+ {' ', N_("search &Again F17"), 'A', menu_search_again_cmd},
+ {' ', N_("&Replace... F4"), 'R', menu_replace_cmd}
+};
+
+static menu_entry SearReplMenuEmacs[] =
+{
+ {' ', N_("&Search... F7"), 'S', menu_search_cmd},
+ {' ', N_("search &Again F17"), 'A', menu_search_again_cmd},
+ {' ', N_("&Replace... F4"), 'R', menu_replace_cmd}
+};
+
+static menu_entry CmdMenu[] =
+{
+ {' ', N_("&Goto line... M-l"), 'G', menu_goto_line},
+ {' ', "", ' ', 0},
+ {' ', N_("insert &Literal... C-q"), 'L', menu_lit_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Refresh screen C-l"), 'R', menu_refresh_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Start record macro C-r"), 'S', menu_begin_record_cmd},
+ {' ', N_("&Finish record macro... C-r"), 'F', menu_end_record_cmd},
+ {' ', N_("&Execute macro... C-a, KEY"), 'E', menu_exec_macro_cmd},
+ {' ', N_("delete macr&O... "), 'O', menu_exec_macro_delete_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("insert &Date/time "), 'D', menu_date_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("format p&Aragraph M-p"), 'A', menu_format_paragraph},
+ {' ', N_("'ispell' s&Pell check C-p"), 'P', menu_ispell_cmd},
+ {' ', N_("sor&T... M-t"), 'T', menu_sort_cmd},
+ {' ', N_("'indent' &C Formatter F19"), 'C', menu_c_form_cmd},
+ {' ', N_("&Mail... "), 'M', menu_mail_cmd}
+};
+
+static menu_entry CmdMenuEmacs[] =
+{
+ {' ', N_("&Goto line... M-l"), 'G', menu_goto_line},
+ {' ', "", ' ', 0},
+ {' ', N_("insert &Literal... C-q"), 'L', menu_lit_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Refresh screen C-l"), 'R', menu_refresh_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("&Start record macro C-r"), 'S', menu_begin_record_cmd},
+ {' ', N_("&Finish record macro... C-r"), 'F', menu_end_record_cmd},
+ {' ', N_("&Execute macro... C-x e, KEY"), 'E', menu_exec_macro_cmd},
+ {' ', N_("delete macr&O... "), 'o', menu_exec_macro_delete_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("insert &Date/time "), 'D', menu_date_cmd},
+ {' ', "", ' ', 0},
+ {' ', N_("format p&Aragraph M-p"), 'a', menu_format_paragraph},
+ {' ', N_("'ispell' s&Pell check M-$"), 'P', menu_ispell_cmd},
+ {' ', N_("sor&T... M-t"), 'T', menu_sort_cmd},
+ {' ', N_("'indent' &C Formatter F19"), 'C', menu_c_form_cmd}
+};
+
+extern void menu_save_mode_cmd (void);
+
+static menu_entry OptMenu[] =
+{
+ {' ', N_("&General... "), 'G', menu_options},
+ {' ', N_("&Save mode..."), 'S', menu_save_mode_cmd}
+#if 0
+ {' ', N_("&Layout..."), 'L', menu_layout_cmd}
+#endif
+};
+
+static menu_entry OptMenuEmacs[] =
+{
+ {' ', N_("&General... "), 'G', menu_options},
+ {' ', N_("&Save mode..."), 'S', menu_save_mode_cmd}
+#if 0
+ {' ', N_("&Layout..."), 'L', menu_layout_cmd}
+#endif
+};
+
+#define menu_entries(x) sizeof(x)/sizeof(menu_entry)
+
+Menu EditMenuBar[N_menus];
+
+void edit_init_menu_normal (void)
+{
+ EditMenuBar[0] = create_menu (_(" File "), FileMenu, menu_entries (FileMenu));
+ EditMenuBar[1] = create_menu (_(" Edit "), EditMenu, menu_entries (EditMenu));
+ EditMenuBar[2] = create_menu (_(" Sear/Repl "), SearReplMenu, menu_entries (SearReplMenu));
+ EditMenuBar[3] = create_menu (_(" Command "), CmdMenu, menu_entries (CmdMenu));
+ EditMenuBar[4] = create_menu (_(" Options "), OptMenu, menu_entries (OptMenu));
+}
+
+void edit_init_menu_emacs (void)
+{
+ EditMenuBar[0] = create_menu (_(" File "), FileMenuEmacs, menu_entries (FileMenuEmacs));
+ EditMenuBar[1] = create_menu (_(" Edit "), EditMenuEmacs, menu_entries (EditMenuEmacs));
+ EditMenuBar[2] = create_menu (_(" Sear/Repl "), SearReplMenuEmacs, menu_entries (SearReplMenuEmacs));
+ EditMenuBar[3] = create_menu (_(" Command "), CmdMenuEmacs, menu_entries (CmdMenuEmacs));
+ EditMenuBar[4] = create_menu (_(" Options "), OptMenuEmacs, menu_entries (OptMenuEmacs));
+}
+
+void edit_done_menu (void)
+{
+ int i;
+ for (i = 0; i < N_menus; i++)
+ destroy_menu (EditMenuBar[i]);
+}
+
+
+void edit_drop_menu_cmd (WEdit * e, int which)
+{
+ if (edit_menubar->active)
+ return;
+ edit_menubar->active = 1;
+ edit_menubar->dropped = drop_menus;
+ edit_menubar->previous_selection = which >= 0 ? which : dlg_item_number (edit_dlg);
+ if (which >= 0)
+ edit_menubar->selected = which;
+ dlg_select_widget (edit_dlg, edit_menubar);
+}
+
+
+void edit_menu_cmd (WEdit * e)
+{
+ edit_drop_menu_cmd (e, -1);
+}
+
+
+int edit_drop_hotkey_menu (WEdit * e, int key)
+{
+ int m = 0;
+ switch (key) {
+ case ALT ('f'):
+ if (edit_key_emulation == EDIT_KEY_EMULATION_EMACS)
+ return 0;
+ m = 0;
+ break;
+ case ALT ('e'):
+ m = 1;
+ break;
+ case ALT ('s'):
+ m = 2;
+ break;
+ case ALT ('c'):
+ m = 3;
+ break;
+ case ALT ('o'):
+ m = 4;
+ break;
+ default:
+ return 0;
+ }
+
+ edit_drop_menu_cmd (e, m);
+ return 1;
+}
+
+
+#else /* !MIDNIGHT */
+
+
+extern CWidget *wedit;
+
+void CSetEditMenu (const char *ident)
+{
+ wedit = CIdent (ident);
+}
+
+CWidget *CGetEditMenu (void)
+{
+ return wedit;
+}
+
+static void menu_cmd (unsigned long i)
+{
+ XEvent e;
+ if (wedit) {
+ memset (&e, 0, sizeof (XEvent));
+ e.type = EditorCommand;
+ e.xkey.keycode = i;
+ e.xkey.window = wedit->winid;
+ CFocus (wedit);
+ CSendEvent (&e);
+ }
+}
+
+void CEditMenuCommand (int i)
+{
+ menu_cmd ((unsigned long) i);
+}
+
+static void menu_key (KeySym i, int state)
+{
+ int cmd, ch;
+ if (edit_translate_key (0, i, state, &cmd, &ch)) {
+ if (cmd > 0)
+ menu_cmd (cmd);
+ }
+}
+
+static void menu_ctrl_key (unsigned long i)
+{
+ menu_key ((KeySym) i, ControlMask);
+}
+
+void CDrawEditMenuButtons (const char *ident, Window parent, Window focus_return, int x, int y)
+{
+ int d;
+
+ CDrawMenuButton (catstrs (ident, ".filemenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 8,
+/* The following are menu options. Do not change the key bindings (eg. C-o) and preserve '\t' */
+ _(" File "),
+ _("Open...\tC-o"), '~', menu_cmd, CK_Load,
+ _("New\tC-n"), '~', menu_cmd, CK_New,
+ "", ' ', 0, 0,
+ _("Save\tF2"), '~', menu_cmd, CK_Save,
+ _("Save as...\tF12"), '~', menu_cmd, CK_Save_As,
+ "", ' ', 0, 0,
+ _("Insert file...\tF15"), '~', menu_cmd, CK_Insert_File,
+ _("Copy to file...\tC-f"), '~', menu_cmd, CK_Save_Block
+ );
+/* Tool hint */
+ CSetToolHint (catstrs (ident, ".filemenu", 0), _("Disk operations"));
+
+ CGetHintPos (&x, &d);
+
+ CDrawMenuButton (catstrs (ident, ".editmenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 14,
+ _(" Edit "),
+ _("Toggle mark\tF3"), '~', menu_cmd, CK_Mark,
+ "", ' ', 0, 0,
+ _("Toggle insert/overwrite\tIns"), '~', menu_cmd, CK_Toggle_Insert,
+ "", ' ', 0, 0,
+ _("Copy block to cursor\tF5"), '~', menu_cmd, CK_Copy,
+ _("Move block to cursor\tF6"), '~', menu_cmd, CK_Move,
+ _("Delete block\tF8/C-Del"), '~', menu_cmd, CK_Remove,
+ "", ' ', 0, 0,
+ _("Copy block to clipbrd\tC-Ins"), '~', menu_cmd, CK_XStore,
+ _("Cut block to clipbrd\tS-Del"), '~', menu_cmd, CK_XCut,
+ _("Paste block from clipbrd\tS-Ins"), '~', menu_cmd, CK_XPaste,
+ _("Selection history\tM-Ins"), '~', menu_cmd, CK_Selection_History,
+ "", ' ', 0, 0,
+ _("Undo\tC-BackSpace"), '~', menu_cmd, CK_Undo
+ );
+/* Tool hint */
+ CSetToolHint (catstrs (ident, ".editmenu", 0), _("Manipulating blocks of text"));
+
+ CGetHintPos (&x, &d);
+
+ CDrawMenuButton (catstrs (ident, ".searchmenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 4,
+ _(" Srch/Replce "),
+ _("Search...\tF7"), '~', menu_cmd, CK_Find,
+ _("Search again\tF17"), '~', menu_cmd, CK_Find_Again,
+ _("Replace...\tF4"), '~', menu_cmd, CK_Replace,
+ _("Replace again\tF14"), '~', menu_cmd, CK_Replace_Again
+ );
+/* Tool hint */
+ CSetToolHint (catstrs (ident, ".searchmenu", 0), _("Search for and replace text"));
+
+ CGetHintPos (&x, &d);
+
+ CDrawMenuButton (catstrs (ident, ".commandmenu", 0), parent, focus_return, x, y, AUTO_WIDTH, AUTO_HEIGHT, 9,
+ _(" Command "),
+ _("Goto line...\tM-l"), '~', menu_cmd, CK_Goto,
+ "", ' ', 0, 0,
+ _("Start record macro\tC-r"), '~', menu_cmd, CK_Begin_Record_Macro,
+ _("Finish record macro...\tC-r"), '~', menu_cmd, CK_End_Record_Macro,
+ _("Execute macro...\tC-a, KEY"), '~', menu_ctrl_key, XK_a,
+ _("Delete macro...\t"), '~', menu_cmd, CK_Delete_Macro,
+ "", ' ', 0, 0,
+ _("Insert date/time\tC-d"), '~', menu_cmd, CK_Date,
+ _("Format paragraph\tM-p"), '~', menu_cmd, CK_Paragraph_Format
+ );
+/* Tool hint */
+ CSetToolHint (catstrs (ident, ".commandmenu", 0), _("Macros and internal commands"));
+}
+
+
+#endif /* !MIDNIGHT */
+
--- /dev/null
+/* editor options dialog box
+
+ Copyright (C) 1996, 1997 the Free Software Foundation
+
+ Authors: 1996, 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "edit.h"
+
+#define OPT_DLG_H 15
+#define OPT_DLG_W 72
+
+#ifndef USE_INTERNAL_EDIT
+#define USE_INTERNAL_EDIT 1
+#endif
+
+#include "../src/main.h" /* extern int option_this_and_that ... */
+
+char *key_emu_str[] =
+{"Intuitive", "Emacs"};
+
+char *wrap_str[] =
+{N_("None"), N_("Dynamic paragraphing"), N_("Type writer wrap")};
+
+extern int option_syntax_highlighting;
+
+void edit_options_dialog (void)
+{
+ char wrap_length[32], tab_spacing[32], *p, *q;
+ int wrap_mode = 0;
+ int tedit_key_emulation = edit_key_emulation;
+ int toption_fill_tabs_with_spaces = option_fill_tabs_with_spaces;
+ int tedit_confirm_save = edit_confirm_save;
+ int tedit_syntax_highlighting = option_syntax_highlighting;
+ int toption_return_does_auto_indent = option_return_does_auto_indent;
+ int toption_backspace_through_tabs = option_backspace_through_tabs;
+ int toption_fake_half_tabs = option_fake_half_tabs;
+
+ QuickWidget quick_widgets[] =
+ {
+/*0 */
+ {quick_button, 6, 10, OPT_DLG_H - 3, OPT_DLG_H, "&Cancel", 0, B_CANCEL, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+/*1 */
+ {quick_button, 2, 10, OPT_DLG_H - 3, OPT_DLG_H, "&Ok", 0, B_ENTER, 0,
+ 0, XV_WLAY_DONTCARE, NULL},
+/*2 */
+ {quick_label, OPT_DLG_W / 2, OPT_DLG_W, OPT_DLG_H - 4, OPT_DLG_H, "Word wrap line length : ", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*3 */
+ {quick_input, OPT_DLG_W / 2 + 24, OPT_DLG_W, OPT_DLG_H - 4, OPT_DLG_H, "", OPT_DLG_W / 2 - 4 - 24, 0,
+ 0, 0, XV_WLAY_DONTCARE, "i"},
+/*4 */
+ {quick_label, OPT_DLG_W / 2, OPT_DLG_W, OPT_DLG_H - 5, OPT_DLG_H, "Tab spacing : ", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*5 */
+ {quick_input, OPT_DLG_W / 2 + 24, OPT_DLG_W, OPT_DLG_H - 5, OPT_DLG_H, "", OPT_DLG_W / 2 - 4 - 24, 0,
+ 0, 0, XV_WLAY_DONTCARE, "i"},
+/*6 */
+#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
+#define OA 1
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, "syntax h&Ighlighting", 8, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+#else
+#define OA 0
+#endif
+/*7 */
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 8, OPT_DLG_H, "confir&M before saving", 6, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*8 */
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 9, OPT_DLG_H, "&Fill tabs with spaces", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*9 */
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 10, OPT_DLG_H, "&Return does auto indent", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*10 */
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "&Backspace through tabs", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*11 */
+ {quick_checkbox, OPT_DLG_W / 2 + 1, OPT_DLG_W, OPT_DLG_H - 12, OPT_DLG_H, "&Fake half tabs", 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*12 */
+ {quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 6, OPT_DLG_H, "", 3, 0,
+ 0, wrap_str, XV_WLAY_DONTCARE, "wrapm"},
+/*13 */
+ {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 7, OPT_DLG_H, N_("Wrap mode"), 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+/*14 */
+ {quick_radio, 5, OPT_DLG_W, OPT_DLG_H - 11, OPT_DLG_H, "", 2, 0,
+ 0, key_emu_str, XV_WLAY_DONTCARE, "keyemu"},
+/*15 */
+ {quick_label, 4, OPT_DLG_W, OPT_DLG_H - 12, OPT_DLG_H, N_("Key emulation"), 0, 0,
+ 0, 0, XV_WLAY_DONTCARE, NULL},
+ {0}};
+
+ sprintf (wrap_length, "%d", option_word_wrap_line_length);
+ sprintf (tab_spacing, "%d", option_tab_spacing);
+
+ quick_widgets[3].text = wrap_length;
+ quick_widgets[3].str_result = &p;
+ quick_widgets[5].text = tab_spacing;
+ quick_widgets[5].str_result = &q;
+ quick_widgets[5 + OA].result = &tedit_syntax_highlighting;
+ quick_widgets[6 + OA].result = &tedit_confirm_save;
+ quick_widgets[7 + OA].result = &toption_fill_tabs_with_spaces;
+ quick_widgets[8 + OA].result = &toption_return_does_auto_indent;
+ quick_widgets[9 + OA].result = &toption_backspace_through_tabs;
+ quick_widgets[10 + OA].result = &toption_fake_half_tabs;
+
+ if (option_auto_para_formatting)
+ wrap_mode = 1;
+ else if (option_typewriter_wrap)
+ wrap_mode = 2;
+ else
+ wrap_mode = 0;
+
+ quick_widgets[11 + OA].result = &wrap_mode;
+ quick_widgets[11 + OA].value = wrap_mode;
+
+ quick_widgets[13 + OA].result = &tedit_key_emulation;
+ quick_widgets[13 + OA].value = tedit_key_emulation;
+
+ {
+ QuickDialog Quick_options =
+ {OPT_DLG_W, OPT_DLG_H, -1, 0, " Editor Options ",
+ "", "quick_input", 0};
+
+ Quick_options.widgets = quick_widgets;
+
+ if (quick_dialog (&Quick_options) != B_CANCEL) {
+ if (p) {
+ option_word_wrap_line_length = atoi (p);
+ free (p);
+ }
+ if (q) {
+ option_tab_spacing = atoi (q);
+ if (option_tab_spacing < 0)
+ option_tab_spacing = 2;
+ option_tab_spacing += option_tab_spacing & 1;
+ free (q);
+ }
+ option_syntax_highlighting = *quick_widgets[5 + OA].result;
+ edit_confirm_save = *quick_widgets[6 + OA].result;
+ option_fill_tabs_with_spaces = *quick_widgets[7 + OA].result;
+ option_return_does_auto_indent = *quick_widgets[8 + OA].result;
+ option_backspace_through_tabs = *quick_widgets[9 + OA].result;
+ option_fake_half_tabs = *quick_widgets[10 + OA].result;
+
+ if (*quick_widgets[11 + OA].result == 1) {
+ option_auto_para_formatting = 1;
+ option_typewriter_wrap = 0;
+ } else if (*quick_widgets[11 + OA].result == 2) {
+ option_auto_para_formatting = 0;
+ option_typewriter_wrap = 1;
+ } else {
+ option_auto_para_formatting = 0;
+ option_typewriter_wrap = 0;
+ }
+
+ edit_key_emulation = *quick_widgets[13 + OA].result;
+
+ return;
+ } else {
+ return;
+ }
+ }
+}
+
--- /dev/null
+/* editor initialisation and callback handler.
+
+ Copyright (C) 1996, 1997 the Free Software Foundation
+
+ Authors: 1996, 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+
+#include <config.h>
+#include "edit.h"
+
+#ifndef MIDNIGHT
+#include <X11/Xmd.h> /* CARD32 */
+#include <X11/Xatom.h>
+#include "app_glob.c"
+#include "coollocal.h"
+#include "editcmddef.h"
+#include "mousemark.h"
+#endif
+
+
+#ifndef MIDNIGHT
+
+extern int EditExposeRedraw;
+CWidget *wedit = 0;
+
+void edit_destroy_callback (CWidget * w)
+{
+ if (w) {
+ edit_clean (w->editor);
+ if (w->editor)
+ free (w->editor);
+ w->editor = NULL;
+ } else
+/* NLS ? */
+ CError ("Trying to destroy non-existing editor widget.\n");
+}
+
+void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton);
+
+extern int option_editor_bg_normal;
+void edit_tri_cursor (Window win);
+/* starting_directory is for the filebrowser */
+CWidget *CDrawEditor (const char *identifier, Window parent, int x, int y,
+ int width, int height, const char *text, const char *filename,
+ const char *starting_directory, unsigned int options, unsigned long text_size)
+{
+ static made_directory = 0;
+ int extra_space_for_hscroll = 0;
+ CWidget *w;
+ WEdit *e;
+
+ if (options & EDITOR_HORIZ_SCROLL)
+ extra_space_for_hscroll = 8;
+
+ wedit = w = CSetupWidget (identifier, parent, x, y,
+ width + 7, height + 6, C_EDITOR_WIDGET,
+ ExposureMask | ButtonPressMask | ButtonReleaseMask | \
+ KeyPressMask | KeyReleaseMask | ButtonMotionMask | \
+ PropertyChangeMask | StructureNotifyMask | \
+ EnterWindowMask | LeaveWindowMask, color_palette (option_editor_bg_normal), 1);
+ edit_tri_cursor (w->winid);
+ w->options = options | WIDGET_TAKES_SELECTION;
+
+ w->destroy = edit_destroy_callback;
+ if (filename)
+ w->label = strdup (filename);
+ else
+ w->label = strdup ("");
+
+ if (!made_directory) {
+ mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
+ made_directory = 1;
+ }
+ e = w->editor = CMalloc (sizeof (WEdit));
+ if (!w->editor) {
+/* Not essential to translate */
+ CError (_ ("Error initialising editor.\n"));
+ return 0;
+ }
+ w->editor->widget = w;
+ e = w->editor = edit_init (e, height / FONT_PIX_PER_LINE, width / FONT_MEAN_WIDTH, filename, text, starting_directory, text_size);
+ if (!e) {
+ CDestroyWidget (w->ident);
+ return 0;
+ }
+ e->macro_i = -1;
+ e->widget = w;
+
+ set_hint_pos (x + width + 7 + WIDGET_SPACING, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll);
+ if (extra_space_for_hscroll) {
+ w->hori_scrollbar = CDrawHorizontalScrollbar (catstrs (identifier, ".hsc", 0), parent,
+ x, y + height + 6, width + 6, 12, 0, 0);
+ CSetScrollbarCallback (w->hori_scrollbar->ident, w->ident, link_hscrollbar_to_editor);
+ }
+ if (!(options & EDITOR_NO_TEXT))
+ CDrawText (catstrs (identifier, ".text", 0), parent, x, y + height + 6 + WIDGET_SPACING + extra_space_for_hscroll, "%s", e->filename);
+ if (!(options & EDITOR_NO_SCROLL)) {
+ w->vert_scrollbar = CDrawVerticalScrollbar (catstrs (identifier, ".vsc", 0), parent,
+ x + width + 7 + WIDGET_SPACING, y, height + 6, 20, 0, 0);
+ CSetScrollbarCallback (w->vert_scrollbar->ident, w->ident, link_scrollbar_to_editor);
+ }
+ return w;
+}
+
+void update_scroll_bars (WEdit * e)
+{
+ int i, x1, x2;
+ CWidget *scroll;
+ scroll = e->widget->vert_scrollbar;
+ if (scroll) {
+ i = e->total_lines - e->start_line + 1;
+ if (i > e->num_widget_lines)
+ i = e->num_widget_lines;
+ if (e->total_lines) {
+ x1 = (double) 65535.0 *e->start_line / (e->total_lines + 1);
+ x2 = (double) 65535.0 *i / (e->total_lines + 1);
+ } else {
+ x1 = 0;
+ x2 = 65535;
+ }
+ if (x1 != scroll->firstline || x2 != scroll->numlines) {
+ scroll->firstline = x1;
+ scroll->numlines = x2;
+ EditExposeRedraw = 1;
+ render_scrollbar (scroll);
+ EditExposeRedraw = 0;
+ }
+ }
+ scroll = e->widget->hori_scrollbar;
+ if (scroll) {
+ i = e->max_column - (-e->start_col) + 1;
+ if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
+ i = e->num_widget_columns * FONT_MEAN_WIDTH;
+ x1 = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
+ x2 = (double) 65535.0 *i / (e->max_column + 1);
+ if (x1 != scroll->firstline || x2 != scroll->numlines) {
+ scroll->firstline = x1;
+ scroll->numlines = x2;
+ EditExposeRedraw = 1;
+ render_scrollbar (scroll);
+ EditExposeRedraw = 0;
+ }
+ }
+}
+
+/* returns the position in the edit buffer of a window click */
+long edit_get_click_pos (WEdit * edit, int x, int y)
+{
+ long click;
+/* (1) goto to left margin */
+ click = edit_bol (edit, edit->curs1);
+
+/* (1) move up or down */
+ if (y > (edit->curs_row + 1))
+ click = edit_move_forward (edit, click, y - (edit->curs_row + 1), 0);
+ if (y < (edit->curs_row + 1))
+ click = edit_move_backward (edit, click, (edit->curs_row + 1) - y);
+
+/* (3) move right to x pos */
+ click = edit_move_forward3 (edit, click, x - edit->start_col - 1, 0);
+ return click;
+}
+
+void edit_translate_xy (int xs, int ys, int *x, int *y)
+{
+ *x = xs - EDIT_TEXT_HORIZONTAL_OFFSET;
+ *y = (ys - EDIT_TEXT_VERTICAL_OFFSET - option_text_line_spacing / 2 - 1) / FONT_PIX_PER_LINE + 1;
+}
+
+extern int just_dropped_something;
+
+static void mouse_redraw (WEdit * edit, long click)
+{
+ edit->force |= REDRAW_PAGE | REDRAW_LINE;
+ edit_update_curs_row (edit);
+ edit_update_curs_col (edit);
+ edit->prev_col = edit_get_col (edit);
+ edit_update_screen (edit);
+ edit->search_start = click;
+}
+
+static void xy (int x, int y, int *x_return, int *y_return)
+{
+ edit_translate_xy (x, y, x_return, y_return);
+}
+
+static long cp (WEdit *edit, int x, int y)
+{
+ return edit_get_click_pos (edit, x, y);
+}
+
+/* return 1 if not marked */
+static int marks (WEdit * edit, long *start, long *end)
+{
+ return eval_marks (edit, start, end);
+}
+
+int column_highlighting = 0;
+
+static int erange (WEdit * edit, long start, long end, int click)
+{
+ if (column_highlighting) {
+ int x;
+ x = edit_move_forward3 (edit, edit_bol (edit, click), 0, click);
+ if ((x >= edit->column1 && x < edit->column2)
+ || (x > edit->column2 && x <= edit->column1))
+ return (start <= click && click < end);
+ else
+ return 0;
+ }
+ return (start <= click && click < end);
+}
+
+static void fin_mark (WEdit *edit)
+{
+ if (edit->mark2 < 0)
+ edit_mark_cmd (edit, 0);
+}
+
+static void move_mark (WEdit *edit)
+{
+ edit_mark_cmd (edit, 1);
+ edit_mark_cmd (edit, 0);
+}
+
+static void release_mark (WEdit *edit, XEvent *event)
+{
+ if (edit->mark2 < 0)
+ edit_mark_cmd (edit, 0);
+ else
+ edit_mark_cmd (edit, 1);
+ if (edit->mark1 != edit->mark2) {
+ edit_get_selection (edit);
+ XSetSelectionOwner (CDisplay, XA_PRIMARY, edit->widget->winid, event->xbutton.time);
+ }
+}
+
+static char *get_block (WEdit * edit, long start_mark, long end_mark, int *type, int *l)
+{
+ char *t;
+ t = (char *) edit_get_block (edit, start_mark, end_mark, l);
+ if (strlen (t) < *l)
+ *type = DndRawData; /* if there are nulls in the data, send as raw */
+ else
+ *type = DndText; /* else send as text */
+ return t;
+}
+
+static void move (WEdit *edit, long click, int y)
+{
+ edit_cursor_move (edit, click - edit->curs1);
+}
+
+static void dclick (WEdit *edit, XEvent *event)
+{
+ edit_mark_cmd (edit, 1);
+ edit_right_word_move (edit);
+ edit_mark_cmd (edit, 0);
+ edit_left_word_move (edit);
+ release_mark (edit, event);
+}
+
+static void redraw (WEdit *edit, long click)
+{
+ mouse_redraw (edit, click);
+}
+
+static void edit_mouse_mark (WEdit * edit, XEvent * event, CEvent * ce)
+{
+ edit_update_curs_row (edit);
+ edit_update_curs_col (edit);
+ if (event->type != MotionNotify) {
+ edit_push_action (edit, KEY_PRESS + edit->start_display);
+ if (edit->mark2 == -1)
+ edit_push_action (edit, MARK_1 + edit->mark1); /* mark1 must be following the cursor */
+ }
+ if (event->type == ButtonPress) {
+ edit->highlight = 0;
+ edit->found_len = 0;
+ }
+ mouse_mark (
+ (void *) edit,
+ event,
+ ce,
+ (void (*) (int, int, int *, int *)) xy,
+ (long (*) (void *, int, int)) cp,
+ (int (*) (void *, long *, long *)) marks,
+ (int (*) (void *, long, long, long)) erange,
+ (void (*) (void *)) fin_mark,
+ (void (*) (void *)) move_mark,
+ (void (*) (void *, XEvent *)) release_mark,
+ (char * (*) (void *, long, long, int *, int *)) get_block,
+ (void (*) (void *, long, int)) move,
+ 0,
+ (void (*) (void *, XEvent *)) dclick,
+ (void (*) (void *, long)) redraw
+ );
+}
+
+void link_scrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
+{
+ int i, start_line;
+ WEdit *e;
+ e = editor->editor;
+ if (!e)
+ return;
+ if (!e->widget->vert_scrollbar)
+ return;
+ start_line = e->start_line;
+ if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
+ edit_move_display (e, (double) scrollbar->firstline * e->total_lines / 65535.0 + 1);
+ } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
+ switch (whichscrbutton) {
+ case 1:
+ edit_move_display (e, e->start_line - e->num_widget_lines + 1);
+ break;
+ case 2:
+ edit_move_display (e, e->start_line - 1);
+ break;
+ case 5:
+ edit_move_display (e, e->start_line + 1);
+ break;
+ case 4:
+ edit_move_display (e, e->start_line + e->num_widget_lines - 1);
+ break;
+ }
+ }
+ if (e->total_lines)
+ scrollbar->firstline = (double) 65535.0 *e->start_line / (e->total_lines + 1);
+ else
+ scrollbar->firstline = 0;
+ i = e->total_lines - e->start_line + 1;
+ if (i > e->num_widget_lines)
+ i = e->num_widget_lines;
+ if (e->total_lines)
+ scrollbar->numlines = (double) 65535.0 *i / (e->total_lines + 1);
+ else
+ scrollbar->numlines = 65535;
+ if (start_line != e->start_line) {
+ e->force |= REDRAW_PAGE | REDRAW_LINE;
+ set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
+ return;
+ }
+ if (e->force) {
+ edit_render_keypress (e);
+ edit_status (e);
+ }
+}
+
+void link_hscrollbar_to_editor (CWidget * scrollbar, CWidget * editor, XEvent * xevent, CEvent * cwevent, int whichscrbutton)
+{
+ int i, start_col;
+ WEdit *e;
+ e = editor->editor;
+ if (!e)
+ return;
+ if (!e->widget->hori_scrollbar)
+ return;
+ start_col = (-e->start_col);
+ if ((xevent->type == ButtonRelease || xevent->type == MotionNotify) && whichscrbutton == 3) {
+ e->start_col = (double) scrollbar->firstline * e->max_column / 65535.0 + 1;
+ e->start_col -= e->start_col % FONT_MEAN_WIDTH;
+ if (e->start_col < 0)
+ e->start_col = 0;
+ e->start_col = (-e->start_col);
+ } else if (xevent->type == ButtonPress && (cwevent->button == Button1 || cwevent->button == Button2)) {
+ switch (whichscrbutton) {
+ case 1:
+ edit_scroll_left (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
+ break;
+ case 2:
+ edit_scroll_left (e, FONT_MEAN_WIDTH);
+ break;
+ case 5:
+ edit_scroll_right (e, FONT_MEAN_WIDTH);
+ break;
+ case 4:
+ edit_scroll_right (e, (e->num_widget_columns - 1) * FONT_MEAN_WIDTH);
+ break;
+ }
+ }
+ scrollbar->firstline = (double) 65535.0 *(-e->start_col) / (e->max_column + 1);
+ i = e->max_column - (-e->start_col) + 1;
+ if (i > e->num_widget_columns * FONT_MEAN_WIDTH)
+ i = e->num_widget_columns * FONT_MEAN_WIDTH;
+ scrollbar->numlines = (double) 65535.0 *i / (e->max_column + 1);
+ if (start_col != (-e->start_col)) {
+ e->force |= REDRAW_PAGE | REDRAW_LINE;
+ set_cursor_position (0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (CCheckWindowEvent (xevent->xany.window, ButtonReleaseMask | ButtonMotionMask, 0))
+ return;
+ }
+ if (e->force) {
+ edit_render_keypress (e);
+ edit_status (e);
+ }
+}
+
+/*
+ This section comes from rxvt-2.21b1/src/screen.c by
+ Robert Nation <nation@rocket.sanders.lockheed.com> &
+ mods by mj olesen <olesen@me.QueensU.CA>
+
+ Changes made for cooledit
+ */
+void selection_send (XSelectionRequestEvent * rq)
+{
+ XEvent ev;
+ static Atom xa_targets = None;
+ if (xa_targets == None)
+ xa_targets = XInternAtom (CDisplay, "TARGETS", False);
+
+ ev.xselection.type = SelectionNotify;
+ ev.xselection.property = None;
+ ev.xselection.display = rq->display;
+ ev.xselection.requestor = rq->requestor;
+ ev.xselection.selection = rq->selection;
+ ev.xselection.target = rq->target;
+ ev.xselection.time = rq->time;
+
+ if (rq->target == xa_targets) {
+ /*
+ * On some systems, the Atom typedef is 64 bits wide.
+ * We need to have a typedef that is exactly 32 bits wide,
+ * because a format of 64 is not allowed by the X11 protocol.
+ */
+ typedef CARD32 Atom32;
+
+ Atom32 target_list[2];
+
+ target_list[0] = (Atom32) xa_targets;
+ target_list[1] = (Atom32) XA_STRING;
+
+ XChangeProperty (CDisplay, rq->requestor, rq->property,
+ xa_targets, 8 * sizeof (target_list[0]), PropModeReplace,
+ (unsigned char *) target_list,
+ sizeof (target_list) / sizeof (target_list[0]));
+ ev.xselection.property = rq->property;
+ } else if (rq->target == XA_STRING) {
+ XChangeProperty (CDisplay, rq->requestor, rq->property,
+ XA_STRING, 8, PropModeReplace,
+ selection.text, selection.len);
+ ev.xselection.property = rq->property;
+ }
+ XSendEvent (CDisplay, rq->requestor, False, 0, &ev);
+}
+
+/*{{{ paste selection */
+
+/*
+ * Respond to a notification that a primary selection has been sent
+ */
+void paste_prop (void *data, void (*insert) (void *, int), Window win, unsigned prop, int delete)
+{
+ long nread;
+ unsigned long bytes_after;
+
+ if (prop == None)
+ return;
+
+ nread = 0;
+ do {
+ unsigned char *s;
+ Atom actual_type;
+ int actual_fmt, i;
+ unsigned long nitems;
+
+ if (XGetWindowProperty (CDisplay, win, prop,
+ nread / 4, 65536, delete,
+ AnyPropertyType, &actual_type, &actual_fmt,
+ &nitems, &bytes_after,
+ &s) != Success) {
+ XFree (s);
+ return;
+ }
+ nread += nitems;
+ for (i = 0; i < nitems; i++)
+ (*insert) (data, s[i]);
+ XFree (s);
+ } while (bytes_after);
+}
+
+void selection_paste (WEdit * edit, Window win, unsigned prop, int delete)
+{
+ long c;
+ c = edit->curs1;
+ paste_prop ((void *) edit,
+ (void (*)(void *, int)) edit_insert,
+ win, prop, delete);
+ edit_cursor_move (edit, c - edit->curs1);
+ edit->force |= REDRAW_COMPLETELY | REDRAW_LINE;
+}
+
+/*}}} */
+
+void selection_clear (void)
+{
+ selection.text = 0;
+ selection.len = 0;
+}
+
+void edit_update_screen (WEdit * e)
+{
+ if (!e)
+ return;
+ if (!e->force)
+ return;
+
+ edit_scroll_screen_over_cursor (e);
+ edit_update_curs_row (e);
+ edit_update_curs_col (e);
+ update_scroll_bars (e);
+ edit_status (e);
+
+ if (e->force & REDRAW_COMPLETELY)
+ e->force |= REDRAW_PAGE;
+
+/* pop all events for this window for internal handling */
+ if (e->force & (REDRAW_CHAR_ONLY | REDRAW_COMPLETELY)) {
+ edit_render_keypress (e);
+ } else if (CCheckWindowEvent (e->widget->winid, ButtonPressMask | ButtonReleaseMask | ButtonMotionMask, 0)
+ || CKeyPending ()) {
+ e->force |= REDRAW_PAGE;
+ return;
+ } else {
+ edit_render_keypress (e);
+ }
+}
+
+extern int space_width;
+
+static void edit_insert_column_of_text (WEdit * edit, unsigned char *data, int size, int width)
+{
+ long cursor;
+ int i, col;
+ cursor = edit->curs1;
+ col = edit_get_col (edit);
+ for (i = 0; i < size; i++) {
+ if (data[i] == '\n') { /* fill in and move to next line */
+ int l;
+ long p;
+ if (edit_get_byte (edit, edit->curs1) != '\n') {
+ l = width - (edit_get_col (edit) - col);
+ while (l > 0) {
+ edit_insert (edit, ' ');
+ l -= space_width;
+ }
+ }
+ for (p = edit->curs1;; p++) {
+ if (p == edit->last_byte)
+ edit_insert_ahead (edit, '\n');
+ if (edit_get_byte (edit, p) == '\n') {
+ p++;
+ break;
+ }
+ }
+ edit_cursor_move (edit, edit_move_forward3 (edit, p, col, 0) - edit->curs1);
+ l = col - edit_get_col (edit);
+ while (l >= space_width) {
+ edit_insert (edit, ' ');
+ l -= space_width;
+ }
+ continue;
+ }
+ edit_insert (edit, data[i]);
+ }
+ edit_cursor_move (edit, cursor - edit->curs1);
+}
+
+#define free_data if (data) {free(data);data=0;}
+
+/* handles drag and drop */
+void handle_client_message (CWidget * w, XEvent * xevent, CEvent * cwevent)
+{
+ int data_type;
+ unsigned char *data;
+ unsigned long size;
+ int xs, ys;
+ long start_line;
+ int x, y, r, deleted = 0;
+ long click;
+ unsigned int state;
+ long start_mark = 0, end_mark = 0;
+ WEdit *e = w->editor;
+
+/* see just below for a comment on what this is for: */
+ if (CIsDropAcknowledge (xevent, &state) != DndNotDnd) {
+ if (!(state & Button1Mask) && just_dropped_something) {
+ edit_push_action (e, KEY_PRESS + e->start_display);
+ edit_block_delete_cmd (e);
+ }
+ return;
+ }
+ data_type = CGetDrop (xevent, &data, &size, &xs, &ys);
+
+ if (data_type == DndNotDnd || xs < 0 || ys < 0 || xs >= w->width || ys >= w->height) {
+ free_data;
+ return;
+ }
+ edit_translate_xy (xs, ys, &x, &y);
+ click = edit_get_click_pos (e, x, y);
+
+ r = eval_marks (e, &start_mark, &end_mark);
+/* musn't be able to drop into a block, otherwise a single click will copy a block: */
+ if (r)
+ goto fine;
+ if (start_mark > click || click >= end_mark)
+ goto fine;
+ if (column_highlighting) {
+ if (!((x >= e->column1 && x < e->column2)
+ || (x > e->column2 && x <= e->column1)))
+ goto fine;
+ }
+ free_data;
+ return;
+ fine:
+ edit_push_action (e, KEY_PRESS + e->start_display);
+
+/* drops to the same window moving to the left: */
+ start_line = e->start_line;
+ if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
+ if ((column_highlighting && x < max (e->column1, e->column2)) || !column_highlighting) {
+ edit_block_delete_cmd (e);
+ deleted = 1;
+ }
+ edit_update_curs_row (e);
+ edit_move_display (e, start_line);
+ click = edit_get_click_pos (e, x, y); /* click pos changes with edit_block_delete_cmd() */
+ edit_cursor_move (e, click - e->curs1);
+ if (data_type == DndFile) {
+ edit_insert_file (e, (char *) data);
+ } else if (data_type != DndFiles) {
+ if (dnd_null_term_type (data_type)) {
+ int len;
+ len = strlen ((char *) data);
+ size = min (len, size);
+ }
+ if (column_highlighting) {
+ edit_insert_column_of_text (e, data, size, abs (e->column2 - e->column1));
+ } else {
+ while (size--)
+ edit_insert_ahead (e, data[size]);
+ }
+ } else {
+ while (size--)
+ edit_insert_ahead (e, data[size] ? data[size] : '\n');
+ }
+
+/* drops to the same window moving to the right: */
+ if (xevent->xclient.data.l[2] == xevent->xclient.window && !(xevent->xclient.data.l[1] & Button1Mask))
+ if (column_highlighting && !deleted)
+ edit_block_delete_cmd (e);
+
+/* The drop has now been successfully recieved. We can now send an acknowledge
+ event back to the window that send the data. When this window recieves
+ the acknowledge event, the app can decide whether or not to delete the data.
+ This allows text to be safely moved betweem text windows without the
+ risk of data being lost. In our case, drag with button1 is a copy
+ drag, while drag with any other button is a move drag (i.e. the sending
+ application must delete its selection after recieving an acknowledge
+ event). We must not, however, send an acknowledge signal if a filelist
+ (for example) was passed to us, since the sender might take this to
+ mean that all those files can be deleted! The two types we can acknowledge
+ are: */
+ if (xevent->xclient.data.l[2] != xevent->xclient.window) /* drops to the same window */
+ if (data_type == DndText || data_type == DndRawData)
+ CDropAcknowledge (xevent);
+ e->force |= REDRAW_COMPLETELY | REDRAW_LINE;
+ free_data;
+}
+
+int eh_editor (CWidget * w, XEvent * xevent, CEvent * cwevent)
+{
+ WEdit *e = w->editor;
+ int r = 0;
+ static int old_tab_spacing = -1;
+
+ if (!e)
+ return 0;
+
+ if (old_tab_spacing != option_tab_spacing)
+ e->force |= REDRAW_COMPLETELY + REDRAW_LINE;
+ old_tab_spacing = option_tab_spacing;
+
+ if (xevent->type == KeyPress) {
+ if (xevent->xkey.keycode == 0x31 && xevent->xkey.state == 0xD) {
+ CSetColor (color_palette (18));
+ CRectangle (w->winid, 0, 0, w->width, w->height);
+ }
+ }
+ switch (xevent->type) {
+ case SelectionNotify:
+ selection_paste (e, xevent->xselection.requestor, xevent->xselection.property, True);
+ r = 1;
+ break;
+ case SelectionRequest:
+ selection_send (&(xevent->xselectionrequest));
+ return 1;
+/* case SelectionClear: ---> This is handled by coolnext.c: CNextEvent() */
+ case ClientMessage:
+ handle_client_message (w, xevent, cwevent);
+ r = 1;
+ break;
+ case ButtonPress:
+ CFocus (w);
+ edit_render_tidbits (w);
+ case ButtonRelease:
+ if (xevent->xbutton.state & ControlMask)
+ column_highlighting = 1;
+ else
+ column_highlighting = 0;
+ case MotionNotify:
+ if (!xevent->xmotion.state && xevent->type == MotionNotify)
+ return 0;
+ resolve_button (xevent, cwevent);
+ edit_mouse_mark (e, xevent, cwevent);
+ break;
+ case Expose:
+ edit_render_expose (e, &(xevent->xexpose));
+ return 1;
+ case FocusIn:
+ CSetCursorColor (e->overwrite ? color_palette (24) : color_palette (19));
+ case FocusOut:
+ edit_render_tidbits (w);
+ e->force |= REDRAW_CHAR_ONLY | REDRAW_LINE;
+ edit_render_keypress (e);
+ return 1;
+ break;
+ case KeyRelease:
+ if (column_highlighting) {
+ column_highlighting = 0;
+ e->force = REDRAW_COMPLETELY | REDRAW_LINE;
+ edit_mark_cmd (e, 1);
+ }
+ break;
+ case KeyPress:
+ cwevent->ident = w->ident;
+ if (!cwevent->command && cwevent->insert < 0) { /* no translation */
+ if ((cwevent->key == XK_r || cwevent->key == XK_R) && (cwevent->state & ControlMask)) {
+ cwevent->command = e->macro_i < 0 ? CK_Begin_Record_Macro : CK_End_Record_Macro;
+ } else {
+ cwevent->command = CKeySymMod (xevent);
+ if (cwevent->command > 0)
+ cwevent->command = CK_Macro (cwevent->command);
+ else
+ break;
+ }
+ }
+ r = edit_execute_key_command (e, cwevent->command, cwevent->insert);
+ if (r)
+ edit_update_screen (e);
+ return r;
+ break;
+ case EditorCommand:
+ cwevent->ident = w->ident;
+ cwevent->command = xevent->xkey.keycode;
+ r = cwevent->handled = edit_execute_key_command (e, xevent->xkey.keycode, -1);
+ break;
+ default:
+ return 0;
+ }
+ edit_update_screen (e);
+ return r;
+}
+
+#else
+
+WEdit *wedit;
+WButtonBar *edit_bar;
+Dlg_head *edit_dlg;
+WMenu *edit_menubar;
+
+int column_highlighting = 0;
+
+static int edit_callback (Dlg_head * h, WEdit * edit, int msg, int par);
+
+static int edit_mode_callback (struct Dlg_head *h, int id, int msg)
+{
+ return 0;
+}
+
+int edit_event (WEdit * edit, Gpm_Event * event, int *result)
+{
+ *result = MOU_NORMAL;
+ edit_update_curs_row (edit);
+ edit_update_curs_col (edit);
+ if (event->type & (GPM_DOWN | GPM_DRAG | GPM_UP)) {
+ if (event->y > 1 && event->x > 0
+ && event->x <= edit->num_widget_columns
+ && event->y <= edit->num_widget_lines + 1) {
+ if (edit->mark2 != -1 && event->type & (GPM_UP | GPM_DRAG))
+ return 1; /* a lone up mustn't do anything */
+ if (event->type & (GPM_DOWN | GPM_UP))
+ edit_push_key_press (edit);
+ edit_cursor_move (edit, edit_bol (edit, edit->curs1) - edit->curs1);
+ if (--event->y > (edit->curs_row + 1))
+ edit_cursor_move (edit,
+ edit_move_forward (edit, edit->curs1, event->y - (edit->curs_row + 1), 0)
+ - edit->curs1);
+ if (event->y < (edit->curs_row + 1))
+ edit_cursor_move (edit,
+ +edit_move_backward (edit, edit->curs1, (edit->curs_row + 1) - event->y)
+ - edit->curs1);
+ edit_cursor_move (edit, (int) edit_move_forward3 (edit, edit->curs1,
+ event->x - edit->start_col - 1, 0) - edit->curs1);
+ edit->prev_col = edit_get_col (edit);
+ if (event->type & GPM_DOWN) {
+ edit_mark_cmd (edit, 1); /* reset */
+ edit->highlight = 0;
+ }
+ if (!(event->type & GPM_DRAG))
+ edit_mark_cmd (edit, 0);
+ edit->force |= REDRAW_COMPLETELY;
+ edit_update_curs_row (edit);
+ edit_update_curs_col (edit);
+ edit_update_screen (edit);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+int menubar_event (Gpm_Event * event, WMenu * menubar); /* menu.c */
+
+int edit_mouse_event (Gpm_Event * event, void *x)
+{
+ int result;
+ if (edit_event ((WEdit *) x, event, &result))
+ return result;
+ else
+ return menubar_event (event, edit_menubar);
+}
+
+extern Menu EditMenuBar[5];
+
+int edit (const char *_file, int line)
+{
+ static int made_directory = 0;
+ int framed = 0;
+ int midnight_colors[4];
+ char *text = 0;
+
+ if (option_backup_ext_int != -1) {
+ option_backup_ext = malloc (sizeof(int) + 1);
+ option_backup_ext[sizeof(int)] = '\0';
+ memcpy (option_backup_ext, (char *) &option_backup_ext_int, sizeof (int));
+ }
+
+ if (!made_directory) {
+ mkdir (catstrs (home_dir, EDIT_DIR, 0), 0700);
+ made_directory = 1;
+ }
+ if (_file) {
+ if (!(*_file)) {
+ _file = 0;
+ text = "";
+ }
+ } else
+ text = "";
+
+ if (!(wedit = edit_init (NULL, LINES - 2, COLS, _file, text, "", 0))) {
+ message (1, _(" Error "), get_error_msg (""));
+ return 0;
+ }
+ wedit->macro_i = -1;
+
+ /* Create a new dialog and add it widgets to it */
+ edit_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
+ edit_mode_callback, "[Internal File Editor]",
+ "edit",
+ DLG_NONE);
+
+ edit_dlg->raw = 1; /*so that tab = '\t' key works */
+
+ init_widget (&(wedit->widget), 0, 0, LINES - 1, COLS,
+ (callback_fn) edit_callback,
+ (destroy_fn) edit_clean,
+ (mouse_h) edit_mouse_event, 0);
+
+ widget_want_cursor (wedit->widget, 1);
+
+ edit_bar = buttonbar_new (1);
+
+ if (!framed) {
+ switch (edit_key_emulation) {
+ case EDIT_KEY_EMULATION_NORMAL:
+ edit_init_menu_normal (); /* editmenu.c */
+ break;
+ case EDIT_KEY_EMULATION_EMACS:
+ edit_init_menu_emacs (); /* editmenu.c */
+ break;
+ }
+ edit_menubar = menubar_new (0, 0, COLS, EditMenuBar, N_menus);
+ }
+ add_widget (edit_dlg, wedit);
+
+ if (!framed)
+ add_widget (edit_dlg, edit_menubar);
+
+ add_widget (edit_dlg, edit_bar);
+ edit_move_display (wedit, line - 1);
+ edit_move_to_line (wedit, line - 1);
+
+ run_dlg (edit_dlg);
+
+ if (!framed)
+ edit_done_menu (); /* editmenu.c */
+
+ destroy_dlg (edit_dlg);
+
+ return 1;
+}
+
+static void edit_my_define (Dlg_head * h, int idx, char *text,
+ void (*fn) (WEdit *), WEdit * edit)
+{
+ define_label_data (h, (Widget *) edit, idx, text, (buttonbarfn) fn, edit);
+}
+
+
+void cmd_F1 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (1));
+}
+
+void cmd_F2 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (2));
+}
+
+void cmd_F3 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (3));
+}
+
+void cmd_F4 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (4));
+}
+
+void cmd_F5 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (5));
+}
+
+void cmd_F6 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (6));
+}
+
+void cmd_F7 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (7));
+}
+
+void cmd_F8 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (8));
+}
+
+void cmd_F9 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (9));
+}
+
+void cmd_F10 (WEdit * edit)
+{
+ send_message (edit->widget.parent, (Widget *) edit, WIDGET_KEY, KEY_F (10));
+}
+
+void edit_labels (WEdit * edit)
+{
+ Dlg_head *h = edit->widget.parent;
+
+ edit_my_define (h, 1, _("Help"), cmd_F1, edit);
+ edit_my_define (h, 2, _("Save"), cmd_F2, edit);
+ edit_my_define (h, 3, _("Mark"), cmd_F3, edit);
+ edit_my_define (h, 4, _("Replac"), cmd_F4, edit);
+ edit_my_define (h, 5, _("Copy"), cmd_F5, edit);
+ edit_my_define (h, 6, _("Move"), cmd_F6, edit);
+ edit_my_define (h, 7, _("Search"), cmd_F7, edit);
+ edit_my_define (h, 8, _("Delete"), cmd_F8, edit);
+ if (!edit->have_frame)
+ edit_my_define (h, 9, _("PullDn"), edit_menu_cmd, edit);
+ edit_my_define (h, 10, _("Quit"), cmd_F10, edit);
+
+ redraw_labels (h, (Widget *) edit);
+}
+
+
+long get_key_state ()
+{
+ return (long) get_modifier ();
+}
+
+void edit_adjust_size (Dlg_head * h)
+{
+ WEdit *edit;
+ WButtonBar *edit_bar;
+
+ edit = (WEdit *) find_widget_type (h, (callback_fn) edit_callback);
+ edit_bar = (WButtonBar *) edit->widget.parent->current->next->widget;
+ widget_set_size (&edit->widget, 0, 0, LINES - 1, COLS);
+ widget_set_size (&edit_bar->widget, LINES - 1, 0, 1, COLS);
+ widget_set_size (&edit_menubar->widget, 0, 0, 1, COLS);
+
+#ifdef RESIZABLE_MENUBAR
+ menubar_arrange(edit_menubar);
+#endif
+}
+
+void edit_update_screen (WEdit * e)
+{
+ edit_scroll_screen_over_cursor (e);
+
+ edit_update_curs_col (e);
+ edit_status (e);
+
+/* pop all events for this window for internal handling */
+
+ if (!is_idle ()) {
+ e->force |= REDRAW_PAGE;
+ return;
+ }
+ if (e->force & REDRAW_COMPLETELY)
+ e->force |= REDRAW_PAGE;
+ edit_render_keypress (e);
+}
+
+static int edit_callback (Dlg_head * h, WEdit * e, int msg, int par)
+{
+ switch (msg) {
+ case WIDGET_INIT:
+ e->force |= REDRAW_COMPLETELY;
+ edit_labels (e);
+ break;
+ case WIDGET_DRAW:
+ e->force |= REDRAW_COMPLETELY;
+ e->num_widget_lines = LINES - 2;
+ e->num_widget_columns = COLS;
+ case WIDGET_FOCUS:
+ edit_update_screen (e);
+ return 1;
+ case WIDGET_KEY:{
+ int cmd, ch;
+ if (edit_drop_hotkey_menu (e, par)) /* first check alt-f, alt-e, alt-s, etc for drop menus */
+ return 1;
+ if (!edit_translate_key (e, 0, par, get_key_state (), &cmd, &ch))
+ return 0;
+ edit_execute_key_command (e, cmd, ch);
+ edit_update_screen (e);
+ }
+ return 1;
+ case WIDGET_COMMAND:
+ edit_execute_key_command (e, par, -1);
+ edit_update_screen (e);
+ return 1;
+ case WIDGET_CURSOR:
+ widget_move (&e->widget, e->curs_row + EDIT_TEXT_VERTICAL_OFFSET, e->curs_col + e->start_col);
+ return 1;
+ }
+ return default_proc (h, msg, par);
+}
+
+#endif
--- /dev/null
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+rootdir = $(srcdir)/..
+@MCFG@@MCF@
+
+CFLAGS = $(XCFLAGS)
+CPPFLAGS = $(XCPPFLAGS)
+LDFLAGS = $(XLDFLAGS)
+DEFS = $(XDEFS)
+LIBS = @SHADOWLIB@ $(XLIBS) @TERMNET@ @PAMLIBS@ $(XLIB)
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+AR = @AR@
+
+#
+# Distribution variables
+#
+
+EDITSRC = edit.c editcmd.c editwidget.c edit_key_translator.c editdraw.c \
+ edit.h editmenu.c editcmddef.h wordproc.c syntax.c editoptions.c
+
+EDITOBJS = edit.o editcmd.o editwidget.o editdraw.o editmenu.o wordproc.o \
+ syntax.o editoptions.o
+
+DIST = Makefile.in README.edit $(EDITSRC)
+
+all: @LIBEDIT_A@
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) -DMIDNIGHT $<
+
+check:
+ @echo no tests are supplied.
+
+libedit.a: $(EDITOBJS)
+ $(RMF) $@
+ $(AR) cr $@ $(EDITOBJS)
+ -$(RANLIB) $@
+
+mcedit:
+ -$(RMF) $(DESTDIR)$(bindir)/$(binprefix)mcedit
+ $(LN_S) mc $(DESTDIR)$(bindir)/$(binprefix)mcedit
+
+showlibdep:
+ @echo 'OBJS="$(EDITOBJS)"'
+
+cross:
+ $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \
+ CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses "
+
+TAGS: $(EDITSRC)
+ etags $(EDITSRC)
+
+clean:
+ $(RMF) *.o core a.out libedit.a
+
+realclean: clean
+ $(RMF) .depend
+ $(RMF) TAGS
+ $(RMF) *~
+
+distclean:
+ -$(RMF) $(srcdir)/*~ $(srcdir)/*.o $(srcdir)/a.out
+ -$(RMF) $(srcdir)/core $(srcdir)/libedit.a
+ -if test $(srcdir) = .; then $(MAKE) realclean; fi
+ -$(RMF) $(srcdir)/Makefile
+
+install: @MCEDIT@
+
+uninstall:
+ -$(RMF) $(DESTDIR)$(bindir)/$(binprefix)mcedit
+
+distcopy:
+ $(CP) $(DIST) ../../mc-$(VERSION)/edit
+
+depend dep: mcdep
+
+fastdeploc:
+
+# ***Dependencies***Do not edit***
+@DOTDEPEND@
+# ***End of dependencies***
--- /dev/null
+/* editor syntax highlighting.
+
+ Copyright (C) 1996, 1997, 1998 the Free Software Foundation
+
+ Authors: 1998 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#ifdef MIDNIGHT
+#include "edit.h"
+#else
+#include "coolwidget.h"
+#endif
+
+#if !defined(MIDNIGHT) || defined(HAVE_SYNTAXH)
+
+int option_syntax_highlighting = 1;
+
+/* these three functions are called from the outside */
+void edit_load_syntax (WEdit * edit, char **names, char *type);
+void edit_free_syntax_rules (WEdit * edit);
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg);
+
+static void *syntax_malloc (size_t x)
+{
+ void *p;
+ p = malloc (x);
+ memset (p, 0, x);
+ return p;
+}
+
+#define syntax_free(x) {if(x){free(x);(x)=0;}}
+
+static int compare_word_to_right (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
+{
+ char *p;
+ int c, j;
+ if (!*text)
+ return 0;
+ c = edit_get_byte (edit, i - 1);
+ if (line_start)
+ if (c != '\n')
+ return 0;
+ if (whole_left)
+ if (strchr (whole_left, c))
+ return 0;
+ for (p = text; *p; p++, i++) {
+ switch (*p) {
+ case '\001':
+ p++;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == *p)
+ break;
+ if (c == '\n')
+ return 0;
+ i++;
+ }
+ break;
+ case '\002':
+ p++;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == *p)
+ break;
+ if (c == '\n' || c == '\t' || c == ' ')
+ return 0;
+ i++;
+ }
+ break;
+ case '\003':
+ p++;
+#if 0
+ c = edit_get_byte (edit, i++);
+ for (j = 0; p[j] != '\003'; j++)
+ if (c == p[j])
+ goto found_char1;
+ return 0;
+ found_char1:
+#endif
+ for (;;i++) {
+ c = edit_get_byte (edit, i);
+ for (j = 0; p[j] != '\003'; j++)
+ if (c == p[j])
+ goto found_char2;
+ break;
+ found_char2:;
+ }
+ i--;
+ while (*p != '\003')
+ p++;
+ break;
+#if 0
+ case '\004':
+ p++;
+ c = edit_get_byte (edit, i++);
+ for (j = 0; p[j] != '\004'; j++)
+ if (c == p[j])
+ return 0;
+ for (;;i++) {
+ c = edit_get_byte (edit, i);
+ for (j = 0; p[j] != '\004'; j++)
+ if (c == p[j])
+ goto found_char4;
+ continue;
+ found_char4:
+ break;
+ }
+ i--;
+ while (*p != '\004')
+ p++;
+ break;
+#endif
+ default:
+ if (*p != edit_get_byte (edit, i))
+ return 0;
+ }
+ }
+ if (whole_right)
+ if (strchr (whole_right, edit_get_byte (edit, i)))
+ return 0;
+ return 1;
+}
+
+static int compare_word_to_left (WEdit * edit, long i, char *text, char *whole_left, char *whole_right, int line_start)
+{
+ char *p;
+ int c, j;
+#if 0
+ int d;
+#endif
+ if (!*text)
+ return 0;
+ if (whole_right)
+ if (strchr (whole_right, edit_get_byte (edit, i + 1)))
+ return 0;
+ for (p = text + strlen (text) - 1; (unsigned long) p >= (unsigned long) text; p--, i--) {
+ switch (*p) {
+ case '\001':
+ p--;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == *p)
+ break;
+ if (c == '\n')
+ return 0;
+ i--;
+ }
+ break;
+ case '\002':
+ p--;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == *p)
+ break;
+ if (c == '\n' || c == '\t' || c == ' ')
+ return 0;
+ i--;
+ }
+ break;
+ case '\003':
+ while (*(--p) != '\003');
+ p++;
+#if 0
+ c = edit_get_byte (edit, i--);
+ for (j = 0; p[j] != '\003'; j++)
+ if (c == p[j])
+ goto found_char1;
+ return 0;
+ found_char1:
+#endif
+ for (;; i--) {
+ c = edit_get_byte (edit, i);
+ for (j = 0; p[j] != '\003'; j++)
+ if (c == p[j])
+ goto found_char2;
+ break;
+ found_char2:;
+ }
+ i++;
+ p--;
+ break;
+#if 0
+ case '\004':
+ while (*(--p) != '\004');
+ d = *p;
+ p++;
+ c = edit_get_byte (edit, i--);
+ for (j = 0; p[j] != '\004'; j++)
+ if (c == p[j])
+ return 0;
+ for (;; i--) {
+ c = edit_get_byte (edit, i);
+ for (j = 0; p[j] != '\004'; j++)
+ if (c == p[j] || c == '\n' || c == d)
+ goto found_char4;
+ continue;
+ found_char4:
+ break;
+ }
+ i++;
+ p--;
+ break;
+#endif
+ default:
+ if (*p != edit_get_byte (edit, i))
+ return 0;
+ }
+ }
+ c = edit_get_byte (edit, i);
+ if (line_start)
+ if (c != '\n')
+ return 0;
+ if (whole_left)
+ if (strchr (whole_left, c))
+ return 0;
+ return 1;
+}
+
+
+#if 0
+#define debug_printf(x,y) fprintf(stderr,x,y)
+#else
+#define debug_printf(x,y)
+#endif
+
+static inline unsigned long apply_rules_going_right (WEdit * edit, long i, unsigned long rule)
+{
+ struct context_rule *r;
+ int context, contextchanged = 0, keyword, c1, c2;
+ int found_right = 0, found_left = 0, keyword_foundleft = 0;
+ int done = 0;
+ unsigned long border;
+ context = (rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT;
+ keyword = (rule & RULE_WORD) >> RULE_WORD_SHIFT;
+ border = rule & (RULE_ON_LEFT_BORDER | RULE_ON_RIGHT_BORDER);
+ c1 = edit_get_byte (edit, i - 1);
+ c2 = edit_get_byte (edit, i);
+ if (!c2 || !c1)
+ return rule;
+
+ debug_printf ("%c->", c1);
+ debug_printf ("%c ", c2);
+
+/* check to turn off a keyword */
+ if (keyword) {
+ struct key_word *k;
+ k = edit->rules[context]->keyword[keyword];
+ if (c1 == '\n')
+ keyword = 0;
+ if (k->last == c1 && compare_word_to_left (edit, i - 1, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = 0;
+ keyword_foundleft = 1;
+ debug_printf ("keyword=%d ", keyword);
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off");
+
+/* check to turn off a context */
+ if (context && !keyword) {
+ r = edit->rules[context];
+ if (r->first_right == c2 && compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right) \
+ &&!(rule & RULE_ON_RIGHT_BORDER)) {
+ debug_printf ("A:3 ", 0);
+ found_right = 1;
+ border = RULE_ON_RIGHT_BORDER;
+ if (r->between_delimiters)
+ context = 0;
+ } else if (!found_left) {
+ if (r->last_right == c1 && compare_word_to_left (edit, i - 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right) \
+ &&(rule & RULE_ON_RIGHT_BORDER)) {
+/* always turn off a context at 4 */
+ debug_printf ("A:4 ", 0);
+ found_left = 1;
+ border = 0;
+ if (!keyword_foundleft)
+ context = 0;
+ } else if (r->last_left == c1 && compare_word_to_left (edit, i - 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left) \
+ &&(rule & RULE_ON_LEFT_BORDER)) {
+/* never turn off a context at 2 */
+ debug_printf ("A:2 ", 0);
+ found_left = 1;
+ border = 0;
+ }
+ }
+ }
+ debug_printf ("\n", 0);
+
+/* check to turn on a keyword */
+ if (!keyword) {
+ char *p;
+ p = (r = edit->rules[context])->keyword_first_chars;
+ while ((p = strchr (p + 1, c2))) {
+ struct key_word *k;
+ int count;
+ count = (unsigned long) p - (unsigned long) r->keyword_first_chars;
+ k = r->keyword[count];
+ if (compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = count;
+ debug_printf ("keyword=%d ", keyword);
+ break;
+ }
+ }
+ }
+/* check to turn on a context */
+ if (!context) {
+ int count;
+ for (count = 1; edit->rules[count] && !done; count++) {
+ r = edit->rules[count];
+ if (!found_left) {
+ if (r->last_right == c1 && compare_word_to_left (edit, i - 1, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right) \
+ &&(rule & RULE_ON_RIGHT_BORDER)) {
+ debug_printf ("B:4 count=%d", count);
+ found_left = 1;
+ border = 0;
+ context = 0;
+ contextchanged = 1;
+ keyword = 0;
+ } else if (r->last_left == c1 && compare_word_to_left (edit, i - 1, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left) \
+ &&(rule & RULE_ON_LEFT_BORDER)) {
+ debug_printf ("B:2 ", 0);
+ found_left = 1;
+ border = 0;
+ if (r->between_delimiters) {
+ context = count;
+ contextchanged = 1;
+ keyword = 0;
+ debug_printf ("context=%d ", context);
+ if (r->first_right == c2 && compare_word_to_right (edit, i, r->right, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_right)) {
+ debug_printf ("B:3 ", 0);
+ found_right = 1;
+ border = RULE_ON_RIGHT_BORDER;
+ context = 0;
+ }
+ }
+ break;
+ }
+ }
+ if (!found_right) {
+ if (r->first_left == c2 && compare_word_to_right (edit, i, r->left, r->whole_word_chars_left, r->whole_word_chars_right, r->line_start_left)) {
+ debug_printf ("B:1 ", 0);
+ found_right = 1;
+ border = RULE_ON_LEFT_BORDER;
+ if (!r->between_delimiters) {
+ debug_printf ("context=%d ", context);
+ if (!keyword)
+ context = count;
+ }
+ break;
+ }
+ }
+ }
+ }
+ if (!keyword && contextchanged) {
+ char *p;
+ p = (r = edit->rules[context])->keyword_first_chars;
+ while ((p = strchr (p + 1, c2))) {
+ struct key_word *k;
+ int coutner;
+ coutner = (unsigned long) p - (unsigned long) r->keyword_first_chars;
+ k = r->keyword[coutner];
+ if (compare_word_to_right (edit, i, k->keyword, k->whole_word_chars_left, k->whole_word_chars_right, k->line_start)) {
+ keyword = coutner;
+ debug_printf ("keyword=%d ", keyword);
+ break;
+ }
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_LEFT_BORDER) ? "left" : "right") : "off");
+ debug_printf ("keyword=%d ", keyword);
+
+ debug_printf (" %d#\n\n", context);
+
+ return (context << RULE_CONTEXT_SHIFT) | (keyword << RULE_WORD_SHIFT) | border;
+}
+
+static inline int resolve_left_delim (WEdit * edit, long i, struct context_rule *r, int s)
+{
+ int c, count;
+ if (!r->conflicts)
+ return s;
+ for (;;) {
+ c = edit_get_byte (edit, i);
+ if (c == '\n')
+ break;
+ for (count = 1; r->conflicts[count]; count++) {
+ struct context_rule *p;
+ p = edit->rules[r->conflicts[count]];
+ if (!p)
+ break;
+ if (p->first_left == c && r->between_delimiters == p->between_delimiters && compare_word_to_right (edit, i, p->left, p->whole_word_chars_left, r->whole_word_chars_right, p->line_start_left))
+ return r->conflicts[count];
+ }
+ i--;
+ }
+ return 0;
+}
+
+static inline unsigned long apply_rules_going_left (WEdit * edit, long i, unsigned long rule)
+{
+ struct context_rule *r;
+ int context, contextchanged = 0, keyword, c2, c1;
+ int found_left = 0, found_right = 0, keyword_foundright = 0;
+ int done = 0;
+ unsigned long border;
+ context = (rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT;
+ keyword = (rule & RULE_WORD) >> RULE_WORD_SHIFT;
+ border = rule & (RULE_ON_RIGHT_BORDER | RULE_ON_LEFT_BORDER);
+ c1 = edit_get_byte (edit, i);
+ c2 = edit_get_byte (edit, i + 1);
+ if (!c2 || !c1)
+ return rule;
+
+ debug_printf ("%c->", c2);
+ debug_printf ("%c ", c1);
+
+/* check to turn off a keyword */
+ if (keyword) {
+ struct key_word *k;
+ k = edit->rules[context]->keyword[keyword];
+ if (c2 == '\n')
+ keyword = 0;
+ if ((k->first == c2 && compare_word_to_right (edit, i + 1, k->keyword, k->whole_word_chars_right, k->whole_word_chars_left, k->line_start)) || (c2 == '\n')) {
+ keyword = 0;
+ keyword_foundright = 1;
+ debug_printf ("keyword=%d ", keyword);
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_RIGHT_BORDER) ? "right" : "left") : "off");
+
+/* check to turn off a context */
+ if (context && !keyword) {
+ r = edit->rules[context];
+ if (r->last_left == c1 && compare_word_to_left (edit, i, r->left, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_left) \
+ &&!(rule & RULE_ON_LEFT_BORDER)) {
+ debug_printf ("A:2 ", 0);
+ found_left = 1;
+ border = RULE_ON_LEFT_BORDER;
+ if (r->between_delimiters)
+ context = 0;
+ } else if (!found_right) {
+ if (r->first_left == c2 && compare_word_to_right (edit, i + 1, r->left, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_left) \
+ &&(rule & RULE_ON_LEFT_BORDER)) {
+/* always turn off a context at 4 */
+ debug_printf ("A:1 ", 0);
+ found_right = 1;
+ border = 0;
+ if (!keyword_foundright)
+ context = 0;
+ } else if (r->first_right == c2 && compare_word_to_right (edit, i + 1, r->right, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_right) \
+ &&(rule & RULE_ON_RIGHT_BORDER)) {
+/* never turn off a context at 2 */
+ debug_printf ("A:3 ", 0);
+ found_right = 1;
+ border = 0;
+ }
+ }
+ }
+ debug_printf ("\n", 0);
+
+/* check to turn on a keyword */
+ if (!keyword) {
+ char *p;
+ p = (r = edit->rules[context])->keyword_last_chars;
+ while ((p = strchr (p + 1, c1))) {
+ struct key_word *k;
+ int count;
+ count = (unsigned long) p - (unsigned long) r->keyword_last_chars;
+ k = r->keyword[count];
+ if (compare_word_to_left (edit, i, k->keyword, k->whole_word_chars_right, k->whole_word_chars_left, k->line_start)) {
+ keyword = count;
+ debug_printf ("keyword=%d ", keyword);
+ break;
+ }
+ }
+ }
+/* check to turn on a context */
+ if (!context) {
+ int count;
+ for (count = 1; edit->rules[count] && !done; count++) {
+ r = edit->rules[count];
+ if (!found_right) {
+ if (r->first_left == c2 && compare_word_to_right (edit, i + 1, r->left, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_left) \
+ &&(rule & RULE_ON_LEFT_BORDER)) {
+ debug_printf ("B:1 count=%d", count);
+ found_right = 1;
+ border = 0;
+ context = 0;
+ contextchanged = 1;
+ keyword = 0;
+ } else if (r->first_right == c2 && compare_word_to_right (edit, i + 1, r->right, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_right) \
+ &&(rule & RULE_ON_RIGHT_BORDER)) {
+ if (!(c2 == '\n' && r->single_char)) {
+ debug_printf ("B:3 ", 0);
+ found_right = 1;
+ border = 0;
+ if (r->between_delimiters) {
+ debug_printf ("context=%d ", context);
+ context = resolve_left_delim (edit, i, r, count);
+ contextchanged = 1;
+ keyword = 0;
+ if (r->last_left == c1 && compare_word_to_left (edit, i, r->left, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_left)) {
+ debug_printf ("B:2 ", 0);
+ found_left = 1;
+ border = RULE_ON_LEFT_BORDER;
+ context = 0;
+ }
+ }
+ break;
+ }
+ }
+ }
+ if (!found_left) {
+ if (r->last_right == c1 && compare_word_to_left (edit, i, r->right, r->whole_word_chars_right, r->whole_word_chars_left, r->line_start_right)) {
+ if (!(c1 == '\n' && r->single_char)) {
+ debug_printf ("B:4 ", 0);
+ found_left = 1;
+ border = RULE_ON_RIGHT_BORDER;
+ if (!keyword)
+ if (!r->between_delimiters)
+ context = resolve_left_delim (edit, i - 1, r, count);
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (!keyword && contextchanged) {
+ char *p;
+ p = (r = edit->rules[context])->keyword_last_chars;
+ while ((p = strchr (p + 1, c1))) {
+ struct key_word *k;
+ int coutner;
+ coutner = (unsigned long) p - (unsigned long) r->keyword_last_chars;
+ k = r->keyword[coutner];
+ if (compare_word_to_left (edit, i, k->keyword, k->whole_word_chars_right, k->whole_word_chars_left, k->line_start)) {
+ keyword = coutner;
+ debug_printf ("keyword=%d ", keyword);
+ break;
+ }
+ }
+ }
+ debug_printf ("border=%s ", border ? ((border & RULE_ON_RIGHT_BORDER) ? "right" : "left") : "off");
+ debug_printf ("keyword=%d ", keyword);
+
+ debug_printf (" %d#\n\n", context);
+
+ return (context << RULE_CONTEXT_SHIFT) | (keyword << RULE_WORD_SHIFT) | border;
+}
+
+
+static unsigned long edit_get_rule (WEdit * edit, long byte_index)
+{
+ long i;
+ if (byte_index < 0) {
+ edit->last_get_rule = -1;
+ edit->rule = 0;
+ return 0;
+ }
+#if 0
+ if (byte_index < edit->last_get_rule_start_display) {
+/* this is for optimisation */
+ for (i = edit->last_get_rule_start_display - 1; i >= byte_index; i--)
+ edit->rule_start_display = apply_rules_going_left (edit, i, edit->rule_start_display);
+ edit->last_get_rule_start_display = byte_index;
+ edit->rule = edit->rule_start_display;
+ } else
+#endif
+ if (byte_index > edit->last_get_rule) {
+ for (i = edit->last_get_rule + 1; i <= byte_index; i++)
+ edit->rule = apply_rules_going_right (edit, i, edit->rule);
+ } else if (byte_index < edit->last_get_rule) {
+ for (i = edit->last_get_rule - 1; i >= byte_index; i--)
+ edit->rule = apply_rules_going_left (edit, i, edit->rule);
+ }
+ edit->last_get_rule = byte_index;
+ return edit->rule;
+}
+
+static void translate_rule_to_color (WEdit * edit, unsigned long rule, int *fg, int *bg)
+{
+ struct key_word *k;
+ k = edit->rules[(rule & RULE_CONTEXT) >> RULE_CONTEXT_SHIFT]->keyword[(rule & RULE_WORD) >> RULE_WORD_SHIFT];
+ *bg = k->bg;
+ *fg = k->fg;
+}
+
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
+{
+ unsigned long rule;
+ if (!edit->rules || byte_index >= edit->last_byte || !option_syntax_highlighting) {
+#ifdef MIDNIGHT
+ *fg = NORMAL_COLOR;
+#else
+ *fg = NO_COLOR;
+ *bg = NO_COLOR;
+#endif
+ } else {
+ rule = edit_get_rule (edit, byte_index);
+ translate_rule_to_color (edit, rule, fg, bg);
+ }
+}
+
+
+/*
+ Returns 0 on error/eof or a count of the number of bytes read
+ including the newline. Result must be free'd.
+ */
+static int read_one_line (char **line, FILE * f)
+{
+ char *p;
+ int len = 256, c, r = 0, i = 0;
+ p = syntax_malloc (len);
+ for (;;) {
+ c = fgetc (f);
+ if (c == -1) {
+ r = 0;
+ break;
+ } else if (c == '\n') {
+ r = i + 1; /* extra 1 for the newline just read */
+ break;
+ } else {
+ if (i >= len - 1) {
+ char *q;
+ q = syntax_malloc (len * 2);
+ memcpy (q, p, len);
+ syntax_free (p);
+ p = q;
+ len *= 2;
+ }
+ p[i++] = c;
+ }
+ }
+ p[i] = 0;
+ *line = p;
+ return r;
+}
+
+static char *strdup_convert (char *s)
+{
+#if 0
+ int e = 0;
+#endif
+ char *r, *p;
+ p = r = strdup (s);
+ while (*s) {
+ switch (*s) {
+ case '\\':
+ s++;
+ switch (*s) {
+ case 'n':
+ *p = '\n';
+ break;
+ case 'r':
+ *p = '\r';
+ break;
+ case 't':
+ *p = '\t';
+ break;
+ case 's':
+ *p = ' ';
+ break;
+ case '*':
+ *p = '*';
+ break;
+ case '\\':
+ *p = '\\';
+ break;
+ case '[':
+ case ']':
+ if ((unsigned long) p == (unsigned long) r || strlen (s) == 1)
+ *p = *s;
+ else {
+#if 0
+ if (!strncmp (s, "[^", 2)) {
+ *p = '\004';
+ e = 1;
+ s++;
+ } else {
+ if (e)
+ *p = '\004';
+ else
+#endif
+ *p = '\003';
+#if 0
+ e = 0;
+ }
+#endif
+ }
+ break;
+ default:
+ *p = *s;
+ break;
+ }
+ break;
+ case '*':
+/* a * or + at the beginning or end of the line must be interpreted literally */
+ if ((unsigned long) p == (unsigned long) r || strlen (s) == 1)
+ *p = '*';
+ else
+ *p = '\001';
+ break;
+ case '+':
+ if ((unsigned long) p == (unsigned long) r || strlen (s) == 1)
+ *p = '+';
+ else
+ *p = '\002';
+ break;
+ default:
+ *p = *s;
+ break;
+ }
+ s++;
+ p++;
+ }
+ *p = 0;
+ return r;
+}
+
+#define whiteness(x) ((x) == '\t' || (x) == '\n' || (x) == ' ')
+
+static void get_args (char *l, char **args, int *argc)
+{
+ *argc = 0;
+ l--;
+ for (;;) {
+ char *p;
+ for (p = l + 1; *p && whiteness (*p); p++);
+ if (!*p)
+ break;
+ for (l = p + 1; *l && !whiteness (*l); l++);
+ *l = '\0';
+ *args = strdup_convert (p);
+ (*argc)++;
+ args++;
+ }
+ *args = 0;
+}
+
+static void free_args (char **args)
+{
+ while (*args) {
+ syntax_free (*args);
+ *args = 0;
+ args++;
+ }
+}
+
+#define check_a {if(!*a){result=line;break;}}
+#define check_not_a {if(*a){result=line;break;}}
+
+#ifdef MIDNIGHT
+
+int try_alloc_color_pair (char *fg, char *bg);
+
+int this_try_alloc_color_pair (char *fg, char *bg)
+{
+ char f[80], b[80], *p;
+ if (fg) {
+ strcpy (f, fg);
+ p = strchr (f, '/');
+ if (p)
+ *p = '\0';
+ fg = f;
+ }
+ if (bg) {
+ strcpy (b, bg);
+ p = strchr (b, '/');
+ if (p)
+ *p = '\0';
+ bg = b;
+ }
+ return try_alloc_color_pair (fg, bg);
+}
+#else
+int this_allocate_color (char *fg)
+{
+ char *p;
+ if (!fg)
+ return allocate_color (0);
+ p = strchr (fg, '/');
+ if (!p)
+ return allocate_color (fg);
+ return allocate_color (p + 1);
+}
+#endif
+
+/* returns line number on error */
+static int edit_read_syntax_rules (WEdit * edit, FILE * f)
+{
+ char *fg, *bg;
+ char whole_right[256];
+ char whole_left[256];
+ char *args[1024], *l = 0;
+ int line = 0;
+ struct context_rule **r, *c;
+ int num_words = -1, num_contexts = -1;
+ int argc, result = 0;
+ int i, j;
+
+ args[0] = 0;
+
+ strcpy (whole_left, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
+ strcpy (whole_right, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_01234567890");
+
+ r = edit->rules = syntax_malloc (256 * sizeof (struct context_rule *));
+
+ for (;;) {
+ char **a;
+ line++;
+ if (!read_one_line (&l, f))
+ break;
+ get_args (l, args, &argc);
+ a = args + 1;
+ if (!args[0]) {
+ /* do nothing */
+ } else if (!strcmp (args[0], "wholechars")) {
+ check_a;
+ if (!strcmp (*a, "left")) {
+ a++;
+ strcpy (whole_left, *a);
+ } else if (!strcmp (*a, "right")) {
+ a++;
+ strcpy (whole_right, *a);
+ } else {
+ strcpy (whole_left, *a);
+ strcpy (whole_right, *a);
+ }
+ a++;
+ check_not_a;
+ } else if (!strcmp (args[0], "context")) {
+ check_a;
+ if (num_contexts == -1) {
+ if (strcmp (*a, "default")) { /* first context is the default */
+ *a = 0;
+ check_a;
+ }
+ a++;
+ c = r[0] = syntax_malloc (sizeof (struct context_rule));
+ c->left = strdup (" ");
+ c->right = strdup (" ");
+ num_contexts = 0;
+ } else {
+ c = r[num_contexts] = syntax_malloc (sizeof (struct context_rule));
+ if (!strcmp (*a, "exclusive")) {
+ a++;
+ c->between_delimiters = 1;
+ }
+ check_a;
+ if (!strcmp (*a, "whole")) {
+ a++;
+ c->whole_word_chars_left = strdup (whole_left);
+ c->whole_word_chars_right = strdup (whole_right);
+ } else if (!strcmp (*a, "wholeleft")) {
+ a++;
+ c->whole_word_chars_left = strdup (whole_left);
+ } else if (!strcmp (*a, "wholeright")) {
+ a++;
+ c->whole_word_chars_right = strdup (whole_right);
+ }
+ check_a;
+ if (!strcmp (*a, "linestart")) {
+ a++;
+ c->line_start_left = 1;
+ }
+ check_a;
+ c->left = strdup (*a++);
+ check_a;
+ if (!strcmp (*a, "linestart")) {
+ a++;
+ c->line_start_right = 1;
+ }
+ check_a;
+ c->right = strdup (*a++);
+ c->last_left = c->left[strlen (c->left) - 1];
+ c->last_right = c->right[strlen (c->right) - 1];
+ c->first_left = *c->left;
+ c->first_right = *c->right;
+ c->single_char = (strlen (c->right) == 1);
+ }
+ c->keyword = syntax_malloc (1024 * sizeof (struct key_word *));
+ num_words = 1;
+ c->keyword[0] = syntax_malloc (sizeof (struct key_word));
+ fg = *a;
+ if (*a)
+ a++;
+ bg = *a;
+ if (*a)
+ a++;
+#ifdef MIDNIGHT
+ c->keyword[0]->fg = this_try_alloc_color_pair (fg, bg);
+#else
+ c->keyword[0]->fg = this_allocate_color (fg);
+ c->keyword[0]->bg = this_allocate_color (bg);
+#endif
+ c->keyword[0]->keyword = strdup (" ");
+ check_not_a;
+ num_contexts++;
+ } else if (!strcmp (args[0], "keyword")) {
+ struct key_word *k;
+ if (num_words == -1)
+ *a = 0;
+ check_a;
+ k = r[num_contexts - 1]->keyword[num_words] = syntax_malloc (sizeof (struct key_word));
+ if (!strcmp (*a, "whole")) {
+ a++;
+ k->whole_word_chars_left = strdup (whole_left);
+ k->whole_word_chars_right = strdup (whole_right);
+ } else if (!strcmp (*a, "wholeleft")) {
+ a++;
+ k->whole_word_chars_left = strdup (whole_left);
+ } else if (!strcmp (*a, "wholeright")) {
+ a++;
+ k->whole_word_chars_right = strdup (whole_right);
+ }
+ check_a;
+ if (!strcmp (*a, "linestart")) {
+ a++;
+ k->line_start = 1;
+ }
+ check_a;
+ if (!strcmp (*a, "whole")) {
+ *a = 0;
+ check_a;
+ }
+ k->keyword = strdup (*a++);
+ k->last = k->keyword[strlen (k->keyword) - 1];
+ k->first = *k->keyword;
+ fg = *a;
+ if (*a)
+ a++;
+ bg = *a;
+ if (*a)
+ a++;
+#ifdef MIDNIGHT
+ k->fg = this_try_alloc_color_pair (fg, bg);
+#else
+ k->fg = this_allocate_color (fg);
+ k->bg = this_allocate_color (bg);
+#endif
+ check_not_a;
+ num_words++;
+ } else if (!strncmp (args[0], "#", 1)) {
+ /* do nothing for comment */
+ } else if (!strcmp (args[0], "file")) {
+ break;
+ } else { /* anything else is an error */
+ *a = 0;
+ check_a;
+ }
+ free_args (args);
+ syntax_free (l);
+ }
+ free_args (args);
+ syntax_free (l);
+
+ if (result)
+ return result;
+
+ if (num_contexts == -1) {
+ result = line;
+ return result;
+ }
+ for (i = 1; edit->rules[i]; i++) {
+ for (j = i + 1; edit->rules[j]; j++) {
+ if (strstr (edit->rules[j]->right, edit->rules[i]->right) && strcmp (edit->rules[i]->right, "\n")) {
+ unsigned char *s;
+ if (!edit->rules[i]->conflicts)
+ edit->rules[i]->conflicts = syntax_malloc (sizeof (unsigned char) * 260);
+ s = edit->rules[i]->conflicts;
+ s[strlen ((char *) s)] = (unsigned char) j;
+ }
+ }
+ }
+
+ {
+ char first_chars[1024], *p;
+ char last_chars[1024], *q;
+ for (i = 0; edit->rules[i]; i++) {
+ c = edit->rules[i];
+ p = first_chars;
+ q = last_chars;
+ *p++ = (char) 1;
+ *q++ = (char) 1;
+ for (j = 1; c->keyword[j]; j++) {
+ *p++ = c->keyword[j]->first;
+ *q++ = c->keyword[j]->last;
+ }
+ *p = '\0';
+ *q = '\0';
+ c->keyword_first_chars = strdup (first_chars);
+ c->keyword_last_chars = strdup (last_chars);
+ }
+ }
+
+ return result;
+}
+
+void (*syntax_change_callback) (CWidget *) = 0;
+
+void edit_set_syntax_change_callback (void (*callback) (CWidget *))
+{
+ syntax_change_callback = callback;
+}
+
+void edit_free_syntax_rules (WEdit * edit)
+{
+ int i, j;
+ if (!edit)
+ return;
+ if (!edit->rules)
+ return;
+ syntax_free (edit->syntax_type);
+ if (syntax_change_callback)
+#ifdef MIDNIGHT
+ (*syntax_change_callback) (&edit->widget);
+#else
+ (*syntax_change_callback) (edit->widget);
+#endif
+ for (i = 0; edit->rules[i]; i++) {
+ if (edit->rules[i]->keyword) {
+ for (j = 0; edit->rules[i]->keyword[j]; j++) {
+ syntax_free (edit->rules[i]->keyword[j]->keyword);
+ syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_left);
+ syntax_free (edit->rules[i]->keyword[j]->whole_word_chars_right);
+ syntax_free (edit->rules[i]->keyword[j]);
+ }
+ }
+ syntax_free (edit->rules[i]->conflicts);
+ syntax_free (edit->rules[i]->left);
+ syntax_free (edit->rules[i]->right);
+ syntax_free (edit->rules[i]->whole_word_chars_left);
+ syntax_free (edit->rules[i]->whole_word_chars_right);
+ syntax_free (edit->rules[i]->keyword);
+ syntax_free (edit->rules[i]->keyword_first_chars);
+ syntax_free (edit->rules[i]->keyword_last_chars);
+ syntax_free (edit->rules[i]);
+ }
+ syntax_free (edit->rules);
+}
+
+#define CURRENT_SYNTAX_RULES_VERSION "22"
+
+char *syntax_text =
+"# syntax rules version " CURRENT_SYNTAX_RULES_VERSION "\n"
+"# Allowable colors for mc are\n"
+"# (after the slash is a Cooledit color, 0-26 or any of the X colors in rgb.txt)\n"
+"# black\n"
+"# red\n"
+"# green\n"
+"# brown\n"
+"# blue\n"
+"# magenta\n"
+"# cyan\n"
+"# lightgray\n"
+"# gray\n"
+"# brightred\n"
+"# brightgreen\n"
+"# yellow\n"
+"# brightblue\n"
+"# brightmagenta\n"
+"# brightcyan\n"
+"# white\n"
+"\n"
+"###############################################################################\n"
+"file ..\\*\\\\.tex$ LaTeX\\s2.09\\sDocument\n"
+"context default\n"
+"wholechars left \\\\\n"
+"wholechars right abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\n"
+"\n"
+"# type style\n"
+" keyword whole \\\\tiny yellow/24\n"
+" keyword whole \\\\scriptsize yellow/24\n"
+" keyword whole \\\\footnotesize yellow/24\n"
+" keyword whole \\\\small yellow/24\n"
+" keyword whole \\\\normalsize yellow/24\n"
+" keyword whole \\\\large yellow/24\n"
+" keyword whole \\\\Large yellow/24\n"
+" keyword whole \\\\LARGE yellow/24\n"
+" keyword whole \\\\huge yellow/24\n"
+" keyword whole \\\\Huge yellow/24\n"
+"\n"
+"# accents and symbols\n"
+" keyword whole \\\\`{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\'{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\^{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\\"{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\~{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\={\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\.{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\u{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\v{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\H{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\t{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\c{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\d{\\[aeiouAEIOU\\]} yellow/24\n"
+" keyword whole \\\\b{\\[aeiouAEIOU\\]} yellow/24\n"
+"\n"
+" keyword whole \\\\dag yellow/24\n"
+" keyword whole \\\\ddag yellow/24\n"
+" keyword whole \\\\S yellow/24\n"
+" keyword whole \\\\P yellow/24\n"
+" keyword whole \\\\copyright yellow/24\n"
+" keyword whole \\\\pounds yellow/24\n"
+"\n"
+"# sectioning and table of contents\n"
+" keyword whole \\\\part[*]{*} brightred/19\n"
+" keyword whole \\\\part{*} brightred/19\n"
+" keyword whole \\\\part\\*{*} brightred/19\n"
+" keyword whole \\\\chapter[*]{*} brightred/19\n"
+" keyword whole \\\\chapter{*} brightred/19\n"
+" keyword whole \\\\chapter\\*{*} brightred/19\n"
+" keyword whole \\\\section[*]{*} brightred/19\n"
+" keyword whole \\\\section{*} brightred/19\n"
+" keyword whole \\\\section\\*{*} brightred/19\n"
+" keyword whole \\\\subsection[*]{*} brightred/19\n"
+" keyword whole \\\\subsection{*} brightred/19\n"
+" keyword whole \\\\subsection\\*{*} brightred/19\n"
+" keyword whole \\\\subsubsection[*]{*} brightred/19\n"
+" keyword whole \\\\subsubsection{*} brightred/19\n"
+" keyword whole \\\\subsubsection\\*{*} brightred/19\n"
+" keyword whole \\\\paragraph[*]{*} brightred/19\n"
+" keyword whole \\\\paragraph{*} brightred/19\n"
+" keyword whole \\\\paragraph\\*{*} brightred/19\n"
+" keyword whole \\\\subparagraph[*]{*} brightred/19\n"
+" keyword whole \\\\subparagraph{*} brightred/19\n"
+" keyword whole \\\\subparagraph\\*{*} brightred/19\n"
+"\n"
+" keyword whole \\\\appendix brightred/19\n"
+" keyword whole \\\\tableofcontents brightred/19\n"
+"\n"
+"# misc\n"
+" keyword whole \\\\item[*] yellow/24\n"
+" keyword whole \\\\item yellow/24\n"
+" keyword whole \\\\\\\\ yellow/24\n"
+" keyword \\\\\\s yellow/24 black/0\n"
+" keyword %% yellow/24\n"
+"\n"
+"# docuement and page styles \n"
+" keyword whole \\\\documentstyle[*]{*} yellow/20\n"
+" keyword whole \\\\documentstyle{*} yellow/20\n"
+" keyword whole \\\\pagestyle{*} yellow/20\n"
+"\n"
+"# cross references\n"
+" keyword whole \\\\label{*} yellow/24\n"
+" keyword whole \\\\ref{*} yellow/24\n"
+"\n"
+"# bibliography and citations\n"
+" keyword whole \\\\bibliography{*} yellow/24\n"
+" keyword whole \\\\bibitem[*]{*} yellow/24\n"
+" keyword whole \\\\bibitem{*} yellow/24\n"
+" keyword whole \\\\cite[*]{*} yellow/24\n"
+" keyword whole \\\\cite{*} yellow/24\n"
+"\n"
+"# splitting the input\n"
+" keyword whole \\\\input{*} yellow/20\n"
+" keyword whole \\\\include{*} yellow/20\n"
+" keyword whole \\\\includeonly{*} yellow/20\n"
+"\n"
+"# line breaking\n"
+" keyword whole \\\\linebreak[\\[01234\\]] yellow/24\n"
+" keyword whole \\\\nolinebreak[\\[01234\\]] yellow/24\n"
+" keyword whole \\\\linebreak yellow/24\n"
+" keyword whole \\\\nolinebreak yellow/24\n"
+" keyword whole \\\\[+] yellow/24\n"
+" keyword whole \\\\- yellow/24\n"
+" keyword whole \\\\sloppy yellow/24\n"
+"\n"
+"# page breaking\n"
+" keyword whole \\\\pagebreak[\\[01234\\]] yellow/24\n"
+" keyword whole \\\\nopagebreak[\\[01234\\]] yellow/24\n"
+" keyword whole \\\\pagebreak yellow/24\n"
+" keyword whole \\\\nopagebreak yellow/24\n"
+" keyword whole \\\\samepage yellow/24\n"
+" keyword whole \\\\newpage yellow/24\n"
+" keyword whole \\\\clearpage yellow/24\n"
+"\n"
+"# defintiions\n"
+" keyword \\\\newcommand{*}[*] cyan/5\n"
+" keyword \\\\newcommand{*} cyan/5\n"
+" keyword \\\\newenvironment{*}[*]{*} cyan/5\n"
+" keyword \\\\newenvironment{*}{*} cyan/5\n"
+"\n"
+"# boxes\n"
+"\n"
+"# begins and ends\n"
+" keyword \\\\begin{document} brightred/14\n"
+" keyword \\\\begin{equation} brightred/14\n"
+" keyword \\\\begin{eqnarray} brightred/14\n"
+" keyword \\\\begin{quote} brightred/14\n"
+" keyword \\\\begin{quotation} brightred/14\n"
+" keyword \\\\begin{center} brightred/14\n"
+" keyword \\\\begin{verse} brightred/14\n"
+" keyword \\\\begin{verbatim} brightred/14\n"
+" keyword \\\\begin{itemize} brightred/14\n"
+" keyword \\\\begin{enumerate} brightred/14\n"
+" keyword \\\\begin{description} brightred/14\n"
+" keyword \\\\begin{array} brightred/14\n"
+" keyword \\\\begin{tabular} brightred/14\n"
+" keyword \\\\begin{thebibliography}{*} brightred/14\n"
+" keyword \\\\begin{sloppypar} brightred/14\n"
+"\n"
+" keyword \\\\end{document} brightred/14\n"
+" keyword \\\\end{equation} brightred/14\n"
+" keyword \\\\end{eqnarray} brightred/14\n"
+" keyword \\\\end{quote} brightred/14\n"
+" keyword \\\\end{quotation} brightred/14\n"
+" keyword \\\\end{center} brightred/14\n"
+" keyword \\\\end{verse} brightred/14\n"
+" keyword \\\\end{verbatim} brightred/14\n"
+" keyword \\\\end{itemize} brightred/14\n"
+" keyword \\\\end{enumerate} brightred/14\n"
+" keyword \\\\end{description} brightred/14\n"
+" keyword \\\\end{array} brightred/14\n"
+" keyword \\\\end{tabular} brightred/14\n"
+" keyword \\\\end{thebibliography}{*} brightred/14\n"
+" keyword \\\\end{sloppypar} brightred/14\n"
+"\n"
+" keyword \\\\begin{*} brightcyan/16\n"
+" keyword \\\\end{*} brightcyan/16\n"
+"\n"
+" keyword \\\\theorem{*}{*} yellow/24\n"
+"\n"
+"# if all else fails\n"
+" keyword whole \\\\+[*]{*}{*}{*} brightcyan/17\n"
+" keyword whole \\\\+[*]{*}{*} brightcyan/17\n"
+" keyword whole \\\\+{*}{*}{*}{*} brightcyan/17\n"
+" keyword whole \\\\+{*}{*}{*} brightcyan/17\n"
+" keyword whole \\\\+{*}{*} brightcyan/17\n"
+" keyword whole \\\\+{*} brightcyan/17\n"
+" keyword \\\\\\[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\n brightcyan/17\n"
+" keyword \\\\\\[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\s brightcyan/17\n"
+" keyword \\\\\\[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\\]\\t brightcyan/17\n"
+"\n"
+"context \\\\pagenumbering{ } yellow/20\n"
+" keyword arabic brightcyan/17\n"
+" keyword roman brightcyan/17\n"
+" keyword alph brightcyan/17\n"
+" keyword Roman brightcyan/17\n"
+" keyword Alph brightcyan/17\n"
+"\n"
+"context % \\n brown/22\n"
+"\n"
+"# mathematical formulas\n"
+"context $ $ brightgreen/6\n"
+"context exclusive \\\\begin{equation} \\\\end{equation} brightgreen/6\n"
+"context exclusive \\\\begin{eqnarray} \\\\end{eqnarray} brightgreen/6\n"
+"\n"
+"\n"
+"###############################################################################\n"
+"file ..\\*\\\\.([chC]|CC|cxx|cc|cpp|CPP|CXX)$ C/C\\+\\+\\sProgram\n"
+"context default\n"
+" keyword whole auto yellow/24\n"
+" keyword whole break yellow/24\n"
+" keyword whole case yellow/24\n"
+" keyword whole char yellow/24\n"
+" keyword whole const yellow/24\n"
+" keyword whole continue yellow/24\n"
+" keyword whole default yellow/24\n"
+" keyword whole do yellow/24\n"
+" keyword whole double yellow/24\n"
+" keyword whole else yellow/24\n"
+" keyword whole enum yellow/24\n"
+" keyword whole extern yellow/24\n"
+" keyword whole float yellow/24\n"
+" keyword whole for yellow/24\n"
+" keyword whole goto yellow/24\n"
+" keyword whole if yellow/24\n"
+" keyword whole int yellow/24\n"
+" keyword whole long yellow/24\n"
+" keyword whole register yellow/24\n"
+" keyword whole return yellow/24\n"
+" keyword whole short yellow/24\n"
+" keyword whole signed yellow/24\n"
+" keyword whole sizeof yellow/24\n"
+" keyword whole static yellow/24\n"
+" keyword whole struct yellow/24\n"
+" keyword whole switch yellow/24\n"
+" keyword whole typedef yellow/24\n"
+" keyword whole union yellow/24\n"
+" keyword whole unsigned yellow/24\n"
+" keyword whole void yellow/24\n"
+" keyword whole volatile yellow/24\n"
+" keyword whole while yellow/24\n"
+" keyword whole asm yellow/24\n"
+" keyword whole catch yellow/24\n"
+" keyword whole class yellow/24\n"
+" keyword whole friend yellow/24\n"
+" keyword whole delete yellow/24\n"
+" keyword whole inline yellow/24\n"
+" keyword whole new yellow/24\n"
+" keyword whole operator yellow/24\n"
+" keyword whole private yellow/24\n"
+" keyword whole protected yellow/24\n"
+" keyword whole public yellow/24\n"
+" keyword whole this yellow/24\n"
+" keyword whole throw yellow/24\n"
+" keyword whole template yellow/24\n"
+" keyword whole try yellow/24\n"
+" keyword whole virtual yellow/24\n"
+" keyword whole bool yellow/24\n"
+" keyword whole const_cast yellow/24\n"
+" keyword whole dynamic_cast yellow/24\n"
+" keyword whole explicit yellow/24\n"
+" keyword whole false yellow/24\n"
+" keyword whole mutable yellow/24\n"
+" keyword whole namespace yellow/24\n"
+" keyword whole reinterpret_cast yellow/24\n"
+" keyword whole static_cast yellow/24\n"
+" keyword whole true yellow/24\n"
+" keyword whole typeid yellow/24\n"
+" keyword whole typename yellow/24\n"
+" keyword whole using yellow/24\n"
+" keyword whole wchar_t yellow/24\n"
+" keyword whole ... yellow/24\n"
+"\n"
+" keyword /\\* brown/22\n"
+" keyword \\*/ brown/22\n"
+"\n"
+" keyword '\\s' brightgreen/16\n"
+" keyword '+' brightgreen/16\n"
+" keyword > yellow/24\n"
+" keyword < yellow/24\n"
+" keyword \\+ yellow/24\n"
+" keyword - yellow/24\n"
+" keyword \\* yellow/24\n"
+" keyword / yellow/24\n"
+" keyword % yellow/24\n"
+" keyword = yellow/24\n"
+" keyword != yellow/24\n"
+" keyword == yellow/24\n"
+" keyword { brightcyan/14\n"
+" keyword } brightcyan/14\n"
+" keyword ( brightcyan/15\n"
+" keyword ) brightcyan/15\n"
+" keyword [ brightcyan/14\n"
+" keyword ] brightcyan/14\n"
+" keyword , brightcyan/14\n"
+" keyword : brightcyan/14\n"
+" keyword ; brightmagenta/19\n"
+"context exclusive /\\* \\*/ brown/22\n"
+"context linestart # \\n brightred/18\n"
+" keyword \\\\\\n yellow/24\n"
+" keyword /\\**\\*/ brown/22\n"
+" keyword \"+\" red/19\n"
+" keyword <+> red/19\n"
+"context \" \" green/6\n"
+" keyword \\\\\" brightgreen/16\n"
+" keyword %% brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]e brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]E brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]f brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]g brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[L\\]G brightgreen/16\n"
+" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]d brightgreen/16\n"
+" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]i brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]o brightgreen/16\n"
+" keyword %\\[0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]u brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]x brightgreen/16\n"
+" keyword %\\[#0\\s-\\+,\\]\\[0123456789\\]\\[.\\]\\[0123456789\\]\\[hl\\]X brightgreen/16\n"
+" keyword %\\[hl\\]n brightgreen/16\n"
+" keyword %\\[.\\]\\[0123456789\\]s brightgreen/16\n"
+" keyword %[*] brightgreen/16\n"
+" keyword %c brightgreen/16\n"
+" keyword \\\\\\\\ brightgreen/16\n"
+"\n"
+"###############################################################################\n"
+"file .\\*ChangeLog$ GNU\\sDistribution\\sChangeLog\\sFile\n"
+"\n"
+"context default\n"
+" keyword \\s+() brightmagenta/23\n"
+" keyword \\t+() brightmagenta/23\n"
+"\n"
+"context linestart \\t\\* : brightcyan/17\n"
+"context linestart \\s\\s\\s\\s\\s\\s\\s\\s\\* : brightcyan/17\n"
+"\n"
+"context linestart 19+-+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart 20+-+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Mon\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Tue\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Wed\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Thu\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Fri\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Sat\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"context linestart Sun\\s+\\s+\\s+\\s \\n yellow/24\n"
+" keyword <+@+> brightred/19\n"
+"\n"
+"\n"
+"###############################################################################\n"
+"file .\\*Makefile[\\\\\\.a-z]\\*$ Makefile\n"
+"\n"
+"context default\n"
+" keyword $(*) yellow/24\n"
+" keyword ${*} brightgreen/16\n"
+" keyword whole linestart include magenta\n"
+" keyword whole linestart endif magenta\n"
+" keyword whole linestart ifeq magenta\n"
+" keyword whole linestart ifneq magenta\n"
+" keyword whole linestart else magenta\n"
+" keyword linestart \\t lightgray/13 red\n"
+" keyword whole .PHONY white/25\n"
+" keyword whole .NOEXPORT white/25\n"
+" keyword = white/25\n"
+" keyword : yellow/24\n"
+" keyword \\\\\\n yellow/24\n"
+"# this handles strange cases like @something@@somethingelse@ properly\n"
+" keyword whole @+@ brightmagenta/23 black/0\n"
+" keyword @+@ brightmagenta/23 black/0\n"
+"\n"
+"context linestart # \\n brown/22\n"
+" keyword whole @+@ brightmagenta/23 black/0\n"
+" keyword @+@ brightmagenta/23 black/0\n"
+"\n"
+"context exclusive = \\n brightcyan/17\n"
+" keyword \\\\\\n yellow/24\n"
+" keyword $(*) yellow/24\n"
+" keyword ${*} brightgreen/16\n"
+" keyword linestart \\t lightgray/13 red\n"
+" keyword whole @+@ brightmagenta/23 black/0\n"
+" keyword @+@ brightmagenta/23 black/0\n"
+"\n"
+"context exclusive linestart \\t \\n\n"
+" keyword \\\\\\n yellow/24\n"
+" keyword $(*) yellow/24\n"
+" keyword ${*} brightgreen/16\n"
+" keyword linestart \\t lightgray/13 red\n"
+" keyword whole @+@ brightmagenta/23 black/0\n"
+" keyword @+@ brightmagenta/23 black/0\n"
+"\n"
+"###############################################################################\n"
+"\n"
+"file .\\*syntax$ Syntax\\sHighlighting\\sdefinitions\n"
+"\n"
+"context default\n"
+" keyword whole keyw\\ord yellow/24\n"
+" keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17\n"
+" keyword whole whole\\[\\t\\s\\]l\\inestart brightcyan/17\n"
+" keyword whole wh\\oleleft\\[\\t\\s\\]l\\inestart brightcyan/17\n"
+" keyword whole wh\\oleright\\[\\t\\s\\]l\\inestart brightcyan/17\n"
+" keyword whole l\\inestart\\[\\t\\s\\]wh\\ole\n"
+" keyword whole l\\inestart\\[\\t\\s\\]wh\\ole\n"
+" keyword whole l\\inestart\\[\\t\\s\\]wh\\oleleft\n"
+" keyword whole l\\inestart\\[\\t\\s\\]wh\\oleright\n"
+" keyword wholeleft whole\\s brightcyan/17\n"
+" keyword wholeleft whole\\t brightcyan/17\n"
+" keyword whole wh\\oleleft brightcyan/17\n"
+" keyword whole wh\\oleright brightcyan/17\n"
+" keyword whole lin\\[e\\]start brightcyan/17\n"
+" keyword whole c\\ontext\\[\\t\\s\\]exclusive brightred/18\n"
+" keyword whole c\\ontext\\[\\t\\s\\]default brightred/18\n"
+" keyword whole c\\ontext brightred/18\n"
+" keyword whole wh\\olechars\\[\\t\\s\\]left brightcyan/17\n"
+" keyword whole wh\\olechars\\[\\t\\s\\]right brightcyan/17\n"
+" keyword whole wh\\olechars brightcyan/17\n"
+" keyword whole f\\ile brightgreen/6\n"
+"\n"
+" keyword whole 0 lightgray/0 blue/26\n"
+" keyword whole 1 lightgray/1 blue/26\n"
+" keyword whole 2 lightgray/2 blue/26\n"
+" keyword whole 3 lightgray/3 blue/26\n"
+" keyword whole 4 lightgray/4 blue/26\n"
+" keyword whole 5 lightgray/5 blue/26\n"
+" keyword whole 6 lightgray/6\n"
+" keyword whole 7 lightgray/7\n"
+" keyword whole 8 lightgray/8\n"
+" keyword whole 9 lightgray/9\n"
+" keyword whole 10 lightgray/10\n"
+" keyword whole 11 lightgray/11\n"
+" keyword whole 12 lightgray/12\n"
+" keyword whole 13 lightgray/13\n"
+" keyword whole 14 lightgray/14\n"
+" keyword whole 15 lightgray/15\n"
+" keyword whole 16 lightgray/16\n"
+" keyword whole 17 lightgray/17\n"
+" keyword whole 18 lightgray/18\n"
+" keyword whole 19 lightgray/19\n"
+" keyword whole 20 lightgray/20\n"
+" keyword whole 21 lightgray/21\n"
+" keyword whole 22 lightgray/22\n"
+" keyword whole 23 lightgray/23\n"
+" keyword whole 24 lightgray/24\n"
+" keyword whole 25 lightgray/25\n"
+" keyword whole 26 lightgray/26\n"
+"\n"
+" keyword wholeleft black\\/ black/0\n"
+" keyword wholeleft red\\/ red/DarkRed\n"
+" keyword wholeleft green\\/ green/green3\n"
+" keyword wholeleft brown\\/ brown/saddlebrown\n"
+" keyword wholeleft blue\\/ blue/blue3\n"
+" keyword wholeleft magenta\\/ magenta/magenta3\n"
+" keyword wholeleft cyan\\/ cyan/cyan3\n"
+" keyword wholeleft lightgray\\/ lightgray/lightgray\n"
+" keyword wholeleft gray\\/ gray/gray\n"
+" keyword wholeleft brightred\\/ brightred/red\n"
+" keyword wholeleft brightgreen\\/ brightgreen/green1\n"
+" keyword wholeleft yellow\\/ yellow/yellow\n"
+" keyword wholeleft brightblue\\/ brightblue/blue1\n"
+" keyword wholeleft brightmagenta\\/ brightmagenta/magenta\n"
+" keyword wholeleft brightcyan\\/ brightcyan/cyan1\n"
+" keyword wholeleft white\\/ white/26\n"
+"\n"
+"context linestart # \\n brown/22\n"
+"\n"
+"file \\.\\* Help\\ssupport\\sother\\sfile\\stypes\n"
+"context default\n"
+"file \\.\\* by\\scoding\\srules\\sin\\s~/.cedit/syntax.\n"
+"context default\n"
+"file \\.\\* See\\sman/syntax\\sin\\sthe\\ssource\\sdistribution\n"
+"context default\n"
+"file \\.\\* and\\sconsult\\sthe\\sman\\spage.\n"
+"context default\n";
+
+
+
+FILE *upgrade_syntax_file (char *syntax_file)
+{
+ FILE *f;
+ char line[80];
+ f = fopen (syntax_file, "r");
+ if (!f) {
+ f = fopen (syntax_file, "w");
+ if (!f)
+ return 0;
+ fprintf (f, "%s", syntax_text);
+ fclose (f);
+ return fopen (syntax_file, "r");
+ }
+ memset (line, 0, 79);
+ fread (line, 80, 1, f);
+ if (!strstr (line, "syntax rules version")) {
+ goto rename_rule_file;
+ } else {
+ char *p;
+ p = strstr (line, "version") + strlen ("version") + 1;
+ if (atoi (p) < atoi (CURRENT_SYNTAX_RULES_VERSION)) {
+ char s[1024];
+ rename_rule_file:
+ strcpy (s, syntax_file);
+ strcat (s, ".OLD");
+ unlink (s);
+ rename (syntax_file, s);
+ unlink (syntax_file); /* might rename() fail ? */
+#ifdef MIDNIGHT
+ edit_message_dialog (" Load Syntax Rules ", " Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. ");
+#else
+ CMessageDialog (0, 20, 20, 0, " Load Syntax Rules ", " Your syntax rule file is outdated \n A new rule file is being installed. \n Your old rule file has been saved with a .OLD extension. ");
+#endif
+ return upgrade_syntax_file (syntax_file);
+ } else {
+ rewind (f);
+ return (f);
+ }
+ }
+ return 0; /* not reached */
+}
+
+/* returns -1 on file error, line number on error in file syntax */
+static int edit_read_syntax_file (WEdit * edit, char **names, char *syntax_file, char *editor_file, char *type)
+{
+ FILE *f;
+ regex_t r;
+ regmatch_t pmatch[1];
+ char *args[1024], *l;
+ int line = 0;
+ int argc;
+ int result = 0;
+ int count = 0;
+
+ f = upgrade_syntax_file (syntax_file);
+ if (!f)
+ return -1;
+ args[0] = 0;
+
+ for (;;) {
+ line++;
+ if (!read_one_line (&l, f))
+ break;
+ get_args (l, args, &argc);
+ if (!args[0]) {
+ } else if (!strcmp (args[0], "file")) {
+ if (!args[1] || !args[2]) {
+ result = line;
+ break;
+ }
+ if (regcomp (&r, args[1], REG_EXTENDED)) {
+ result = line;
+ break;
+ }
+ if (names) {
+ names[count++] = strdup (args[2]);
+ names[count] = 0;
+ } else if (type) {
+ if (!strcmp (type, args[2]))
+ goto found_type;
+ } else if (editor_file && edit) {
+ if (!regexec (&r, editor_file, 1, pmatch, 0)) {
+ int line_error;
+ found_type:
+ line_error = edit_read_syntax_rules (edit, f);
+ if (line_error)
+ result = line + line_error;
+ else {
+ syntax_free (edit->syntax_type);
+ edit->syntax_type = strdup (args[2]);
+ if (syntax_change_callback)
+#ifdef MIDNIGHT
+ (*syntax_change_callback) (&edit->widget);
+#else
+ (*syntax_change_callback) (edit->widget);
+#endif
+/* if there are no rules then turn off syntax highlighting for speed */
+ if (!edit->rules[1])
+ if (!edit->rules[0]->keyword[1])
+ edit_free_syntax_rules (edit);
+ }
+ break;
+ }
+ }
+ }
+ free_args (args);
+ syntax_free (l);
+ }
+ free_args (args);
+ syntax_free (l);
+
+ fclose (f);
+
+ return result;
+}
+
+/* loads rules into edit struct. one of edit or names must be zero. if
+ edit is zero, a list of types will be stored into name. type may be zero
+ in which case the type will be selected according to the filename. */
+void edit_load_syntax (WEdit * edit, char **names, char *type)
+{
+ int r;
+ char *f;
+
+ edit_free_syntax_rules (edit);
+
+#ifdef MIDNIGHT
+ if (!SLtt_Use_Ansi_Colors)
+ return;
+#endif
+
+ if (edit) {
+ if (!edit->filename)
+ return;
+ if (!*edit->filename && !type)
+ return;
+ }
+ f = catstrs (home_dir, SYNTAX_FILE, 0);
+ r = edit_read_syntax_file (edit, names, f, edit ? edit->filename : 0, type);
+ if (r == -1) {
+ edit_free_syntax_rules (edit);
+ edit_error_dialog (_ (" Load syntax file "), _ (" File access error "));
+ return;
+ }
+ if (r) {
+ char s[80];
+ edit_free_syntax_rules (edit);
+ sprintf (s, _ (" Syntax error in file %s on line %d "), f, r);
+ edit_error_dialog (_ (" Load syntax file "), s);
+ return;
+ }
+}
+
+#else
+
+int option_syntax_highlighting = 0;
+
+void edit_load_syntax (WEdit * edit, char **names, char *type)
+{
+ return;
+}
+
+void edit_free_syntax_rules (WEdit * edit)
+{
+ return;
+}
+
+void edit_get_syntax_color (WEdit * edit, long byte_index, int *fg, int *bg)
+{
+ *fg = NORMAL_COLOR;
+}
+
+#endif /* !defined(MIDNIGHT) || defined(HAVE_SYNTAXH) */
+
+
+
+
--- /dev/null
+/* wordproc.c - word-processor mode for the editor: does dynamic
+ paragraph formatting.
+ Copyright (C) 1996 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include "edit.h"
+
+#ifdef MIDNIGHT
+#define tab_width option_tab_spacing
+#endif
+
+int line_is_blank (WEdit * edit, long line);
+
+#define NO_FORMAT_CHARS_START "-+*\\,.;:&>"
+
+static long line_start (WEdit * edit, long line)
+{
+ static long p = -1, l = 0;
+ int c;
+ if (p == -1 || abs (l - line) > abs (edit->curs_line - line)) {
+ l = edit->curs_line;
+ p = edit->curs1;
+ }
+ if (line < l)
+ p = edit_move_backward (edit, p, l - line);
+ else if (line > l)
+ p = edit_move_forward (edit, p, line - l, 0);
+ l = line;
+ p = edit_bol (edit, p);
+ while (strchr ("\t ", c = edit_get_byte (edit, p)))
+ p++;
+ return p;
+}
+
+static int bad_line_start (WEdit * edit, long p)
+{
+ int c;
+ c = edit_get_byte (edit, p);
+ if (c == '.') { /* `...' is acceptable */
+ if (edit_get_byte (edit, p + 1) == '.')
+ if (edit_get_byte (edit, p + 2) == '.')
+ return 0;
+ return 1;
+ }
+ if (c == '-') {
+ if (edit_get_byte (edit, p + 1) == '-')
+ if (edit_get_byte (edit, p + 2) == '-')
+ return 0; /* `---' is acceptable */
+ return 1;
+ }
+ if (strchr (NO_FORMAT_CHARS_START, c))
+ return 1;
+ return 0;
+}
+
+static long begin_paragraph (WEdit * edit, long p, int force)
+{
+ int i;
+ for (i = edit->curs_line - 1; i > 0; i--) {
+ if (line_is_blank (edit, i)) {
+ i++;
+ break;
+ }
+ if (force) {
+ if (bad_line_start (edit, line_start (edit, i))) {
+ i++;
+ break;
+ }
+ }
+ }
+ return edit_move_backward (edit, edit_bol (edit, edit->curs1), edit->curs_line - i);
+}
+
+static long end_paragraph (WEdit * edit, long p, int force)
+{
+ int i;
+ for (i = edit->curs_line + 1; i < edit->total_lines; i++) {
+ if (line_is_blank (edit, i)) {
+ i--;
+ break;
+ }
+ if (force)
+ if (bad_line_start (edit, line_start (edit, i))) {
+ i--;
+ break;
+ }
+ }
+ return edit_eol (edit, edit_move_forward (edit, edit_bol (edit, edit->curs1), i - edit->curs_line, 0));
+}
+
+static char *get_paragraph (WEdit * edit, long p, long q, int indent, int *size)
+{
+ char *s, *t;
+ t = malloc ((q - p) + 2 * (q - p) / option_word_wrap_line_length + 10);
+ if (!t)
+ return 0;
+ for (s = t; p < q; p++, s++) {
+ if (indent)
+ if (edit_get_byte (edit, p - 1) == '\n')
+ while (strchr ("\t ", edit_get_byte (edit, p)))
+ p++;
+ *s = edit_get_byte (edit, p);
+ }
+ *size = (unsigned long) s - (unsigned long) t;
+ t[*size] = '\n';
+ return t;
+}
+
+static void strip_newlines (char *t, int size)
+{
+ char *p = t;
+ while (size--) {
+ *p = *p == '\n' ? ' ' : *p;
+ p++;
+ }
+}
+
+#ifndef MIDNIGHT
+int edit_width_of_long_printable (int c);
+#endif
+/*
+ This is a copy of the function
+ int calc_text_pos (WEdit * edit, long b, long *q, int l)
+ in propfont.c :(
+ It calculates the number of chars in a line specified to length l in pixels
+ */
+extern int tab_width;
+static inline int next_tab_pos (int x)
+{
+ return x += tab_width - x % tab_width;
+}
+static int line_pixel_length (char *t, long b, int l)
+{
+ int x = 0, c, xn = 0;
+ for (;;) {
+ c = t[b];
+ switch (c) {
+ case '\n':
+ return b;
+ case '\t':
+ xn = next_tab_pos (x);
+ break;
+ default:
+#ifdef MIDNIGHT
+ xn = x + 1;
+#else
+ xn = x + edit_width_of_long_printable (c);
+#endif
+ break;
+ }
+ if (xn > l)
+ break;
+ x = xn;
+ b++;
+ }
+ return b;
+}
+
+/* find the start of a word */
+static int next_word_start (char *t, int q, int size)
+{
+ int i;
+ for (i = q;; i++) {
+ switch (t[i]) {
+ case '\n':
+ return -1;
+ case '\t':
+ case ' ':
+ for (;; i++) {
+ if (t[i] == '\n')
+ return -1;
+ if (t[i] != ' ' && t[i] != '\t')
+ return i;
+ }
+ break;
+ }
+ }
+}
+
+/* find the start of a word */
+static int word_start (char *t, int q, int size)
+{
+ int i = q;
+ if (t[q] == ' ' || t[q] == '\t')
+ return next_word_start (t, q, size);
+ for (;;) {
+ int c;
+ if (!i)
+ return -1;
+ c = t[i - 1];
+ if (c == '\n')
+ return -1;
+ if (c == ' ' || c == '\t')
+ return i;
+ i--;
+ }
+}
+
+/* replaces ' ' with '\n' to properly format a paragraph */
+static void format_this (char *t, int size, int indent)
+{
+ int q = 0, ww;
+ strip_newlines (t, size);
+ ww = option_word_wrap_line_length * FONT_MEAN_WIDTH - indent;
+ if (ww < FONT_MEAN_WIDTH * 2)
+ ww = FONT_MEAN_WIDTH * 2;
+ for (;;) {
+ int p;
+ q = line_pixel_length (t, q, ww);
+ if (q > size)
+ break;
+ if (t[q] == '\n')
+ break;
+ p = word_start (t, q, size);
+ if (p == -1)
+ q = next_word_start (t, q, size); /* Return the end of the word if the beginning
+ of the word is at the beginning of a line
+ (i.e. a very long word) */
+ else
+ q = p;
+ if (q == -1) /* end of paragraph */
+ break;
+ if (q)
+ t[q - 1] = '\n';
+ }
+}
+
+static void replace_at (WEdit * edit, long q, int c)
+{
+ edit_cursor_move (edit, q - edit->curs1);
+ edit_delete (edit);
+ edit_insert_ahead (edit, c);
+}
+
+void edit_insert_indent (WEdit * edit, int indent);
+
+/* replaces a block of text */
+static void put_paragraph (WEdit * edit, char *t, long p, long q, int indent, int size)
+{
+ long cursor;
+ int i, c = 0;
+ cursor = edit->curs1;
+ if (indent)
+ while (strchr ("\t ", edit_get_byte (edit, p)))
+ p++;
+ for (i = 0; i < size; i++, p++) {
+ if (i && indent) {
+ if (t[i - 1] == '\n' && c == '\n') {
+ while (strchr ("\t ", edit_get_byte (edit, p)))
+ p++;
+ } else if (t[i - 1] == '\n') {
+ long curs;
+ edit_cursor_move (edit, p - edit->curs1);
+ curs = edit->curs1;
+ edit_insert_indent (edit, indent);
+ if (cursor >= curs)
+ cursor += edit->curs1 - p;
+ p = edit->curs1;
+ } else if (c == '\n') {
+ edit_cursor_move (edit, p - edit->curs1);
+ while (strchr ("\t ", edit_get_byte (edit, p))) {
+ edit_delete (edit);
+ if (cursor > edit->curs1)
+ cursor--;
+ }
+ p = edit->curs1;
+ }
+ }
+ c = edit_get_byte (edit, p);
+ if (c != t[i])
+ replace_at (edit, p, t[i]);
+ }
+ edit_cursor_move (edit, cursor - edit->curs1); /* restore cursor position */
+}
+
+int edit_indent_width (WEdit * edit, long p);
+
+static int test_indent (WEdit * edit, long p, long q)
+{
+ int indent;
+ indent = edit_indent_width (edit, p++);
+ if (!indent)
+ return 0;
+ for (; p < q; p++)
+ if (edit_get_byte (edit, p - 1) == '\n')
+ if (indent != edit_indent_width (edit, p))
+ return 0;
+ return indent;
+}
+
+void format_paragraph (WEdit * edit, int force)
+{
+ long p, q;
+ int size;
+ char *t;
+ int indent = 0;
+ if (option_word_wrap_line_length < 2)
+ return;
+ if (line_is_blank (edit, edit->curs_line))
+ return;
+ p = begin_paragraph (edit, edit->curs1, force);
+ q = end_paragraph (edit, edit->curs1, force);
+ indent = test_indent (edit, p, q);
+ t = get_paragraph (edit, p, q, indent, &size);
+ if (!t)
+ return;
+ if (!force) {
+ int i;
+ if (strchr (NO_FORMAT_CHARS_START, *t)) {
+ free (t);
+ return;
+ }
+ for (i = 0; i < size - 1; i++) {
+ if (t[i] == '\n') {
+ if (strchr (NO_FORMAT_CHARS_START "\t ", t[i + 1])) {
+ free (t);
+ return;
+ }
+ }
+ }
+ }
+ format_this (t, q - p, indent);
+ put_paragraph (edit, t, p, q, indent, size);
+ free (t);
+}
+
+
+
+
+
+
+
+
+
+
--- /dev/null
+#!/bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+ echo "install: no destination specified"
+ exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+ dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0
--- /dev/null
+VERSION=4.1.36
+
+SHELL = /bin/sh
+
+# This variable makes it possible to move the installation root to another
+# directory. This is useful when you're creating a binary distribution of mc.
+# If empty, normal root will be used.
+# You can run e.g. 'make install DESTDIR=/packages/mc/3.0' to accomplish
+# that.
+# DESTDIR = /opt/apps/mc/$(VERSION)
+
+# Installation target directories & other installation stuff
+prefix = @prefix@
+exec_prefix = $(prefix)
+binprefix =
+manprefix =
+
+builddir = @builddir@
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib/mc
+suppbindir = $(libdir)/bin
+tidir = $(libdir)/term
+extfsdir = $(libdir)/extfs
+icondir = $(prefix)/share/icons/mc
+mandir = $(prefix)/man/man1
+datadir = $(prefix)/share
+localedir = $(datadir)/locale
+manext = 1
+man8dir = $(prefix)/man/man8
+man8ext = 8
+xv_bindir = @xv_bindir@
+
+# Tools & program stuff
+SEDCMD = @SEDCMD@
+SEDCMD2 = @SEDCMD2@
+STRIP = @STRIP@
+@SET_MAKE@
+CC = @CC@
+CPP = @CPP@
+AR = @AR@
+RANLIB = @RANLIB@
+RM = @RM@
+RMF = @RM@ -f
+MV = @MV@
+CP = @CP@
+LN_S = @LN_S@
+AWK = @AWK@
+AWK_VAR_OPTION = @AWK_VAR_OPTION@
+
+# Flags & libs
+# No way, to make make happy (except GNU), we cannot use := to append
+# something to these, so that's why there is a leading _
+XCFLAGS = @CFLAGS@
+XCPPFLAGS = @CPPFLAGS@ -I.. -DBINDIR=\""$(bindir)/"\" -DLIBDIR=\""$(libdir)/"\" -DICONDIR=\""$(icondir)/"\" $(XINC) -DLOCALEDIR=\""$(localedir)/"\"
+XLDFLAGS = @LDFLAGS@
+XDEFS = @DEFS@
+XLIBS = @LIBS@
+
+# Where do we have the sources?
+# You shouldn't have to edit this :)
+mcsrcdir = $(rootdir)/src
+docdir = $(rootdir)/doc
+mclibdir = $(rootdir)/lib
+slangdir = $(rootdir)/slang
+vfsdir = $(rootdir)/vfs
+xvdir = $(rootdir)/xv
+tkdir = $(rootdir)/tk
+gnomedir = $(rootdir)/gnome
+icodir = $(rootdir)/icons
+
+hpath = -I$(mcsrcdir) -I$(slangdir) -I$(vfsdir) -I$(xvdir) -I$(xvdir)/support/xview_private -I$(tkdir)
+
+# Rules
+first_rule: all
+
+@PHONY@ all check cross TAGS clean install uninstall distcopy depend dep
+@PHONY@ fastdep fastdepslang fastdepvfs fastdeploc slowdep
+
+@PCENTRULE@../slang/%.o : ../slang/%.c
+@PCENTRULE@ cd ../slang; $(MAKE) libmcslang.a
+
+@PCENTRULE@../vfs/%.o : ../vfs/%.c
+@PCENTRULE@ cd ../vfs; $(MAKE) libvfs.a
+
+fastdep: dummy
+ if test x"`echo $(srcdir)/*.[ch]`" != x'$(srcdir)/*.[ch]'; then { cd $(srcdir); $(AWK) -f $(mcsrcdir)/depend.awk $(AWK_VAR_OPTION) hpath="$(hpath)" $(AWK_VAR_OPTION) srcdir="$(srcdir)" *.[ch];} > .depend; fi
+ -$(MAKE) fastdeploc
+ @WRITEDEP@
+
+fastdepslang:
+@PCENTRULE@ { { { cd ../slang; $(MAKE) showlibdep;} | grep OBJS; cat .depend;} | { cd $(slangdir); $(AWK) -f $(mcsrcdir)/depend.awk $(AWK_VAR_OPTION) dolib="../slang libmcslang.a" $(AWK_VAR_OPTION) hpath="$(hpath)" $(AWK_VAR_OPTION) srcdir="$(slangdir)";};} >> .depend
+
+fastdepvfs:
+@PCENTRULE@ { { { cd ../vfs; $(MAKE) showlibdep;} | grep OBJS; cat .depend;} | { cd $(vfsdir); $(AWK) -f $(mcsrcdir)/depend.awk $(AWK_VAR_OPTION) dolib="../vfs libvfs.a" $(AWK_VAR_OPTION) hpath="$(hpath)" $(AWK_VAR_OPTION) srcdir="$(vfsdir)";};} >> .depend
+
+slowdep: dummy
+ if test x"`echo $(srcdir)/*.[ch]`" != x'$(srcdir)/*.[ch]'; then \
+ $(CPP) -M $(CPPFLAGS) $(DEFS) $(CFLAGS) $(srcdir)/*.c > .depend; fi
+ @WRITEDEP@
+
+mcdep: @dep@
+
+dummy:
+
+# End of Make.common
--- /dev/null
+#include "VERSION"
+#ifndef WINDRES
+# include "windows.h"
+// # include "winver.h"
+#endif
+
+/* English (U.S.) resources */
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+
+#ifdef _WIN32
+#ifndef WINDRES
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#endif
+#pragma code_page(1252)
+#endif /* _WIN32 */
+
+/* Version */
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 3,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40000L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Free Software Foundation"
+ VALUE "FileDescription", "GNU Midnight Commander"
+ VALUE "FileVersion", VERSION
+ VALUE "InternalName", "MC"
+ VALUE "LegalCopyright", "(c) Free Software Foundation"
+ VALUE "LegalTrademarks", "see GNU General Public License"
+ VALUE "OriginalFilename", "MC.EXE"
+ VALUE "ProductName", "GNU Midnight Commander"
+ VALUE "ProductVersion", VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+
+/* Icon */
+// 0 ICON DISCARDABLE "mc_nt.ico"
+// 1 ICON DISCARDABLE "bez03.ico"
+
+#endif /* English (U.S.) resources */
+
--- /dev/null
+#/bin/sh
+#
+prefix=/usr/local
+if test -n `echo $prefix | grep prefix`; then
+ prefix=/usr/local
+fi
+if test x$BASH = x; then
+ BASHRC=
+else
+ BASHRC=~/.bashrc
+fi
+if test "x$EUID" = x0; then
+ PROFILE=/etc/profile
+else
+ PROFILE=~/.profile
+fi
+if test -f $PROFILE; then
+ A=`grep "mc ()" $PROFILE`
+ B=
+ if test -n "$BASHRC"; then
+ if test -f $BASHRC; then
+ B=`grep "mc ()" $BASHRC`
+ fi
+ fi
+ if test -n "$A"; then
+ :
+ else
+ if test -n "$B"; then
+ :
+ else
+ A=`typeset -f | grep "mc ()" 2>/dev/null`
+ if test ! -n "$A"; then
+ echo "mc () installation."
+ if test -n "$BASHRC"; then
+ echo "While examining your $PROFILE and $BASHRC,"
+ else
+ echo "While examining your $PROFILE,"
+ fi
+ echo "I've found that you have no mc () function defined there."
+ echo "This function enables a feature of mc(1) that when you leave mc(1),"
+ echo "you return to a directory where you were in mc just before exiting"
+ echo "and not to the directory you've started mc from."
+ echo "Would you like to append"
+ echo 'mc () { MC=`'$prefix'/bin/mc -P "$@"`; [ -n "$MC" ] && cd "$MC"; unset MC };'
+ if test -n "$BASHRC"; then
+ echo "function to your (p) $PROFILE (mc function will be active in your login shells)"
+ echo -n "or to your (b) $BASHRC (in every bash instance) or (n) no? [p|b|n] "
+ else
+ echo -n "function to your $PROFILE? [y|n] "
+ fi
+ read rep
+ if test -n "$BASHRC"; then
+ INITFILE=$BASHRC
+ else
+ INITFILE=$PROFILE
+ fi
+ case $rep in
+ [Nn]*) exit ;;
+ [Pp]*) INITFILE=$PROFILE ;;
+ esac
+ echo >>$INITFILE
+ echo 'mc () { MC=`'$prefix'/bin/mc -P "$@"`; [ -n "$MC" ] && cd "$MC"; unset MC };' >>$INITFILE
+ echo "mc () function appended to your $INITFILE"
+ fi
+ fi
+ fi
+fi
--- /dev/null
+#/bin/sh
+#
+prefix=@prefix@
+if test -n `echo $prefix | grep prefix`; then
+ prefix=/usr/local
+fi
+if test x$BASH = x; then
+ BASHRC=
+else
+ BASHRC=~/.bashrc
+fi
+if test "x$EUID" = x0; then
+ PROFILE=/etc/profile
+else
+ PROFILE=~/.profile
+fi
+if test -f $PROFILE; then
+ A=`grep "mc ()" $PROFILE`
+ B=
+ if test -n "$BASHRC"; then
+ if test -f $BASHRC; then
+ B=`grep "mc ()" $BASHRC`
+ fi
+ fi
+ if test -n "$A"; then
+ :
+ else
+ if test -n "$B"; then
+ :
+ else
+ A=`typeset -f | grep "mc ()" 2>/dev/null`
+ if test ! -n "$A"; then
+ echo "mc () installation."
+ if test -n "$BASHRC"; then
+ echo "While examining your $PROFILE and $BASHRC,"
+ else
+ echo "While examining your $PROFILE,"
+ fi
+ echo "I've found that you have no mc () function defined there."
+ echo "This function enables a feature of mc(1) that when you leave mc(1),"
+ echo "you return to a directory where you were in mc just before exiting"
+ echo "and not to the directory you've started mc from."
+ echo "Would you like to append"
+ echo 'mc () { MC=`'$prefix'/bin/mc -P "$@"`; [ -n "$MC" ] && cd "$MC"; unset MC };'
+ if test -n "$BASHRC"; then
+ echo "function to your (p) $PROFILE (mc function will be active in your login shells)"
+ echo -n "or to your (b) $BASHRC (in every bash instance) or (n) no? [p|b|n] "
+ else
+ echo -n "function to your $PROFILE? [y|n] "
+ fi
+ read rep
+ if test -n "$BASHRC"; then
+ INITFILE=$BASHRC
+ else
+ INITFILE=$PROFILE
+ fi
+ case $rep in
+ [Nn]*) exit ;;
+ [Pp]*) INITFILE=$PROFILE ;;
+ esac
+ echo >>$INITFILE
+ echo 'mc () { MC=`'$prefix'/bin/mc -P "$@"`; [ -n "$MC" ] && cd "$MC"; unset MC };' >>$INITFILE
+ echo "mc () function appended to your $INITFILE"
+ fi
+ fi
+ fi
+fi
--- /dev/null
+#! /bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Public domain
+
+# $Id: mkinstalldirs,v 1.1 2001/12/30 09:49:36 sedwards Exp $
+
+errstatus=0
+
+for file
+do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d
+ do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+
+ mkdir "$pathcomp" || lasterr=$?
+
+ if test ! -d "$pathcomp"; then
+ errstatus=$lasterr
+ fi
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- /dev/null
+TARGET_OS=NT
+
+CC=gcc
+LINK=gcc -s
+OBJ_SUFFIX=o
+OBJ_PLACE=-o
+EXE_PLACE=-o
+
+# ---- Compiler-specific optional stuff
+MC_MISC_CFLAGS=
+OBJS_DIR=release
+EXTRA_MC_SRCS=
+SPECIFIC_DEFINES=
+SPECIFIC_MC_CFLAGS=-O2 $(MC_MISC_CFLAGS)
+SPECIFIC_MC_LFLAGS_EXTRA=
+SPECIFIC_SLANG_CFLAGS=$(SPECIFIC_MC_CFLAGS)
+SPECIFIC_MCEDIT_CFLAGS=$(SPECIFIC_MC_CFLAGS)
+
+# ---- Compiler independent defines
+include Makefile.PC
+
+# ---- Linkers are very compiler-specific
+
+SPECIFIC_MC_LFLAGS=$(SPECIFIC_MC_LFLAGS_EXTRA)
+MC_LIBS= # -lintl
+
+$(MC_EXE): $(OBJS) $(MCEDIT_OBJS) $(SLANG_OBJS)
+ $(LINK) $(EXE_PLACE) $(MC_EXE) $(SPECIFIC_MC_LFLAGS) $+ $(MC_LIBS)
--- /dev/null
+# Makefile.PC
+#
+# This is the Makefile for Midnight Commander under OS/2 and Windows NT
+#
+# Written by Dan Nicolaescu
+# 970423 hacked by Juan f. Grigera
+# 970525 hacked again by jfg to add internal editor
+# 971127 hacked by Pavel Roskin to make it work with mc-4.1.11
+# 980206 hacked by Pavel Roskin to make it work with GNU make
+# 980329 changed by Pavel Roskin to make it common for OS/2 and NT
+#
+# Supported Compilers:
+#
+# For Windows NT:
+# Makefile.VC4: Microsoft Visual C++ 4.0 and above
+# Makefile.BC5: Borland C++ 5.x
+# Makefile.MIN: MinGW
+# Makefile.RSX: RSX
+# For OS/2:
+# Makefile.EMX: EMX/GCC
+# Makefile.BC2: Borland C++ 2.x
+# Makefile.IBM: IBM CSet or Visual Age C++
+# ...
+
+# ---- Directories
+MC_PC_DIR=.
+MC_SRC_DIR=../src
+VFS_DIR=../vfs
+MCEDIT_SRC_DIR=../edit
+MCEDIT_OBJS_DIR=$(OBJS_DIR)/edit
+SLANG_SRC_DIR=../slang
+SLANG_OBJS_DIR=$(OBJS_DIR)/slang
+MC_EXE=$(OBJS_DIR)/mc.exe
+
+# --- Midnight Defines
+COMMON_DEFINES=-DMC_$(TARGET_OS) $(SPECIFIC_DEFINES)
+MC_DEFINES=$(COMMON_DEFINES) -DHAVE_CONFIG_H
+MC_INCLUDES=-I$(MC_PC_DIR) -I$(SLANG_SRC_DIR)
+SLANG_DEFINES=$(COMMON_DEFINES)
+SLANG_INCLUDES=-I$(MC_PC_DIR) -I$(SLANG_SRC_DIR)
+MCEDIT_DEFINES=$(COMMON_DEFINES) -DHAVE_CONFIG_H
+MCEDIT_INCLUDES=-I$(MC_PC_DIR) -I$(SLANG_SRC_DIR)
+
+CFLAGS=$(SPECIFIC_MC_CFLAGS) $(MC_INCLUDES) $(MC_DEFINES) -c
+SLANG_CFLAGS=$(SPECIFIC_SLANG_CFLAGS) $(SLANG_INCLUDES) $(SLANG_DEFINES) -c
+MCEDIT_CFLAGS=$(SPECIFIC_MCEDIT_CFLAGS) $(MCEDIT_INCLUDES) $(MCEDIT_DEFINES) -c
+
+
+all: object-dirs mc
+object-dirs: $(OBJS_DIR) $(SLANG_OBJS_DIR) $(MCEDIT_OBJS_DIR)
+
+mc: $(MC_EXE)
+
+clean:
+ deltree -y "$(SLANG_OBJS_DIR)"
+ deltree -y "$(MCEDIT_OBJS_DIR)"
+ deltree -y "$(OBJS_DIR)"
+
+$(OBJS_DIR):
+ mkdir "$@"
+
+$(SLANG_OBJS_DIR):
+ mkdir "$@"
+
+$(MCEDIT_OBJS_DIR):
+ mkdir "$@"
+
+$(OBJS_DIR)/%.$(OBJ_SUFFIX): $(MC_PC_DIR)/%.c
+ $(CC) $(CFLAGS) $(OBJ_PLACE)$@ $<
+
+$(OBJS_DIR)/%.$(OBJ_SUFFIX): $(MC_SRC_DIR)/%.c
+ $(CC) $(CFLAGS) $(OBJ_PLACE)$@ $<
+
+$(SLANG_OBJS_DIR)/%.$(OBJ_SUFFIX): $(SLANG_SRC_DIR)/%.c
+ $(CC) $(SLANG_CFLAGS) $(OBJ_PLACE)$@ $<
+
+$(MCEDIT_OBJS_DIR)/%.$(OBJ_SUFFIX): $(MCEDIT_SRC_DIR)/%.c
+ $(CC) $(MCEDIT_CFLAGS) $(OBJ_PLACE)$@ $<
+
+MC_SRCS= \
+ terms.c \
+ user.c \
+ file.c \
+ listmode.c \
+ cmd.c \
+ command.c \
+ help.c \
+ menu.c \
+ view.c \
+ dir.c \
+ info.c \
+ widget.c \
+ option.c \
+ dlg.c \
+ panelize.c \
+ profile.c \
+ util.c \
+ dialog.c \
+ ext.c \
+ color.c \
+ layout.c \
+ setup.c \
+ regex.c \
+ hotlist.c \
+ tree.c \
+ win.c \
+ complete.c \
+ find.c \
+ wtools.c \
+ boxes.c \
+ background.c \
+ main.c \
+ popt.c \
+ text.c \
+ screen.c
+
+PC_SRCS= \
+ slint_pc.c \
+ chmod.c \
+ drive.c
+
+NT_SRCS= \
+ cons_nt.c \
+ dirent_nt.c \
+ key_nt.c \
+ util_win32.c \
+ util_winnt.c \
+ util_nt.c
+
+OS2_SRCS= \
+ cons_os2.c \
+ dirent_os2.c \
+ key_os2.c \
+ util_os2.c
+
+SLANG_NT=slw32tty.c
+SLANG_OS2=slos2tty.c
+
+SLANG_SRCS= \
+ slerr.c \
+ slgetkey.c \
+ slsmg.c \
+ slvideo.c \
+ $(SLANG_$(TARGET_OS))
+
+MCEDIT_SRCS= \
+ edit.c \
+ editcmd.c \
+ editdraw.c \
+ editmenu.c \
+ editoptions.c \
+ editwidget.c \
+ syntax.c \
+ wordproc.c
+
+SRCS=$(MC_SRCS) $(PC_SRCS) $($(TARGET_OS)_SRCS) $(EXTRA_MC_SRCS)
+
+OBJS=$(addprefix $(OBJS_DIR)/, \
+ $(patsubst %.c,%.$(OBJ_SUFFIX),$(SRCS)))
+SLANG_OBJS=$(addprefix $(SLANG_OBJS_DIR)/, \
+ $(patsubst %.c,%.$(OBJ_SUFFIX),$(SLANG_SRCS)))
+MCEDIT_OBJS=$(addprefix $(MCEDIT_OBJS_DIR)/, \
+ $(patsubst %.c,%.$(OBJ_SUFFIX),$(MCEDIT_SRCS)))
+
+ifdef RSC
+
+ifndef RES_SUFFIX
+RES_SUFFIX=res
+endif # RES_SUFFIX
+
+MC_RES=$(OBJS_DIR)/mc.$(RES_SUFFIX)
+
+$(MC_RES): $(MC_PC_DIR)/mc.rc $(MC_PC_DIR)/mc_nt.ico $(MC_PC_DIR)/config.h ../VERSION
+ $(RSC) $(RES_PLACE)$(MC_RES) $(RC_DEFINES) $(MC_PC_DIR)/mc.rc
+
+else
+MC_RES=
+endif # !RSC
--- /dev/null
+BUGS OF PC port
+
+- Troubles with keys (Ctrl-Tab, Gray +,-,*, Alt-Shift-A etc)
+- Filtered view hangs in close_pipe() because error is set, but nothing
+is available on stderr
+- Windows '95 will not delete directory if not empty. (as it does
+ not return ENOTEMPTY but ENOACCESS)! Already fixed?
+- Windows '95 will not allow "''" in root drives
+- OS/2 port uses always screen size 80x25. Do we need newer SLang?
+- IBM C++ has some problems with O_TEXT -> troubles with editor
+- OS/2 port causes access violation while copying files.
+- getcwd from EMX returns a UNIX-like path -> drive change fails.
+
+-please report!
+
--- /dev/null
+Tue May 12 17:16:43 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * Makefile.RSX, mc.rc: Resources support for RSX
+
+ * Makefile.PC, *.c: Some includes corrected for MinGW
+ compatability (dir.h exists both in mc and MinGW)
+
+Fri May 8 10:49:21 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * Makefile.PC, Makefile.MIN: support for custom extension
+ for compiled resourses
+
+ * key_nt.c: Minor changes for MinGW
+
+ * mc.rc: WindRes support
+
+ * slint_pc.c: support for syntax highlighting
+
+Fri May 1 17:33:11 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * chmod.c: Updated call to update_panels()
+
+ * config.h, Makefile.MIN: Support for MinGW added
--- /dev/null
+/* Chmod command for Windows NT and OS/2
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#ifdef __os2__
+#define INCL_DOSFILEMGR
+#include <os2.h>
+#endif
+
+#ifdef _OS_NT
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include <stdio.h>
+/* for chmod and stat */
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "../src/tty.h"
+#include "../src/mad.h"
+#include "../src/util.h"
+#include "../src/win.h"
+#include "../src/color.h"
+#include "../src/dlg.h"
+#include "../src/widget.h"
+#include "../src/dialog.h" /* For do_refresh() */
+
+#include "../src/dir.h"
+#include "../src/panel.h" /* Needed for the externs */
+#include "../src/file.h"
+#include "../src/main.h"
+#include "../src/chmod.h"
+#include "../src/achown.h"
+#include "../src/chown.h"
+
+#ifdef _OS_NT
+#define FILE_ARCHIVED FILE_ATTRIBUTE_ARCHIVE
+#define FILE_DIRECTORY FILE_ATTRIBUTE_DIRECTORY
+#define FILE_HIDDEN FILE_ATTRIBUTE_HIDDEN
+#define FILE_READONLY FILE_ATTRIBUTE_READONLY
+#define FILE_SYSTEM FILE_ATTRIBUTE_SYSTEM
+#define mk_chmod(fname,st) SetFileAttributes(fname,st)
+#endif
+
+static int single_set;
+struct Dlg_head *ch_dlg;
+
+#define PX 5
+#define PY 2
+
+#define FX 40
+#define FY 2
+
+#define BX 6
+#define BY 17
+
+#define TX 40
+#define TY 12
+
+#define PERMISSIONS 4
+#define BUTTONS 6
+
+#define B_MARKED B_USER
+#define B_ALL B_USER+1
+#define B_SETMRK B_USER+2
+#define B_CLRMRK B_USER+3
+
+
+int mode_change, need_update;
+int c_file, end_chmod;
+
+umode_t and_mask, or_mask, c_stat;
+char *c_fname, *c_fown, *c_fgrp, *c_fperm;
+int c_fsize;
+
+static WLabel *statl;
+static int normal_color;
+static int title_color;
+static int selection_color;
+
+/* bsedos.h */
+struct {
+ mode_t mode;
+ char *text;
+ int selected;
+ WCheck *check;
+} check_perm[PERMISSIONS] = {
+
+ {
+ FILE_ARCHIVED, N_("Archive"), 0, 0,
+ },
+ {
+ FILE_READONLY, N_("Read Only"), 0, 0,
+ },
+ {
+ FILE_HIDDEN, N_("Hidden"), 0, 0,
+ },
+ {
+ FILE_SYSTEM, N_("System"), 0, 0,
+ },
+};
+
+struct {
+ int ret_cmd, flags, y, x;
+ char *text;
+} chmod_but[BUTTONS] = {
+
+ {
+ B_CANCEL, NORMAL_BUTTON, 2, 33, N_("&Cancel"),
+ },
+ {
+ B_ENTER, DEFPUSH_BUTTON, 2, 17, N_("&Set"),
+ },
+ {
+ B_CLRMRK, NORMAL_BUTTON, 0, 42, N_("C&lear marked"),
+ },
+ {
+ B_SETMRK, NORMAL_BUTTON, 0, 27, N_("S&et marked"),
+ },
+ {
+ B_MARKED, NORMAL_BUTTON, 0, 12, N_("&Marked all"),
+ },
+ {
+ B_ALL, NORMAL_BUTTON, 0, 0, N_("Set &all"),
+ },
+};
+
+static void chmod_toggle_select (void)
+{
+ int Id = ch_dlg->current->dlg_id - BUTTONS + single_set * 2;
+
+ attrset (normal_color);
+ check_perm[Id].selected ^= 1;
+
+ dlg_move (ch_dlg, PY + PERMISSIONS - Id, PX + 1);
+ addch ((check_perm[Id].selected) ? '*' : ' ');
+ dlg_move (ch_dlg, PY + PERMISSIONS - Id, PX + 3);
+}
+
+static void chmod_refresh (void)
+{
+ attrset (normal_color);
+ dlg_erase (ch_dlg);
+
+ draw_box (ch_dlg, 1, 2, 20 - single_set, 66);
+ draw_box (ch_dlg, PY, PX, PERMISSIONS + 2, 33);
+ draw_box (ch_dlg, FY, FX, 10, 25);
+
+ dlg_move (ch_dlg, FY + 1, FX + 2);
+ addstr (_("Name"));
+ dlg_move (ch_dlg, FY + 3, FX + 2);
+ addstr (_("Permissions (Octal)"));
+ dlg_move (ch_dlg, FY + 5, FX + 2);
+ addstr (_("Owner name"));
+ dlg_move (ch_dlg, FY + 7, FX + 2);
+ addstr (_("Group name"));
+
+ attrset (title_color);
+ dlg_move (ch_dlg, 1, 28);
+ addstr (_(" Chmod command "));
+ dlg_move (ch_dlg, PY, PX + 1);
+ addstr (_(" Permission "));
+ dlg_move (ch_dlg, FY, FX + 1);
+ addstr (_(" File "));
+
+ attrset (selection_color);
+
+ dlg_move (ch_dlg, TY, TX);
+ addstr (_("Use SPACE to change"));
+ dlg_move (ch_dlg, TY + 1, TX);
+ addstr (_("an option, ARROW KEYS"));
+ dlg_move (ch_dlg, TY + 2, TX);
+ addstr (_("to move between options"));
+ dlg_move (ch_dlg, TY + 3, TX);
+ addstr (_("and T or INS to mark"));
+}
+
+static int chmod_callback (Dlg_head *h, int Par, int Msg)
+{
+ char buffer [10];
+
+ switch (Msg) {
+ case DLG_ACTION:
+ if (Par >= BUTTONS - single_set * 2){
+ c_stat ^= check_perm[Par - BUTTONS + single_set * 2].mode;
+ sprintf (buffer, "%o", c_stat);
+ label_set_text (statl, buffer);
+ chmod_toggle_select ();
+ mode_change = 1;
+ }
+ break;
+
+ case DLG_KEY:
+ if ((Par == 'T' || Par == 't' || Par == KEY_IC) &&
+ ch_dlg->current->dlg_id >= BUTTONS - single_set * 2) {
+ chmod_toggle_select ();
+ if (Par == KEY_IC)
+ dlg_one_down (ch_dlg);
+ return 1;
+ }
+ break;
+#ifndef HAVE_X
+ case DLG_DRAW:
+ chmod_refresh ();
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void init_chmod (void)
+{
+ int i;
+
+ do_refresh ();
+ end_chmod = c_file = need_update = 0;
+ single_set = (cpanel->marked < 2) ? 2 : 0;
+
+ if (use_colors){
+ normal_color = COLOR_NORMAL;
+ title_color = COLOR_HOT_NORMAL;
+ selection_color = COLOR_NORMAL;
+ } else {
+ normal_color = NORMAL_COLOR;
+ title_color = SELECTED_COLOR;
+ selection_color = SELECTED_COLOR;
+ }
+
+ ch_dlg = create_dlg (0, 0, 22 - single_set, 70, dialog_colors,
+ chmod_callback, _("[Chmod]"), _("chmod"), DLG_CENTER);
+
+ x_set_dialog_title (ch_dlg, _("Chmod command"));
+
+#define XTRACT(i) BY+chmod_but[i].y-single_set, BX+chmod_but[i].x, \
+ chmod_but[i].ret_cmd, chmod_but[i].flags, chmod_but[i].text, 0, 0, NULL
+
+ tk_new_frame (ch_dlg, "b.");
+ for (i = 0; i < BUTTONS; i++) {
+ if (i == 2 && single_set)
+ break;
+ else
+ add_widgetl (ch_dlg, button_new (XTRACT (i)), XV_WLAY_RIGHTOF);
+ }
+
+
+#define XTRACT2(i) 0, check_perm [i].text, NULL
+ tk_new_frame (ch_dlg, "c.");
+ for (i = 0; i < PERMISSIONS; i++) {
+ check_perm[i].check = check_new (PY + (PERMISSIONS - i), PX + 2,
+ XTRACT2 (i));
+ add_widget (ch_dlg, check_perm[i].check);
+ }
+}
+
+int pc_stat_file (char *filename)
+{
+ mode_t st;
+
+#ifdef _OS_NT
+ st = GetFileAttributes (filename);
+#endif /* _OS_NT */
+
+#ifdef __os2__
+ HFILE fHandle = 0L;
+ ULONG fInfoLevel = 1; /* 1st Level Info: Standard attributs */
+ FILESTATUS3 fInfoBuf;
+ ULONG fInfoBufSize;
+ ULONG fAction = 0;
+ APIRET rc;
+
+ fInfoBufSize = sizeof(FILESTATUS3);
+ rc = DosOpen((PSZ) filename,
+ &fHandle,
+ &fAction,
+ (ULONG) 0,
+ FILE_NORMAL,
+ OPEN_ACTION_OPEN_IF_EXISTS,
+ (OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE),
+ (PEAOP2) NULL);
+ if (rc != 0) {
+ return -1;
+ }
+
+ rc = DosQueryFileInfo(fHandle, fInfoLevel, &fInfoBuf, fInfoBufSize);
+ DosClose(fHandle);
+ if (rc != 0) {
+ return -1; /* error ! */
+ } else {
+ st = fInfoBuf.attrFile;
+ }
+#endif /* __os2__ */
+
+ if (st & FILE_DIRECTORY)
+ st = -1;
+ return st;
+}
+
+static void chmod_done (void)
+{
+ if (need_update)
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+char *next_file (void)
+{
+ while (!cpanel->dir.list[c_file].f.marked)
+ c_file++;
+
+ return cpanel->dir.list[c_file].fname;
+}
+
+#ifdef __os2__
+static int mk_chmod (char *filename, ULONG st)
+{
+ HFILE fHandle = 0L;
+ ULONG fInfoLevel = 1; /* 1st Level Info: Standard attributs */
+ FILESTATUS3 fInfoBuf;
+ ULONG fInfoBufSize;
+ ULONG fAction = 0L;
+ APIRET rc;
+
+ if (!(st & FILE_READONLY))
+ chmod(filename, (S_IWRITE | S_IREAD));
+ fInfoBufSize = sizeof(FILESTATUS3);
+ rc = DosOpen((PSZ) filename,
+ &fHandle,
+ &fAction,
+ (ULONG) 0,
+ FILE_NORMAL,
+ OPEN_ACTION_OPEN_IF_EXISTS,
+ (OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE),
+ 0L);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = DosQueryFileInfo(fHandle, fInfoLevel, &fInfoBuf, fInfoBufSize);
+ if (rc!=0) {
+ DosClose(fHandle);
+ return rc;
+ }
+ fInfoBuf.attrFile = st;
+ rc = DosSetFileInfo(fHandle, fInfoLevel, &fInfoBuf, fInfoBufSize);
+ rc = DosClose(fHandle);
+ return rc;
+}
+#endif /* __os2__ */
+
+static void do_chmod (mode_t sf)
+{
+ sf &= and_mask;
+ sf |= or_mask;
+
+ mk_chmod(cpanel->dir.list[c_file].fname, sf);
+
+ do_file_mark (cpanel, c_file, 0);
+}
+
+static void apply_mask (mode_t sf)
+{
+ char *fname;
+ mode_t sf_stat;
+
+ need_update = end_chmod = 1;
+ do_chmod (sf);
+
+ do {
+ fname = next_file ();
+ if ((sf_stat = pc_stat_file (fname)) < 0)
+ break;
+
+ c_stat = sf_stat;
+ do_chmod (c_stat);
+ } while (cpanel->marked);
+}
+
+void chmod_cmd (void)
+{
+ char buffer [10];
+ char *fname;
+ int i;
+ mode_t sf_stat;
+
+ do { /* do while any files remaining */
+ init_chmod ();
+ if (cpanel->marked)
+ fname = next_file (); /* next marked file */
+ else
+ fname = selection (cpanel)->fname; /* single file */
+
+ if ((sf_stat = pc_stat_file (fname)) < 0) /* get status of file */
+ break;
+
+ c_stat = sf_stat;
+ mode_change = 0; /* clear changes flag */
+
+ /* set check buttons */
+ for (i = 0; i < PERMISSIONS; i++){
+ check_perm[i].check->state = (c_stat & check_perm[i].mode) ? 1 : 0;
+ check_perm[i].selected = 0;
+ }
+
+ tk_new_frame (ch_dlg, "l.");
+ /* Set the labels */
+ c_fname = name_trunc (fname, 21);
+ add_widget (ch_dlg, label_new (FY+2, FX+2, c_fname, NULL));
+ c_fown = _("unknown");
+ add_widget (ch_dlg, label_new (FY+6, FX+2, c_fown, NULL));
+ c_fgrp = _("unknown");
+ add_widget (ch_dlg, label_new (FY+8, FX+2, c_fgrp, NULL));
+ sprintf (buffer, "%o", c_stat);
+ statl = label_new (FY+4, FX+2, buffer, NULL);
+ add_widget (ch_dlg, statl);
+ tk_end_frame ();
+
+ run_dlg (ch_dlg); /* retrieve an action */
+
+ /* do action */
+ switch (ch_dlg->ret_value){
+ case B_ENTER:
+ if (mode_change)
+ mk_chmod (fname, c_stat); /*.ado */
+ need_update = 1;
+ break;
+
+ case B_CANCEL:
+ end_chmod = 1;
+ break;
+
+ case B_ALL:
+ case B_MARKED:
+ and_mask = or_mask = 0;
+ and_mask = ~and_mask;
+
+ for (i = 0; i < PERMISSIONS; i++) {
+ if (check_perm[i].selected || ch_dlg->ret_value == B_ALL)
+ if (check_perm[i].check->state & C_BOOL)
+ or_mask |= check_perm[i].mode;
+ else
+ and_mask &= ~check_perm[i].mode;
+ }
+
+ apply_mask (sf_stat);
+ break;
+
+ case B_SETMRK:
+ and_mask = or_mask = 0;
+ and_mask = ~and_mask;
+
+ for (i = 0; i < PERMISSIONS; i++) {
+ if (check_perm[i].selected)
+ or_mask |= check_perm[i].mode;
+ }
+
+ apply_mask (sf_stat);
+ break;
+ case B_CLRMRK:
+ and_mask = or_mask = 0;
+ and_mask = ~and_mask;
+
+ for (i = 0; i < PERMISSIONS; i++) {
+ if (check_perm[i].selected)
+ and_mask &= ~check_perm[i].mode;
+ }
+
+ apply_mask (sf_stat);
+ break;
+ }
+
+ if (cpanel->marked && ch_dlg->ret_value!=B_CANCEL) {
+ do_file_mark (cpanel, c_file, 0);
+ need_update = 1;
+ }
+ destroy_dlg (ch_dlg);
+ } while (cpanel->marked && !end_chmod);
+ chmod_done ();
+}
--- /dev/null
+/****************************************************************************
+ CONFIG.H - Midnight Commander Configuration for Win32 and OS/2
+
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ----------------------------------------------------------------------------
+ Changes:
+ - Created 951204/jfg
+ - Changed from Alexander Dong (ado) for OS/2
+ - Changed 980329 by Pavel Roskin for both OS/2 and NT
+
+ ----------------------------------------------------------------------------
+ Contents:
+ - Headers flags
+ - Library flags
+ - Typedefs
+ - etc.
+ ****************************************************************************/
+#ifndef __CONFIG_H
+#define __CONFIG_H
+
+#define OS2_NT
+
+#ifdef MC_NT
+# ifndef WIN32
+# define WIN32
+# endif
+# ifndef __WIN32__
+# define __WIN32__
+# endif
+# ifndef MSWINDOWS
+# define MSWINDOWS
+# endif
+# ifndef _OS_NT
+# define _OS_NT
+# endif
+#endif /* MC_NT */
+
+#ifdef MC_OS2
+# ifndef OS2
+# define OS2
+# endif
+# ifndef __os2__
+# define __os2__
+# endif
+#endif /* MC_OS2 */
+
+#include "../VERSION"
+
+#ifndef pc_system
+# define pc_system
+#endif
+
+#ifndef HAVE_SLANG
+# define HAVE_SLANG
+#endif
+
+#ifndef _CONSOLE
+# define _CONSOLE
+#endif
+
+#define FLOAT_TYPE
+#define MIDNIGHT
+#define USE_INTERNAL_EDIT
+
+#define STDC_HEADERS
+#define HAVE_STDLIB_H
+#define HAVE_STRING_H
+#define HAVE_DIRENT_H
+#define HAVE_LIMITS_H
+#define HAVE_FCNTL_H
+#define HAVE_UTIME_H
+
+#define HAVE_MEMSET
+#define HAVE_MEMCHR
+#define HAVE_MEMCPY
+#define HAVE_MEMCMP
+#define HAVE_MEMMOVE
+#define HAVE_STRDUP
+#define HAVE_STRERROR
+#define HAVE_TRUNCATE
+
+#define REGEX_MALLOC
+#define NO_INFOMOUNT
+
+typedef unsigned int umode_t;
+#define S_IFLNK 0
+#define S_ISLNK(x) 0
+
+#ifdef __EMX__
+
+#define S_IFBLK 0
+#define S_ISBLK(x) 0
+
+#endif /* __EMX__ */
+
+#ifdef __MINGW32__
+
+#define S_IRGRP 0000040
+#define S_IWGRP 0000020
+#define S_IXGRP 0000010
+#define S_IROTH 0000004
+#define S_IWOTH 0000002
+#define S_IXOTH 0000001
+
+#define ENABLE_NLS
+
+#define pipe(p) _pipe(p, 4096, 0x8000 /* O_BINARY */)
+
+/*typedef int mode_t;*/
+typedef unsigned int nlink_t;
+typedef int gid_t;
+typedef int uid_t;
+/*typedef int pid_t;*/
+
+#endif /* __MINGW32__ */
+
+#ifdef _MSC_VER
+
+#pragma include_alias(<utime.h>, <sys/utime.h>)
+
+#define INLINE
+#define inline
+
+#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+
+#define S_ISFIFO(m) 0
+#define S_ISBLK(x) 0
+
+#define S_IRWXU 0000700
+#define S_IRUSR 0000400
+#define S_IWUSR 0000200
+#define S_IXUSR 0000100
+
+#define S_IRWXG 0000070
+#define S_IRGRP 0000040
+#define S_IWGRP 0000020
+#define S_IXGRP 0000010
+#define S_IRWXO 0000007
+#define S_IROTH 0000004
+#define S_IWOTH 0000002
+#define S_IXOTH 0000001
+
+/* FIXME: is this definition correct? */
+#define R_OK 4
+
+#define pipe(p) _pipe(p, 4096, 0x8000 /* O_BINARY */)
+#define popen _popen
+#define pclose _pclose
+
+typedef int mode_t;
+typedef unsigned int nlink_t;
+typedef int gid_t;
+typedef int uid_t;
+typedef int pid_t;
+
+#endif /* _MSC_VER */
+
+#ifdef __BORLANDC__
+
+#define INLINE
+#define inline
+
+#define S_IRWXG 0000070
+#define S_IRGRP 0000040
+#define S_IWGRP 0000020
+#define S_IXGRP 0000010
+#define S_IRWXO 0000007
+#define S_IROTH 0000004
+#define S_IWOTH 0000002
+#define S_IXOTH 0000001
+
+/* FIXME: is this definition correct? */
+#define R_OK 4
+
+#define pipe(p) _pipe(p, 4096, 0x8000 /* O_BINARY */)
+#define popen _popen
+#define pclose _pclose
+#define sleep _sleep
+
+typedef int pid_t;
+
+#endif /* __BORLANDC__ */
+
+#ifdef __IBMC__
+
+#define INLINE
+#define inline
+
+#define S_ISFIFO(m) 0
+#define S_ISBLK(x) 0
+
+#define S_ISCHR(m) (((m) & S_IFCHR) != 0)
+#define S_ISDIR(m) (((m) & S_IFDIR) != 0)
+#define S_ISREG(m) (((m) & S_IFREG) != 0)
+
+#define S_IRWXU 0000700
+#define S_IRUSR 0000400
+#define S_IWUSR 0000200
+#define S_IXUSR 0000100
+
+#define S_IRWXG 0000070
+#define S_IRGRP 0000040
+#define S_IWGRP 0000020
+#define S_IXGRP 0000010
+#define S_IRWXO 0000007
+#define S_IROTH 0000004
+#define S_IWOTH 0000002
+#define S_IXOTH 0000001
+
+#define ENOTDIR ENOENT
+
+/* FIXME: is this definition correct? */
+#define R_OK 4
+
+#pragma map( chdir , "_chdir" )
+#pragma map( getcwd, "_getcwd" )
+#pragma map( mkdir , "_mkdir" )
+#pragma map( rmdir , "_rmdir" )
+
+#define popen DosCreatePipe
+#define pclose DosClose
+#define sleep DosSleep
+
+typedef unsigned int nlink_t;
+typedef int mode_t;
+typedef int gid_t;
+typedef int uid_t;
+typedef int pid_t;
+
+#endif /* __IBMC__ */
+
+#endif /* __CONFIG_H */
--- /dev/null
+/* Client interface for General purpose Win32 console save/restore server
+ Having the same interface as its Linux counterpart:
+ Copyright (C) 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Note:
+ show_console_contents doesn't know how to write to its window
+ the rest works fine.
+*/
+#include <config.h>
+
+#include <windows.h>
+#include "trace_nt.h"
+
+int cons_saver_pid = 1;
+
+#include "../src/tty.h"
+#include "../src/util.h"
+#include "../src/win.h"
+#include "../src/cons.saver.h"
+
+signed char console_flag = 1;
+static HANDLE hSaved, hNew;
+
+void show_console_contents (int starty, unsigned char begin_line,
+ unsigned char end_line)
+{
+ COORD c0 = { 0, 0 };
+ COORD csize;
+ SMALL_RECT rect;
+ CHAR_INFO *pchar;
+
+ csize.X = COLS;
+ csize.Y = end_line-begin_line;
+ rect.Left = 0;
+ rect.Top = begin_line;
+ rect.Right = COLS;
+ rect.Bottom = end_line;
+
+/* -- This code reads characters and attributes */
+ pchar = malloc (sizeof(CHAR_INFO) * (end_line-begin_line) * COLS);
+ /* Copy from one console to the curses virtual screen */
+ win32APICALL(ReadConsoleOutput (hSaved, pchar, csize, c0, &rect));
+
+ /* FIXME: this should've work,
+ but refresh() is called after this write :-( */
+ win32APICALL(WriteConsoleOutput (hNew, pchar, csize, c0, &rect));
+
+ free (pchar);
+}
+
+void handle_console (unsigned char action)
+{
+ static SECURITY_ATTRIBUTES sa;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ switch (action){
+ case CONSOLE_INIT:
+ /* Save Standard handle */
+ hSaved = GetStdHandle (STD_OUTPUT_HANDLE);
+
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.lpSecurityDescriptor = NULL;
+ /* Create a new console buffer */
+ sa.bInheritHandle = TRUE;
+ win32APICALL_HANDLE(hNew,
+ CreateConsoleScreenBuffer (GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, &sa,
+ CONSOLE_TEXTMODE_BUFFER, NULL));
+ win32APICALL(GetConsoleScreenBufferInfo(hSaved, &csbi));
+ csbi.dwSize.X=csbi.srWindow.Right-csbi.srWindow.Left;
+ csbi.dwSize.Y=csbi.srWindow.Bottom-csbi.srWindow.Right;
+ win32APICALL(SetConsoleScreenBufferSize(hNew, csbi.dwSize));
+
+ /* that becomes standard handle */
+ win32APICALL(SetConsoleActiveScreenBuffer(hNew));
+ win32APICALL(SetConsoleMode(hNew, ENABLE_PROCESSED_INPUT));
+ win32APICALL(SetStdHandle(STD_OUTPUT_HANDLE, hNew));
+ break;
+
+ case CONSOLE_DONE:
+ win32APICALL(CloseHandle (hNew));
+ break;
+
+ case CONSOLE_SAVE:
+ /* Current = our standard handle */
+ win32APICALL(SetConsoleActiveScreenBuffer (hNew));
+ win32APICALL(SetStdHandle (STD_OUTPUT_HANDLE, hNew));
+ break;
+
+ case CONSOLE_RESTORE:
+ /* Put saved (shell) screen buffer */
+ win32APICALL(SetConsoleActiveScreenBuffer (hSaved));
+ win32APICALL(SetStdHandle (STD_OUTPUT_HANDLE, hSaved));
+ break;
+ default:
+ win32Trace(("Invalid action code %d sent to handle_console", action));
+ }
+}
--- /dev/null
+/* Client interface for General purpose OS/2 console save/restore server.
+ 1997 Alexander Dong <ado@software-ag.de>
+ Having the same interface as its Linux counterpart:
+ Copyright (C) 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+
+#ifdef __os2__
+#define INCL_BASE
+#define INCL_NOPM
+#define INCL_VIO
+#define INCL_KBD
+#define INCL_DOS
+#define INCL_SUB
+#define INCL_DOSERRORS
+#include <os2.h>
+#endif
+
+#include "../src/tty.h"
+#include "../src/util.h"
+#include "../src/win.h"
+#include "../src/cons.saver.h"
+
+signed char console_flag = 1;
+static unsigned char *scr_buffer;
+static unsigned char *pointer;
+
+static int GetScrRows();
+static int GetScrCols();
+
+static int GetScrRows()
+{
+ VIOMODEINFO pvMode = {80};
+ unsigned int hVio = 0;
+ VioGetMode(&pvMode, hVio);
+ return (pvMode.row ? pvMode.row: 25);
+}
+
+static int GetScrCols()
+{
+ VIOMODEINFO pvMode = {80};
+ unsigned int hVio = 0;
+ VioGetMode(&pvMode, hVio);
+ return (pvMode.col ? pvMode.col: 80);
+}
+
+void show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
+{
+ int col = GetScrCols();
+ int row = GetScrRows();
+ int n;
+ register int z;
+
+ pointer = scr_buffer;
+ for (z=0; z<(begin_line * col); z++) {
+ pointer++; pointer++;
+ }
+ n = (end_line - begin_line + 1) * col;
+ VioWrtCellStr((PCH) pointer, (USHORT) n, begin_line, 0, 0);
+ return;
+}
+
+void handle_console (unsigned char action)
+{
+ static int col;
+ static int row;
+ int n;
+
+ switch (action) {
+ case CONSOLE_INIT: /* Initialize */
+ col = GetScrCols();
+ row = GetScrRows();
+ scr_buffer = (unsigned char *) malloc(col * row * 2); /* short values */
+ n = col * row * 2;
+ VioReadCellStr((PCH) scr_buffer, (USHORT *) &n, 0, 0, 0); /* Just save it */
+ break;
+ case CONSOLE_DONE:
+ free(scr_buffer);
+ break;
+ case CONSOLE_SAVE: /* Save the screen */
+ n = col * row * 2;
+ VioReadCellStr((PCH) scr_buffer, (USHORT *) &n, 0, 0, 0);
+ break;
+ case CONSOLE_RESTORE:
+ n = col * row * 2;
+ VioWrtCellStr ((PCH) scr_buffer, (USHORT) n, 0, 0, 0); /* Write it back */
+ break;
+ default:
+ /* This is not possible, but if we are here, just save the screen */
+ handle_console(CONSOLE_SAVE);
+ break;
+ }
+ return;
+}
--- /dev/null
+/*
+ * direct.h Defines the types and structures used by the directory routines
+ *
+ */
+#ifndef _DIRENT_H_incl
+#define _DIRENT_H_incl
+
+#ifdef __cplupplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+#define NAME_MAX 255 /* maximum filename for HPFS or NTFS */
+
+typedef struct dirent {
+ unsigned long* d_handle;
+ unsigned d_attr; /* file's attribute */
+ unsigned short int d_time; /* file's time */
+ unsigned short int d_date; /* file's date */
+ long d_size; /* file's size */
+ char d_name[ NAME_MAX + 1 ]; /* file's name */
+ unsigned short d_ino; /* serial number (not used) */
+ char d_first; /* flag for 1st time */
+} DIR;
+
+extern int closedir( DIR * );
+extern DIR *opendir( const char * );
+extern struct dirent *readdir( DIR * );
+
+#ifdef __cplusplus
+};
+#endif
+
+#endif /* _DIRENT_H_incl */
--- /dev/null
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+#include <errno.h>
+#include "dirent.h"
+
+DIR *opendir (const char * a_dir)
+{
+ int err;
+ WIN32_FIND_DATA wfd;
+ DIR* dd_dir = (DIR*) malloc (sizeof(DIR));
+
+ char *c_dir = malloc (strlen(a_dir) + 4);
+ strcpy (c_dir, a_dir);
+ strcat (c_dir, "\\*");
+
+ dd_dir->d_handle = FindFirstFile (c_dir, &wfd);
+ if (dd_dir->d_handle == INVALID_HANDLE_VALUE) {
+ err = GetLastError();
+ switch (err) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ errno = ENOMEM;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ free(dd_dir);
+ return NULL;
+ }
+ dd_dir->d_attr = (wfd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
+ ? 0 : wfd.dwFileAttributes;
+
+ dd_dir->d_time = dd_dir->d_date = 10;
+ dd_dir->d_size = wfd.nFileSizeLow;
+ strcpy (dd_dir->d_name, wfd.cFileName);
+ dd_dir->d_first = 1;
+
+ free (c_dir);
+ return dd_dir;
+}
+
+DIR *readdir( DIR * dd_dir)
+{
+ int err;
+ WIN32_FIND_DATA wfd;
+
+ if (dd_dir->d_first) {
+ dd_dir->d_first = 0;
+ return dd_dir;
+ }
+
+ if(!FindNextFile (dd_dir->d_handle, &wfd)) {
+ err = GetLastError();
+ switch (err) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ errno = ENOMEM;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ return NULL;
+ }
+ dd_dir->d_attr = (wfd.dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
+ ? 0 : wfd.dwFileAttributes;
+
+ dd_dir->d_time = dd_dir->d_date = 10;
+ dd_dir->d_size = wfd.nFileSizeLow;
+ strcpy (dd_dir->d_name, wfd.cFileName);
+ return dd_dir;
+}
+
+int closedir (DIR *dd_dir)
+{
+ FindClose(dd_dir->d_handle);
+ free (dd_dir);
+ return 1;
+}
+
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#define INCL_DOSFILEMGR
+#define INCL_DOSERRORS
+#include <os2.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "dirent.h"
+
+DIR *opendir (const char * a_dir)
+{
+ APIRET rc;
+ FILEFINDBUF3 FindBuffer = {0};
+ ULONG FileCount = 1;
+ DIR *dd_dir = (DIR*) malloc (sizeof(DIR));
+ char *c_dir = (char*) malloc (strlen(a_dir) + 5);
+
+ strcpy (c_dir, a_dir);
+ strcat (c_dir, "\\*.*");
+ dd_dir->d_handle = (unsigned long*) HDIR_CREATE;
+
+ rc = DosFindFirst(c_dir,
+ (PHDIR) &dd_dir->d_handle,
+ FILE_SYSTEM | FILE_HIDDEN | FILE_DIRECTORY,
+ (PVOID) &FindBuffer,
+ sizeof(FILEFINDBUF3),
+ &FileCount,
+ FIL_STANDARD);
+
+ if (rc) {
+ switch (rc) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ case ERROR_BUFFER_OVERFLOW:
+ errno = ENOMEM;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ free(dd_dir);
+ return NULL;
+ }
+ dd_dir->d_attr = FindBuffer.attrFile;
+ dd_dir->d_time = dd_dir->d_date = 10;
+ dd_dir->d_size = FindBuffer.cbFile;
+ strcpy (dd_dir->d_name, FindBuffer.achName);
+ dd_dir->d_first = 1;
+
+ free (c_dir);
+ return dd_dir;
+}
+
+DIR *readdir( DIR * dd_dir)
+{
+ APIRET rc;
+ FILEFINDBUF3 FindBuffer = {0};
+ ULONG FileCount = 1;
+ DIR *ret_dir = (DIR*) malloc (sizeof(DIR));
+
+ if (dd_dir->d_first) {
+ dd_dir->d_first = 0;
+ return dd_dir;
+ }
+
+ rc = DosFindNext((HDIR) dd_dir->d_handle,
+ (PVOID) &FindBuffer,
+ sizeof(FILEFINDBUF3),
+ &FileCount);
+
+ if (rc) {
+ switch (rc) {
+ case ERROR_NO_MORE_FILES:
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+ case ERROR_BUFFER_OVERFLOW:
+ errno = ENOMEM;
+ break;
+ default:
+ errno = EINVAL;
+ break;
+ }
+ return NULL;
+ }
+
+ ret_dir->d_attr = FindBuffer.attrFile;
+ ret_dir->d_time = ret_dir->d_date = 10;
+ ret_dir->d_size = FindBuffer.cbFile;
+ strcpy (ret_dir->d_name, FindBuffer.achName);
+ return ret_dir;
+}
+
+int closedir (DIR *dd_dir)
+{
+ if (dd_dir->d_handle != (unsigned long*) HDIR_CREATE) {
+ DosFindClose((HDIR) dd_dir->d_handle);
+ }
+ free (dd_dir);
+ return 1;
+}
--- /dev/null
+/* Ch-Drive command for Windows NT and OS/2
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Bug:
+ the code will not work if you have more drives than those that
+ can fit in a panel.
+ */
+
+#include <config.h>
+#ifdef _OS_NT
+#include <windows.h>
+#include "util_win32.h"
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include "../src/tty.h"
+#include "../src/mad.h"
+#include "../src/util.h"
+#include "../src/win.h"
+#include "../src/color.h"
+#include "../src/dlg.h"
+#include "../src/widget.h"
+#include "../src/dialog.h"
+#include "../src/dir.h"
+#include "../src/panel.h"
+#include "../src/main.h"
+#include "../src/cmd.h"
+
+struct Dlg_head *drive_dlg;
+WPanel *this_panel;
+
+static int drive_dlg_callback (Dlg_head *h, int Par, int Msg);
+static void drive_dlg_refresh (void);
+static void drive_cmd(void);
+
+#define B_DRIVE_BASE 100
+#define MAX_LGH 13 /* Length for drives */
+
+static void drive_cmd()
+{
+ int i, nNewDrive, nDrivesAvail;
+ char szTempBuf[7], szDrivesAvail[27*4], *p;
+
+ /* Dialogbox position */
+ int x_pos;
+ int y_pos = (LINES-6)/2-3;
+ int y_height;
+ int x_width;
+
+ int m_drv;
+
+ /* Get drives name and count */
+#ifdef _OS_NT
+ GetLogicalDriveStrings (255, szDrivesAvail);
+ for (nDrivesAvail = 0, p = szDrivesAvail; *p; nDrivesAvail++)
+ p+=4;
+#else
+ unsigned long uDriveNum, uDriveMap;
+ nDrivesAvail = 0;
+ p = szDrivesAvail;
+ DosQueryCurrentDisk(&uDriveNum, &uDriveMap);
+ for (i = 0; i < 26; i++) {
+ if ( uDriveMap & (1 << i) ) {
+ *p = 'A' + i;
+ p += 4;
+ nDrivesAvail++;
+ }
+ }
+ *p = 0;
+#endif
+
+ /* Create Dialog */
+ do_refresh ();
+
+ m_drv = ((nDrivesAvail > MAX_LGH) ? MAX_LGH: nDrivesAvail);
+ /* Center on x, relative to panel */
+ x_pos = this_panel->widget.x + (this_panel->widget.cols - m_drv*3)/2 + 2;
+
+ if (nDrivesAvail > MAX_LGH) {
+ y_height = 8;
+ x_width = 33;
+ } else {
+ y_height = 6;
+ x_width = (nDrivesAvail - 1) * 2 + 9;
+ }
+
+ drive_dlg = create_dlg (y_pos, x_pos, y_height, x_width, dialog_colors,
+ drive_dlg_callback, _("[ChDrive]"),_("drive"), DLG_NONE);
+
+ x_set_dialog_title (drive_dlg, _("Change Drive") );
+
+ if (nDrivesAvail>MAX_LGH) {
+ for (i = 0; i < nDrivesAvail - MAX_LGH; i++) {
+ p -= 4;
+ sprintf(szTempBuf, "&%c", *p);
+ add_widgetl(drive_dlg,
+ button_new (5,
+ (m_drv-i-1)*2+4 - (MAX_LGH*2 - nDrivesAvail) * 2,
+ B_DRIVE_BASE + nDrivesAvail - i - 1,
+ HIDDEN_BUTTON,
+ szTempBuf, 0, NULL, NULL),
+ XV_WLAY_RIGHTOF);
+ }
+ }
+
+ /* Add a button for each drive */
+ for (i = 0; i < m_drv; i++) {
+ p -= 4;
+ sprintf (szTempBuf, "&%c", *p);
+ add_widgetl(drive_dlg,
+ button_new (3, (m_drv-i-1)*2+4, B_DRIVE_BASE+m_drv-i-1,
+ HIDDEN_BUTTON, szTempBuf, 0, NULL, NULL),
+ XV_WLAY_RIGHTOF);
+ }
+
+ run_dlg(drive_dlg);
+
+ /* do action */
+ if (drive_dlg->ret_value != B_CANCEL) {
+ int errocc = 0; /* no error */
+ int rtn;
+ char drvLetter;
+
+ /* Set the Panel to Directory listing mode first */
+ int is_right=(this_panel==right_panel);
+
+ set_display_type (is_right?1:0, view_listing);
+ this_panel=is_right?right_panel:left_panel;
+ /* */
+
+ nNewDrive = drive_dlg->ret_value - B_DRIVE_BASE;
+ drvLetter = (char) *(szDrivesAvail + (nNewDrive*4));
+#ifdef _OS_NT
+ if (win32_GetPlatform() == OS_WinNT) { /* Windows NT */
+ rtn = _chdrive(drvLetter - 'A' + 1);
+ } else { /* Windows 95 */
+ rtn = 1;
+ SetCurrentDirectory(szDrivesAvail+(nNewDrive*4));
+ }
+#else
+ rtn = DosSetDefaultDisk(nNewDrive + 1);
+#endif
+ if (rtn == -1)
+ errocc = 1;
+ else {
+ getcwd (this_panel->cwd, sizeof (this_panel->cwd)-2);
+ if (toupper(drvLetter) == toupper(*(this_panel->cwd))) {
+ clean_dir (&this_panel->dir, this_panel->count);
+ this_panel->count = do_load_dir(&this_panel->dir,
+ this_panel->sort_type,
+ this_panel->reverse,
+ this_panel->case_sensitive,
+ this_panel->filter);
+ this_panel->top_file = 0;
+ this_panel->selected = 0;
+ this_panel->marked = 0;
+ this_panel->total = 0;
+ show_dir(this_panel);
+ reread_cmd();
+ } else
+ errocc = 1;
+ }
+ if (errocc)
+ message (1, _(" Error "), _(" Can't access drive %c: "),
+ *(szDrivesAvail+(nNewDrive*4)) );
+ }
+ destroy_dlg (drive_dlg);
+ repaint_screen ();
+}
+
+
+void drive_cmd_a()
+{
+ this_panel = left_panel;
+ drive_cmd();
+}
+
+void drive_cmd_b()
+{
+ this_panel = right_panel;
+ drive_cmd();
+}
+
+void drive_chg(WPanel *panel)
+{
+ this_panel = panel;
+ drive_cmd();
+}
+
+static int drive_dlg_callback (Dlg_head *h, int Par, int Msg)
+{
+ switch (Msg) {
+#ifndef HAVE_X
+ case DLG_DRAW:
+ drive_dlg_refresh ();
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void drive_dlg_refresh (void)
+{
+ attrset (dialog_colors[0]);
+ dlg_erase (drive_dlg);
+ draw_box (drive_dlg, 1, 1, drive_dlg->lines-2, drive_dlg->cols-2);
+
+ attrset (dialog_colors[2]);
+ dlg_move (drive_dlg, 1, drive_dlg->cols/2 - 7);
+ addstr (_(" Change Drive "));
+}
--- /dev/null
+void drive_cmd_a(WPanel *);
+void drive_cmd_b(WPanel *);
+void drive_chg(WPanel *panel);
+
--- /dev/null
+/* Keyboard support routines.
+ for Windows NT system.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Bugs:
+ Have trouble with non-US keyboards, "Alt-gr"+keys (API tells CTRL-ALT is pressed)
+ */
+#include <config.h>
+#ifndef _OS_NT
+#error This file is for Win32 systems.
+#else
+
+#include <windows.h>
+#include <stdio.h>
+#include "../src/mouse.h"
+#include "../src/global.h"
+#include "../src/main.h"
+#include "../src/key.h"
+#include "../vfs/vfs.h"
+#include "../src/tty.h"
+#include "trace_nt.h"
+
+/* Global variables */
+int old_esc_mode = 0;
+HANDLE hConsoleInput;
+DWORD dwSaved_ControlState;
+Gpm_Event evSaved_Event;
+
+/* Unused variables */
+int double_click_speed; /* they are here to keep linker happy */
+int mou_auto_repeat;
+int use_8th_bit_as_meta = 0;
+
+/* Static Tables */
+struct {
+ int key_code;
+ int vkcode;
+} key_table [] = {
+ { KEY_F(1), VK_F1 },
+ { KEY_F(2), VK_F2 },
+ { KEY_F(3), VK_F3 },
+ { KEY_F(4), VK_F4 },
+ { KEY_F(5), VK_F5 },
+ { KEY_F(6), VK_F6 },
+ { KEY_F(7), VK_F7 },
+ { KEY_F(8), VK_F8 },
+ { KEY_F(9), VK_F9 },
+ { KEY_F(10), VK_F10 },
+ { KEY_F(11), VK_F11 },
+ { KEY_F(12), VK_F12 },
+ { KEY_F(13), VK_F13 },
+ { KEY_F(14), VK_F14 },
+ { KEY_F(15), VK_F15 },
+ { KEY_F(16), VK_F16 },
+ { KEY_F(17), VK_F17 },
+ { KEY_F(18), VK_F18 },
+ { KEY_F(19), VK_F19 },
+ { KEY_F(20), VK_F20 },
+ { KEY_IC, VK_INSERT },
+ { KEY_DC, VK_DELETE },
+ { KEY_BACKSPACE, VK_BACK },
+
+ { KEY_PPAGE, VK_PRIOR },
+ { KEY_NPAGE, VK_NEXT },
+ { KEY_LEFT, VK_LEFT },
+ { KEY_RIGHT, VK_RIGHT },
+ { KEY_UP, VK_UP },
+ { KEY_DOWN, VK_DOWN },
+ { KEY_HOME, VK_HOME },
+ { KEY_END, VK_END },
+
+ { ALT('*'), VK_MULTIPLY },
+ { ALT('+'), VK_ADD },
+ { ALT('-'), VK_SUBTRACT },
+
+ { ALT('\t'), VK_PAUSE }, /* Added to make Complete work press Pause */
+
+ { ESC_CHAR, VK_ESCAPE },
+
+ { 0, 0}
+};
+
+/* init_key - Called in main.c to initialize ourselves
+ Get handle to console input
+*/
+void init_key (void)
+{
+ win32APICALL_HANDLE (hConsoleInput, GetStdHandle (STD_INPUT_HANDLE));
+}
+
+int ctrl_pressed ()
+{
+ if(dwSaved_ControlState & RIGHT_ALT_PRESSED) return 0;
+ /* The line above fixes the BUG with the AltGr Keys*/
+ return dwSaved_ControlState & (RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED);
+}
+
+int shift_pressed ()
+{
+ if(dwSaved_ControlState & RIGHT_ALT_PRESSED) return 0;
+ /* The line above fixes the BUG with the AltGr Keys*/
+ return dwSaved_ControlState & SHIFT_PRESSED;
+}
+
+int alt_pressed ()
+{
+ return dwSaved_ControlState & (/* RIGHT_ALT_PRESSED | */ LEFT_ALT_PRESSED);
+}
+
+static int VKtoCurses (int a_vkc)
+{
+ int i;
+
+ for (i = 0; key_table[i].vkcode != 0; i++)
+ if (a_vkc == key_table[i].vkcode) {
+ return key_table[i].key_code;
+ }
+ return 0;
+}
+
+static int translate_key_code(int asc, int scan)
+{
+ int c;
+ switch(scan){
+ case 106: /* KP_MULT*/
+ return ALT('*');
+ case 107: /* KP_PLUS*/
+ return ALT('+');
+ case 109: /* KP_MINUS*/
+ return ALT('-');
+ }
+ c = VKtoCurses (scan);
+ if (!asc && !c)
+ return 0;
+ if (asc && c)
+ return c;
+ if (!asc || asc=='\t' )
+ {
+ if (shift_pressed() && (c >= KEY_F(1)) && (c <= KEY_F(10)))
+ c += 10;
+ if (alt_pressed() && (c >= KEY_F(1)) && (c <= KEY_F(2)))
+ c += 10;
+ if (alt_pressed() && (c == KEY_F(7)))
+ c = ALT('?');
+ if (asc == '\t'){
+ if(ctrl_pressed())c = ALT('\t');
+ else c=asc;
+ }
+ return c;
+ }
+ if (ctrl_pressed())
+ return XCTRL(asc);
+ if (alt_pressed())
+ return ALT(asc);
+ if (asc == 13)
+ return 10;
+ return asc;
+}
+
+int get_key_code (int no_delay)
+{
+ INPUT_RECORD ir; /* Input record */
+ DWORD dw; /* number of records actually read */
+ int ch, vkcode, j;
+
+ if (no_delay) {
+ /* Check if any input pending, otherwise return */
+ nodelay (stdscr, TRUE);
+ win32APICALL(PeekConsoleInput(hConsoleInput, &ir, 1, &dw));
+ if (!dw)
+ return 0;
+ }
+
+ do {
+ win32APICALL(ReadConsoleInput(hConsoleInput, &ir, 1, &dw));
+ switch (ir.EventType) {
+ case KEY_EVENT:
+ if (!ir.Event.KeyEvent.bKeyDown) /* Process key just once: when pressed */
+ break;
+
+ vkcode = ir.Event.KeyEvent.wVirtualKeyCode;
+//#ifndef __MINGW32__
+ ch = ir.Event.KeyEvent.uChar.AsciiChar;
+//#else
+// ch = ir.Event.KeyEvent.AsciiChar;
+//#endif
+ dwSaved_ControlState = ir.Event.KeyEvent.dwControlKeyState;
+ j = translate_key_code (ch, vkcode);
+ if (j)
+ return j;
+ break;
+
+ case MOUSE_EVENT:
+ /* Save event as a GPM-like event */
+ evSaved_Event.x = ir.Event.MouseEvent.dwMousePosition.X;
+ evSaved_Event.y = ir.Event.MouseEvent.dwMousePosition.Y+1;
+ evSaved_Event.buttons = ir.Event.MouseEvent.dwButtonState;
+ switch (ir.Event.MouseEvent.dwEventFlags) {
+ case 0:
+ evSaved_Event.type = GPM_DOWN | GPM_SINGLE;
+ break;
+ case MOUSE_MOVED:
+ evSaved_Event.type = GPM_MOVE;
+ break;
+ case DOUBLE_CLICK:
+ evSaved_Event.type = GPM_DOWN | GPM_DOUBLE;
+ break;
+ };
+ return 0;
+ }
+ } while (!no_delay);
+ return 0;
+}
+
+static int getch_with_delay (void)
+{
+ int c;
+
+ while (1) {
+ /* Try to get a character */
+ c = get_key_code (0);
+ if (c != ERR)
+ break;
+ }
+ /* Success -> return the character */
+ return c;
+}
+
+/* Returns a character read from stdin with appropriate interpretation */
+int get_event (Gpm_Event *event, int redo_event, int block)
+{
+ int c;
+ static int flag; /* Return value from select */
+ static int dirty = 3;
+
+ if ((dirty == 1) || is_idle ()){
+ refresh ();
+ doupdate ();
+ dirty = 1;
+ } else
+ dirty++;
+
+ vfs_timeout_handler ();
+
+ c = block ? getch_with_delay () : get_key_code (1);
+
+ if (!c) {
+ /* Code is 0, so this is a Control key or mouse event */
+ return EV_NONE; /* FIXME: mouse not supported */
+ }
+
+ return c;
+}
+
+/* Returns a key press, mouse events are discarded */
+int mi_getch ()
+{
+ Gpm_Event ev;
+ int key;
+
+ while ((key = get_event (&ev, 0, 1)) == 0)
+ ;
+ return key;
+}
+
+/*
+ is_idle - A function to check if we're idle.
+ It checks for any waiting event (that can be a Key, Mouse event,
+ and other internal events like focus or menu)
+*/
+int is_idle (void)
+{
+ DWORD dw;
+ if (GetNumberOfConsoleInputEvents (hConsoleInput, &dw))
+ if (dw > 15)
+ return 0;
+ return 1;
+}
+
+/* get_modifier */
+int get_modifier()
+{
+ int retval = 0;
+
+ if (dwSaved_ControlState & LEFT_ALT_PRESSED) /* code is not clean, because we return Linux-like bitcodes*/
+ retval |= ALTL_PRESSED;
+ if (dwSaved_ControlState & RIGHT_ALT_PRESSED)
+ retval |= ALTR_PRESSED;
+
+ if (dwSaved_ControlState & RIGHT_CTRL_PRESSED ||
+ dwSaved_ControlState & LEFT_CTRL_PRESSED)
+ retval |= CONTROL_PRESSED;
+
+ if (dwSaved_ControlState & SHIFT_PRESSED)
+ retval |= SHIFT_PRESSED;
+
+ return retval;
+}
+
+/* void functions for UNIX compatibility */
+void define_sequence (int code, char* vkcode, int action) {}
+void channels_up() {}
+void channels_down() {}
+void init_key_input_fd (void) {}
+void numeric_keypad_mode (void) {}
+void application_keypad_mode (void) {}
+
+/* mouse is not yet supported, sorry */
+void init_mouse (void) {}
+void shut_mouse (void) {}
+
+#endif /* _OS_NT */
--- /dev/null
+/* Keyboard support routines.
+ for OS/2 system.
+
+ 20. April 97: Alexander Dong (ado)
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <config.h>
+#ifndef __os2__
+#error This file is for OS/2 systems.
+#else
+
+#define INCL_BASE
+#define INCL_NOPM
+#define INCL_VIO
+#define INCL_KBD
+#define INCL_DOS
+#define INCL_DOSERRORS
+#define INCL_WININPUT
+#include <os2.h>
+#include <stdio.h>
+#include "../src/mouse.h"
+#include "../src/global.h"
+#include "../src/main.h"
+#include "../src/key.h"
+#include "../vfs/vfs.h"
+#include "../src/tty.h"
+
+/* Code to read keystrokes in a separate thread */
+
+typedef struct kbdcodes {
+ UCHAR ascii;
+ UCHAR scan;
+ USHORT shift; /* .ado: change for mc */
+} KBDCODES;
+
+/* Global variables */
+int old_esc_mode = 0;
+/* HANDLE hConsoleInput;
+DWORD dwSaved_ControlState; */
+Gpm_Event evSaved_Event;
+
+/* Unused variables */
+int double_click_speed; /* they are here to keep linker happy */
+int mou_auto_repeat;
+int use_8th_bit_as_meta = 0;
+
+static int VKtoCurses (int vkcode);
+
+/* -------------------------------------------------------------- */
+/* DEFINITIONS:
+ Return from SLANG: KeyCode: 0xaaaabbcc
+
+ where: aaaa = Flags
+ bb = Scan code
+ cc = ASCII-code (if available)
+
+ if no flags (CTRL and ALT) is set, cc will be returned.
+ If CTRL is pressed, cc is already the XCTRL(code).
+ case cc is:
+ 0xE0: The scan code will be used for the following keys:
+ Insert: 0x52, DEL: 0x53,
+ Page_Up: 0x49, Page_Down: 0x51,
+ Pos1: 0x47, Ende: 0x4F,
+ Up: 0x48, Down: 0x50,
+ Left: 0x4B, Right: 0x4D,
+
+ 0x00: The function keys are defined as:
+ F1: 3b00, F2: 3c00 ... F10: 4400, F11: 8500, F12: 8600.
+ With ALT-bit set:
+ ALT(F1): 6800, 6900,... ALT(F10): 7100, ALT(F11): 8b00
+ ALT(F12): 8c00
+
+ Mapping for ALT(key_code):
+ For Mapping with normal keys, only the scan code can be
+ used. (see struct ALT_table)
+
+ Special keys:
+ ENTER (number block): 0xaaaaE00D
+ + (number block): 0xaaaa4E2B Normal: 1B2B
+ - (number block): 0xaaaa4A2D Normal: 352D
+ * (number block): 0xaaaa372A Normal: 1B2A
+ / (number block): 0xaaaaE02F
+*/
+/* -------------------------------------------------------------- */
+#define RIGHT_SHIFT_PRESSED 1
+#define LEFT_SHIFT_PRESSED 2
+#define CTRL_PRESSED 4
+#define ALT_PRESSED 8
+#define SCROLL_LOCK_MODE 16
+#define NUM_LOCK_MODE 32
+#define CAPS_LOCK_MODE 64
+#define INSERT_MODE 128
+#define LEFT_CTRL_PRESSED 256
+#define LEFT_ALT_PRESSED 512
+#define RIGHT_CTRL_PRESSED 1024
+#define RIGHT_ALT_PRESSED 2048
+#define SCROLL_LOCK_PRESSED 4096
+#define NUM_LOCK_PRESSED 8192
+#define CAPS_LOCK_PRESSED 16384
+#define SYSREQ 32768
+/* -------------------------------------------------------------- */
+
+/* Static Tables */
+struct {
+ int key_code;
+ int vkcode;
+} fkt_table [] = {
+ { KEY_F(1), 0x3B },
+ { KEY_F(2), 0x3C },
+ { KEY_F(3), 0x3D },
+ { KEY_F(4), 0x3E },
+ { KEY_F(5), 0x3F },
+ { KEY_F(6), 0x40 },
+ { KEY_F(7), 0x41 },
+ { KEY_F(8), 0x42 },
+ { KEY_F(9), 0x43 },
+ { KEY_F(10), 0x44 },
+ { KEY_F(11), 0x85 },
+ { KEY_F(12), 0x86 },
+ { 0, 0}
+};
+
+
+struct {
+ int key_code;
+ int vkcode;
+} ALT_table [] = {
+ { ALT('a'), 0x1E },
+ { ALT('b'), 0x30 },
+ { ALT('c'), 0x2E },
+ { ALT('d'), 0x20 },
+ { ALT('e'), 0x12 },
+ { ALT('f'), 0x21 },
+ { ALT('g'), 0x22 },
+ { ALT('h'), 0x23 },
+ { ALT('i'), 0x17 },
+ { ALT('j'), 0x24 },
+ { ALT('k'), 0x25 },
+ { ALT('l'), 0x26 },
+ { ALT('m'), 0x32 },
+ { ALT('n'), 0x31 },
+ { ALT('o'), 0x18 },
+ { ALT('p'), 0x19 },
+ { ALT('q'), 0x10 },
+ { ALT('r'), 0x13 },
+ { ALT('s'), 0x1F },
+ { ALT('t'), 0x14 },
+ { ALT('u'), 0x16 },
+ { ALT('v'), 0x2F },
+ { ALT('w'), 0x11 },
+ { ALT('x'), 0x2D },
+ { ALT('y'), 0x15 },
+ { ALT('z'), 0x2C },
+ { ALT('\n'), 0x1c },
+ { ALT('\n'), 0xA6 },
+ { ALT(KEY_F(1)), 0x68 },
+ { ALT(KEY_F(2)), 0x69 },
+ { ALT(KEY_F(3)), 0x6A },
+ { ALT(KEY_F(4)), 0x6B },
+ { ALT(KEY_F(5)), 0x6C },
+ { ALT(KEY_F(6)), 0x6D },
+ { ALT(KEY_F(7)), 0x6E },
+ { ALT(KEY_F(8)), 0x6F },
+ { ALT(KEY_F(9)), 0x70 },
+ { ALT(KEY_F(10)), 0x71 },
+ { ALT(KEY_F(11)), 0x8B },
+ { ALT(KEY_F(12)), 0x8C },
+ { 0, 0}
+};
+
+
+struct {
+ int key_code;
+ int vkcode;
+} movement [] = {
+ { KEY_IC, 0x52 },
+ { KEY_DC, 0x53 },
+ { KEY_PPAGE, 0x49 },
+ { KEY_NPAGE, 0x51 },
+ { KEY_LEFT, 0x4B },
+ { KEY_RIGHT, 0x4D },
+ { KEY_UP, 0x48 },
+ { KEY_DOWN, 0x50 },
+ { KEY_HOME, 0x47 },
+ { KEY_END, 0x4F },
+ { 0, 0}
+};
+
+
+/* init_key -- to make linker happy */
+void init_key (void)
+{
+ return;
+}
+
+
+/* The maximum sequence length (32 + null terminator) */
+static int seq_buffer[33];
+static int *seq_append = 0;
+
+static int push_char (int c)
+{
+ if (!seq_append)
+ seq_append = seq_buffer;
+
+ if (seq_append == &(seq_buffer [sizeof (seq_buffer)-2]))
+ return 0;
+ *(seq_append++) = c;
+ *seq_append = 0;
+ return 1;
+}
+
+int get_key_code (int no_delay)
+{
+ unsigned int inp_ch;
+
+ if (no_delay) {
+ /* Check if any input pending, otherwise return */
+ nodelay (stdscr, TRUE);
+ inp_ch = SLang_input_pending(0);
+ if (inp_ch == 0) {
+ return 0;
+ }
+ }
+
+ if (no_delay) {
+ return (VKtoCurses(inp_ch));
+ }
+
+ do {
+ inp_ch = SLang_getkey();
+ if (!inp_ch)
+ inp_ch = (SLang_getkey() << 8);
+ if (inp_ch) return (VKtoCurses(inp_ch));
+ } while (!no_delay);
+ return 0;
+}
+
+static int VKtoCurses (int a_vkc)
+{
+ int ctrlState = 0;
+ int altState = 0;
+
+ int fsState;
+ char scanCode;
+ char asciiCode;
+ register int i;
+ int rtnCode = 0;
+
+ fsState = (a_vkc & 0xFFFF0000) >> 16;
+ fsState &= (~INSERT_MODE); /* Ignore Insertion mode */
+
+ scanCode = (char) ((a_vkc & 0x0000FFFF) >> 8);
+ asciiCode = (char) (a_vkc & 0x000000FF);
+
+ ctrlState = (fsState & CTRL_PRESSED);
+ altState = (fsState & ALT_PRESSED);
+
+ rtnCode = asciiCode;
+
+ if (ctrlState) {
+ /* CTRL pressed */
+ rtnCode = XCTRL(asciiCode);
+ }
+
+ if (altState) {
+ /* ALT pressed
+ * rtnCode = ALT(asciiCode);
+ *
+ * With German keyboards, the Values between 7B -> 7D
+ * and 5b, 5d, 40, fd, fc and e6 are only reachable with the AltGr
+ * key. If such a combination is used, asciiCode will not be zero.
+ * With the normal ALT key, the asciiCode will always be zero.
+ */
+ if (asciiCode) {
+ return asciiCode;
+ }
+ }
+
+ /* Scan Movement codes */
+ if (asciiCode == 0) {
+ /* Replace key code with that in table */
+ for (i=0; movement[i].vkcode != 0 || movement[i].key_code != 0; i++)
+ if (scanCode == movement[i].vkcode)
+ return (movement[i].key_code);
+ }
+
+ if (asciiCode == 0) {
+ /* Function-key detected */
+ for (i=0; fkt_table[i].vkcode != 0 || fkt_table[i].key_code != 0; i++)
+ if (scanCode == fkt_table[i].vkcode)
+ return (fkt_table[i].key_code);
+ /* ALT - KEY */
+ /* if (altState) */ {
+ for (i=0; ALT_table[i].vkcode != 0 || ALT_table[i].key_code != 0; i++)
+ if (scanCode == ALT_table[i].vkcode)
+ return (ALT_table[i].key_code);
+ }
+ }
+
+ if (asciiCode == 0x0d) {
+ return '\n';
+ }
+
+ return rtnCode;
+}
+
+
+static int getch_with_delay (void)
+{
+ int c;
+
+ while (1) {
+ /* Try to get a character */
+ c = get_key_code (0);
+ if (c != ERR)
+ break;
+ }
+ /* Success -> return the character */
+ return c;
+}
+
+int get_event (Gpm_Event *event, int redo_event, int block)
+{
+ int c;
+ static int dirty = 3;
+
+ if ((dirty == 1) || is_idle ()){
+ refresh ();
+ doupdate ();
+ dirty = 1;
+ } else
+ dirty++;
+
+ vfs_timeout_handler ();
+
+ c = block ? getch_with_delay () : get_key_code (1);
+ if (!c) {
+ /* Code is 0, so this is a Control key or mouse event */
+ *event = evSaved_Event;
+ return EV_NONE; /* FIXME: when should we return EV_MOUSE ? */
+ }
+
+ return c;
+}
+
+/* Returns a key press, mouse events are discarded */
+int mi_getch ()
+{
+ Gpm_Event ev;
+ int key;
+
+ while ((key = get_event (&ev, 0, 1)) == 0)
+ ;
+ return key;
+}
+
+
+/*
+ is_idle - A function to check if we're idle.
+ It checks for any waiting event (that can be a Key, Mouse event,
+ and other internal events like focus or menu)
+*/
+int is_idle (void)
+{
+ return 1;
+}
+
+/* get_modifier */
+int get_modifier()
+{
+ return 0;
+}
+
+int ctrl_pressed ()
+{
+ return 0;
+}
+
+
+/* void functions for UNIX copatibility */
+void define_sequence (int code, char* vkcode, int action) {}
+void channels_up() {}
+void channels_down() {}
+void init_key_input_fd (void) {}
+void numeric_keypad_mode (void) {}
+void application_keypad_mode (void) {}
+
+/* mouse is not yet supported, sorry */
+void init_mouse (void) {}
+void shut_mouse (void) {}
+
+#endif /* __os2__ */
--- /dev/null
+#include "../VERSION"
+#ifndef WINDRES
+# include "windows.h"
+# include "winver.h"
+#endif
+
+/* English (U.S.) resources */
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+
+#ifdef _WIN32
+#ifndef WINDRES
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#endif
+#pragma code_page(1252)
+#endif /* _WIN32 */
+
+/* Version */
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 3,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40000L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904E4"
+ BEGIN
+ VALUE "CompanyName", "Free Software Foundation"
+ VALUE "FileDescription", "GNU Midnight Commander"
+ VALUE "FileVersion", VERSION
+ VALUE "InternalName", "MC"
+ VALUE "LegalCopyright", "(c) Free Software Foundation"
+ VALUE "LegalTrademarks", "see GNU General Public License"
+ VALUE "OriginalFilename", "MC.EXE"
+ VALUE "ProductName", "GNU Midnight Commander"
+ VALUE "ProductVersion", VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1252
+ END
+END
+
+
+/* Icon */
+// 0 ICON DISCARDABLE "mc_nt.ico"
+// 1 ICON DISCARDABLE "bez03.ico"
+
+#endif /* English (U.S.) resources */
+
--- /dev/null
+ This is the port of Midnight Commander for OS/2, Windows 95 and Windows NT.
+
+ This port is based on the port for Windows NT by
+ Juan Grigera <grigera@isis.unlp.edu.ar>
+and the port for OS/2 by
+ Alexander Dong <ado@software-ag.de>
+and is currently maintained by
+ Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ This port of the Midnight Commander is released under the GNU General
+Public License version 2.0 or any later version. See file COPYING for
+details.
+
+ Following compilers are supported:
+ For Windows NT:
+ Makefile.VC4: Microsoft Visual C++ 4.0 and above
+ Makefile.BC5: Borland C++ 5.x
+ For OS/2:
+ Makefile.EMX: EMX/GCC
+ Makefile.BC2: Borland C++ 2.x
+ Makefile.IBM: IBM CSet or Visual Age C++
+
+ You need GNU make in order to compile mc. Other implementation of
+make will not work! Run
+
+gmake -f Makefile.xxx [RELEASE=1]
+
+where gmake is name of GNU make and Makefile.xxx is the makefile for
+your compiler. You may want to add RELEASE=1 if you want to compile an
+optimized version without debug information.
+ Please note, that not all compilers are equal. You may need to create
+dummy include files or change something in order to be able to compile
+mc. BUT PLEASE DON'T TRY TO INCORPORATE SUCH QUICK HACKS INTO THE
+MC DISTRIBUTION! Try to make your changes work with all other compilers.
+ If you add a file, don't forget to add it into FILES statement of
+Makefile in this directory. Otherwise this file will not be copied to
+the distribution.
+ This port is not very stable now. See files BUGS and TODO in this
+directory.
+
+Pavel Roskin <pavel.roskin@ecsoft.co.uk>
--- /dev/null
+/* Slang interface to the Midnight Commander for Windows NT and OS/2
+ This emulates some features of ncurses on top of slang
+ S-lang is not fully consistent between its Unix and non-Unix versions.
+
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include "../src/tty.h"
+#include "../src/mad.h"
+#include "../src/color.h"
+#include "../src/util.h"
+#include "../src/mouse.h" /* Gpm_Event is required in key.h */
+#include "../src/key.h" /* define_sequence */
+#include "../src/main.h" /* extern: force_colors */
+#include "../src/win.h" /* do_exit_ca_mode */
+
+#ifdef HAVE_SLANG
+
+
+static void slang_sigterm ()
+{
+ SLsmg_reset_smg ();
+}
+
+static int slinterrupt;
+
+void enable_interrupt_key(void)
+{
+ SLang_set_abort_signal(NULL);
+ slinterrupt = 1;
+}
+void disable_interrupt_key(void)
+{
+ slinterrupt = 0;
+}
+int got_interrupt ()
+{
+ int t;
+ int SLKeyboard_Quit=0; /* FIXME!! */
+ t = slinterrupt ? SLKeyboard_Quit : 0;
+ /* SLKeyboard_Quit = 0; */
+ return t;
+}
+
+/* Only done the first time */
+void slang_init (void)
+{
+ SLtt_get_terminfo ();
+ SLang_init_tty (XCTRL('c'), 1, 0);
+ slang_prog_mode ();
+ load_terminfo_keys ();
+}
+
+/* Done each time we come back from done mode */
+void slang_prog_mode (void)
+{
+ SLsmg_init_smg ();
+ SLsmg_touch_lines (0, LINES);
+}
+
+/* Called each time we want to shutdown slang screen manager */
+void slang_shell_mode (void)
+{
+
+}
+
+void slang_shutdown ()
+{
+ slang_shell_mode ();
+ do_exit_ca_mode ();
+ SLang_reset_tty ();
+
+ /* reset the colors to those that were
+ * active when the program was started up
+ (not written)
+ */
+}
+
+/* keypad routines */
+void slang_keypad (int set)
+{
+ /* enable keypad strings */
+}
+
+static int no_slang_delay;
+
+void set_slang_delay (int v)
+{
+ no_slang_delay = v;
+}
+
+void hline (int ch, int len)
+{
+ int last_x, last_y;
+
+ last_x = SLsmg_get_column ();
+ last_y = SLsmg_get_row ();
+
+ if (ch == 0)
+ ch = ACS_HLINE;
+
+ if (ch == ACS_HLINE){
+ SLsmg_draw_hline (len);
+ } else {
+ while (len--)
+ addch (ch);
+ }
+ move (last_y, last_x);
+}
+
+void vline (int character, int len)
+{
+ if (!slow_terminal){
+ SLsmg_draw_vline (len);
+ } else {
+ int last_x, last_y, pos = 0;
+
+ last_x = SLsmg_get_column ();
+ last_y = SLsmg_get_row ();
+
+ while (len--){
+ move (last_y + pos++, last_x);
+ addch (' ');
+ }
+ move (last_x, last_y);
+ }
+}
+
+int has_colors ()
+{
+ /* No terminals on NT, make default color */
+ if (!disable_colors)
+ SLtt_Use_Ansi_Colors = 1;
+
+ /* Setup emulated colors */
+ if (SLtt_Use_Ansi_Colors){
+ /* DO NOT TRANSLATE WITH gettext SYNTAX coloring will be broken */
+ init_pair (A_REVERSE, "black", "white");
+ } else {
+/* SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
+ SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
+ SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
+ */ }
+ return SLtt_Use_Ansi_Colors;
+}
+
+void attrset (int color)
+{
+ if (!SLtt_Use_Ansi_Colors){
+ SLsmg_set_color (color);
+ return;
+ }
+
+ if (color & A_BOLD){
+ if (color == A_BOLD)
+ SLsmg_set_color (A_BOLD);
+ else
+ SLsmg_set_color ((color & (~A_BOLD)) + 8);
+ return;
+ }
+
+ if (color == A_REVERSE)
+ SLsmg_set_color (A_REVERSE);
+ else
+ SLsmg_set_color (color);
+}
+
+void load_terminfo_keys ()
+{
+}
+
+int getch ()
+{
+ if (no_slang_delay)
+ if (SLang_input_pending (0) == 0)
+ return -1;
+
+ return SLang_getkey ();
+}
+
+extern int slow_terminal;
+
+#else
+
+/* Non slang builds do not understand got_interrupt */
+int got_interrupt ()
+{
+ return 0;
+}
+#endif /* HAVE_SLANG */
+
+void mc_refresh (void)
+{
+/* if (!we_are_background) (no background mode yet) */
+ refresh ();
+}
+
+void slang_set_raw_mode (void)
+{
+ return;
+}
+
+int max_index = 0;
+
+void
+init_pair (int index, char *foreground, char *background)
+{
+
+ SLtt_set_color (index, "", foreground, background);
+ if (index > max_index)
+ max_index = index;
+}
+
+int
+alloc_color_pair (char *foreground, char *background)
+{
+ init_pair (++max_index, foreground, background);
+ return max_index;
+}
+
+int
+try_alloc_color_pair (char *fg, char *bg)
+{
+ static struct colors_avail {
+ struct colors_avail *next;
+ char *fg, *bg;
+ int index;
+ } *p, c =
+ {
+ 0, 0, 0, 0
+ };
+
+ c.index = NORMAL_COLOR;
+ p = &c;
+ for (;;) {
+ if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
+ && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
+ return p->index;
+ if (!p->next)
+ break;
+ p = p->next;
+ }
+ p->next = malloc (sizeof (c));
+ p = p->next;
+ p->next = 0;
+ p->fg = fg ? strdup (fg) : 0;
+ p->bg = bg ? strdup (bg) : 0;
+ /* DO NOT TRANSLATE WITH gettext SYNTAX coloring will be broken */
+ if (!fg)
+ fg = "white";
+ if (!bg)
+ bg = "blue";
+ p->index = alloc_color_pair (fg, bg);
+ return p->index;
+}
--- /dev/null
+/* Systems having sys/param.h should not include this file */
+
+#ifdef HAVE_PARAM_H
+#error Remove this file if you have real sys/param.h
+#else
+/* FIXME: We should warn, that this file should not be included */
+#endif
--- /dev/null
+
+#ifndef _SYS_TIME_H
+#define _SYS_TIME_H
+
+#ifndef _WINSOCKAPI_ /* winsock.h defines struct timeval */
+
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+
+#endif
+
+int gettimeofday (struct timeval*, void *);
+
+#endif
--- /dev/null
+TODO
+
+- Make most files common for OS/2 and NT
+- Move settings from mc.ini to the registry for Windows NT/95 (optionally?)
+- Fix opendir/readdir d_date and d_time packing (they return 10).
+- Fix gettimeofday()
+- Write a better stat function than the one RTL gives us. We can provide
+user ID (on NT) and rwx permissions.
+- Optionally use vfsapi.lib for ext2 filesystems on OS/2
+- Write the VFS
+- Write a better documentation
+- Write a better canonify_pathname()
--- /dev/null
+/* trace_nt.c - Debugging routines
+ for Midnight Commander, under Win32
+
+ Written 951215 by Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <config.h>
+#ifdef HAVE_TRACE
+
+#include <stdio.h>
+#ifdef _OS_NT
+#include <windows.h>
+#endif
+#include <errno.h>
+#include "trace_nt.h"
+
+/* Global variables */
+int __win32_tracing_enabled = 1;
+
+static int _win32_tracing_started = 0;
+static FILE *__win32_trace_f = NULL;
+
+/* Definitions */
+#define TRACE_FILE "mcTrace.out"
+
+/* Prototypes - static funcs */
+static void _win32InitTrace (void);
+static void _win32EndTrace (void);
+static const char* GetLastErrorText(void);
+static char *visbuf(const char *buf);
+
+
+/*
+ void _win32InitTrace()
+ This func will open file TRACE_FILE for output and add _win32EndTrace to onexit
+ list of funcs.
+ */
+static void _win32InitTrace()
+{
+ if (!_win32_tracing_started) {
+ _win32_tracing_started = 1;
+
+ __win32_trace_f = fopen(TRACE_FILE, "wt");
+ if (__win32_trace_f == NULL) {
+ printf("Midnight Commander[DEBUG]: Can't open trace file '" TRACE_FILE "': %s \n", strerror(errno));
+ }
+ atexit (&_win32EndTrace);
+ }
+}
+
+/*
+ void _win32EndTrace()
+ This func closes file TRACE_FILE if opened.
+ */
+static void _win32EndTrace()
+{
+ if (_win32_tracing_started) {
+ _win32_tracing_started = 0;
+ if (__win32_trace_f)
+ fclose (__win32_trace_f);
+ }
+
+}
+
+/*
+ void _win32Trace (char *fmt, ...)
+ Format and output debug strings. They are written to TRACE_FILE.
+ Debug Output is controlled by SetTrace (see below).
+ Win32: Output is sent to Debug Output also.
+ */
+void _win32Trace (const char *fmt, ...)
+{
+ va_list ap;
+ char buffer[256];
+ char *vp;
+
+
+ if (!_win32_tracing_started)
+ _win32InitTrace();
+
+ va_start(ap, fmt);
+ vsprintf(buffer, fmt, ap);
+ vp = buffer;
+
+#ifdef _OS_NT /* Write Output to Debug monitor also */
+ OutputDebugString (vp);
+ #if (_MSC_VER > 800) /* Don't write newline in MSVC++ 1.0, has a dammed bug in Debug Output screen */
+ OutputDebugString ("\n");
+ #endif
+#endif
+
+ if(__win32_trace_f)
+ fprintf (__win32_trace_f, "%s\n", vp);
+}
+
+/*
+ void SetTrace (int trace)
+ Control debug output. Turn it of or on.
+ trace: 0 = off, 1 = on.
+ */
+void _win32SetTrace (int trace)
+{
+ /* Prototypes - interlan funcs */
+ __win32_tracing_enabled = trace;
+}
+void _win32TraceOn ()
+{
+ __win32_tracing_enabled = 1;
+}
+void _win32TraceOff()
+{
+ __win32_tracing_enabled = 0;
+}
+
+
+#ifdef _OS_NT
+/*
+ void DebugFailedWin32APICall (const char* name, int line, const char* file)
+ Report a System call failure.
+ name - text containing the source code that called the offending API func
+ line, file - place of "name" in code
+
+ See Also: definition of win32APICALL macro.
+ */
+void _win32DebugFailedWin32APICall (const char* name, int line, const char* file)
+{
+ _win32Trace ("%s(%d): Call to Win32 API Failed. \"%s\".", file, line, name);
+ _win32Trace (" System Error (%d): %s. ", GetLastError(), GetLastErrorText());
+}
+#endif
+
+/*
+ void DebugAssertionFailed (const char* name, int line, const char* file)
+ Report a logical condition failure. (e.g. a bad argument to a func)
+ name - text containing the logical condition
+ line, file - place of "name" in code
+
+ See Also: definition of ASSERT macro.
+ */
+void _win32DebugAssertionFailed (const char* name, int line, const char* file)
+{
+ _win32Trace ("%s(%d): Assertion failed! \"%s\".", file, line, name);
+}
+
+
+/* const char* GetLastErrorText()
+ Retrieves the text associated with the last system error.
+
+ Returns pointer to static buffer. Contents valid till next call
+*/
+static const char* GetLastErrorText()
+{
+#define MAX_MSG_SIZE 256
+ static char szMsgBuf[MAX_MSG_SIZE];
+ DWORD dwError, dwRes;
+
+ dwError = GetLastError ();
+
+ dwRes = FormatMessage (
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ dwError,
+ MAKELANGID (LANG_ENGLISH, SUBLANG_ENGLISH_US),
+ szMsgBuf,
+ MAX_MSG_SIZE,
+ NULL);
+ if (0 == dwRes) {
+ sprintf (szMsgBuf, "FormatMessage failed with %d", GetLastError());
+ }
+ return szMsgBuf;
+}
+
+#endif /*HAVE_TRACE*/
--- /dev/null
+/* trace_nt.h - Debugging routines
+
+ Written by Juan Grigera<grigera@isis.unlp.edu.ar>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* ------------------------------------------------------------------------------------------ *
+ TRACER FUNCTIONS
+ * ------------------------------------------------------------------------------------------ */
+
+#ifdef HAVE_TRACE
+/************************/
+/* Debug version */
+/************************/
+
+/* Macros
+ ------
+ win32Trace(x) - Trace macro. Use double in parenthesis for x. Same args as printf.
+ win32ASSERT(x) - assert macro, but will not abort program and output sent to trace routine.
+ win32APICALL(x) - Use to enclose a Win32 system call that should return TRUE.
+ win32APICALL_HANDLE(h,api) - Use to enclose a Win32 system call that should return a handle.
+*/
+#define win32Trace(x) if (__win32_tracing_enabled) _win32Trace x
+#define win32ASSERT(x) if (!(x)) _win32DebugAssertionFailed (#x, __LINE__, __FILE__)
+#define win32APICALL(x) if (!(x)) _win32DebugFailedWin32APICall (#x, __LINE__, __FILE__)
+#define win32APICALL_HANDLE(h,api) h=api; if (h==INVALID_HANDLE_VALUE) _win32DebugFailedWin32APICall (#h" = "#api, __LINE__, __FILE__)
+
+/* Prototypes */
+void _win32Trace (const char *, ...);
+void _win32DebugFailedWin32APICall (const char *name, int line, const char *file);
+void _win32DebugAssertionFailed (const char *name, int line, const char *file);
+
+void _win32SetTrace (int trace);
+void _win32TraceOn (void);
+void _win32TraceOff (void);
+
+#define SetTrace _win32SetTrace
+#define TraceOn _win32TraceOn
+#define TraceOff _win32TraceOff
+
+/* Global variables */
+extern int __win32_tracing_enabled;
+
+#else
+/************************/
+/* Non-debug version */
+/************************/
+
+/* Wipe-out these macros */
+#define win32Trace(x)
+#define win32ASSERT(x)
+#define win32APICALL(x) x
+#define win32APICALL_HANDLE(h,api) h=api;
+
+/* Wipe-out these funcs */
+#define SetTrace(x)
+#define TraceOn()
+#define TraceOff()
+#endif
--- /dev/null
+/* Various utilities - NT versions
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+
+ Written 1994, 1995, 1996 by:
+ Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
+ Jakub Jelinek, Mauricio Plaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h> /* my_system */
+#include <limits.h> /* INT_MAX */
+#include <errno.h>
+#if defined(_MSC_VER)
+#include <sys/time.h___> /* select: timeout */
+#else
+#include <sys/time.h> /* select: timeout */
+#endif
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <process.h>
+#include "../src/fs.h"
+#include "../src/util.h"
+#include "util_win32.h"
+
+#ifdef __BORLANDC__
+#define ENOTEMPTY ERROR_DIR_NOT_EMPTY
+#endif
+
+char *get_owner (int uid)
+{
+ return "none";
+}
+
+char *get_group (int gid)
+{
+ return "none";
+}
+
+/* Pipes are guaranteed to be able to hold at least 4096 bytes */
+/* More than that would be unportable */
+#define MAX_PIPE_SIZE 4096
+
+static int error_pipe[2]; /* File descriptors of error pipe */
+static int old_error; /* File descriptor of old standard error */
+
+/* Creates a pipe to hold standard error for a later analysis. */
+/* The pipe can hold 4096 bytes. Make sure no more is written */
+/* or a deadlock might occur. */
+void open_error_pipe (void)
+{
+ if (pipe (error_pipe) < 0){
+ message (0, _(" Warning "), _(" Pipe failed ") );
+ }
+ old_error = dup (2);
+ if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
+ message (0, _(" Warning "), _(" Dup failed ") );
+ close (error_pipe[0]);
+ close (error_pipe[1]);
+ }
+ close (error_pipe[1]);
+}
+
+void close_error_pipe (int error, char *text)
+{
+ char *title;
+ char msg[MAX_PIPE_SIZE];
+ int len = 0;
+
+ if (error)
+ title = _(" Error ");
+ else
+ title = _(" Warning ");
+ if (old_error >= 0){
+ close (2);
+ dup (old_error);
+ close (old_error);
+ len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
+
+ if (len >= 0)
+ msg[len] = 0;
+ close (error_pipe[0]);
+ }
+ if (error < 0)
+ return; /* Just ignore error message */
+ if (text == NULL){
+ if (len == 0) return; /* Nothing to show */
+
+ /* Show message from pipe */
+ message (error, title, msg);
+ } else {
+ /* Show given text and possible message from pipe */
+ message (error, title, " %s \n %s ", text, msg);
+ }
+}
+
+void check_error_pipe (void)
+{
+ char error[MAX_PIPE_SIZE];
+ int len = 0;
+ if (old_error >= 0){
+ while (len < MAX_PIPE_SIZE)
+ {
+ int rvalue;
+
+ rvalue = -1; // read (error_pipe[0], error + len, 1);
+ if (rvalue <= 0)
+ break;
+ len ++;
+ }
+ error[len] = 0;
+ close (error_pipe[0]);
+ }
+ if (len > 0)
+ message (0, _(" Warning "), error);
+}
+
+int my_system (int as_shell_command, const char *shell, const char *command)
+{
+ int status = 0;
+
+#if 0
+/* .ado: temp. turn out */
+ if (as_shell_command) {
+ /* It is only the shell, /c will not work */
+ if (command)
+ spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
+ else
+ spawnlp (P_WAIT, shell, (char *) 0);
+ } else
+ spawnl (P_WAIT, shell, shell, command, (char *) 0);
+
+ if (win32_GetPlatform() == OS_Win95) {
+ SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
+ }
+#endif
+ if (as_shell_command) {
+ if (!access(command, 0)) {
+ switch(win32_GetEXEType (shell)) {
+ case EXE_win16: /* Windows 3.x archive or OS/2 */
+ case EXE_win32GUI: /* NT or Chicago GUI API */
+ spawnlp (P_NOWAIT, shell, shell, "/c", command, (char *) 0); /* don't wait for GUI programs to end */
+ break;
+ case EXE_otherCUI: /* DOS COM, MZ, ZM, Phar Lap */
+ case EXE_win32CUI: /* NT or Chicago Console API, also OS/2 */
+ case EXE_Unknown:
+ default:
+ spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
+ break;
+ }
+ }
+ else
+ spawnlp (P_WAIT, shell, shell, "/c", command, (char *) 0);
+ }
+ else
+ spawnl (P_WAIT, shell, shell, command, (char *) 0);
+
+ if (win32_GetPlatform() == OS_Win95) {
+ SetConsoleTitle ("GNU Midnight Commander"); /* title is gone after spawn... */
+ }
+
+ return status;
+}
+
+/* get_default_shell
+ Get the default shell for the current hardware platform
+*/
+char* get_default_shell()
+{
+ if (win32_GetPlatform() == OS_WinNT)
+ return "cmd.exe";
+ else
+ return "command.com";
+}
+
+char *tilde_expand (char *directory)
+{
+ return strdup (directory);
+}
+
+/* sleep: Call Windows API.
+ Can't do simple define. That would need <windows.h> in every source
+*/
+#ifndef __EMX__
+void sleep(unsigned long dwMiliSecs)
+{
+ Sleep(dwMiliSecs);
+}
+#endif
+
+/* Canonicalize path, and return a new path. Do everything in situ.
+ The new path differs from path in:
+ Multiple `/'s are collapsed to a single `/'.
+ Leading `./'s and trailing `/.'s are removed.
+ Trailing `/'s are removed.
+ Non-leading `../'s and trailing `..'s are handled by removing
+ portions of the path. */
+char *canonicalize_pathname (char *path)
+{
+ int i, start;
+ char stub_char;
+
+ stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
+
+ /* Walk along path looking for things to compact. */
+ i = 0;
+ for (;;) {
+ if (!path[i])
+ break;
+
+ while (path[i] && path[i] != PATH_SEP)
+ i++;
+
+ start = i++;
+
+ /* If we didn't find any slashes, then there is nothing left to do. */
+ if (!path[start])
+ break;
+
+ /* Handle multiple `/'s in a row. */
+ while (path[i] == PATH_SEP)
+ i++;
+
+ if ((start + 1) != i) {
+ strcpy (path + start + 1, path + i);
+ i = start + 1;
+ }
+
+ /* Handle backquoted `/'. */
+ if (start > 0 && path[start - 1] == '\\')
+ continue;
+
+ /* Check for trailing `/'. */
+ if (start && !path[i]) {
+ zero_last:
+ path[--i] = '\0';
+ break;
+ }
+
+ /* Check for `../', `./' or trailing `.' by itself. */
+ if (path[i] == '.') {
+ /* Handle trailing `.' by itself. */
+ if (!path[i + 1])
+ goto zero_last;
+
+ /* Handle `./'. */
+ if (path[i + 1] == PATH_SEP) {
+ strcpy (path + i, path + i + 1);
+ i = start;
+ continue;
+ }
+
+ /* Handle `../' or trailing `..' by itself.
+ Remove the previous ?/ part with the exception of
+ ../, which we should leave intact. */
+ if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
+ while (--start > -1 && path[start] != PATH_SEP);
+ if (!strncmp (path + start + 1, "../", 3))
+ continue;
+ strcpy (path + start + 1, path + i + 2);
+ i = start;
+ continue;
+ }
+ }
+ }
+
+ if (!*path) {
+ *path = stub_char;
+ path[1] = '\0';
+ }
+ return path;
+}
+
+#ifndef USE_VFS
+/*
+ int mc_rmdir (char *path);
+ Fix for Win95 UGLY BUG in rmdir: it will return ENOACCESS instead
+ of ENOTEMPTY.
+ */
+int mc_rmdir (char *path)
+{
+ if (win32_GetPlatform() == OS_Win95) {
+ if (rmdir(path)) {
+ SetLastError (ERROR_DIR_NOT_EMPTY);
+#ifndef __EMX__
+ /* FIXME: We are always saying the same thing! */
+ _doserrno = ERROR_DIR_NOT_EMPTY;
+#endif
+ errno = ENOTEMPTY;
+ return -1;
+ } else
+ return 0;
+ }
+ else
+ return rmdir(path); /* No trouble in Windows NT */
+}
+
+static int conv_nt_unx_rc(int rc)
+{
+ int errCode;
+ switch (rc) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_TOO_MANY_OPEN_FILES:
+ errCode = ENOENT;
+ break;
+ case ERROR_INVALID_HANDLE:
+ case ERROR_ARENA_TRASHED:
+ case ERROR_ACCESS_DENIED:
+ case ERROR_INVALID_ACCESS:
+ case ERROR_WRITE_PROTECT:
+ case ERROR_WRITE_FAULT:
+ case ERROR_READ_FAULT:
+ case ERROR_SHARING_VIOLATION:
+ errCode = EACCES;
+ break;
+ case ERROR_NOT_ENOUGH_MEMORY:
+ errCode = ENOMEM;
+ break;
+ case ERROR_INVALID_BLOCK:
+ case ERROR_INVALID_FUNCTION:
+ case ERROR_INVALID_DRIVE:
+ errCode = ENODEV;
+ break;
+ case ERROR_CURRENT_DIRECTORY:
+ errCode = ENOTDIR;
+ break;
+ case ERROR_NOT_READY:
+ errCode = EINVAL;
+ break;
+ default:
+ errCode = EINVAL;
+ break;
+ } /* endswitch */
+ return errCode;
+}
+
+/*
+ int mc_unlink (char *pathName)
+ For Windows 95 and NT, files should be able to be deleted even
+ if they don't have write-protection. We should build a question box
+ like: Delete anyway? Yes <No> All
+*/
+int mc_unlink (char *pathName)
+{
+ char *fileName;
+ char *trunced_name;
+ static int erase_all = 0;
+ BOOL rc;
+ DWORD returnError;
+
+ rc = DeleteFile(pathName);
+ returnError = GetLastError();
+ if ((rc == FALSE) && (returnError == ERROR_ACCESS_DENIED)) {
+ int result;
+ if (!erase_all) {
+ errno = conv_nt_unx_rc(returnError);
+ trunced_name = name_trunc(pathName, 30);
+ fileName = (char *) malloc(strlen(trunced_name) + 16);
+ strcpy(fileName, _("File "));
+ strcat(fileName, trunced_name);
+ strcat(fileName, _(" protected"));
+ result = query_dialog(fileName, _("Delete anyway?"), 3, 3, _(" No "), _(" Yes "), _(" All in the future!"));
+ free(fileName);
+
+ switch (result) {
+ case 0:
+ do_refresh ();
+ return -1;
+ case 1:
+ do_refresh ();
+ break;
+ case 2:
+ do_refresh ();
+ erase_all = 1;
+ break;
+ default:
+ do_refresh ();
+ return -1;
+ break;
+ }
+ }
+
+ chmod(pathName, S_IWRITE); /* make it writable */
+ rc = DeleteFile(pathName);
+ returnError = GetLastError();
+ if (rc == FALSE) {
+ errno = conv_nt_unx_rc(returnError);
+ return -1;
+ }
+ }
+ if (rc == TRUE) return 0;
+ else
+ return -1;
+}
+#endif /*USE_VFS*/
+
+void my_statfs (struct my_statfs *myfs_stats, char *path)
+{
+ int len = 0;
+ DWORD lpSectorsPerCluster, lpBytesPerSector, lpFreeClusters, lpClusters;
+ DWORD lpMaximumComponentLength, lpFileSystemFlags;
+ static char lpVolumeNameBuffer[256], lpFileSystemNameBuffer[30];
+
+ GetDiskFreeSpace(NULL, &lpSectorsPerCluster, &lpBytesPerSector,
+ &lpFreeClusters, &lpClusters);
+
+ /* KBytes available */
+ myfs_stats->avail = (unsigned int)( ((double)lpSectorsPerCluster * lpBytesPerSector * lpFreeClusters) / 1024 );
+
+ /* KBytes total */
+ myfs_stats->total = (unsigned int)( ((double)lpSectorsPerCluster * lpBytesPerSector * lpClusters) / 1024 );
+ myfs_stats->nfree = lpFreeClusters;
+ myfs_stats->nodes = lpClusters;
+
+ GetVolumeInformation(NULL, lpVolumeNameBuffer, 255, NULL,
+ &lpMaximumComponentLength, &lpFileSystemFlags,
+ lpFileSystemNameBuffer, 30);
+
+ myfs_stats->mpoint = lpFileSystemNameBuffer;
+ myfs_stats->device = lpVolumeNameBuffer;
+
+
+ myfs_stats->type = GetDriveType(NULL);
+ switch (myfs_stats->type) {
+ /*
+ * mmm. DeviceIoControl may fail if you are not root case
+ * F5_1Pt2_512, 5.25", 1.2MB, 512 bytes/sector
+ * myfs_stats->typename = "5.25\" 1.2MB"; break; case
+ * F3_1Pt44_512, 3.5", 1.44MB, 512 bytes/sector
+ * myfs_stats->typename = "3.5\" 1.44MB"; break; case
+ * F3_2Pt88_512, 3.5", 2.88MB, 512 bytes/sector
+ * myfs_stats->typename = "3.5\" 2.88MB"; break; case
+ * F3_20Pt8_512, 3.5", 20.8MB, 512 bytes/sector
+ * myfs_stats->typename = "3.5\" 20.8MB"; break; case
+ * F3_720_512, 3.5", 720KB, 512 bytes/sector
+ * myfs_stats->typename = "3.5\" 720MB"; break; case
+ * F5_360_512, 5.25", 360KB, 512 bytes/sector
+ * myfs_stats->typename = "5.25\" 360KB"; break; case
+ * F5_320_512, 5.25", 320KB, 512 bytes/sector
+ * case F5_320_1024, 5.25", 320KB, 1024
+ * bytes/sector myfs_stats->typename = "5.25\" 320KB"; break;
+ * case F5_180_512, 5.25", 180KB, 512
+ * bytes/sector myfs_stats->typename = "5.25\" 180KB"; break;
+ * case F5_160_512, 5.25", 160KB, 512
+ * bytes/sector myfs_stats->typename = "5.25\" 160KB"; break;
+ * case RemovableMedia, Removable media other than
+ * floppy myfs_stats->typename = "Removable"; break; case
+ * FixedMedia Fixed hard disk media
+ * myfs_stats->typename = "Hard Disk"; break; case Unknown:
+ * Format is unknown
+ */
+ case DRIVE_REMOVABLE:
+ myfs_stats->typename = _("Removable");
+ break;
+ case DRIVE_FIXED:
+ myfs_stats->typename = _("Hard Disk");
+ break;
+ case DRIVE_REMOTE:
+ myfs_stats->typename = _("Networked");
+ break;
+ case DRIVE_CDROM:
+ myfs_stats->typename = _("CD-ROM");
+ break;
+ case DRIVE_RAMDISK:
+ myfs_stats->typename = _("RAM disk");
+ break;
+ default:
+ myfs_stats->typename = _("unknown");
+ break;
+ };
+}
+
+int gettimeofday (struct timeval* tvp, void *p)
+{
+ if (p != NULL)
+ return 0;
+
+ /* Since MC only calls this func from get_random_hint we return
+ some value, not exactly the "correct" one */
+ tvp->tv_sec = GetTickCount()/1000; /* Number of milliseconds since Windows //started*/
+ tvp->tv_usec = GetTickCount();
+}
+
+/* FAKE functions */
+
+int
+look_for_exe(const char* pathname)
+{
+ int j;
+ char *p;
+ int lgh = strlen(pathname);
+
+ if (lgh < 4) {
+ return 0;
+ } else {
+ p = (char *) pathname;
+ for (j=0; j<lgh-4; j++) {
+ p++;
+ } /* endfor */
+ if (!stricmp(p, ".exe") ||
+ !stricmp(p, ".bat") ||
+ !stricmp(p, ".com") ||
+ !stricmp(p, ".cmd")) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+lstat (const char* pathname, struct stat *buffer)
+{
+ int rc = stat (pathname, buffer);
+#ifdef __BORLANDC__
+ if (rc == 0) {
+ if (!(buffer->st_mode & S_IFDIR)) {
+ if (!look_for_exe(pathname)) {
+ buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
+int getuid ()
+{
+/* SID sid;
+ LookupAccountName (NULL, &sid...
+ return 0;
+*/
+ return 0;
+}
+
+int getgid ()
+{
+ return 0;
+}
+
+int readlink (char* path, char* buf, int size)
+{
+ return -1;
+}
+int symlink (char *n1, char *n2)
+{
+ return -1;
+}
+int link (char *p1, char *p2)
+{
+ return -1;
+}
+int chown (char *path, int owner, int group)
+{
+ return -1;
+}
+int mknod (char *path, int mode, int dev)
+{
+ return -1;
+}
+
+void init_uid_gid_cache (void)
+{
+ return;
+}
+
+/* INHANDLE is a result of some mc_open call to any vfs, this function
+ returns a normal handle (to be used with read) of a pipe for reading
+ of the output of COMMAND with arguments ... (must include argv[0] as
+ well) which gets as its input at most INLEN bytes from the INHANDLE
+ using mc_read. You have to call mc_doublepclose to close the returned
+ handle afterwards. If INLEN is -1, we read as much as we can :) */
+int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
+{
+ int pipe0 [2], pipe1 [2], std_sav [2];
+#define MAXARGS 16
+ int argno;
+ char *args[MAXARGS];
+ char buffer [8192];
+ int i;
+ va_list ap;
+
+ pid_t pid;
+
+ // Create the pipes
+ if(_pipe(pipe0, 8192, O_BINARY | O_NOINHERIT) == -1)
+ exit (1);
+ if(_pipe(pipe1, 8192, O_BINARY | O_NOINHERIT) == -1)
+ exit (1);
+ // Duplicate stdin/stdout handles (next line will close original)
+ std_sav[0] = _dup(_fileno(stdin));
+ std_sav[1] = _dup(_fileno(stdout));
+ // Duplicate read end of pipe0 to stdin handle
+ if(_dup2(pipe0[0], _fileno(stdin)) != 0)
+ exit (1);
+ // Duplicate write end of pipe1 to stdout handle
+ if(_dup2(pipe1[1], _fileno(stdout)) != 0)
+ exit (1);
+ // Close original read end of pipe0
+ close(pipe0[0]);
+ // Close original write end of pipe1
+ close(pipe1[1]);
+
+ va_start (ap, command);
+ argno = 0;
+ while ((args[argno++] = va_arg(ap, char *)) != NULL)
+ if (argno == (MAXARGS - 1)) {
+ args[argno] = NULL;
+ break;
+ }
+ va_end (ap);
+ // Spawn process
+ pid = spawnvp(P_NOWAIT,command, args);// argv[1], (const char* const*)&argv[1]);
+ if(!pid)
+ exit (1);
+ // Duplicate copy of original stdin back into stdin
+ if(_dup2(std_sav[0], _fileno(stdin)) != 0)
+ exit (1);
+ // Duplicate copy of original stdout back into stdout
+ if(_dup2(std_sav[1], _fileno(stdout)) != 0)
+ exit (1);
+ // Close duplicate copy of original stdout and stdin
+ close(std_sav[0]);
+ close(std_sav[1]);
+
+
+ while ((i = _read (inhandle, buffer,
+ (inlen == -1 || inlen > 8192)
+ ? 8192 : inlen)) > 0) {
+ write (pipe0 [1], buffer, i);
+ if (inlen != -1) {
+ inlen -= i;
+ if (!inlen)
+ break;
+ }
+ }
+ close (pipe0 [1]);
+ *the_pid = pid;
+ return pipe1 [0];
+
+}
+
+int mc_doublepclose (int pipe, pid_t pid)
+{
+ int status = 0;
+
+ close (pipe);
+ _cwait ( &status, pid, 0);
+ return status;
+}
+
+/*hacks to get it compile, remove these after vfs works */
+
+/*hacks to get it compile, remove these after vfs works */
+#ifndef USE_VFS
+char *vfs_get_current_dir (void)
+{
+ return NULL;
+}
+
+int vfs_current_is_extfs (void)
+{
+ return 0;
+}
+
+int vfs_file_is_ftp (char *filename)
+{
+ return 0;
+}
+
+int mc_utime (char *path, void *times)
+{
+ return 0;
+}
+
+
+void extfs_run (char *file)
+{
+ return;
+}
+#endif
+
+char *
+get_default_editor (void)
+{
+ return "notepad.exe";
+}
+
+int
+errno_dir_not_empty (int err)
+{
+ if (err == ENOTEMPTY || err == EEXIST || err == EACCES)
+ return 1;
+ return 0;
+}
+
+/* The MC library directory is by default the directory where mc.exe
+ is situated. It is possible to specify this directory via MCHOME
+ environment variable */
+char *
+get_mc_lib_dir ()
+{
+ char *cur;
+ char *mchome = getenv("MCHOME");
+
+ if (mchome && *mchome)
+ return mchome;
+ mchome = malloc(MC_MAXPATHLEN);
+ GetModuleFileName(NULL, mchome, MC_MAXPATHLEN);
+ for (cur = mchome + strlen(mchome); \
+ (cur > mchome) && (*cur != PATH_SEP); cur--);
+ *cur = 0;
+ cur = strdup(mchome);
+ free(mchome);
+ if (!cur || !*cur) {
+ free(cur);
+ return "C:\\MC";
+ }
+ return cur;
+}
+int get_user_rights (struct stat *buf)
+{
+ return 2;
+}
+void init_groups (void)
+{
+}
+void delete_groups (void)
+{
+}
--- /dev/null
+/* Various utilities - OS/2 versions
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+
+ Written 1994, 1995, 1996 by:
+ Juan Grigera, Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
+ Jakub Jelinek, Mauricio Plaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+
+#define INCL_DOS
+#define INCL_PM
+#define INCL_DOSPROCESS
+#define INCL_DOSFILEMGR
+#define INCL_DOSDEVICES /* Device values */
+#define INCL_DOSDATETIME
+#define INCL_DOSERRORS
+#include <os2.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <io.h>
+#include <fcntl.h>
+#include <signal.h> /* my_system */
+#include <limits.h> /* INT_MAX */
+#include <sys/time.h> /* select: timeout */
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <process.h>
+#include "../src/fs.h"
+#include "../src/util.h"
+#include "../src/dialog.h"
+
+#ifndef ENOTEMPTY
+#define ENOTEMPTY ERROR_DIR_NOT_EMPTY
+#endif
+
+char *
+get_owner (int uid)
+{
+ return "none";
+}
+
+char *
+get_group (int gid)
+{
+ return "none";
+}
+
+/* Pipes are guaranteed to be able to hold at least 4096 bytes */
+/* More than that would be unportable */
+#define MAX_PIPE_SIZE 4096
+
+static int error_pipe[2]; /* File descriptors of error pipe */
+static int old_error; /* File descriptor of old standard error */
+
+/* Creates a pipe to hold standard error for a later analysis. */
+/* The pipe can hold 4096 bytes. Make sure no more is written */
+/* or a deadlock might occur. */
+void
+open_error_pipe (void)
+{
+ return;
+}
+
+void
+close_error_pipe (int error, char *text)
+{
+ return;
+}
+
+void
+check_error_pipe (void)
+{
+ char error[MAX_PIPE_SIZE];
+ int len = 0;
+ if (old_error >= 0){
+ while (len < MAX_PIPE_SIZE)
+ {
+ int rvalue;
+
+ rvalue = read (error_pipe[0], error + len, 1);
+ len ++;
+ if (rvalue <= 0)
+ break;
+ }
+ error[len] = 0;
+ close (error_pipe[0]);
+ }
+ if (len > 0)
+ message (0, " Warning ", error);
+}
+
+
+static int
+StartWindowsProg (char *name, SHORT type)
+{
+#if 0 /* FIXME: PM DDL's should be loaded (or not loaded) at run time */
+ PROGDETAILS pDetails;
+
+ memset(&pDetails, 0, sizeof(PROGDETAILS)) ;
+ pDetails.Length = sizeof(pDetails);
+ pDetails.pszExecutable = name; /* program name */
+ pDetails.pszStartupDir = NULL; /* default directory for new app. */
+ pDetails.pszParameters = NULL; /* command line */
+ pDetails.progt.fbVisible = SHE_VISIBLE ;
+ pDetails.pszEnvironment = NULL;
+
+ switch (type) {
+ case 0:
+ /* Win Standard */
+ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
+ break;
+ case 1:
+ /* Win 3.1 Protect */
+ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
+ break;
+ case 2:
+ /* Win 3.1 Enh. Protect */
+ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
+ break;
+ default:
+ pDetails.progt.progc = PROG_31_ENHSEAMLESSCOMMON ;
+ break;
+ }
+ WinStartApp(NULLHANDLE,
+ &pDetails,
+ NULL,
+ NULL,
+ SAF_INSTALLEDCMDLINE|SAF_STARTCHILDAPP) ;
+#endif
+ return 0;
+}
+
+
+static int
+os2_system (int as_shell_command, const char *shell, const char *command, char *parm);
+
+/*
+ as_shell_command = 1: If a program is started during input line, CTRL-O
+ or RETURN
+ = 0: F3, F4
+*/
+int
+my_system (int as_shell_command, const char *shell, const char *command)
+{
+ char *sh; /* This is the shell -- always! */
+ char *cmd; /* This is the command (only the command) */
+ char *parm; /* This is the parameter (can be more than one) */
+ register int length, i;
+ char temp[4096]; /* That's enough! */
+
+ sh = get_default_shell();
+ if (strcmp(sh, shell)) {
+ /*
+ Not equal -- That means: shell is the program and command is the
+ parameter
+ */
+ cmd = (char *) shell;
+ parm = (char *) command;
+ } else {
+ /* look into the command and take out the program */
+ if (command) {
+ strcpy(temp, command);
+ length = strlen(command);
+ for (i=length-1; i>=0; i--) {
+ if (command[i] == ' ') {
+ temp[i] = (char) 0;
+ length--;
+ } else
+ break;
+ }
+ if (i==-1) {
+ /* only blanks */
+ return -1;
+ }
+ if (parm = strchr(temp, (char) ' ')) {
+ *parm = (char) 0;
+ parm++;
+ }
+ cmd = (char *) temp;
+ } else {
+ /* command is NULL */
+ cmd = parm = NULL;
+ }
+ }
+ return os2_system (as_shell_command, sh, cmd, parm);
+}
+
+static int
+ux_startp (const char *shell, const char *command, const char *parm)
+{
+ if (parm) {
+ spawnlp (P_WAIT,
+ (char *) shell,
+ (char *) shell,
+ "/c",
+ (char *) command,
+ (char *) parm,
+ (char *) 0);
+ } else {
+ spawnlp (P_WAIT,
+ (char *) shell,
+ (char *) shell,
+ "/c",
+ (char *) command,
+ (char *) 0);
+ }
+ return 0;
+}
+
+
+static int
+os2_system (int as_shell_command, const char *shell, const char *command, char *parm)
+{
+ register int i, j;
+ ULONG AppType = 0; /* Application type flags (returned) */
+ APIRET rc = NO_ERROR; /* Return Code */
+ char pathValue[5] = "PATH"; /* For DosSearchPath */
+ UCHAR searchResult[MC_MAXPATHLEN * 2 + 1]; /* For DosSearchPath */
+
+ char *cmdString;
+ char *postFix[3];
+ char *line;
+ /* ------------------------------------------------------- */
+ STARTDATA StartData;
+ CHAR ObjBuf[100];
+ ULONG SessionID;
+ PID pid;
+
+ if (command == NULL) {
+ /* .ado: just start a shell, we don't need the parameter */
+ spawnl (P_WAIT,
+ (char *) shell,
+ (char *) shell,
+ (char *) command, (char *) 0);
+ return 0;
+ }
+
+ memset(&StartData, 0, sizeof(StartData)) ;
+ StartData.Length = sizeof(StartData);
+ StartData.Related = SSF_RELATED_CHILD;
+ StartData.FgBg = SSF_FGBG_BACK;
+ StartData.TraceOpt = SSF_TRACEOPT_NONE;
+ StartData.PgmTitle = NULL;
+ StartData.TermQ = NULL;
+ StartData.InheritOpt = SSF_INHERTOPT_PARENT;
+ StartData.IconFile = 0;
+ StartData.PgmHandle = 0;
+ StartData.PgmControl = SSF_CONTROL_VISIBLE ;
+ StartData.ObjectBuffer = ObjBuf;
+ StartData.ObjectBuffLen = 100;
+ StartData.PgmInputs = parm;
+
+ postFix[0] = ".exe";
+ postFix[1] = ".cmd";
+ postFix[2] = ".bat";
+
+ i = strlen(command);
+ if (command[i-1] == ' ') {
+ /* The user has used ALT-RETURN */
+ i--;
+ }
+ cmdString = (char *) malloc(i+1);
+ for (j=0; j<i; j++) {
+ cmdString[j] = command[j];
+ }
+ cmdString[j] = (char) 0;
+
+ if ((i < 5) || ((i > 4) && (cmdString[i-4]) != '.')) {
+ /* without Extension */
+ line = (char *) malloc(i+5);
+ rc = 1;
+ for (i=0; (i<3 && rc); i++) {
+ /* Search for the file */
+ strcpy(line, cmdString);
+ strcat(line, postFix[i]);
+ rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY),
+ (PSZ) pathValue,
+ line,
+ searchResult,
+ sizeof(searchResult));
+ }
+ free (line);
+ } else {
+ /* Just search */
+ rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY),
+ (PSZ) pathValue,
+ cmdString,
+ searchResult,
+ sizeof(searchResult));
+ }
+ free(cmdString);
+ if (rc != 0) {
+ /* Internal command or the program was written with absolut path */
+ return ux_startp(shell, command, parm);
+ }
+
+ /* Application to be started */
+ StartData.PgmName = searchResult;
+ StartData.Environment = NULL;
+ rc = DosQueryAppType(searchResult, &AppType);
+ if (rc == NO_ERROR) {
+ StartData.SessionType = PROG_WINDOWABLEVIO;
+ if ((AppType & 0x00000007) == FAPPTYP_WINDOWAPI) {
+ /* Window API */
+ StartData.SessionType = PROG_PM;
+ return DosStartSession(&StartData, &SessionID, &pid);
+ }
+ if ((AppType & 0x00000007) == FAPPTYP_WINDOWCOMPAT) {
+ /* Window compat */
+ return ux_startp(shell, command, parm);
+ }
+ if (AppType & 0x0000ffff & FAPPTYP_DOS) {
+ /* PC/DOS Format */
+ StartData.SessionType = PROG_WINDOWEDVDM;
+ return DosStartSession(&StartData, &SessionID, &pid);
+ }
+ if (AppType & 0x0000ffff & FAPPTYP_WINDOWSREAL) {
+ /* Windows real mode app */
+ return StartWindowsProg(searchResult, 0);
+ }
+ if (AppType & 0x0000ffff & FAPPTYP_WINDOWSPROT) {
+ /* Windows Protect mode app*/
+ return StartWindowsProg(searchResult, 1);
+ }
+ if (AppType & 0x0000ffff & FAPPTYP_WINDOWSPROT31) {
+ /* Windows 3.1 Protect mode app*/
+ return StartWindowsProg(searchResult, 2);
+ }
+ rc = DosStartSession(&StartData, &SessionID, &pid) ;
+ } else {
+ /* It's not a known exe type or it's a CMD/BAT file */
+ i = strlen(searchResult);
+ if ((toupper(searchResult[--i]) == 'T') &&
+ (toupper(searchResult[--i]) == 'A') &&
+ (toupper(searchResult[--i]) == 'B') &&
+ (searchResult[--i] == '.') ) {
+ StartData.SessionType = PROG_WINDOWEDVDM;
+ rc = DosStartSession(&StartData, &SessionID, &pid) ;
+ } else {
+ rc = ux_startp (shell, command, parm);
+ }
+ }
+ return rc;
+}
+
+char *tilde_expand (char *directory)
+{
+ return strdup (directory);
+}
+
+
+/* Canonicalize path, and return a new path. Do everything in situ.
+ The new path differs from path in:
+ Multiple BACKSLASHs are collapsed to a single BACKSLASH.
+ Leading `./'s and trailing `/.'s are removed.
+ Trailing BACKSLASHs are removed.
+ Non-leading `../'s and trailing `..'s are handled by removing
+ portions of the path. */
+char *
+canonicalize_pathname (char *path)
+{
+ int i, start;
+ char stub_char;
+
+ stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
+
+ /* Walk along path looking for things to compact. */
+ i = 0;
+ for (;;) {
+ if (!path[i])
+ break;
+
+ while (path[i] && path[i] != PATH_SEP)
+ i++;
+
+ start = i++;
+
+ /* If we didn't find any slashes, then there is nothing left to do. */
+ if (!path[start])
+ break;
+
+ /* Handle multiple BACKSLASHs in a row. */
+ while (path[i] == PATH_SEP)
+ i++;
+
+ if ((start + 1) != i) {
+ strcpy (path + start + 1, path + i);
+ i = start + 1;
+ }
+
+ /* Handle backquoted BACKSLASH. */
+/* if (start > 0 && path[start - 1] == '\\')
+ continue; */
+
+ /* Check for trailing BACKSLASH. */
+ if (start && !path[i]) {
+ zero_last:
+ path[--i] = '\0';
+ break;
+ }
+
+ /* Check for `../', `./' or trailing `.' by itself. */
+ if (path[i] == '.') {
+ /* Handle trailing `.' by itself. */
+ if (!path[i + 1])
+ goto zero_last;
+
+ /* Handle `./'. */
+ if (path[i + 1] == PATH_SEP) {
+ strcpy (path + i, path + i + 1);
+ i = start;
+ continue;
+ }
+
+ /* Handle `../' or trailing `..' by itself.
+ Remove the previous ?/ part with the exception of
+ ../, which we should leave intact. */
+ if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
+ while (--start > -1 && path[start] != PATH_SEP);
+ if (!strncmp (path + start + 1, "..\\", 3))
+ continue;
+ strcpy (path + start + 1, path + i + 2);
+ i = start;
+ continue;
+ }
+ }
+ }
+
+ if (!*path) {
+ *path = stub_char;
+ path[1] = '\0';
+ }
+ return path;
+}
+
+
+void
+my_statfs (struct my_statfs *myfs_stats, char *path)
+{
+ PFSALLOCATE pBuf;
+ PFSINFO pFsInfo;
+ ULONG lghBuf;
+
+ ULONG diskNum = 0;
+ ULONG logical = 0;
+
+ UCHAR szDeviceName[3] = "A:";
+ PBYTE pszFSDName = NULL; /* pointer to FS name */
+ APIRET rc = NO_ERROR; /* Return code */
+ BYTE fsqBuffer[sizeof(FSQBUFFER2) + (3 * CCHMAXPATH)] = {0};
+ ULONG cbBuffer = sizeof(fsqBuffer); /* Buffer length) */
+ PFSQBUFFER2 pfsqBuffer = (PFSQBUFFER2) fsqBuffer;
+
+ int i, len = 0;
+
+ /* ------------------------------------------------------------------ */
+
+ lghBuf = sizeof(FSALLOCATE);
+ pBuf = (PFSALLOCATE) malloc(lghBuf);
+
+ /* Get the free number of Bytes */
+ rc = DosQueryFSInfo(0L, FSIL_ALLOC, (PVOID) pBuf, lghBuf);
+ /* KBytes available */
+ myfs_stats->avail = pBuf->cSectorUnit * pBuf->cUnitAvail * pBuf->cbSector / 1024;
+ /* KBytes total */
+ myfs_stats->total = pBuf->cSectorUnit * pBuf->cUnit * pBuf->cbSector / 1024;
+ myfs_stats->nfree = pBuf->cUnitAvail;
+ myfs_stats->nodes = pBuf->cbSector;
+
+ lghBuf = sizeof(FSINFO);
+ pFsInfo = (PFSINFO) malloc(lghBuf);
+ rc = DosQueryFSInfo(0L,
+ FSIL_VOLSER,
+ (PVOID) pFsInfo,
+ lghBuf);
+ /* Get name */
+ myfs_stats->device = strdup(pFsInfo->vol.szVolLabel); /* Label of the Disk */
+
+ /* Get the current disk for DosQueryFSAttach */
+ rc = DosQueryCurrentDisk(&diskNum, &logical);
+
+ szDeviceName[0] = (UCHAR) (diskNum + (ULONG) 'A' - 1);
+ /* Now get the type of the disk */
+ rc = DosQueryFSAttach(szDeviceName,
+ 0L,
+ FSAIL_QUERYNAME,
+ pfsqBuffer,
+ &cbBuffer);
+
+ pszFSDName = pfsqBuffer->szName + pfsqBuffer->cbName + 1;
+ myfs_stats->mpoint = strdup(pszFSDName); /* FAT, HPFS ... */
+
+ myfs_stats->type = pBuf->idFileSystem;
+ /* What is about 3 ?*/
+ if (myfs_stats->type == 0) {
+ myfs_stats->typename = (char *) malloc(11);
+ strcpy(myfs_stats->typename, "Local Disk");
+ } else {
+ myfs_stats->typename = (char *) malloc(13);
+ strcpy(myfs_stats->typename, "Other Device");
+ }
+
+ free(pBuf);
+ free(pFsInfo);
+}
+
+int
+gettimeofday (struct timeval* tvp, void *p)
+{
+ DATETIME pdt = {0};
+ if (p != NULL) /* what is "p"? */
+ return 0;
+
+ /* Since MC only calls this func from get_random_hint we return
+ * some value, not exactly the "correct" one
+ */
+ DosGetDateTime(&pdt);
+ tvp->tv_usec = (pdt.hours * 60 + pdt.minutes) * 60 + pdt.seconds;
+ /* Number of milliseconds since Windows started */
+ tvp->tv_sec = tvp->tv_usec * 1000 + pdt.hundredths * 10;
+ return 0;
+}
+
+/* FAKE functions */
+
+int
+look_for_exe(const char* pathname)
+{
+ int j;
+ char *p;
+ int lgh = strlen(pathname);
+
+ if (lgh < 4) {
+ return 0;
+ } else {
+ p = (char *) pathname;
+ for (j=0; j<lgh-4; j++) {
+ p++;
+ }
+ if (!stricmp(p, ".exe") ||
+ !stricmp(p, ".bat") ||
+ !stricmp(p, ".com") ||
+ !stricmp(p, ".cmd")) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+lstat (const char* pathname, struct stat *buffer)
+{
+ int rc = stat (pathname, buffer);
+#ifdef __BORLANDC__
+ if (rc == 0) {
+ if (!(buffer->st_mode & S_IFDIR)) {
+ if (!look_for_exe(pathname)) {
+ buffer->st_mode &= !S_IXUSR & !S_IXGRP & !S_IXOTH;
+ }
+ }
+ }
+#endif
+ return rc;
+}
+
+int
+getuid ()
+{
+ return 0;
+}
+
+int
+getgid ()
+{
+ return 0;
+}
+
+int
+readlink (char* path, char* buf, int size)
+{
+ return -1;
+}
+
+int
+symlink (char *n1, char *n2)
+{
+ return -1;
+}
+
+int
+link (char *p1, char *p2)
+{
+ return -1;
+}
+
+int
+chown (char *path, int owner, int group)
+{
+ return -1;
+}
+
+int
+mknod (char *path, int mode, int dev)
+{
+ return -1;
+}
+
+void
+init_uid_gid_cache (void)
+{
+ return;
+}
+
+int
+mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
+{
+ return 0;
+}
+
+int
+mc_doublepclose (int pipe, pid_t pid)
+{
+ return 0;
+}
+
+/*hacks to get it compile, remove these after vfs works */
+char *
+vfs_get_current_dir (void)
+{
+ return NULL;
+}
+
+int
+vfs_current_is_extfs (void)
+{
+ return 0;
+}
+
+int
+vfs_file_is_ftp (char *filename)
+{
+ return 0;
+}
+
+int
+mc_utime (char *path, void *times)
+{
+ return 0;
+}
+
+
+void
+extfs_run (char *file)
+{
+ return;
+}
+
+int
+geteuid(void)
+{
+ return 0;
+}
+
+
+int
+mc_chdir(char *pathname)
+{
+ APIRET ret;
+ register int lgh = strlen(pathname);
+
+ /* Set the current drive */
+ if (lgh == 0) {
+ return -1;
+ } else {
+ /* First set the default drive */
+ if (lgh > 1) {
+ if (pathname[1] == ':') {
+ ret = DosSetDefaultDisk(toupper(pathname[0]) - 'A' + 1);
+ }
+ }
+ /* After that, set the current dir! */
+ ret = DosSetCurrentDir(pathname);
+ }
+ return ret;
+}
+
+int
+mc_chmod(char *pathName, int unxmode)
+{
+ /* OS/2 does not need S_REG */
+ int os2Mode = unxmode & 0x0FFF;
+ return chmod(pathName, os2Mode);
+}
+
+static int
+conv_os2_unx_rc(int os2rc)
+{
+ int errCode;
+ switch (os2rc) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ case ERROR_FILENAME_EXCED_RANGE:
+ errCode = ENOENT;
+ break;
+ case ERROR_NOT_DOS_DISK:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_SHARING_BUFFER_EXCEEDED:
+ case ERROR_ACCESS_DENIED:
+ errCode = EACCES;
+ break;
+ case ERROR_INVALID_PARAMETER:
+ errCode = EINVAL;
+ break;
+ default:
+ errCode = EINVAL;
+ break;
+ }
+ return errCode;
+}
+
+int
+mc_open (char *file, int flags, int pmode)
+{
+ return open(file, (flags | O_BINARY), pmode);
+}
+
+int
+mc_unlink(char *pathName)
+{
+ /* Use OS/2 API to delete a file, if the file is set as read-only,
+ the file will be deleted without asking the user! */
+ APIRET rc;
+ rc = DosDelete(pathName);
+ if (!rc) {
+ return 0;
+ }
+ if (rc == ERROR_ACCESS_DENIED) {
+ chmod(pathName, (S_IREAD|S_IWRITE));
+ rc = DosDelete(pathName);
+ if (rc) {
+ errno = conv_os2_unx_rc(rc) ;
+ return -1;
+ } else {
+ return 0;
+ }
+ } else {
+ errno = conv_os2_unx_rc(rc) ;
+ return -1;
+ }
+}
+
+char *
+get_default_editor (void)
+{
+ char *tmp;
+ APIRET rc;
+ char pathValue[5] = "PATH";
+ UCHAR searchResult[MC_MAXPATHLEN + 1];
+
+ /* EPM is not always be installed */
+ rc = DosSearchPath((SEARCH_IGNORENETERRS | SEARCH_ENVIRONMENT | SEARCH_CUR_DIRECTORY),
+ (PSZ) pathValue,
+ "EPM.EXE",
+ searchResult,
+ sizeof(searchResult));
+ if (rc != 0) {
+ /* The system editor is always there */
+ return strdup("e.exe");
+ } else {
+ /* Let it be searched from my_system */
+ return strdup("epm.exe");
+ }
+}
+
+/* get_default_shell
+ Get the default shell for the current hardware platform
+ TODO: Get the value of %OS2_SHELL% or %SHELL%: which one?
+*/
+char *
+get_default_shell()
+{
+ return getenv ("COMSPEC");
+}
+
+int
+errno_dir_not_empty (int err)
+{
+ if (err == ENOTEMPTY)
+ return 1;
+ return 0;
+}
+
+/* The MC library directory is by default the directory where mc.exe
+ is situated. It is recommended to specify this directory via MCHOME
+ environment variable, otherwise you will be unable to rename mc.exe */
+char *
+get_mc_lib_dir ()
+{
+ HMODULE mc_hm;
+ int rc;
+ char *cur = NULL;
+ char *mchome = getenv("MCHOME");
+
+ if (mchome && *mchome)
+ return mchome;
+ mchome = malloc(MC_MAXPATHLEN);
+ rc = DosQueryModuleHandle ("MC.EXE", &mc_hm);
+ if (!rc)
+ rc = DosQueryModuleName (mc_hm, MC_MAXPATHLEN, mchome);
+ if (!rc)
+ {
+ for (cur = mchome + strlen(mchome); \
+ (cur > mchome) && (*cur != PATH_SEP); cur--);
+ *cur = 0;
+ cur = strdup(mchome);
+ free(mchome);
+ }
+ if (!cur || !*cur) {
+ free(cur);
+ return "C:\\MC";
+ }
+ return cur;
+}
+
+int get_user_rights (struct stat *buf)
+{
+ return 2;
+}
+void init_groups (void)
+{
+}
+void delete_groups (void)
+{
+}
--- /dev/null
+/* Utilities - Win32 utilities (Windows NT and Windows '95)
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+
+ Written 1996 by Juan Grigera<grigera@isis.unlp.edu.ar>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include <config.h>
+#include <windows.h>
+#include "util_win32.h"
+#include "trace_nt.h"
+
+/* int win32_GetPlatform ()
+ Checks in which OS Midnight Commander is running.
+
+ Returns:
+ OS_WinNT - Windows NT 3.x
+ OS_Win95 - Windows 4.x
+
+ Note: GetVersionEx (Win32API) is called only once.
+*/
+int win32_GetPlatform ()
+{
+ static int platform = 0;
+
+ return (platform ? platform : (platform = win32_GetVersionEx()) );
+}
+
+/* int win32_GetVersionEx ()
+ intended for use by win32_GetPlatform only
+*/
+int win32_GetVersionEx ()
+{
+ OSVERSIONINFO ovi;
+
+ ovi.dwOSVersionInfoSize = sizeof(ovi);
+ win32APICALL( GetVersionEx(&ovi) );
+
+ return ovi.dwPlatformId;
+}
+
+/* int win32_GetEXEType (const char* filename)
+ Determines whether filename (an Executable) is
+ a Console application (CUI) or a Graphical application(GUI).
+
+ filename - Name of executable file to check
+
+ Returns: EXE_win16 - Windows 3.x archive or OS/2
+ EXE_win32CUI - NT or Chicago Console API, also OS/2
+ EXE_win32GUI - NT or Chicago GUI API
+ EXE_otherCUI - DOS COM, MZ, ZM, Phar Lap
+ EXE_Unknown - Unknown
+ EXE_Error - Couldn't read file/EXE image
+
+ TODO: better management of OS/2 images
+ EXE_CompressedArchive can be easily implemented
+ Notes: This function parses the executable header (the only ugly way
+ to do it). If header is not found or not understood,
+ 0 is returned.
+
+ Information on NE, LE, LX and MZ taken from Ralf Brown's interrupt
+ list, under INT 21-function 4B ("EXEC" - LOAD AND/OR EXECUTE PROGRAM),
+ Tables 0806 - 836.
+
+ Parsing of PE header (Win32 signature, "Portable Executable")
+ taken from MSKBase article Number: Q90493.
+*/
+
+/* ---- Executable Signatures ---- */
+
+/* Alternative DOS signagure */
+#define IMAGE_DOS_SIGNATURE_ALTERNATIVE 0x4D5A /* ZM */
+
+/* Phar Lap .EXP files */
+#define IMAGE_OLDPHARLAP_SIGNATURE 0x504D /* MP */
+#define IMAGE_NEWPHARLAP_286_SIGNATURE 0x3250 /* P2 */
+#define IMAGE_NEWPHARLAP_386_SIGNATURE 0x3350 /* P3 */
+
+/* New Executables */
+#define IMAGE_LX_SIGNATURE 0x584C /* LX */
+#define IMAGE_PE_SIGNATURE 0x4550 /* PE */
+
+
+int win32_GetEXEType (const char* a_szFileName)
+{
+/* FIXME: MinGW cannot compile this code */
+#ifndef __MINGW32__
+ HANDLE hImage;
+ DWORD dwDumm;
+ DWORD SectionOffset;
+ DWORD CoffHeaderOffset;
+ WORD wSignature;
+/* DWORD MoreDosHeader[16]; */
+
+ IMAGE_DOS_HEADER image_dos_header;
+ IMAGE_FILE_HEADER image_file_header;
+ IMAGE_OPTIONAL_HEADER image_optional_header;
+/* IMAGE_SECTION_HEADER image_section_header; */
+
+ /* Open the EXE file - Use Native API for SHARE compatibility */
+ hImage = CreateFile(a_szFileName, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (hImage == INVALID_HANDLE_VALUE) {
+ win32Trace (("win32_GetEXEType: Could not open file %s. API Error %d.", a_szFileName, GetLastError()));
+ return EXE_Error;
+ }
+
+ /* Read the MZ (DOS) image header. */
+ win32APICALL( ReadFile (hImage, (LPVOID)&image_dos_header, sizeof(IMAGE_DOS_HEADER), &dwDumm, NULL) );
+
+ switch (image_dos_header.e_magic) {
+ case IMAGE_DOS_SIGNATURE: /* MZ or ZM */
+ case IMAGE_DOS_SIGNATURE_ALTERNATIVE:
+ break;
+
+ case IMAGE_OLDPHARLAP_SIGNATURE: /* MP, P2, P3: Phar Lap executables */
+ case IMAGE_NEWPHARLAP_286_SIGNATURE:
+ case IMAGE_NEWPHARLAP_386_SIGNATURE:
+ return EXE_otherCUI;
+
+ default:
+ return EXE_otherCUI; /* Probably .COM? */
+ }
+
+ /* Read more MS-DOS header. */
+/* win32APICALL( ReadFile (hImage, MoreDosHeader, sizeof(MoreDosHeader)); */
+
+ /* Get new executable header */
+ CoffHeaderOffset = SetFilePointer(hImage, image_dos_header.e_lfanew, NULL, FILE_BEGIN);
+/* + sizeof(ULONG); */
+ win32APICALL( ReadFile (hImage, (LPVOID) &wSignature, sizeof(WORD), &dwDumm, NULL) );
+
+ switch (wSignature) {
+ case IMAGE_PE_SIGNATURE: /* PE - Portable Executable */
+ break;
+ case IMAGE_OS2_SIGNATURE: /* NE - New Executable OS/2 and Windows 3.x */
+ case IMAGE_OS2_SIGNATURE_LE: /* LE - Linear Execuable (Windows 3.x) */
+ case IMAGE_LX_SIGNATURE: /* LX - Linear Execuable (OS/2) */
+ return EXE_win16;
+ default:
+ return EXE_Unknown; /* unknown New Executable or bad pointer */
+
+ }
+
+ /* Continue parsing PE (COFF-like) */
+ SectionOffset = CoffHeaderOffset + IMAGE_SIZEOF_FILE_HEADER + IMAGE_SIZEOF_NT_OPTIONAL_HEADER;
+
+ win32APICALL( ReadFile(hImage, (LPVOID) &image_file_header, IMAGE_SIZEOF_FILE_HEADER, &dwDumm, NULL) );
+
+ /* Read optional header. */
+ win32APICALL( ReadFile(hImage, (LPVOID) &image_optional_header, IMAGE_SIZEOF_NT_OPTIONAL_HEADER, &dwDumm, NULL) );
+
+ switch (image_optional_header.Subsystem) {
+ case IMAGE_SUBSYSTEM_WINDOWS_GUI:
+ return EXE_win32GUI;
+
+ case IMAGE_SUBSYSTEM_WINDOWS_CUI:
+ case IMAGE_SUBSYSTEM_OS2_CUI:
+ case IMAGE_SUBSYSTEM_POSIX_CUI:
+ return EXE_win32CUI;
+
+ case IMAGE_SUBSYSTEM_UNKNOWN:
+ case IMAGE_SUBSYSTEM_NATIVE:
+ return EXE_Unknown; /* FIXME: what is "NATIVE??" */
+ default:
+ win32Trace(("Unknown type %u.\n", image_optional_header.Subsystem));
+ return EXE_Unknown;
+ }
+#else
+ return EXE_Unknown;
+#endif /* !__MINGW32__ */
+}
+
+
--- /dev/null
+/* util.Win32.h - Header
+ Utilities - Win32 utilities (Windows NT and Windows '95)
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+
+ Written 1996 by Juan Grigera<grigera@isis.unlp.edu.ar>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+/* Prototypes */
+int win32_GetPlatform ();
+int win32_GetEXEType (const char* a_szFileName);
+int win32_GetVersionEx ();
+
+
+/* Constants */
+enum {
+ OS_WinNT = VER_PLATFORM_WIN32_NT, /* windows.h values */
+ OS_Win95 = VER_PLATFORM_WIN32_WINDOWS,
+};
+
+enum {
+ EXE_Unknown,
+ EXE_win16,
+ EXE_win32CUI,
+ EXE_win32GUI,
+ EXE_otherCUI,
+ EXE_Error
+};
+
--- /dev/null
+/* Utilities - Windows NT specific utilities (not in Win95)
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+
+ Written 1996 by Juan Grigera<grigera@isis.unlp.edu.ar>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+#include <config.h>
+#include <windows.h>
+#include "util_win32.h"
+#include "trace_nt.h"
+
+
+/* int winnt_IsAdministrator() - Determines whether user has Administrator (root)
+ priviledges.
+ Return: 1 if administrator
+ 0 if not
+
+ Note: Code taken from MSKbase Number: Q118626.
+
+ To determine whether or not a user is an administrator, you need to examine
+ the user's access token with GetTokenInformation(). The access token
+ represents the user's privileges and the groups to which the user belongs.
+*/
+
+int winnt_IsAdministrator()
+{
+ HANDLE hAccessToken;
+ UCHAR InfoBuffer[1024];
+ PTOKEN_GROUPS ptgGroups = (PTOKEN_GROUPS)InfoBuffer;
+ DWORD dwInfoBufferSize;
+ PSID psidAdministrators;
+ SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY;
+ UINT x;
+ BOOL bSuccess;
+
+ if(!OpenProcessToken(GetCurrentProcess(),TOKEN_READ,&hAccessToken))
+ return 0;
+
+ bSuccess = GetTokenInformation(hAccessToken,TokenGroups,InfoBuffer,
+ 1024, &dwInfoBufferSize);
+
+ CloseHandle(hAccessToken);
+
+ if( !bSuccess )
+ return 0;
+
+ if(!AllocateAndInitializeSid(&siaNtAuthority, 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &psidAdministrators))
+ return 0;
+
+ bSuccess = 0;
+ for(x=0;x<ptgGroups->GroupCount;x++) {
+ if( EqualSid(psidAdministrators, ptgGroups->Groups[x].Sid) ) {
+ bSuccess = 1;
+ break;
+ }
+ }
+ FreeSid(psidAdministrators);
+ return bSuccess;
+}
+
+
+int geteuid ()
+{
+ if (winnt_IsAdministrator())
+ return 0;
+ return 1;
+}
+
--- /dev/null
+#include <sys/utime.h>
--- /dev/null
+# Generated automatically from Makefile.in by configure.
+srcdir = .
+
+rootdir = $(srcdir)/..
+include ../Make.common
+
+CFLAGS = $(XCFLAGS)
+CPPFLAGS = $(XCPPFLAGS)
+LDFLAGS = $(XLDFLAGS)
+DEFS = $(XDEFS)
+LIBS = $(XLIBS) $(XLIB)
+AR = /usr/bin/ar
+
+SLANGSRCS = sldisply.c slerr.c slsmg.c slutty.c slgetkey.c slmemcpy.c \
+ slmemset.c sltermin.c sltoken.c slsignal.c \
+ slvideo.c slw32tty.c slos2tty.c
+
+SLANGHDRS = slang.h _slang.h sl-feat.h jdmacros.h
+
+SLANGOBJS = sldisply.o slerr.o slsmg.o slutty.o \
+ slgetkey.o slmemcpy.o slmemset.o sltermin.o \
+ sltoken.o slsignal.o
+
+#
+# Distribution variables
+#
+
+DISTSLANG = Makefile.in README $(SLANGSRCS) $(SLANGHDRS)
+
+all: libmcslang.a
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) $<
+
+check:
+ @echo no tests are supplied.
+
+libmcslang.a: $(SLANGOBJS)
+ $(RMF) $@
+ $(AR) cr $@ $(SLANGOBJS)
+ -$(RANLIB) $@
+
+showlibdep:
+ @echo 'OBJS="$(SLANGOBJS)"'
+
+cross:
+ $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \
+ CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses "
+
+TAGS: $(SLANGSRCS)
+ etags $(SLANGSRCS)
+
+clean:
+ $(RMF) *.o core a.out libmcslang.a
+
+realclean: clean
+ $(RMF) .depend
+ $(RMF) TAGS
+ $(RMF) *~
+
+distclean:
+ -$(RMF) $(srcdir)/*~ $(srcdir)/*.o $(srcdir)/core $(srcdir)/a.out
+ -$(RMF) $(srcdir)/libmcslang.a
+ -if test $(srcdir) = .; then $(MAKE) realclean; fi
+ -$(RMF) $(srcdir)/Makefile
+
+distcopy:
+ $(CP) $(DISTSLANG) ../../mc-$(VERSION)/slang
+
+install uninstall:
+
+depend dep: mcdep
+
+fastdeploc:
+
+# ***Dependencies***Do not edit***
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+# ***End of dependencies***
--- /dev/null
+/* header file for S-Lang internal structures that users do not (should not)
+ need. Use slang.h for that purpose. */
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+
+#include "config.h"
+
+#include <string.h>
+
+#include "jdmacros.h"
+
+#ifdef VMS
+# define SLANG_SYSTEM_NAME "_VMS"
+#else
+# if defined (__GO32__) || defined (__EMX__) || \
+ defined (msdos) || defined (__os2__)
+# define SLANG_SYSTEM_NAME "_IBMPC"
+# else
+# define SLANG_SYSTEM_NAME "_UNIX"
+# endif
+#endif /* VMS */
+
+#ifdef msdos
+#define SLANG_MAX_SYMBOLS 500
+#else
+#define SLANG_MAX_SYMBOLS 2500
+#endif
+/* maximum number of global symbols--- slang builtin, functions, global vars */
+
+
+/* These quantities are main_types for byte-compiled code. They are used
+ * by the inner_interp routine. The ones commented out with a // are
+ * actually defined in slang.h because they are also used as the main_type in
+ * the name table.
+ */
+
+/* // #define SLANG_LVARIABLE 0x01 */
+#define SLANG_LOGICAL 0x02
+#define SLANG_BINARY 0x03
+/* // #define SLANG_INTRINSIC 0x06 */
+/* // #define SLANG_FUNCTION 0x07 */
+#define SLANG_LITERAL 0x08 /* constant objects */
+#define SLANG_BLOCK 0x09
+#define SLANG_EQS 0x0A
+#define SLANG_UNARY 0x0B
+#define SLANG_LUNARY 0x0C
+
+/* // #define SLANG_GVARIABLE 0x0D */
+/* // #define SLANG_IVARIABLE 0x0E */ /* intrinsic variables */
+/* // #define SLANG_RVARIABLE 0x0F */ /* read only variable */
+
+/* These 3 MUST be in this order too ! */
+#define SLANG_RETURN 0x10
+#define SLANG_BREAK 0x11
+#define SLANG_CONTINUE 0x12
+
+#define SLANG_EXCH 0x13
+#define SLANG_LABEL 0x14
+#define SLANG_LOBJPTR 0x15
+#define SLANG_GOBJPTR 0x16
+#define SLANG_X_ERROR 0x17
+/* These must be in this order */
+#define SLANG_X_USER0 0x18
+#define SLANG_X_USER1 0x19
+#define SLANG_X_USER2 0x1A
+#define SLANG_X_USER3 0x1B
+#define SLANG_X_USER4 0x1C
+
+#ifdef SLANG_NOOP
+# define SLANG_NOOP_DIRECTIVE 0x2F
+#endif
+
+/* If SLANG_DATA occurs as the main_type for an object in the interpreter's
+ * byte-code, it currently refers to a STRING.
+ */
+/* // #define SLANG_DATA 0x30 */ /* real objects which may be destroyed */
+
+
+/* Subtypes */
+#define ERROR_BLOCK 0x01
+/* gets executed if block encounters error other than stack related */
+#define EXIT_BLOCK 0x02
+#define USER_BLOCK0 0x03
+#define USER_BLOCK1 0x04
+#define USER_BLOCK2 0x05
+#define USER_BLOCK3 0x06
+#define USER_BLOCK4 0x07
+/* The user blocks MUST be in the above order */
+
+/* directive subtypes */
+#define SLANG_LOOP_MASK 0x80
+#define SLANG_LOOP 0x81
+#define SLANG_WHILE 0x82
+#define SLANG_FOR 0x83
+#define SLANG_FOREVER 0x84
+#define SLANG_CFOR 0x85
+#define SLANG_DOWHILE 0x86
+
+#define SLANG_IF_MASK 0x40
+#define SLANG_IF 0x41
+#define SLANG_IFNOT 0x42
+#define SLANG_ELSE 0x43
+
+
+/* local, global variable assignments
+ * The order here is important. See interp_variable_eqs to see how this
+ * is exploited. */
+#define SLANG_EQS_MASK 0x20
+/* local variables */
+/* Keep these in this order!! */
+#define SLANG_LEQS 0x21
+#define SLANG_LPEQS 0x22
+#define SLANG_LMEQS 0x23
+#define SLANG_LPP 0x24
+#define SLANG_LMM 0x25
+/* globals */
+/* Keep this on this order!! */
+#define SLANG_GEQS 0x26
+#define SLANG_GPEQS 0x27
+#define SLANG_GMEQS 0x28
+#define SLANG_GPP 0x29
+#define SLANG_GMM 0x2A
+/* intrinsic variables */
+#define SLANG_IEQS 0x2B
+#define SLANG_IPEQS 0x2C
+#define SLANG_IMEQS 0x2D
+#define SLANG_IPP 0x2E
+#define SLANG_IMM 0x2F
+
+
+#define SLANG_ELSE_MASK 0x10
+#define SLANG_ANDELSE 0x11
+#define SLANG_ORELSE 0x12
+#define SLANG_SWITCH 0x13
+
+/* LOGICAL SUBTYPES (operate on integers) */
+#define SLANG_MOD 16
+#define SLANG_OR 17
+#define SLANG_AND 18
+#define SLANG_BAND 19
+#define SLANG_BOR 20
+#define SLANG_BXOR 21
+#define SLANG_SHL 22
+#define SLANG_SHR 23
+
+/* LUnary Subtypes */
+#define SLANG_NOT 24
+#define SLANG_BNOT 25
+
+typedef struct SLBlock_Type
+ {
+ unsigned char main_type;
+ unsigned char sub_type;
+ union
+ {
+ struct SLBlock_Type *blk;
+ int i_blk;
+ SLang_Name_Type *n_blk;
+ char *s_blk;
+#ifdef FLOAT_TYPE
+ float64 *f_blk; /*literal float is a pointer */
+#endif
+ long l_blk;
+ }
+ b;
+ }
+SLBlock_Type;
+
+
+typedef struct
+{
+ unsigned char main_type; /* block, intrinsic... */
+ unsigned char sub_type; /* SLANG_WHILE, SLANG_DATA, ... */
+ union
+ {
+ long l_val;
+ char *s_val;
+ int i_val;
+ SLuser_Object_Type *uobj;
+ SLang_Name_Type *n_val;
+#ifdef FLOAT_TYPE
+ float64 f_val;
+#endif
+ } v;
+} SLang_Object_Type;
+
+
+extern void SLang_free_object (SLang_Object_Type *);
+
+extern int SLang_pop_non_object (SLang_Object_Type *);
+
+extern void _SLdo_error (char *, ...);
+extern void SLcompile(char *);
+extern void (*SLcompile_ptr)(char *);
+
+typedef struct
+{
+ char *name; int type;
+} SLang_Name2_Type;
+
+extern void SLstupid_hash(void);
+
+typedef struct SLName_Table
+{
+ struct SLName_Table *next; /* next table */
+ SLang_Name_Type *table; /* pointer to table */
+ int n; /* entries in this table */
+ char name[32]; /* name of table */
+ int ofs[256]; /* offsets into table */
+} SLName_Table;
+
+extern SLName_Table *SLName_Table_Root;
+#ifdef MSWINDOWS
+extern SLang_Name_Type *SLang_Name_Table;
+#else
+extern SLang_Name_Type SLang_Name_Table[SLANG_MAX_SYMBOLS];
+#endif
+
+extern SLang_Name2_Type SL_Binary_Ops [];
+extern SLang_Object_Type *SLStack_Pointer;
+extern char *SLbyte_compile_name(char *);
+extern int SLang_pop(SLang_Object_Type *);
+extern char *SLexpand_escaped_char(char *, char *);
+extern void SLexpand_escaped_string (char *, char *, char *);
+
+extern SLang_Object_Type *_SLreverse_stack (int);
+extern SLang_Name_Type *SLang_locate_name(char *);
+
+/* returns a pointer to a MALLOCED string */
+extern char *SLstringize_object (SLang_Object_Type *);
+
+/* array types */
+typedef struct SLArray_Type
+{
+ unsigned char type; /* int, float, etc... */
+ int dim; /* # of dims (max 3) */
+ int x, y, z; /* actual dims */
+ union
+ {
+ unsigned char *c_ptr;
+ unsigned char **s_ptr;
+ int *i_ptr;
+#ifdef FLOAT_TYPE
+ float64 *f_ptr;
+#endif
+ SLuser_Object_Type **u_ptr;
+ }
+ buf;
+ unsigned char flags; /* readonly, etc... If this is non-zero,
+ * the buf pointer will NOT be freed.
+ * See SLarray_free_array.
+ */
+} SLArray_Type;
+
+
+/* Callback to delete array */
+extern void SLarray_free_array (long *);
+
+
+/* maximum size of run time stack */
+#ifdef msdos
+#define SLANG_MAX_STACK_LEN 500
+#else
+#define SLANG_MAX_STACK_LEN 2500
+#endif
+
+#ifdef MSWINDOWS
+extern SLang_Object_Type *SLRun_Stack;
+#else
+extern SLang_Object_Type SLRun_Stack[SLANG_MAX_STACK_LEN];
+#endif
+
+extern SLang_Object_Type *SLStack_Pointer;
+
+extern int SLang_Trace;
+extern int SLstack_depth(void);
+
+extern void SLang_trace_fun(char *);
+extern void SLexecute_function(SLang_Name_Type *);
+extern char *SLmake_string (char *);
+
+extern int _SLeqs_name(char *, SLang_Name2_Type *);
+extern void SLang_push(SLang_Object_Type *);
+extern void SLang_push_float(float64);
+extern void SLadd_variable(char *);
+extern void SLang_clear_error(void);
+extern void SLarray_info (void);
+extern int SLPreprocess_Only; /* preprocess instead of
+ * bytecompiling
+ */
+
+extern void SLdo_pop (void);
+extern unsigned int SLsys_getkey (void);
+extern int SLsys_input_pending (int);
+
+#ifdef REAL_UNIX_SYSTEM
+extern int SLtt_tigetflag (char *, char **);
+extern int SLtt_tigetnum (char *, char **);
+extern char *SLtt_tigetstr (char *, char **);
+extern char *SLtt_tigetent (char *);
+#endif
+
+#ifdef msdos
+#define MAX_INPUT_BUFFER_LEN 40
+#else
+#define MAX_INPUT_BUFFER_LEN 1024
+#endif
+extern unsigned char SLang_Input_Buffer [MAX_INPUT_BUFFER_LEN];
+extern unsigned int SLang_Input_Buffer_Len;
+
+extern int SLregister_types (void);
+
+#ifndef pc_system
+extern char *SLtt_Graphics_Char_Pairs;
+#endif /* NOT pc_system */
+
+extern void _SLerrno_set_return_status (void);
+extern char *_SLerrno_strerror (void);
+extern int _SLerrno_Return_Status;
+
--- /dev/null
+#ifndef _JD_MACROS_H_
+#define _JD_MACROS_H_
+
+/* This file defines some macros that I use with programs that link to
+ * the slang library.
+ */
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+# include <malloc.h>
+#endif
+
+#ifdef HAVE_MEMORY_H
+# include <memory.h>
+#endif
+
+#ifndef SLMEMSET
+# ifdef HAVE_MEMSET
+# define SLMEMSET memset
+# else
+# define SLMEMSET SLmemset
+# endif
+#endif
+
+#ifndef SLMEMCHR
+# ifdef HAVE_MEMCHR
+# define SLMEMCHR memchr
+# else
+# define SLMEMCHR SLmemchr
+# endif
+#endif
+
+#ifndef SLMEMCPY
+# ifdef HAVE_MEMCPY
+# define SLMEMCPY memcpy
+# else
+# define SLMEMCPY SLmemcpy
+# endif
+#endif
+
+/* Note: HAVE_MEMCMP requires an unsigned memory comparison!!! */
+#ifndef SLMEMCMP
+# ifdef HAVE_MEMCMP
+# define SLMEMCMP memcmp
+# else
+# define SLMEMCMP SLmemcmp
+# endif
+#endif
+
+#if SLANG_VERSION < 9934
+# define SLmemcmp jed_memcmp
+# define SLmemcpy jed_memcpy
+# define SLmemset jed_memset
+# define SLmemchr jed_memchr
+#endif
+
+#ifndef SLFREE
+# define SLFREE free
+#endif
+
+#ifndef SLMALLOC
+# define SLMALLOC malloc
+#endif
+
+#ifndef SLCALLOC
+# define SLCALLOC calloc
+#endif
+
+#ifndef SLREALLOC
+# define SLREALLOC realloc
+#endif
+
+#endif /* _JD_MACROS_H_ */
--- /dev/null
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+rootdir = $(srcdir)/..
+@MCFG@@MCF@
+
+CFLAGS = $(XCFLAGS)
+CPPFLAGS = $(XCPPFLAGS)
+LDFLAGS = $(XLDFLAGS)
+DEFS = $(XDEFS)
+LIBS = $(XLIBS) $(XLIB)
+AR = @AR@
+
+SLANGSRCS = sldisply.c slerr.c slsmg.c slutty.c slgetkey.c slmemcpy.c \
+ slmemset.c sltermin.c sltoken.c slsignal.c \
+ slvideo.c slw32tty.c slos2tty.c
+
+SLANGHDRS = slang.h _slang.h sl-feat.h jdmacros.h
+
+SLANGOBJS = sldisply.o slerr.o slsmg.o slutty.o \
+ slgetkey.o slmemcpy.o slmemset.o sltermin.o \
+ sltoken.o slsignal.o
+
+#
+# Distribution variables
+#
+
+DISTSLANG = Makefile.in README $(SLANGSRCS) $(SLANGHDRS)
+
+all: @LIBSLANG@
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) $<
+
+check:
+ @echo no tests are supplied.
+
+libmcslang.a: $(SLANGOBJS)
+ $(RMF) $@
+ $(AR) cr $@ $(SLANGOBJS)
+ -$(RANLIB) $@
+
+showlibdep:
+ @echo 'OBJS="$(SLANGOBJS)"'
+
+cross:
+ $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \
+ CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses "
+
+TAGS: $(SLANGSRCS)
+ etags $(SLANGSRCS)
+
+clean:
+ $(RMF) *.o core a.out libmcslang.a
+
+realclean: clean
+ $(RMF) .depend
+ $(RMF) TAGS
+ $(RMF) *~
+
+distclean:
+ -$(RMF) $(srcdir)/*~ $(srcdir)/*.o $(srcdir)/core $(srcdir)/a.out
+ -$(RMF) $(srcdir)/libmcslang.a
+ -if test $(srcdir) = .; then $(MAKE) realclean; fi
+ -$(RMF) $(srcdir)/Makefile
+
+distcopy:
+ $(CP) $(DISTSLANG) ../../mc-$(VERSION)/slang
+
+install uninstall:
+
+depend dep: mcdep
+
+fastdeploc:
+
+# ***Dependencies***Do not edit***
+@DOTDEPEND@
+# ***End of dependencies***
--- /dev/null
+
+This is the Slang Screen Manager, it has been modified a little to
+make it work with the Midnight Commander. If you want to get the
+complete Slang distribution, you may grab it from:
+
+space.mit.edu:/pub/davis
+
+All of the patches relevant to Slang have been sumbited to John Davis
+for inclusion in his Slang version, changes that are only useful for
+the Midnight Commander have not been submited.
+
+miguel.
--- /dev/null
+/* Set this to 1 to enable Kanji support */
+#define SLANG_HAS_KANJI_SUPPORT 0
--- /dev/null
+#ifndef DAVIS_SLANG_H_
+#define DAVIS_SLANG_H_
+/* -*- mode: C; mode: fold; -*- */
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+#define SLANG_VERSION 9938
+/*{{{ System Dependent Macros and Typedefs */
+
+#if defined(__WATCOMC__) && !defined(__QNX__)
+# ifndef msdos
+# define msdos
+# endif
+# ifndef DOS386
+# define DOS386
+# endif
+# ifndef FLOAT_TYPE
+# define FLOAT_TYPE
+# endif
+# ifndef pc_system
+# define pc_system
+# endif
+#endif /* __watcomc__ */
+
+#ifdef unix
+# ifndef __unix__
+# define __unix__ 1
+# endif
+#endif
+
+#ifndef __GO32__
+# ifdef __unix__
+# define REAL_UNIX_SYSTEM
+# endif
+#endif
+
+/* Set of the various defines for pc systems. This includes OS/2 */
+#ifdef __MSDOS__
+# ifndef msdos
+# define msdos
+# endif
+# ifndef pc_system
+# define pc_system
+# endif
+#endif
+
+#ifdef __GO32__
+# ifndef pc_system
+# define pc_system
+# endif
+# ifdef REAL_UNIX_SYSTEM
+# undef REAL_UNIX_SYSTEM
+# endif
+#endif
+
+#if defined(__EMX__) && defined(OS2)
+# ifndef pc_system
+# define pc_system
+# endif
+# ifndef __os2__
+# define __os2__
+# endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#if 0
+}
+#endif
+/* ---------------------------- Generic Macros ----------------------------- */
+
+/* __SC__ is defined for Symantec C++
+ DOS386 is defined for -mx memory model, 32 bit DOS extender. */
+
+#ifdef VOID
+# undef VOID
+#endif
+
+#if defined(msdos) && !defined(DOS386) & !defined(__WIN32__) && !defined(__GO32__)
+# ifdef __SC__
+# include <dos.h>
+# endif
+ typedef void *VOID_STAR;
+# define VOID void
+# include <alloc.h>
+#else
+# if defined (__cplusplus) || defined(__STDC__)
+ typedef void *VOID_STAR;
+# define VOID void
+# else
+ typedef unsigned char *VOID_STAR;
+# define VOID unsigned char
+# endif
+#endif
+
+#if 1
+ typedef int (*FVOID_STAR)(void);
+#else
+# define FVOID_STAR VOID_STAR
+#endif
+
+#if defined(msdos) && !defined(DOS386) && !defined(__GO32__) && !defined(__WIN32__)
+# define SLFREE(buf) farfree((void far *)(buf))
+# define SLMALLOC(x) farmalloc((unsigned long) (x))
+# define SLREALLOC(buf, n) farrealloc((void far *) (buf), (unsigned long) (n))
+# define SLCALLOC(n, m) farcalloc((unsigned long) (n), (unsigned long) (m))
+#else
+# if defined(VMS) && !defined(__DECC)
+# define SLFREE VAXC$FREE_OPT
+# define SLMALLOC VAXC$MALLOC_OPT
+# define SLREALLOC VAXC$REALLOC_OPT
+# define SLCALLOC VAXC$CALLOC_OPT
+# else
+# define SLFREE(x) free((char *)(x))
+# define SLMALLOC malloc
+# if defined(__cplusplus) && !defined(__BEOS__)
+# define SLREALLOC(p,n) realloc((malloc_t) (p), (n))
+# else
+# define SLREALLOC realloc
+# endif
+# define SLCALLOC calloc
+# endif
+#endif
+
+#ifdef SL_MALLOC_DEBUG
+# undef SLMALLOC
+# undef SLCALLOC
+# undef SLREALLOC
+# undef SLFREE
+# define SLMALLOC(x) SLdebug_malloc((unsigned long) (x))
+# define SLFREE(x) SLdebug_free((unsigned char *)(x))
+# define SLCALLOC(n, m) SLdebug_calloc((unsigned long) (n), (unsigned long)(m))
+# define SLREALLOC(p, x) SLdebug_realloc((unsigned char *)(p), (unsigned long)(x))
+#endif /* SL_MALLOC_DEBUG */
+
+ extern unsigned char *SLdebug_malloc (unsigned long);
+ extern unsigned char *SLdebug_calloc (unsigned long, unsigned long);
+ extern unsigned char *SLdebug_realloc (unsigned char *, unsigned long);
+ extern void SLdebug_free (unsigned char *);
+ extern void SLmalloc_dump_statistics (void);
+ extern char *SLstrcpy(register char *, register char *);
+ extern int SLstrcmp(register char *, register char *);
+ extern char *SLstrncpy(char *, register char *, register int);
+
+ extern void SLmemset (char *, char, int);
+ extern char *SLmemchr (register char *, register char, register int);
+ extern char *SLmemcpy (char *, char *, int);
+ extern int SLmemcmp (char *, char *, int);
+
+#ifdef float64
+# undef float64
+#endif
+
+#ifndef FLOAT64_TYPEDEFED
+# define FLOAT64_TYPEDEFED
+ typedef double float64;
+#endif
+
+
+/*}}}*/
+
+/*{{{ Interpreter Typedefs */
+
+#define SLANG_MAX_NAME_LEN 30
+/* maximum length of an identifier */
+/* first char in identifiers is the hash */
+
+ /* Note that long is used for addresses instead of void *. The reason for
+ * this is that I have a gut feeling that sizeof (long) > sizeof(void *)
+ * on some machines. This is certainly the case for MSDOS where addresses
+ * can be 16 bit.
+ */
+typedef struct SLang_Name_Type
+ {
+#ifdef SLANG_STATS
+ int n; /* number of times referenced */
+#endif
+ char name[SLANG_MAX_NAME_LEN + 2]; /* [0] is hash */
+
+ unsigned char sub_type;
+
+/* Values for main_type may be as follows. The particlular values are
+ * for compatability.
+ */
+#define SLANG_LVARIABLE 0x01
+#define SLANG_INTRINSIC 0x06
+#define SLANG_FUNCTION 0x07
+#define SLANG_GVARIABLE 0x0D
+#define SLANG_IVARIABLE 0x0E /* intrinsic variables */
+/* Note!!! For Macro MAKE_VARIABLE below to work, SLANG_IVARIABLE Must
+ be 1 less than SLANG_RVARIABLE!!! */
+#define SLANG_RVARIABLE 0x0F /* read only variable */
+ unsigned char main_type;
+ long addr;
+ }
+SLang_Name_Type;
+
+
+typedef struct SLang_Load_Type
+{
+ long name; /* file name, string address, ... */
+ long handle; /* FILE *, string address, etc... */
+
+ char *ptr; /* input pointer to next line in object
+ * to be read.
+ */
+ /* Things below here are used by S-Lang. */
+ int type; /* 'F' = file, 'S' = String, etc.. */
+ char *buf; /* buffer for file, etc... */
+ char *(*read)(struct SLang_Load_Type *); /* function to call to read obj */
+ int n; /* line number, etc... */
+ char token[256]; /* token to be parsed */
+ int ofs; /* offset from buf where last read
+ * took place
+ */
+ int top_level; /* 1 if at top level of parsing */
+} SLang_Load_Type;
+
+#if defined(ultrix) && !defined(__GNUC__)
+# ifndef NO_PROTOTYPES
+# define NO_PROTOTYPES
+# endif
+#endif
+
+#ifndef NO_PROTOTYPES
+# define _PROTO(x) x
+#else
+# define _PROTO(x) ()
+#endif
+
+typedef struct SL_OOBinary_Type
+{
+ unsigned char sub_type; /* partner type for binary op */
+
+ /* The function take the binary op as first argument, the operand types
+ * form the second and third parameters and the last two parameters are
+ * pointers to the objects themselves. It is up to the function to push
+ * the result on the stack. It must return 1 if it handled the operation
+ * return zero if the operation is not defined.
+ */
+ int (*binary_function)_PROTO((int, unsigned char, unsigned char,
+ VOID_STAR, VOID_STAR));
+
+ struct SL_OOBinary_Type *next;
+}
+SL_OOBinary_Type;
+
+typedef struct
+{
+ /* Methods */
+ void (*destroy)_PROTO((VOID_STAR));
+ /* called to delete/free the object */
+ char *(*string)_PROTO((VOID_STAR));
+ /* returns a string representation of the object */
+ int (*unary_function)_PROTO((int, unsigned char, VOID_STAR));
+ /* unary operation function */
+ SL_OOBinary_Type *binary_ops;
+
+ int (*copy_function)_PROTO((unsigned char, VOID_STAR));
+ /* This function is called do make a copy of the object */
+} SLang_Class_Type;
+
+extern SLang_Class_Type *SLang_Registered_Types[256];
+
+typedef struct
+{
+ unsigned char main_type; /* SLANG_RVARIABLE, etc.. */
+ unsigned char sub_type; /* int, string, etc... */
+ long *obj; /* address of user structure */
+
+ /* Everything below is considered private */
+ unsigned int count; /* number of references */
+}
+SLuser_Object_Type;
+
+
+/*}}}*/
+/*{{{ Interpreter Function Prototypes */
+
+ extern volatile int SLang_Error;
+ /* Non zero if error occurs. Must be reset to zero to continue. */
+
+ extern int SLang_Traceback;
+ /* If non-zero, dump an S-Lang traceback upon error. Available as
+ _traceback in S-Lang. */
+
+ extern char *SLang_User_Prompt;
+ /* Prompt to use when reading from stdin */
+ extern int SLang_Version;
+
+ extern void (*SLang_Error_Routine)(char *);
+ /* Pointer to application dependent error messaging routine. By default,
+ messages are displayed on stderr. */
+
+ extern void (*SLang_Exit_Error_Hook)(char *);
+ extern void SLang_exit_error (char *);
+ extern void (*SLang_Dump_Routine)(char *);
+ /* Called if S-Lang traceback is enabled as well as other debugging
+ routines (e.g., trace). By default, these messages go to stderr. */
+
+ extern void (*SLang_Interrupt)(void);
+ /* function to call whenever inner interpreter is entered. This is
+ a good place to set SLang_Error to USER_BREAK. */
+
+ extern void (*SLang_User_Clear_Error)(void);
+ /* function that gets called when '_clear_error' is called. */
+ extern int (*SLang_User_Open_Slang_Object)(SLang_Load_Type *);
+ extern int (*SLang_User_Close_Slang_Object)(SLang_Load_Type *);
+ /* user defined loading routines. */
+
+
+ /* If non null, these call C functions before and after a slang function. */
+ extern void (*SLang_Enter_Function)(char *);
+ extern void (*SLang_Exit_Function)(char *);
+
+
+/* Functions: */
+
+ extern int init_SLang(void);
+ /* This function is mandatory and must be called by all applications */
+ extern int init_SLfiles(void);
+ /* called if fputs, fgets, etc are need in S-Lang */
+ extern int init_SLmath(void);
+ /* called if math functions sin, cos, etc... are needed. */
+
+ extern int init_SLunix(void);
+ /* unix system functions chmod, stat, etc... */
+
+ extern int init_SLmatrix(void);
+
+ extern int SLang_add_table(SLang_Name_Type *, char *);
+ /* add application dependent function table p1 to S-Lang. A name p2 less
+ * than 32 characters must also be supplied.
+ * Returns 0 upon failure or 1 upon success. */
+
+ extern int SLang_add_global_variable (char *);
+ extern int SLang_load_object(SLang_Load_Type *);
+ extern int SLang_load_file(char *);
+ /* Load a file of S-Lang code for interpreting. If the parameter is
+ NULL, input comes from stdin. */
+
+ extern void SLang_restart(int);
+ /* should be called if an error occurs. If the passed integer is
+ * non-zero, items are popped off the stack; otherwise, the stack is
+ * left intact. Any time the stack is believed to be trashed, this routine
+ * should be called with a non-zero argument (e.g., if setjmp/longjmp is
+ * called). */
+
+ extern void SLang_byte_compile_file(char *, int *);
+ /* takes a file of S-Lang code and ``byte-compiles'' it for faster
+ * loading. The new filename is equivalent to the old except that a `c' is
+ * appended to the name. (e.g., init.sl --> init.slc). If the second
+ * parameter is non-zero, preprocess the file only.
+ */
+
+ extern void SLang_autoload(char *, char *);
+ /* Automatically load S-Lang function p1 from file p2. This function
+ is also available via S-Lang */
+
+ extern char *SLang_load_string(char *);
+ /* Like SLang_load_file except input is from a null terminated string. */
+
+ extern void SLang_do_pop(void);
+ /* pops item off stack and frees any memory associated with it */
+
+ extern int SLang_pop_integer(int *);
+ /* pops integer *p0 from the stack. Returns 0 upon success and non-zero
+ * if the stack is empty or a type mismatch occurs, setting SLang_Error.
+ */
+
+ extern int SLpop_string (char **);
+ extern int SLang_pop_string(char **, int *);
+ /* pops string *p0 from stack. If *p1 is non-zero, the string must be
+ * freed after its use. DO NOT FREE p0 if *p1 IS ZERO! Returns 0 upon
+ * success */
+
+ extern int SLang_pop_float(float64 *, int *, int *);
+ /* Pops float *p1 from stack. If *p3 is non-zero, *p1 was derived
+ from the integer *p2. Returns zero upon success. */
+
+ extern SLuser_Object_Type *SLang_pop_user_object (unsigned char);
+ extern void SLang_free_user_object (SLuser_Object_Type *);
+ extern void SLang_free_intrinsic_user_object (SLuser_Object_Type *);
+ /* This is like SLang_free_user_object but is meant to free those
+ * that have been declared as intrinsic variables by the application.
+ * Normally an application would never need to call this.
+ */
+
+ extern void SLang_push_user_object (SLuser_Object_Type *);
+ extern SLuser_Object_Type *SLang_create_user_object (unsigned char);
+
+ extern int SLang_add_unary_op (unsigned char, FVOID_STAR);
+ extern int SLang_add_binary_op (unsigned char, unsigned char, FVOID_STAR);
+ extern int SLang_register_class (unsigned char, FVOID_STAR, FVOID_STAR);
+ extern int SLang_add_copy_operation (unsigned char, FVOID_STAR);
+
+ extern long *SLang_pop_pointer(unsigned char *, unsigned char *, int *);
+ /* Returns a pointer to object of type *p1,*p2 on top of stack.
+ If *p3 is non-zero, the Object must be freed after use. */
+
+
+ extern void SLang_push_float(float64);
+ /* Push Float onto stack */
+
+ extern void SLang_push_string(char *);
+ /* Push string p1 onto stack */
+
+ extern void SLang_push_integer(int);
+ /* push integer p1 on stack */
+
+ extern void SLang_push_malloced_string(char *);
+ /* The normal SLang_push_string mallocs space for the string. This one
+ does not. DO NOT FREE IT IF YOU USE THIS ROUTINE */
+
+ extern int SLang_is_defined(char *);
+ /* Return non-zero is p1 is defined otherwise returns 0. */
+
+ extern int SLang_run_hooks(char *, char *, char *);
+ /* calls S-Lang function p1 pushing strings p2 and p3 onto the stack
+ * first. If either string is NULL, it is not pushed. If p1 is not
+ * defined, 0 is returned. */
+
+ extern int SLang_execute_function(char *);
+ /* Call S-Lang function p1. Returns 0 if the function is not defined
+ * and 1 if it is.
+ */
+
+ extern char *SLang_find_name(char *);
+ /* Return a pointer to p1 in table if it is defined. Returns NULL
+ * otherwise. This is useful when one wants to avoid redundant strings.
+ */
+
+ extern char *SLang_rpn_interpret(char *);
+ /* Interpret string as reverse polish notation */
+
+ extern void SLang_doerror(char *);
+ /* set SLang_Error and display p1 as error message */
+
+ extern SLuser_Object_Type *SLang_add_array(char *, long *,
+ int, int, int, int,
+ unsigned char, unsigned char);
+ /* This function has not been tested thoroughly yet. Its purpose is to
+ * allow a S-Lang procedure to access a C array. For example, suppose that
+ * you have an array of 100 ints defined as:
+ *
+ * int c_array[100];
+ *
+ * By calling something like:
+ *
+ * SLang_add_array ("array_name", (long *) c_array, 1, 100, 0, 0,
+ * 'i', SLANG_IVARIABLE);
+ *
+ * the array can be accessed by the name 'array_name'. This function
+ * returns -1 upon failure. The 3rd argument specifies the dimension
+ * of the array, the 4th, and 5th arguments specify how many elements
+ * there are in the x,y, and z directions. The last argument must
+ * be one of:
+ *
+ * SLANG_IVARIABLE: indicates array is writable
+ * SLANG_RVARIABLE: indicates array is read only
+ *
+ * Returns NULL upon failure.
+ */
+
+
+extern int SLang_free_array_handle (int);
+/* This routine may be called by application to free array handle created by
+ * the application. Returns 0 upon success, -1 if the handle is invalid and
+ * -2 if the handle is not associated with a C array.
+ */
+
+ extern char *SLang_extract_list_element(char *, int *, int*);
+ extern void SLexpand_escaped_string (register char *, register char *,
+ register char *);
+
+extern SLang_Name_Type *SLang_get_function (char *);
+/* The parameter is the name of a user defined S-Lang function. This
+ * routine returns NULL if the function does not exist or it returns the
+ * a pointer to it in an internal S-Lang table. This pointer can be used
+ * by 'SLexecute_function' to call the function directly from C.
+ */
+
+extern void SLexecute_function(SLang_Name_Type *);
+/* This function allows an application to call a S-Lang function from within
+ * the C program. The parameter must be non-NULL and must have been
+ * previously obtained by a call to 'SLang_get_function'.
+ */
+extern void SLroll_stack (int *);
+/* If argument *p is positive, the top |*p| objects on the stack are rolled
+ * up. If negative, the stack is rolled down.
+ */
+
+extern void SLmake_lut (unsigned char *, unsigned char *, unsigned char);
+
+ extern int SLang_guess_type (char *);
+
+
+/*}}}*/
+
+/*{{{ Misc Functions */
+
+extern char *SLmake_string (char *);
+extern char *SLmake_nstring (char *, unsigned int);
+/* Returns a null terminated string made from the first n characters of the
+ * string.
+ */
+
+extern char *SLcurrent_time_string (void);
+
+extern int SLatoi(unsigned char *);
+
+extern int SLang_extract_token(char **, char *, int);
+/* returns 0 upon failure and non-zero upon success. The first parameter
+ * is a pointer to the input stream which this function will bump along.
+ * The second parameter is the buffer where the token is placed. The third
+ * parameter is used internally by the S-Lang library and should be 0 for
+ * user applications.
+ */
+
+/*}}}*/
+
+/*{{{ SLang getkey interface Functions */
+
+#ifdef REAL_UNIX_SYSTEM
+extern int SLang_TT_Baud_Rate;
+extern int SLang_TT_Read_FD;
+#endif
+
+extern int SLang_init_tty (int, int, int);
+/* Initializes the tty for single character input. If the first parameter *p1
+ * is in the range 0-255, it will be used for the abort character;
+ * otherwise, (unix only) if it is -1, the abort character will be the one
+ * used by the terminal. If the second parameter p2 is non-zero, flow
+ * control is enabled. If the last parmeter p3 is zero, output processing
+ * is NOT turned on. A value of zero is required for the screen management
+ * routines. Returns 0 upon success. In addition, if SLang_TT_Baud_Rate ==
+ * 0 when this function is called, SLang will attempt to determine the
+ * terminals baud rate. As far as the SLang library is concerned, if
+ * SLang_TT_Baud_Rate is less than or equal to zero, the baud rate is
+ * effectively infinite.
+ */
+
+extern void SLang_reset_tty (void);
+/* Resets tty to what it was prior to a call to SLang_init_tty */
+#ifdef REAL_UNIX_SYSTEM
+extern void SLtty_set_suspend_state (int);
+ /* If non-zero argument, terminal driver will be told to react to the
+ * suspend character. If 0, it will not.
+ */
+extern int (*SLang_getkey_intr_hook) (void);
+#endif
+
+#define SLANG_GETKEY_ERROR 0xFFFF
+extern unsigned int SLang_getkey (void);
+/* reads a single key from the tty. If the read fails, 0xFFFF is returned. */
+
+extern void SLang_ungetkey_string (unsigned char *, unsigned int);
+extern void SLang_buffer_keystring (unsigned char *, unsigned int);
+extern void SLang_ungetkey (unsigned char);
+extern void SLang_flush_input (void);
+extern int SLang_input_pending (int);
+extern int SLang_Abort_Char;
+/* The value of the character (0-255) used to trigger SIGINT */
+extern int SLang_Ignore_User_Abort;
+/* If non-zero, pressing the abort character will not result in USER_BREAK
+ * SLang_Error. */
+
+extern void SLang_set_abort_signal (void (*)(int));
+/* If SIGINT is generated, the function p1 will be called. If p1 is NULL
+ * the SLang_default signal handler is called. This sets SLang_Error to
+ * USER_BREAK. I suspect most users will simply want to pass NULL.
+ */
+
+extern volatile int SLKeyBoard_Quit;
+
+#ifdef VMS
+/* If this function returns -1, ^Y will be added to input buffer. */
+extern int (*SLtty_VMS_Ctrl_Y_Hook) (void);
+#endif
+/*}}}*/
+
+/*{{{ SLang Keymap routines */
+
+typedef struct SLKeymap_Function_Type
+ {
+ char *name;
+ int (*f)(void);
+ }
+SLKeymap_Function_Type;
+
+typedef struct SLang_Key_Type
+ {
+ unsigned char str[13]; /* key sequence */
+#define SLKEY_F_INTERPRET 0x01
+#define SLKEY_F_INTRINSIC 0x02
+#define SLKEY_F_KEYSYM 0x03
+ unsigned char type; /* type of function */
+#ifdef SLKEYMAP_OBSOLETE
+ VOID_STAR f; /* function to invoke */
+#else
+ union
+ {
+ char *s;
+ FVOID_STAR f;
+ unsigned int keysym;
+ }
+ f;
+#endif
+ struct SLang_Key_Type *next; /* */
+ }
+SLang_Key_Type;
+
+#define MAX_KEYMAP_NAME_LEN 8
+typedef struct SLKeyMap_List_Type
+{
+ char name[MAX_KEYMAP_NAME_LEN + 1];
+ SLang_Key_Type *keymap;
+ SLKeymap_Function_Type *functions; /* intrinsic functions */
+}
+SLKeyMap_List_Type;
+
+/* This is arbitrary but I have got to start somewhere */
+#ifdef msdos
+#define SLANG_MAX_KEYMAPS 10
+#else
+#define SLANG_MAX_KEYMAPS 30
+#endif
+
+extern SLKeyMap_List_Type SLKeyMap_List[SLANG_MAX_KEYMAPS]; /* these better be inited to 0! */
+
+
+extern char *SLang_process_keystring(char *);
+
+#ifdef SLKEYMAP_OBSOLETE
+extern int SLang_define_key1(char *, VOID_STAR, unsigned int, SLKeyMap_List_Type *);
+/* define key p1 in keymap p4 to invoke function p2. If type p3 is given by
+ * SLKEY_F_INTRINSIC, p2 is an intrinsic function, else it is a string to be
+ * passed to the interpreter for evaluation. The return value is important.
+ * It returns 0 upon success, -1 upon malloc error, and -2 if the key is
+ * inconsistent. SLang_Error is set upon error. */
+#else
+extern int SLkm_define_key (char *, FVOID_STAR, SLKeyMap_List_Type *);
+#endif
+
+extern int SLang_define_key(char *, char *, SLKeyMap_List_Type *);
+/* Like define_key1 except that p2 is a string that is to be associated with
+ * a function in the functions field of p3. This routine calls define_key1.
+ */
+
+extern int SLkm_define_keysym (char *, unsigned int, SLKeyMap_List_Type *);
+
+extern void SLang_undefine_key(char *, SLKeyMap_List_Type *);
+
+extern SLKeyMap_List_Type *SLang_create_keymap(char *, SLKeyMap_List_Type *);
+/* create and returns a pointer to a new keymap named p1 created by copying
+ * keymap p2. If p2 is NULL, it is up to the calling routine to initialize
+ * the keymap.
+ */
+
+extern char *SLang_make_keystring(unsigned char *);
+
+extern SLang_Key_Type *SLang_do_key(SLKeyMap_List_Type *, int (*)(void));
+/* read a key using keymap p1 with getkey function p2 */
+
+extern
+#ifdef SLKEYMAP_OBSOLETE
+ VOID_STAR
+#else
+ FVOID_STAR
+#endif
+ SLang_find_key_function(char *, SLKeyMap_List_Type *);
+
+extern SLKeyMap_List_Type *SLang_find_keymap(char *);
+
+extern int SLang_Last_Key_Char;
+extern int SLang_Key_TimeOut_Flag;
+
+
+/*}}}*/
+
+/*{{{ SLang Readline Interface */
+
+typedef struct SLang_Read_Line_Type
+{
+ struct SLang_Read_Line_Type *prev, *next;
+ unsigned char *buf;
+ int buf_len; /* number of chars in the buffer */
+ int num; /* num and misc are application specific*/
+ int misc;
+} SLang_Read_Line_Type;
+
+/* Maximum size of display */
+#define SLRL_DISPLAY_BUFFER_SIZE 256
+
+typedef struct
+{
+ SLang_Read_Line_Type *root, *tail, *last;
+ unsigned char *buf; /* edit buffer */
+ int buf_len; /* sizeof buffer */
+ int point; /* current editing point */
+ int tab; /* tab width */
+ int len; /* current line size */
+
+ /* display variables */
+ int edit_width; /* length of display field */
+ int curs_pos; /* current column */
+ int start_column; /* column offset of display */
+ int dhscroll; /* amount to use for horiz scroll */
+ char *prompt;
+
+ FVOID_STAR last_fun; /* last function executed by rl */
+
+ /* These two contain an image of what is on the display */
+ unsigned char upd_buf1[SLRL_DISPLAY_BUFFER_SIZE];
+ unsigned char upd_buf2[SLRL_DISPLAY_BUFFER_SIZE];
+ unsigned char *old_upd, *new_upd; /* pointers to previous two buffers */
+ int new_upd_len, old_upd_len; /* length of output buffers */
+
+ SLKeyMap_List_Type *keymap;
+
+ /* tty variables */
+ unsigned int flags; /* */
+#define SL_RLINE_NO_ECHO 1
+#define SL_RLINE_USE_ANSI 2
+ unsigned int (*getkey)(void); /* getkey function -- required */
+ void (*tt_goto_column)(int);
+ void (*tt_insert)(char);
+ void (*update_hook)(unsigned char *, int, int);
+ /* The update hook is called with a pointer to a buffer p1 that contains
+ * an image of what the update hook is suppoed to produce. The length
+ * of the buffer is p2 and after the update, the cursor is to be placed
+ * in column p3.
+ */
+} SLang_RLine_Info_Type;
+
+extern int SLang_RL_EOF_Char;
+
+extern SLang_Read_Line_Type * SLang_rline_save_line (SLang_RLine_Info_Type *);
+extern int SLang_init_readline (SLang_RLine_Info_Type *);
+extern int SLang_read_line (SLang_RLine_Info_Type *);
+extern int SLang_rline_insert (char *);
+extern void SLrline_redraw (SLang_RLine_Info_Type *);
+extern int SLang_Rline_Quit;
+
+/*}}}*/
+
+/*{{{ Low Level Screen Output Interface */
+
+extern unsigned long SLtt_Num_Chars_Output;
+extern int SLtt_Baud_Rate;
+
+typedef unsigned long SLtt_Char_Type;
+
+#define SLTT_BOLD_MASK 0x01000000
+#define SLTT_BLINK_MASK 0x02000000
+#define SLTT_ULINE_MASK 0x04000000
+#define SLTT_REV_MASK 0x08000000
+#define SLTT_ALTC_MASK 0x10000000
+
+extern int SLtt_Screen_Rows;
+extern int SLtt_Screen_Cols;
+extern int SLtt_Term_Cannot_Insert;
+extern int SLtt_Term_Cannot_Scroll;
+extern int SLtt_Use_Ansi_Colors;
+extern int SLtt_Ignore_Beep;
+#if defined(REAL_UNIX_SYSTEM)
+extern int SLtt_Force_Keypad_Init;
+#endif
+
+#ifndef __GO32__
+#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
+extern int SLtt_Blink_Mode;
+extern int SLtt_Use_Blink_For_ACS;
+extern int SLtt_Newline_Ok;
+extern int SLtt_Has_Alt_Charset;
+extern int SLtt_Has_Status_Line; /* if 0, NO. If > 0, YES, IF -1, ?? */
+# ifndef VMS
+extern int SLtt_Try_Termcap;
+# endif
+#endif
+#endif
+
+#ifdef msdos
+extern int SLtt_Msdos_Cheap_Video;
+#endif
+
+
+extern int SLtt_flush_output (void);
+extern void SLtt_set_scroll_region(int, int);
+extern void SLtt_reset_scroll_region(void);
+extern void SLtt_reverse_video (int);
+extern void SLtt_bold_video (void);
+extern void SLtt_begin_insert(void);
+extern void SLtt_end_insert(void);
+extern void SLtt_del_eol(void);
+extern void SLtt_goto_rc (int, int);
+extern void SLtt_delete_nlines(int);
+extern void SLtt_delete_char(void);
+extern void SLtt_erase_line(void);
+extern void SLtt_normal_video(void);
+extern void SLtt_cls(void);
+extern void SLtt_beep(void);
+extern void SLtt_reverse_index(int);
+extern void SLtt_smart_puts(unsigned short *, unsigned short *, int, int);
+extern void SLtt_write_string (char *);
+extern void SLtt_putchar(char);
+extern void SLtt_init_video (void);
+extern void SLtt_reset_video (void);
+extern void SLtt_get_terminfo(void);
+extern void SLtt_get_screen_size (void);
+extern int SLtt_set_cursor_visibility (int);
+
+#if defined(VMS) || defined(REAL_UNIX_SYSTEM)
+extern void SLtt_enable_cursor_keys(void);
+extern void SLtt_set_term_vtxxx(int *);
+extern void SLtt_set_color_esc (int, char *);
+extern void SLtt_wide_width(void);
+extern void SLtt_narrow_width(void);
+extern int SLtt_set_mouse_mode (int, int);
+extern void SLtt_set_alt_char_set (int);
+extern int SLtt_write_to_status_line (char *, int);
+extern void SLtt_disable_status_line (void);
+# ifdef REAL_UNIX_SYSTEM
+ extern char *SLtt_tgetstr (char *);
+ extern int SLtt_tgetnum (char *);
+ extern int SLtt_tgetflag (char *);
+ extern char *SLtt_tigetent (char *);
+ extern char *SLtt_tigetstr (char *, char **);
+ extern int SLtt_tigetnum (char *, char **);
+# endif
+#endif
+
+extern SLtt_Char_Type SLtt_get_color_object (int);
+extern void SLtt_set_color_object (int, SLtt_Char_Type);
+extern void SLtt_set_color (int, char *, char *, char *);
+extern void SLtt_set_mono (int, char *, SLtt_Char_Type);
+extern void SLtt_add_color_attribute (int, SLtt_Char_Type);
+extern void SLtt_set_color_fgbg (int, SLtt_Char_Type, SLtt_Char_Type);
+
+/*}}}*/
+
+/*{{{ SLang Preprocessor Interface */
+
+typedef struct
+{
+ int this_level;
+ int exec_level;
+ int prev_exec_level;
+ char preprocess_char;
+ char comment_char;
+ unsigned char flags;
+#define SLPREP_BLANK_LINES_OK 1
+#define SLPREP_COMMENT_LINES_OK 2
+}
+SLPreprocess_Type;
+
+extern int SLprep_open_prep (SLPreprocess_Type *);
+extern void SLprep_close_prep (SLPreprocess_Type *);
+extern int SLprep_line_ok (char *, SLPreprocess_Type *);
+ extern int SLdefine_for_ifdef (char *);
+ /* Adds a string to the SLang #ifdef preparsing defines. SLang already
+ defines MSDOS, UNIX, and VMS on the appropriate system. */
+extern int (*SLprep_exists_hook) (char *, char);
+
+
+/*}}}*/
+
+/*{{{ SLsmg Screen Management Functions */
+
+#include <stdarg.h>
+extern void SLsmg_fill_region (int, int, int, int, unsigned char);
+#ifndef pc_system
+extern void SLsmg_set_char_set (int);
+extern int SLsmg_Scroll_Hash_Border;
+#endif
+extern void SLsmg_suspend_smg (void);
+extern void SLsmg_resume_smg (void);
+extern void SLsmg_erase_eol (void);
+extern void SLsmg_gotorc (int, int);
+extern void SLsmg_erase_eos (void);
+extern void SLsmg_reverse_video (void);
+extern void SLsmg_set_color (int);
+extern void SLsmg_normal_video (void);
+extern void SLsmg_printf (char *, ...);
+extern void SLsmg_vprintf (char *, va_list);
+extern void SLsmg_write_string (char *);
+extern void SLsmg_write_nstring (char *, int);
+extern void SLsmg_write_char (char);
+extern void SLsmg_write_nchars (char *, int);
+extern void SLsmg_write_wrapped_string (char *, int, int, int, int, int);
+extern void SLsmg_cls (void);
+extern void SLsmg_refresh (void);
+extern void SLsmg_touch_lines (int, int);
+extern int SLsmg_init_smg (void);
+extern void SLsmg_reset_smg (void);
+extern unsigned short SLsmg_char_at(void);
+extern void SLsmg_set_screen_start (int *, int *);
+extern void SLsmg_draw_hline (int);
+extern void SLsmg_draw_vline (int);
+extern void SLsmg_draw_object (int, int, unsigned char);
+extern void SLsmg_draw_box (int, int, int, int);
+extern int SLsmg_get_column(void);
+extern int SLsmg_get_row(void);
+extern void SLsmg_forward (int);
+extern void SLsmg_write_color_chars (unsigned short *, unsigned int);
+extern unsigned int SLsmg_read_raw (unsigned short *, unsigned int);
+extern unsigned int SLsmg_write_raw (unsigned short *, unsigned int);
+
+extern int SLsmg_Display_Eight_Bit;
+extern int SLsmg_Tab_Width;
+extern int SLsmg_Newline_Moves;
+extern int SLsmg_Backspace_Moves;
+
+#ifdef pc_system
+# define SLSMG_HLINE_CHAR 0xC4
+# define SLSMG_VLINE_CHAR 0xB3
+# define SLSMG_ULCORN_CHAR 0xDA
+# define SLSMG_URCORN_CHAR 0xBF
+# define SLSMG_LLCORN_CHAR 0xC0
+# define SLSMG_LRCORN_CHAR 0xD9
+# define SLSMG_RTEE_CHAR 0xB4
+# define SLSMG_LTEE_CHAR 0xC3
+# define SLSMG_UTEE_CHAR 0xC2
+# define SLSMG_DTEE_CHAR 0xC1
+# define SLSMG_PLUS_CHAR 0xC5
+/* There are several to choose from: 0xB0, 0xB1, and 0xB2 */
+# define SLSMG_CKBRD_CHAR 0xB0
+#else
+# define SLSMG_HLINE_CHAR 'q'
+# define SLSMG_VLINE_CHAR 'x'
+# define SLSMG_ULCORN_CHAR 'l'
+# define SLSMG_URCORN_CHAR 'k'
+# define SLSMG_LLCORN_CHAR 'm'
+# define SLSMG_LRCORN_CHAR 'j'
+# define SLSMG_CKBRD_CHAR 'a'
+# define SLSMG_RTEE_CHAR 'u'
+# define SLSMG_LTEE_CHAR 't'
+# define SLSMG_UTEE_CHAR 'w'
+# define SLSMG_DTEE_CHAR 'v'
+# define SLSMG_PLUS_CHAR 'n'
+#endif
+
+#ifndef pc_system
+# define SLSMG_COLOR_BLACK 0x000000
+# define SLSMG_COLOR_RED 0x000001
+# define SLSMG_COLOR_GREEN 0x000002
+# define SLSMG_COLOR_BROWN 0x000003
+# define SLSMG_COLOR_BLUE 0x000004
+# define SLSMG_COLOR_MAGENTA 0x000005
+# define SLSMG_COLOR_CYAN 0x000006
+# define SLSMG_COLOR_LGRAY 0x000007
+# define SLSMG_COLOR_GRAY 0x000008
+# define SLSMG_COLOR_BRIGHT_RED 0x000009
+# define SLSMG_COLOR_BRIGHT_GREEN 0x00000A
+# define SLSMG_COLOR_BRIGHT_BROWN 0x00000B
+# define SLSMG_COLOR_BRIGHT_BLUE 0x00000C
+# define SLSMG_COLOR_BRIGHT_CYAN 0x00000D
+# define SLSMG_COLOR_BRIGHT_MAGENTA 0x00000E
+# define SLSMG_COLOR_BRIGHT_WHITE 0x00000F
+#endif
+
+/*}}}*/
+
+/*{{{ SLang Keypad Interface */
+
+#define SL_KEY_ERR 0xFFFF
+
+#define SL_KEY_UP 0x101
+#define SL_KEY_DOWN 0x102
+#define SL_KEY_LEFT 0x103
+#define SL_KEY_RIGHT 0x104
+#define SL_KEY_PPAGE 0x105
+#define SL_KEY_NPAGE 0x106
+#define SL_KEY_HOME 0x107
+#define SL_KEY_END 0x108
+#define SL_KEY_A1 0x109
+#define SL_KEY_A3 0x10A
+#define SL_KEY_B2 0x10B
+#define SL_KEY_C1 0x10C
+#define SL_KEY_C3 0x10D
+#define SL_KEY_REDO 0x10E
+#define SL_KEY_UNDO 0x10F
+#define SL_KEY_BACKSPACE 0x110
+#define SL_KEY_ENTER 0x111
+#define SL_KEY_IC 0x112
+#define SL_KEY_DELETE 0x113
+
+#define SL_KEY_F0 0x200
+#define SL_KEY_F(X) (SL_KEY_F0 + X)
+
+/* I do not intend to use keysymps > 0x1000. Applications can use those. */
+/* Returns 0 upon success or -1 upon error. */
+int SLkp_define_keysym (char *, unsigned int);
+
+/* This function must be called AFTER SLtt_get_terminfo and not before. */
+extern int SLkp_init (void);
+
+/* This function uses SLang_getkey and assumes that what ever initialization
+ * is required for SLang_getkey has been performed.
+ */
+extern int SLkp_getkey (void);
+
+/*}}}*/
+
+/*{{{ SLang Scroll Interface */
+
+typedef struct _SLscroll_Type
+{
+ struct _SLscroll_Type *next;
+ struct _SLscroll_Type *prev;
+ unsigned int flags;
+}
+SLscroll_Type;
+
+typedef struct
+{
+ unsigned int flags;
+ SLscroll_Type *top_window_line; /* list element at top of window */
+ SLscroll_Type *bot_window_line; /* list element at bottom of window */
+ SLscroll_Type *current_line; /* current list element */
+ SLscroll_Type *lines; /* first list element */
+ unsigned int nrows; /* number of rows in window */
+ unsigned int hidden_mask; /* applied to flags in SLscroll_Type */
+ unsigned int line_num; /* current line number (visible) */
+ unsigned int num_lines; /* total number of lines (visible) */
+ unsigned int window_row; /* row of current_line in window */
+ unsigned int border; /* number of rows that form scroll border */
+ int cannot_scroll; /* should window scroll or recenter */
+}
+SLscroll_Window_Type;
+
+extern int SLscroll_find_top (SLscroll_Window_Type *);
+extern int SLscroll_find_line_num (SLscroll_Window_Type *);
+extern unsigned int SLscroll_next_n (SLscroll_Window_Type *, unsigned int);
+extern unsigned int SLscroll_prev_n (SLscroll_Window_Type *, unsigned int);
+extern int SLscroll_pageup (SLscroll_Window_Type *);
+extern int SLscroll_pagedown (SLscroll_Window_Type *);
+
+/*}}}*/
+
+/*{{{ Signal Routines */
+
+typedef void SLSig_Fun_Type (int);
+extern SLSig_Fun_Type *SLsignal (int, SLSig_Fun_Type *);
+extern SLSig_Fun_Type *SLsignal_intr (int, SLSig_Fun_Type *);
+#ifndef pc_system
+extern int SLsig_block_signals (void);
+extern int SLsig_unblock_signals (void);
+#endif
+/*}}}*/
+
+/*{{{ Interpreter Macro Definitions */
+
+/* This value is a main_type just like the other main_types defined
+ * near the definition of SLang_Name_Type. Applications should avoid using
+ * this so if you do not understands its role, do not use it.
+ */
+#define SLANG_DATA 0x30 /* real objects which may be destroyed */
+
+/* Subtypes */
+
+/* The definitions here are for objects that may be on the run-time stack.
+ * They are actually sub_types of literal and data main_types.
+ */
+#define VOID_TYPE 1
+#define INT_TYPE 2
+#ifdef FLOAT_TYPE
+# undef FLOAT_TYPE
+# define FLOAT_TYPE 3
+#endif
+#define CHAR_TYPE 4
+#define INTP_TYPE 5
+/* An object of INTP_TYPE should never really occur on the stack. Rather,
+ * the integer to which it refers will be there instead. It is defined here
+ * because it is a valid type for MAKE_VARIABLE.
+ */
+
+#define SLANG_OBJ_TYPE 6
+/* SLANG_OBJ_TYPE refers to an object on the stack that is a pointer to
+ * some other object.
+ */
+
+#if 0
+/* This is not ready yet. */
+# define SLANG_NOOP 9
+#endif
+
+/* Everything above string should correspond to a pointer in the object
+ * structure. See do_binary (slang.c) for exploitation of this fact.
+ */
+#define STRING_TYPE 10
+/* Array type MUST be the smallest number for SLuser_Object_Type structs */
+#define ARRAY_TYPE 20
+/* I am reserving values greater than or equal to user applications. The
+ * first 99 are used for S-Lang.
+ */
+
+
+/* Binary and Unary Subtypes */
+/* Since the application can define new types and can overload the binary
+ * and unary operators, these definitions must be present in this file.
+ */
+#define SLANG_PLUS 1
+#define SLANG_MINUS 2
+#define SLANG_TIMES 3
+#define SLANG_DIVIDE 4
+#define SLANG_EQ 5
+#define SLANG_NE 6
+#define SLANG_GT 7
+#define SLANG_GE 8
+#define SLANG_LT 9
+#define SLANG_LE 10
+
+/* UNARY subtypes (may be overloaded) */
+#define SLANG_ABS 11
+#define SLANG_SIGN 12
+#define SLANG_SQR 13
+#define SLANG_MUL2 14
+#define SLANG_CHS 15
+
+/* error codes, severe errors are less than 0 */
+#define SL_INVALID_PARM -6
+#define SL_MALLOC_ERROR -5
+#define INTERNAL_ERROR -4
+#define UNKNOWN_ERROR -3
+#define STACK_OVERFLOW -1
+#define STACK_UNDERFLOW -2
+#define INTRINSIC_ERROR 1
+/* Intrinsic error is an error generated by intrinsic functions */
+#define USER_BREAK 2
+#define UNDEFINED_NAME 3
+#define SYNTAX_ERROR 4
+#define DUPLICATE_DEFINITION 5
+#define TYPE_MISMATCH 6
+#define READONLY_ERROR 7
+#define DIVIDE_ERROR 8
+/* object could not be opened */
+#define SL_OBJ_NOPEN 9
+/* unknown object */
+#define SL_OBJ_UNKNOWN 10
+
+extern char *SLang_Error_Message;
+
+extern void SLadd_name(char *, long, unsigned char, unsigned char);
+extern void SLadd_at_handler (long *, char *);
+
+#define SLANG_MAKE_ARGS(out, in) ((unsigned char)(out) | ((unsigned short) (in) << 4))
+
+#ifdef SLANG_STATS
+
+#define MAKE_INTRINSIC(n, f, out, in) \
+ {0, n, (out | (in << 4)), SLANG_INTRINSIC, (long) f}
+
+#define MAKE_VARIABLE(n, v, t, r) \
+ {0, n, t, (SLANG_IVARIABLE + r), (long) v}
+
+#else
+#define MAKE_INTRINSIC(n, f, out, in) \
+ {n, (out | (in << 4)), SLANG_INTRINSIC, (long) f}
+
+#define MAKE_VARIABLE(n, v, t, r) \
+ {n, t, (SLANG_IVARIABLE + r), (long) v}
+#endif
+
+#define SLANG_END_TABLE MAKE_INTRINSIC("", 0, 0, 0)
+
+
+/*}}}*/
+
+/*{{{ Upper/Lowercase Functions */
+
+extern void SLang_define_case(int *, int *);
+extern void SLang_init_case_tables (void);
+
+extern unsigned char Chg_UCase_Lut[256];
+extern unsigned char Chg_LCase_Lut[256];
+#define UPPER_CASE(x) (Chg_UCase_Lut[(unsigned char) (x)])
+#define LOWER_CASE(x) (Chg_LCase_Lut[(unsigned char) (x)])
+#define CHANGE_CASE(x) (((x) == Chg_LCase_Lut[(unsigned char) (x)]) ?\
+ Chg_UCase_Lut[(unsigned char) (x)] : Chg_LCase_Lut[(unsigned char) (x)])
+
+
+/*}}}*/
+
+/*{{{ Regular Expression Interface */
+
+typedef struct
+{
+ unsigned char *pat; /* regular expression pattern */
+ unsigned char *buf; /* buffer for compiled regexp */
+ unsigned int buf_len; /* length of buffer */
+ int case_sensitive; /* 1 if match is case sensitive */
+ int must_match; /* 1 if line must contain substring */
+ int must_match_bol; /* true if it must match beginning of line */
+ unsigned char must_match_str[16]; /* 15 char null term substring */
+ int osearch; /* 1 if ordinary search suffices */
+ unsigned int min_length; /* minimum length the match must be */
+ int beg_matches[10]; /* offset of start of \( */
+ unsigned int end_matches[10]; /* length of nth submatch
+ * Note that the entire match corresponds
+ * to \0
+ */
+ int offset; /* offset to be added to beg_matches */
+} SLRegexp_Type;
+
+extern unsigned char *SLang_regexp_match(unsigned char *,
+ unsigned int,
+ SLRegexp_Type *);
+extern int SLang_regexp_compile (SLRegexp_Type *);
+extern char *SLregexp_quote_string (char *, char *, unsigned int);
+
+
+/*}}}*/
+
+/*{{{ SLang Command Interface */
+
+#define SLCMD_MAX_ARGS 10
+struct _SLcmd_Cmd_Type; /* Pre-declaration is needed below */
+typedef struct
+{
+ struct _SLcmd_Cmd_Type *table;
+ int argc;
+ char *string_args[SLCMD_MAX_ARGS];
+ int int_args[SLCMD_MAX_ARGS];
+ float64 float_args[SLCMD_MAX_ARGS];
+ unsigned char arg_type[SLCMD_MAX_ARGS];
+} SLcmd_Cmd_Table_Type;
+
+
+typedef struct _SLcmd_Cmd_Type
+{
+ int (*cmdfun)(int, SLcmd_Cmd_Table_Type *);
+ char cmd[32];
+ char arg_type[SLCMD_MAX_ARGS];
+} SLcmd_Cmd_Type;
+
+extern int SLcmd_execute_string (char *, SLcmd_Cmd_Table_Type *);
+
+/*}}}*/
+
+/*{{{ SLang Search Interface */
+
+typedef struct
+{
+ int cs; /* case sensitive */
+ unsigned char key[256];
+ int ind[256];
+ int key_len;
+ int dir;
+} SLsearch_Type;
+
+extern int SLsearch_init (char *, int, int, SLsearch_Type *);
+/* This routine must first be called before any search can take place.
+ * The second parameter specifies the direction of the search: greater than
+ * zero for a forwrd search and less than zero for a backward search. The
+ * third parameter specifies whether the search is case sensitive or not.
+ * The last parameter is a pointer to a structure that is filled by this
+ * function and it is this structure that must be passed to SLsearch.
+ */
+
+unsigned char *SLsearch (unsigned char *, unsigned char *, SLsearch_Type *);
+/* To use this routine, you must first call 'SLsearch_init'. Then the first
+ * two parameters p1 and p2 serve to define the region over which the search
+ * is to take place. The third parameter is the structure that was previously
+ * initialized by SLsearch_init.
+ *
+ * The routine returns a pointer to the match if found otherwise it returns
+ * NULL.
+ */
+
+/*}}}*/
+
+#if 0
+{
+#endif
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _DAVIS_SLANG_H_ */
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+/*
+ * SLTT_TRANSP_ACS_PATCH (#define/#undef):
+ *
+ * The problem: some terminals (e.g. QNX/qansi*) map the whole upper half of
+ * the ASCII table to the lower half, when alt-char-set is activated with
+ * the smacs/as string-sequence. This means, that if 0 <= ch < 128 written
+ * to the terminal, it will be translated to (ch+128) automatically by the
+ * terminal: so not only the line-drawing characters can be written, when
+ * the alt-char-set is activated. It implicitly means, that space, NL, CR,
+ * etc. characters (exactly: anything besides the "standard" line drawing
+ * characters) can not be written directly to the terminal, when the
+ * alt-char-set is activated, because writing these characters doesn't cause
+ * an implicit/temporary switching-back to the standard char-set!
+ *
+ * The original code in SLang assumes that space, NL, CR, etc. can be
+ * printed when alt-char-set is activated. If SLTT_TRANSP_ACS_PATCH is
+ * defined, the modified code will not use this assumption.
+ * [Remark: the patch-code is not the most exact solution, but works...]
+ */
+/*#define SLTT_TRANSP_ACS_PATCH 1*/
+
+/*
+ * QNX_QANSI_SLANG_COMPAT_ACS (#define/#undef):
+ *
+ * A more OS/terminal-specific solution for the problem mentioned above
+ * (->SLTT_TRANSP_ACS_PATCH).
+ *
+ * If QNX_QANSI_SLANG_COMPAT_ACS is defined, the default smacs/sa, rmacs/ae,
+ * acsc/ac [and sgr/sa, if it would be used!] command sequences will be
+ * replaced internally with the "old style" (pre-QNX 4.23) sequences in case
+ * of QNX/qansi terminals. Using these optional command sequences the terminal
+ * remains compatible with the original SLang code (without using the
+ * workaround-code enabled by defining SLTT_TRANSP_ACS_PATCH).
+ */
+/*#define QNX_QANSI_SLANG_COMPAT_ACS 1*/
+
+/* auto-configuration */
+#ifdef SLTT_TRANSP_ACS_PATCH
+# if defined(__QNX__) && defined(QNX_QANSI_SLANG_COMPAT_ACS)
+# undef SLTT_TRANSP_ACS_PATCH
+# endif
+#else
+# if defined(__QNX__) && !defined(QNX_QANSI_SLANG_COMPAT_ACS)
+# define QNX_QANSI_SLANG_COMPAT_ACS 1
+# endif
+#endif
+
+#include "sl-feat.h"
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#ifdef SCO_FLAVOR
+# include <sys/types.h>
+# include <sys/timeb.h> /* for struct timeb, used in time.h */
+#endif
+#include <time.h>
+#include <ctype.h>
+
+#ifndef VMS
+# include <sys/time.h>
+# ifdef __QNX__
+# include <sys/select.h>
+# endif
+# include <sys/types.h>
+#endif
+
+#ifdef __BEOS__
+/* Prototype for select */
+# include <net/socket.h>
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# include <termios.h>
+#endif
+
+#ifdef VMS
+# include <unixlib.h>
+# include <unixio.h>
+# include <dvidef.h>
+# include <descrip.h>
+# include <lib$routines.h>
+# include <starlet.h>
+#else
+# if !defined(sun)
+# include <sys/ioctl.h>
+# endif
+#endif
+
+
+#ifdef SYSV
+# include <sys/termio.h>
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# include <sys/tty.h>
+#endif
+
+#if defined (_AIX) && !defined (FD_SET)
+# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
+#endif
+
+#include <errno.h>
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#if defined(__DECC) && defined(VMS)
+/* These get prototypes for write an sleep */
+# include <unixio.h>
+#endif
+#include <signal.h>
+
+
+/* Colors: These definitions are used for the display. However, the
+ * application only uses object handles which get mapped to this
+ * internal representation. The mapping is performed by the Color_Map
+ * structure below. */
+
+#define CHAR_MASK 0x000000FF
+#define FG_MASK 0x0000FF00
+#define BG_MASK 0x00FF0000
+#define ATTR_MASK 0x1F000000
+#define BGALL_MASK 0x0FFF0000
+
+/* The 0x10000000 bit represents the alternate character set. BGALL_MASK does
+ * not include this attribute.
+ */
+
+
+
+#define GET_FG(color) ((color & FG_MASK) >> 8)
+#define GET_BG(color) ((color & BG_MASK) >> 16)
+#define MAKE_COLOR(fg, bg) (((fg) | ((bg) << 8)) << 8)
+
+int SLtt_Screen_Cols;
+int SLtt_Screen_Rows;
+int SLtt_Term_Cannot_Insert;
+int SLtt_Term_Cannot_Scroll;
+int SLtt_Use_Ansi_Colors;
+int SLtt_Blink_Mode = 1;
+int SLtt_Use_Blink_For_ACS = 0;
+int SLtt_Newline_Ok = 0;
+int SLtt_Has_Alt_Charset = 0;
+int SLtt_Force_Keypad_Init = 0;
+
+/* -1 means unknown */
+int SLtt_Has_Status_Line = -1; /* hs */
+
+static int Automatic_Margins;
+/* static int No_Move_In_Standout; */
+static int Worthless_Highlight;
+#define HP_GLITCH_CODE
+#ifdef HP_GLITCH_CODE
+/* This glitch is exclusive to HP term. Basically it means that to clear
+ * attributes, one has to erase to the end of the line.
+ */
+static int Has_HP_Glitch;
+#endif
+
+static char *Reset_Color_String;
+
+static int Linux_Console;
+
+/* It is crucial that JMAX_COLORS must be less than 128 since the high bit
+ * is used to indicate a character from the ACS (alt char set). The exception
+ * to this rule is if SLtt_Use_Blink_For_ACS is true. This means that of
+ * the highbit is set, we interpret that as a blink character. This is
+ * exploited by DOSemu.
+ */
+#define JMAX_COLORS 256
+#define JNORMAL_COLOR 0
+
+typedef struct
+{
+ SLtt_Char_Type fgbg;
+ SLtt_Char_Type mono;
+ char *custom_esc;
+} Ansi_Color_Type;
+
+#define RGB1(r, g, b) ((r) | ((g) << 1) | ((b) << 2))
+#define RGB(r, g, b, br, bg, bb) ((RGB1(r, g, b) << 8) | (RGB1(br, bg, bb) << 16))
+
+static Ansi_Color_Type Ansi_Color_Map[JMAX_COLORS] =
+{
+ {RGB(1, 1, 1, 0, 0, 0), 0x00000000, NULL}, /* white/black */
+ {RGB(0, 1, 0, 0, 0, 0), SLTT_REV_MASK, NULL}, /* green/black */
+ {RGB(1, 0, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* magenta/black */
+ {RGB(0, 1, 1, 0, 0, 0), SLTT_REV_MASK, NULL}, /* cyan/black */
+ {RGB(1, 0, 0, 0, 0, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 0, 0, 0, 0, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 0, 0, 0, 1, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 0, 1, 1, 0, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 0, 0), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(1, 0, 1, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 0, 0, 0, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL},
+ {RGB(0, 1, 0, 1, 1, 1), SLTT_REV_MASK, NULL}
+};
+
+
+/* This is the string to use to use when outputting color information.
+ */
+#ifdef M_UNIX
+/* work around for sco console bug that can't handle combined sequences */
+ static char *Color_Escape_Sequence = "\033[3%dm\033[4%dm";
+#else
+/* Believe it or not, this is what is in the linux terminfo database. It
+ * produces the same escape sequence but it is much more CPU intensive.
+ * Why not just encode it as "\033[3%p1%dm\033[4%p2%dm" ???
+ */
+ /* static char *Color_Escape_Sequence = "\033[%p1%{30}%+%dm\033[%p2%{40}%+%dm"; */
+static char *Color_Escape_Sequence = "\033[3%d;4%dm";
+#endif
+
+char *SLtt_Graphics_Char_Pairs; /* ac termcap string -- def is vt100 */
+
+
+/* 1 if terminal lacks the ability to do into insert mode or into delete
+ mode. Currently controlled by S-Lang but later perhaps termcap. */
+
+static char *UnderLine_Vid_Str;
+static char *Blink_Vid_Str;
+static char *Bold_Vid_Str;
+static char *Ins_Mode_Str; /* = "\033[4h"; */ /* ins mode (im) */
+static char *Eins_Mode_Str; /* = "\033[4l"; */ /* end ins mode (ei) */
+static char *Scroll_R_Str; /* = "\033[%d;%dr"; */ /* scroll region */
+static char *Cls_Str; /* = "\033[2J\033[H"; */ /* cl termcap STR for ansi terminals */
+static char *Rev_Vid_Str; /* = "\033[7m"; */ /* mr,so termcap string */
+static char *Norm_Vid_Str; /* = "\033[m"; */ /* me,se termcap string */
+static char *Del_Eol_Str; /* = "\033[K"; */ /* ce */
+static char *Del_Char_Str; /* = "\033[P"; */ /* dc */
+static char *Del_N_Lines_Str; /* = "\033[%dM"; */ /* DL */
+static char *Add_N_Lines_Str; /* = "\033[%dL"; */ /* AL */
+static char *Rev_Scroll_Str;
+static char *Curs_Up_Str;
+static char *Curs_F_Str; /* RI termcap string */
+static char *Cursor_Visible_Str; /* ve termcap string */
+static char *Cursor_Invisible_Str; /* vi termcap string */
+
+static char *Start_Alt_Chars_Str; /* as */
+static char *End_Alt_Chars_Str; /* ae */
+static char *Enable_Alt_Char_Set; /* eA */
+
+static char *Term_Init_Str;
+static char *Keypad_Init_Str;
+static char *Term_Reset_Str;
+static char *Keypad_Reset_Str;
+
+/* status line functions */
+static char *Disable_Status_line_Str; /* ds */
+static char *Return_From_Status_Line_Str; /* fs */
+static char *Goto_Status_Line_Str; /* ts */
+static int Num_Status_Line_Columns; /* ws */
+static int Status_Line_Esc_Ok; /* es */
+
+/* static int Len_Curs_F_Str = 5; */
+
+/* cm string has %i%d since termcap numbers columns from 0 */
+/* char *CURS_POS_STR = "\033[%d;%df"; ansi-- hor and vert pos */
+static char *Curs_Pos_Str; /* = "\033[%i%d;%dH";*/ /* cm termcap string */
+
+
+/* scrolling region */
+static int Scroll_r1 = 0, Scroll_r2 = 23;
+static int Cursor_r, Cursor_c; /* 0 based */
+
+/* current attributes --- initialized to impossible value */
+static SLtt_Char_Type Current_Fgbg = 0xFFFFFFFFU;
+
+static int Cursor_Set; /* 1 if cursor position known, 0
+ * if not. -1 if only row is known
+ */
+
+
+#define MAX_OUTPUT_BUFFER_SIZE 4096
+
+static unsigned char Output_Buffer[MAX_OUTPUT_BUFFER_SIZE];
+static unsigned char *Output_Bufferp = Output_Buffer;
+
+unsigned long SLtt_Num_Chars_Output;
+
+#ifdef SLTT_TRANSP_ACS_PATCH
+static int SLtt_ACS_Active = 0;
+#endif
+
+static int sl_usleep (unsigned long usecs)
+{
+#ifndef VMS
+ struct timeval tv;
+ tv.tv_sec = usecs / 1000000;
+ tv.tv_usec = usecs % 1000000;
+ return select(0, NULL, NULL, NULL, &tv);
+#else
+ return 0;
+#endif
+}
+
+int SLtt_flush_output (void)
+{
+ int nwrite = 0;
+ unsigned int total;
+ int n = (int) (Output_Bufferp - Output_Buffer);
+
+ SLtt_Num_Chars_Output += n;
+
+ total = 0;
+ while (n > 0)
+ {
+ nwrite = write (fileno(stdout), (char *) Output_Buffer + total, n);
+ if (nwrite == -1)
+ {
+ nwrite = 0;
+#ifdef EAGAIN
+ if (errno == EAGAIN)
+ {
+ sl_usleep (100000); /* 1/10 sec */
+ continue;
+ }
+#endif
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK)
+ {
+ sl_usleep (100000);
+ continue;
+ }
+#endif
+#ifdef EINTR
+ if (errno == EINTR) continue;
+#endif
+ break;
+ }
+ n -= nwrite;
+ total += nwrite;
+ }
+ Output_Bufferp = Output_Buffer;
+ return n;
+}
+
+
+int SLtt_Baud_Rate;
+static void tt_write(char *str, unsigned int n)
+{
+ static unsigned long last_time;
+ static int total;
+ unsigned long now;
+ unsigned int ndiff;
+
+ if ((str == NULL) || (n == 0)) return;
+ total += n;
+
+ while (1)
+ {
+ ndiff = MAX_OUTPUT_BUFFER_SIZE - (int) (Output_Bufferp - Output_Buffer);
+ if (ndiff < n)
+ {
+ SLMEMCPY ((char *) Output_Bufferp, (char *) str, ndiff);
+ Output_Bufferp += ndiff;
+ SLtt_flush_output ();
+ n -= ndiff;
+ str += ndiff;
+ }
+ else
+ {
+ SLMEMCPY ((char *) Output_Bufferp, str, n);
+ Output_Bufferp += n;
+ break;
+ }
+ }
+
+ if (((SLtt_Baud_Rate > 150) && (SLtt_Baud_Rate <= 9600))
+ && (10 * total > SLtt_Baud_Rate))
+ {
+ total = 0;
+ if ((now = (unsigned long) time(NULL)) - last_time <= 1)
+ {
+ SLtt_flush_output ();
+ sleep((unsigned) 1);
+ }
+ last_time = now;
+ }
+}
+
+
+void SLtt_write_string (char *str)
+{
+ if (str != NULL) tt_write(str, strlen(str));
+}
+
+
+void SLtt_putchar (char ch)
+{
+#ifdef SLTT_TRANSP_ACS_PATCH
+ int restore_acs = 0;
+#endif
+
+ SLtt_normal_video ();
+ if (Cursor_Set == 1)
+ {
+ if (ch >= ' ') Cursor_c++;
+#ifndef SLTT_TRANSP_ACS_PATCH
+ else if (ch == '\b') Cursor_c--;
+#else
+ if (ch <= ' ' && SLtt_ACS_Active)
+ {
+ SLtt_set_alt_char_set (0);
+ restore_acs = 1;
+ }
+ if (ch == '\b') Cursor_c--;
+#endif
+ else if (ch == '\r') Cursor_c = 0;
+ else Cursor_Set = 0;
+
+ if ((Cursor_c + 1 == SLtt_Screen_Cols)
+ && Automatic_Margins) Cursor_Set = 0;
+ }
+
+ if (Output_Bufferp < Output_Buffer + MAX_OUTPUT_BUFFER_SIZE)
+ {
+ *Output_Bufferp++ = (unsigned char) ch;
+ }
+ else tt_write (&ch, 1);
+
+#ifdef SLTT_TRANSP_ACS_PATCH
+ if (restore_acs)
+ {
+ SLtt_set_alt_char_set (1);
+ }
+#endif
+}
+
+/* this is supposed to be fast--- also handles
+ termcap: %d, &i, %., %+, %r strings as well as terminfo stuff */
+static unsigned int tt_sprintf(char *buf, char *fmt, int x, int y)
+{
+ register unsigned char *f = (unsigned char *) fmt, *b, ch;
+ int offset = 0, tinfo = 0;
+ int stack[10];
+ int i = 0, z;
+ stack[0] = y; stack[1] = x; i = 2;
+
+ b = (unsigned char *) buf;
+ if (fmt != NULL) while ((ch = *f++) != 0)
+ {
+ if (ch != '%') *b++ = ch;
+ else
+ {
+ ch = *f++;
+ if (tinfo)
+ {
+ if ((ch <= '3') && (ch >= '0'))
+ {
+ /* map it to termcap. Since this is terminfo,
+ * it must be one of:
+ * %2d, %3d, %02d, %03d
+ *
+ * I am assuming that a terminal that understands
+ * %2d form will also understand the %02d form. These
+ * only differ by a space padding the field.
+ */
+
+ /* skip the 'd'-- hope it is there */
+ if (ch == '0')
+ {
+ ch = *f;
+ f += 2;
+ }
+ else f++;
+ }
+ }
+
+ switch (ch)
+ {
+ case 'p':
+ tinfo = 1;
+ ch = *f++;
+ if (ch == '1') stack[i++] = x; else stack[i++] = y;
+ break;
+
+ case '\'': /* 'x' */
+ stack[i++] = *f++;
+ f++;
+ break;
+
+ case '{': /* literal constant, e.g. {30} */
+ z = 0;
+ while (((ch = *f) <= '9') && (ch >= '0'))
+ {
+ z = z * 10 + (ch - '0');
+ f++;
+ }
+ stack[i++] = z;
+ if (ch == '}') f++;
+ break;
+
+ case 'd':
+ case '2':
+ case '3':
+ z = stack[--i];
+ z += offset;
+ if (z >= 100)
+ {
+ *b++ = z / 100 + '0';
+ z = z % 100;
+ goto ten;
+ }
+ else if (ch == 3)
+ {
+ *b++ = '0';
+ ch = '2';
+ }
+
+ if (z >= 10)
+ {
+ ten:
+ *b++ = z / 10 + '0';
+ z = z % 10;
+ }
+ else if (ch == 2) *b++ = '0';
+
+ *b++ = z + '0';
+ break;
+
+ case 'i':
+ offset = 1;
+ break;
+
+ case '+':
+ if (tinfo)
+ {
+ z = stack[--i];
+ stack[i-1] += z;
+ }
+ else
+ {
+ ch = *f++;
+ if ((unsigned char) ch == 128) ch = 0;
+ ch = ch + (unsigned char) stack[--i];
+ if (ch == '\n') ch++;
+ *b++ = ch;
+ }
+ break;
+
+ case 'r':
+ stack[0] = x;
+ stack[1] = y;
+ break;
+
+ case '.':
+ case 'c':
+ ch = (unsigned char) stack[--i];
+ if (ch == '\n') ch++;
+ *b++ = ch;
+ break;
+
+ default:
+ *b++ = ch;
+ }
+ }
+ }
+ *b = 0;
+ return((unsigned int) (b - (unsigned char *) buf));
+}
+
+static void tt_printf(char *fmt, int x, int y)
+{
+ char buf[256];
+ unsigned int n;
+ if (fmt == NULL) return;
+ n = tt_sprintf(buf, fmt, x, y);
+ tt_write(buf, n);
+}
+
+
+void SLtt_set_scroll_region (int r1, int r2)
+{
+ Scroll_r1 = r1;
+ Scroll_r2 = r2;
+ tt_printf (Scroll_R_Str, Scroll_r1, Scroll_r2);
+ Cursor_Set = 0;
+}
+
+void SLtt_reset_scroll_region (void)
+{
+ SLtt_set_scroll_region(0, SLtt_Screen_Rows - 1);
+}
+
+int SLtt_set_cursor_visibility (int show)
+{
+ if ((Cursor_Visible_Str == NULL) || (Cursor_Invisible_Str == NULL))
+ return -1;
+
+ SLtt_write_string (show ? Cursor_Visible_Str : Cursor_Invisible_Str);
+ return 0;
+}
+
+
+/* the goto_rc function moves to row relative to scrolling region */
+void SLtt_goto_rc(int r, int c)
+{
+ char *s = NULL;
+ int n;
+ char buf[6];
+#ifdef SLTT_TRANSP_ACS_PATCH
+ int check_alt_acs = 0;
+#endif
+
+ if (c < 0)
+ {
+ c = -c - 1;
+ Cursor_Set = 0;
+ }
+
+ /* if (No_Move_In_Standout && Current_Fgbg) SLtt_normal_video (); */
+ r += Scroll_r1;
+
+ if ((Cursor_Set > 0) || ((Cursor_Set < 0) && !Automatic_Margins))
+ {
+ n = r - Cursor_r;
+ if ((n == -1) && (Cursor_Set > 0) && (Cursor_c == c)
+ && (Curs_Up_Str != NULL))
+ {
+ s = Curs_Up_Str;
+ }
+ else if ((n >= 0) && (n <= 4))
+ {
+ if ((n == 0) && (Cursor_Set == 1)
+ && ((c > 1) || (c == Cursor_c)))
+ {
+ if (Cursor_c == c) return;
+ if (Cursor_c == c + 1)
+ {
+ s = buf;
+ *s++ = '\b'; *s = 0;
+ s = buf;
+#ifdef SLTT_TRANSP_ACS_PATCH
+ check_alt_acs = 1;
+#endif
+ }
+ }
+ else if (c == 0)
+ {
+ s = buf;
+ if ((Cursor_Set != 1) || (Cursor_c != 0)) *s++ = '\r';
+ while (n--) *s++ = '\n';
+#ifdef VMS
+ /* Need to add this after \n to start a new record. Sheesh. */
+ *s++ = '\r';
+#endif
+ *s = 0;
+ s = buf;
+#ifdef SLTT_TRANSP_ACS_PATCH
+ check_alt_acs = 1;
+#endif
+ }
+ /* Will fail on VMS */
+#ifndef VMS
+ else if (SLtt_Newline_Ok && (Cursor_Set == 1) &&
+ (Cursor_c >= c) && (c + 3 > Cursor_c))
+ {
+ s = buf;
+ while (n--) *s++ = '\n';
+ n = Cursor_c - c;
+ while (n--) *s++ = '\b';
+ *s = 0;
+ s = buf;
+#ifdef SLTT_TRANSP_ACS_PATCH
+ check_alt_acs = 1;
+#endif
+ }
+#endif
+ }
+ }
+#ifndef SLTT_TRANSP_ACS_PATCH
+ if (s != NULL) SLtt_write_string(s);
+#else
+ if (s != NULL)
+ {
+ if (check_alt_acs && SLtt_ACS_Active)
+ {
+ SLtt_set_alt_char_set (0);
+ SLtt_write_string(s);
+ SLtt_set_alt_char_set (1);
+ }
+ else SLtt_write_string(s);
+ }
+#endif
+ else tt_printf(Curs_Pos_Str, r, c);
+ Cursor_c = c; Cursor_r = r;
+ Cursor_Set = 1;
+}
+
+void SLtt_begin_insert (void)
+{
+ SLtt_write_string(Ins_Mode_Str);
+}
+
+void SLtt_end_insert (void)
+{
+ SLtt_write_string(Eins_Mode_Str);
+}
+
+void SLtt_delete_char (void)
+{
+ SLtt_normal_video ();
+ SLtt_write_string(Del_Char_Str);
+}
+
+void SLtt_erase_line (void)
+{
+ SLtt_write_string("\r");
+ Cursor_Set = 1; Cursor_c = 0;
+ SLtt_del_eol();
+}
+
+void SLtt_delete_nlines (int n)
+{
+ int r1, curs;
+ char buf[132];
+#ifdef SLTT_TRANSP_ACS_PATCH
+ int restore_acs = 0;
+#endif
+
+ if (n <= 0) return;
+ SLtt_normal_video ();
+ if (Del_N_Lines_Str != NULL) tt_printf(Del_N_Lines_Str,n, 0);
+ else
+ /* get a new terminal */
+ {
+ r1 = Scroll_r1;
+ curs = Cursor_r;
+ SLtt_set_scroll_region(curs, Scroll_r2);
+ SLtt_goto_rc(Scroll_r2 - Scroll_r1, 0);
+#ifdef SLTT_TRANSP_ACS_PATCH
+ if (SLtt_ACS_Active)
+ {
+ SLtt_set_alt_char_set (0);
+ restore_acs = 1;
+ }
+#endif
+ SLMEMSET(buf, '\n', (unsigned int) n);
+ tt_write(buf, (unsigned int) n);
+#ifdef SLTT_TRANSP_ACS_PATCH
+ if (restore_acs) SLtt_set_alt_char_set (1);
+#endif
+ /* while (n--) tt_putchar('\n'); */
+ SLtt_set_scroll_region(r1, Scroll_r2);
+ SLtt_goto_rc(curs, 0);
+ }
+}
+
+void SLtt_cls (void)
+{
+ SLtt_normal_video();
+ SLtt_reset_scroll_region ();
+ SLtt_write_string(Cls_Str);
+}
+
+void SLtt_reverse_index (int n)
+{
+ if (!n) return;
+
+ SLtt_normal_video();
+ if (Add_N_Lines_Str != NULL) tt_printf(Add_N_Lines_Str,n, 0);
+ else
+ {
+ while(n--) SLtt_write_string(Rev_Scroll_Str);
+ }
+}
+
+
+int SLtt_Ignore_Beep = 1;
+static char *Visible_Bell_Str;
+
+void SLtt_beep (void)
+{
+ if (SLtt_Ignore_Beep & 0x1) SLtt_putchar('\007');
+
+ if (SLtt_Ignore_Beep & 0x2)
+ {
+ if (Visible_Bell_Str != NULL) SLtt_write_string (Visible_Bell_Str);
+#ifdef __linux__
+ else if (Linux_Console)
+ {
+ SLtt_write_string ("\033[?5h");
+ SLtt_flush_output ();
+ sl_usleep (50000);
+ SLtt_write_string ("\033[?5l");
+ }
+#endif
+ }
+ SLtt_flush_output ();
+}
+
+void SLtt_del_eol (void)
+{
+ if (Current_Fgbg != 0xFFFFFFFFU) SLtt_normal_video ();
+ SLtt_write_string(Del_Eol_Str);
+}
+
+typedef struct
+{
+ char *name;
+ SLtt_Char_Type color;
+}
+Color_Def_Type;
+
+#define MAX_COLOR_NAMES 17
+static Color_Def_Type Color_Defs [MAX_COLOR_NAMES] =
+{
+ {"black", SLSMG_COLOR_BLACK},
+ {"red", SLSMG_COLOR_RED},
+ {"green", SLSMG_COLOR_GREEN},
+ {"brown", SLSMG_COLOR_BROWN},
+ {"blue", SLSMG_COLOR_BLUE},
+ {"magenta", SLSMG_COLOR_MAGENTA},
+ {"cyan", SLSMG_COLOR_CYAN},
+ {"lightgray", SLSMG_COLOR_LGRAY},
+ {"gray", SLSMG_COLOR_GRAY},
+ {"brightred", SLSMG_COLOR_BRIGHT_RED},
+ {"brightgreen", SLSMG_COLOR_BRIGHT_GREEN},
+ {"yellow", SLSMG_COLOR_BRIGHT_BROWN},
+ {"brightblue", SLSMG_COLOR_BRIGHT_BLUE},
+ {"brightmagenta", SLSMG_COLOR_BRIGHT_CYAN},
+ {"brightcyan", SLSMG_COLOR_BRIGHT_MAGENTA},
+ {"white", SLSMG_COLOR_BRIGHT_WHITE},
+ {"default", 25}
+};
+
+
+void SLtt_set_mono (int obj, char *what, SLtt_Char_Type mask)
+{
+ (void) what;
+ if ((obj < 0) || (obj >= JMAX_COLORS))
+ {
+ return;
+ }
+ Ansi_Color_Map[obj].mono = mask & ATTR_MASK;
+}
+
+static char *check_color_for_digit_form (char *color)
+{
+ unsigned int i, ich;
+ char *s = color;
+
+ i = 0;
+ while ((ich = (int) *s) != 0)
+ {
+ if ((ich < '0') || (ich > '9'))
+ return color;
+
+ i = i * 10 + (ich - '0');
+ s++;
+ }
+
+ if (i < MAX_COLOR_NAMES)
+ color = Color_Defs[i].name;
+
+ return color;
+}
+
+static int get_default_colors (char **fgp, char **bgp)
+{
+ static char fg_buf[16], bg_buf[16], *bg, *fg;
+ static int already_parsed;
+ char *p, *pmax;
+
+ if (already_parsed == -1)
+ return -1;
+
+ if (already_parsed)
+ {
+ *fgp = fg;
+ *bgp = bg;
+ return 0;
+ }
+
+ already_parsed = -1;
+
+ bg = getenv ("COLORFGBG");
+
+ if (bg == NULL)
+ {
+ bg = getenv ("DEFAULT_COLORS");
+ if (bg == NULL)
+ return -1;
+ }
+
+ p = fg_buf;
+ pmax = p + (sizeof (fg_buf) - 1);
+
+ while ((*bg != 0) && (*bg != ';'))
+ {
+ if (p < pmax) *p++ = *bg;
+ bg++;
+ }
+ *p = 0;
+
+ if (*bg) bg++;
+
+ p = bg_buf;
+ pmax = p + (sizeof (bg_buf) - 1);
+
+ /* Mark suggested allowing for extra spplication specific stuff following
+ * the background color. That is what the check for the semi-colon is for.
+ */
+ while ((*bg != 0) && (*bg != ';'))
+ {
+ if (p < pmax) *p++ = *bg;
+ bg++;
+ }
+ *p = 0;
+
+ if (!strcmp (fg_buf, "default") || !strcmp(bg_buf, "default"))
+ {
+ *fgp = *bgp = fg = bg = "default";
+ }
+ else
+ {
+ *fgp = fg = check_color_for_digit_form (fg_buf);
+ *bgp = bg = check_color_for_digit_form (bg_buf);
+ }
+ already_parsed = 1;
+ return 0;
+}
+
+
+static unsigned char FgBg_Stats[JMAX_COLORS];
+
+static int Color_0_Modified = 0;
+
+void SLtt_set_color_object (int obj, SLtt_Char_Type attr)
+{
+ char *cust_esc;
+
+ if ((obj < 0) || (obj >= JMAX_COLORS)) return;
+
+ cust_esc = Ansi_Color_Map[obj].custom_esc;
+ if (cust_esc != NULL)
+ {
+ SLFREE (cust_esc);
+ FgBg_Stats[(Ansi_Color_Map[obj].fgbg >> 8) & 0x7F] -= 1;
+ Ansi_Color_Map[obj].custom_esc = NULL;
+ }
+
+ Ansi_Color_Map[obj].fgbg = attr;
+ if (obj == 0) Color_0_Modified = 1;
+}
+
+SLtt_Char_Type SLtt_get_color_object (int obj)
+{
+ if ((obj < 0) || (obj >= JMAX_COLORS)) return 0;
+ return Ansi_Color_Map[obj].fgbg;
+}
+
+
+void SLtt_add_color_attribute (int obj, SLtt_Char_Type attr)
+{
+ if ((obj < 0) || (obj >= JMAX_COLORS)) return;
+
+ Ansi_Color_Map[obj].fgbg |= (attr & ATTR_MASK);
+ if (obj == 0) Color_0_Modified = 1;
+}
+
+static SLtt_Char_Type fb_to_fgbg (SLtt_Char_Type f, SLtt_Char_Type b)
+{
+ SLtt_Char_Type attr = 0;
+
+ if ((f & 0xF0) == 0)
+ {
+ if (f & 0x8) attr = SLTT_BOLD_MASK;
+ f &= 0x7;
+ }
+ else f = 9;
+
+ if ((b & 0xF0) == 0)
+ {
+ if (b & 0x8) attr |= SLTT_BLINK_MASK;
+ b &= 0x7;
+ }
+ else b = 9;
+
+ return ((f << 8) | (b << 16) | attr);
+}
+
+static int make_color_fgbg (char *fg, char *bg, SLtt_Char_Type *fgbg)
+{
+ SLtt_Char_Type f = 0xFFFFFFFFU, b = 0xFFFFFFFFU;
+ char *dfg, *dbg;
+ unsigned int i;
+
+ if ((fg != NULL) && (*fg == 0)) fg = NULL;
+ if ((bg != NULL) && (*bg == 0)) bg = NULL;
+
+ if ((fg == NULL) || (bg == NULL))
+ {
+ if (-1 == get_default_colors (&dfg, &dbg))
+ return -1;
+
+ if (fg == NULL) fg = dfg;
+ if (bg == NULL) bg = dbg;
+ }
+
+ for (i = 0; i < MAX_COLOR_NAMES; i++)
+ {
+ if (strcmp(fg, Color_Defs[i].name)) continue;
+ f = Color_Defs[i].color;
+ break;
+ }
+
+ for (i = 0; i < MAX_COLOR_NAMES; i++)
+ {
+ if (strcmp(bg, Color_Defs[i].name)) continue;
+ b = Color_Defs[i].color;
+ break;
+ }
+
+ if ((f == 0xFFFFFFFFU) || (b == 0xFFFFFFFFU))
+ return -1;
+
+ *fgbg = fb_to_fgbg (f, b);
+ return 0;
+}
+
+void SLtt_set_color (int obj, char *what, char *fg, char *bg)
+{
+ SLtt_Char_Type fgbg;
+
+ (void) what;
+ if ((obj < 0) || (obj >= JMAX_COLORS))
+ return;
+
+ if (-1 != make_color_fgbg (fg, bg, &fgbg))
+ SLtt_set_color_object (obj, fgbg);
+}
+
+void SLtt_set_color_fgbg (int obj, SLtt_Char_Type f, SLtt_Char_Type b)
+{
+ SLtt_set_color_object (obj, fb_to_fgbg (f, b));
+}
+
+void SLtt_set_color_esc (int obj, char *esc)
+{
+ char *cust_esc;
+ SLtt_Char_Type fgbg = 0;
+ int i;
+
+ if ((obj < 0) || (obj >= JMAX_COLORS))
+ {
+ return;
+ }
+
+ cust_esc = Ansi_Color_Map[obj].custom_esc;
+ if (cust_esc != NULL)
+ {
+ SLFREE (cust_esc);
+ FgBg_Stats[(Ansi_Color_Map[obj].fgbg >> 8) & 0x7F] -= 1;
+ }
+
+ cust_esc = (char *) SLMALLOC (strlen(esc) + 1);
+ if (cust_esc != NULL) strcpy (cust_esc, esc);
+
+ Ansi_Color_Map[obj].custom_esc = cust_esc;
+ if (cust_esc == NULL) fgbg = 0;
+ else
+ {
+ /* The whole point of this is to generate a unique fgbg */
+ for (i = 0; i < JMAX_COLORS; i++)
+ {
+ if (FgBg_Stats[i] == 0) fgbg = i;
+
+ if (obj == i) continue;
+ if ((Ansi_Color_Map[i].custom_esc) == NULL) continue;
+ if (!strcmp (Ansi_Color_Map[i].custom_esc, cust_esc))
+ {
+ fgbg = (Ansi_Color_Map[i].fgbg >> 8) & 0x7F;
+ break;
+ }
+ }
+ FgBg_Stats[fgbg] += 1;
+ }
+
+ fgbg |= 0x80;
+ Ansi_Color_Map[obj].fgbg = (fgbg | (fgbg << 8)) << 8;
+ if (obj == 0) Color_0_Modified = 1;
+}
+
+void SLtt_set_alt_char_set (int i)
+{
+#ifndef SLTT_TRANSP_ACS_PATCH
+ static int last_i;
+#else
+#define last_i SLtt_ACS_Active
+#endif
+ if (SLtt_Has_Alt_Charset == 0) return;
+ if (i == last_i) return;
+ SLtt_write_string (i ? Start_Alt_Chars_Str : End_Alt_Chars_Str );
+ /* if (i) Current_Fgbg |= SLTT_ALTC_MASK;
+ else Current_Fgbg &= ~SLTT_ALTC_MASK; */
+ last_i = i;
+#ifdef SLTT_TRANSP_ACS_PATCH
+#undef last_i
+#endif
+}
+
+static void write_attributes (SLtt_Char_Type fgbg)
+{
+ int bg0, fg0;
+
+ if (Worthless_Highlight) return;
+ if (fgbg == Current_Fgbg) return;
+
+ /* Before spitting out colors, fix attributes */
+ if ((fgbg & ATTR_MASK) != (Current_Fgbg & ATTR_MASK))
+ {
+ if (Current_Fgbg & ATTR_MASK)
+ {
+ SLtt_write_string(Norm_Vid_Str);
+ /* In case normal video turns off ALL attributes: */
+ if (fgbg & SLTT_ALTC_MASK)
+ Current_Fgbg &= ~SLTT_ALTC_MASK;
+ SLtt_set_alt_char_set (0);
+ }
+
+ if ((fgbg & SLTT_ALTC_MASK)
+ != (Current_Fgbg & SLTT_ALTC_MASK))
+ {
+ SLtt_set_alt_char_set ((int) (fgbg & SLTT_ALTC_MASK));
+ }
+
+ if (fgbg & SLTT_ULINE_MASK) SLtt_write_string (UnderLine_Vid_Str);
+ if (fgbg & SLTT_BOLD_MASK) SLtt_bold_video ();
+ if (fgbg & SLTT_REV_MASK) SLtt_write_string (Rev_Vid_Str);
+ if (fgbg & SLTT_BLINK_MASK)
+ {
+ /* Someday Linux will have a blink mode that set high intensity
+ * background. Lets be prepared.
+ */
+ if (SLtt_Blink_Mode) SLtt_write_string (Blink_Vid_Str);
+ }
+ }
+
+ if (SLtt_Use_Ansi_Colors)
+ {
+ fg0 = (int) GET_FG(fgbg);
+ bg0 = (int) GET_BG(fgbg);
+ tt_printf(Color_Escape_Sequence, fg0, bg0);
+ }
+ Current_Fgbg = fgbg;
+}
+
+static int Video_Initialized;
+
+void SLtt_reverse_video (int color)
+{
+ SLtt_Char_Type fgbg;
+ char *esc;
+
+ if (Worthless_Highlight) return;
+ if ((color < 0) || (color >= JMAX_COLORS)) return;
+
+ if (Video_Initialized == 0)
+ {
+ if (color == JNORMAL_COLOR)
+ {
+ SLtt_write_string (Norm_Vid_Str);
+ }
+ else SLtt_write_string (Rev_Vid_Str);
+ Current_Fgbg = 0xFFFFFFFFU;
+ return;
+ }
+
+ if (SLtt_Use_Ansi_Colors)
+ {
+ fgbg = Ansi_Color_Map[color].fgbg;
+ if ((esc = Ansi_Color_Map[color].custom_esc) != NULL)
+ {
+ if (fgbg != Current_Fgbg)
+ {
+ Current_Fgbg = fgbg;
+ SLtt_write_string (esc);
+ return;
+ }
+ }
+ }
+ else fgbg = Ansi_Color_Map[color].mono;
+
+ if (fgbg == Current_Fgbg) return;
+ write_attributes (fgbg);
+}
+
+
+
+
+void SLtt_normal_video (void)
+{
+ SLtt_reverse_video(JNORMAL_COLOR);
+}
+
+void SLtt_narrow_width (void)
+{
+ SLtt_write_string("\033[?3l");
+}
+
+void SLtt_wide_width (void)
+{
+ SLtt_write_string("\033[?3h");
+}
+
+/* Highest bit represents the character set. */
+#define COLOR_MASK 0x7F00
+
+#define COLOR_OF(x) (((unsigned int)(x) & COLOR_MASK) >> 8)
+/*
+#define COLOR_EQS(a, b) \
+ (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)
+*/
+
+#define COLOR_EQS(a, b) \
+ (SLtt_Use_Ansi_Colors \
+ ? (Ansi_Color_Map[COLOR_OF(a)].fgbg == Ansi_Color_Map[COLOR_OF(b)].fgbg)\
+ : (Ansi_Color_Map[COLOR_OF(a)].mono == Ansi_Color_Map[COLOR_OF(b)].mono))
+
+
+#define CHAR_EQS(a, b) (((a) == (b))\
+ || ((((a) & ~COLOR_MASK) == ((b) & ~COLOR_MASK))\
+ && COLOR_EQS((a), (b))))
+
+
+/* The whole point of this routine is to prevent writing to the last column
+ * and last row on terminals with automatic margins.
+ */
+static void write_string_with_care (char *str)
+{
+ unsigned int len;
+
+ if (str == NULL) return;
+
+ len = strlen (str);
+ if (Automatic_Margins && (Cursor_r + 1 == SLtt_Screen_Rows))
+ {
+ if (len + (unsigned int) Cursor_c >= (unsigned int) SLtt_Screen_Cols)
+ {
+ /* For now, just do not write there. Later, something more
+ * sophisticated will be implemented.
+ */
+ if (SLtt_Screen_Cols > Cursor_c)
+ len = SLtt_Screen_Cols - Cursor_c - 1;
+ else len = 0;
+ }
+ }
+ tt_write (str, len);
+}
+
+static void send_attr_str (unsigned short *s)
+{
+ unsigned char out[256], ch, *p;
+ register SLtt_Char_Type attr;
+ register unsigned short sh;
+ int color, last_color = -1;
+
+ p = out;
+ while (0 != (sh = *s++))
+ {
+ ch = sh & 0xFF;
+ color = ((int) sh & 0xFF00) >> 8;
+#ifdef SLTT_TRANSP_ACS_PATCH
+ if (ch <= ' ' && (color & 0x80)) color &= ~0x80;
+#endif
+ if (color != last_color)
+ {
+ if (SLtt_Use_Ansi_Colors) attr = Ansi_Color_Map[color & 0x7F].fgbg;
+ else attr = Ansi_Color_Map[color & 0x7F].mono;
+
+ /* sh => color */
+ if (color & 0x80) /* alternate char set */
+ {
+ if (SLtt_Use_Blink_For_ACS)
+ {
+ if (SLtt_Blink_Mode) attr |= SLTT_BLINK_MASK;
+ }
+ else attr |= SLTT_ALTC_MASK;
+ }
+
+
+ if (attr != Current_Fgbg)
+ {
+#ifndef SLTT_TRANSP_ACS_PATCH
+ if ((ch != ' ') ||
+ /* it is a space so only consider it different if it
+ * has different attributes.
+ */
+ (attr & BGALL_MASK) != (Current_Fgbg & BGALL_MASK))
+#endif
+ {
+ if (p != out)
+ {
+ *p = 0;
+ write_string_with_care ((char *) out);
+ Cursor_c += (int) (p - out);
+ p = out;
+ }
+
+ if (SLtt_Use_Ansi_Colors && (NULL != Ansi_Color_Map[color & 0x7F].custom_esc))
+ {
+ SLtt_write_string (Ansi_Color_Map[color & 0x7F].custom_esc);
+ /* Just in case the custom escape sequence screwed up
+ * the alt character set state...
+ */
+ if ((attr & SLTT_ALTC_MASK) != (Current_Fgbg & SLTT_ALTC_MASK))
+ SLtt_set_alt_char_set ((int) (attr & SLTT_ALTC_MASK));
+ Current_Fgbg = attr;
+ }
+ else write_attributes (attr);
+
+ last_color = color;
+ }
+ }
+ }
+ *p++ = ch;
+ }
+ *p = 0;
+ if (p != out) write_string_with_care ((char *) out);
+ Cursor_c += (int) (p - out);
+}
+
+static void forward_cursor (unsigned int n, int row)
+{
+ char buf[30];
+
+
+ if (n <= 4)
+ {
+ SLtt_normal_video ();
+ SLMEMSET (buf, ' ', n);
+ buf[n] = 0;
+ write_string_with_care (buf);
+ Cursor_c += n;
+ }
+ else if (Curs_F_Str != NULL)
+ {
+ Cursor_c += n;
+ n = tt_sprintf(buf, Curs_F_Str, (int) n, 0);
+ tt_write(buf, n);
+ }
+ else SLtt_goto_rc (row, (int) (Cursor_c + n));
+}
+
+
+#define SPACE_CHAR (0x20 | (JNORMAL_COLOR << 8))
+
+void SLtt_smart_puts(unsigned short *neww, unsigned short *oldd, int len, int row)
+{
+ register unsigned short *p, *q, *qmax, *pmax, *buf;
+ unsigned short buffer[256];
+ unsigned int n_spaces;
+ unsigned short *space_match, *last_buffered_match;
+#ifdef HP_GLITCH_CODE
+ int handle_hp_glitch = 0;
+#endif
+
+ q = oldd; p = neww;
+ qmax = oldd + len;
+ pmax = p + len;
+
+ /* Find out where to begin --- while they match, we are ok */
+ while (1)
+ {
+ if (q == qmax) return;
+#if SLANG_HAS_KANJI_SUPPORT
+ if (*p & 0x80)
+ { /* new is kanji */
+ if ((*q & 0x80) && ((q + 1) < qmax))
+ { /* old is also kanji */
+ if (((0xFF & *q) != (0xFF & *p))
+ || ((0xFF & q[1]) != (0xFF & p[1])))
+ break; /* both kanji, but not match */
+
+ else
+ { /* kanji match ! */
+ if (!COLOR_EQS(*q, *p)) break;
+ q++; p++;
+ if (!COLOR_EQS(*q, *p)) break;
+ /* really match! */
+ q++; p++;
+ continue;
+ }
+ }
+ else break; /* old is not kanji */
+ }
+ else
+ { /* new is not kanji */
+ if (*q & 0x80) break; /* old is kanji */
+ }
+#endif
+ if (!CHAR_EQS(*q, *p)) break;
+ q++; p++;
+ }
+
+ /*position the cursor */
+ SLtt_goto_rc (row, (int) (p - neww));
+
+#ifdef HP_GLITCH_CODE
+ if (Has_HP_Glitch)
+ {
+ unsigned short *qq = q;
+ while (qq < qmax)
+ {
+ if (*qq & 0xFF00)
+ {
+ SLtt_normal_video ();
+ SLtt_del_eol ();
+ qmax = q;
+ handle_hp_glitch = 1;
+ break;
+ }
+ qq++;
+ }
+ }
+#endif
+ /* Find where the last non-blank character on old/new screen is */
+
+ while (qmax > q)
+ {
+ qmax--;
+ if (!CHAR_EQS(*qmax, SPACE_CHAR))
+ {
+ qmax++;
+ break;
+ }
+ }
+
+ while (pmax > p)
+ {
+ pmax--;
+ if (!CHAR_EQS(*pmax, SPACE_CHAR))
+ {
+ pmax++;
+ break;
+ }
+ }
+
+ last_buffered_match = buf = buffer; /* buffer is empty */
+
+#ifdef HP_GLITCH_CODE
+ if (handle_hp_glitch)
+ {
+ while (p < pmax)
+ {
+ *buf++ = *p++;
+ }
+ }
+#endif
+
+ /* loop using overwrite then skip algorithm until done */
+ while (1)
+ {
+ /* while they do not match and we do not hit a space, buffer them up */
+ n_spaces = 0;
+ while (p < pmax)
+ {
+ if (CHAR_EQS(*q,SPACE_CHAR) && CHAR_EQS(*p, SPACE_CHAR))
+ {
+ /* If *q is not a space, we would have to overwrite it.
+ * However, if *q is a space, then while *p is also one,
+ * we only need to skip over the blank field.
+ */
+ space_match = p;
+ p++; q++;
+ while ((p < pmax)
+ && CHAR_EQS(*q,SPACE_CHAR)
+ && CHAR_EQS(*p, SPACE_CHAR))
+ {
+ p++;
+ q++;
+ }
+ n_spaces = (unsigned int) (p - space_match);
+ break;
+ }
+#if SLANG_HAS_KANJI_SUPPORT
+ if ((*p & 0x80) && ((p + 1) < pmax))
+ { /* new is kanji */
+ if (*q & 0x80)
+ { /* old is also kanji */
+ if (((0xFF & *q) != (0xFF & *p))
+ || ((0xFF & q[1]) != (0xFF & p[1])))
+ {
+ /* both kanji, but not match */
+ *buf++ = *p++;
+ *buf++ = *p++;
+ q += 2;
+ continue;
+ }
+ else
+ { /* kanji match ? */
+ if (!COLOR_EQS(*q, *p) || !COLOR_EQS(*(q+1), *(p+1)))
+ {
+ /* code is match ,but color is diff */
+ *buf++ = *p++;
+ *buf++ = *p++;
+ continue;
+ }
+ /* really match ! */
+ break;
+ }
+ }
+ else
+ { /* old is not kanji */
+ *buf++ = *p++;
+ *buf++ = *p++;
+ q += 2;
+ continue;
+ }
+ }
+ else
+ { /* new is not kanji */
+ if (*q & 0x80)
+ { /* old is kanji */
+ *buf++ = *p++;
+ q++;
+ continue;
+ }
+ }
+#endif
+
+ if (CHAR_EQS(*q, *p)) break;
+ *buf++ = *p++;
+ q++;
+ }
+ *buf = 0;
+
+ if (buf != buffer) send_attr_str (buffer);
+ buf = buffer;
+
+ if (n_spaces && (p < pmax))
+ {
+ forward_cursor (n_spaces, row);
+ }
+
+ /* Now we overwrote what we could and cursor is placed at position
+ * of a possible match of new and old. If this is the case, skip
+ * some more.
+ */
+#if !SLANG_HAS_KANJI_SUPPORT
+ while ((p < pmax) && CHAR_EQS(*p, *q))
+ {
+ *buf++ = *p++;
+ q++;
+ }
+#else
+ /* Kanji */
+ while (p < pmax)
+ {
+ if ((*p & 0x80) && ((p + 1) < pmax))
+ { /* new is kanji */
+ if (*q & 0x80)
+ { /* old is also kanji */
+ if (((0xFF & *q) == (0xFF & *p))
+ && ((0xFF & q[1]) == (0xFF & p[1])))
+ {
+ /* kanji match ? */
+ if (!COLOR_EQS(*q, *p)
+ || !COLOR_EQS(q[1], p[1]))
+ break;
+
+ *buf++ = *p++;
+ q++;
+ if (p >= pmax)
+ {
+ *buf++ = SPACE_CHAR;
+ p++;
+ break;
+ }
+ else
+ {
+ *buf++ = *p++;
+ q++;
+ continue;
+ }
+ }
+ else break; /* both kanji, but not match */
+ }
+ else break; /* old is not kanji */
+ }
+ else
+ { /* new is not kanji */
+ if (*q & 0x80) break; /* old is kanji */
+ if (!CHAR_EQS(*q, *p)) break;
+ *buf++ = *p++;
+ q++;
+ }
+ }
+#endif
+ last_buffered_match = buf;
+ if (p >= pmax) break;
+
+ /* jump to new position is it is greater than 5 otherwise
+ * let it sit in the buffer and output it later.
+ */
+ if ((int) (buf - buffer) >= 5)
+ {
+ forward_cursor ((unsigned int) (buf - buffer), row);
+ last_buffered_match = buf = buffer;
+ }
+ }
+
+ if (buf != buffer)
+ {
+ if (q < qmax)
+ {
+ if ((buf == last_buffered_match)
+ && ((int) (buf - buffer) >= 5))
+ {
+ forward_cursor ((unsigned int) (buf - buffer), row);
+ }
+ else
+ {
+ *buf = 0;
+ send_attr_str (buffer);
+ }
+ }
+ }
+ if (q < qmax) SLtt_del_eol ();
+ if (Automatic_Margins && (Cursor_c + 1 >= SLtt_Screen_Cols)) Cursor_Set = 0;
+}
+
+
+static void get_color_info (void)
+{
+ char *fg, *bg;
+
+ SLtt_Use_Ansi_Colors = (NULL != getenv ("COLORTERM"));
+
+ if (-1 == get_default_colors (&fg, &bg))
+ return;
+
+ /* Check to see if application has already set them. */
+ if (Color_0_Modified)
+ return;
+
+ SLtt_set_color (0, NULL, fg, bg);
+ SLtt_set_color (1, NULL, bg, fg);
+}
+
+
+/* termcap stuff */
+
+#ifdef __unix__
+
+#ifndef USE_TERMCAP
+static char *Tbuf;
+static char *Tstr_Buf;
+
+#define tgetstr SLtt_tigetstr
+#define tgetent SLtt_tigetent
+#define TGETNUM(x) SLtt_tigetnum((x), &Tbuf)
+#define TGETFLAG(x) SLtt_tigetflag((x), &Tbuf)
+#else
+
+extern char *tgetstr(char *, char **);
+extern int tgetent(char *, char *);
+extern int tgetnum(char *);
+extern int tgetflag(char *);
+static char Tstr_Buf[1024];
+static char Tbuf[4096];
+#define TGETNUM tgetnum
+#define TGETFLAG tgetflag
+#endif
+
+static char *my_tgetstr(char *what, char **p)
+{
+ register char *w, *w1;
+ char *wsave;
+ what = tgetstr(what, p);
+ if (what != NULL)
+ {
+ /* Check for AIX brain-damage */
+ if (*what == '@')
+ return NULL;
+
+ /* lose pad info --- with today's technology, term is a loser if
+ it is really needed */
+ while ((*what == '.') ||
+ ((*what >= '0') && (*what <= '9'))) what++;
+ if (*what == '*') what++;
+
+ /* lose terminfo padding--- looks like $<...> */
+ w = what;
+ while (*w) if ((*w++ == '$') && (*w == '<'))
+ {
+ w1 = w - 1;
+ while (*w && (*w != '>')) w++;
+ if (*w == 0) break;
+ w++;
+ wsave = w1;
+ while ((*w1++ = *w++) != 0);
+ w = wsave;
+ }
+ if (*what == 0) what = NULL;
+ }
+ return(what);
+}
+
+char *SLtt_tgetstr (char *s)
+{
+#ifdef USE_TERMCAP
+ static
+#endif
+ char *p = Tstr_Buf;
+ return my_tgetstr (s, &p);
+}
+
+int SLtt_tgetnum (char *s)
+{
+ return TGETNUM (s);
+}
+int SLtt_tgetflag (char *s)
+{
+ return TGETFLAG (s);
+}
+
+
+static int Vt100_Like = 0;
+
+void SLtt_get_terminfo (void)
+{
+ char *term, *t, ch;
+ int is_xterm;
+ int almost_vtxxx;
+
+ get_color_info ();
+
+ if (NULL == (term = (char *) getenv("TERM")))
+ {
+ SLang_exit_error("TERM environment variable needs set.");
+ }
+
+ Linux_Console = (!strncmp (term, "linux", 5)
+#ifdef linux
+ || !strncmp(term, "con", 3)
+#endif
+ );
+
+ t = term;
+
+ if (strcmp(t, "vt52") && (*t++ == 'v') && (*t++ == 't')
+ && (ch = *t, (ch >= '1') && (ch <= '9'))) Vt100_Like = 1;
+
+ is_xterm = !strncmp (term, "xterm", 5);
+ almost_vtxxx = (Vt100_Like
+ || Linux_Console
+ || is_xterm
+ || !strcmp (term, "screen"));
+
+#ifndef USE_TERMCAP
+ if (NULL == (Tbuf = tgetent (term)))
+ {
+ char err_buf[512];
+ if (almost_vtxxx) /* Special cases. */
+ {
+ int vt102 = 1;
+ if (!strcmp (term, "vt100")) vt102 = 0;
+ SLtt_set_term_vtxxx (&vt102);
+ return;
+ }
+ sprintf (err_buf, "Unknown terminal: %s\n\
+Check the TERM environment variable.\n\
+Also make sure that the terminal is defined in the terminfo database.\n\
+Alternatively, set the TERMCAP environment variable to the desired\n\
+termcap entry.", term);
+ SLang_exit_error(err_buf);
+ }
+ Tstr_Buf = Tbuf;
+#else /* USE_TERMCAP */
+ if (1 != tgetent(Tbuf, term)) SLang_exit_error("Unknown terminal.");
+#endif /* NOT USE_TERMCAP */
+
+ if ((NULL == (Cls_Str = SLtt_tgetstr("cl")))
+ || (NULL == (Curs_Pos_Str = SLtt_tgetstr("cm"))))
+ {
+ SLang_exit_error("Terminal not powerful enough for SLang.");
+ }
+
+ if ((NULL == (Ins_Mode_Str = SLtt_tgetstr("im")))
+ || ( NULL == (Eins_Mode_Str = SLtt_tgetstr("ei")))
+ || ( NULL == (Del_Char_Str = SLtt_tgetstr("dc"))))
+ SLtt_Term_Cannot_Insert = 1;
+
+ Visible_Bell_Str = SLtt_tgetstr ("vb");
+ Curs_Up_Str = SLtt_tgetstr ("up");
+ Rev_Scroll_Str = SLtt_tgetstr("sr");
+ Del_N_Lines_Str = SLtt_tgetstr("DL");
+ Add_N_Lines_Str = SLtt_tgetstr("AL");
+
+ /* Actually these are used to initialize terminals that use cursor
+ * addressing. Hard to believe.
+ */
+ Term_Init_Str = SLtt_tgetstr ("ti");
+ Term_Reset_Str = SLtt_tgetstr ("te");
+
+ /* If I do this for vtxxx terminals, arrow keys start sending ESC O A,
+ * which I do not want. This is mainly for HP terminals.
+ */
+ if ((almost_vtxxx == 0) || SLtt_Force_Keypad_Init)
+ {
+ Keypad_Init_Str = SLtt_tgetstr ("ks");
+ Keypad_Reset_Str = SLtt_tgetstr ("ke");
+ }
+
+ /* Make up for defective termcap/terminfo databases */
+ if ((Vt100_Like && (term[2] != '1'))
+ || Linux_Console
+ || is_xterm
+ )
+ {
+ if (Del_N_Lines_Str == NULL) Del_N_Lines_Str = "\033[%dM";
+ if (Add_N_Lines_Str == NULL) Add_N_Lines_Str = "\033[%dL";
+ }
+
+ Scroll_R_Str = SLtt_tgetstr("cs");
+
+ SLtt_get_screen_size ();
+
+ if ((Scroll_R_Str == NULL)
+ || (((NULL == Del_N_Lines_Str) || (NULL == Add_N_Lines_Str))
+ && (NULL == Rev_Scroll_Str)))
+ {
+ if (is_xterm
+ || Linux_Console
+ )
+ {
+ /* Defective termcap mode!!!! */
+ SLtt_set_term_vtxxx (NULL);
+ }
+ else SLtt_Term_Cannot_Scroll = 1;
+ }
+
+ Del_Eol_Str = SLtt_tgetstr("ce");
+
+ Rev_Vid_Str = SLtt_tgetstr("mr");
+ if (Rev_Vid_Str == NULL) Rev_Vid_Str = SLtt_tgetstr("so");
+
+ Bold_Vid_Str = SLtt_tgetstr("md");
+
+ /* Although xterm cannot blink, it does display the blinking characters
+ * as bold ones. Some Rxvt will display the background as high intensity.
+ */
+ if ((NULL == (Blink_Vid_Str = SLtt_tgetstr("mb")))
+ && is_xterm)
+ Blink_Vid_Str = "\033[5m";
+
+ UnderLine_Vid_Str = SLtt_tgetstr("us");
+
+ Start_Alt_Chars_Str = SLtt_tgetstr ("as"); /* smacs */
+ End_Alt_Chars_Str = SLtt_tgetstr ("ae"); /* rmacs */
+ Enable_Alt_Char_Set = SLtt_tgetstr ("eA"); /* enacs */
+ SLtt_Graphics_Char_Pairs = SLtt_tgetstr ("ac");
+
+#ifndef NCURSES_BRAIN_DAMAGE_CONTROL
+# define NCURSES_BRAIN_DAMAGE_CONTROL 0
+#endif
+
+#if NCURSES_BRAIN_DAMAGE_CONTROL
+ if (Linux_Console)
+ {
+# if 0
+ char *lgcp = "l\332m\300k\277j\331u\264t\303v\301w\302q\304x\263n\053o\176s\137`\004a\260f\370g\361~\011,\020+\021.\031-\030h\261i\0250\333";
+
+ SLtt_Graphics_Char_Pairs = lgcp;
+ Start_Alt_Chars_Str = "\033(B\033)U\016";
+ End_Alt_Chars_Str = "\033(B\033)0\017";
+ Enable_Alt_Char_Set = NULL;
+# else
+ char *lgcp = "`\004a\261f\370g\361h\260j\331k\277l\332m\300n\305o\302q\304r\362s_t\303u\264v\301w\302x\263y\371z\372{\373|\374}\375~";
+
+ SLtt_Graphics_Char_Pairs = lgcp;
+ Start_Alt_Chars_Str = "\033[11m";
+ End_Alt_Chars_Str = "\033[10m";
+ Enable_Alt_Char_Set = NULL;
+# endif
+ }
+#endif
+
+ if (NULL == SLtt_Graphics_Char_Pairs)
+ {
+ /* make up for defective termcap/terminfo */
+ if (Vt100_Like)
+ {
+ Start_Alt_Chars_Str = "\016";
+ End_Alt_Chars_Str = "\017";
+ Enable_Alt_Char_Set = "\033)0";
+ }
+ }
+
+ /* aixterm added by willi */
+ if (is_xterm || !strncmp (term, "aixterm", 7))
+ {
+ Start_Alt_Chars_Str = "\016";
+ End_Alt_Chars_Str = "\017";
+ Enable_Alt_Char_Set = "\033(B\033)0";
+ }
+
+ if ((SLtt_Graphics_Char_Pairs == NULL) &&
+ ((Start_Alt_Chars_Str == NULL) || (End_Alt_Chars_Str == NULL)))
+ {
+ SLtt_Has_Alt_Charset = 0;
+ Enable_Alt_Char_Set = NULL;
+ }
+ else SLtt_Has_Alt_Charset = 1;
+
+
+ /* status line capabilities */
+ if ((SLtt_Has_Status_Line == -1)
+ && (0 != (SLtt_Has_Status_Line = TGETFLAG ("hs"))))
+ {
+ Disable_Status_line_Str = SLtt_tgetstr ("ds");
+ Return_From_Status_Line_Str = SLtt_tgetstr ("fs");
+ Goto_Status_Line_Str = SLtt_tgetstr ("ts");
+ Status_Line_Esc_Ok = TGETFLAG("es");
+ Num_Status_Line_Columns = TGETNUM("ws");
+ if (Num_Status_Line_Columns < 0) Num_Status_Line_Columns = 0;
+ }
+
+ if (NULL == (Norm_Vid_Str = SLtt_tgetstr("me")))
+ {
+ Norm_Vid_Str = SLtt_tgetstr("se");
+ }
+
+ Cursor_Invisible_Str = SLtt_tgetstr("vi");
+ Cursor_Visible_Str = SLtt_tgetstr("ve");
+
+ Curs_F_Str = SLtt_tgetstr("RI");
+
+#if 0
+ if (NULL != Curs_F_Str)
+ {
+ Len_Curs_F_Str = strlen(Curs_F_Str);
+ }
+ else Len_Curs_F_Str = strlen(Curs_Pos_Str);
+#endif
+
+ Automatic_Margins = TGETFLAG ("am");
+ /* No_Move_In_Standout = !TGETFLAG ("ms"); */
+#ifdef HP_GLITCH_CODE
+ Has_HP_Glitch = TGETFLAG ("xs");
+#else
+ Worthless_Highlight = TGETFLAG ("xs");
+#endif
+
+ if (Worthless_Highlight == 0)
+ { /* Magic cookie glitch */
+ Worthless_Highlight = (TGETNUM ("sg") > 0);
+ }
+
+ if (Worthless_Highlight)
+ SLtt_Has_Alt_Charset = 0;
+
+ /* Check for color information in the termcap. A program should not
+ * rely on this information being accurate.
+ */
+ if (SLtt_Use_Ansi_Colors == 0)
+ {
+ Reset_Color_String = SLtt_tgetstr ("op");
+
+ SLtt_Use_Ansi_Colors = ((NULL != Reset_Color_String)
+ || (NULL != SLtt_tgetstr ("Sf"))
+ || (NULL != SLtt_tgetstr ("Sb"))
+ || (NULL != SLtt_tgetstr ("AF"))
+ || (NULL != SLtt_tgetstr ("AB"))
+ || (-1 != SLtt_tgetnum ("Co"))
+ || (-1 != SLtt_tgetnum ("pa")));
+
+ }
+
+#if defined(__QNX__) && defined(QNX_QANSI_SLANG_COMPAT_ACS)
+ /*
+ * Override the alt-char-set handling string in case of a
+ * QNX/qansi terminal: use the "old style" strings in order
+ * to be compatible with S-Lang without the SLTT_TRANSP_ACS_PATCH
+ * code...
+ */
+ if (SLtt_Has_Alt_Charset &&
+ strncmp(term, "qansi", 5) == 0 &&
+ Start_Alt_Chars_Str[0] != '\016')
+ {
+ Start_Alt_Chars_Str = "\016"; /* smacs/as (^N) */
+ End_Alt_Chars_Str = "\017"; /* rmacs/ae (^O) */
+ SLtt_Graphics_Char_Pairs = /* acsc/ac */
+ "``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~O\141";
+
+ /*
+ * it would be required to modify the sgr/sa entry also, if it
+ * would be used (->embedded as/ae sequences)...
+ */
+ }
+#endif /* __QNX__ && QNX_QANSI_SLANG_COMPAT_ACS */
+
+}
+
+#endif
+/* Unix */
+
+/* specific to vtxxx only */
+void SLtt_enable_cursor_keys (void)
+{
+#ifdef __unix__
+ if (Vt100_Like)
+#endif
+ SLtt_write_string("\033=\033[?1l");
+}
+
+#ifdef VMS
+void SLtt_get_terminfo ()
+{
+ int zero = 0;
+
+ get_color_info ();
+
+ SLtt_set_term_vtxxx(&zero);
+ Start_Alt_Chars_Str = "\016";
+ End_Alt_Chars_Str = "\017";
+ SLtt_Has_Alt_Charset = 1;
+ SLtt_Graphics_Char_Pairs = "aaffgghhjjkkllmmnnooqqssttuuvvwwxx";
+ Enable_Alt_Char_Set = "\033(B\033)0";
+ SLtt_get_screen_size ();
+}
+#endif
+
+/* This sets term for vt102 terminals it parameter vt100 is 0. If vt100
+ * is non-zero, set terminal appropriate for a only vt100
+ * (no add line capability). */
+
+void SLtt_set_term_vtxxx(int *vt100)
+{
+ Norm_Vid_Str = "\033[m";
+
+ Scroll_R_Str = "\033[%i%d;%dr";
+ Cls_Str = "\033[2J\033[H";
+ Rev_Vid_Str = "\033[7m";
+ Bold_Vid_Str = "\033[1m";
+ Blink_Vid_Str = "\033[5m";
+ UnderLine_Vid_Str = "\033[4m";
+ Del_Eol_Str = "\033[K";
+ Rev_Scroll_Str = "\033M";
+ Curs_F_Str = "\033[%dC";
+ /* Len_Curs_F_Str = 5; */
+ Curs_Pos_Str = "\033[%i%d;%dH";
+ if ((vt100 == NULL) || (*vt100 == 0))
+ {
+ Ins_Mode_Str = "\033[4h";
+ Eins_Mode_Str = "\033[4l";
+ Del_Char_Str = "\033[P";
+ Del_N_Lines_Str = "\033[%dM";
+ Add_N_Lines_Str = "\033[%dL";
+ SLtt_Term_Cannot_Insert = 0;
+ }
+ else
+ {
+ Del_N_Lines_Str = NULL;
+ Add_N_Lines_Str = NULL;
+ SLtt_Term_Cannot_Insert = 1;
+ }
+ SLtt_Term_Cannot_Scroll = 0;
+ /* No_Move_In_Standout = 0; */
+}
+
+void SLtt_init_video (void)
+{
+ /* send_string_to_term("\033[?6h"); */
+ /* relative origin mode */
+ SLtt_write_string (Term_Init_Str);
+ SLtt_write_string (Keypad_Init_Str);
+ SLtt_reset_scroll_region();
+ SLtt_end_insert();
+ SLtt_write_string (Enable_Alt_Char_Set);
+ Video_Initialized = 1;
+}
+
+
+void SLtt_reset_video (void)
+{
+ SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
+ Cursor_Set = 0;
+ SLtt_normal_video (); /* MSKermit requires this */
+ SLtt_write_string(Norm_Vid_Str);
+
+ Current_Fgbg = 0xFFFFFFFFU;
+ SLtt_set_alt_char_set (0);
+ if (SLtt_Use_Ansi_Colors)
+ {
+ if (Reset_Color_String == NULL)
+ {
+ SLtt_Char_Type attr;
+ if (-1 != make_color_fgbg (NULL, NULL, &attr))
+ write_attributes (attr);
+ else SLtt_write_string ("\033[0m\033[m");
+ }
+ else SLtt_write_string (Reset_Color_String);
+ Current_Fgbg = 0xFFFFFFFFU;
+ }
+ SLtt_erase_line ();
+ SLtt_write_string (Keypad_Reset_Str);
+ SLtt_write_string (Term_Reset_Str);
+ SLtt_flush_output ();
+ Video_Initialized = 0;
+}
+
+void SLtt_bold_video (void)
+{
+ SLtt_write_string (Bold_Vid_Str);
+}
+
+int SLtt_set_mouse_mode (int mode, int force)
+{
+ char *term;
+
+ if (force == 0)
+ {
+ if (NULL == (term = (char *) getenv("TERM"))) return -1;
+ if (strncmp ("xterm", term, 5))
+ return -1;
+ }
+
+ if (mode)
+ SLtt_write_string ("\033[?9h");
+ else
+ SLtt_write_string ("\033[?9l");
+
+ return 0;
+}
+
+
+void SLtt_disable_status_line (void)
+{
+ if (SLtt_Has_Status_Line > 0)
+ SLtt_write_string (Disable_Status_line_Str);
+}
+
+int SLtt_write_to_status_line (char *s, int col)
+{
+ if ((SLtt_Has_Status_Line <= 0)
+ || (Goto_Status_Line_Str == NULL)
+ || (Return_From_Status_Line_Str == NULL))
+ return -1;
+
+ tt_printf (Goto_Status_Line_Str, col, 0);
+ SLtt_write_string (s);
+ SLtt_write_string (Return_From_Status_Line_Str);
+ return 0;
+}
+
+
+void SLtt_get_screen_size (void)
+{
+#ifdef VMS
+ int status, code;
+ unsigned short chan;
+ $DESCRIPTOR(dev_dsc, "SYS$INPUT:");
+#endif
+#ifdef __os2__
+ VIOMODEINFO vioModeInfo;
+#endif
+ int r = 0, c = 0;
+
+#if defined(TIOCGWINSZ) && !defined(SCO_FLAVOR)
+ struct winsize wind_struct;
+
+ do
+ {
+ if ((ioctl(1,TIOCGWINSZ,&wind_struct) == 0)
+ || (ioctl(0, TIOCGWINSZ, &wind_struct) == 0)
+ || (ioctl(2, TIOCGWINSZ, &wind_struct) == 0))
+ {
+ c = (int) wind_struct.ws_col;
+ r = (int) wind_struct.ws_row;
+ break;
+ }
+ }
+ while (errno == EINTR);
+
+#endif
+
+#ifdef VMS
+ status = sys$assign(&dev_dsc,&chan,0,0,0);
+ if (status & 1)
+ {
+ code = DVI$_DEVBUFSIZ;
+ status = lib$getdvi(&code, &chan,0, &c, 0,0);
+ if (!(status & 1))
+ c = 80;
+ code = DVI$_TT_PAGE;
+ status = lib$getdvi(&code, &chan,0, &r, 0,0);
+ if (!(status & 1))
+ r = 24;
+ sys$dassgn(chan);
+ }
+#endif
+
+#ifdef __os2__
+ vioModeInfo.cb = sizeof(vioModeInfo);
+ VioGetMode (&vioModeInfo, 0);
+ c = vioModeInfo.col;
+ r = vioModeInfo.row;
+#endif
+
+ if (r <= 0)
+ {
+ char *s = getenv ("LINES");
+ if (s != NULL) r = atoi (s);
+ }
+
+ if (c <= 0)
+ {
+ char *s = getenv ("COLUMNS");
+ if (s != NULL) c = atoi (s);
+ }
+
+ if ((r <= 0) || (r > 200)) r = 24;
+ if ((c <= 0) || (c > 250)) c = 80;
+ SLtt_Screen_Rows = r;
+ SLtt_Screen_Cols = c;
+}
--- /dev/null
+/* error handling common to all routines. */
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#include "slang.h"
+#include "_slang.h"
+
+void (*SLang_Error_Routine)(char *);
+void (*SLang_Exit_Error_Hook)(char *);
+volatile int SLang_Error = 0;
+char *SLang_Error_Message;
+volatile int SLKeyBoard_Quit = 0;
+
+void SLang_doerror (char *error)
+{
+ char err [1024];
+ char *str = NULL;
+
+ *err = 0;
+
+ str = "Slang/Midnight Commander unknown error";
+
+ sprintf(err, "S-Lang Error: %s", str);
+
+ if (SLang_Error_Routine == NULL)
+ {
+ fputs (err, stderr);
+ fputs("\r\n", stderr);
+ }
+ else
+ (*SLang_Error_Routine)(err);
+}
+
+
+
+void SLang_exit_error (char *s)
+{
+ if (SLang_Exit_Error_Hook != NULL)
+ {
+ (*SLang_Exit_Error_Hook) (s);
+ }
+ if (s != NULL) fprintf (stderr, "%s\n", s);
+ exit (-1);
+}
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "slang.h"
+#include "_slang.h"
+
+unsigned int SLang_Input_Buffer_Len = 0;
+unsigned char SLang_Input_Buffer [MAX_INPUT_BUFFER_LEN];
+
+int SLang_Abort_Char = 7;
+int SLang_Ignore_User_Abort = 0;
+
+/* This has the effect of mapping all characters in the range 128-169 to
+ * ESC [ something
+ */
+#ifndef __GO32__
+# if defined(__unix__) || defined(vms)
+# define DEC_8BIT_HACK 64
+# endif
+#endif
+
+#ifdef OS2_NT /* see the replacement in src/slint.c */
+unsigned int SLang_getkey (void)
+{
+ unsigned int imax;
+ unsigned int ch;
+
+ if (SLang_Input_Buffer_Len)
+ {
+ ch = (unsigned int) *SLang_Input_Buffer;
+ SLang_Input_Buffer_Len--;
+ imax = SLang_Input_Buffer_Len;
+
+ SLMEMCPY ((char *) SLang_Input_Buffer,
+ (char *) (SLang_Input_Buffer + 1), imax);
+ }
+ else if (0xFFFF == (ch = SLsys_getkey ())) return ch;
+
+#ifdef DEC_8BIT_HACK
+ if (ch & 0x80)
+ {
+ unsigned char i;
+ i = (unsigned char) (ch & 0x7F);
+ if (i < ' ')
+ {
+ i += DEC_8BIT_HACK;
+ SLang_ungetkey (i);
+ ch = 27;
+ }
+ }
+#endif
+ return(ch);
+}
+#endif /* OS2_NT */
+
+void SLang_ungetkey_string (unsigned char *s, unsigned int n)
+{
+ register unsigned char *bmax, *b, *b1;
+ if (SLang_Input_Buffer_Len + n + 3 > MAX_INPUT_BUFFER_LEN) return;
+
+ b = SLang_Input_Buffer;
+ bmax = (b - 1) + SLang_Input_Buffer_Len;
+ b1 = bmax + n;
+ while (bmax >= b) *b1-- = *bmax--;
+ bmax = b + n;
+ while (b < bmax) *b++ = *s++;
+ SLang_Input_Buffer_Len += n;
+}
+
+void SLang_buffer_keystring (unsigned char *s, unsigned int n)
+{
+
+ if (n + SLang_Input_Buffer_Len + 3 > MAX_INPUT_BUFFER_LEN) return;
+
+ SLMEMCPY ((char *) SLang_Input_Buffer + SLang_Input_Buffer_Len,
+ (char *) s, n);
+ SLang_Input_Buffer_Len += n;
+}
+
+void SLang_ungetkey (unsigned char ch)
+{
+ SLang_ungetkey_string(&ch, 1);
+}
+
+#ifdef OS2_NT /* see the replacement in src/slint.c */
+int SLang_input_pending (int tsecs)
+{
+ int n;
+ unsigned char c;
+ if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
+
+ n = SLsys_input_pending (tsecs);
+
+ if (n <= 0) return 0;
+
+ c = (unsigned char) SLang_getkey ();
+ SLang_ungetkey_string (&c, 1);
+
+ return n;
+}
+#endif /* OS2_NT */
+
+void SLang_flush_input (void)
+{
+ int quit = SLKeyBoard_Quit;
+
+ SLang_Input_Buffer_Len = 0;
+ SLKeyBoard_Quit = 0;
+ while (SLsys_input_pending (0) > 0)
+ {
+ (void) SLsys_getkey ();
+ /* Set this to 0 because SLsys_getkey may stuff keyboard buffer if
+ * key sends key sequence (OS/2, DOS, maybe VMS).
+ */
+ SLang_Input_Buffer_Len = 0;
+ }
+ SLKeyBoard_Quit = quit;
+}
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+
+/* These routines are fast memcpy, memset routines. When available, I
+ use system rouines. For msdos, I use inline assembly. */
+
+/* The current versions only work in the forward direction only!! */
+
+#include "config.h"
+
+#include <stdio.h>
+#include "slang.h"
+#include "_slang.h"
+
+char *SLmemcpy(char *s1, char *s2, int n)
+{
+#if defined(msdos) && !defined(__WIN32__) && !defined(__GO32__)
+ asm mov ax, ds
+ asm mov bx, si
+ asm mov dx, di
+ asm mov cx, n
+ asm les di, s1
+ asm lds si, s2
+ asm cld
+ asm rep movsb
+ asm mov ds, ax
+ asm mov si, bx
+ asm mov di, dx
+ return(s1);
+
+#else
+ register char *smax, *s = s1;
+ int n2;
+
+ n2 = n % 4;
+ smax = s + (n - 4);
+ while (s <= smax)
+ {
+ *s = *s2; *(s + 1) = *(s2 + 1); *(s + 2) = *(s2 + 2); *(s + 3) = *(s2 + 3);
+ s += 4;
+ s2 += 4;
+ }
+ while (n2--) *s++ = *s2++;
+ return(s1);
+#endif
+}
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+
+/* These routines are fast memcpy, memset routines. When available, I
+ use system rouines. For msdos, I use inline assembly. */
+
+/* The current versions only work in the forward direction only!! */
+
+#include "config.h"
+
+#include <stdio.h>
+
+
+#include "slang.h"
+#include "_slang.h"
+
+void SLmemset(char *p, char space, int n)
+{
+#if defined(msdos) && !defined(__WIN32__) && !defined(__GO32__)
+ asm mov al, space
+ asm mov dx, di
+ asm mov cx, n
+ asm les di, p
+ asm cld
+ asm rep stosb
+ asm mov di, dx
+#else
+ register char *pmax;
+
+ pmax = p + (n - 4);
+ n = n % 4;
+ while (p <= pmax)
+ {
+ *p++ = space; *p++ = space; *p++ = space; *p++= space;
+ }
+ while (n--) *p++ = space;
+#endif
+}
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#define INCL_BASE
+#define INCL_NOPM
+#define INCL_VIO
+#define INCL_KBD
+#define INCL_DOS
+#if 0
+# define INCL_DOSSEMAPHORES
+#endif
+#ifdef LONG
+#undef LONG
+#endif
+#ifdef VOID
+#undef VOID
+#endif
+#include <os2.h>
+
+#include <signal.h>
+#include <process.h>
+
+KBDINFO initialKbdInfo; /* keyboard info */
+
+/* Code to read keystrokes in a separate thread */
+
+typedef struct kbdcodes {
+ UCHAR ascii;
+ UCHAR scan;
+/* USHORT shift; */
+} KBDCODES;
+
+#define BUFFER_LEN 4096
+static KBDCODES threadKeys[BUFFER_LEN];
+static int atEnd = 0;
+static int startBuf;
+static int endBuf;
+
+/* Original code used semaphores to control access to threadKeys.
+ * It is expected that the semaphore code will be deleted after 0.97.
+*/
+#if 0
+
+#ifdef __os2_16__
+
+typedef USHORT APIRET;
+static HSEM Hmtx;
+
+#define DosRequestMutexSem(hmtx,timeout) DosSemRequest(hmtx,timeout)
+#define DosReleaseMutexSem(hmtx) DosSemClear(hmtx)
+#define DosCloseMutexSem(hmtx) DosCloseSem(hmtx)
+
+#else /* !defined(__os2_16__) */
+
+static HMTX Hmtx; /* Mutex Semaphore */
+
+#endif
+
+
+static APIRET CreateSem(void)
+{
+#ifdef __os2_16__
+ char SemName[32];
+ sprintf(SemName, "\\SEM\\jed\\%u", getpid());
+ return ( DosCreateSem (0, &Hmtx, SemName) );
+#else
+ return ( DosCreateMutexSem (NULL, &Hmtx, 0, 0) );
+#endif
+}
+
+static APIRET RequestSem(void)
+{
+ return ( DosRequestMutexSem (Hmtx, -1) );
+}
+
+static APIRET ReleaseSem(void)
+{
+ return ( DosReleaseMutexSem (Hmtx) );
+}
+
+static APIRET CloseSem(void)
+{
+ return( DosCloseMutexSem (Hmtx) );
+}
+
+#else
+
+#define CreateSem()
+#define RequestSem()
+#define ReleaseSem()
+#define CloseSem()
+
+#endif
+
+
+static void set_kbd(void)
+{
+ KBDINFO kbdInfo;
+
+ kbdInfo = initialKbdInfo;
+ kbdInfo.fsMask &= ~0x0001; /* not echo on */
+ kbdInfo.fsMask |= 0x0002; /* echo off */
+ kbdInfo.fsMask &= ~0x0008; /* cooked mode off */
+ kbdInfo.fsMask |= 0x0004; /* raw mode */
+ kbdInfo.fsMask &= ~0x0100; /* shift report off */
+ KbdSetStatus(&kbdInfo, 0);
+}
+
+static void thread_getkey ()
+{
+ KBDKEYINFO keyInfo;
+ int n;
+
+ while (!atEnd) { /* at end is a flag */
+ set_kbd();
+ KbdCharIn(&keyInfo, IO_NOWAIT, 0); /* get a character */
+ if (keyInfo.fbStatus & 0x040) { /* found a char process it */
+ if (keyInfo.chChar == SLang_Abort_Char) {
+ if (SLang_Ignore_User_Abort == 0) SLang_Error = USER_BREAK;
+ SLKeyBoard_Quit = 1;
+ }
+ n = (endBuf + 1) % BUFFER_LEN;
+ if (n == startBuf) {
+ DosBeep (500, 20);
+ KbdFlushBuffer(0);
+ continue;
+ }
+ RequestSem();
+ threadKeys [n].ascii = keyInfo.chChar;
+ threadKeys [n].scan = keyInfo.chScan;
+/* threadKeys [n].shift = keyInfo.fsState; */
+ endBuf = n;
+ ReleaseSem();
+ } else /* no char available*/
+ DosSleep (20);
+ }
+}
+
+static void thread_code (void *Args)
+{
+ (void) Args;
+ startBuf = -1; /* initialize the buffer pointers */
+ endBuf = -1;
+ thread_getkey ();
+ atEnd = 0; /* reset the flag */
+ _endthread();
+}
+
+
+/* The code below is in the main thread */
+
+int SLang_init_tty(int abort_char, int dum2, int dum3)
+{
+ VIOCURSORINFO cursorInfo, OldcursorInfo;
+
+ (void) dum2; (void) dum3;
+ if (abort_char == -1) abort_char = 3; /* ^C */
+ SLang_Abort_Char = abort_char;
+
+ /* set ^C off */
+ signal (SIGINT, SIG_IGN);
+ signal (SIGBREAK, SIG_IGN);
+
+ /* set up the keyboard */
+
+ initialKbdInfo.cb = sizeof(initialKbdInfo);
+ KbdGetStatus(&initialKbdInfo, 0);
+ set_kbd();
+
+ /* open a semaphore */
+ CreateSem();
+
+ /* start a separate thread to read the keyboard */
+#if defined(__BORLANDC__)
+ _beginthread (thread_code, 8096, NULL);
+#else
+ _beginthread (thread_code, NULL, 8096, NULL);
+#endif
+
+ VioGetCurType (&OldcursorInfo, 0);
+ cursorInfo.yStart = 1;
+ cursorInfo.cEnd = 15;
+ cursorInfo.cx = 1;
+ cursorInfo.attr = 1;
+ if (VioSetCurType (&cursorInfo, 0))
+ VioSetCurType (&OldcursorInfo, 0); /* reset to previous value */
+
+ return 0;
+}
+
+void SLang_reset_tty (void)
+{
+ atEnd = 1; /* set flag and wait until thread ends */
+ while (atEnd) {DosSleep (0);}
+
+ CloseSem();
+
+ /* close the keyboard */
+ KbdSetStatus(&initialKbdInfo, 0); /* restore original state */
+}
+
+#define keyWaiting() (endBuf != startBuf)
+
+/* sleep for *tsecs tenths of a sec waiting for input */
+
+int SLsys_input_pending(int tsecs)
+{
+ int count = tsecs * 5;
+
+ if (count)
+ {
+ while(count > 0)
+ {
+ DosSleep(20); /* 20 ms or 1/50 sec */
+ if (keyWaiting ()) break;
+ count--;
+ }
+ return(count);
+ }
+ else return(keyWaiting ());
+}
+
+unsigned int SLsys_getkey ()
+{
+ unsigned int c;
+ unsigned char scan;
+
+ int tsecs = 300;
+
+ if (!keyWaiting())
+ while (!SLsys_input_pending(tsecs));
+
+ /* read codes from buffer */
+ RequestSem();
+ startBuf = (startBuf + 1) % BUFFER_LEN;
+ c = threadKeys [startBuf].ascii;
+ scan = threadKeys [startBuf].scan;
+ ReleaseSem();
+
+ if ((c == 8) && (scan == 0x0e)) c = 127;
+ if (c == 0xE0) c = 0;
+ if (c == 0) SLang_ungetkey (scan);
+ return (c);
+}
+
+
+void SLang_set_abort_signal (void (*dum)(int))
+{
+ (void) dum;
+}
--- /dev/null
+#include "config.h"
+
+#include <stdio.h>
+#include <signal.h>
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+/* This function will cause system calls to be restarted after signal if possible */
+SLSig_Fun_Type *SLsignal (int sig, SLSig_Fun_Type *f)
+{
+#ifdef SLANG_POSIX_SIGNALS
+ struct sigaction old_sa, new_sa;
+
+# ifdef SIGALRM
+ /* We want system calls to be interrupted by SIGALRM. */
+ if (sig == SIGALRM) return SLsignal_intr (sig, f);
+# endif
+
+ sigemptyset (&new_sa.sa_mask);
+ new_sa.sa_handler = f;
+
+ new_sa.sa_flags = 0;
+# ifdef SA_RESTART
+ new_sa.sa_flags |= SA_RESTART;
+# endif
+
+ if (-1 == sigaction (sig, &new_sa, &old_sa))
+ return (SLSig_Fun_Type *) SIG_ERR;
+
+ return old_sa.sa_handler;
+#else
+ /* Not POSIX. */
+ return signal (sig, f);
+#endif
+}
+
+/* This function will NOT cause system calls to be restarted after
+ * signal if possible
+ */
+SLSig_Fun_Type *SLsignal_intr (int sig, SLSig_Fun_Type *f)
+{
+#ifdef SLANG_POSIX_SIGNALS
+ struct sigaction old_sa, new_sa;
+
+ sigemptyset (&new_sa.sa_mask);
+ new_sa.sa_handler = f;
+
+ new_sa.sa_flags = 0;
+# ifdef SA_INTERRUPT
+ new_sa.sa_flags |= SA_INTERRUPT;
+# endif
+
+ if (-1 == sigaction (sig, &new_sa, &old_sa))
+ return (SLSig_Fun_Type *) SIG_ERR;
+
+ return old_sa.sa_handler;
+#else
+ /* Not POSIX. */
+ return signal (sig, f);
+#endif
+}
+
+
+/* We are primarily interested in blocking signals that would cause the
+ * application to reset the tty. These include suspend signals and
+ * possibly interrupt signals.
+ */
+#ifdef SLANG_POSIX_SIGNALS
+static sigset_t Old_Signal_Mask;
+#endif
+
+static volatile unsigned int Blocked_Depth;
+
+int SLsig_block_signals (void)
+{
+#ifdef SLANG_POSIX_SIGNALS
+ sigset_t new_mask;
+#endif
+
+ Blocked_Depth++;
+ if (Blocked_Depth != 1)
+ {
+ return 0;
+ }
+
+#ifdef SLANG_POSIX_SIGNALS
+ sigemptyset (&new_mask);
+# ifdef SIGQUIT
+ sigaddset (&new_mask, SIGQUIT);
+# endif
+# ifdef SIGTSTP
+ sigaddset (&new_mask, SIGTSTP);
+# endif
+# ifdef SIGINT
+ sigaddset (&new_mask, SIGINT);
+# endif
+# ifdef SIGTTIN
+ sigaddset (&new_mask, SIGTTIN);
+# endif
+# ifdef SIGTTOU
+ sigaddset (&new_mask, SIGTTOU);
+# endif
+
+ (void) sigprocmask (SIG_BLOCK, &new_mask, &Old_Signal_Mask);
+ return 0;
+#else
+ /* Not implemented. */
+ return -1;
+#endif
+}
+
+int SLsig_unblock_signals (void)
+{
+ if (Blocked_Depth == 0)
+ return -1;
+
+ Blocked_Depth--;
+
+ if (Blocked_Depth != 0)
+ return 0;
+
+#ifdef SLANG_POSIX_SIGNALS
+ (void) sigprocmask (SIG_SETMASK, &Old_Signal_Mask, NULL);
+ return 0;
+#else
+ return -1;
+#endif
+}
--- /dev/null
+/* SLang Screen management routines */
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+typedef struct Screen_Type
+ {
+ int n; /* number of chars written last time */
+ int flags; /* line untouched, etc... */
+ unsigned short *old, *neew;
+#ifndef pc_system
+ unsigned long old_hash, new_hash;
+#endif
+ }
+Screen_Type;
+
+#define TOUCHED 0x1
+#define TRASHED 0x2
+
+#ifndef pc_system
+#define MAX_SCREEN_SIZE 120
+#else
+#define MAX_SCREEN_SIZE 75
+#endif
+
+Screen_Type SL_Screen[MAX_SCREEN_SIZE];
+static int Start_Col, Start_Row;
+static int Screen_Cols, Screen_Rows;
+static int This_Row, This_Col;
+static int This_Color; /* only the first 8 bits of this
+ * are used. The highest bit is used
+ * to indicate an alternate character
+ * set. This leaves 127 userdefineable
+ * color combination.
+ */
+
+#ifndef pc_system
+#define ALT_CHAR_FLAG 0x80
+#else
+#define ALT_CHAR_FLAG 0x00
+#endif
+
+int SLsmg_Newline_Moves = 0;
+int SLsmg_Backspace_Moves = 0;
+
+static void blank_line (unsigned short *p, int n, unsigned char ch)
+{
+ register unsigned short *pmax = p + n;
+ register unsigned short color_ch;
+
+ color_ch = (This_Color << 8) | (unsigned short) ch;
+
+ while (p < pmax)
+ {
+ *p++ = color_ch;
+ }
+}
+
+
+static void clear_region (int row, int n)
+{
+ int i;
+ int imax = row + n;
+
+ if (imax > Screen_Rows) imax = Screen_Rows;
+ for (i = row; i < imax; i++)
+ {
+ if (i >= 0)
+ {
+ blank_line (SL_Screen[i].neew, Screen_Cols, ' ');
+ SL_Screen[i].flags |= TOUCHED;
+ }
+ }
+}
+
+void SLsmg_erase_eol (void)
+{
+ int r, c;
+
+ c = This_Col - Start_Col;
+ r = This_Row - Start_Row;
+
+ if ((r < 0) || (r >= Screen_Rows)) return;
+ if (c < 0) c = 0; else if (c >= Screen_Cols) return;
+ blank_line (SL_Screen[This_Row].neew + c , Screen_Cols - c, ' ');
+ SL_Screen[This_Row].flags |= TOUCHED;
+}
+
+static void scroll_up (void)
+{
+ unsigned int i, imax;
+ unsigned short *neew;
+
+ neew = SL_Screen[0].neew;
+ imax = Screen_Rows - 1;
+ for (i = 0; i < imax; i++)
+ {
+ SL_Screen[i].neew = SL_Screen[i + 1].neew;
+ SL_Screen[i].flags |= TOUCHED;
+ }
+ SL_Screen[i].neew = neew;
+ SL_Screen[i].flags |= TOUCHED;
+ blank_line (neew, Screen_Cols, ' ');
+ This_Row--;
+}
+
+
+
+
+void SLsmg_gotorc (int r, int c)
+{
+ This_Row = r;
+ This_Col = c;
+}
+
+int SLsmg_get_row (void)
+{
+ return This_Row;
+}
+
+int SLsmg_get_column (void)
+{
+ return This_Col;
+}
+
+void SLsmg_erase_eos (void)
+{
+ SLsmg_erase_eol ();
+ clear_region (This_Row + 1, Screen_Rows);
+}
+
+static int This_Alt_Char;
+
+#ifndef pc_system
+void SLsmg_set_char_set (int i)
+{
+ if (SLtt_Use_Blink_For_ACS) return; /* alt chars not used and the alt bit
+ * is used to indicate a blink.
+ */
+ if (i) This_Alt_Char = ALT_CHAR_FLAG;
+ else This_Alt_Char = 0;
+
+ This_Color &= 0x7F;
+ This_Color |= This_Alt_Char;
+}
+#endif
+
+void SLsmg_set_color (int color)
+{
+ if (color < 0) return;
+ This_Color = color | This_Alt_Char;
+}
+
+
+void SLsmg_reverse_video (void)
+{
+ SLsmg_set_color (1);
+}
+
+
+void SLsmg_normal_video (void)
+{
+ This_Color = This_Alt_Char; /* reset video but NOT char set. */
+}
+
+
+static int point_visible (int col_too)
+{
+ return ((This_Row >= Start_Row) && (This_Row < Start_Row + Screen_Rows)
+ && ((col_too == 0)
+ || ((This_Col >= Start_Col)
+ && (This_Col < Start_Col + Screen_Cols))));
+}
+
+void SLsmg_printf (char *fmt, ...)
+{
+ char p[1000];
+ va_list ap;
+
+ va_start(ap, fmt);
+ (void) vsprintf(p, fmt, ap);
+ va_end(ap);
+
+ SLsmg_write_string (p);
+}
+
+void SLsmg_write_string (char *str)
+{
+ SLsmg_write_nchars (str, strlen (str));
+}
+
+void SLsmg_write_nstring (char *str, int n)
+{
+ int width;
+ char blank = ' ';
+ if (str == NULL) width = 0;
+ else
+ {
+ width = strlen (str);
+ if (width > n) width = n;
+ SLsmg_write_nchars (str, width);
+ }
+ while (width++ < n) SLsmg_write_nchars (&blank, 1);
+}
+
+void SLsmg_write_wrapped_string (char *s, int r, int c, int dr, int dc, int fill)
+{
+ register char ch, *p;
+ int maxc = dc;
+
+ if ((dr == 0) || (dc == 0)) return;
+ p = s;
+ dc = 0;
+ while (1)
+ {
+ ch = *p++;
+ if ((ch == 0) || (ch == '\n'))
+ {
+ int diff;
+
+ diff = maxc - dc;
+
+ SLsmg_gotorc (r, c);
+ SLsmg_write_nchars (s, dc);
+ if (fill && (diff > 0))
+ {
+ while (diff--) SLsmg_write_char (' ');
+ }
+ if ((ch == 0) || (dr == 1)) break;
+
+ r++;
+ dc = 0;
+ dr--;
+ s = p;
+ }
+ else if (dc == maxc)
+ {
+ SLsmg_gotorc (r, c);
+ SLsmg_write_nchars (s, dc + 1);
+ if (dr == 1) break;
+
+ r++;
+ dc = 0;
+ dr--;
+ s = p;
+ }
+ else dc++;
+ }
+}
+
+
+
+int SLsmg_Tab_Width = 8;
+
+/* Minimum value for which eight bit char is displayed as is. */
+
+#ifndef pc_system
+int SLsmg_Display_Eight_Bit = 160;
+static unsigned char Alt_Char_Set[129];/* 129th is used as a flag */
+#else
+int SLsmg_Display_Eight_Bit = 128;
+#endif
+
+void SLsmg_write_nchars (char *str, int n)
+{
+ register unsigned short *p, old, neew, color;
+ unsigned char ch;
+ unsigned int flags;
+ int len, start_len, max_len;
+ char *str_max;
+ int newline_flag;
+#ifndef pc_system
+ int alt_char_set_flag;
+
+ alt_char_set_flag = ((SLtt_Use_Blink_For_ACS == 0)
+ && (This_Color & ALT_CHAR_FLAG));
+#endif
+
+ str_max = str + n;
+ color = This_Color << 8;
+
+ top: /* get here only on newline */
+
+ newline_flag = 0;
+ start_len = Start_Col;
+
+ if (point_visible (0) == 0) return;
+
+ len = This_Col;
+ max_len = start_len + Screen_Cols;
+
+ p = SL_Screen[This_Row].neew;
+ if (len > start_len) p += (len - start_len);
+
+ flags = SL_Screen[This_Row].flags;
+ while ((len < max_len) && (str < str_max))
+ {
+ ch = (unsigned char) *str++;
+
+#ifndef pc_system
+ if (alt_char_set_flag)
+ ch = Alt_Char_Set [ch & 0x7F];
+#endif
+ if (((ch >= ' ') && (ch < 127))
+ || (ch >= (unsigned char) SLsmg_Display_Eight_Bit)
+#ifndef pc_system
+ || alt_char_set_flag
+#endif
+ )
+ {
+ len += 1;
+ if (len > start_len)
+ {
+ old = *p;
+ neew = color | (unsigned short) ch;
+ if (old != neew)
+ {
+ flags |= TOUCHED;
+ *p = neew;
+ }
+ p++;
+ }
+ }
+
+ else if ((ch == '\t') && (SLsmg_Tab_Width > 0))
+ {
+ n = len;
+ n += SLsmg_Tab_Width;
+ n = SLsmg_Tab_Width - (n % SLsmg_Tab_Width);
+ if (len + n > max_len) n = max_len - len;
+ neew = color | (unsigned short) ' ';
+ while (n--)
+ {
+ len += 1;
+ if (len > start_len)
+ {
+ if (*p != neew)
+ {
+ flags |= TOUCHED;
+ *p = neew;
+ }
+ p++;
+ }
+ }
+ }
+ else if (ch == '\n')
+ {
+ newline_flag = 1;
+ break;
+ }
+ else if ((ch == 0x8) && SLsmg_Backspace_Moves)
+ {
+ if (len != 0) len--;
+ }
+ else
+ {
+ if (ch & 0x80)
+ {
+ neew = color | (unsigned short) '~';
+ len += 1;
+ if (len > start_len)
+ {
+ if (*p != neew)
+ {
+ *p = neew;
+ flags |= TOUCHED;
+ }
+ p++;
+ if (len == max_len) break;
+ ch &= 0x7F;
+ }
+ }
+
+ len += 1;
+ if (len > start_len)
+ {
+ neew = color | (unsigned short) '^';
+ if (*p != neew)
+ {
+ *p = neew;
+ flags |= TOUCHED;
+ }
+ p++;
+ if (len == max_len) break;
+ }
+
+ if (ch == 127) ch = '?'; else ch = ch + '@';
+ len++;
+ if (len > start_len)
+ {
+ neew = color | (unsigned short) ch;
+ if (*p != neew)
+ {
+ *p = neew;
+ flags |= TOUCHED;
+ }
+ p++;
+ }
+ }
+ }
+
+ SL_Screen[This_Row].flags = flags;
+ This_Col = len;
+
+ if (SLsmg_Newline_Moves == 0)
+ return;
+
+ if (newline_flag == 0)
+ {
+ while (str < str_max)
+ {
+ if (*str == '\n') break;
+ str++;
+ }
+ if (str == str_max) return;
+ str++;
+ }
+
+ This_Row++;
+ This_Col = 0;
+ if (This_Row == Start_Row + Screen_Rows)
+ {
+ if (SLsmg_Newline_Moves > 0) scroll_up ();
+ }
+ goto top;
+}
+
+
+void SLsmg_write_char (char ch)
+{
+ SLsmg_write_nchars (&ch, 1);
+}
+
+static int Cls_Flag;
+
+
+void SLsmg_cls (void)
+{
+ This_Color = 0;
+ clear_region (0, Screen_Rows);
+ This_Color = This_Alt_Char;
+ Cls_Flag = 1;
+}
+#if 0
+static void do_copy (unsigned short *a, unsigned short *b)
+{
+ unsigned short *amax = a + Screen_Cols;
+
+ while (a < amax) *a++ = *b++;
+}
+#endif
+
+#ifndef pc_system
+int SLsmg_Scroll_Hash_Border = 0;
+static unsigned long compute_hash (unsigned short *s, int n)
+{
+ register unsigned long h = 0, g;
+ register unsigned long sum = 0;
+ register unsigned short *smax, ch;
+ int is_blank = 2;
+
+ s += SLsmg_Scroll_Hash_Border;
+ smax = s + (n - SLsmg_Scroll_Hash_Border);
+ while (s < smax)
+ {
+ ch = *s++;
+ if (is_blank && ((ch & 0xFF) != 32)) is_blank--;
+
+ sum += ch;
+
+ h = sum + (h << 3);
+ if ((g = h & 0xE0000000UL) != 0)
+ {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+ }
+ if (is_blank) return 0;
+ return h;
+}
+
+static unsigned long Blank_Hash;
+
+static void try_scroll (void)
+{
+ int i, j, di, r1, r2, rmin, rmax;
+ unsigned long hash;
+ int color, did_scroll = 0;
+ unsigned short *tmp;
+ int ignore;
+
+ /* find region limits. */
+
+ for (rmax = Screen_Rows - 1; rmax > 0; rmax--)
+ {
+ if (SL_Screen[rmax].new_hash != SL_Screen[rmax].old_hash)
+ {
+ r1 = rmax - 1;
+ if ((r1 == 0)
+ || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
+ break;
+
+ rmax = r1;
+ }
+ }
+
+ for (rmin = 0; rmin < rmax; rmin++)
+ {
+ if (SL_Screen[rmin].new_hash != SL_Screen[rmin].old_hash)
+ {
+ r1 = rmin + 1;
+ if ((r1 == rmax)
+ || (SL_Screen[r1].new_hash != SL_Screen[r1].old_hash))
+ break;
+
+ rmin = r1;
+ }
+ }
+
+
+ for (i = rmax; i > rmin; i--)
+ {
+ hash = SL_Screen[i].new_hash;
+ if (hash == Blank_Hash) continue;
+
+ if ((hash == SL_Screen[i].old_hash)
+ || ((i + 1 < Screen_Rows) && (hash == SL_Screen[i + 1].old_hash))
+ || ((i - 1 > rmin) && (SL_Screen[i].old_hash == SL_Screen[i - 1].new_hash)))
+ continue;
+
+ for (j = i - 1; j >= rmin; j--)
+ {
+ if (hash == SL_Screen[j].old_hash) break;
+ }
+ if (j < rmin) continue;
+
+ r2 = i; /* end scroll region */
+
+ di = i - j;
+ j--;
+ ignore = 0;
+ while ((j >= rmin) && (SL_Screen[j].old_hash == SL_Screen[j + di].new_hash))
+ {
+ if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
+ j--;
+ }
+ r1 = j + 1;
+
+ /* If this scroll only scrolls this line into place, don't do it.
+ */
+ if ((di > 1) && (r1 + di + ignore == r2)) continue;
+
+ /* If there is anything in the scrolling region that is ok, abort the
+ * scroll.
+ */
+
+ for (j = r1; j <= r2; j++)
+ {
+ if ((SL_Screen[j].old_hash != Blank_Hash)
+ && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
+ {
+ /* See if the scroll is happens to scroll this one into place. */
+ if ((j + di > r2) || (SL_Screen[j].old_hash != SL_Screen[j + di].new_hash))
+ break;
+ }
+ }
+ if (j <= r2) continue;
+
+ color = This_Color; This_Color = 0;
+ did_scroll = 1;
+ SLtt_normal_video ();
+ SLtt_set_scroll_region (r1, r2);
+ SLtt_goto_rc (0, 0);
+ SLtt_reverse_index (di);
+ SLtt_reset_scroll_region ();
+ /* Now we have a hole in the screen. Make the virtual screen look
+ * like it.
+ */
+ for (j = r1; j <= r2; j++) SL_Screen[j].flags = TOUCHED;
+
+ while (di--)
+ {
+ tmp = SL_Screen[r2].old;
+ for (j = r2; j > r1; j--)
+ {
+ SL_Screen[j].old = SL_Screen[j - 1].old;
+ SL_Screen[j].old_hash = SL_Screen[j - 1].old_hash;
+ }
+ SL_Screen[r1].old = tmp;
+ blank_line (SL_Screen[r1].old, Screen_Cols, ' ');
+ SL_Screen[r1].old_hash = Blank_Hash;
+ r1++;
+ }
+ This_Color = color;
+ }
+ if (did_scroll) return;
+
+ /* Try other direction */
+
+ for (i = rmin; i < rmax; i++)
+ {
+ hash = SL_Screen[i].new_hash;
+ if (hash == Blank_Hash) continue;
+ if (hash == SL_Screen[i].old_hash) continue;
+
+ /* find a match further down screen */
+ for (j = i + 1; j <= rmax; j++)
+ {
+ if (hash == SL_Screen[j].old_hash) break;
+ }
+ if (j > rmax) continue;
+
+ r1 = i; /* beg scroll region */
+ di = j - i; /* number of lines to scroll */
+ j++; /* since we know this is a match */
+
+ /* find end of scroll region */
+ ignore = 0;
+ while ((j <= rmax) && (SL_Screen[j].old_hash == SL_Screen[j - di].new_hash))
+ {
+ if (SL_Screen[j].old_hash == Blank_Hash) ignore++;
+ j++;
+ }
+ r2 = j - 1; /* end of scroll region */
+
+ /* If this scroll only scrolls this line into place, don't do it.
+ */
+ if ((di > 1) && (r1 + di + ignore == r2)) continue;
+
+ /* If there is anything in the scrolling region that is ok, abort the
+ * scroll.
+ */
+
+ for (j = r1; j <= r2; j++)
+ {
+ if ((SL_Screen[j].old_hash != Blank_Hash)
+ && (SL_Screen[j].old_hash == SL_Screen[j].new_hash))
+ {
+ if ((j - di < r1) || (SL_Screen[j].old_hash != SL_Screen[j - di].new_hash))
+ break;
+ }
+
+ }
+ if (j <= r2) continue;
+
+ color = This_Color; This_Color = 0;
+ SLtt_normal_video ();
+ SLtt_set_scroll_region (r1, r2);
+ SLtt_goto_rc (0, 0); /* relative to scroll region */
+ SLtt_delete_nlines (di);
+ SLtt_reset_scroll_region ();
+ /* Now we have a hole in the screen. Make the virtual screen look
+ * like it.
+ */
+ for (j = r1; j <= r2; j++) SL_Screen[j].flags = TOUCHED;
+
+ while (di--)
+ {
+ tmp = SL_Screen[r1].old;
+ for (j = r1; j < r2; j++)
+ {
+ SL_Screen[j].old = SL_Screen[j + 1].old;
+ SL_Screen[j].old_hash = SL_Screen[j + 1].old_hash;
+ }
+ SL_Screen[r2].old = tmp;
+ blank_line (SL_Screen[r2].old, Screen_Cols, ' ');
+ SL_Screen[r2].old_hash = Blank_Hash;
+ r2--;
+ }
+ This_Color = color;
+ }
+}
+
+#endif /* NOT pc_system */
+
+
+
+static int Smg_Inited;
+
+void SLsmg_refresh (void)
+{
+ int i;
+
+ if (Smg_Inited == 0) return;
+#ifndef pc_system
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ if (SL_Screen[i].flags == 0) continue;
+ SL_Screen[i].new_hash = compute_hash (SL_Screen[i].neew, Screen_Cols);
+ }
+#endif
+
+ if (Cls_Flag)
+ {
+ SLtt_normal_video (); SLtt_cls ();
+ }
+#ifndef pc_system
+ else if (SLtt_Term_Cannot_Scroll == 0) try_scroll ();
+#endif
+
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ int trashed;
+
+ if (SL_Screen[i].flags == 0) continue;
+
+ if (SL_Screen[i].flags & TRASHED)
+ {
+ SLtt_goto_rc (i, -1); /* Force cursor to move */
+ SLtt_goto_rc (i, 0);
+ if (Cls_Flag == 0) SLtt_del_eol ();
+ trashed = 1;
+ }
+ else trashed = 0;
+
+ if (Cls_Flag || trashed)
+ {
+ int color = This_Color;
+ This_Color = 0;
+ blank_line (SL_Screen[i].old, Screen_Cols, ' ');
+ This_Color = color;
+ }
+
+ SL_Screen[i].old[Screen_Cols] = 0;
+ SL_Screen[i].neew[Screen_Cols] = 0;
+
+ SLtt_smart_puts (SL_Screen[i].neew, SL_Screen[i].old, Screen_Cols, i);
+
+ SLMEMCPY ((char *) SL_Screen[i].old, (char *) SL_Screen[i].neew,
+ Screen_Cols * sizeof (short));
+
+ SL_Screen[i].flags = 0;
+#ifndef pc_system
+ SL_Screen[i].old_hash = SL_Screen[i].new_hash;
+#endif
+ }
+
+ if (point_visible (1)) SLtt_goto_rc (This_Row - Start_Row, This_Col - Start_Col);
+ SLtt_flush_output ();
+ Cls_Flag = 0;
+}
+
+static int compute_clip (int row, int n, int box_start, int box_end,
+ int *rmin, int *rmax)
+{
+ int row_max;
+
+ if (n < 0) return 0;
+ if (row >= box_end) return 0;
+ row_max = row + n;
+ if (row_max <= box_start) return 0;
+
+ if (row < box_start) row = box_start;
+ if (row_max >= box_end) row_max = box_end;
+ *rmin = row;
+ *rmax = row_max;
+ return 1;
+}
+
+void SLsmg_touch_lines (int row, int n)
+{
+ int i;
+ int r1, r2;
+
+ if (0 == compute_clip (row, n, Start_Row, Start_Row + Screen_Rows, &r1, &r2))
+ return;
+
+ r1 -= Start_Row;
+ r2 -= Start_Row;
+ for (i = r1; i < r2; i++)
+ {
+ SL_Screen[i].flags |= TRASHED;
+ }
+}
+
+#ifndef pc_system
+static char Fake_Alt_Char_Pairs [] = "a:j+k+l+m+q-t+u+v+w+x|";
+
+static void init_alt_char_set (void)
+{
+ int i;
+ unsigned char *p, *pmax, ch;
+
+ if (Alt_Char_Set[128] == 128) return;
+
+ i = 32;
+ memset ((char *)Alt_Char_Set, ' ', i);
+ while (i <= 128)
+ {
+ Alt_Char_Set [i] = i;
+ i++;
+ }
+
+ /* Map to VT100 */
+ if (SLtt_Has_Alt_Charset)
+ {
+ p = (unsigned char *) SLtt_Graphics_Char_Pairs;
+ if (p == NULL) return;
+ }
+ else p = (unsigned char *) Fake_Alt_Char_Pairs;
+ pmax = p + strlen ((char *) p);
+
+ /* Some systems have messed up entries for this */
+ while (p < pmax)
+ {
+ ch = *p++;
+ ch &= 0x7F; /* should be unnecessary */
+ Alt_Char_Set [ch] = *p;
+ p++;
+ }
+}
+#endif
+
+#ifndef pc_system
+# define BLOCK_SIGNALS SLsig_block_signals ();
+# define UNBLOCK_SIGNALS SLsig_unblock_signals ();
+#else
+# define BLOCK_SIGNALS
+# define UNBLOCK_SIGNALS
+#endif
+
+static int Smg_Suspended;
+void SLsmg_suspend_smg (void)
+{
+ BLOCK_SIGNALS
+
+ if (Smg_Suspended == 0)
+ {
+ SLtt_reset_video ();
+ Smg_Suspended = 1;
+ }
+
+ UNBLOCK_SIGNALS
+}
+
+void SLsmg_resume_smg (void)
+{
+ int i;
+ BLOCK_SIGNALS
+
+ if (Smg_Suspended == 0)
+ {
+ UNBLOCK_SIGNALS
+ return;
+ }
+
+ Smg_Suspended = 0;
+ SLtt_init_video ();
+ Cls_Flag = 1;
+ for (i = 0; i < Screen_Rows; i++)
+ SL_Screen[i].flags |= TRASHED;
+ SLsmg_refresh ();
+
+ UNBLOCK_SIGNALS
+}
+
+int SLsmg_init_smg (void)
+{
+ int i, len;
+ unsigned short *old, *neew;
+ BLOCK_SIGNALS
+
+ if (Smg_Inited) SLsmg_reset_smg ();
+ SLtt_init_video ();
+ Screen_Cols = SLtt_Screen_Cols;
+ Screen_Rows = SLtt_Screen_Rows;
+ This_Col = This_Row = Start_Col = Start_Row = 0;
+
+ This_Color = 0;
+ This_Alt_Char = 0;
+ Cls_Flag = 1;
+#ifndef pc_system
+ init_alt_char_set ();
+#endif
+ len = Screen_Cols + 3;
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ if ((NULL == (old = (unsigned short *) SLMALLOC (sizeof(short) * len)))
+ || ((NULL == (neew = (unsigned short *) SLMALLOC (sizeof(short) * len)))))
+ {
+ SLang_Error = SL_MALLOC_ERROR;
+ UNBLOCK_SIGNALS
+ return 0;
+ }
+ blank_line (old, len, ' ');
+ blank_line (neew, len, ' ');
+ SL_Screen[i].old = old;
+ SL_Screen[i].neew = neew;
+ SL_Screen[i].flags = 0;
+#ifndef pc_system
+ Blank_Hash = compute_hash (old, Screen_Cols);
+ SL_Screen[i].new_hash = SL_Screen[i].old_hash = Blank_Hash;
+#endif
+ }
+ Smg_Inited = 1;
+ UNBLOCK_SIGNALS
+ return 1;
+}
+
+
+void SLsmg_reset_smg (void)
+{
+ int i;
+ BLOCK_SIGNALS
+
+ if (Smg_Inited == 0)
+ {
+ UNBLOCK_SIGNALS
+ return;
+ }
+ for (i = 0; i < Screen_Rows; i++)
+ {
+ if (SL_Screen[i].old != NULL) SLFREE (SL_Screen[i].old);
+ if (SL_Screen[i].neew != NULL) SLFREE (SL_Screen[i].neew);
+ SL_Screen[i].old = SL_Screen[i].neew = NULL;
+ }
+ SLtt_reset_video ();
+ This_Alt_Char = This_Color = 0;
+ Smg_Inited = 0;
+
+ UNBLOCK_SIGNALS
+}
+
+
+unsigned short SLsmg_char_at (void)
+{
+ if (point_visible (1))
+ {
+ return SL_Screen[This_Row - Start_Row].neew[This_Col - Start_Col];
+ }
+ return 0;
+}
+
+
+void SLsmg_vprintf (char *fmt, va_list ap)
+{
+ char p[1000];
+
+ (void) vsprintf(p, fmt, ap);
+
+ SLsmg_write_string (p);
+}
+
+void SLsmg_set_screen_start (int *r, int *c)
+{
+ int or = Start_Row, oc = Start_Col;
+
+ if (c == NULL) Start_Col = 0;
+ else
+ {
+ Start_Col = *c;
+ *c = oc;
+ }
+ if (r == NULL) Start_Row = 0;
+ else
+ {
+ Start_Row = *r;
+ *r = or;
+ }
+}
+
+void SLsmg_draw_object (int r, int c, unsigned char object)
+{
+ This_Row = r; This_Col = c;
+
+ if (point_visible (1))
+ {
+ int color = This_Color;
+ This_Color |= ALT_CHAR_FLAG;
+ SLsmg_write_char (object);
+ This_Color = color;
+ }
+
+ This_Col = c + 1;
+}
+
+void SLsmg_draw_hline (int n)
+{
+ static unsigned char hbuf[16];
+ int count;
+ int cmin, cmax;
+ int final_col = This_Col + n;
+ int save_color;
+
+ if ((This_Row < Start_Row) || (This_Row >= Start_Row + Screen_Rows)
+ || (0 == compute_clip (This_Col, n, Start_Col, Start_Col + Screen_Cols,
+ &cmin, &cmax)))
+ {
+ This_Col = final_col;
+ return;
+ }
+
+ if (hbuf[0] == 0)
+ {
+ SLMEMSET ((char *) hbuf, SLSMG_HLINE_CHAR, 16);
+ }
+
+ n = cmax - cmin;
+ count = n / 16;
+
+ save_color = This_Color;
+ This_Color |= ALT_CHAR_FLAG;
+ This_Col = cmin;
+
+ SLsmg_write_nchars ((char *) hbuf, n % 16);
+ while (count-- > 0)
+ {
+ SLsmg_write_nchars ((char *) hbuf, 16);
+ }
+
+ This_Color = save_color;
+ This_Col = final_col;
+}
+
+void SLsmg_draw_vline (int n)
+{
+ unsigned char ch = SLSMG_VLINE_CHAR;
+ int c = This_Col, rmin, rmax;
+ int final_row = This_Row + n;
+ int save_color;
+
+ if (((c < Start_Col) || (c >= Start_Col + Screen_Cols)) ||
+ (0 == compute_clip (This_Row, n, Start_Row, Start_Row + Screen_Rows,
+ &rmin, &rmax)))
+ {
+ This_Row = final_row;
+ return;
+ }
+
+ save_color = This_Color;
+ This_Color |= ALT_CHAR_FLAG;
+
+ for (This_Row = rmin; This_Row < rmax; This_Row++)
+ {
+ This_Col = c;
+ SLsmg_write_nchars ((char *) &ch, 1);
+ }
+
+ This_Col = c; This_Row = final_row;
+ This_Color = save_color;
+}
+
+void SLsmg_draw_box (int r, int c, int dr, int dc)
+{
+ if (!dr || !dc) return;
+ This_Row = r; This_Col = c;
+ dr--; dc--;
+ SLsmg_draw_hline (dc);
+ SLsmg_draw_vline (dr);
+ This_Row = r; This_Col = c;
+ SLsmg_draw_vline (dr);
+ SLsmg_draw_hline (dc);
+ SLsmg_draw_object (r, c, SLSMG_ULCORN_CHAR);
+ SLsmg_draw_object (r, c + dc, SLSMG_URCORN_CHAR);
+ SLsmg_draw_object (r + dr, c, SLSMG_LLCORN_CHAR);
+ SLsmg_draw_object (r + dr, c + dc, SLSMG_LRCORN_CHAR);
+ This_Row = r; This_Col = c;
+}
+
+void SLsmg_fill_region (int r, int c, int dr, int dc, unsigned char ch)
+{
+ static unsigned char hbuf[16];
+ int count;
+ int dcmax, rmax;
+
+
+ if ((dc < 0) || (dr < 0)) return;
+
+ SLsmg_gotorc (r, c);
+ r = This_Row; c = This_Col;
+
+ dcmax = Screen_Cols - This_Col;
+ if (dc > dcmax) dc = dcmax;
+
+ rmax = This_Row + dr;
+ if (rmax > Screen_Rows) rmax = Screen_Rows;
+
+#if 0
+ ch = Alt_Char_Set[ch];
+#endif
+ if (ch != hbuf[0]) SLMEMSET ((char *) hbuf, (char) ch, 16);
+
+ for (This_Row = r; This_Row < rmax; This_Row++)
+ {
+ This_Col = c;
+ count = dc / 16;
+ SLsmg_write_nchars ((char *) hbuf, dc % 16);
+ while (count-- > 0)
+ {
+ SLsmg_write_nchars ((char *) hbuf, 16);
+ }
+ }
+
+ This_Row = r;
+}
+
+void SLsmg_forward (int n)
+{
+ This_Col += n;
+}
+
+void SLsmg_write_color_chars (unsigned short *s, unsigned int len)
+{
+ unsigned short *smax, sh;
+ char buf[32], *b, *bmax;
+ int color, save_color;
+
+ smax = s + len;
+ b = buf;
+ bmax = b + sizeof (buf);
+
+ save_color = This_Color;
+
+ while (s < smax)
+ {
+ sh = *s++;
+
+ color = sh >> 8;
+ if ((color != This_Color) || (b == bmax))
+ {
+ if (b != buf)
+ {
+ SLsmg_write_nchars (buf, (int) (b - buf));
+ b = buf;
+ }
+ This_Color = color;
+ }
+ *b++ = (char) (sh & 0xFF);
+ }
+
+ if (b != buf)
+ SLsmg_write_nchars (buf, (int) (b - buf));
+
+ This_Color = save_color;
+}
+
+unsigned int SLsmg_read_raw (unsigned short *buf, unsigned int len)
+{
+ unsigned int r, c;
+
+ if (0 == point_visible (1)) return 0;
+
+ r = (unsigned int) (This_Row - Start_Row);
+ c = (unsigned int) (This_Col - Start_Col);
+
+ if (c + len > (unsigned int) Screen_Cols)
+ len = (unsigned int) Screen_Cols - c;
+
+ memcpy ((char *) buf, (char *) (SL_Screen[r].neew + c), len * sizeof (short));
+ return len;
+}
+
+unsigned int SLsmg_write_raw (unsigned short *buf, unsigned int len)
+{
+ unsigned int r, c;
+ unsigned short *dest;
+
+ if (0 == point_visible (1)) return 0;
+
+ r = (unsigned int) (This_Row - Start_Row);
+ c = (unsigned int) (This_Col - Start_Col);
+
+ if (c + len > (unsigned int) Screen_Cols)
+ len = (unsigned int) Screen_Cols - c;
+
+ dest = SL_Screen[r].neew + c;
+
+ if (0 != memcmp ((char *) dest, (char *) buf, len * sizeof (short)))
+ {
+ memcpy ((char *) dest, (char *) buf, len * sizeof (short));
+ SL_Screen[r].flags |= TOUCHED;
+ }
+ return len;
+}
--- /dev/null
+/* This file contains enough terminfo reading capabilities sufficient for
+ * the slang SLtt interface.
+ */
+
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifndef USE_SETUPTERM
+#include "slang.h"
+#include "_slang.h"
+
+/*
+ * The majority of the comments found in the file were taken from the
+ * term(4) man page on an SGI.
+ */
+
+/* Short integers are stored in two 8-bit bytes. The first byte contains
+ * the least significant 8 bits of the value, and the second byte contains
+ * the most significant 8 bits. (Thus, the value represented is
+ * 256*second+first.) The value -1 is represented by 0377,0377, and the
+ * value -2 is represented by 0376,0377; other negative values are illegal.
+ * The -1 generally means that a capability is missing from this terminal.
+ * The -2 means that the capability has been cancelled in the terminfo
+ * source and also is to be considered missing.
+ */
+
+static int make_integer (unsigned char *buf)
+{
+ register int lo, hi;
+ lo = (int) *buf++; hi = (int) *buf;
+ if (hi == 0377)
+ {
+ if (lo == 0377) return -1;
+ if (lo == 0376) return -2;
+ }
+ return lo + 256 * hi;
+}
+
+/*
+ * The compiled file is created from the source file descriptions of the
+ * terminals (see the -I option of infocmp) by using the terminfo compiler,
+ * tic, and read by the routine setupterm [see curses(3X).] The file is
+ * divided into six parts in the following order: the header, terminal
+ * names, boolean flags, numbers, strings, and string table.
+ *
+ * The header section begins the file. This section contains six short
+ * integers in the format described below. These integers are (1) the magic
+ * number (octal 0432); (2) the size, in bytes, of the names section; (3)
+ * the number of bytes in the boolean section; (4) the number of short
+ * integers in the numbers section; (5) the number of offsets (short
+ * integers) in the strings section; (6) the size, in bytes, of the string
+ * table.
+ */
+
+#define MAGIC 0432
+
+/* In this structure, all char * fields are malloced EXCEPT if the
+ * structure is SLTERMCAP. In that case, only terminal_names is malloced
+ * and the other fields are pointers into it.
+ */
+typedef struct
+{
+#define SLTERMINFO 1
+#define SLTERMCAP 2
+ unsigned int flags;
+
+ unsigned int name_section_size;
+ char *terminal_names;
+
+ unsigned int boolean_section_size;
+ unsigned char *boolean_flags;
+
+ unsigned int num_numbers;
+ unsigned char *numbers;
+
+ unsigned int num_string_offsets;
+ unsigned char *string_offsets;
+
+ unsigned int string_table_size;
+ char *string_table;
+
+} Terminfo_Type;
+
+static char *tcap_getstr (char *, Terminfo_Type *);
+static int tcap_getnum (char *, Terminfo_Type *);
+static int tcap_getflag (char *, Terminfo_Type *);
+static int tcap_getent (char *, Terminfo_Type *);
+
+static FILE *open_terminfo (char *file, Terminfo_Type *h)
+{
+ FILE *fp;
+ unsigned char buf[12];
+
+ fp = fopen (file, "rb");
+ if (fp == NULL) return NULL;
+
+ if ((12 == fread ((char *) buf, 1, 12, fp) && (MAGIC == make_integer (buf))))
+ {
+ h->name_section_size = make_integer (buf + 2);
+ h->boolean_section_size = make_integer (buf + 4);
+ h->num_numbers = make_integer (buf + 6);
+ h->num_string_offsets = make_integer (buf + 8);
+ h->string_table_size = make_integer (buf + 10);
+ }
+ else
+ {
+ fclose (fp);
+ fp = NULL;
+ }
+ return fp;
+}
+
+/*
+ * The terminal names section comes next. It contains the first line of the
+ * terminfo description, listing the various names for the terminal,
+ * separated by the bar ( | ) character (see term(5)). The section is
+ * terminated with an ASCII NUL character.
+ */
+
+/* returns pointer to malloced space */
+static unsigned char *read_terminfo_section (FILE *fp, unsigned int size)
+{
+ char *s;
+
+ if (NULL == (s = (char *) SLMALLOC (size))) return NULL;
+ if (size != fread (s, 1, size, fp))
+ {
+ SLFREE (s);
+ return NULL;
+ }
+ return (unsigned char *) s;
+}
+
+static char *read_terminal_names (FILE *fp, Terminfo_Type *t)
+{
+ return t->terminal_names = (char *) read_terminfo_section (fp, t->name_section_size);
+}
+
+/*
+ * The boolean flags have one byte for each flag. This byte is either 0 or
+ * 1 as the flag is present or absent. The value of 2 means that the flag
+ * has been cancelled. The capabilities are in the same order as the file
+ * <term.h>.
+ */
+
+static unsigned char *read_boolean_flags (FILE *fp, Terminfo_Type *t)
+{
+ /* Between the boolean section and the number section, a null byte is
+ * inserted, if necessary, to ensure that the number section begins on an
+ * even byte offset. All short integers are aligned on a short word
+ * boundary.
+ */
+
+ unsigned int size = (t->name_section_size + t->boolean_section_size) % 2;
+ size += t->boolean_section_size;
+
+ return t->boolean_flags = read_terminfo_section (fp, size);
+}
+
+
+
+/*
+ * The numbers section is similar to the boolean flags section. Each
+ * capability takes up two bytes, and is stored as a short integer. If the
+ * value represented is -1 or -2, the capability is taken to be missing.
+ */
+
+static unsigned char *read_numbers (FILE *fp, Terminfo_Type *t)
+{
+ return t->numbers = read_terminfo_section (fp, 2 * t->num_numbers);
+}
+
+
+/* The strings section is also similar. Each capability is stored as a
+ * short integer, in the format above. A value of -1 or -2 means the
+ * capability is missing. Otherwise, the value is taken as an offset from
+ * the beginning of the string table. Special characters in ^X or \c
+ * notation are stored in their interpreted form, not the printing
+ * representation. Padding information ($<nn>) and parameter information
+ * (%x) are stored intact in uninterpreted form.
+ */
+
+static unsigned char *read_string_offsets (FILE *fp, Terminfo_Type *t)
+{
+ return t->string_offsets = (unsigned char *) read_terminfo_section (fp, 2 * t->num_string_offsets);
+}
+
+
+/* The final section is the string table. It contains all the values of
+ * string capabilities referenced in the string section. Each string is
+ * null terminated.
+ */
+
+static char *read_string_table (FILE *fp, Terminfo_Type *t)
+{
+ return t->string_table = (char *) read_terminfo_section (fp, t->string_table_size);
+}
+
+
+/*
+ * Compiled terminfo(4) descriptions are placed under the directory
+ * /usr/share/lib/terminfo. In order to avoid a linear search of a huge
+ * UNIX system directory, a two-level scheme is used:
+ * /usr/share/lib/terminfo/c/name where name is the name of the terminal,
+ * and c is the first character of name. Thus, att4425 can be found in the
+ * file /usr/share/lib/terminfo/a/att4425. Synonyms for the same terminal
+ * are implemented by multiple links to the same compiled file.
+ */
+
+#define MAX_TI_DIRS 7
+static char *Terminfo_Dirs [MAX_TI_DIRS] =
+{
+ NULL,
+ "/usr/lib/terminfo",
+ "/usr/share/lib/terminfo",
+ "/usr/local/lib/terminfo",
+ "/lib/terminfo",
+ "/usr/local/share/terminfo",
+ "/usr/share/terminfo"
+};
+
+char *SLtt_tigetent (char *term)
+{
+ char *tidir;
+ int i;
+ FILE *fp = NULL;
+ char file[256];
+ Terminfo_Type *ti;
+
+ if (
+ (term == NULL)
+#ifdef SLANG_UNTIC
+ && (SLang_Untic_Terminfo_File == NULL)
+#endif
+ )
+ return NULL;
+
+ if (NULL == (ti = (Terminfo_Type *) SLMALLOC (sizeof (Terminfo_Type))))
+ {
+ return NULL;
+ }
+
+#ifdef SLANG_UNTIC
+ if (SLang_Untic_Terminfo_File != NULL)
+ {
+ fp = open_terminfo (SLang_Untic_Terminfo_File, ti);
+ goto fp_open_label;
+ }
+ else
+#endif
+ /* If we are on a termcap based system, use termcap */
+ if (0 == tcap_getent (term, ti)) return (char *) ti;
+
+ Terminfo_Dirs[0] = getenv ("TERMINFO");
+ i = 0;
+ while (i < MAX_TI_DIRS)
+ {
+ tidir = Terminfo_Dirs[i];
+ if (tidir != NULL)
+ {
+ sprintf (file, "%s/%c/%s", tidir, *term, term);
+ if (NULL != (fp = open_terminfo (file, ti))) break;
+ }
+ i++;
+ }
+#ifdef SLANG_UNTIC
+ fp_open_label:
+#endif
+
+ if (fp != NULL)
+ {
+ if (NULL != read_terminal_names (fp, ti))
+ {
+ if (NULL != read_boolean_flags (fp, ti))
+ {
+ if (NULL != read_numbers (fp, ti))
+ {
+ if (NULL != read_string_offsets (fp, ti))
+ {
+ if (NULL != read_string_table (fp, ti))
+ {
+ /* success */
+ fclose (fp);
+ ti->flags = SLTERMINFO;
+ return (char *) ti;
+ }
+ SLFREE (ti->string_offsets);
+ }
+ SLFREE (ti->numbers);
+ }
+ SLFREE (ti->boolean_flags);
+ }
+ SLFREE (ti->terminal_names);
+ }
+ fclose (fp);
+ }
+
+ SLFREE (ti);
+ return NULL;
+}
+
+#ifdef SLANG_UNTIC
+# define UNTIC_COMMENT(x) ,x
+#else
+# define UNTIC_COMMENT(x)
+#endif
+
+typedef struct
+{
+ char name[3];
+ int offset;
+#ifdef SLANG_UNTIC
+ char *comment;
+#endif
+}
+Tgetstr_Map_Type;
+
+/* I need to add: K1-5, %0-5(not important), @8, &8... */
+static Tgetstr_Map_Type Tgetstr_Map [] =
+{
+ {"@7", 164 UNTIC_COMMENT("KEY End")},
+ {"AB", 360 UNTIC_COMMENT("set a color background")},
+ {"AF", 359 UNTIC_COMMENT("set a color foreground")},
+ {"AL", 110 UNTIC_COMMENT("parm_insert_line")},
+ {"DL", 106 UNTIC_COMMENT("parm_delete_line")},
+ {"RI", 112 UNTIC_COMMENT("parm_right_cursor")},
+ {"Sf", 302 UNTIC_COMMENT("set foreground (color)")},
+ {"Sb", 303 UNTIC_COMMENT("set background (color)")},
+ {"ac", 146 UNTIC_COMMENT("acs_chars")},
+ {"ae", 38 UNTIC_COMMENT("exit_alt_charset_mode")},
+ {"as", 25 UNTIC_COMMENT("enter_alt_charset_mode")},
+ {"ce", 6 UNTIC_COMMENT("clr_eol")},
+ {"cl", 5 UNTIC_COMMENT("clear_screen")},
+ {"cm", 10 UNTIC_COMMENT("cursor_address")},
+ {"cs", 3 UNTIC_COMMENT("change_scroll_region")},
+ {"dc", 21 UNTIC_COMMENT("delete_character")},
+ {"ds", 23 UNTIC_COMMENT("disable status line")},
+ {"eA", 155 UNTIC_COMMENT("enable alt char set")},
+ {"ei", 42 UNTIC_COMMENT("exit_insert_mode")},
+ {"fs", 47 UNTIC_COMMENT("return from status line")},
+ {"im", 31 UNTIC_COMMENT("enter_insert_mode")},
+ {"k0", 65 UNTIC_COMMENT("key_f0")},
+ {"k1", 66 UNTIC_COMMENT("key_f1")},
+ {"k2", 68 UNTIC_COMMENT("key_f2")},
+ {"k3", 69 UNTIC_COMMENT("key_f3")},
+ {"k4", 70 UNTIC_COMMENT("key_f4")},
+ {"k5", 71 UNTIC_COMMENT("key_f5")},
+ {"k6", 72 UNTIC_COMMENT("key_f6")},
+ {"k7", 73 UNTIC_COMMENT("key_f7")},
+ {"k8", 74 UNTIC_COMMENT("key_f8")},
+ {"k9", 75 UNTIC_COMMENT("key_f9")},
+ {"kA", 78 UNTIC_COMMENT("key_il")},
+ {"kC", 57 UNTIC_COMMENT("key_clear")},
+ {"kD", 59 UNTIC_COMMENT("key_dc")},
+ {"kE", 63 UNTIC_COMMENT("key_eol,")},
+ {"kF", 84 UNTIC_COMMENT("key_sf")},
+ {"kH", 80 UNTIC_COMMENT("key_ll")},
+ {"kI", 77 UNTIC_COMMENT("key_ic")},
+ {"kL", 60 UNTIC_COMMENT("key_dl")},
+ {"kM", 62 UNTIC_COMMENT("key_eic,")},
+ {"kN", 81 UNTIC_COMMENT("key_npage")},
+ {"kP", 82 UNTIC_COMMENT("key_ppage")},
+ {"kR", 85 UNTIC_COMMENT("key_sr")},
+ {"kS", 64 UNTIC_COMMENT("key_eos,")},
+ {"kT", 86 UNTIC_COMMENT("key_stab")},
+ {"ka", 56 UNTIC_COMMENT("key_catab")},
+ {"k;", 67 UNTIC_COMMENT("key_f10")},
+ {"kb", 55 UNTIC_COMMENT("key_backspace")},
+ {"kd", 61 UNTIC_COMMENT("key_down")},
+ {"ke", 88 UNTIC_COMMENT("End keypad transmit mode")},
+ {"kh", 76 UNTIC_COMMENT("key_home")},
+ {"kl", 79 UNTIC_COMMENT("key_left")},
+ {"kr", 83 UNTIC_COMMENT("key_right")},
+ {"ks", 89 UNTIC_COMMENT("Start keypad transmit mode")},
+ {"kt", 58 UNTIC_COMMENT("key_ctab")},
+ {"ku", 87 UNTIC_COMMENT("key_up")},
+ {"mb", 26 UNTIC_COMMENT("enter_blink_mode")},
+ {"md", 27 UNTIC_COMMENT("enter_bold_mode")},
+ {"me", 39 UNTIC_COMMENT("exit_attribute_mode")},
+ {"mr", 34 UNTIC_COMMENT("enter_reverse_mode")},
+ {"op", 297 UNTIC_COMMENT("orig_pair (color)")},
+ {"pf", 119 UNTIC_COMMENT("turn OFF printer")},
+ {"po", 120 UNTIC_COMMENT("turn ON printer")},
+ {"se", 43 UNTIC_COMMENT("exit_standout_mode")},
+ {"so", 35 UNTIC_COMMENT("enter_standout_mode")},
+ {"sr", 130 UNTIC_COMMENT("scroll_reverse")},
+ {"te", 40 UNTIC_COMMENT("end cursor addressing")},
+ {"ti", 28 UNTIC_COMMENT("begin cursor addressing")},
+ {"ts", 135 UNTIC_COMMENT("goto to status line")},
+ {"up", 19 UNTIC_COMMENT("cursor_up")},
+ {"us", 36 UNTIC_COMMENT("enter_underline_mode")},
+ {"vb", 45 UNTIC_COMMENT("flash_screen")},
+ {"ve", 16 UNTIC_COMMENT("make cursor very visible")},
+ {"vi", 13 UNTIC_COMMENT("make cursor invisible")},
+ {"vs", 20 UNTIC_COMMENT("make cursor very visible")},
+ {"", 0 UNTIC_COMMENT(NULL)}
+};
+
+static int compute_cap_offset (char *cap, Terminfo_Type *t, Tgetstr_Map_Type *map, unsigned int max_ofs)
+{
+ char cha, chb;
+
+ (void) t;
+ cha = *cap++; chb = *cap;
+
+ while (*map->name != 0)
+ {
+ if ((cha == *map->name) && (chb == *(map->name + 1)))
+ {
+ if (map->offset >= (int) max_ofs) return -1;
+ return map->offset;
+ }
+ map++;
+ }
+ return -1;
+}
+
+
+char *SLtt_tigetstr (char *cap, char **pp)
+{
+ int offset;
+ Terminfo_Type *t;
+
+ if ((pp == NULL) || (NULL == (t = (Terminfo_Type *) *pp))) return NULL;
+
+ if (t->flags == SLTERMCAP) return tcap_getstr (cap, t);
+
+ offset = compute_cap_offset (cap, t, Tgetstr_Map, t->num_string_offsets);
+ if (offset < 0) return NULL;
+ offset = make_integer (t->string_offsets + 2 * offset);
+ if (offset < 0) return NULL;
+ return t->string_table + offset;
+}
+
+static Tgetstr_Map_Type Tgetnum_Map[] =
+{
+ {"co", 0 UNTIC_COMMENT("columns")},
+ {"li", 2 UNTIC_COMMENT("lines")},
+ {"Co", 13 UNTIC_COMMENT("max colors")},
+ {"pa", 14 UNTIC_COMMENT("max pairs")},
+ {"sg", 4 UNTIC_COMMENT("magic cookie glitch")},
+ {"ws", 7 UNTIC_COMMENT("num columns in status line")},
+ {"", -1 UNTIC_COMMENT(NULL)}
+};
+
+int SLtt_tigetnum (char *cap, char **pp)
+{
+ int offset;
+ Terminfo_Type *t;
+
+ if ((pp == NULL) || (NULL == (t = (Terminfo_Type *) *pp))) return -1;
+
+ if (t->flags == SLTERMCAP) return tcap_getnum (cap, t);
+
+ offset = compute_cap_offset (cap, t, Tgetnum_Map, t->num_numbers);
+ if (offset < 0) return -1;
+ return make_integer (t->numbers + 2 * offset);
+}
+
+static Tgetstr_Map_Type Tgetflag_Map[] =
+{
+ {"am", 1 UNTIC_COMMENT("auto right margin")},
+ {"hs", 9 UNTIC_COMMENT("has status line")},
+ {"ms", 14 UNTIC_COMMENT("move standout mode")},
+ {"xs", 3 UNTIC_COMMENT("ceol standout glitch")},
+ {"xn", 4 UNTIC_COMMENT("NEWLINE ignored after 80 columns")},
+ {"es", 16 UNTIC_COMMENT("status line esc ok")},
+ {"", -1 UNTIC_COMMENT(NULL)}
+};
+
+int SLtt_tigetflag (char *cap, char **pp)
+{
+ int offset;
+ Terminfo_Type *t;
+
+ if ((pp == NULL) || (NULL == (t = (Terminfo_Type *) *pp))) return -1;
+
+ if (t->flags == SLTERMCAP) return tcap_getflag (cap, t);
+
+ offset = compute_cap_offset (cap, t, Tgetflag_Map, t->boolean_section_size);
+
+ if (offset < 0) return -1;
+ return (int) *(t->boolean_flags + offset);
+}
+
+
+
+/* These are my termcap routines. They only work with the TERMCAP environment
+ * variable. This variable must contain the termcap entry and NOT the file.
+ */
+
+static int tcap_getflag (char *cap, Terminfo_Type *t)
+{
+ char a, b;
+ char *f = (char *) t->boolean_flags;
+ char *fmax;
+
+ if (f == NULL) return 0;
+ fmax = f + t->boolean_section_size;
+
+ a = *cap;
+ b = *(cap + 1);
+ while (f < fmax)
+ {
+ if ((a == f[0]) && (b == f[1]))
+ return 1;
+ f += 2;
+ }
+ return 0;
+}
+
+static char *tcap_get_cap (unsigned char *cap, unsigned char *caps, unsigned int len)
+{
+ unsigned char c0, c1;
+ unsigned char *caps_max;
+
+ c0 = cap[0];
+ c1 = cap[1];
+
+ if (caps == NULL) return NULL;
+ caps_max = caps + len;
+ while (caps < caps_max)
+ {
+ if ((c0 == caps[0]) && (c1 == caps[1]))
+ {
+ return (char *) caps + 3;
+ }
+ caps += (int) caps[2];
+ }
+ return NULL;
+}
+
+
+static int tcap_getnum (char *cap, Terminfo_Type *t)
+{
+ cap = tcap_get_cap ((unsigned char *) cap, t->numbers, t->num_numbers);
+ if (cap == NULL) return -1;
+ return atoi (cap);
+}
+
+static char *tcap_getstr (char *cap, Terminfo_Type *t)
+{
+ return tcap_get_cap ((unsigned char *) cap, (unsigned char *) t->string_table, t->string_table_size);
+}
+
+static int tcap_extract_field (unsigned char *t0)
+{
+ register unsigned char ch, *t = t0;
+ while (((ch = *t) != 0) && (ch != ':')) t++;
+ if (ch == ':') return (int) (t - t0);
+ return -1;
+}
+
+int SLtt_Try_Termcap = 1;
+static int tcap_getent (char *term, Terminfo_Type *ti)
+{
+ unsigned char *termcap, ch;
+ unsigned char *buf, *b;
+ unsigned char *t;
+ int len;
+
+ if (SLtt_Try_Termcap == 0) return -1;
+#if 1
+ /* XFREE86 xterm sets the TERMCAP environment variable to an invalid
+ * value. Specifically, it lacks the tc= string.
+ */
+ if (!strncmp (term, "xterm", 5))
+ return -1;
+#endif
+ termcap = (unsigned char *) getenv ("TERMCAP");
+ if ((termcap == NULL) || (*termcap == '/')) return -1;
+
+ /* We have a termcap so lets use it provided it does not have a reference
+ * to another terminal via tc=. In that case, user terminfo. The alternative
+ * would be to parse the termcap file which I do not want to do right now.
+ * Besides, this is a terminfo based system and if the termcap were parsed
+ * terminfo would almost never get a chance to run. In addition, the tc=
+ * thing should not occur if tset is used to set the termcap entry.
+ */
+ t = termcap;
+ while ((len = tcap_extract_field (t)) != -1)
+ {
+ if ((len > 3) && (t[0] == 't') && (t[1] == 'c') && (t[2] == '='))
+ return -1;
+ t += (len + 1);
+ }
+
+ /* malloc some extra space just in case it is needed. */
+ len = strlen ((char *) termcap) + 256;
+ if (NULL == (buf = (unsigned char *) SLMALLOC ((unsigned int) len))) return -1;
+
+ b = buf;
+
+ /* The beginning of the termcap entry contains the names of the entry.
+ * It is terminated by a colon.
+ */
+
+ ti->terminal_names = (char *) b;
+ t = termcap;
+ len = tcap_extract_field (t);
+ if (len < 0)
+ {
+ SLFREE (buf);
+ return -1;
+ }
+ strncpy ((char *) b, (char *) t, (unsigned int) len);
+ b[len] = 0;
+ b += len + 1;
+ ti->name_section_size = len;
+
+
+ /* Now, we are really at the start of the termcap entries. Point the
+ * termcap variable here since we want to refer to this a number of times.
+ */
+ termcap = t + (len + 1);
+
+
+ /* Process strings first. */
+ ti->string_table = (char *) b;
+ t = termcap;
+ while (-1 != (len = tcap_extract_field (t)))
+ {
+ unsigned char *b1;
+ unsigned char *tmax;
+
+ /* We are looking for: XX=something */
+ if ((len < 4) || (t[2] != '=') || (*t == '.'))
+ {
+ t += len + 1;
+ continue;
+ }
+ tmax = t + len;
+ b1 = b;
+
+ while (t < tmax)
+ {
+ ch = *t++;
+ if ((ch == '\\') && (t < tmax))
+ {
+ t = (unsigned char *) SLexpand_escaped_char ((char *) t, (char *) &ch);
+ }
+ else if ((ch == '^') && (t < tmax))
+ {
+ ch = *t++;
+ if (ch == '?') ch = 127;
+ else ch = (ch | 0x20) - ('a' - 1);
+ }
+ *b++ = ch;
+ }
+ /* Null terminate it. */
+ *b++ = 0;
+ len = (int) (b - b1);
+ b1[2] = (unsigned char) len; /* replace the = by the length */
+ /* skip colon to next field. */
+ t++;
+ }
+ ti->string_table_size = (int) (b - (unsigned char *) ti->string_table);
+
+ /* Now process the numbers. */
+
+ t = termcap;
+ ti->numbers = b;
+ while (-1 != (len = tcap_extract_field (t)))
+ {
+ unsigned char *b1;
+ unsigned char *tmax;
+
+ /* We are looking for: XX#NUMBER */
+ if ((len < 4) || (t[2] != '#') || (*t == '.'))
+ {
+ t += len + 1;
+ continue;
+ }
+ tmax = t + len;
+ b1 = b;
+
+ while (t < tmax)
+ {
+ *b++ = *t++;
+ }
+ /* Null terminate it. */
+ *b++ = 0;
+ len = (int) (b - b1);
+ b1[2] = (unsigned char) len; /* replace the # by the length */
+ t++;
+ }
+ ti->num_numbers = (int) (b - ti->numbers);
+
+ /* Now process the flags. */
+ t = termcap;
+ ti->boolean_flags = b;
+ while (-1 != (len = tcap_extract_field (t)))
+ {
+ /* We are looking for: XX#NUMBER */
+ if ((len != 2) || (*t == '.') || (*t <= ' '))
+ {
+ t += len + 1;
+ continue;
+ }
+ b[0] = t[0];
+ b[1] = t[1];
+ t += 3;
+ b += 2;
+ }
+ ti->boolean_section_size = (int) (b - ti->boolean_flags);
+ ti->flags = SLTERMCAP;
+ return 0;
+}
+
+#else /* USE_SETUPTERM */
+
+/* Ching Hui fixes so that it will work on AIX and OSF/1 */
+#include <curses.h>
+#include <term.h>
+
+int SLtt_Try_Termcap = 1;
+
+char *SLtt_tigetent (char *term)
+{
+ int rc;
+
+ setupterm(term, 1, &rc);
+ if (rc != 1)
+ return NULL;
+ return (char *)cur_term;
+}
+
+#define MATCH_CHAR(c, variable) \
+ do { \
+ if (*(cap + 1) == c) \
+ return variable; \
+ } while (0)
+
+char *SLtt_tigetstr (char *cap, char **pp)
+{
+ if ((pp == NULL) || ((cur_term = (struct term *) *pp) == NULL))
+ return NULL;
+
+ switch(*cap) {
+ case '@':
+ MATCH_CHAR('7', key_end);
+ break;
+ case 'A':
+ MATCH_CHAR('A', parm_insert_line);
+ break;
+ case 'D':
+ MATCH_CHAR('L', parm_delete_line);
+ break;
+ case 'R':
+ MATCH_CHAR('I', parm_right_cursor);
+ break;
+ case 'a':
+#ifdef acs_chars
+ MATCH_CHAR('c', acs_chars);
+#elif defined (box_chars_1)
+ MATCH_CHAR('c', box_chars_1); /* AIX hack */
+#else
+ MATCH_CHAR('c', NULL);
+#endif
+ MATCH_CHAR('e', exit_alt_charset_mode);
+ MATCH_CHAR('s', enter_alt_charset_mode);
+ break;
+ case 'c':
+ MATCH_CHAR('e', clr_eol);
+ MATCH_CHAR('l', clear_screen);
+ MATCH_CHAR('m', cursor_address);
+ MATCH_CHAR('s', change_scroll_region);
+ break;
+ case 'd':
+ MATCH_CHAR('c', delete_character);
+ break;
+ case 'e':
+ MATCH_CHAR('i', exit_insert_mode);
+#ifdef ena_acs
+ MATCH_CHAR('A', ena_acs); /* aix hack */
+#else
+ MATCH_CHAR('A', NULL);
+#endif
+ break;
+ case 'i':
+ MATCH_CHAR('m', enter_insert_mode);
+ break;
+ case 'k':
+ MATCH_CHAR('0', key_f0);
+ MATCH_CHAR('1', key_f1);
+ MATCH_CHAR('1', key_f1);
+ MATCH_CHAR('2', key_f2);
+ MATCH_CHAR('3', key_f3);
+ MATCH_CHAR('4', key_f4);
+ MATCH_CHAR('5', key_f5);
+ MATCH_CHAR('6', key_f6);
+ MATCH_CHAR('7', key_f7);
+ MATCH_CHAR('8', key_f8);
+ MATCH_CHAR('9', key_f9);
+ MATCH_CHAR('A', key_il);
+ MATCH_CHAR('C', key_clear);
+ MATCH_CHAR('D', key_dc);
+ MATCH_CHAR('E', key_eol);
+ MATCH_CHAR('F', key_sf);
+ MATCH_CHAR('H', key_ll);
+ MATCH_CHAR('I', key_ic);
+ MATCH_CHAR('L', key_dl);
+ MATCH_CHAR('M', key_eic);
+ MATCH_CHAR('N', key_npage);
+ MATCH_CHAR('P', key_ppage);
+ MATCH_CHAR('R', key_sr);
+ MATCH_CHAR('S', key_eos);
+ MATCH_CHAR('T', key_stab);
+ MATCH_CHAR('a', key_catab);
+ MATCH_CHAR(';', key_f10);
+ MATCH_CHAR('b', key_backspace);
+ MATCH_CHAR('d', key_down);
+ MATCH_CHAR('e', keypad_local);
+ MATCH_CHAR('h', key_home);
+ MATCH_CHAR('l', key_left);
+ MATCH_CHAR('r', key_right);
+ MATCH_CHAR('s', keypad_xmit);
+ MATCH_CHAR('t', key_ctab);
+ MATCH_CHAR('u', key_up);
+ break;
+ case 'm':
+ MATCH_CHAR('b', enter_blink_mode);
+ MATCH_CHAR('d', enter_bold_mode);
+ MATCH_CHAR('e', exit_attribute_mode);
+ MATCH_CHAR('r', enter_reverse_mode);
+ break;
+ case 's':
+ MATCH_CHAR('e', exit_standout_mode);
+ MATCH_CHAR('o', enter_standout_mode);
+ MATCH_CHAR('r', scroll_reverse);
+ break;
+ case 't':
+ MATCH_CHAR('e', exit_ca_mode);
+ MATCH_CHAR('i', enter_ca_mode);
+ break;
+ case 'u':
+ MATCH_CHAR('p', cursor_up);
+ MATCH_CHAR('s', enter_underline_mode);
+ break;
+ case 'v':
+ MATCH_CHAR('b', flash_screen);
+ MATCH_CHAR('i', cursor_invisible);
+ MATCH_CHAR('s', cursor_visible);
+ break;
+ case 'F':
+ MATCH_CHAR('1', key_f11);
+ MATCH_CHAR('2', key_f12);
+ MATCH_CHAR('3', key_f13);
+ MATCH_CHAR('4', key_f14);
+ MATCH_CHAR('5', key_f15);
+ MATCH_CHAR('6', key_f16);
+ MATCH_CHAR('7', key_f17);
+ MATCH_CHAR('8', key_f18);
+ MATCH_CHAR('9', key_f19);
+ MATCH_CHAR('A', key_f20);
+ break;
+#ifdef orig_pair
+ case 'o':
+ MATCH_CHAR('p', orig_pair);
+ break;
+#endif
+ }
+ return NULL;
+}
+
+int SLtt_tigetnum (char *cap, char **pp)
+{
+ if ((pp == NULL) || ((cur_term = (struct term *) *pp) == NULL))
+ return (int) NULL;
+ switch(*cap) {
+ case 'c':
+ MATCH_CHAR('o', columns);
+ break;
+ case 'l':
+ MATCH_CHAR('i', lines);
+ break;
+ }
+ return -1;
+}
+
+int SLtt_tigetflag (char *cap, char **pp)
+{
+ if ((pp == NULL) || ((cur_term = (struct term *) *pp) == NULL))
+ return (int) NULL;
+ switch(*cap) {
+ case 'a':
+ MATCH_CHAR('m', auto_right_margin);
+ break;
+ case 'm':
+ MATCH_CHAR('s', move_standout_mode);
+ break;
+ case 'x':
+ MATCH_CHAR('s', ceol_standout_glitch);
+ break;
+ case 's':
+ MATCH_CHAR('g', magic_cookie_glitch);
+ break;
+ }
+ return -1;
+}
+
+#endif /* !USE_SETUPTERM */
--- /dev/null
+/*--------------------------------*-C-*---------------------------------*
+ * File: sltoken.c
+ *
+ * Descript: ---
+ *
+ * Requires: ---
+ *
+ * Public: SLexpand_escaped_char ();
+ * SLexpand_escaped_string ();
+ * SLang_extract_token ();
+ * SLang_guess_type ();
+ * SLatoi ();
+ *
+ * Private: ---
+ *
+ * Notes: ---
+ *
+ * Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+\*----------------------------------------------------------------------*/
+
+#include "config.h"
+
+#include <stdio.h>
+
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+#include <string.h>
+#include "slang.h"
+#include "_slang.h"
+
+/* There are non-zeros at positions "\t %()*,/:;[]{}" */
+
+static unsigned char special_chars[256] =
+{
+ /* 0 */ 0,0,0,0,0,0,0,0, 0,'\t',0,0,0,0,0,0,
+ /* 16 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 32 */ ' ',0,0,0,0,'%',0,0, '(',')','*',0,',',0,0,'/',
+ /* 48 */ 0,0,0,0,0,0,0,0, 0,0,':',';',0,0,0,0,
+ /* 64 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 80 */ 0,0,0,0,0,0,0,0, 0,0,0,'[',0,']',0,0,
+ /* 96 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 112 */ 0,0,0,0,0,0,0,0, 0,0,0,'{',0,'}',0,0,
+ /* 8-bit characters */
+ /* 128 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 144 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 160 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 176 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 192 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 208 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 224 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
+ /* 240 */ 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
+};
+
+char *SLexpand_escaped_char(char *p, char *ch)
+{
+ int i = 0;
+ int max = 0, num, base = 0;
+ char ch1;
+
+ ch1 = *p++;
+
+ switch (ch1)
+ {
+ default: num = ch1; break;
+ case 'n': num = '\n'; break;
+ case 't': num = '\t'; break;
+ case 'v': num = '\v'; break;
+ case 'b': num = '\b'; break;
+ case 'r': num = '\r'; break;
+ case 'f': num = '\f'; break;
+ case 'E': case 'e': num = 27; break;
+ case 'a': num = 7;
+ break;
+
+ /* octal */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ max = '7';
+ base = 8; i = 2; num = ch1 - '0';
+ break;
+
+ case 'd': /* decimal -- S-Lang extension */
+ base = 10;
+ i = 3;
+ max = '9';
+ num = 0;
+ break;
+
+ case 'x': /* hex */
+ base = 16;
+ max = '9';
+ i = 2;
+ num = 0;
+ break;
+ }
+
+ while (i--)
+ {
+ ch1 = *p;
+
+ if ((ch1 <= max) && (ch1 >= '0'))
+ {
+ num = base * num + (ch1 - '0');
+ }
+ else if (base == 16)
+ {
+ ch1 |= 0x20;
+ if ((ch1 < 'a') || ((ch1 > 'f'))) break;
+ num = base * num + 10 + (ch1 - 'a');
+ }
+ else break;
+ p++;
+ }
+
+ *ch = (char) num;
+ return p;
+}
+
+void SLexpand_escaped_string (register char *s, register char *t,
+ register char *tmax)
+{
+ char ch;
+
+ while (t < tmax)
+ {
+ ch = *t++;
+ if (ch == '\\')
+ {
+ t = SLexpand_escaped_char (t, &ch);
+ }
+ *s++ = ch;
+ }
+ *s = 0;
+}
+
+
+int SLang_extract_token (char **linep, char *word_parm, int byte_comp)
+{
+ register char ch, *line, *word = word_parm;
+ int string;
+ char ch1;
+ char *word_max;
+
+ word_max = word + 250;
+
+ line = *linep;
+
+ /* skip white space */
+ while (((ch = *line) == ' ')
+ || (ch == '\t')) line++;
+
+ if ((!ch) || (ch == '\n'))
+ {
+ *linep = line;
+ return(0);
+ }
+
+ *word++ = ch;
+ line++;
+
+ /* Look for -something and rule out --something and -= something */
+ if ((ch == '-') &&
+ (*line != '-') && (*line != '=') && ((*line > '9') || (*line < '0')))
+ {
+ *word = 0;
+ *linep = line;
+ return 1;
+ }
+
+
+ if (ch == '"') string = 1; else string = 0;
+ if (ch == '\'')
+ {
+ if ((ch = *line++) != 0)
+ {
+ if (ch == '\\')
+ {
+ line = SLexpand_escaped_char(line, &ch1);
+ ch = ch1;
+ }
+ if (*line++ == '\'')
+ {
+ --word;
+ sprintf(word, "%d", (int) ((unsigned char) ch));
+ word += strlen (word); ch = '\'';
+ }
+ else SLang_Error = SYNTAX_ERROR;
+ }
+ else SLang_Error = SYNTAX_ERROR;
+ }
+ else if (!special_chars[(unsigned char) ch])
+ {
+ while (ch = *line++,
+ (ch > '"') ||
+ ((ch != '\n') && (ch != 0) && (ch != '"')))
+ {
+ if (string)
+ {
+ if (ch == '\\')
+ {
+ ch = *line++;
+ if ((ch == 0) || (ch == '\n')) break;
+ if (byte_comp) *word++ = '\\';
+ else
+ {
+ line = SLexpand_escaped_char(line - 1, &ch1);
+ ch = ch1;
+ }
+ }
+ }
+ else if (special_chars[(unsigned char) ch])
+ {
+ line--;
+ break;
+ }
+
+ *word++ = ch;
+ if (word > word_max)
+ {
+ SLang_doerror ("Token to large.");
+ break;
+ }
+ }
+ }
+
+ if ((!ch) || (ch == '\n')) line--;
+ if ((ch == '"') && string) *word++ = '"'; else if (string) SLang_Error = SYNTAX_ERROR;
+ *word = 0;
+ *linep = line;
+ /* massage variable-- and ++ into --variable, etc... */
+ if (((int) (word - word_parm) > 2)
+ && (ch = *(word - 1), (ch == '+') || (ch == '-'))
+ && (ch == *(word - 2)))
+ {
+ word--;
+ while (word >= word_parm + 2)
+ {
+ *word = *(word - 2);
+ word--;
+ }
+ *word-- = ch;
+ *word-- = ch;
+ }
+ return(1);
+}
+
+
+int SLang_guess_type (char *t)
+{
+ char *p;
+ register char ch;
+
+ if (*t == '-') t++;
+ p = t;
+#ifdef FLOAT_TYPE
+ if (*p != '.')
+ {
+#endif
+ while ((*p >= '0') && (*p <= '9')) p++;
+ if (t == p) return(STRING_TYPE);
+ if ((*p == 'x') && (p == t + 1)) /* 0x?? */
+ {
+ p++;
+ while (ch = *p,
+ ((ch >= '0') && (ch <= '9'))
+ || (((ch | 0x20) >= 'a') && ((ch | 0x20) <= 'f'))) p++;
+ }
+ if (*p == 0) return(INT_TYPE);
+#ifndef FLOAT_TYPE
+ return(STRING_TYPE);
+#else
+ }
+
+ /* now down to float case */
+ if (*p == '.')
+ {
+ p++;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ }
+ if (*p == 0) return(FLOAT_TYPE);
+ if ((*p != 'e') && (*p != 'E')) return(STRING_TYPE);
+ p++;
+ if ((*p == '-') || (*p == '+')) p++;
+ while ((*p >= '0') && (*p <= '9')) p++;
+ if (*p != 0) return(STRING_TYPE); else return(FLOAT_TYPE);
+#endif
+}
+
+int SLatoi (unsigned char *s)
+{
+ register unsigned char ch;
+ register unsigned int value;
+ register int base;
+
+ if (*s != '0') return atoi((char *) s);
+
+ /* look for 'x' which indicates hex */
+ s++;
+ if ((*s | 0x20) == 'x')
+ {
+ base = 16;
+ s++;
+ if (*s == 0)
+ {
+ SLang_Error = SYNTAX_ERROR;
+ return -1;
+ }
+ }
+ else base = 8;
+
+
+ value = 0;
+ while ((ch = *s++) != 0)
+ {
+ char ch1 = ch | 0x20;
+ switch (ch1)
+ {
+ default:
+ SLang_Error = SYNTAX_ERROR;
+ break;
+ case '8':
+ case '9':
+ if (base != 16) SLang_Error = SYNTAX_ERROR;
+ /* drop */
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ ch1 -= '0';
+ break;
+
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ if (base != 16) SLang_Error = SYNTAX_ERROR;
+ ch1 = (ch1 - 'a') + 10;
+ break;
+ }
+ value = value * base + ch1;
+ }
+ return (int) value;
+}
--- /dev/null
+/* slutty.c --- Unix Low level terminal (tty) functions for S-Lang */
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+
+#include "config.h"
+
+#include <stdio.h>
+#include <signal.h>
+/* sequent support thanks to Kenneth Lorber <keni@oasys.dt.navy.mil> */
+/* SYSV (SYSV ISC R3.2 v3.0) provided by iain.lea@erlm.siemens.de */
+
+#if defined (_AIX) && !defined (_ALL_SOURCE)
+# define _ALL_SOURCE /* so NBBY is defined in <sys/types.h> */
+#endif
+
+#ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+#ifdef SYSV
+# include <fcntl.h>
+# ifndef CRAY
+# include <sys/termio.h>
+# include <sys/stream.h>
+# include <sys/ptem.h>
+# include <sys/tty.h>
+# endif
+#endif
+
+
+#ifdef __BEOS__
+/* Prototype for select */
+# include <net/socket.h>
+#endif
+
+#include <sys/file.h>
+
+#ifndef sun
+# include <sys/ioctl.h>
+#endif
+
+#ifdef __QNX__
+# include <sys/select.h>
+#endif
+
+#include <sys/stat.h>
+#include <errno.h>
+
+#if defined (_AIX) && !defined (FD_SET)
+# include <sys/select.h> /* for FD_ISSET, FD_SET, FD_ZERO */
+#endif
+
+#ifndef O_RDWR
+# include <fcntl.h>
+#endif
+
+
+#include "slang.h"
+#include "_slang.h"
+
+int SLang_TT_Read_FD = -1;
+int SLang_TT_Baud_Rate;
+
+
+#ifdef HAVE_TERMIOS_H
+# if !defined(HAVE_TCGETATTR) || !defined(HAVE_TCSETATTR)
+# undef HAVE_TERMIOS_H
+# endif
+#endif
+
+#ifndef HAVE_TERMIOS_H
+
+# if !defined(CBREAK) && defined(sun)
+# ifndef BSD_COMP
+# define BSD_COMP 1
+# endif
+# include <sys/ioctl.h>
+# endif
+
+typedef struct
+ {
+ struct tchars t;
+ struct ltchars lt;
+ struct sgttyb s;
+ }
+TTY_Termio_Type;
+#else
+# include <termios.h>
+typedef struct termios TTY_Termio_Type;
+#endif
+
+static TTY_Termio_Type Old_TTY;
+
+#ifdef HAVE_TERMIOS_H
+static struct
+{
+ speed_t key;
+ int value;
+} Baud_Rates[] =
+{
+ {B0, 0},
+ {B50, 50},
+ {B75, 75},
+ {B110, 110},
+ {B134, 134},
+ {B150, 150},
+ {B200, 200},
+ {B300, 300},
+ {B600, 600},
+ {B1200, 1200},
+ {B1800, 1800},
+ {B2400, 2400},
+ {B4800, 4800},
+ {B9600, 9600},
+ {B19200, 19200},
+ {B38400, 38400}
+#ifdef B57600
+ , {B57600, 57600}
+#endif
+#ifdef B115200
+ , {B115200, 115200}
+#endif
+#ifdef B230400
+ , {B230400, 230400}
+#endif
+};
+#endif
+
+#ifdef HAVE_TERMIOS_H
+# define GET_TERMIOS(fd, x) tcgetattr(fd, x)
+# define SET_TERMIOS(fd, x) tcsetattr(fd, TCSADRAIN, x)
+#else
+# ifdef TCGETS
+# define GET_TERMIOS(fd, x) ioctl(fd, TCGETS, x)
+# define SET_TERMIOS(fd, x) ioctl(fd, TCSETS, x)
+# else
+# define X(x,m) &(((TTY_Termio_Type *)(x))->m)
+# define GET_TERMIOS(fd, x) \
+ ((ioctl(fd, TIOCGETC, X(x,t)) || \
+ ioctl(fd, TIOCGLTC, X(x,lt)) || \
+ ioctl(fd, TIOCGETP, X(x,s))) ? -1 : 0)
+# define SET_TERMIOS(fd, x) \
+ ((ioctl(fd, TIOCSETC, X(x,t)) ||\
+ ioctl(fd, TIOCSLTC, X(x,lt)) || \
+ ioctl(fd, TIOCSETP, X(x,s))) ? -1 : 0)
+# endif
+#endif
+
+static int TTY_Inited = 0;
+static int TTY_Open = 0;
+
+#ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
+# define NULL_VALUE -1
+#else
+# ifdef _POSIX_VDISABLE
+# define NULL_VALUE _POSIX_VDISABLE
+# else
+# define NULL_VALUE 255
+# endif
+#endif
+
+static int
+speed_t2baud_rate (speed_t s)
+{
+ int i;
+
+ for (i = 0; i < sizeof (Baud_Rates)/sizeof (Baud_Rates[0]); i++)
+ if (Baud_Rates[i].key == s)
+ return (Baud_Rates[i].value);
+ return 0;
+}
+
+int SLang_init_tty (int abort_char, int no_flow_control, int opost)
+{
+ TTY_Termio_Type newtty;
+
+ SLsig_block_signals ();
+
+ if (TTY_Inited)
+ {
+ SLsig_unblock_signals ();
+ return 0;
+ }
+
+ TTY_Open = 0;
+
+ if ((SLang_TT_Read_FD == -1)
+ || (1 != isatty (SLang_TT_Read_FD)))
+ {
+#if 0
+#ifdef O_RDWR
+# ifndef __BEOS__ /* I have been told that BEOS will HANG if passed /dev/tty */
+ if ((SLang_TT_Read_FD = open("/dev/tty", O_RDWR)) >= 0)
+ {
+ TTY_Open = 1;
+ }
+# endif
+#endif
+#endif /* 0 */
+ if (TTY_Open == 0)
+ {
+
+#if 0
+/* In the Midnight Commander we bind stderr sometimes to a pipe. If we
+ use stderr for terminal input and call SLang_getkey while stderr is
+ bound to a pipe MC will hang completly in SLsys_input_pending.
+ NOTE: There's an independent fix for this problem in src/slint.c for
+ the case that the Midnight Commander is linked against a shared slang
+ library compiled from different sources.
+ */
+ SLang_TT_Read_FD = fileno (stderr);
+ if (1 != isatty (SLang_TT_Read_FD))
+#endif
+ {
+ SLang_TT_Read_FD = fileno (stdin);
+ if (1 != isatty (SLang_TT_Read_FD))
+ {
+ fprintf (stderr, "Failed to open terminal.");
+ return -1;
+ }
+ }
+ }
+ }
+
+ SLang_Abort_Char = abort_char;
+
+ /* Some systems may not permit signals to be blocked. As a result, the
+ * return code must be checked.
+ */
+ while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
+ {
+ if (errno != EINTR)
+ {
+ SLsig_unblock_signals ();
+ return -1;
+ }
+ }
+
+ while (-1 == GET_TERMIOS(SLang_TT_Read_FD, &newtty))
+ {
+ if (errno != EINTR)
+ {
+ SLsig_unblock_signals ();
+ return -1;
+ }
+ }
+
+#ifndef HAVE_TERMIOS_H
+ newtty.s.sg_flags &= ~(ECHO);
+ newtty.s.sg_flags &= ~(CRMOD);
+ /* if (Flow_Control == 0) newtty.s.sg_flags &= ~IXON; */
+ newtty.t.t_eofc = 1;
+ if (abort_char == -1) SLang_Abort_Char = newtty.t.t_intrc;
+ newtty.t.t_intrc = SLang_Abort_Char; /* ^G */
+ newtty.t.t_quitc = 255;
+ newtty.lt.t_suspc = 255; /* to ignore ^Z */
+ newtty.lt.t_dsuspc = 255; /* to ignore ^Y */
+ newtty.lt.t_lnextc = 255;
+ newtty.s.sg_flags |= CBREAK; /* do I want cbreak or raw????? */
+#else
+
+ /* get baud rate */
+
+ /* [not only QNX related !?!]
+ * ECHO(0x08) is a c_lflag bit, it means here PARMRK(0x08) in c_iflag!!!
+ */
+ /*newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);*/
+ newtty.c_iflag &= ~(INLCR | ICRNL);
+#ifdef ISTRIP
+ /* newtty.c_iflag &= ~ISTRIP; */
+#endif
+ if (opost == 0) newtty.c_oflag &= ~OPOST;
+
+ if (SLang_TT_Baud_Rate == 0)
+ {
+/* Note: if this generates an compiler error, simply remove
+ the statement */
+#ifdef HAVE_CFGETOSPEED
+ SLang_TT_Baud_Rate = cfgetospeed (&newtty);
+#endif
+ SLang_TT_Baud_Rate = speed_t2baud_rate (SLang_TT_Baud_Rate);
+ }
+ if (no_flow_control) newtty.c_iflag &= ~IXON; else newtty.c_iflag |= IXON;
+
+ newtty.c_cc[VMIN] = 1;
+ newtty.c_cc[VTIME] = 0;
+ newtty.c_cc[VEOF] = 1;
+ newtty.c_lflag = ISIG | NOFLSH;
+ if (abort_char == -1) SLang_Abort_Char = newtty.c_cc[VINTR];
+ newtty.c_cc[VINTR] = SLang_Abort_Char; /* ^G */
+ newtty.c_cc[VQUIT] = NULL_VALUE;
+ newtty.c_cc[VSUSP] = NULL_VALUE; /* to ignore ^Z */
+#ifdef VSWTCH
+ newtty.c_cc[VSWTCH] = NULL_VALUE; /* to ignore who knows what */
+#endif
+#endif /* NOT HAVE_TERMIOS_H */
+
+ while (-1 == SET_TERMIOS(SLang_TT_Read_FD, &newtty))
+ {
+ if (errno != EINTR)
+ {
+ SLsig_unblock_signals ();
+ return -1;
+ }
+ }
+
+ TTY_Inited = 1;
+ SLsig_unblock_signals ();
+ return 0;
+}
+
+void SLtty_set_suspend_state (int mode)
+{
+ TTY_Termio_Type newtty;
+
+ SLsig_block_signals ();
+
+ if (TTY_Inited == 0)
+ {
+ SLsig_unblock_signals ();
+ return;
+ }
+
+ while ((-1 == GET_TERMIOS (SLang_TT_Read_FD, &newtty))
+ && (errno == EINTR))
+ ;
+
+#ifndef HAVE_TERMIOS_H
+ if (mode == 0) newtty.lt.t_suspc = 255;
+ else newtty.lt.t_suspc = Old_TTY.lt.t_suspc;
+#else
+ if (mode == 0) newtty.c_cc[VSUSP] = NULL_VALUE;
+ else newtty.c_cc[VSUSP] = Old_TTY.c_cc[VSUSP];
+#endif
+
+ while ((-1 == SET_TERMIOS (SLang_TT_Read_FD, &newtty))
+ && (errno == EINTR))
+ ;
+
+ SLsig_unblock_signals ();
+}
+
+void SLang_reset_tty (void)
+{
+ SLsig_block_signals ();
+
+ if (TTY_Inited == 0)
+ {
+ SLsig_unblock_signals ();
+ return;
+ }
+
+ while ((-1 == SET_TERMIOS(SLang_TT_Read_FD, &Old_TTY))
+ && (errno == EINTR))
+ ;
+
+ if (TTY_Open)
+ {
+ while ((-1 == close (SLang_TT_Read_FD))
+ && (errno == EINTR))
+ ;
+
+ TTY_Open = 0;
+ SLang_TT_Read_FD = -1;
+ }
+
+ TTY_Inited = 0;
+ SLsig_unblock_signals ();
+}
+
+static void default_sigint (int sig)
+{
+ sig = errno; /* use parameter */
+
+ SLKeyBoard_Quit = 1;
+ if (SLang_Ignore_User_Abort == 0) SLang_Error = USER_BREAK;
+ SLsignal_intr (SIGINT, default_sigint);
+ errno = sig;
+}
+
+void SLang_set_abort_signal (void (*hand)(int))
+{
+ int save_errno = errno;
+
+ if (hand == NULL) hand = default_sigint;
+ SLsignal_intr (SIGINT, hand);
+
+ errno = save_errno;
+}
+
+#ifndef FD_SET
+#define FD_SET(fd, tthis) *(tthis) = 1 << (fd)
+#define FD_ZERO(tthis) *(tthis) = 0
+#define FD_ISSET(fd, tthis) (*(tthis) & (1 << fd))
+typedef int fd_set;
+#endif
+
+static fd_set Read_FD_Set;
+
+
+/* HACK: If > 0, use 1/10 seconds. If < 0, use 1/1000 seconds */
+
+int SLsys_input_pending(int tsecs)
+{
+ struct timeval wait;
+ long usecs, secs;
+
+ if (TTY_Inited == 0) return -1;
+
+ if (tsecs >= 0)
+ {
+ secs = tsecs / 10;
+ usecs = (tsecs % 10) * 100000;
+ }
+ else
+ {
+ tsecs = -tsecs;
+ secs = tsecs / 1000;
+ usecs = (tsecs % 1000) * 1000;
+ }
+
+ wait.tv_sec = secs;
+ wait.tv_usec = usecs;
+
+ FD_ZERO(&Read_FD_Set);
+ FD_SET(SLang_TT_Read_FD, &Read_FD_Set);
+
+ return select(SLang_TT_Read_FD + 1, &Read_FD_Set, NULL, NULL, &wait);
+}
+
+
+int (*SLang_getkey_intr_hook) (void);
+
+static int handle_interrupt (void)
+{
+ if (SLang_getkey_intr_hook != NULL)
+ {
+ int save_tty_fd = SLang_TT_Read_FD;
+
+ if (-1 == (*SLang_getkey_intr_hook) ())
+ return -1;
+
+ if (save_tty_fd != SLang_TT_Read_FD)
+ return -1;
+ }
+
+ return 0;
+}
+
+unsigned int SLsys_getkey (void)
+{
+ unsigned char c;
+
+ if (TTY_Inited == 0)
+ {
+ int ic = fgetc (stdin);
+ if (ic == EOF) return SLANG_GETKEY_ERROR;
+ return (unsigned int) ic;
+ }
+
+ while (1)
+ {
+ int ret;
+
+ if (SLKeyBoard_Quit)
+ return SLang_Abort_Char;
+
+ if (0 == (ret = SLsys_input_pending (100)))
+ continue;
+
+ if (ret != -1)
+ break;
+
+ if (SLKeyBoard_Quit)
+ return SLang_Abort_Char;
+
+ if (errno == EINTR)
+ {
+ if (-1 == handle_interrupt ())
+ return SLANG_GETKEY_ERROR;
+
+ continue;
+ }
+
+ break; /* let read handle it */
+ }
+
+ while (-1 == read(SLang_TT_Read_FD, (char *) &c, 1))
+ {
+ if (errno == EINTR)
+ {
+ if (-1 == handle_interrupt ())
+ return SLANG_GETKEY_ERROR;
+
+ if (SLKeyBoard_Quit)
+ return SLang_Abort_Char;
+
+ continue;
+ }
+#ifdef EAGAIN
+ if (errno == EAGAIN)
+ {
+ sleep (1);
+ continue;
+ }
+#endif
+#ifdef EWOULDBLOCK
+ if (errno == EWOULDBLOCK)
+ {
+ sleep (1);
+ continue;
+ }
+#endif
+#ifdef EIO
+ if (errno == EIO)
+ {
+ SLang_exit_error ("SLsys_getkey: EIO error.");
+ }
+#endif
+ return SLANG_GETKEY_ERROR;
+ }
+
+ return((unsigned int) c);
+}
+
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include <stdlib.h>
+
+#ifdef __WIN32__
+# include <windows.h>
+#endif
+
+#ifdef __GO32__
+# undef msdos
+#endif
+
+#if defined (msdos)
+# include <conio.h>
+# include <bios.h>
+# include <mem.h>
+#endif
+#if defined (__WATCOMC__)
+# include <graph.h>
+# define int86 int386 /* simplify code writing */
+#endif
+
+#if defined (__GO32__)
+# include <pc.h>
+# define GO32_VIDEO
+#endif
+
+#if defined (__os2__) && !defined (EMX_VIDEO)
+# define INCL_BASE
+# define INCL_NOPM
+# define INCL_VIO
+# define INCL_KBD
+# include <os2.h>
+#else
+# if defined (__EMX__) /* EMX video does both DOS & OS/2 */
+# ifndef EMX_VIDEO
+# define EMX_VIDEO
+# endif
+# include <sys/video.h>
+# endif
+#endif
+
+#include <dos.h>
+#include "slang.h"
+
+#ifdef GO32_VIDEO
+# define HAS_SAVE_SCREEN
+#endif
+
+/* ------------------------- global variables ------------------------- */
+
+#ifdef WIN32
+extern HANDLE hStdout, hStdin;
+extern CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+#endif
+
+
+int SLtt_Term_Cannot_Insert;
+int SLtt_Term_Cannot_Scroll;
+int SLtt_Ignore_Beep = 3;
+int SLtt_Use_Ansi_Colors;
+
+int SLtt_Screen_Rows = 25;
+int SLtt_Screen_Cols = 80;
+
+/* ------------------------- local variables -------------------------- */
+static int Attribute_Byte;
+static int Scroll_r1 = 0, Scroll_r2 = 25;
+static int Cursor_Row = 1, Cursor_Col = 1;
+static int Current_Color;
+static int IsColor = 1;
+static int Blink_Killed; /* high intensity background enabled */
+
+#define JMAX_COLORS 256
+#define JNORMAL_COLOR 0
+#define JNO_COLOR -1
+
+static unsigned char Color_Map [JMAX_COLORS] =
+{
+ 0x7, 0x70, 0x70, 0x70, 0x70, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7,
+ 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7
+};
+
+
+#define JMAX_COLOR_NAMES 16
+static char *Color_Names [JMAX_COLOR_NAMES] =
+{
+ "black", "blue", "green", "cyan",
+ "red", "magenta", "brown", "lightgray",
+ "gray", "brightblue", "brightgreen", "brightcyan",
+ "brightred", "brightmagenta", "yellow", "white"
+};
+
+/*
+ * set_color_from_attribute (int attribute);
+ * define the correspondence of color to attribute
+ */
+#define set_color_from_attribute(a)\
+ SLtt_set_color (\
+ JNORMAL_COLOR, NULL,\
+ Color_Names[(a) & 0xf],\
+ Color_Names[(a) >> 4])
+/* this is how to make a space character */
+#define mkSpaceChar() (((Attribute_Byte) << 8) | 0x20)
+
+/* buffer to hold a line of character/attribute pairs */
+#define MAXCOLS 256
+static unsigned char Line_Buffer [MAXCOLS*2];
+
+/*----------------------------------------------------------------------*\
+ * define various ways and means of writing to the screen
+\*----------------------------------------------------------------------*/
+#if defined (__GO32__) || defined (__WATCOMC__)
+# if !defined (GO32_VIDEO)
+# define HAS_LINEAR_SCREEN
+# endif
+#else /* __GO32__ or __WATCOMC__ */
+# if defined (msdos)
+# define USE_ASM
+# endif
+#endif /* __GO32__ or __WATCOMC__ */
+
+/* define for direct to memory screen writes */
+#if defined (USE_ASM) || defined (HAS_LINEAR_SCREEN)
+static unsigned char *Video_Base;
+# define mkScreenPointer(row,col) ((unsigned short *)\
+ (Video_Base +\
+ 2 * (SLtt_Screen_Cols * (row)\
+ + (col))))
+# if defined (USE_ASM)
+int SLtt_Msdos_Cheap_Video = 0;
+static int Video_Status_Port;
+
+# define MONO_STATUS 0x3BA
+# define CGA_STATUS 0x3DA
+# define CGA_SETMODE 0x3D8
+
+# define SNOW_CHECK \
+if (SLtt_Msdos_Cheap_Video)\
+{ while ((inp (CGA_STATUS) & 0x08)); while (!(inp (CGA_STATUS) & 0x08)); }
+# endif /* USE_ASM */
+#endif /* USE_ASM or HAS_LINEAR_SCREEN */
+
+
+/* -------------------------------------------------------------------- */
+#if defined (__WATCOMC__)
+# define ScreenPrimary (0xb800 << 4)
+# define ScreenSize (SLtt_Screen_Cols * SLtt_Screen_Rows)
+# define ScreenSetCursor (x,y) _settextposition (x+1,y+1)
+void ScreenGetCursor (int *x, int *y)
+{
+ struct rccoord rc = _gettextposition ();
+ *x = rc.row - 1;
+ *y = rc.col - 1;
+}
+void ScreenRetrieve (unsigned char *dest)
+{
+ memcpy (dest, (unsigned char *) ScreenPrimary, 2 * ScreenSize);
+}
+void ScreenUpdate (unsigned char *src)
+{
+ memcpy ((unsigned char *) ScreenPrimary, src, 2 * ScreenSize);
+}
+#endif /* __WATCOMC__ */
+
+#ifdef HAS_SAVE_SCREEN
+static void *Saved_Screen_Buffer;
+static int Saved_Cursor_Row;
+
+static void save_screen (void)
+{
+ int row, col;
+
+ if (Saved_Screen_Buffer != NULL)
+ {
+ SLFREE (Saved_Screen_Buffer);
+ Saved_Screen_Buffer = NULL;
+ }
+#ifdef GO32_VIDEO
+ Saved_Screen_Buffer = SLMALLOC (sizeof (short) *
+ ScreenCols () * ScreenRows ());
+
+ if (Saved_Screen_Buffer == NULL)
+ return;
+
+ ScreenRetrieve (Saved_Screen_Buffer);
+ ScreenGetCursor (&row, &col);
+ Saved_Cursor_Row = row;
+#endif
+
+}
+
+static void restore_screen (void)
+{
+ if (Saved_Screen_Buffer == NULL) return;
+#ifdef GO32_VIDEO
+ ScreenUpdate (Saved_Screen_Buffer);
+ SLtt_goto_rc (Saved_Cursor_Row, 0);
+#endif
+
+}
+#endif /* HAS_SAVE_SCREEN */
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_write_string (char *str);
+ *
+ * put string STR to 'stdout'
+\*----------------------------------------------------------------------*/
+void SLtt_write_string (char *str)
+{
+#ifdef WIN32
+ int bytes;
+
+ (void) WriteConsole(hStdout, str, strlen(str), &bytes, NULL);
+#else
+ fputs (str, stdout);
+#endif
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_set_scroll_region (int r1, int r2);
+ *
+ * define a scroll region of top_row to bottom_row
+\*----------------------------------------------------------------------*/
+void SLtt_set_scroll_region (int top_row, int bottom_row)
+{
+ Scroll_r1 = top_row;
+ Scroll_r2 = bottom_row;
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_reset_scroll_region (void);
+ *
+ * reset the scrol region to be the entire screen,
+ * ie, SLtt_set_scroll_region (0, SLtt_Screen_Rows);
+\*----------------------------------------------------------------------*/
+void SLtt_reset_scroll_region (void)
+{
+ Scroll_r1 = 0;
+ Scroll_r2 = SLtt_Screen_Rows;
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_goto_rc (int row, int col);
+ *
+ * move the terminal cursor to x,y position COL, ROW and record the
+ * position in Cursor_Row, Cursor_Col
+\*----------------------------------------------------------------------*/
+void SLtt_goto_rc (int row, int col)
+{
+#ifdef WIN32
+ COORD newPosition;
+ newPosition.X = col;
+ newPosition.Y = row;
+#endif
+
+#if !defined (USE_ASM)
+ if (row > SLtt_Screen_Rows) row = SLtt_Screen_Rows;
+ if (col > SLtt_Screen_Cols) col = SLtt_Screen_Cols;
+# if defined (EMX_VIDEO)
+ v_gotoxy (col, Scroll_r1 + row);
+# else /* EMX_VIDEO_ */
+# if defined (__os2__)
+ VioSetCurPos (Scroll_r1 + row, col, 0);
+# elif defined(WIN32)
+ (void) SetConsoleCursorPosition(hStdout, newPosition);
+# else /* __os2__ */
+# if defined (__GO32__) || defined (__WATCOMC__)
+ ScreenSetCursor(Scroll_r1 + row, col);
+# endif /* __GO32__ or __WATCOMC__ */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO_ */
+ Cursor_Row = row;
+ Cursor_Col = col;
+#else /* USE_ASM */
+ /* if (r > SLtt_Screen_Rows - 1) r = SLtt_Screen_Rows - 1; */
+ asm mov ax, row
+ asm mov bx, SLtt_Screen_Rows
+ asm dec bx
+ asm cmp ax, bx
+ asm jle L1
+ asm mov ax, bx
+ L1:
+ /* if (c > SLtt_Screen_Cols - 1) c = SLtt_Screen_Cols - 1; */
+ asm mov cx, SLtt_Screen_Cols
+ asm dec cx
+ asm mov bx, col
+ asm cmp bx, cx
+ asm jle L2
+ asm mov bx, cx
+ L2:
+ asm mov Cursor_Row, ax
+ asm mov Cursor_Col, bx
+ asm add ax, Scroll_r1
+ asm xor dx, dx
+ asm mov dh, al
+ asm mov dl, bl
+ asm xor bx, bx
+ asm mov ax, 0x200
+ asm int 0x10
+#endif /* USE_ASM */
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: static void slvid_getxy (void);
+ *
+ * retrieve the cursor position into Cursor_Row, Cursor_Col
+\*----------------------------------------------------------------------*/
+static void slvid_getxy (void)
+{
+#if !defined (USE_ASM)
+# if defined (EMX_VIDEO)
+ v_getxy (&Cursor_Col, &Cursor_Row);
+# else /* EMX_VIDEO */
+# if defined (__os2__)
+ VioGetCurPos ((USHORT*) &Cursor_Row, (USHORT*) &Cursor_Col, 0);
+# elif defined(WIN32)
+ CONSOLE_SCREEN_BUFFER_INFO screenInfo;
+ if (GetConsoleScreenBufferInfo(hStdout, &screenInfo) == TRUE)
+ {
+ Cursor_Row = screenInfo.dwCursorPosition.Y;
+ Cursor_Col = screenInfo.dwCursorPosition.X;
+ }
+# else /* __os2__ */
+# if defined (__GO32__) || defined (__WATCOMC__)
+ ScreenGetCursor (&Cursor_Row, &Cursor_Col);
+# endif /* __GO32__ or __WATCOMC__ */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO */
+#else /* USE_ASM */
+ asm mov ah, 3
+ asm mov bh, 0
+ asm int 10h
+ asm xor ax, ax
+ asm mov al, dh
+ asm mov Cursor_Row, ax
+ asm xor ax, ax
+ asm mov al, dl
+ asm mov Cursor_Col, ax
+#endif /* USE_ASM */
+}
+
+/*----------------------------------------------------------------------*\
+ * static void slvid_deleol (int x);
+ *
+ * write space characters from column X of row Cursor_Row through to
+ * SLtt_Screen_Cols using the current Attribute_Byte
+\*----------------------------------------------------------------------*/
+#if defined (GO32_VIDEO)
+static void slvid_deleol (int x)
+{
+ while (x < SLtt_Screen_Cols)
+ ScreenPutChar (32, Attribute_Byte, x++, Cursor_Row);
+}
+#endif
+#if defined (EMX_VIDEO)
+static void slvid_deleol (int x)
+{
+ unsigned char *p, *pmax;
+ int w = mkSpaceChar ();
+ int count = SLtt_Screen_Cols - x;
+
+ p = Line_Buffer;
+ pmax = p + 2 * count;
+
+ while (p < pmax)
+ {
+ *p++ = (unsigned char) w;
+ *p++ = (unsigned char) (w >> 8);
+ }
+
+ v_putline (Line_Buffer, x, Cursor_Row, count);
+}
+#endif /* EMX_VIDEO */
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_begin_insert (void);
+ *
+ * insert a single space, moving everything right 1 character to make room
+\*----------------------------------------------------------------------*/
+void SLtt_begin_insert (void)
+{
+#if !defined (GO32_VIDEO)
+# if defined (HAS_LINEAR_SCREEN) || defined (USE_ASM)
+ unsigned short *p;
+# if defined (HAS_LINEAR_SCREEN)
+ unsigned short *pmin;
+# endif
+# endif
+ int n;
+ slvid_getxy ();
+ n = SLtt_Screen_Cols - Cursor_Col;
+ /* Msdos_Insert_Mode = 1; */
+
+# ifndef WIN32
+# if defined (EMX_VIDEO)
+ v_getline (Line_Buffer, Cursor_Col, Cursor_Row, n);
+ v_putline (Line_Buffer, Cursor_Col+1, Cursor_Row, n - 1);
+# else /* EMX_VIDEO */
+# if defined (__os2__)
+ n = 2 * (n - 1);
+ VioReadCellStr ((PCH)Line_Buffer, (USHORT*) &n, Cursor_Row, Cursor_Col, 0);
+ VioWrtCellStr ((PCH)Line_Buffer, n, Cursor_Row, Cursor_Col + 1, 0);
+# else /* __os2__ */
+ p = mkScreenPointer (Cursor_Row, SLtt_Screen_Cols - 1);
+
+# if defined (HAS_LINEAR_SCREEN)
+ /* pmin = p - (n-1); */
+ pmin = mkScreenPointer (Cursor_Row, Cursor_Col);
+ while (p-- > pmin) *(p + 1) = *p;
+# else
+ SNOW_CHECK;
+ asm mov ax, ds
+ asm mov bx, di
+ asm mov dx, si
+
+ asm mov cx, n
+ asm les di, p
+ asm lds si, p
+ asm sub si, 2
+ asm std
+ asm rep movsw
+
+ asm mov ds, ax
+ asm mov di, bx
+ asm mov si, dx
+# endif /* HAS_LINEAR_SCREEN */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO */
+
+# endif /* WIN32 */
+
+#endif /* not GO32_VIDEO */
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_end_insert (void);
+ *
+ * any cleanup after insert a blank column
+\*----------------------------------------------------------------------*/
+void SLtt_end_insert (void)
+{
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_delete_char (void);
+ *
+ * delete a single character, moving everything left 1 column to take
+ * up the room
+\*----------------------------------------------------------------------*/
+void SLtt_delete_char (void)
+{
+#if !defined (GO32_VIDEO)
+# if defined (HAS_LINEAR_SCREEN) || defined (USE_ASM)
+ unsigned short *p;
+# if defined (HAS_LINEAR_SCREEN)
+ register unsigned short *p1;
+# endif
+# endif
+ int n;
+
+ slvid_getxy ();
+ n = SLtt_Screen_Cols - Cursor_Col - 1;
+
+# ifndef WIN32
+
+# if defined (EMX_VIDEO)
+ v_getline (Line_Buffer, Cursor_Col+1, Cursor_Row, n);
+ v_putline (Line_Buffer, Cursor_Col, Cursor_Row, n);
+# else /* EMX_VIDEO */
+# if defined (__os2__)
+ n *= 2;
+ VioReadCellStr ((PCH)Line_Buffer, (USHORT*)&n, Cursor_Row, Cursor_Col + 1, 0);
+ VioWrtCellStr ((PCH)Line_Buffer, n, Cursor_Row, Cursor_Col, 0);
+ return;
+# else /* __os2__ */
+ p = mkScreenPointer (Cursor_Row, Cursor_Col);
+
+# if defined (HAS_LINEAR_SCREEN)
+ while (n--)
+ {
+ p1 = p + 1;
+ *p = *p1;
+ p++;
+ }
+# else /* HAS_LINEAR_SCREEN */
+ SNOW_CHECK;
+ asm mov ax, ds
+ asm mov bx, si
+ asm mov dx, di
+
+ asm mov cx, n
+ asm les di, p
+ asm lds si, p
+ asm add si, 2
+ asm cld
+ asm rep movsw
+
+ asm mov ds, ax
+ asm mov si, bx
+ asm mov di, dx
+# endif /* HAS_LINEAR_SCREEN */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO */
+
+# endif /* WIN32 */
+
+#endif /* not GO32_VIDEO */
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_erase_line (void);
+ *
+ * This function is *only* called on exit.
+ * It sets attribute byte to Black & White
+\*----------------------------------------------------------------------*/
+void SLtt_erase_line (void)
+{
+
+#ifndef WIN32
+
+# if defined (GO32_VIDEO) || defined (EMX_VIDEO)
+ Attribute_Byte = 0x07;
+ slvid_deleol (0);
+# else /* GO32_VIDEO or EMX_VIDEO */
+# if defined (__os2__)
+ USHORT w;
+ Attribute_Byte = 0x07;
+ w = mkSpaceChar ();
+ VioWrtNCell ((BYTE*)&w, SLtt_Screen_Cols, Cursor_Row, 0, 0);
+# else /* __os2__ */
+ unsigned short w;
+ unsigned short *p = mkScreenPointer (Cursor_Row, 0);
+# if defined (HAS_LINEAR_SCREEN)
+ register unsigned short *pmax = p + SLtt_Screen_Cols;
+
+ Attribute_Byte = 0x07;
+ w = mkSpaceChar ();
+ while (p < pmax) *p++ = w;
+# else /* HAS_LINEAR_SCREEN */
+ Attribute_Byte = 0x07;
+ w = mkSpaceChar ();
+ SNOW_CHECK;
+ asm mov dx, di
+ asm mov ax, w
+ asm mov cx, SLtt_Screen_Cols
+ asm les di, p
+ asm cld
+ asm rep stosw
+ asm mov di, dx
+# endif /* HAS_LINEAR_SCREEN */
+# endif /* __os2__ */
+# endif /* GO32_VIDEO or EMX_VIDEO */
+ Current_Color = JNO_COLOR; /* since we messed with attribute byte */
+
+#endif /* WIN32 */
+
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_delete_nlines (int nlines);
+ *
+ * delete NLINES by scrolling up the region <Scroll_r1, Scroll_r2>
+\*----------------------------------------------------------------------*/
+void SLtt_delete_nlines (int nlines)
+{
+ SLtt_normal_video ();
+
+#ifndef WIN32
+
+# if defined (EMX_VIDEO)
+ v_attrib (Attribute_Byte);
+ v_scroll (0, Scroll_r1, SLtt_Screen_Cols-1, Scroll_r2, nlines, V_SCROLL_UP);
+# else /* EMX_VIDEO */
+# if defined (__os2__)
+ {
+ Line_Buffer[0] = ' '; Line_Buffer[1] = Attribute_Byte;
+ VioScrollUp (Scroll_r1, 0, Scroll_r2, SLtt_Screen_Cols-1,
+ nlines, (PCH) Line_Buffer, 0);
+ }
+# else /* __os2__ */
+# if defined (USE_ASM)
+ /* This has the effect of pulling all lines below it up */
+ asm mov ax, nlines
+ asm mov ah, 6 /* int 6h */
+ asm xor cx, cx
+ asm mov ch, byte ptr Scroll_r1
+ asm mov dx, SLtt_Screen_Cols
+ asm dec dx
+ asm mov dh, byte ptr Scroll_r2
+ asm mov bh, byte ptr Attribute_Byte
+ asm int 10h
+# else /* USE_ASM */
+ {
+ union REGS r;
+# if defined (__WATCOMC__)
+ r.x.eax = nlines;
+ r.x.ecx = 0;
+# else
+ r.x.ax = nlines;
+ r.x.cx = 0;
+# endif
+ r.h.ah = 6;
+ r.h.ch = Scroll_r1;
+ r.h.dl = SLtt_Screen_Cols - 1;
+ r.h.dh = Scroll_r2;
+ r.h.bh = Attribute_Byte;
+ int86 (0x10, &r, &r);
+ }
+# endif /* USE_ASM */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO */
+
+#endif /* WIN32 */
+
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_reverse_index (int nlines);
+ *
+ * scroll down the region <Scroll_r1, Scroll_r2> by NLINES
+\*----------------------------------------------------------------------*/
+void SLtt_reverse_index (int nlines)
+{
+ SLtt_normal_video ();
+
+#ifndef WIN32
+
+# if defined (EMX_VIDEO)
+ v_attrib (Attribute_Byte);
+ v_scroll (0, Scroll_r1, SLtt_Screen_Cols-1, Scroll_r2, nlines,
+ V_SCROLL_DOWN);
+# else /* EMX_VIDEO */
+# if defined (__os2__)
+ {
+ Line_Buffer[0] = ' '; Line_Buffer[1] = Attribute_Byte;
+ VioScrollDn (Scroll_r1, 0, Scroll_r2, SLtt_Screen_Cols-1,
+ nlines, (PCH) Line_Buffer, 0);
+ }
+# else /* __os2__ */
+# if defined (USE_ASM)
+ asm xor cx, cx
+ asm mov ch, byte ptr Scroll_r1
+ asm mov dx, SLtt_Screen_Cols
+ asm dec dx
+ asm mov dh, byte ptr Scroll_r2
+ asm mov bh, byte ptr Attribute_Byte
+ asm mov ah, 7
+ asm mov al, byte ptr nlines
+ asm int 10h
+# else /* USE_ASM */
+ {
+ union REGS r;
+ r.h.al = nlines;
+# if defined (__WATCOMC__)
+ r.x.ecx = 0;
+# else
+ r.x.cx = 0;
+# endif
+ r.h.ah = 7;
+ r.h.ch = Scroll_r1;
+ r.h.dl = SLtt_Screen_Cols - 1;
+ r.h.dh = Scroll_r2;
+ r.h.bh = Attribute_Byte;
+ int86 (0x10, &r, &r);
+ }
+# endif /* USE_ASM */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO */
+
+#endif /* WIN32 */
+
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: static void slvid_invert_region (int top_row, int bot_row);
+ *
+ * invert the display in the region, top_row <= row < bot_row
+\*----------------------------------------------------------------------*/
+static void slvid_invert_region (int top_row, int bot_row)
+{
+
+#ifndef WIN32
+
+# if defined (EMX_VIDEO)
+ int row, col;
+
+ for (row = top_row; row < bot_row; row++)
+ {
+ v_getline (Line_Buffer, 0, row, SLtt_Screen_Cols);
+ for (col = 1; col < SLtt_Screen_Cols * 2; col += 2)
+ Line_Buffer [col] ^= 0xff;
+ v_putline (Line_Buffer, 0, row, SLtt_Screen_Cols);
+ }
+# else /* EMX_VIDEO */
+# ifdef __os2__
+ int row, col;
+ USHORT length = SLtt_Screen_Cols * 2;
+
+ for (row = top_row; row < bot_row; row++)
+ {
+ VioReadCellStr ((PCH)Line_Buffer, &length, row, 0, 0);
+ for (col = 1; col < length; col += 2)
+ Line_Buffer [col] ^= 0xff;
+ VioWrtCellStr ((PCH)Line_Buffer, length, row, 0, 0);
+ }
+# else /* __os2__ */
+# if defined (__GO32__) || defined (__WATCOMC__)
+ unsigned char buf [2 * 180 * 80]; /* 180 cols x 80 rows */
+ unsigned char *b, *bmax;
+
+ b = buf + 1 + 2 * SLtt_Screen_Cols * top_row;
+ bmax = buf + 1 + 2 * SLtt_Screen_Cols * bot_row;
+ ScreenRetrieve (buf);
+ while (b < bmax)
+ {
+ *b ^= 0xFF;
+ b += 2;
+ }
+ ScreenUpdate (buf);
+# else /* __GO32__ or __WATCOMC__ */
+ register unsigned short ch, sh;
+ register unsigned short *pmin = mkScreenPointer (top_row, 0);
+ register unsigned short *pmax = mkScreenPointer (bot_row, 0);
+
+ while (pmin < pmax)
+ {
+ sh = *pmin;
+ ch = sh;
+ ch = ch ^ 0xFF00;
+ *pmin = (ch & 0xFF00) | (sh & 0x00FF);
+ pmin++;
+ }
+# endif /* __GO32__ or __WATCOMC__ */
+# endif /* __os2__ */
+# endif /* EMX_VIDEO */
+
+#endif /* WIN32 */
+
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_beep (void);
+ *
+ * signal error by a "bell" condition, the type of signal is governed
+ * by the value of SLtt_Ignore_Beep:
+ *
+ * 0 silent bell
+ * 1 audible bell
+ * 2 visual bell
+ * 4 special visual bell (only flash the bottom status line)
+ *
+ * these may be combined:
+ * eg, 3 = audible visual bell.
+ * but if both the visual bell and the "special" visual bell are specified,
+ * only the special bell is used.
+\*----------------------------------------------------------------------*/
+void SLtt_beep (void)
+{
+ int audible; /* audible bell */
+ int special = 0; /* first row to invert */
+ int visual = 0; /* final row to invert */
+ if (!SLtt_Ignore_Beep) return;
+
+ audible = (SLtt_Ignore_Beep & 1);
+ if ( (SLtt_Ignore_Beep & 4) )
+ {
+ special = SLtt_Screen_Rows - 1;
+ visual = special--; /* only invert bottom status line */
+ }
+ else if ( (SLtt_Ignore_Beep & 2) )
+ {
+ visual = SLtt_Screen_Rows;
+ }
+
+ if (visual) slvid_invert_region (special, visual);
+#if defined (EMX_VIDEO)
+ if (audible) /*sound (1500)*/; _sleep2 (100); if (audible) /* nosound () */;
+#else
+# ifdef __os2__
+ if (audible) DosBeep (1500, 100); else DosSleep (100);
+
+# elif defined(WIN32)
+
+# else
+ if (audible) sound (1500); delay (100); if (audible) nosound ();
+# endif
+#endif
+ if (visual) slvid_invert_region (special, visual);
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_del_eol (void);
+ *
+ * delete from the current cursor position to the end of the row
+\*----------------------------------------------------------------------*/
+void SLtt_del_eol (void)
+{
+
+#ifndef WIN32
+
+# if defined (GO32_VIDEO) || defined (EMX_VIDEO)
+ if (Current_Color != JNO_COLOR) SLtt_normal_video ();
+ slvid_deleol (Cursor_Col);
+# else /* GO32_VIDEO or EMX_VIDEO */
+# ifdef __os2__
+ USHORT w;
+ if (Current_Color != JNO_COLOR) SLtt_normal_video ();
+ w = mkSpaceChar ();
+ VioWrtNCell ((BYTE*)&w, (SLtt_Screen_Cols - Cursor_Col),
+ Cursor_Row, Cursor_Col, 0);
+# else /* __os2__ */
+ unsigned short *p = mkScreenPointer (Cursor_Row, Cursor_Col);
+ int n = SLtt_Screen_Cols - Cursor_Col;
+ unsigned short w;
+# if defined (HAS_LINEAR_SCREEN)
+ unsigned short *pmax = p + n;
+
+ if (Current_Color != JNO_COLOR) SLtt_normal_video ();
+ w = mkSpaceChar ();
+ while (p < pmax) *p++ = w;
+# else /* HAS_LINEAR_SCREEN */
+ if (Current_Color != JNO_COLOR) SLtt_normal_video ();
+ w = mkSpaceChar ();
+ SNOW_CHECK;
+ asm mov dx, di
+ asm les di, p
+ asm mov ax, w
+ asm mov cx, n
+ asm cld
+ asm rep stosw
+
+ asm mov di, dx
+# endif /* HAS_LINEAR_SCREEN */
+# endif /* __os2__ */
+# endif /* GO32_VIDEO or EMX_VIDEO */
+
+#endif /* WIN32 */
+
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_reverse_video (int color);
+ *
+ * set Attribute_Byte corresponding to COLOR.
+ * Use Current_Color to remember the color which was set.
+ * convert from the COLOR number to the attribute value.
+\*----------------------------------------------------------------------*/
+void SLtt_reverse_video (int color)
+{
+ Attribute_Byte = Color_Map [color];
+ Current_Color = color;
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_normal_video (void);
+ *
+ * reset the attributes for normal video
+\*----------------------------------------------------------------------*/
+void SLtt_normal_video (void)
+{
+ SLtt_reverse_video (JNORMAL_COLOR);
+}
+
+#if defined (USE_ASM)
+/*----------------------------------------------------------------------*\
+ * Function: static unsigned short *video_write (register unsigned char *pp,
+ * register unsigned char *p,
+ * register unsigned short *pos)
+ *
+ * write out (P - PP) characters from the array pointed to by PP
+ * at position (POS, Cursor_Row) in the current Attribute_Byte
+ *
+ * increment POS to reflect the number of characters sent and
+ * return the it as a pointer
+\*----------------------------------------------------------------------*/
+static unsigned short *video_write (register unsigned char *pp,
+ register unsigned char *p,
+ register unsigned short *pos)
+{
+ int n = (int) (p - pp); /* num of characters of PP to write */
+
+ asm push si
+ asm push ds
+ asm push di
+
+ /* set up register for BOTH fast and slow */
+ asm mov bx, SLtt_Msdos_Cheap_Video
+
+ /* These are the registers needed for both fast AND slow */
+ asm mov ah, byte ptr Attribute_Byte
+ asm mov cx, n
+ asm lds si, dword ptr pp
+ asm les di, dword ptr pos
+ asm cld
+
+ asm cmp bx, 0 /* cheap video test */
+ asm je L_fast
+ asm mov bx, ax
+ asm mov dx, CGA_STATUS
+ asm jg L_slow_blank
+
+ /* slow video */
+ asm cli
+
+ /* wait for retrace */
+ L_slow:
+ asm in al, dx
+ asm test al, 1
+ asm jnz L_slow
+
+ L_slow1:
+ asm in al, dx
+ asm test al, 1
+ asm jz L_slow1
+
+ /* move a character out */
+ asm mov ah, bh
+ asm lodsb
+ asm stosw
+ asm loop L_slow
+
+ asm sti
+ asm jmp done
+
+/* -------------- slow video, vertical retace and pump --------------*/
+ L_slow_blank:
+ L_slow_blank_loop:
+ asm in al, dx
+ asm test al, 8
+ asm jnz L_slow_blank_loop
+
+ L_slow_blank1:
+ asm in al, dx
+ asm test al, 8
+ asm jz L_slow_blank1
+ /* write line */
+ asm mov ah, bh
+ L_slow_blank2:
+ asm lodsb
+ asm stosw
+ asm loop L_slow_blank2
+
+ asm jmp done
+/*-------------- Fast video --------------*/
+
+ L_fast:
+ asm lodsb
+ asm stosw
+ asm loop L_fast
+ done:
+ asm pop di
+ asm pop ds
+ asm pop si
+ return (pos + n);
+}
+#endif /* USE_ASM */
+
+/*----------------------------------------------------------------------*\
+ * Function: static void write_attributes (unsigned short *src,
+ * int count);
+ *
+ * Copy COUNT character/color pairs from the array pointed to by
+ * SRC to the screen at position (0,Cursor_Row).
+ * NB: SRC contains character/color pairs -- the color must be converted to
+ * an ansi attribute.
+ *
+ * Write out
+ * 1) a combination of string/attributes
+ * 2) each string of continuous colour
+ *
+ * approach 2) is used for assembler output, while 1) is used when a higher
+ * level API is available or direct to memory writing is possible: emx video
+ * routines, os/2, go32, watcom.
+\*----------------------------------------------------------------------*/
+static void write_attributes (unsigned short *src, int count)
+{
+ register unsigned char *p = Line_Buffer;
+ register unsigned short pair;
+#ifdef WIN32
+ register unsigned char * org_src = src;
+ COORD coord;
+ long bytes;
+#endif
+#if !defined (USE_ASM)
+# if defined (HAS_LINEAR_SCREEN)
+ register unsigned short *pos = mkScreenPointer (Cursor_Row, 0);
+# endif
+ int n = count;
+
+ /* write into a character/attribute pair */
+ while (n-- > 0)
+ {
+ pair = *(src++); /* character/color pair */
+ SLtt_reverse_video (pair >> 8); /* color change */
+# if defined (HAS_LINEAR_SCREEN)
+ *(pos++) = ((unsigned short) Attribute_Byte << 8) | pair & 0xff;
+# else
+# if defined(EMX_VIDEO) || !defined(WIN32)
+ *(p++) = pair & 0xff; /* character byte */
+ *(p++) = Attribute_Byte; /* attribute byte */
+# else
+ /* WIN32 for now... */
+ *(p++) = pair & 0xff;
+# endif
+# endif
+ }
+
+# if !defined (HAS_LINEAR_SCREEN)
+# if defined (EMX_VIDEO)
+ v_putline (Line_Buffer, Cursor_Col, Cursor_Row, count);
+# else /* EMX_VIDEO */
+# if defined (__os2__)
+ VioWrtCellStr ((PCH)Line_Buffer, (USHORT)(2 * count),
+ (USHORT)Cursor_Row, (USHORT)Cursor_Col, 0);
+# elif defined(WIN32)
+ /* do color attributes later */
+ p = Line_Buffer;
+ coord.X = Cursor_Col;
+ coord.Y = Cursor_Row;
+ WriteConsoleOutputCharacter(hStdout, p, count, coord, &bytes);
+
+ /* write color attributes */
+ p = Line_Buffer;
+ n = count;
+ src = org_src; /* restart the src pointer */
+
+ /* write into attributes only */
+ while (n-- > 0)
+ {
+ pair = *(src++); /* character/color pair */
+ SLtt_reverse_video (pair >> 8); /* color change */
+ *(p++) = Attribute_Byte; /* attribute byte */
+ *(p++) = 0; /* what's this for? */
+ }
+
+ WriteConsoleOutputAttribute(hStdout, Line_Buffer, count, coord, &bytes);
+# else /* __os2__ */
+ /* ScreenUpdateLine (void *virtual_screen_line, int row); */
+ p = Line_Buffer;
+ n = Cursor_Col;
+ while (count-- > 0)
+ {
+ ScreenPutChar ((int)p[0], (int)p[1], n++, Cursor_Row);
+ p += 2;
+ }
+# endif /* EMX_VIDEO */
+# endif /* __os2__ */
+# endif /* HAS_LINEAR_SCREEN */
+#else /* not USE_ASM */
+ unsigned char ch, color;
+ register unsigned short *pos = mkScreenPointer (Cursor_Row, 0);
+
+ while (count--)
+ {
+ pair = *(src++); /* character/color pair */
+ ch = pair & 0xff; /* character value */
+ color = pair >> 8; /* color value */
+ if (color != Current_Color) /* need a new color */
+ {
+ if (p != Line_Buffer)
+ {
+ pos = video_write (Line_Buffer, p, pos);
+ p = Line_Buffer;
+ }
+ SLtt_reverse_video (color); /* change color */
+ }
+ *(p++) = ch;
+ }
+ pos = video_write (Line_Buffer, p, pos);
+#endif /* not USE_ASM */
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_smart_puts (unsigned short *new_string,
+ * unsigned short *old_string,
+ * int len, int row);
+ *
+ * puts NEW_STRING, which has length LEN, at row ROW. NEW_STRING contains
+ * characters/colors packed in the form value = ((color << 8) | (ch));
+ *
+ * the puts tries to avoid overwriting the same characters/colors
+ *
+ * OLD_STRING is not used, maintained for compatibility with other systems
+\*----------------------------------------------------------------------*/
+void SLtt_smart_puts (unsigned short *new_string,
+ unsigned short *old_string,
+ int len, int row)
+{
+ (void) old_string;
+ Cursor_Row = row;
+ Cursor_Col = 0;
+ write_attributes (new_string, len);
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_reset_video (void);
+\*----------------------------------------------------------------------*/
+void SLtt_reset_video (void)
+{
+ SLtt_goto_rc (SLtt_Screen_Rows - 1, 0);
+#ifdef HAS_SAVE_SCREEN
+ restore_screen ();
+#endif
+ Attribute_Byte = 0x07;
+ Current_Color = JNO_COLOR;
+ SLtt_del_eol ();
+}
+
+#if 0
+void wide_width (void)
+{
+}
+
+void narrow_width (void)
+{
+}
+#endif
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_cls (void);
+\*----------------------------------------------------------------------*/
+void SLtt_cls (void)
+{
+#ifdef WIN32
+ long bytes;
+ COORD coord;
+ char ch;
+#endif
+ SLtt_normal_video ();
+#if defined (__GO32__) || defined (__WATCOMC__) || defined (EMX_VIDEO)
+ SLtt_reset_scroll_region ();
+ SLtt_goto_rc (0, 0);
+ SLtt_delete_nlines (SLtt_Screen_Rows);
+#else /* __GO32__ or __WATCOMC__ or EMX_VIDEO */
+# ifdef __os2__
+ {
+ Line_Buffer [0] = ' '; Line_Buffer [1] = Attribute_Byte;
+ VioScrollUp (0, 0, -1, -1, -1, (PCH)Line_Buffer, 0);
+ }
+# elif defined(WIN32)
+ /* clear the WIN32 screen in one shot */
+ coord.X = 0;
+ coord.Y = 0;
+
+ ch = ' ';
+
+ (void) FillConsoleOutputCharacter(hStdout,
+ ch,
+ csbiInfo.dwMaximumWindowSize.Y * csbiInfo.dwMaximumWindowSize.X,
+ coord,
+ &bytes);
+
+ /* now set screen to the current attribute */
+ ch = Attribute_Byte;
+ (void) FillConsoleOutputAttribute(hStdout,
+ ch,
+ csbiInfo.dwMaximumWindowSize.Y * csbiInfo.dwMaximumWindowSize.X,
+ coord,
+ &bytes);
+# else /* __os2__ */
+ asm mov dx, SLtt_Screen_Cols
+ asm dec dx
+ asm mov ax, SLtt_Screen_Rows
+ asm dec ax
+ asm mov dh, al
+ asm xor cx, cx
+ asm xor ax, ax
+ asm mov ah, 7
+ asm mov bh, byte ptr Attribute_Byte
+ asm int 10h
+# endif /* __os2__ */
+#endif /* __GO32__ or __WATCOMC__ or EMX_VIDEO */
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_putchar (char ch);
+ *
+ * put CH on the screen in the current position.
+ * this function is called assuming that cursor is in correct position
+\*----------------------------------------------------------------------*/
+
+void SLtt_putchar (char ch)
+{
+#if !defined (GO32_VIDEO) && !defined (EMX_VIDEO)
+ unsigned short p, *pp;
+# if defined(WIN32)
+ long bytes;
+# endif
+#endif
+
+ if (Current_Color) SLtt_normal_video ();
+ slvid_getxy (); /* get current position */
+ switch (ch)
+ {
+ case 7: /* ^G - break */
+ SLtt_beep (); break;
+ case 8: /* ^H - backspace */
+ SLtt_goto_rc (Cursor_Row, Cursor_Col - 1); break;
+ case 13: /* ^M - carriage return */
+ SLtt_goto_rc (Cursor_Row, 0); break;
+ default: /* write character to screen */
+#if defined (EMX_VIDEO)
+ v_putn (ch, 1);
+#else /* EMX_VIDEO */
+# ifdef __os2__
+ VioWrtCharStrAtt (&ch, 1, Cursor_Row, Cursor_Col,
+ (BYTE*)&Attribute_Byte, 0);
+# elif defined(WIN32)
+ WriteConsole(hStdout, &ch, 1, &bytes, NULL);
+# else /* __os2__ */
+# ifdef GO32_VIDEO
+ ScreenPutChar ((int) ch, Attribute_Byte, Cursor_Col, Cursor_Row);
+# else /* GO32_VIDEO */
+ pp = mkScreenPointer (Cursor_Row, Cursor_Col);
+ p = (Attribute_Byte << 8) | (unsigned char) ch;
+
+# ifdef USE_ASM
+ SNOW_CHECK;
+# endif
+ *pp = p;
+# endif /* GO32_VIDEO */
+# endif /* __os2__ */
+#endif /* EMX_VIDEO */
+ SLtt_goto_rc (Cursor_Row, Cursor_Col + 1);
+ }
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_set_color (int obj, char *what, char *fg, char *bg);
+ *
+ * set foreground and background colors of OBJ to the attributes which
+ * correspond to the names FG and BG, respectively.
+ *
+ * WHAT is the name corresponding to the object OBJ, but is not used in
+ * this routine.
+\*----------------------------------------------------------------------*/
+void SLtt_set_color (int obj, char *what, char *fg, char *bg)
+{
+ int i, b = -1, f = -1;
+#ifdef WIN32
+ int newcolor;
+#endif
+
+ (void) what;
+
+ if ( !IsColor || (obj < 0) || (obj >= JMAX_COLORS))
+ return;
+
+ for (i = 0; i < JMAX_COLOR_NAMES; i++ )
+ {
+ if (!strcmp (fg, Color_Names [i]))
+ {
+ f = i;
+ break;
+ }
+ }
+
+ for (i = 0; i < JMAX_COLOR_NAMES; i++)
+ {
+ if (!strcmp (bg, Color_Names [i]))
+ {
+ if (Blink_Killed) b = i; else b = i & 0x7;
+ break;
+ }
+ }
+ if ((f == -1) || (b == -1) || (f == b)) return;
+#if 1
+ Color_Map [obj] = (b << 4) | f;
+#else
+
+ /*
+ 0 1 2 3
+ "black", "blue", "green", "cyan",
+ 4 5 6 7
+ "red", "magenta", "brown", "lightgray",
+ 8 9 10 11
+ "gray", "brightblue", "brightgreen", "brightcyan",
+ 12 13 14 15
+ "brightred", "brightmagenta", "yellow", "white"
+ */
+
+ /* these aren't all right yet */
+ switch (f)
+ {
+ case 0: newcolor = 0; break;
+ case 1: newcolor = FOREGROUND_BLUE; break;
+ case 2: newcolor = FOREGROUND_GREEN; break;
+ case 3: newcolor = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
+
+ case 4: newcolor = FOREGROUND_RED; break;
+ case 5: newcolor = FOREGROUND_RED | FOREGROUND_BLUE; break;
+ case 6: newcolor = FOREGROUND_GREEN | FOREGROUND_RED; break;
+ case 7: newcolor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+
+ case 8: newcolor = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; break;
+ case 9: newcolor = FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+ case 10: newcolor = FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
+ case 11: newcolor = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+
+ case 12: newcolor = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
+ case 13: newcolor = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+ case 14: newcolor = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+ case 15: newcolor = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+ }
+ // switch
+
+ /*
+ 0 1 2 3
+ "black", "blue", "green", "cyan",
+ 4 5 6 7
+ "red", "magenta", "brown", "lightgray",
+ 8 9 10 11
+ "gray", "brightblue", "brightgreen", "brightcyan",
+ 12 13 14 15
+ "brightred", "brightmagenta", "yellow", "white"
+ */
+
+ switch (b)
+ {
+ case 0: newcolor |= 0; break;
+ case 1: newcolor |= BACKGROUND_BLUE; break;
+ case 2: newcolor |= BACKGROUND_GREEN; break;
+ case 3: newcolor |= BACKGROUND_GREEN | BACKGROUND_BLUE; break;
+
+ case 4: newcolor |= BACKGROUND_RED; break;
+ case 5: newcolor |= BACKGROUND_RED | BACKGROUND_BLUE; break;
+ case 6: newcolor |= BACKGROUND_GREEN | BACKGROUND_RED; break;
+ case 7: newcolor |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY; break;
+
+ case 8: newcolor |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE; break;
+ case 9: newcolor |= BACKGROUND_BLUE | BACKGROUND_INTENSITY; break;
+ case 10: newcolor |= BACKGROUND_GREEN | BACKGROUND_INTENSITY; break;
+ case 11: newcolor |= BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY; break;
+
+ case 12: newcolor |= BACKGROUND_RED | BACKGROUND_INTENSITY; break;
+ case 13: newcolor |= BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_INTENSITY; break;
+ case 14: newcolor |= BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY; break;
+ case 15: newcolor |= BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY; break;
+ }
+ // switch
+
+ Color_Map [obj] = newcolor;
+
+#endif
+ /* if we're setting the normal color, and the attribute byte hasn't
+ been set yet, set it to the new color */
+ if ((obj == 0) && (Attribute_Byte == 0))
+ SLtt_reverse_video (0);
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_get_terminfo (void)
+\*----------------------------------------------------------------------*/
+void SLtt_get_terminfo (void)
+{
+#ifdef WIN32
+ SLtt_Screen_Rows = csbiInfo.dwMaximumWindowSize.Y;
+ SLtt_Screen_Cols = csbiInfo.dwMaximumWindowSize.X;
+#endif
+#ifdef GO32_VIDEO
+ SLtt_Screen_Rows = ScreenRows ();
+ SLtt_Screen_Cols = ScreenCols ();
+#endif
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLtt_init_video (void);
+\*----------------------------------------------------------------------*/
+void SLtt_init_video (void)
+{
+#if defined (EMX_VIDEO)
+ int OldCol, OldRow;
+#endif
+
+#ifdef HAS_SAVE_SCREEN
+ save_screen ();
+#endif
+
+ Cursor_Row = Cursor_Col = 0;
+
+#if defined (EMX_VIDEO)
+
+ v_init ();
+ if ( v_hardware () != V_MONOCHROME ) IsColor = 1; else IsColor = 0;
+
+ v_getxy(&OldCol,&OldRow);
+
+ v_gotoxy (0, 0);
+ if (IsColor)
+ {
+ if (_osmode == OS2_MODE)
+ {
+# if 0
+ /* Enable high-intensity background colors */
+ VIOINTENSITY RequestBlock;
+ RequestBlock.cb = sizeof (RequestBlock);
+ RequestBlock.type = 2; RequestBlock.fs = 1;
+ VioSetState (&RequestBlock, 0); /* nop if !fullscreen */
+# endif
+ Blink_Killed = 1;
+ }
+ else
+ {
+ Blink_Killed = 1; /* seems to work */
+ }
+ }
+
+ if (!Attribute_Byte)
+ {
+ /* find the attribute currently under the cursor */
+ v_getline (Line_Buffer, OldCol, OldRow, 1);
+ Attribute_Byte = Line_Buffer[1];
+ set_color_from_attribute (Attribute_Byte);
+ }
+
+ v_attrib (Attribute_Byte);
+ /* SLtt_Term_Cannot_Insert = 1; */
+#else /* EMX_VIDEO */
+# ifdef __os2__
+ IsColor = 1; /* is it really? */
+ {
+ /* Enable high-intensity background colors */
+ VIOINTENSITY RequestBlock;
+ RequestBlock.cb = sizeof (RequestBlock);
+ RequestBlock.type = 2; RequestBlock.fs = 1;
+ VioSetState (&RequestBlock, 0); /* nop if !fullscreen */
+ Blink_Killed = 1;
+ }
+
+ if (!Attribute_Byte)
+ {
+ /* find the attribute currently under the cursor */
+ USHORT Length = 2, Row, Col;
+ VioGetCurPos (&Row, &Col, 0);
+ VioReadCellStr ((PCH)Line_Buffer, &Length, Row, Col, 0);
+ Attribute_Byte = Line_Buffer[1];
+ set_color_from_attribute (Attribute_Byte);
+ }
+# elif defined(WIN32)
+ /* initialize the WIN32 console */
+ IsColor = 1; /* yes, the WIN32 console can do color (on a color monitor) */
+# else
+# if defined (__GO32__) || defined (__WATCOMC__)
+# ifdef GO32_VIDEO
+ SLtt_Term_Cannot_Insert = 1;
+# else
+ Video_Base = (unsigned char *) ScreenPrimary;
+# endif
+ if (!Attribute_Byte) Attribute_Byte = 0x17;
+ IsColor = 1; /* is it really? */
+
+ if (IsColor)
+ {
+ union REGS r;
+# ifdef __WATCOMC__
+ r.x.eax = 0x1003; r.x.ebx = 0;
+# else
+ r.x.ax = 0x1003; r.x.bx = 0;
+# endif
+ int86 (0x10, &r, &r);
+ Blink_Killed = 1;
+ }
+# else /* (__GO32__ or __WATCOMC__ */
+ {
+ unsigned char *p = (unsigned char far *) 0x00400049L;
+ if (*p == 7)
+ {
+ Video_Status_Port = MONO_STATUS;
+ Video_Base = (unsigned char *) MK_FP (0xb000,0000);
+ IsColor = 0;
+ }
+ else
+ {
+ Video_Status_Port = CGA_STATUS;
+ Video_Base = (unsigned char *) MK_FP (0xb800,0000);
+ IsColor = 1;
+ }
+ }
+
+ /* test for video adapter type. Of primary interest is whether there is
+ * snow or not. Assume snow if the card is color and not EGA or greater.
+ */
+
+ /* Use Ralf Brown test for EGA or greater */
+ asm mov ah, 0x12
+ asm mov bl, 0x10
+ asm mov bh, 0xFF
+ asm int 10h
+ asm cmp bh, 0xFF
+ asm je L1
+
+ /* (V)EGA */
+ asm xor bx, bx
+ asm mov SLtt_Msdos_Cheap_Video, bx
+ asm mov ax, Attribute_Byte
+ asm cmp ax, bx
+ asm jne L2
+ asm mov ax, 0x17
+ asm mov Attribute_Byte, ax
+ asm jmp L2
+
+ L1:
+ /* Not (V)EGA */
+ asm mov ah, 0x0F
+ asm int 10h
+ asm cmp al, 7
+ asm je L3
+ asm mov ax, 1
+ asm mov SLtt_Msdos_Cheap_Video, ax
+ L3:
+ asm mov ax, Attribute_Byte
+ asm cmp ax, 0
+ asm jne L2
+ asm mov ax, 0x07
+ asm mov Attribute_Byte, ax
+ L2:
+ /* toggle the blink bit so we can use hi intensity background */
+ if (IsColor && !SLtt_Msdos_Cheap_Video)
+ {
+ asm mov ax, 0x1003
+ asm mov bx, 0
+ asm int 0x10
+ Blink_Killed = 1;
+ }
+# endif /* __GO32__ or __WATCOMC__ */
+# endif /* __os2__ */
+#endif /* EMX_VIDEO */
+ SLtt_set_scroll_region (0, SLtt_Screen_Rows);
+ SLtt_Use_Ansi_Colors = IsColor;
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: int SLtt_flush_output (void);
+\*----------------------------------------------------------------------*/
+int SLtt_flush_output (void)
+{
+ fflush (stdout);
+ return -1;
+}
+
+int SLtt_set_cursor_visibility (int show)
+{
+ (void) show;
+ return -1;
+}
+
+void SLtt_set_mono (int obj_unused, char *unused, SLtt_Char_Type c_unused)
+{
+ (void) obj_unused;
+ (void) unused;
+ (void) c_unused;
+}
+
+/* /////////////////////// end of file (c source) ///////////////////// */
--- /dev/null
+/* Copyright (c) 1992, 1995 John E. Davis
+ * All rights reserved.
+ *
+ * You may distribute under the terms of either the GNU General Public
+ * License or the Perl Artistic License.
+ */
+
+#include "config.h"
+#include <stdio.h>
+
+#include <windows.h>
+#include <winbase.h>
+
+#include "slang.h"
+#include "_slang.h"
+
+#ifdef __cplusplus
+# define _DOTS_ ...
+#else
+# define _DOTS_ void
+#endif
+
+
+
+/*----------------------------------------------------------------------*\
+ * Function: static void set_ctrl_break (int state);
+ *
+ * set the control-break setting
+\*----------------------------------------------------------------------*/
+static void set_ctrl_break (int state)
+{
+}
+
+
+/*----------------------------------------------------------------------*\
+ * Function: int SLang_init_tty (int abort_char, int no_flow_control,
+ * int opost);
+ *
+ * initialize the keyboard interface and attempt to set-up the interrupt 9
+ * handler if ABORT_CHAR is non-zero.
+ * NO_FLOW_CONTROL and OPOST are only for compatiblity and are ignored.
+\*----------------------------------------------------------------------*/
+
+HANDLE hStdout, hStdin;
+CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+
+int SLang_init_tty (int abort_char, int no_flow_control, int opost)
+{
+ SMALL_RECT windowRect;
+ COORD newPosition;
+ long flags;
+
+#ifndef SLANG_SAVES_CONSOLE
+ /* first off, create a new console so the old one can be restored on exit */
+ HANDLE console = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ |FILE_SHARE_WRITE,
+ 0,
+ CONSOLE_TEXTMODE_BUFFER,
+ 0);
+ if (SetConsoleActiveScreenBuffer(console) == FALSE) {
+ return -1;
+ }
+#endif
+
+ /* start things off at the origin */
+ newPosition.X = 0;
+ newPosition.Y = 0;
+
+ /* still read in characters from stdin, but output to the new console */
+ /* this way, on program exit, the original screen is restored */
+ hStdin = GetStdHandle(STD_INPUT_HANDLE);
+/* hStdin = console; */
+
+#ifndef SLANG_SAVES_CONSOLE
+ hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+#else
+ hStdout = console;
+#endif
+
+ if (hStdin == INVALID_HANDLE_VALUE || hStdout == INVALID_HANDLE_VALUE) {
+ return -1; /* failure */
+ }
+
+ if (!GetConsoleScreenBufferInfo(hStdout, &csbiInfo)) {
+ return -1; /* failure */
+ } // if
+
+ windowRect.Left = 0;
+ windowRect.Top = 0;
+ windowRect.Right = csbiInfo.srWindow.Right - csbiInfo.srWindow.Left; //dwMaximumWindowSize.X - 1;
+ windowRect.Bottom = csbiInfo.srWindow.Bottom - csbiInfo.srWindow.Top; //dwMaximumWindowSize.Y - 1;
+ if (!SetConsoleWindowInfo(hStdout, TRUE, &windowRect)) {
+ return -1;
+ }
+
+ if (SetConsoleMode(hStdin, 0) == FALSE) {
+ return -1; /* failure */
+ }
+
+ if (SetConsoleMode(hStdout, 0) == FALSE) {
+ return -1; /* failure */
+ }
+
+ if (GetConsoleMode(hStdin, &flags)) {
+ if (flags & ENABLE_PROCESSED_INPUT) {
+ return -1;
+ }
+ }
+
+ (void) SetConsoleCursorPosition(hStdout, newPosition);
+
+ /* success */
+ return 0;
+} /* SLang_init_tty */
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLang_reset_tty (void);
+ *
+ * reset the tty before exiting
+\*----------------------------------------------------------------------*/
+void SLang_reset_tty (void)
+{
+ set_ctrl_break (1);
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: int SLsys_input_pending (int tsecs);
+ *
+ * sleep for *tsecs tenths of a sec waiting for input
+\*----------------------------------------------------------------------*/
+int SLsys_input_pending (int tsecs)
+{
+ INPUT_RECORD record;
+ long one = 1;
+ long bytesRead;
+
+ while (1)
+ {
+ if (PeekConsoleInput(hStdin, &record, 1, &bytesRead))
+ {
+ if (bytesRead == 1)
+ {
+ if ((record.EventType == KEY_EVENT)
+ && record.Event.KeyEvent.bKeyDown)
+ {
+ /* ok, there is a keypress here */
+ return 1;
+ }
+ else
+ {
+ /* something else is here, so read it and try again */
+ (void) ReadConsoleInput(hStdin, &record, 1, &bytesRead);
+ }
+ }
+ else
+ {
+ /* no Pending events */
+ return 0;
+ }
+ }
+ else
+ {
+ /* function failed */
+ return 0;
+ }
+ }
+#if 0
+ /* no delays yet */
+ /* use Sleep */
+ /*
+ int count = tsecs * 5;
+
+ if (keyWaiting()) return 1;
+ while (count > 0)
+ {
+ delay (20); 20 ms or 1/50 sec
+ if (keyWaiting()) break;
+ count--;
+ }
+ return (count);
+ */
+#endif
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: unsigned int SLsys_getkey (void);
+ *
+ * wait for and get the next available keystroke.
+ * Also re-maps some useful keystrokes.
+ *
+ * Backspace (^H) => Del (127)
+ * Ctrl-Space => ^@ (^@^3 - a pc NUL char)
+ * extended keys are prefixed by a null character
+\*----------------------------------------------------------------------*/
+unsigned int SLsys_getkey (void)
+{
+ unsigned int scan, ch, shift;
+ long key, bytesRead;
+ INPUT_RECORD record;
+
+ while (1) {
+ if (!ReadConsoleInput(hStdin, &record, 1, &bytesRead)) {
+ return 0;
+ }
+ if (record.EventType == KEY_EVENT && record.Event.KeyEvent.bKeyDown) {
+/*#ifndef __MINGW32__*/
+ return record.Event.KeyEvent.uChar.AsciiChar;
+/*#else
+ return record.Event.KeyEvent.AsciiChar;
+#endif*/
+ }
+ }
+/* ReadFile(hStdin, &key, 1, &bytesRead, NULL); */
+
+/* return key; */
+}
+
+/*----------------------------------------------------------------------*\
+ * Function: void SLang_set_abort_signal (void (*handler)(int));
+\*----------------------------------------------------------------------*/
+void SLang_set_abort_signal (void (*handler)(int))
+{
+
+}
--- /dev/null
+# Generated automatically from Makefile.in by configure.
+srcdir = .
+
+rootdir = $(srcdir)/..
+include ../Make.common
+
+CFLAGS = $(XCFLAGS)
+CPPFLAGS = $(XCPPFLAGS) -DREGEX_MALLOC
+LDFLAGS = $(XLDFLAGS)
+DEFS = $(XDEFS)
+LIBS = $(XLIBS) $(XLIB)
+OURLIBS = -lvfs -lmcslang -ledit
+INSTALL = /usr/bin/install -c
+INSTALL_PROGRAM = ${INSTALL}
+INSTALL_DATA = ${INSTALL} -m 644
+
+SRCS = dir.c util.c main.c screen.c dialog.c key.c keyxdef.c menu.c\
+ file.c win.c color.c help.c find.c profile.c user.c view.c \
+ ext.c mouse.c setup.c dlg.c option.c info.c \
+ tree.c widget.c chmod.c mad.c xcurses.c xslint.c \
+ wtools.c cons.handler.c chown.c subshell.c terms.c boxes.c \
+ hotlist.c achown.c layout.c fsusage.c mountlist.c regex.c \
+ complete.c slint.c command.c cmd.c panelize.c learn.c \
+ listmode.c utilunix.c background.c rxvt.c popt.c \
+ text.c
+
+HDRS = color.h file.h mouse.h user.h dialog.h find.h main.h \
+ util.h dir.h global.h menu.h panel.h win.h mem.h \
+ help.h profile.h dlg.h option.h tree.h info.h \
+ widget.h chmod.h cons.saver.h mad.h wtools.h chown.h \
+ subshell.h view.h setup.h key.h ext.h boxes.h \
+ hotlist.h layout.h fsusage.h mountlist.h regex.h complete.h \
+ myslang.h command.h cmd.h tty.h fs.h panelize.h achown.h \
+ learn.h listmode.h features.inc background.h \
+ x.h popt.h textconf.h i18n.h
+
+OBJS = dir.o util.o screen.o dialog.o key.o keyxdef.o menu.o\
+ file.o win.o color.o help.o find.o profile.o user.o view.o \
+ ext.o mouse.o setup.o dlg.o option.o \
+ tree.o widget.o chmod.o mad.o wtools.o info.o \
+ cons.handler.o chown.o subshell.o terms.o boxes.o \
+ hotlist.o achown.o layout.o fsusage.o mountlist.o \
+ regex.o complete.o slint.o command.o \
+ cmd.o main.o panelize.o learn.o listmode.o utilunix.o \
+ background.o rxvt.o popt.o text.o
+
+#
+# Distribution variables
+#
+
+DISTFILES = \
+ $(HDRS) $(SRCS) Makefile.in TODO ChangeLog OChangeLog man2hlp.c \
+ gindex.pl xmkdir cons.saver.c ncurses.patch mc.hlp depend.awk \
+ fixhlp.c mfmt.c
+
+# Should be: mc $(srcdir)/mc.hlp but it's remaking it always
+
+all: mc mcmfmt
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) $<
+
+cons.saver: cons.saver.o
+ $(CC) -s cons.saver.o -o cons.saver
+
+check:
+ @echo no tests are supplied.
+
+mc: $(OBJS) libvfs.a libmcslang.a libedit.a
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) -L../vfs -L../slang -L../edit $(OURLIBS) $(LIBS)
+
+mfmt: mfmt.o
+ $(CC) $(LDFLAGS) mfmt.o -o mfmt
+
+mcmfmt: mfmt
+ cp mfmt mcmfmt
+
+libvfs.a:
+ cd ../vfs; $(MAKE) libvfs.a
+ -$(RMF) libvfs.a
+ $(LN_S) ../vfs/libvfs.a .
+
+libmcslang.a:
+ cd ../slang; $(MAKE) libmcslang.a
+ -$(RMF) libmcslang.a
+ $(LN_S) ../slang/libmcslang.a .
+
+libedit.a:
+ cd ../edit; $(MAKE) libedit.a
+ -$(RMF) libedit.a
+ $(LN_S) ../edit/libedit.a .
+
+cross:
+ $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \
+ CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses "
+
+$(srcdir)/mc.hlp: $(docdir)/mc.1.in $(mclibdir)/xnc.hlp $(srcdir)/gindex.pl
+ $(MAKE) man2hlp
+ ./man2hlp 58 $(docdir)/mc.1.in | cat - $(mclibdir)/xnc.hlp | \
+ perl $(srcdir)/gindex.pl > $(srcdir)/mc.hlp
+
+mc.html: $(docdir)/mc.1.in man2hlp
+ ./man2hlp 0 $(docdir)/mc.1.in > body.html
+ cat index.html body.html > mc.html
+ $(RM) index.html body.html
+
+TAGS: $(SRCS)
+ etags $(SRCS)
+
+clean:
+ $(RMF) mc cons.saver man2hlp fixhlp *.o core a.out mc.html mcmfmt
+ $(RMF) libvfs.a libedit.a libmcslang.a mfmt
+
+realclean: clean
+ $(RMF) .depend
+ $(RMF) TAGS
+ $(RMF) *~
+
+distclean:
+ -$(RMF) $(srcdir)/*~ $(srcdir)/mc $(srcdir)/cons.saver
+ -$(RMF) $(srcdir)/mfmt
+ -$(RMF) $(srcdir)/man2hlp $(srcdir)/fixhlp $(srcdir)/*.o $(srcdir)/core
+ -$(RMF) $(srcdir)/a.out $(srcdir)/mc.html
+ -$(RMF) $(srcdir)/libvfs.a $(srcdir)/libmcslang.a $(srcdir)/libedit.a
+ -if test $(srcdir) = .; then $(MAKE) realclean; fi
+ -$(RMF) $(srcdir)/Makefile
+
+install: mc mfmt
+ $(INSTALL_PROGRAM) mc $(DESTDIR)$(bindir)/$(binprefix)mc
+ $(INSTALL_PROGRAM) mcmfmt $(DESTDIR)$(bindir)/$(binprefix)mcmfmt
+ $(SEDCMD2) < $(srcdir)/mc.hlp > $(DESTDIR)$(libdir)/$(libprefix)mc.hlp
+
+install.saver: cons.saver
+ $(INSTALL_PROGRAM) -m 4755 cons.saver $(DESTDIR)$(suppbindir)/cons.saver
+
+uninstall:
+ cd $(bindir); $(RMF) $(binprefix)mc
+ cd $(bindir); $(RMF) $(binprefix)mcmfmt
+ cd $(bindir); $(RMF) $(binprefix)cons.saver
+ cd $(libdir); $(RMF) $(libprefix)mc.hlp
+
+distcopy: $(srcdir)/mc.hlp
+ $(CP) $(DISTFILES) ../../mc-$(VERSION)/src
+
+depend dep: mcdep
+
+fastdeploc: fastdepslang fastdepvfs
+
+# ***Dependencies***Do not edit***
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
+# ***End of dependencies***
--- /dev/null
+/* Chown-advanced command -- for the Midnight Commander
+ Copyright (C) 1994, 1995 Radek Doulik
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+/* Needed for the extern declarations of integer parameters */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> /* For malloc() */
+#include <errno.h> /* For errno on SunOS systems */
+#include "mad.h"
+#include "tty.h"
+#include "util.h" /* Needed for the externs */
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+#include "wtools.h" /* For init_box_colors() */
+#include "key.h" /* XCTRL and ALT macros */
+
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "chmod.h"
+#include "main.h"
+#include "../vfs/vfs.h"
+
+#define BX 5
+#define BY 6
+
+#define TX 50
+#define TY 2
+
+#define BUTTONS 9
+
+#define B_SETALL B_USER
+#define B_SKIP B_USER + 1
+
+#define B_OWN B_USER + 3
+#define B_GRP B_USER + 4
+#define B_OTH B_USER + 5
+#define B_OUSER B_USER + 6
+#define B_OGROUP B_USER + 7
+
+struct {
+ int ret_cmd, flags, y, x;
+ char *text;
+} chown_advanced_but [BUTTONS] = {
+ { B_CANCEL, NORMAL_BUTTON, 4, 55, N_("&Cancel") },
+ { B_ENTER, DEFPUSH_BUTTON,4, 45, N_("&Set") },
+ { B_SKIP, NORMAL_BUTTON, 4, 36, N_("S&kip") },
+ { B_SETALL, NORMAL_BUTTON, 4, 24, N_("Set &all")},
+ { B_ENTER, NARROW_BUTTON, 0, 47, " "},
+ { B_ENTER, NARROW_BUTTON, 0, 29, " "},
+ { B_ENTER, NARROW_BUTTON, 0, 19, " "},
+ { B_ENTER, NARROW_BUTTON, 0, 11, " "},
+ { B_ENTER, NARROW_BUTTON, 0, 3, " "},
+};
+
+WButton *b_att[3]; /* permission */
+WButton *b_user, *b_group; /* owner */
+
+static int files_on_begin; /* Number of files at startup */
+static int flag_pos;
+static int x_toggle;
+static char ch_flags[11];
+static char *ch_perm = "rwx";
+static umode_t ch_cmode;
+struct stat *sf_stat;
+static int need_update;
+static int end_chown;
+static int current_file;
+static int single_set;
+static char *fname;
+
+static void get_ownership ()
+{ /* set buttons - ownership */
+ char *name_t;
+
+ name_t = name_trunc (get_owner (sf_stat->st_uid), 15);
+ memset (b_user->text, ' ', 15);
+ strncpy (b_user->text, name_t, strlen (name_t));
+ name_t = name_trunc (get_group (sf_stat->st_gid), 15);
+ memset (b_group->text, ' ', 15);
+ strncpy (b_group->text, name_t, strlen (name_t));
+}
+
+
+static int inc_flag_pos (int f_pos)
+{
+ if (flag_pos == 10) {
+ flag_pos = 0;
+ return 0;
+ }
+ flag_pos++;
+ if (!(flag_pos % 3) || f_pos > 2)
+ return 0;
+ return 1;
+}
+
+static int dec_flag_pos (int f_pos)
+{
+ if (!flag_pos) {
+ flag_pos = 10;
+ return 0;
+ }
+ flag_pos--;
+ if (!((flag_pos + 1) % 3) || f_pos > 2)
+ return 0;
+ return 1;
+}
+
+static void set_perm_by_flags (char *s, int f_p)
+{
+ int i;
+
+ for (i = 0; i < 3; i++)
+ if (ch_flags[f_p + i] == '+')
+ s[i] = ch_perm[i];
+ else if (ch_flags[f_p + i] == '-')
+ s[i] = '-';
+ else
+ s[i] = (ch_cmode & (1 << (8 - f_p - i))) ? ch_perm[i] : '-';
+}
+
+static void set_perm (char *s, int p)
+{
+ s[0] = (p & 4) ? 'r' : '-';
+ s[1] = (p & 2) ? 'w' : '-';
+ s[2] = (p & 1) ? 'x' : '-';
+}
+
+static umode_t get_perm (char *s, int base)
+{
+ umode_t m;
+
+ m = 0;
+ m |= (s [0] == '-') ? 0 :
+ ((s[0] == '+') ? (1 << (base + 2)) : (1 << (base + 2)) & ch_cmode);
+
+ m |= (s [1] == '-') ? 0 :
+ ((s[1] == '+') ? (1 << (base + 1)) : (1 << (base + 1)) & ch_cmode);
+
+ m |= (s [2] == '-') ? 0 :
+ ((s[2] == '+') ? (1 << base) : (1 << base) & ch_cmode);
+
+ return m;
+}
+
+static umode_t get_mode ()
+{
+ umode_t m;
+
+ m = ch_cmode ^ (ch_cmode & 0777);
+ m |= get_perm (ch_flags, 6);
+ m |= get_perm (ch_flags + 3, 3);
+ m |= get_perm (ch_flags + 6, 0);
+
+ return m;
+}
+
+static void print_flags (void)
+{
+ int i;
+
+ attrset (COLOR_NORMAL);
+
+ for (i = 0; i < 3; i++){
+ dlg_move (ch_dlg, BY+1, 9+i);
+ addch (ch_flags [i]);
+ }
+
+ for (i = 0; i < 3; i++){
+ dlg_move (ch_dlg, BY + 1, 17 + i);
+ addch (ch_flags [i+3]);
+ }
+
+ for (i = 0; i < 3; i++){
+ dlg_move (ch_dlg, BY + 1, 25 + i);
+ addch (ch_flags [i+6]);
+ }
+
+ set_perm_by_flags (b_att[0]->text, 0);
+ set_perm_by_flags (b_att[1]->text, 3);
+ set_perm_by_flags (b_att[2]->text, 6);
+
+ for (i = 0; i < 15; i++){
+ dlg_move (ch_dlg, BY+1, 35+i);
+ addch (ch_flags[9]);
+ }
+ for (i = 0; i < 15; i++){
+ dlg_move (ch_dlg, BY + 1, 53 + i);
+ addch (ch_flags[10]);
+ }
+}
+
+static void update_mode (Dlg_head * h)
+{
+ print_flags ();
+ attrset (COLOR_NORMAL);
+ dlg_move (h, BY + 2, 9);
+ printw ("%12o", get_mode ());
+ send_message (h, h->current->widget, WIDGET_FOCUS, 0);
+}
+
+static int l_call (void *data)
+{
+ return 1;
+}
+
+static int chl_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+ case DLG_DRAW:
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 0, 0, 13, 17);
+ break;
+
+ case DLG_KEY:
+ switch (Par) {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ h->ret_value = Par;
+ dlg_stop (h);
+ }
+ }
+ return 0;
+}
+
+static void do_enter_key (Dlg_head *h, int f_pos)
+{
+ Dlg_head *chl_dlg;
+ WListbox *chl_list;
+ struct passwd *chl_pass;
+ struct group *chl_grp;
+ WLEntry *fe;
+ int lxx, lyy, chl_end, b_pos;
+
+ do {
+ lxx = (COLS - 74) / 2 + ((f_pos == 3) ? 35 : 53);
+ lyy = (LINES - 13) / 2;
+ chl_end = 0;
+
+ chl_dlg = create_dlg (lyy, lxx, 13, 17, dialog_colors, chl_callback,
+ "[Chown-advanced]", "achown_enter", DLG_NONE);
+
+ /* get new listboxes */
+ chl_list = listbox_new (1, 1, 15, 11, 0, l_call, NULL);
+
+ listbox_add_item (chl_list, 0, 0, "<Unknown>", NULL);
+
+ if (f_pos == 3) {
+ /* get and put user names in the listbox */
+ setpwent ();
+ while ((chl_pass = getpwent ()))
+ listbox_add_item (chl_list, 0, 0, chl_pass->pw_name, NULL);
+ endpwent ();
+ fe = listbox_search_text (chl_list, get_owner (sf_stat->st_uid));
+ }
+ else
+ {
+ /* get and put group names in the listbox */
+ setgrent ();
+ while ((chl_grp = getgrent ())) {
+ listbox_add_item (chl_list, 0, 0, chl_grp->gr_name, NULL);
+ }
+ endgrent ();
+ fe = listbox_search_text (chl_list, get_group (sf_stat->st_gid));
+ }
+
+ if (fe)
+ listbox_select_entry (chl_list, fe);
+
+ b_pos = chl_list->pos;
+ add_widget (chl_dlg, chl_list);
+
+ run_dlg (chl_dlg);
+
+ if (b_pos != chl_list->pos){
+ int ok = 0;
+ if (f_pos == 3){
+ chl_pass = getpwnam (chl_list->current->text);
+ if (chl_pass){
+ ok = 1;
+ sf_stat->st_uid = chl_pass->pw_uid;
+ }
+ } else {
+ chl_grp = getgrnam (chl_list->current->text);
+ if (chl_grp){
+ sf_stat->st_gid = chl_grp->gr_gid;
+ ok = 1;
+ }
+ }
+ if (ok){
+ ch_flags [f_pos + 6] = '+';
+ get_ownership ();
+ }
+ dlg_focus (h);
+ if (ok)
+ print_flags ();
+ }
+ if (chl_dlg->ret_value == KEY_LEFT){
+ if (f_pos == 4)
+ chl_end = 1;
+ dlg_one_up (ch_dlg);
+ f_pos--;
+ } else if (chl_dlg->ret_value == KEY_RIGHT) {
+ if (f_pos == 3)
+ chl_end = 1;
+ dlg_one_down (ch_dlg);
+ f_pos++;
+ }
+ /* Here we used to redraw the window */
+ destroy_dlg (chl_dlg);
+ } while (chl_end);
+}
+
+static void chown_refresh (void)
+{
+ attrset (COLOR_NORMAL);
+ dlg_erase (ch_dlg);
+
+ draw_box (ch_dlg, 1, 2, 11, 70);
+
+ dlg_move (ch_dlg, BY - 1, 8);
+ addstr (_("owner"));
+ dlg_move (ch_dlg, BY - 1, 16);
+ addstr (_("group"));
+ dlg_move (ch_dlg, BY - 1, 24);
+ addstr (_("other"));
+
+ dlg_move (ch_dlg, BY - 1, 35);
+ addstr (_("owner"));
+ dlg_move (ch_dlg, BY - 1, 53);
+ addstr (_("group"));
+
+ dlg_move (ch_dlg, 3, 4);
+ addstr (_("On"));
+ dlg_move (ch_dlg, BY + 1, 4);
+ addstr (_("Flag"));
+ dlg_move (ch_dlg, BY + 2, 4);
+ addstr (_("Mode"));
+
+
+ if (!single_set){
+ dlg_move (ch_dlg, 3, 54);
+ printw (_("%6d of %d"), files_on_begin - (cpanel->marked) + 1,
+ files_on_begin);
+ }
+
+ print_flags ();
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (ch_dlg, 1, 24);
+ addstr (_(" Chown advanced command "));
+}
+
+static void chown_info_update ()
+{
+ /* display file info */
+ attrset (COLOR_NORMAL);
+
+ /* name && mode */
+ dlg_move (ch_dlg, 3, 8);
+ printw ("%s", name_trunc (fname, 45));
+ dlg_move (ch_dlg, BY + 2, 9);
+ printw ("%12o", get_mode ());
+
+ /* permissions */
+ set_perm (b_att[0]->text, sf_stat->st_mode >> 6);
+ set_perm (b_att[1]->text, sf_stat->st_mode >> 3);
+ set_perm (b_att[2]->text, sf_stat->st_mode);
+}
+
+static void b_setpos (int f_pos) {
+ b_att[0]->hotpos=-1;
+ b_att[1]->hotpos=-1;
+ b_att[2]->hotpos=-1;
+ b_att[f_pos]->hotpos = (flag_pos % 3);
+}
+
+static int advanced_chown_callback (Dlg_head * h, int Par, int Msg)
+{
+ int i = 0, f_pos = BUTTONS - h->current->dlg_id - single_set - 1;
+
+ switch (Msg) {
+ case DLG_DRAW:
+ chown_refresh ();
+ chown_info_update ();
+ return 1;
+
+ case DLG_POST_KEY:
+ if (f_pos < 3)
+ b_setpos (f_pos);
+ break;
+
+ case DLG_FOCUS:
+ if (f_pos < 3) {
+ if ((flag_pos / 3) != f_pos)
+ flag_pos = f_pos * 3;
+ b_setpos (f_pos);
+ } else if (f_pos < 5)
+ flag_pos = f_pos + 6;
+ break;
+
+ case DLG_KEY:
+ switch (Par) {
+
+ case XCTRL('b'):
+ case KEY_LEFT:
+ if (f_pos < 5)
+ return (dec_flag_pos (f_pos));
+ break;
+
+ case XCTRL('f'):
+ case KEY_RIGHT:
+ if (f_pos < 5)
+ return (inc_flag_pos (f_pos));
+ break;
+
+ case ' ':
+ if (f_pos < 3)
+ return 1;
+ break;
+
+ case '\n':
+ case KEY_ENTER:
+ if (f_pos <= 2 || f_pos >= 5)
+ break;
+ do_enter_key (h, f_pos);
+ return 1;
+
+ case ALT ('x'):
+ i++;
+
+ case ALT ('w'):
+ i++;
+
+ case ALT ('r'):
+ Par = i + 3;
+ for (i = 0; i < 3; i++)
+ ch_flags[i * 3 + Par - 3] = (x_toggle & (1 << Par)) ? '-' : '+';
+ x_toggle ^= (1 << Par);
+ update_mode (h);
+ dlg_broadcast_msg (h, WIDGET_DRAW, 0);
+ send_message (h, h->current->widget, WIDGET_FOCUS, 0);
+ break;
+
+ case XCTRL ('x'):
+ i++;
+
+ case XCTRL ('w'):
+ i++;
+
+ case XCTRL ('r'):
+ Par = i;
+ for (i = 0; i < 3; i++)
+ ch_flags[i * 3 + Par] = (x_toggle & (1 << Par)) ? '-' : '+';
+ x_toggle ^= (1 << Par);
+ update_mode (h);
+ dlg_broadcast_msg (h, WIDGET_DRAW, 0);
+ send_message (h, h->current->widget, WIDGET_FOCUS, 0);
+ break;
+
+ case 'x':
+ i++;
+
+ case 'w':
+ i++;
+
+ case 'r':
+ if (f_pos > 2)
+ break;
+ flag_pos = f_pos * 3 + i; /* (strchr(ch_perm,Par)-ch_perm); */
+ if (((WButton *) h->current->widget)->text[(flag_pos % 3)] == '-')
+ ch_flags[flag_pos] = '+';
+ else
+ ch_flags[flag_pos] = '-';
+ update_mode (h);
+ break;
+
+ case '4':
+ i++;
+
+ case '2':
+ i++;
+
+ case '1':
+ if (f_pos > 2)
+ break;
+ flag_pos = i + f_pos * 3;
+ ch_flags[flag_pos] = '=';
+ update_mode (h);
+ break;
+
+ case '-':
+ if (f_pos > 2)
+ break;
+
+ case '*':
+ if (Par == '*')
+ Par = '=';
+
+ case '=':
+ case '+':
+ if (f_pos > 4)
+ break;
+ ch_flags[flag_pos] = Par;
+ update_mode (h);
+ advanced_chown_callback (h, KEY_RIGHT, DLG_KEY);
+ if (flag_pos>8 || !(flag_pos%3)) dlg_one_down (h);
+
+ break;
+ }
+ return 0;
+ }
+ return 0;
+}
+
+static void init_chown_advanced (void)
+{
+ int i;
+
+ sf_stat = (struct stat *) malloc (sizeof (struct stat));
+ do_refresh ();
+ end_chown = need_update = current_file = 0;
+ single_set = (cpanel->marked < 2) ? 2 : 0;
+ memset (ch_flags, '=', 11);
+ flag_pos = 0;
+ x_toggle = 070;
+
+ ch_dlg = create_dlg (0, 0, 13, 74, dialog_colors, advanced_chown_callback,
+ "[Chown-advanced]", "achown", DLG_CENTER);
+
+#define XTRACT(i) BY+chown_advanced_but[i].y, BX+chown_advanced_but[i].x, \
+ chown_advanced_but[i].ret_cmd, chown_advanced_but[i].flags, chown_advanced_but[i].text, \
+ 0, 0, NULL
+
+ for (i = 0; i < BUTTONS - 5; i++)
+ if (!single_set || i < 2)
+ add_widget (ch_dlg, button_new (XTRACT (i)));
+
+ b_att[0] = button_new (XTRACT (8));
+ b_att[1] = button_new (XTRACT (7));
+ b_att[2] = button_new (XTRACT (6));
+ b_user = button_new (XTRACT (5));
+ b_group = button_new (XTRACT (4));
+
+ add_widget (ch_dlg, b_group);
+ add_widget (ch_dlg, b_user);
+ add_widget (ch_dlg, b_att[2]);
+ add_widget (ch_dlg, b_att[1]);
+ add_widget (ch_dlg, b_att[0]);
+}
+
+void chown_advanced_done (void)
+{
+ free (sf_stat);
+ if (need_update)
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+#if 0
+static inline void do_chown (uid_t u, gid_t g)
+{
+ chown (cpanel->dir.list[current_file].fname, u, g);
+ file_mark (cpanel, current_file, 0);
+}
+#endif
+
+static char *next_file (void)
+{
+ while (!cpanel->dir.list[current_file].f.marked)
+ current_file++;
+
+ return cpanel->dir.list[current_file].fname;
+}
+
+static void apply_advanced_chowns (struct stat *sf)
+{
+ char *fname;
+ gid_t a_gid = sf->st_gid;
+ uid_t a_uid = sf->st_uid;
+
+ fname = cpanel->dir.list[current_file].fname;
+ need_update = end_chown = 1;
+ if (mc_chmod (fname, get_mode ()) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chmod \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ /* call mc_chown only, if mc_chmod didn't fail */
+ else if (mc_chown (fname, (ch_flags[9] == '+') ? sf->st_uid : -1,
+ (ch_flags[10] == '+') ? sf->st_gid : -1) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chown \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ do_file_mark (cpanel, current_file, 0);
+
+ do {
+ fname = next_file ();
+
+ if (!stat_file (fname, sf))
+ break;
+ ch_cmode = sf->st_mode;
+ if (mc_chmod (fname, get_mode ()) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chmod \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ /* call mc_chown only, if mc_chmod didn't fail */
+ else if (mc_chown (fname, (ch_flags[9] == '+') ? a_uid : -1, (ch_flags[10] == '+') ? a_gid : -1) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chown \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+
+ do_file_mark (cpanel, current_file, 0);
+ } while (cpanel->marked);
+}
+
+void chown_advanced_cmd (void)
+{
+
+ files_on_begin = cpanel->marked;
+
+ if (!vfs_current_is_local ()) {
+ if (vfs_current_is_extfs ()) {
+ message (1, _(" Oops... "),
+ _(" I can't run the Advanced Chown command on an extfs "));
+ return;
+ } else if (vfs_current_is_tarfs ()) {
+ message (1, _(" Oops... "),
+ _(" I can't run the Advanced Chown command on a tarfs "));
+ return;
+ }
+ }
+
+ do { /* do while any files remaining */
+ init_chown_advanced ();
+
+ if (cpanel->marked)
+ fname = next_file (); /* next marked file */
+ else
+ fname = selection (cpanel)->fname; /* single file */
+
+ if (!stat_file (fname, sf_stat)){ /* get status of file */
+ destroy_dlg (ch_dlg);
+ break;
+ }
+ ch_cmode = sf_stat->st_mode;
+
+ chown_refresh ();
+
+ get_ownership ();
+
+ /* game can begin */
+ run_dlg (ch_dlg);
+
+ switch (ch_dlg->ret_value) {
+ case B_CANCEL:
+ end_chown = 1;
+ break;
+
+ case B_ENTER:
+ need_update = 1;
+ if (mc_chmod (fname, get_mode ()) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chmod \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ /* call mc_chown only, if mc_chmod didn't fail */
+ else if (mc_chown (fname, (ch_flags[9] == '+') ? sf_stat->st_uid : -1, (ch_flags[10] == '+') ? sf_stat->st_gid : -1) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chown \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ break;
+ case B_SETALL:
+ apply_advanced_chowns (sf_stat);
+ break;
+
+ case B_SKIP:
+ break;
+
+ }
+
+ if (cpanel->marked && ch_dlg->ret_value != B_CANCEL) {
+ do_file_mark (cpanel, current_file, 0);
+ need_update = 1;
+ }
+ destroy_dlg (ch_dlg);
+ } while (cpanel->marked && !end_chown);
+
+ chown_advanced_done ();
+}
--- /dev/null
+#ifndef __ACHOWN_H
+#define __ACHOWN_H
+void chown_advanced_cmd (void);
+#endif
--- /dev/null
+/* {{{ Copyright */
+
+/* Background support.
+ Copyright (C) 1996 The Free Software Foundation
+
+ Written by: 1996 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* }}} */
+
+#include <config.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include "dlg.h"
+#include "widget.h"
+#include "wtools.h"
+
+/*
+ * We currenlty only support one way of comunicating the background
+ * and foreground process by using the socketpair system call
+ */
+#ifdef USE_NETCODE
+# include <sys/socket.h>
+#endif
+#include "tty.h"
+#include "util.h"
+#include "dialog.h"
+#include "file.h"
+#include "background.h"
+#include "mad.h"
+#include "key.h" /* For add_select_channel(), delete_select_channel() */
+
+/* If true, this is a background process */
+int we_are_background = 0;
+
+/* Ugh, ugly hack */
+extern int do_append;
+extern int recursive_result;
+
+#ifdef WITH_BACKGROUND
+/* If set background tasks wait to be attached */
+int background_wait = 0;
+
+#ifndef HAVE_SOCKETPAIR
+int socketpair(int, int, int, int fd[2]);
+#endif
+
+/* File descriptor for talking to our parent */
+static int parent_fd;
+
+#define MAXCALLARGS 4 /* Number of arguments supported */
+#define mymsg "Desde el hijo\n\r"
+
+struct TaskList *task_list = NULL;
+
+void
+register_task_running (pid_t pid, int fd, char *info)
+{
+ TaskList *new;
+
+ new = xmalloc (sizeof (TaskList), "note_task_running");
+ new->pid = pid;
+ new->info = info;
+ new->state = Task_Running;
+ new->next = task_list;
+ new->fd = fd;
+ task_list = new;
+
+ add_select_channel (fd, background_attention, (void *) pid);
+}
+
+void
+unregister_task_running (pid_t pid, int fd)
+{
+ TaskList *p = task_list;
+ TaskList *prev = 0;
+
+ while (p){
+ if (p->pid == pid){
+ if (prev)
+ prev->next = p->next;
+ else
+ task_list = p->next;
+ free (p->info);
+ free (p);
+ break;
+ }
+ prev = p;
+ p = p->next;
+ }
+ delete_select_channel (fd);
+}
+
+/*
+ * Try to make the Midnight Commander a background job
+ *
+ * Returns:
+ * 1 for parent
+ * 0 for child
+ * -1 on failure
+ */
+int
+do_background (char *info)
+{
+ int comm [2]; /* control connection stream */
+ int pid;
+
+ if (socketpair (AF_UNIX, SOCK_STREAM, 0, comm) == -1)
+ return -1;
+
+ if ((pid = fork ()) == -1)
+ return -1;
+
+ if (pid == 0){
+ int nullfd;
+
+ parent_fd = comm [1];
+ we_are_background = 1;
+
+ /* Make stdin/stdout/stderr point somewhere */
+ close (0);
+ close (1);
+ close (2);
+
+ if ((nullfd = open ("/dev/null", O_RDONLY)) != -1){
+ dup2 (nullfd, 0);
+ dup2 (nullfd, 1);
+ dup2 (nullfd, 2);
+ }
+
+ /* To make it obvious if it fails, there is a bug report on this */
+ write (2, mymsg, sizeof (mymsg));
+ write (1, mymsg, sizeof (mymsg));
+
+ /* Just for debugging the background back end */
+ if (background_wait){
+ volatile int i = 1;
+
+ while (i)
+ ;
+ }
+ return 0;
+ } else {
+ close (comm [1]);
+ register_task_running (pid, comm [0], info);
+ return 1;
+ }
+}
+
+char *
+background_title (char *str)
+{
+ char *result = copy_strings (_("Background process:"), str, NULL);
+
+ return result;
+}
+
+/* {{{ Routines that do the real job */
+void
+real_message_1s (enum OperationMode mode, int *flags, char *title, char *str1)
+{
+ char *full_title;
+
+ if (mode == Background)
+ full_title = background_title (title);
+ else
+ full_title = title;
+
+ message (*flags, title, str1);
+
+ if (title != full_title)
+ free (full_title);
+}
+
+void
+real_message_2s (enum OperationMode mode, int *flags, char *title, char *str1, char *str2)
+{
+ char *full_title;
+
+ if (mode == Background)
+ full_title = background_title (title);
+ else
+ full_title = title;
+
+ message (*flags, title, str1, str2);
+
+ if (title != full_title)
+ free (full_title);
+}
+
+void
+real_message_3s (enum OperationMode mode, int *flags, char *title, char *str1, char *str2, const char *str3)
+{
+ char *full_title;
+
+ if (mode == Background)
+ full_title = background_title (title);
+ else
+ full_title = title;
+
+ message (*flags, title, str1, str2, str3);
+
+ if (title != full_title)
+ free (full_title);
+}
+/* }}} */
+
+/* {{{ Parent handlers */
+
+/* Parent/child protocol
+ *
+ * the child (the background) process send the following:
+ * void *routine -- routine to be invoked in the parent
+ * int nargc -- number of arguments
+ * int type -- Return argument type.
+ *
+ * If the routine is zero, then it is a way to tell the parent
+ * that the process is dying.
+ *
+ * nargc arguments in the following format:
+ * int size of the coming block
+ * size bytes with the block
+ *
+ * Now, the parent loads all those and then invokes
+ * the routine with pointers to the information passed
+ * (we just support pointers).
+ *
+ * If the return type is integer:
+ *
+ * the parent then writes an int to the child with
+ * the return value from the routine and the values
+ * of any global variable that is modified in the parent
+ * currently: do_append and recursive_result.
+ *
+ * If the return type is a string:
+ *
+ * the parent writes the resulting string lenght
+ * if the result string was NULL or the empty string,
+ * then the lenght is zero.
+ * The parent then writes the string lenght and frees
+ * the result string.
+ */
+/*
+ * Receive requests from background process and invoke the
+ * specified routine
+ */
+
+int
+background_attention (int fd, void *xpid)
+{
+ void *routine;
+ int argc, i, result, status;
+ char *data [MAXCALLARGS];
+ char *resstr;
+ pid_t pid = (pid_t) xpid;
+ int bytes;
+ enum ReturnType type;
+ char *background_process_error = _(" Background process error ");
+
+ bytes = read (fd, &routine, sizeof (routine));
+ if (bytes < (sizeof (routine))){
+ if (errno == ECHILD)
+ message (1, background_process_error, _(" Child died unexpectedly "));
+ else
+ message (1, background_process_error, _(" Unknown error in child "));
+ unregister_task_running (pid, fd);
+ waitpid (pid, &status, 0);
+ return 0;
+ }
+
+ /* If the routine is zero, then the child is telling us that he is dying */
+ if ((int) routine == MSG_CHILD_EXITING){
+ unregister_task_running (pid, fd);
+ waitpid (pid, &status, 0);
+ return 0;
+ }
+
+ read (fd, &argc, sizeof (argc));
+ if (argc > MAXCALLARGS){
+ message (1, _(" Background protocol error "),
+ _(" Background process sent us a request for more arguments \n"
+ " than we can handle. \n"));
+ }
+ read (fd, &type, sizeof (type));
+
+ for (i = 0; i < argc; i++){
+ int size;
+
+ read (fd, &size, sizeof (size));
+ data [i] = xmalloc (size+1, "RPC Arguments");
+ read (fd, data [i], size);
+
+ data [i][size] = 0; /* NULL terminate the blocks (they could be strings) */
+ }
+
+ /* Handle the call */
+ if (type == Return_Integer){
+ switch (argc){
+ case 1:
+ result = (*(int (*)(int, char *))routine)(Background, data [0]);
+ break;
+ case 2:
+ result = (*(int (*)(int, char *, char *))routine)
+ (Background, data [0], data [1]);
+ break;
+ case 3:
+ result = (*(int (*)(int, char *, char *, char *))routine)
+ (Background, data [0], data [1], data [2]);
+ break;
+ case 4:
+ result = (*(int (*)(int, char *, char *, char *, char *))routine)
+ (Background, data [0], data [1], data [2], data [3]);
+ break;
+ }
+
+ /* Send the result code and the value for shared variables */
+ write (fd, &result, sizeof (int));
+ write (fd, &do_append, sizeof (do_append));
+ write (fd, &recursive_result, sizeof (recursive_result));
+
+ } else if (type == Return_String) {
+ int len;
+
+ /* FIXME: string routines should also use the Foreground/Background
+ * parameter. Currently, this is not used here
+ */
+ switch (argc){
+ case 1:
+ resstr = (*(char * (*)(char *))routine)(data [0]);
+ break;
+ case 2:
+ resstr = (*(char * (*)(char *, char *))routine)
+ (data [0], data [1]);
+ break;
+ case 3:
+ resstr = (*(char * (*)(char *, char *, char *))routine)
+ (data [0], data [1], data [2]);
+ break;
+ case 4:
+ resstr = (*(char * (*)(char *, char *, char *, char *))routine)
+ (data [0], data [1], data [2], data [3]);
+ break;
+ }
+ if (resstr){
+ len = strlen (resstr);
+ write (fd, &len, sizeof (len));
+ if (len){
+ write (fd, resstr, len);
+ free (resstr);
+ }
+ } else {
+ len = 0;
+ write (fd, &len, sizeof (len));
+ }
+ }
+ for (i = 0; i < argc; i++)
+ free (data [i]);
+
+ do_refresh ();
+ mc_refresh ();
+#ifndef HAVE_X
+ doupdate ();
+#endif
+ return 0;
+}
+
+
+/* }}} */
+
+/* {{{ client RPC routines */
+void
+parent_call_header (void *routine, int argc, enum ReturnType type)
+{
+ write (parent_fd, &routine, sizeof (routine));
+ write (parent_fd, &argc, sizeof (int));
+ write (parent_fd, &type, sizeof (type));
+}
+
+int
+parent_call (void *routine, int argc, ...)
+{
+ va_list ap;
+ int i;
+
+ va_start (ap, argc);
+ parent_call_header (routine, argc, Return_Integer);
+ for (i = 0; i < argc; i++){
+ int len;
+ void *value;
+
+ len = va_arg (ap, int);
+ value = va_arg (ap, void *);
+ write (parent_fd, &len, sizeof (int));
+ write (parent_fd, value, len);
+ }
+ /* Besides the regular result, get the value for
+ * variables that may be modified in the parent that affect our behaviour
+ */
+ read (parent_fd, &i, sizeof (int));
+ read (parent_fd, &do_append, sizeof (do_append));
+ read (parent_fd, &recursive_result, sizeof (recursive_result));
+ return i;
+}
+
+char *
+parent_call_string (void *routine, int argc, ...)
+{
+ va_list ap;
+ char *str;
+ int i;
+
+ va_start (ap, argc);
+ parent_call_header (routine, argc, Return_String);
+ for (i = 0; i < argc; i++){
+ int len;
+ void *value;
+
+ len = va_arg (ap, int);
+ value = va_arg (ap, void *);
+ write (parent_fd, &len, sizeof (int));
+ write (parent_fd, value, len);
+ }
+ read (parent_fd, &i, sizeof (int));
+ if (!i)
+ return NULL;
+ str = xmalloc (i + 1, "parent_return");
+ read (parent_fd, str, i);
+ str [i] = 0;
+ return str;
+}
+
+void
+tell_parent (int msg)
+{
+ write (parent_fd, &msg, sizeof (int));
+}
+
+int
+call_1s (int (*routine)(enum OperationMode, char *), char *str)
+{
+ if (we_are_background)
+ return parent_call ((void *)routine, 1, strlen (str), str);
+ else
+ return (*routine)(Foreground, str);
+}
+
+void
+message_1s (int flags, char *title, char *str1)
+{
+ if (we_are_background)
+ parent_call ((void *)real_message_1s, 3, sizeof (flags), &flags,
+ strlen (title), title, strlen (str1), str1);
+ else
+ real_message_1s (Foreground, &flags, title, str1);
+}
+
+void
+message_2s (int flags, char *title, char *str1, char *str2)
+{
+ if (we_are_background)
+ parent_call ((void *)real_message_2s, 4, sizeof (flags), &flags,
+ strlen (title), title, strlen (str1), str1,
+ strlen (str2), str2);
+ else
+ real_message_2s (Foreground, &flags, title, str1, str2);
+}
+
+void
+message_3s (int flags, char *title, char *str1, char *str2, const char *str3)
+{
+ if (we_are_background)
+ parent_call ((void *)real_message_3s, 3, sizeof (flags), &flags,
+ strlen (title), title, strlen (str1), str1,
+ strlen (str2), str2, strlen (str3), str3);
+ else
+ real_message_3s (Foreground, &flags, title, str1, str2, str3);
+}
+
+char *
+input_dialog_help (char *header, char *text, char *help, char *def_text)
+{
+ extern char *real_input_dialog_help (char *header, char *text, char *help, char *def_text);
+ if (we_are_background)
+ return parent_call_string ((void *)real_input_dialog_help, 4,
+ strlen (header), header,
+ strlen (text), text,
+ strlen (help), help,
+ strlen (def_text), def_text);
+ else
+ return real_input_dialog_help (header, text, help, def_text);
+}
+
+#else /* Else => No background code support */
+
+/* {{{ Stubs if background code is not supported */
+void
+message_1s (int flags, char *title, char *str1)
+{
+ message (flags, title, str1);
+}
+
+void
+message_2s (int flags, char *title, char *str1, char *str2)
+{
+ message (flags, title, str1, str2);
+}
+
+void
+message_3s (int flags, char *title, char *str1, char *str2, const char *str3)
+{
+ message (flags, title, str1, str2, str3);
+}
+
+char *
+input_dialog_help (char *header, char *text, char *help, char *def_text)
+{
+ return real_input_dialog_help (header, text, help, def_text);
+}
+/* }}} */
+
+#endif
+
+/* {{{ Functions shared between background and foreground */
+
+void
+message_1s1d (int flags, char *title, char *str, int d)
+{
+ char *p;
+
+ p = xmalloc (strlen (str) + 30, "1s1d");
+ sprintf (p, str, d);
+ message_1s (flags, title, p);
+ free (p);
+}
+
+/* }}} */
--- /dev/null
+#ifndef __BACKGROUND_H
+#define __BACKGROUND_H
+
+/* Background code requires socketpair to be available */
+/* Do not add the background code if it is not supported */
+#ifdef USE_NETCODE
+# define WITH_BACKGROUND
+#endif
+
+/* Used for parent/child communication. These are numbers that
+ * could not possible be a routine address.
+ */
+enum {
+ MSG_CHILD_EXITING
+};
+
+/* First argument passed to real functions */
+enum OperationMode {
+ Foreground,
+ Background
+};
+
+enum ReturnType {
+ Return_String,
+ Return_Integer
+};
+
+enum TaskState {
+ Task_Running,
+ Task_Stopped
+};
+
+typedef struct TaskList {
+ int fd;
+ pid_t pid;
+ int state;
+ char *info;
+ struct TaskList *next;
+} TaskList;
+
+extern struct TaskList *task_list;
+
+extern int background_wait;
+
+int do_background (char *info);
+int background_attention (int fd, void *xpid);
+void tell_parent (int msg);
+int parent_call (void *routine, int argc, ...);
+int call_1s (int (*routine)(enum OperationMode, char *), char *str);
+
+void unregister_task_running (pid_t, int fd);
+void register_task_running (pid_t, int, char *);
+
+/* stubs */
+void message_1s (int flags, char *title, char *str1);
+void message_2s (int flags, char *title, char *str1, char *str2);
+void message_3s (int flags, char *title, char *str1, char *str2, const char *str3);
+void message_1s1d (int flags, char *title, char *str, int d);
+
+#endif
--- /dev/null
+/* Some misc dialog boxes for the program.
+
+ Copyright (C) 1994, 1995 the Free Software Foundation
+
+ Authors: 1994, 1995 Miguel de Icaza
+ 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <malloc.h>
+#include <signal.h>
+#include <ctype.h>
+#include "global.h"
+#include "mad.h" /* The great mad */
+#include "util.h" /* Required by panel.h */
+#include "win.h" /* Our window tools */
+#include "color.h" /* Color definitions */
+#include "dlg.h" /* The nice dialog manager */
+#include "widget.h" /* The widgets for the nice dialog manager */
+#include "dialog.h" /* For do_refresh() */
+#include "wtools.h"
+#include "setup.h" /* For profile_name */
+#include "profile.h" /* Load/save user formats */
+#include "key.h" /* XCTRL and ALT macros */
+#include "command.h" /* For cmdline */
+#include "dir.h"
+#include "panel.h"
+#include "boxes.h"
+#include "main.h" /* For the confirm_* variables */
+#include "tree.h"
+#include "layout.h" /* for get_nth_panel_name proto */
+#include "background.h" /* for background definitions */
+#include "x.h"
+
+static int DISPLAY_X = 45, DISPLAY_Y = 14;
+
+static Dlg_head *dd;
+static WRadio *my_radio;
+static WInput *user;
+static WInput *status;
+static WCheck *check_status;
+static int current_mode;
+extern int ftpfs_always_use_proxy;
+
+static char **displays_status;
+static char* display_title = N_(" Listing mode ");
+
+/* Controls whether the array strings have been translated */
+static int i18n_displays_flag;
+static char *displays [LIST_TYPES] = {
+ N_("&Full file list"),
+ N_("&Brief file list"),
+ N_("&Long file list"),
+ N_("&User defined:"),
+ N_("&Icon view"),
+};
+
+static int user_hotkey = 'u';
+
+static int display_callback (struct Dlg_head *h, int id, int Msg)
+{
+#ifndef HAVE_X
+ char *text;
+ WInput *input;
+
+ switch (Msg){
+ case DLG_DRAW:
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 1, 2, h->lines - 2, h->cols - 4);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 1, (h->cols - strlen(display_title))/2);
+ addstr (display_title);
+ attrset (COLOR_NORMAL);
+ break;
+
+ case DLG_UNFOCUS:
+ if((WRadio *) h->current->widget == my_radio){
+ assign_text (status, displays_status [my_radio->sel]);
+ input_set_point (status, 0);
+ }
+ break;
+
+ case DLG_KEY:
+ if (id == '\n'){
+ if((WRadio *) h->current->widget == my_radio){
+ assign_text (status, displays_status [my_radio->sel]);
+ dlg_stop (h);
+ break;
+ }
+
+ if ((WInput *) h->current->widget == user){
+ h->ret_value = B_USER + 6;
+ dlg_stop (h);
+ break;
+ }
+
+ if ((WInput *) h->current->widget == status){
+ h->ret_value = B_USER + 7;
+ dlg_stop (h);
+ break;
+ }
+ }
+
+ if (tolower(id) == user_hotkey && h->current->widget != (Widget *) user
+ && h->current->widget != (Widget *) status){
+ my_radio->sel = 3;
+ dlg_select_widget (h, my_radio); /* force redraw */
+ dlg_select_widget (h, user);
+ return MSG_HANDLED;
+ }
+ }
+#endif
+ return MSG_NOT_HANDLED;
+}
+
+static void display_init (int radio_sel, char *init_text,
+ int _check_status, char ** _status)
+{
+ char* user_mini_status = _("user &Mini status");
+ char* ok_button = _("&Ok");
+ char* cancel_button = _("&Cancel");
+
+ static int button_start = 30;
+
+ displays_status = _status;
+
+ if (!i18n_displays_flag){
+ int i, l, maxlen = 0;
+ char* cp;
+
+ display_title = _(display_title);
+ for (i = 0; i < LIST_TYPES; i++)
+ {
+ displays [i] = _(displays [i]);
+ if ((l = strlen(displays [i])) > maxlen)
+ maxlen = l;
+ }
+
+ i = strlen (ok_button) + 5;
+ l = strlen (cancel_button) + 3;
+ l = max(i, l);
+
+ i = maxlen + l + 16;
+ if (i > DISPLAY_X)
+ DISPLAY_X = i;
+
+ i = strlen (user_mini_status) + 13;
+ if (i > DISPLAY_X)
+ DISPLAY_X = i;
+
+ i = strlen (display_title) + 8;
+ if (i > DISPLAY_X)
+ DISPLAY_X = i;
+
+ button_start = DISPLAY_X - l - 5;
+
+ /* get hotkey of user-defined format string */
+ cp = strchr(displays[LIST_TYPES-1],'&');
+ if (cp != NULL && *++cp != '\0')
+ user_hotkey = tolower(*cp);
+
+ i18n_displays_flag = 1;
+ }
+ dd = create_dlg (0, 0, DISPLAY_Y, DISPLAY_X, dialog_colors,
+ display_callback, "[Left and Right Menus]", "display",
+ DLG_CENTER | DLG_GRID);
+
+ x_set_dialog_title (dd, _("Listing mode"));
+ add_widgetl (dd,
+ button_new (4, button_start, B_CANCEL,
+ NORMAL_BUTTON, cancel_button, 0, 0, "cancel-button"),
+ XV_WLAY_RIGHTOF);
+
+ add_widgetl (dd,
+ button_new (3, button_start, B_ENTER,
+ DEFPUSH_BUTTON, ok_button, 0, 0, "ok-button"),
+ XV_WLAY_CENTERROW);
+
+ status = input_new (10, 9, INPUT_COLOR, DISPLAY_X-14, _status [radio_sel], "mini-input");
+ add_widgetl (dd, status, XV_WLAY_RIGHTDOWN);
+ input_set_point (status, 0);
+
+ check_status = check_new (9, 5, _check_status, user_mini_status, "mini-status");
+ add_widgetl (dd, check_status, XV_WLAY_NEXTROW);
+
+ user = input_new (7, 9, INPUT_COLOR, DISPLAY_X-14, init_text, "user-fmt-input");
+ add_widgetl (dd, user, XV_WLAY_RIGHTDOWN);
+ input_set_point (user, 0);
+
+#ifdef PORT_HAS_ICON_VIEW
+ my_radio = radio_new (3, 5, LIST_TYPES, displays, 1, "radio");
+#else
+ my_radio = radio_new (3, 5, LIST_TYPES-1, displays, 1, "radio");
+#endif
+ my_radio->sel = my_radio->pos = current_mode;
+ add_widgetl (dd, my_radio, XV_WLAY_BELOWCLOSE);
+}
+
+int display_box (WPanel *panel, char **userp, char **minip, int *use_msformat,
+ int num)
+{
+ int result, i;
+ char *section = NULL;
+ char *p;
+
+ if (!panel) {
+ p = get_nth_panel_name (num);
+ panel = (WPanel *) xmalloc (sizeof (WPanel), "temporary panel");
+ panel->list_type = list_full;
+ panel->user_format = strdup (DEFAULT_USER_FORMAT);
+ panel->user_mini_status = 0;
+ for (i = 0; i < LIST_TYPES; i++)
+ panel->user_status_format[i] = strdup (DEFAULT_USER_FORMAT);
+ section = copy_strings ("Temporal:", p, 0);
+ if (!profile_has_section (section, profile_name)) {
+ free (section);
+ section = strdup (p);
+ }
+ panel_load_setup (panel, section);
+ free (section);
+ }
+
+ current_mode = panel->list_type;
+ display_init (current_mode, panel->user_format,
+ panel->user_mini_status, panel->user_status_format);
+
+ run_dlg (dd);
+
+ result = -1;
+
+ if (section) {
+ free (panel->user_format);
+ for (i = 0; i < LIST_TYPES; i++)
+ free (panel->user_status_format [i]);
+ free (panel);
+ }
+
+ if (dd->ret_value != B_CANCEL){
+ result = my_radio->sel;
+ *userp = strdup (user->buffer);
+ *minip = strdup (status->buffer);
+ *use_msformat = check_status->state & C_BOOL;
+ }
+ destroy_dlg (dd);
+
+ return result;
+}
+
+int SORT_X = 40, SORT_Y = 14;
+
+char *sort_orders_names [SORT_TYPES];
+
+sortfn *sort_box (sortfn *sort_fn, int *reverse, int *case_sensitive)
+{
+ int i, r, l;
+ sortfn *result;
+ WCheck *c, *case_sense;
+
+ char* ok_button = _("&Ok");
+ char* cancel_button = _("&Cancel");
+ char* reverse_label = _("&Reverse");
+ char* case_label = _("case sensi&tive");
+ char* sort_title = _("Sort order");
+
+ static int i18n_sort_flag = 0, check_pos = 0, button_pos = 0;
+
+ if (!i18n_sort_flag)
+ {
+ int maxlen = 0;
+ for (i = SORT_TYPES-1; i >= 0; i--)
+ {
+ sort_orders_names [i] = _(sort_orders [i].sort_name);
+ r = strlen (sort_orders_names [i]);
+ if (r > maxlen)
+ maxlen = r;
+ }
+
+ check_pos = maxlen + 9;
+
+ r = strlen (reverse_label) + 4;
+ i = strlen (case_label) + 4;
+ if (i > r)
+ r = i;
+
+ l = strlen (ok_button) + 6;
+ i = strlen (cancel_button) + 4;
+ if (i > l)
+ l = i;
+
+ i = check_pos + max(r,l) + 2;
+
+ if (i > SORT_X)
+ SORT_X = i;
+
+ i = strlen (sort_title) + 6;
+ if (i > SORT_X)
+ SORT_X = i;
+
+ button_pos = SORT_X - l - 2;
+
+ i18n_sort_flag = 1;
+ }
+
+ result = 0;
+
+ for (i = 0; i < SORT_TYPES; i++)
+ if ((sortfn *) (sort_orders [i].sort_fn) == sort_fn){
+ current_mode = i;
+ break;
+ }
+
+ dd = create_dlg (0, 0, SORT_Y, SORT_X, dialog_colors, common_dialog_callback,
+ "[Left and Right Menus]", "sort", DLG_CENTER | DLG_GRID);
+
+ x_set_dialog_title (dd, sort_title);
+
+ add_widgetl (dd,
+ button_new (10, button_pos, B_CANCEL, NORMAL_BUTTON, cancel_button,
+ 0, 0, "cancel-button"), XV_WLAY_CENTERROW);
+
+ add_widgetl (dd,
+ button_new (9, button_pos, B_ENTER, DEFPUSH_BUTTON, ok_button,
+ 0, 0, "ok-button"), XV_WLAY_RIGHTDOWN);
+
+ case_sense = check_new (4, check_pos, *case_sensitive, case_label, "case-check");
+ add_widgetl (dd, case_sense, XV_WLAY_RIGHTDOWN);
+ c = check_new (3, check_pos, *reverse, reverse_label, "reverse-check");
+ add_widgetl (dd, c, XV_WLAY_RIGHTDOWN);
+
+ my_radio = radio_new (3, 3, SORT_TYPES, sort_orders_names, 1, "radio-1");
+ my_radio->sel = my_radio->pos = current_mode;
+
+ add_widget (dd, my_radio);
+ run_dlg (dd);
+
+ r = dd->ret_value;
+ if (r != B_CANCEL){
+ result = (sortfn *) sort_orders [my_radio->sel].sort_fn;
+ *reverse = c->state & C_BOOL;
+ *case_sensitive = case_sense->state & C_BOOL;
+ } else
+ result = sort_fn;
+ destroy_dlg (dd);
+
+ return result;
+}
+
+#define CONFY 10
+#define CONFX 46
+
+static int my_delete;
+static int my_overwrite;
+static int my_execute;
+static int my_exit;
+
+static QuickWidget conf_widgets [] = {
+{ quick_button, 4, 6, 4, CONFY, N_("&Cancel"),
+ 0, B_CANCEL, 0, 0, XV_WLAY_RIGHTOF, "c" },
+{ quick_button, 4, 6, 3, CONFY, N_("&Ok"),
+ 0, B_ENTER, 0, 0, XV_WLAY_CENTERROW, "o" },
+
+{ quick_checkbox, 1, 13, 6, CONFY, N_(" confirm &Exit "),
+ 9, 0, &my_exit, 0, XV_WLAY_BELOWCLOSE, "e" },
+{ quick_checkbox, 1, 13, 5, CONFY, N_(" confirm e&Xecute "),
+ 10, 0, &my_execute, 0, XV_WLAY_BELOWCLOSE, "x" },
+{ quick_checkbox, 1, 13, 4, CONFY, N_(" confirm o&Verwrite "),
+ 10, 0, &my_overwrite, 0, XV_WLAY_BELOWCLOSE, "ov" },
+{ quick_checkbox, 1, 13, 3, CONFY, N_(" confirm &Delete "),
+ 9, 0, &my_delete, 0, XV_WLAY_BELOWCLOSE, "de" },
+{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, XV_WLAY_DONTCARE }
+};
+
+static QuickDialog confirmation =
+{ CONFX, CONFY, -1, -1, N_(" Confirmation "), "[Confirmation]", "quick_confirm",
+ conf_widgets, 0 };
+
+void confirm_box ()
+{
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+
+ if (!i18n_flag)
+ {
+ register int i = sizeof(conf_widgets)/sizeof(QuickWidget) - 1;
+ int l1, maxlen = 0;
+ while (i--)
+ {
+ conf_widgets [i].text = _(conf_widgets [i].text);
+ l1 = strlen (conf_widgets [i].text) + 3;
+ if (l1 > maxlen)
+ maxlen = l1;
+ }
+
+ /*
+ * If buttons start on 4/6, checkboxes (with some add'l space)
+ * must take not more than it.
+ */
+ confirmation.xlen = (maxlen + 5) * 6 / 4;
+
+ /*
+ * And this for the case when buttons with some space to the right
+ * do not fit within 2/6
+ */
+ l1 = strlen (conf_widgets [0].text) + 3;
+ i = strlen (conf_widgets [1].text) + 5;
+ if (i > l1)
+ l1 = i;
+
+ i = (l1 + 3) * 6 / 2;
+ if (i > confirmation.xlen)
+ confirmation.xlen = i;
+
+ confirmation.title = _(confirmation.title);
+
+ i18n_flag = confirmation.i18n = 1;
+ }
+
+#endif /* ENABLE_NLS */
+
+ my_delete = confirm_delete;
+ my_overwrite = confirm_overwrite;
+ my_execute = confirm_execute;
+ my_exit = confirm_exit;
+
+ if (quick_dialog (&confirmation) != B_CANCEL){
+ confirm_delete = my_delete;
+ confirm_overwrite = my_overwrite;
+ confirm_execute = my_execute;
+ confirm_exit = my_exit;
+ }
+}
+
+#define DISPY 11
+#define DISPX 46
+
+static int new_mode;
+static int new_meta;
+
+char *display_bits_str [] =
+{ N_("Full 8 bits output"), N_("ISO 8859-1"), N_("7 bits") };
+
+static QuickWidget display_widgets [] = {
+{ quick_button, 4, 6, 4, DISPY, N_("&Cancel"),
+ 0, B_CANCEL, 0, 0, XV_WLAY_CENTERROW, "c" },
+{ quick_button, 4, 6, 3, DISPY, N_("&Ok"),
+ 0, B_ENTER, 0, 0, XV_WLAY_CENTERROW, "o" },
+{ quick_checkbox, 4, DISPX, 7, DISPY, N_("F&ull 8 bits input"),
+ 0, 0, &new_meta, 0, XV_WLAY_BELOWCLOSE, "u" },
+{ quick_radio, 4, DISPX, 3, DISPY, "", 3, 0,
+ &new_mode, display_bits_str, XV_WLAY_BELOWCLOSE, "r" },
+{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, XV_WLAY_DONTCARE }
+};
+
+static QuickDialog display_bits =
+{ DISPX, DISPY, -1, -1, N_(" Display bits "), "[Display bits]",
+ "dbits", display_widgets, 0 };
+
+void display_bits_box ()
+{
+ int current_mode;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+ if (!i18n_flag)
+ {
+ register int i;
+ int l1, maxlen = 0;
+ for (i = 0; i < 3; i++)
+ {
+ display_widgets [i].text = _(display_widgets[i].text);
+ display_bits_str [i] = _(display_bits_str [i]);
+ l1 = strlen (display_bits_str [i]);
+ if (l1 > maxlen)
+ maxlen = l1;
+ }
+ l1 = strlen (display_widgets [2].text);
+ if (l1 > maxlen)
+ maxlen = l1;
+
+
+ display_bits.xlen = (maxlen + 5) * 6 / 4;
+
+ /* See above confirm_box */
+ l1 = strlen (display_widgets [0].text) + 3;
+ i = strlen (display_widgets [1].text) + 5;
+ if (i > l1)
+ l1 = i;
+
+ i = (l1 + 3) * 6 / 2;
+ if (i > display_bits.xlen)
+ display_bits.xlen = i;
+
+ display_bits.title = _(display_bits.title);
+ i18n_flag = display_bits.i18n = 1;
+ }
+
+#endif /* ENABLE_NLS */
+
+ if (full_eight_bits)
+ current_mode = 0;
+ else if (eight_bit_clean)
+ current_mode = 1;
+ else
+ current_mode = 2;
+
+ display_widgets [3].value = current_mode;
+ new_meta = !use_8th_bit_as_meta;
+ if (quick_dialog (&display_bits) != B_ENTER)
+ return;
+
+ eight_bit_clean = new_mode < 2;
+ full_eight_bits = new_mode == 0;
+#ifndef HAVE_SLANG
+ meta (stdscr, eight_bit_clean);
+#else
+ SLsmg_Display_Eight_Bit = full_eight_bits ? 128 : 160;
+#endif
+ use_8th_bit_as_meta = !new_meta;
+}
+
+#define TREE_Y 20
+#define TREE_X 60
+
+static int tree_colors [4];
+
+static int tree_callback (struct Dlg_head *h, int id, int msg)
+{
+ switch (msg){
+
+ case DLG_POST_KEY:
+ /* The enter key will be processed by the tree widget */
+ if (id == '\n' || ((WTree *)(h->current->widget))->done){
+ h->ret_value = B_ENTER;
+ dlg_stop (h);
+ }
+ return MSG_HANDLED;
+
+ case DLG_DRAW:
+ common_dialog_repaint (h);
+ break;
+ }
+ return MSG_NOT_HANDLED;
+}
+
+char *tree (char *current_dir)
+{
+ WTree *mytree;
+ Dlg_head *dlg;
+ char *val;
+ WButtonBar *bar;
+
+ tree_colors [3] = dialog_colors [0];
+ tree_colors [1] = dialog_colors [1];
+
+ /* Create the components */
+ dlg = create_dlg (0, 0, TREE_Y, TREE_X, tree_colors,
+ tree_callback, "[Directory Tree]", "tree", DLG_CENTER);
+ mytree = tree_new (0, 2, 2, TREE_Y - 6, TREE_X - 5);
+ add_widget (dlg, mytree);
+ bar = buttonbar_new(1);
+ add_widget (dlg, bar);
+ bar->widget.x = 0;
+ bar->widget.y = LINES - 1;
+
+ run_dlg (dlg);
+ if (dlg->ret_value == B_ENTER)
+ val = strdup (mytree->selected_ptr->name);
+ else
+ val = 0;
+
+ destroy_dlg (dlg);
+ return val;
+}
+#ifndef USE_VFS
+#ifdef USE_NETCODE
+#undef USE_NETCODE
+#endif
+#endif
+
+#ifdef USE_VFS
+
+#if defined(USE_NETCODE)
+#define VFSY 15
+#else
+#define VFSY 11
+#endif
+
+#define VFSX 56
+
+extern int vfs_timeout;
+extern int tar_gzipped_memlimit;
+extern int ftpfs_always_use_proxy;
+
+#if defined(USE_NETCODE)
+extern char *ftpfs_anonymous_passwd;
+extern char *ftpfs_proxy_host;
+extern ftpfs_directory_timeout;
+extern int use_netrc;
+#endif
+
+int vfs_use_limit = 1;
+static char *ret_timeout;
+static char *ret_limit;
+
+#if defined(USE_NETCODE)
+static char *ret_passwd;
+static char *ret_directory_timeout;
+static char *ret_ftp_proxy;
+static int ret_use_netrc;
+#endif
+
+#if 0
+/* Not used currently */
+{ quick_checkbox, 4, VFSX, 10, VFSY, "Use ~/.netrc",
+ 'U', 0, 0, &ret_use_netrc, 0, XV_WLAY_BELOWCLOSE, "" },
+#endif
+
+char *confvfs_str [] =
+{ N_("Always to memory"), N_("If size less than:") };
+
+static QuickWidget confvfs_widgets [] = {
+{ quick_button, 30, VFSX, VFSY - 3, VFSY, N_("&Cancel"),
+ 0, B_CANCEL, 0, 0, XV_WLAY_RIGHTOF, "button-cancel" },
+{ quick_button, 12, VFSX, VFSY - 3, VFSY, N_("&Ok"),
+ 0, B_ENTER, 0, 0, XV_WLAY_CENTERROW, "button-ok" },
+#if defined(USE_NETCODE)
+{ quick_input, 30, VFSX, 10, VFSY, "", 22, 0, 0, &ret_ftp_proxy,
+ XV_WLAY_RIGHTDOWN, "input-ftp-proxy" },
+{ quick_checkbox, 4, VFSX, 10, VFSY, N_("&Always use ftp proxy"), 0, 0,
+ &ftpfs_always_use_proxy, 0, XV_WLAY_RIGHTDOWN, "check-ftp-proxy" },
+{ quick_label, 46, VFSX, 9, VFSY, N_("sec"),
+ 0, 0, 0, 0, XV_WLAY_RIGHTOF, "label-sec" },
+{ quick_input, 35, VFSX, 9, VFSY, "", 10, 0, 0, &ret_directory_timeout,
+ XV_WLAY_RIGHTDOWN, "input-timeout" },
+{ quick_label, 4, VFSX, 9, VFSY, N_("ftpfs directory cache timeout:"),
+ 0, 0, 0, 0, XV_WLAY_NEXTROW, "label-cache"},
+{ quick_input, 28, VFSX, 8, VFSY, "", 24, 0, 0, &ret_passwd,
+ XV_WLAY_RIGHTDOWN, "input-passwd" },
+{ quick_label, 4, VFSX, 8, VFSY, N_("ftp anonymous password:"),
+ 0, 0, 0, 0, XV_WLAY_NEXTROW, "label-pass"},
+#endif
+{ quick_input, 26, VFSX, 6, VFSY, "", 10, 0, 0, &ret_limit,
+ XV_WLAY_RIGHTDOWN, "input-limit" },
+{ quick_radio, 4, VFSX, 5, VFSY, "", 2, 0,
+ &vfs_use_limit, confvfs_str, XV_WLAY_BELOWCLOSE, "radio" },
+{ quick_label, 4, VFSX, 4, VFSY, N_("Gzipped tar archive extract:"),
+ 0, 0, 0, 0, XV_WLAY_NEXTROW, "label-tar" },
+{ quick_label, 46, VFSX, 3, VFSY, "sec",
+ 0, 0, 0, 0, XV_WLAY_RIGHTOF, "label-sec2" },
+{ quick_input, 35, VFSX, 3, VFSY, "", 10, 0, 0, &ret_timeout,
+ XV_WLAY_RIGHTOF, "input-timo-vfs" },
+{ quick_label, 4, VFSX, 3, VFSY, N_("Timeout for freeing VFSs:"),
+ 0, 0, 0, 0, XV_WLAY_BELOWCLOSE, "label-vfs" },
+{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, XV_WLAY_DONTCARE, 0 }
+};
+
+static QuickDialog confvfs_dlg =
+{ VFSX, VFSY, -1, -1, N_(" Virtual File System Setting "), "[Virtual FS]", "quick_vfs", confvfs_widgets, 0 };
+
+#if defined(USE_NETCODE)
+#define VFS_WIDGETBASE 7
+#else
+#define VFS_WIDGETBASE 0
+#endif
+
+void configure_vfs ()
+{
+ char buffer1 [15], buffer2 [15];
+#if defined(USE_NETCODE)
+ char buffer3[15];
+#endif
+
+ if (tar_gzipped_memlimit > -1) {
+ if (tar_gzipped_memlimit == 0)
+ strcpy (buffer1, "0 B");
+ else if ((tar_gzipped_memlimit % (1024*1024)) == 0) /* I.e. in M */
+ sprintf (buffer1, "%i MB", (int)(((unsigned)tar_gzipped_memlimit) >> 20));
+ else if ((tar_gzipped_memlimit % 1024) == 0) /* I.e. in K */
+ sprintf (buffer1, "%i KB", (int)(((unsigned)tar_gzipped_memlimit) >> 10));
+ else if ((tar_gzipped_memlimit % 1000) == 0)
+ sprintf (buffer1, "%i kB", (int)(tar_gzipped_memlimit / 1000));
+ else
+ sprintf (buffer1, "%i B", (int)tar_gzipped_memlimit);
+ confvfs_widgets [2 + VFS_WIDGETBASE].text = buffer1;
+ } else
+ confvfs_widgets [2 + VFS_WIDGETBASE].text = "5 MB";
+ sprintf (buffer2, "%i", vfs_timeout);
+ confvfs_widgets [6 + VFS_WIDGETBASE].text = buffer2;
+ confvfs_widgets [3 + VFS_WIDGETBASE].value = vfs_use_limit;
+#if defined(USE_NETCODE)
+ ret_use_netrc = use_netrc;
+ sprintf(buffer3, "%i", ftpfs_directory_timeout);
+ confvfs_widgets[5].text = buffer3;
+ confvfs_widgets[7].text = ftpfs_anonymous_passwd;
+ confvfs_widgets[2].text = ftpfs_proxy_host ? ftpfs_proxy_host : "";
+#endif
+
+ if (quick_dialog (&confvfs_dlg) != B_CANCEL) {
+ char *p;
+
+ vfs_timeout = atoi (ret_timeout);
+ free (ret_timeout);
+ if (vfs_timeout < 0 || vfs_timeout > 10000)
+ vfs_timeout = 10;
+ if (!vfs_use_limit)
+ tar_gzipped_memlimit = -1;
+ else {
+ tar_gzipped_memlimit = atoi (ret_limit);
+ if (tar_gzipped_memlimit < 0)
+ tar_gzipped_memlimit = -1;
+ else {
+ for (p = ret_limit; *p == ' ' || (*p >= '0' && *p <= '9'); p++);
+ switch (*p) {
+ case 'm':
+ case 'M': tar_gzipped_memlimit <<= 20; break;
+ case 'K': tar_gzipped_memlimit <<= 10; break;
+ case 'k': tar_gzipped_memlimit *= 1000; break;
+ }
+ }
+ }
+ free (ret_limit);
+#if defined(USE_NETCODE)
+ free(ftpfs_anonymous_passwd);
+ ftpfs_anonymous_passwd = ret_passwd;
+ if (ftpfs_proxy_host)
+ free(ftpfs_proxy_host);
+ ftpfs_proxy_host = ret_ftp_proxy;
+ ftpfs_directory_timeout = atoi(ret_directory_timeout);
+ use_netrc = ret_use_netrc;
+ free(ret_directory_timeout);
+#endif
+ }
+}
+
+#endif
+
+char *cd_dialog (void)
+{
+ QuickDialog Quick_input;
+ QuickWidget quick_widgets [] = {
+#ifdef HAVE_TK
+#define INPUT_INDEX 2
+ { quick_button, 0, 1, 0, 1, N_("&Cancel"), 0, B_CANCEL, 0, 0, XV_WLAY_DONTCARE, "cancel" },
+ { quick_button, 0, 1, 0, 1, N_("&Ok"), 0, B_ENTER, 0, 0, XV_WLAY_DONTCARE, "ok" },
+#else
+#define INPUT_INDEX 0
+#endif
+ { quick_input, 6, 57, 5, 0, "", 50, 0, 0, 0, XV_WLAY_RIGHTOF, "input" },
+ { quick_label, 3, 57, 2, 0, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "label" },
+ { 0 } };
+
+ char *my_str;
+ int len;
+
+ Quick_input.xlen = 57;
+ Quick_input.title = _("Quick cd");
+ Quick_input.help = "[Quick cd]";
+ Quick_input.class = "quick_input";
+ quick_widgets [INPUT_INDEX].text = "";
+ quick_widgets [INPUT_INDEX].value = 2; /* want cd like completion */
+ quick_widgets [INPUT_INDEX+1].text = _("cd");
+ quick_widgets [INPUT_INDEX+1].y_divisions =
+ quick_widgets [INPUT_INDEX].y_divisions = Quick_input.ylen = 5;
+
+ len = strlen (quick_widgets [INPUT_INDEX+1].text);
+
+ quick_widgets [INPUT_INDEX+1].relative_x = 3;
+ quick_widgets [INPUT_INDEX].relative_x =
+ quick_widgets [INPUT_INDEX+1].relative_x + len + 1;
+
+ Quick_input.xlen = len + quick_widgets [INPUT_INDEX].hotkey_pos + 7;
+ quick_widgets [INPUT_INDEX].x_divisions =
+ quick_widgets [INPUT_INDEX+1].x_divisions = Quick_input.xlen;
+
+ Quick_input.i18n = 1;
+ Quick_input.xpos = 2;
+ Quick_input.ypos = LINES - 2 - Quick_input.ylen;
+ quick_widgets [INPUT_INDEX].relative_y = 2;
+ quick_widgets [INPUT_INDEX].str_result = &my_str;
+
+ Quick_input.widgets = quick_widgets;
+ if (quick_dialog (&Quick_input) != B_CANCEL){
+ return *(quick_widgets [INPUT_INDEX].str_result);
+ } else
+ return 0;
+}
+
+void symlink_dialog (char *existing, char *new, char **ret_existing,
+ char **ret_new)
+{
+ QuickDialog Quick_input;
+ QuickWidget quick_widgets [] = {
+#undef INPUT_INDEX
+#if defined(HAVE_TK) || defined(HAVE_GNOME)
+#define INPUT_INDEX 2
+ { quick_button, 0, 1, 0, 1, _("&Cancel"), 0, B_CANCEL, 0, 0,
+ XV_WLAY_DONTCARE, "cancel" },
+ { quick_button, 0, 1, 0, 1, _("&Ok"), 0, B_ENTER, 0, 0,
+ XV_WLAY_DONTCARE, "ok" },
+#else
+#define INPUT_INDEX 0
+#endif
+ { quick_input, 6, 80, 5, 8, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-1" },
+ { quick_label, 6, 80, 4, 8, "", 0, 0, 0, 0, XV_WLAY_BELOWOF, "label-1" },
+ { quick_input, 6, 80, 3, 8, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-2" },
+ { quick_label, 6, 80, 2, 8, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-2" },
+ { 0 } };
+
+ Quick_input.xlen = 64;
+ Quick_input.ylen = 8;
+ Quick_input.title = "Symbolic link";
+ Quick_input.help = "[File Menu]";
+ Quick_input.class = "quick_symlink";
+ Quick_input.i18n = 0;
+ quick_widgets [INPUT_INDEX].text = new;
+ quick_widgets [INPUT_INDEX+1].text = _("Symbolic link filename:");
+ quick_widgets [INPUT_INDEX+2].text = existing;
+ quick_widgets [INPUT_INDEX+3].text = _("Existing filename (filename symlink will point to):");
+ Quick_input.xpos = -1;
+ quick_widgets [INPUT_INDEX].str_result = ret_new;
+ quick_widgets [INPUT_INDEX+2].str_result = ret_existing;
+
+ Quick_input.widgets = quick_widgets;
+ if (quick_dialog (&Quick_input) == B_CANCEL){
+ *ret_new = NULL;
+ *ret_existing = NULL;
+ }
+}
+
+#ifdef WITH_BACKGROUND
+#define B_STOP B_USER+1
+#define B_RESUME B_USER+2
+#define B_KILL B_USER+3
+
+static int JOBS_X = 60;
+#define JOBS_Y 15
+static WListbox *bg_list;
+static Dlg_head *jobs_dlg;
+
+static void
+jobs_fill_listbox (void)
+{
+ static char *state_str [2];
+ TaskList *tl = task_list;
+
+ if (!state_str [0]){
+ state_str [0] = _("Running ");
+ state_str [1] = _("Stopped");
+ }
+
+ while (tl){
+ char *s;
+
+ s = copy_strings (state_str [tl->state], " ", tl->info, NULL);
+ listbox_add_item (bg_list, LISTBOX_APPEND_AT_END, 0, s, (void *) tl);
+ free (s);
+ tl = tl->next;
+ }
+}
+
+static int
+task_cb (int action, void *ignored)
+{
+ TaskList *tl;
+ int sig;
+
+ if (!bg_list->list)
+ return 0;
+
+ /* Get this instance information */
+ tl = (TaskList *) bg_list->current->data;
+
+ if (action == B_STOP){
+ sig = SIGSTOP;
+ tl->state = Task_Stopped;
+ } else if (action == B_RESUME){
+ sig = SIGCONT;
+ tl->state = Task_Running;
+ } else if (action == B_KILL){
+ sig = SIGKILL;
+ }
+
+ if (sig == SIGINT)
+ unregister_task_running (tl->pid, tl->fd);
+
+ kill (tl->pid, sig);
+ listbox_remove_list (bg_list);
+ jobs_fill_listbox ();
+
+ /* This can be optimized to just redraw this widget :-) */
+ dlg_redraw (jobs_dlg);
+
+ return 0;
+}
+
+static struct
+{
+ char* name;
+ int xpos;
+ int value;
+ int (*callback)();
+ char* tkname;
+}
+job_buttons [] =
+{
+ {N_("&Stop"), 3, B_STOP, task_cb, "button-stop"},
+ {N_("&Resume"), 12, B_RESUME, task_cb, "button-cont"},
+ {N_("&Kill"), 23, B_KILL, task_cb, "button-kill"},
+ {N_("&Ok"), 35, B_CANCEL, NULL, "button-ok"},
+};
+
+void
+jobs_cmd (void)
+{
+ register int i;
+ int n_buttons = sizeof (job_buttons) / sizeof (job_buttons[0]);
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+ if (!i18n_flag)
+ {
+ int startx = job_buttons [0].xpos;
+ int len;
+
+ for (i = 0; i < n_buttons; i++)
+ {
+ job_buttons [i].name = _(job_buttons [i].name);
+
+ len = strlen (job_buttons [i].name) + 4;
+ JOBS_X = max (JOBS_X, startx + len + 3);
+
+ job_buttons [i].xpos = startx;
+ startx += len;
+ }
+
+ /* Last button - Ok a.k.a. Cancel :) */
+ job_buttons [n_buttons - 1].xpos =
+ JOBS_X - strlen (job_buttons [n_buttons - 1].name) - 7;
+
+ i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ jobs_dlg = create_dlg (0, 0, JOBS_Y, JOBS_X, dialog_colors,
+ common_dialog_callback, "[Background jobs]", "jobs",
+ DLG_CENTER | DLG_GRID);
+ x_set_dialog_title (jobs_dlg, _("Background Jobs"));
+
+ bg_list = listbox_new (2, 3, JOBS_X-7, JOBS_Y-9, listbox_nothing, 0, "listbox");
+ add_widget (jobs_dlg, bg_list);
+
+ i = n_buttons;
+ while (i--)
+ {
+ add_widget (jobs_dlg, button_new (JOBS_Y-4,
+ job_buttons [i].xpos, job_buttons [i].value,
+ NORMAL_BUTTON, job_buttons [i].name,
+ job_buttons [i].callback, 0,
+ job_buttons [i].tkname));
+ }
+
+ /* Insert all of task information in the list */
+ jobs_fill_listbox ();
+ run_dlg (jobs_dlg);
+
+ destroy_dlg (jobs_dlg);
+}
+#endif
--- /dev/null
+#ifndef __BOXES_H
+#define __BOXES_H
+
+extern char *user_format [];
+
+int display_box (WPanel *p, char **user, char **mini, int *use_msformat, int num);
+sortfn *sort_box (sortfn *sort_fn, int *reverse, int *case_sensitive);
+void confirm_box (void);
+void display_bits_box ();
+#ifdef USE_VFS
+void configure_vfs ();
+#endif
+void jobs_cmd ();
+char *cd_dialog (void);
+void symlink_dialog (char *existing, char *new, char **ret_existing, char **ret_new);
+#endif
--- /dev/null
+Mon Oct 5 21:33:14 1998 Norbert Warmuth <nwarmuth@privat.circular.de>
+
+ * screen.c (parse_display_format): Don't dereference NULL pointer
+ when format string is an empty string.
+
+Fri Oct 2 19:22:24 1998 Norbert Warmuth <nwarmuth@privat.circular.de>
+
+ * setup.c (panel_load_setup): equality operator used for assignment
+
+ * setup.c: save and restore new global variable/option
+ ftp_use_unix_list_options
+
+Mon Sep 28 21:55:13 1998 Norbert Warmuth <nwarmuth@privat.circular.de>
+
+ * find.c: Changed hotkey of the continue-button (both Chdir and
+ Continue used `C').
+
+Tue Sep 15 21:52:00 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * mc.hlp, doc/mc.1.in, doc/mc.sgml: updated my EMail address
+
+1998-09-14 Norbert Warmuth <k3190@fh-sw.de>
+
+ * file.c (move_dir_dir): Fixed severe bug reported by Andrew Pechenov
+ <zx80@demo.ru> (losing files when moving directories cross filesystem
+ boundaries): make sure erase_list is emptied always not only when we
+ deleted files.
+
+1998-08-26 Ludovic Drolez <ldrolez@usa.net>
+
+ * Made the program relocatable by using the MCHOME environment
+ variable.
+
+Mon May 25 23:32:35 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * editdraw.c (print_to_widget): Ifdef'd SLang specific code in order
+ to make it compile with ncurses. Syntax highlighting in the
+ internal editor is already disabled when SLang isn't used.
+
+1998-05-24 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * widget.c (port_region_marked_for_delete): New per-port
+ piece of code: Provides a way for good selection killing.
+
+Sun May 24 02:45:03 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * utilunix.c, util.h (errno_dir_not_empty): deleted
+
+Sat May 23 22:29:57 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * file.c (check_dir_is_empty): New function which takes a path and
+ returns -1 on error, 1 if there are no entries besides "." and
+ ".." in the directory path points to, 0 else. This function
+ actually opens and reads the directory and doesn't do tricks we
+ used to do with rmdir.
+
+ * file.c (erase_dir, erase_dir_iff_empty): Use check_dir_is_empty
+ to detect non empty directories. The old code tried to remove the
+ directory and decided on errno whether the failure of rmdir was
+ caused by a non empty directory or whether there was a different
+ error.
+ Unfortunatly not every filesystem sets errno to EDIRNOTEMPTY if
+ you try to delete a non empty directory. Namely the linux user
+ space nfs server sets errno to EIO, Suns nfs server sets it to
+ EEXIST and the AIX nfs server sets it to ??? (Steve reported
+ problems on AIX so I guess AIX sets errno to a value we currently
+ don't check).
+
+1998-maj-18 Tamasi Gyorgy (gt_cosy@usa.net)
+
+ * lib/mc.menu: 'Z' on 'tar.Z' and 'tar.z' files: '%f' -> '$1'.
+
+ * lib/mc.ext.in.qnx.diff, lib/mc.menu.qnx.diff (QNX): modified
+ 'mc.ext.in' (tar -t: output to stderr); modified 'mc.menu' (tar is
+ not GNU tar: doesn't know '-z'); support for '*.tar.F':
+ 'freeze'-compressed tar files [No automatic configure/install
+ implemented: patches must be applied before running 'configure'
+ (mc.ext.in.qnx.diff: this patch can be not only QNX-specific...)]
+
+ * lib/Makefile.in: 'mc.ext.in.qnx.diff' and 'mc.menu.qnx.diff' added
+ to DISTLIB.
+
+ * slang/sldisply.c:
+
+ SLTT_TRANSP_ACS_PATCH dependant code:
+
+ The problem: some terminals (QNX/qansi*, SCO OS5/ansi [?]) map the
+ whole upper half of the ASCII table to the lower half, when
+ alt-char-set is activated with the smacs/as string-sequence. This
+ means, that if 0 <= ch < 128 written to the terminal, it will be
+ translated to (ch+128) automatically by the terminal: so not only
+ the line-drawing characters can be written, when the alt-char-set
+ is activated. It implicitly means, that space, NL, CR, etc.
+ characters (exactly: anything besides the "standard" line drawing
+ characters) can not be written directly to the terminal, when the
+ alt-char-set is activated, because writing these characters
+ doesn't cause an implicit/temporary switching-back to the standard
+ char-set!
+
+ The original code in SLang assumes that space, NL, CR, etc. can be
+ printed when alt-char-set is activated. If SLTT_TRANSP_ACS_PATCH
+ is defined, the modified code will not use this assumption.
+ [Remark: the patch-code is not the most exact solution, but
+ works...]
+
+ QNX_QANSI_SLANG_COMPAT_ACS_PATCH dependant code:
+
+ A more OS/terminal-specific solution for the problem mentioned
+ above (->SLTT_TRANSP_ACS_PATCH).
+
+ If QNX_QANSI_SLANG_COMPAT_ACS is defined, the default smacs/sa,
+ rmacs/ae, acsc/ac [and sgr/sa, if it would be used!] command
+ sequences will be replaced internally with the "old style"
+ (pre-QNX 4.23) sequences in case of QNX/qansi terminals. Using
+ these optional command sequences the terminal remains compatible
+ with the original SLang code (without using the workaround-code
+ enabled by defining SLTT_TRANSP_ACS_PATCH).
+
+ Remark:
+
+ Currently SLTT_TRANSP_ACS_PATCH is not auto-configured by
+ 'configure'. (Must be manually defined...)
+
+ There is some (QNX-specific) auto-configuration hand-coded in the
+ source:
+
+ #ifdef SLTT_TRANSP_ACS_PATCH
+ # if defined(__QNX__) && defined(QNX_QANSI_SLANG_COMPAT_ACS)
+ # undef SLTT_TRANSP_ACS_PATCH
+ # endif
+ #else
+ # if defined(__QNX__) && !defined(QNX_QANSI_SLANG_COMPAT_ACS)
+ # define QNX_QANSI_SLANG_COMPAT_ACS 1
+ # endif
+ #endif
+
+ * slang/slutty.c: "newtty.c_iflag &= ~(ECHO | INLCR | ICRNL);"
+ ECHO(0x08) is a c_lflag bit, it means PARMRK(0x08) in c_iflag. (!?!)
+
+ * src/file.c: 'do_reget' can be extern if (USE_VFS && USE_NETCODE),
+ not if (USE_VFS).
+
+ * src/find.c (search_content()): Variable 'i' "must be" 'int', not
+ 'char'. ["i == -1": (buggy?) WCC 10.6 doesn't convert automatically
+ (int)(-1) to (char)(-1) (GCC does), so "comparison result always 0"
+ warning produced. It is cleaner to define 'i' as 'int', than cast
+ '-1' to 'char', because 'read()' returns 'int'.]
+
+ * src/key.c (init_key()): Call load_xtra_key_defines() and clear
+ 'use_8th_bit_as_meta' by default under QNX, if a 'qnx*' terminal
+ detected. (A saved config file (mc.ini) can override it later...)
+
+ * src/key.h: Declare load_xtra_key_defines().
+
+ * src/keyxdef.c: Provides a method to define some platform-specific
+ additional key mappings. (e.g. QNX terminals can handle most of
+ META-? combinations as ALT-?...) ('keyxdef.c' currently not listed
+ in doc/FILES...)
+
+ * src/layout.c: TIOCGWINSZ must be available (so <sys/ioctl.h> (?)
+ included), because window-resizing code doesn't work, if not defined.
+
+ * src/main.c: 'print_usage()' is reserved name in the QNX run-time
+ library, so 'print_usage()' renamed to 'print_mc_usage()'
+
+ * src/mouse.c (QNX): ncurses 1.9.8a ported to QNX doesn't provide the
+ 'SP' pointer as a global symbol in the library, so the keyok()
+ emulation currently can not be used under QNX (4.24 & Watcom C 10.6
+ release version).
+
+ * src/slint.c (QNX): 'qansi*' terminals added to the color_terminals[]
+ list.
+
+ * src/subshell.c, src/utilunix.c (QNX): include <unix.h> to get
+ prototype for exec*()!!! [See README.QNX/Section 1.4 about the
+ dangerous "No prototype for <function>" warnings emitted by Watcom C,
+ if <function> is a 'printf()'-style function having variable number
+ of arguments and you compile your source with the default register
+ calling convention!!!]
+
+ * Makefile.in: 'keyxdef' module added to SRCS and OBJS.
+
+ * <mc-root>/README.QNX: QNX-specific notes.
+
+ * <mc-root>/configure (line 3369), <mc-root>/configure.in (line 88):
+ 'test x$CCOPTS = x;' modified to 'test "x$CCOPTS" = x;'
+
+ * <mc-root>/Makefile.in: README.QNX added to DISTMAIN.
+
+Thu May 21 00:09:45 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * menu.c (menubar_event): Don't set menubar->selected to the
+ invalid value -1. Fix for the bug reported by root@liepa.soften.ktu.lt
+
+ * menu.c (menubar_drop_compute): removed the check for inrange
+ items which isn't necessary any longer.
+
+Wed May 20 16:27:56 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * widget.c (history_put): input line history was defunct because
+ there was an #ifndef where an #ifdef should be.
+ Btw. PORT_WIDGET_WANTS_HISTORY seems incomplete because a lot of
+ history code is included even when this define is undefined.
+
+1998-05-19 Tamasi Gyorgy <gt_cosy@usa.net>
+
+ * src/*: Until I get a better ChangeLog: Tamasi's port of the
+ code to QNX.
+
+1998-05-19 Alexander Lukyanov <lav@yars.free.net>
+
+ * Makefile.in: Distirbution fix so that people are not forced to
+ install gettext.
+
+1998-05-19 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * ext.c: Memory leak fixed.
+
+Mon May 18 22:24:09 1998 Norbert Warmuth <k3190@fh-sw.de>
+ * lib/mc.ini.in: s/reges/regex/
+
+ * main.c (process_args): return void, the return value was only
+ used once but wrong (-h displayed help twice).
+ (handle_args): -h: don't display help twice
+ (print_usage): Don't print program name and version, that's
+ already done by version(0).
+
+ * menu.c (menubar_paint_idx): Highlight Hotkeys also on slow
+ terminals (hotkeys were not displayed at all).
+
+1998-05-18 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * menu.c (menubar_drop_compute): Check for inrange items.
+
+1998-05-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * color.c (init_colors): Provide X-only version of color
+ initialization.
+
+Thu May 14 01:56:11 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * configure.in: Don't add -lintl to LIBS when included gettext is
+ used (further checks for libraries would fail because libintl.a
+ isn't build, yet). Instead use and substitute LINTL.
+
+ * Makefile.in (OURLIBS): add @LINTL@
+
+Tue May 12 17:45:49 1998 <psheer@obsidian.co.za>
+
+ * syntax.c: yet more minor modifications.
+
+1998-05-11 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c: New default: auto-save setup.
+
+ * screen.c (move_right, move_left): Add support for icon-view movement.
+
+1998-05-09 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * setup.c (panel_load_setup): On non-icon editions, fall back to
+ list_full
+
+Sun May 10 13:27:50 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * widget.c (handle_char): Don't try to to delete default text in
+ input widget more than once. Right after MC's start copy_filename
+ (ESC Enter) failed because a flag wasn't cleared while characters
+ were stuffed into the commandline (Andrej reported this bug).
+
+ * main.c (copy_readlink): usr mc_readlink instead of readlink
+
+ * file.c: Changed default for the copy/move option "dive into
+ subdir if exists" to off (note: this was only possible after the
+ change in setup.c).
+
+ (copy_dir_dir): Activated the previously uncommented code which
+ implements "Dive into subdirs". Even when there's no case where we
+ actually would like that behaviour it is a documented feature.
+ Though I don't wanted to change the default behavour. Hence the
+ option change.
+
+ (file_mask_defaults): set dive_into_subdirs
+
+ (file_mask_dialog): Fix for debian Bug #20727: Move operation with
+ "[ ] Dive into subdir if exists" and destination filename not
+ wildcarded. If destination is an existing directory then files
+ will be moved into this directory. If destination is not an
+ existing directory then src file will be renamed (one file
+ selected) or an error will be displayed (more than one file
+ selected).
+
+ (file_mask_dialog): made the option "Using shell patterns" local
+ to the current copy/move operation, i.e. this option is always
+ initialized with the global options's value. Previously it affected
+ the global Options/Configuration/shell Patterns.
+ Another possiblilty would be to make the global option a default
+ option on startup and keep changes in the copy/move dialog
+ (without saving these changes with save setup).
+
+ * setup.c: Don't save and load options which can be changed
+ outside the options menu. For example I don't like that
+ preserve_uid_gid and dive_into_subdirs from the copy/move dialog
+ are saved and restored (strange, what about the other options from
+ this dialog?).
+ It would be much cleaner to make these option read-only. This way
+ one could edit ~/.mc/ini to provide default option setting on
+ startup and "Save setup" wouldn't have side effects outside the
+ option's menu.
+
+Sun May 10 13:24:20 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * doc/mc.1.in, doc/mc.sgml, mc.hlp: Updated to reflect new default
+ for dive into subdirs.
+
+Sun May 10 13:21:45 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/syntax.c: Disable debug messages on stderr.
+
+ * edit/edit.h: Added missing _()
+
+1998-05-06 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * layout.c (flag_winch): Propagate the window change to the slave
+ pty even when not running our event loop. The resize_subshell
+ routine is thread safe.
+
+ * dlg.c (update_cursor, dlg_broadcast_msg_to): Do not send
+ messages if no widgets are on the Dlg_head, this happens now with
+ the gmc code, as we can have all of the windows shut down.
+
+Wed May 6 13:46:37 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * syntax.c: more bug fixes.
+
+1998-05-04 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * view.c (view_quit_cmd): Use dlg_stop.
+
+ * main.c (ctl_x_cmd): Implement ctl-x handling as a state of the
+ key press events. Drop the usage of mi_getch to acomplish this
+ task.
+ (midnight_callback): Deal with the current map depending on the
+ c-x state.
+
+Mon May 4 10:21:31 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * background.c (message_1s1d): the unprocessed string with %d was
+ passed to message_1s; fixed small memory leak
+
+ * widget.c (button_callback): WIDGET_CURSOR: make cursor position
+ dependend from button type (fixes the off by one bug in advanced
+ changeown).
+
+ * file.c (copy_file_file): Schedule deletion of short target file
+ only when we created or truncated the target file and not already
+ when we decided to overwrite an existing file.
+
+1998-05-03 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * boxes.c (task_cb): Use kill, not INT, as we are catching INT in
+ the program.
+
+Sat May 2 14:07:05 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * setup.c: ALT('H') now shows a directory history - that
+ ESC SHIFT-h or ALT-SHIFT-h
+
+Fri May 1 17:45:58 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * syntax.c: initial support for LaTeX 2.09 files added,
+
+ * syntax.c: some minor bug fixes. and reorganisation
+ of context and keyword priorities.
+
+Fri May 1 11:24:21 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * syntax.c: syntax highlighting segfaults when editing a binary
+ file - now fixed.
+
+Thu Apr 30 12:23:50 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * src/file.c: lot of i18n of file Copy/Move/Delete operations. Maintainers
+ of message catalogs please notice introduced op_names1 and formats for
+ file operations.
+
+ * src/boxes.c: i18n of background jobs control and quick cd
+ dialog boxes.
+
+ * src/menu.c (menubar_arrange): resizing of menubar upon changes of
+ window size is now controlled by preprocessor symbol RESIZABLE_MENUBAR
+ (now it's off by default, as requested in mailing list). If it is off,
+ menubar items are separated with fixed number of spaces (3).
+
+ * src/layout.c, edit/editwidget.c: calls to menubar_arrange ifdef'ed
+
+
+1998-04-30 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c (parse_an_arg): GNOME edition keeps track of various
+ --geometry and various directories passed.
+
+1998-04-29 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c (update_panels): Great API simplification. update_panels
+ only cares about the contents of the current panel, every other
+ panel keeps the current selection (this was the behaviour
+ anyways).
+
+ update_panels can be provided in a per-port fashion as well.
+
+Wed Apr 29 03:06:09 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * syntax.c: some optimisations, as well as support for
+ syntax highlighting of Makefiles and ChangeLog files.
+ Fixed some syntax highlighting bugs. All C and C++
+ keywords added.
+
+Tue Apr 28 06:11:08 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * view.c (toggle_wrap_mode, toggle_hex_mode): Force recalculation
+ of bottom_first (we mustn't use an already calculated and cached
+ value because it is invalid for the new mode and the End key would
+ not move to the end of the file).
+
+ * configure.in: Renamed the option `--with-our-slang' to
+ `--with-included-slang' (this one looks better because we also
+ have an `--with-included-gettext').
+ Make the option `--with-ext2undel' recognice a given path.
+
+ * cmd.c (view_file_at_line): In plain view (F13) set the default
+ magic flag to zero in order to view the file content unprocessed
+ (esp. don't uncompress files if they are compressed). The
+ view_simple_cmd got broken when the default magic flag in view.c
+ was changed from 0 to 1.
+
+ * view.c (do_view_init, goto_line): Set wrap mode temporary off
+ to make goto line number work, i.e. `line number' now always means
+ line number in file and not line number on screen (in wrap mode
+ one long line wrapped once is displayed in two lines on the screen).
+ That's important when the viewer is invoked from the find file
+ dialog to display even in wrap mode approxiamtly the part of the
+ file where we found the content we searched for.
+
+ (move_forward2): In wrap mode lines were sometimes counted wrong
+ causing cursor up to move more than one line.
+
+ (move_backward2): Fixed the movement in wrap mode.
+
+ (change_viewer): Always re-init viewer when we have a filename,
+ i. e. if the viewer is invoked with simple_view_cmd then we can switch
+ with the F8 key between unprocessed file content und uncompressed
+ file content.
+ (view_init): re-init view also when magic flag was altered
+
+1998-04-27 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (is_a_panel): Added a routine to determine if a widget
+ is a panel.
+
+1998-04-27 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (file_entry_color): Check if fe->fname has something.
+
+Sun Apr 26 00:21:12 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * slint.c: Applied the patch from Bill Nottingham <wen1@cec.wustl.edu>
+ to make it link against SLang >=1.0.
+ I reviewed the diffs to the part of SLang we use and there are no
+ further changes to MC necessary (one function's return value
+ changed it's meaning but we don't use this return value).
+
+ * configure.in: Undone the change which prevented linkage against
+ SLang >=1.0
+
+Sat Apr 25 13:41:43 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * edit.h, syntax.h: some optimisations to improve syntax
+ highlighting speed.
+
+1998-04-24 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * color.h: Move the CTYPE definition
+
+Fri Apr 24 16:43:25 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * main.h, setup.c: editor_syntax_highlighting option added
+ for ini file.
+
+Fri Apr 24 14:54:06 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * syntax.c: added. this files reads ~/.cedit/mcsyntax and
+ processes generic rules for syntax highlighting of different
+ file types. Syntax highlighting does not store an attribute byte
+ for each byte of the edit buffer. Rather, it calculates colours
+ on the fly, with an optimised algorithm, as the text is being
+ rendered.
+
+ * edit.c, edit.h, editwidget.c, editdraw.c: changes to facilitate
+ syntax highlighting.
+
+ * editoptions.c: dialog box updated with a syntax highlighting
+ checkbox.
+
+ * slint.c: new function alloc_color_pair(). This allocates a new
+ color index. init_pair() itself now records the last colour index
+ so that colours can be added on to the end of the colour list
+ with alloc_color_pair().
+
+ * slint.c: new function try_alloc_color_pair() returns a new index
+ for a color with named fg and bg. Checks if that named colour
+ already exists before setting a new index.
+
+1998-04-23 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * user.c (execute_menu_command): Create temporary file exclusively
+ as well.
+
+ * main.c (do_execute), utilunix.c (my_system), gutil.c, ext.c:
+ Changed the way we execute programs. Now a new set of flags exist
+ that indicates how the execution is done. In ports that execute
+ by sending the process to background, when executing temporary
+ files, we have to remove the files after the child process has
+ finished executing the code not after the calling do_execute.
+
+ * ext.c (exec_extension): Create temporary file exclusively.
+
+Mon Apr 20 01:32:20 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * configure.in: Don't try to link MC against SLang >= 1.0. I will
+ remove this restriction when I'm sure that it's save to use the new
+ version (the documentation to SLang mentions some changes of
+ return values).
+
+1998-04-16 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * file.h: Added prototype for copy_dir_dir.
+
+ * file.c (real_do_file_error): use the proper flags, this is not a
+ D_INSERT dialog box, for what it is worth. Important bug fix.
+
+ * utilunix.c (get_owner): Declare.
+
+ * widget.h: Added various missing prototypes for the X edition.
+ * view.h: Added various missing prototypes for the X edition.
+ * widget.c (x_radio_toggle): New per-port variable: PORT_HAS_RADIO_TOGGLE
+
+1998-04-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (GT): Assign two spaces for the minimum size of the
+ "type" field for the GNOME edition. This gives some extra space
+ for the icon that gets displayed.
+
+ * dlg.c (remove_widget): New function: used to remove a widget
+ from an existing Dlg_head;
+ (destroy_widget): Destroy a specific Widget.
+ (add_widgetl): Extended to deal with the fact that a running
+ Dlg_head can become empty.
+
+ * panelize.c (l_call): Update the input line every time the user
+ selects the entry with the mouse (pretty common in the gnome
+ edition).
+
+ * hotlist.c (add_new_group_input): Removed an extra field that was
+ causing problems.
+
+ * find.c (find_parameters): Tree button is gone for gnome until we
+ get the tree function working on gnome.
+
+ * cmd.c (save_setup_cmd): Per Elliot's suggestion, do not pop up a
+ dialog box to inform the user about the saved setup.
+
+1998-04-15 Pavel Machek <pavel@elf.ucw.cz>
+
+ * cmd.c: Report failed chdir attempts.
+
+Wed Apr 15 10:48:41 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * src/hotlist.c: changes to hotlist boxes i18n.
+
+ * src/panelize.c: changes to panelize boxes i18n.
+
+ * src/wtools.c (query_dialog): Take care about possible '&' in
+ button names while calculating window sizes and button positions.
+
+1998-04-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (string_file_nlinks): The buffer was too small and we
+ were overwriting parts of it.
+
+ * subshell.c (do_subshell_chdir): Memory leak fix.
+
+ * find.c (do_search): Do not use undefined order of evaluation.
+
+ * user.c: Do not use undefined order of evaluation.
+
+ * dlg.c (init_dlg): Do init the default return value.
+
+Sun Apr 12 03:09:17 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * cmd.c (view_other_cmd): #ifdef'd application_keypad_mode and
+ numeric_keypad_mode (don't include it in non text editions)
+
+Sun Apr 12 02:48:26 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * xv/xvscreen.c: removed duplicate (conflicting) definition
+ of do_enter()
+
+Sun Apr 12 02:24:57 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * text.c (edition_post_exec), cmd.c (view_other_cmd): Don't change
+ the keypad mode when we don't use the alternate plus minus. Pavel
+ forgot an if-clause when he replaced the escape sequences (or
+ another point of view: I forgot one if-clause at different place).
+
+Fri Apr 10 17:35:23 1998 Philippe De Muyter <phdm@macqel.be>
+
+ * configure.in (AC_NCURSES): When checking for library location,
+ put -L option before -l option, not after.
+
+Fri Apr 10 10:35:06 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * file.c (file_mask_dialog): When the shell patterns option was
+ off source_mask was freed twice.
+
+1998-04-10 Marc Ewing <marc@redhat.com>
+
+ * panel.h: added up_b
+
+1998-04-08 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * widget.c (update_input): Set the used flag early in update_input
+ to allow X widget to catch the right value
+
+ * screen.c (do_enter): Return the status for the operation.
+
+ * main.c (main): Sigh. This was hard. I added support for argp.
+ Right now we support both argp for the GNOME edition and popt for
+ the other editions. I will remove popt support in the future and
+ only keep argp.
+
+ * dlg.c (add_widgetl): Adding widgets to an already running dialog
+ had some flaws. Fix this.
+
+Wed Apr 8 11:15:29 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * src/find.c: changes to find_parameters/find_file i18n.
+
+ * src/widget.c: new function introduced, button_scan_hotkey();
+ button_new() and button_set_text() fixed to use mentioned function.
+
+ * src/key.[ch], src/dlg.c: changes to make recognition of ESC char as
+ ALT(c) possible for 8-bit chars. (By replacing 'A'/'Z' comparisons with
+ call to isalpha() in the way proposed by Norbert).
+
+ * src/boxes.c: changes to display box i18n
+
+ * src/learn.c: changes to learn key dialog i18n
+
+1998-04-07 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c (update_one_panel_widget): New routine: Updates a panel
+ based on the widget, not the index. Used by the GUI versions.
+
+ * find.c (find_file): Cancel idle tasks before we destroy the find
+ dialog.
+
+ * dlg.c (destroy_dlg): Call x_destroy_dlg_start, a new hook that
+ is invoked to allow the frontend code to prepare for dialog
+ destruction. Only the Gnome edition is using this: it uses this
+ to hide the dialog and avoid flickering.
+
+ * main.c: dtterm also has mouse support.
+
+1998-04-06 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * wtools.c (quick_callback): Process DLG_KEY events on X.
+
+ * utilunix.c (max_open_files): new routine; Used to figure out
+ the number of available file descriptors.
+
+Sat Apr 4 00:16:49 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * src/layout.c: changes to layout dialog box i18n
+
+ * src/option.c: changes to configure box i18n
+
+ * src/cmd.c: added N_() macro for machine_str
+
+ * src/wtools.c (real_input_dialog_help): ok/cancel buttons are places
+ symmetrically spaced relatively to center of the box. It produces
+ nicer appearance with i18n (IMO :)
+
+ * src/boxes.c (confirm_box): i18n stuff added.
+
+Mon Apr 6 07:48:22 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * Makefile.in: "make dist" works with bash 1.x again
+
+Fri Apr 3 05:23:20 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * configure.in: ALL_LINGUAS test added, to allow specify list
+ of languages to be installed by setting env variable before
+ configure. If it is empty, it defaults to full list.
+
+ * src/menu.h menu_entry.{hot_pos, is_dupped} dropped
+
+ * src/menu.c: consistency fixes: pull-down menu items are now
+ accessible either with arrow keys or with hotkeys, denoted with &
+ (and highlighted). (key combinations, placed to the right of items
+ intended to be used from outside the menus). Freeing menu entries
+ removed as it no longer needed
+
+ * src/main.c, edit/editmenu.c: menubar init code is changed to conform
+ above fixes.
+
+ * edit/edit.h: use of "Cancel" in error_dialogs replaced with
+ "Dismiss", to avoid collisions in translation of "Cancel" in other
+ places with this case.
+
+ * src/boxes.c: select_format() and it's support removed, as it is
+ obsoleted by input line history feature. display_init()/display_callback
+ fixed to suite i18n changes. sort_box() - alike.
+
+ * src/option.c: pause_options added &'s and gettext calls to expand
+ statically assigned values.
+
+ * src/widget.c: (radio_callback) hotkey recognition is changed to
+ &-notation, rather than simple uppercase.
+
+ * src/dlg.c: (dlg_try_hotkey) plain symbol comparison replaced with
+ call to isalpha(), this fixes errorneous exit from input line, when
+ button hotkey is 8-bit NLS char.
+
+Fri Apr 3 12:23:28 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * TODO: Removed obsolete entries: Similar entries in tree view
+ are displayed correct; user specific files has been moved
+ to ~/.mc/
+ Added: Check what to do with menubar_arrange/destroy_menu stubs
+ in tk/tkmenu.c; the interal editor (not portet yet) adds entries
+ to the wrong menubar
+
+Wed Apr 1 00:15:30 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * key.c, key.h (numeric_keypad_mode, application_keypad_mode): New
+ functions which encapsulate two hardcoded escape sequences from main.c.
+
+ * main.c (main): Use the two new functions from key.c
+
+ * main.c, screen.c: Moved all file selection keys from the default
+ keymap to the keymap for panels in listing mode.
+ Changed *_selection_cmd to *_selection_cmd_panel in panel_keymap
+ (functions in panel_keymap get a WPanel * as first parameter,
+ i.e. the indirection with cpanel isn't necessary).
+
+ * main.c (midnight_callback): Keys '*' and '-' were not treated
+ when only_leading_plus_minus==0;
+ Optimized the if-clauses a little bit (i.e. removed duplicate
+ checks). More optimation is possible but it would make the whole
+ stuff completly unreadable.
+
+ * key.c (correct_key_code): KP_ADD, KP_SUBTRACT and KP_MULTIPLY
+ will be translated to +, - and * only if the option
+ alternate_plus_minus is turned off.
+
+ * learn.c (learn_keys): Turn alternate_plus_minus temporarily on
+ to avoid translation of KP_ADD, KP_SUBTRACT and KP_MULTIPLY in
+ correct_key_code/make sure keypad is in application mode (makes it
+ possible to learn this keys).
+
+ * cmd.c (reverse_selection_cmd_panel): New function (renamed from
+ reverse_selection_cmd, takes a WPanel * as parameter, references to
+ cpanel changed to panel/the passed parameter).
+ reverse_selection_cmd now simply calls this function with cpanel.
+ This pair was missing among the *_selection_cmd* functions.
+
+ * cmd.h: Added function prototypes.
+
+1998-03-31 Paul Sheer <psheer@obsidian.co.za>
+
+ * cmd.c (nice_cd): Forgot to invoke the history registration in
+ one spot.
+
+1998-03-30 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * menu.c (destroy_menu): Implement destroy_menu for all of the
+ ports as a routine that frees the menu entries if
+ internationalization has been enabled.
+
+ * wtools.c (quick_dialog_skip): Do not i18n any string that is empty.
+
+Sun Mar 29 23:02:09 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * src/menu.[ch]: new member to menu_entry (hot_pos) introduced to make
+ internationalized version of menu use externally defined hotkeys
+ (denoted with preceding &). create_menu() fixed to load intl text of
+ the entries. Some fixes around menu.c to enable usage of reloaded
+ hotkeys.
+
+ * main.c, editmenu.c: menu initialization code fixed to conform new
+ menu structure. editmenu init code includes N_(..) now.
+
+ * menu.c, layout.c, editwidget.c: bar menu items displacement is made
+ dynamically upon initialization and window size changes. Mouse event
+ processing is fixed accordingly.
+
+Sat Mar 28 13:18:36 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * src/screen.c: (repaint_file) last patches to format_file() in the
+ same file broke appearance of panels in brief mode -- fixed.
+
+Mon Mar 30 20:02:49 1998 Paul Sheer <psheer@obsidian.co.za>
+
+ * main.c, screen.c, dirhist.c, dirhist.h, main.h, widget.c,
+ main.h and others?: Directory history added. The previous
+ directory history code was removed. The directory history now
+ loads and saves using the same routines as the input widget. The
+ keys meta-y, and meta-u are used to go backward and forward
+ through the history. The buttons to the right and left of the
+ current directory display on the panel can be used as well. The
+ v button brings up a history, but no key is assigned to this.
+ Discussion as to correct color and shape of these buttons is
+ open. show_hist() in widget.c is made generic to be called for
+ any widget. Help pages still needed to be added for the
+ directory history.
+
+Wed Mar 25 19:05:31 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * view.c (view_done): Set monitor off before deleting the view
+ file dialog.
+
+ * subshell.c (init_subshell): Added ':q' to $cwd in the precmd for
+ tcsh. It preventes command and filename substitution (e.g. for
+ a directory named "[word] words")
+
+Mon Mar 23 18:06:10 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c: Deleted some old and unused code
+
+1998-03-24 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * All over the src/ directory: Internationalization changes.
+
+ * background.c: Avoid buffer over-runs and reduce number of
+ internationalization strings.
+
+Mon Mar 23 14:04:07 1998 Philippe De Muyter <phdm@macqel.be>
+
+ * configure.in (nlink_t): Check it using AC_CHECK_TYPE.
+ * acconfig.h (nlink_t): New define slot.
+
+Mon Mar 23 08:17:55 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * src/main.c: mcedit can be named mce or mcedit.exe - only
+ 3 first letters are significant. The same for mcview.
+ Console is always saved in do_execute() if it was saved there.
+
+ * src/util.h: STRNOMP introduced (strncmp on unix and strnicmp
+ on OS2_NT)
+
+ * slang/slgetkey.c: SLang_getkey() and SLang_input_pending()
+ enabled for OS2_NT
+
+ * myslang.h: using fast one_vline() and one_hline() for OS2_NT
+
+Mon Mar 23 00:47:51 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * autogen.sh: added support for builddir != srcdir
+
+ * doc/Makefile.in: The manual pages are generated files and
+ located in the builddir and not in the srcdir.
+
+ * find.c (find_file): Use the same hotkey for the panelize button
+ as we use with the external panelize command.
+
+Fri Mar 20 17:51:01 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * myslang.h: --with-ncurses didn't compile: renamed
+ KEY_BACKTAB to KEY_BTAB (the name ncurses uses)
+
+ * dlg.c (dlg_key_event): likewise
+
+1998-03-19 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c: Remove KEY_DC forever. This should have never been
+ here.
+
+Wed Mar 18 22:08:34 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * achown.c (do_enter_key): call endgrent, endpwent.
+
+ * chown.c (init_chown): call endgrent, endpwent.
+
+Tue Mar 17 23:58:40 1998 Pavel Machek <pavel@elf.ucw.cz>
+
+ * src/file.c: Fix for the case where the disk gets full.
+
+Tue Mar 16 18:35:53 1998 Stas Maximov <stmax@u213.srcc.msu.su>
+
+ * src/hotlist.c default values for dialogs which add entries to hotlist
+ are now set to the current directory.
+
+Tue Mar 10 14:42:01 1998 Stas Maximov <stmax@u213.srcc.msu.su>
+
+ * vfs/extfs.c, lib/mc.ext, vfs/extfs/extfs.ini, vfs/extfs/cpio.in
+ Added support for cpio extfs including compressed and gziped
+ cpio archives. compress and gzip handled separately because I saw
+ a lot of systems which have compress, but don't have gzip.
+
+Sat Feb 21 16:46:49 1998 Stas Maximov <stmax@u213.srcc.msu.su>
+
+ * src/subshell.c: failed to grantpt on SVR4 due to zero-initialized
+ subshell_pid. sigaction handler for SIGCHLD does waitpid(subshell_pid,
+ ...) and when subshell_pid == 0 it steals the zombie from grantpt(3)
+ which does fork/exec/waitpid for suid program to set the permissions on
+ pty. It's enough to initialize it to 1 or -2.
+
+1998-03-16 Federico Mena Quintero <federico@nuclecu.unam.mx>
+
+ * util.c (convert_pattern): Now the internal buffer is malloc()ed
+ instead of being static. This is required for long patterns.
+ (regexp_match): Free the pattern after calling convert_pattern().
+
+ * file.c (file_mask_dialog): Free the source_mask after calling
+ convert_pattern().
+
+Mon Mar 16 13:03:45 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * cmd.c: Internal edit is used by default. vi may be
+ confusing for some users.
+
+ * tree.c: tree_rmdir_cmd() should not return any value,
+ because it is not analyzed for errors.
+
+ * main.c: NT code: use O_BINARY instead of _O_BINARY
+
+ * util.c: DO not test for arguments that do not make sense under
+ Windows NT.
+
+ * file.c: utime.h always included for Windows NT port.
+
+ * view.c: Events are flushed only if the ports supports it.
+
+Mon Mar 16 12:30:39 1998 Stas Maximov <stmax@u213.srcc.msu.su>
+
+ * hotlist.c: Defaults on the hotlist add-current and new-entry is
+ the current directory.
+
+Sat Mar 14 17:30:21 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * file.c (panel_operate): Why was the flags in query_dialog set to
+ D_INSERT is a big mistery. Should be fixed now.
+
+Fri Mar 13 18:10:58 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * dlg.c (dlg_stop): New routine used to finish dialog boxes.
+
+ * cmd.c (set_panel_filter_to): Implementation split. To be used
+ by GNOME.
+
+ * widget.c (input_new): GNOME-entry widget is inspired in the
+ WInput + the history patches from Paul. Use the GNOME-entry
+ history, as this makes it easier to deal with the filter button on
+ the panel.
+
+ * setup.c (save_panel_types): Do not use if running on the gnome
+ edition. This need a lot of fixing for making this work with
+ gnome and session management.
+
+ * main.c (do_nc): DO not call setup_panels_and_run_mc as
+ create_panels in gnome edition does all this.
+
+ (setup_mc): Skip part of the setup.
+
+ (do_execute): Do not Execute any of the pause code after
+ run for gnome.
+
+Wed Mar 12 17:46:09 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * screen.c (chdir_other_panel, chdir_to_readlink): Use passed
+ panel instead of cpanel (removed mixed use of panel and cpanel).
+
+ * main.c, screen.c: Deleted F13 from the default keymap, added F13
+ and F14 to the panel's keymap (the keymap for panels in listing
+ mode). These two keys are only useful for panels in listing mode.
+ It seems there are even more candidates for such a move. Especially
+ select_cmd and unselect_cmd which appeared recently for the GNOME
+ edition in screen.c act unexpected for panels in tree-mode.
+
+ * cmd.c (view_simple_cmd): Added WPanel* to the parameter list.
+
+ (edit_cmd_new): No need to get a panel because it is not used.
+
+ * panelize.c: Changed hotkey of the Panelize button (Alt-p is
+ already used by the input line history). I wonder if I should
+ change it in the find dialog, too (just to have a unique hotkey
+ for the panelize button).
+
+Wed Mar 11 19:02:48 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * view.c: Lots of changes: Split the X11 code from the main view
+ program. This is needed to cleanly support the addition of the
+ Gnome version of the file viewer;
+
+ New names for old functions (just a view_ prefix):
+ view_add_character, view_add_string, view_gotoyx, view_set_color,
+ view_display_clean. Now all of them take a WView argument (which
+ is ignored in the macro for the text edition). This is to support
+ multiple open views at once.
+
+ * boxes.c (symlink_dialog): Enable ok/cancel buttons for the Gnome edition.
+
+ * cmd.c (link_cmd, symlink_cmd): Provide the filename to operate
+ on.
+
+Tue Mar 10 20:41:45 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * cmd.c (unselect_cmd_panel, select_cmd_panel): To avoid races on
+ the X11 version, these routines now take a panel argument at
+ invocation time.
+
+ * widget.c (radio_callback): Call x_radio_focus for FOCUS/UNFOCUS
+ events.
+ (button_callback): Fallback to default_msg on WIDGET_FOCUS
+ messages.
+
+1998-03-10 Federico Mena Quintero <federico@nuclecu.unam.mx>
+
+ * xslint.c (getch): Added missing "return".
+
+ * utilunix.c (init_groups): Added parentheses around
+ assignment/truth value.
+
+ * boxes.c: #include <stdlib.h>
+
+ * screen.c (string_inode): Cast fe->buf.st_ino to long to be
+ consistent with sprintf format.
+
+ * main.c (handle_args): Added parentheses around assignment/truth value.
+
+Sat Mar 7 14:33:38 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * src/complete.c: obsolete hack for OS/2 and NT removed.
+ Completion works for NT now (not very good)
+
+ * src/main.c: HOME variable is respected by NT and OS/2
+ versions. If it is missing, we use LIBDIR on OS2_NT and "/"
+ on Unix.
+
+ * src/key.h: SHIFT_PRESSED is set to 0x0010 on NT. This value
+ doesn't conflict with definitions for ALT and CTRL, but it is
+ SDK-compatible.
+
+ * vfs/vfs.h: Minor changes for OS/2. EMX defines mkdir with
+ 2 arguments
+
+ * vfs/tcputil,c, vfs/utilvfs.c: signal.h was includes twice.
+
+ * vfs/Makefile.in: undelfs.h is not used and should disapper
+
+ * slang/slos2tty.c: new file, copied from SLang-0.99.38,
+ needed for OS/2 port
+
+ * slang/Makefile.in: added slos2tty.c
+
+ * vfs/extfs/README: annoying spell errors corrected
+
+ * src/main.c: --termcap disabled for OS2_NT because it doesn't
+ (and cannot) work. ARCH_FLAGS is not needed anymore.
+
+ * src/text.c: most includes removed. Added a warning is someone
+ compiles this file with HAVE_X. Improved color scheme for
+ consoles with 16 background colors (e.g. OS/2). Hack for OS/2
+ removed.
+
+ * src/util.c, src/util.h: STRCOMP and MC_ARCH_FLAGS are moved
+ to util.h. It may be useful to use them for filenames' completion
+ on OS2_NT
+
+Fri Mar 6 19:29:54 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * find.c: Simplify header files: use the fs.h include file.
+
+ (use x_flush_events).
+
+ * screen.c (string_file_name): In GNOME, the CList widget does the
+ filename truncation, so we do not do it here.
+
+ (panel_new): Initialize all of the wpanel contents to zero. This
+ will is required by the GNOME X ports (to figure out if a field
+ has been inited or not).
+
+Thu Mar 5 10:28:40 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * popt.c (poptParseArgvString): make it compile with the native
+ compiler on AIX 4.1.3
+
+1998-03-04 Federico Mena Quintero <federico@nuclecu.unam.mx>
+
+ * cmd.c: Added #include "x.h"
+
+Wed Mar 4 14:49:55 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * doc/mc.1.in, mc.hlp: updated (these files haven't been updated
+ at the last change to mc.sgml)
+
+ * doc/mc.sgml: spelling error corrected
+
+ * Makefile.in: renamed all references of mc.1 to mc.1.in
+
+ * find.c (locate_egrep): Don't use an absolute path if egrep isn't
+ found at the usual places. Then execvp will search the directories
+ passed in the environment PATH variable (a little bit slower but
+ better than a defunct find content).
+
+ * tree.c: removed the include file I mistakenly added with my
+ last patch.
+
+Tue Mar 3 20:00:36 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * file.c (get_file): Take a panel argument. I am pretty sure that
+ this is broken for the case where we are copying from a WTree.
+
+ (panel_operate): take a panel argument instead of defaulting to
+ cpanel.
+
+Mon Mar 2 15:54:55 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * dlg.c (create_dlg): Set running to 0 on creation;
+ (add_widgetl): do widget initialization if the dialog is already
+ running when this dialog box is created.
+
+Mon Mar 2 12:11:37 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/ftpfs.c (changetype): Removed the hack which always forced
+ sending the command "TYPE I" when changing to binary transfer mode
+ was requested even when MC thought the connection was already in
+ binary mode (bucket->isbinary == 1). The correct fix is now in
+ login_server.
+
+ * vfs/ftpfs.c (login_server): Set the transfer mode stored in
+ the bucket to UNKNOWN (the bucket might be reused and the old
+ transfer mode isn't valid any longer).
+
+ * screen.c (panel_key): Cleanup: deleted if-clause with -1 (EV_NONE)
+ which isn't delivered to widgets by the dialog manager; always
+ return 1 when key was handled; removed the function keys from the
+ panel's keymap (the function keys are always handled by the
+ buttonbar); don't eat characters below ' ' (C-l and Shift-F3 now
+ work even when quick search was started); characters between 32 and
+ 255 start quick search if there is no commandline (no C-s necessary
+ to start search).
+
+ * tree.c (tree_key): likewise
+
+Tue Feb 24 18:37:36 1998 Stas Maximov <stmax@u213.srcc.msu.su>
+
+ * subshell.c: Set subshell_pid to 1 on startup
+
+Fri Feb 13 19:59:39 1998 Alexander Savelyev <fano@VCom.kiev.ua>
+
+ * screen.c: KEY_DC is also handled by delete_cmd.
+
+ * vfs/ftpfs.c (chdir): sending the CWD command is not necessary
+ (imho).
+
+ (ftpfs_connection_close): Do not use WAIT_REPLY, closes
+ connections faster.
+
+ (open_data_connection): implement the reget command.
+
+ * boxes.c: bigger VFS dialog box.
+
+ * file.c (init_replace): Add support for copying files only if the
+ size differs, and support for regetting ftp files.
+
+Wed Feb 11 20:08:50 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * user.c (execute_menu_command): Extented the syntax of %-macros
+ used in the user menu in order to switch quoting on (default) and
+ off, e.g. %0f means don't quote the expanded macro, %f and %1f mean
+ quote the expanded macro.
+
+
+Fri Jan 30 16:43:47 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * dlg.c (create_dlg): Now we pass the flags parameter to the
+ create_dialog routine.
+
+ * tkmain.c (xtoolkit_create_dialog): Check for the grided value
+
+Fri Jan 23 07:28:54 1998 Peter Daum <gator@cs.tu-berlin.de>
+
+ * extfs.c (open_extfs_archive): Pass the filename to the list
+ command.
+
+ * extfs/mailfs: New file system for browsing mail files (support
+ for compressed mail fiels as well).
+
+Fri Jan 23 07:19:18 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * edit/edit.h: mc_mkdir requires 2 arguments for any operation
+ system. Obsolete #ifdef's removed.
+
+ * edit/editwidget.c: ansi standard violation removed
+
+ * nt/Makefile.NT: default SLang directory is now ../slang. Most
+ of SLang sources are no more compiled for MC.
+
+ * nt/drive.h: new file. Copied from os2/drive.h with minor changes
+
+ * nt/ket.nt.c: new way for handling conflicting SHIFT_PRESSED
+ definitions. get_event can work without blocking. Copy, move
+ and delete operations work normally.
+
+ * nt/slint.nt.c: SLang_getkey2 and Slang_input_pending2 are
+ copied from src/slint.c
+
+ * nt/sys/param.h: annoying warnings temporaly suppressed.
+
+ * slang/slvideo.c, slang/slw32tty.c: new files. They contain
+ changes by Alexander Dong.
+
+ * src/myslang.h: definitions for acsii symbols removed, since
+ they are available in slang.h. Double lines are not used anymore.
+
+ * src/panelize.c: sys/wait.h is included only if HAVE_SYS_WAIT_H
+ is defined
+
+ * nt/Makefile.NT: text.c is added
+
+ * nt/Makefile.VC4: "-debug" switch for linker is not used for
+ release version
+
+ * src/screen.c (show_dir): double lines are no more used by NT and
+ OS/2 ports.
+
+ * src/wtools.c (real_input_dialog_help): layout of input dialog for
+ XView port is corrected
+
+ * edit/edit.h: mc_mkdir requires 2 arguments for any operation
+ system. Obsolete #ifdef's removed.
+
+ * edit/editwidget.c: ansi standard violation removed
+
+Wed Jan 21 14:01:29 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * ext.c (regex_command): reverted the patch that changed tests for
+ *p == ' ' || *p == '\t' to isspace(). isspace() is true for tabs,
+ newlines, carriage-returns and vertical tabs as well. Which is
+ not what we want.
+
+Wed Jan 21 11:58:39 1998 Sung-Hyun Nam <namsh@lgic.co.kr>
+
+ * ftpfs.c (retrieve_dir): Avoid compiler warning by testing
+ explicitly the value.
+
+ screen.c (format_file): color not initialized when we met
+ empty_line.
+
+Wed Jan 21 11:28:21 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * cmd.c, utilunix.c: cosmetic changes to reduce compiler warnings
+
+ * utilunix.c (my_system): small fix for SCO zombies moved here;
+ now it returns WEXITSTATUS(status) instead of status itself. While
+ missing it may not hurt on i.e., linux, on SCO it gives incorrect
+ value.
+
+ * vfs/extfs.c system() calls replaced with my_system() call; this
+ allows a greater degree of control - fixes SCO system() return value
+ processing. Notice: plain replacement system() with WEXITSTATUS(system)
+ does not produce correct behavior (don't ask me why).
+
+ * panelize.c (do_external_panelize): similar fixes for pclose()
+ return value on SCO.
+
+ view.c (load_view_file): inverted value of viewer_magic_flag to
+ put viewer decompression state in accordance with F8 label text.
+ Also default_nroff_flag is initialized to be 1; thus enabling all
+ filter processing by default easies mc usage for novice users.
+
+Sun Jan 18 13:47:37 1998 Sung-Hyun Nam <namsh@lgic.co.kr>
+
+ * main.c
+ * panel.h, tkscreen.h : error when compile dlg.c
+ * tkconf.h : paint_frame
+ * screen.c : to include paint_frame
+ * tkmain.c : I just copied clr_scr() from the text.c
+
+Fri Jan 16 16:19:59 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (format_file): Do not invoke the file_compute_color
+ routine for empty lines.
+
+ * gmain.c: Color scheme for Gnome
+
+ * gscreen.c: Color setup now allocated the GdkColor *.
+
+ * color.c: Moved the default color setting to a per-port
+ location (text.c for the text mode edition); new color
+ configuration: core; Fixed the case where the color spec was
+ buggy and we kept on a infinite loop;
+
+Fri Jan 16 13:47:13 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * nt/drive.nt.c, nt/chmod.nt.c: Updated button_new and check_new
+ calls
+
+Fri Jan 16 12:47:39 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/ftpfs.c (command): Don't log passwords when the dialog between
+ server and client is logged to a file (mc -l logfile).
+
+ * vfs/ftpfs.c (resolve_symlink, retrieve_dir): When a directory
+ contains spaces send two commands ("CWD path" and "LIST .") instead of
+ one command ("LIST path") in order to get directory listings.
--- /dev/null
+/* Chmod command -- for the Midnight Commander
+ Copyright (C) 1994 Radek Doulik
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h> /* For errno on SunOS systems */
+/* Needed for the extern declarations of integer parameters */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include "tty.h"
+#include "mad.h"
+#include "util.h"
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "main.h"
+#include "chmod.h"
+#include "achown.h"
+#include "chown.h"
+#include "../vfs/vfs.h"
+
+#ifdef HAVE_TK
+# include "tkmain.h"
+#endif
+
+static int single_set;
+struct Dlg_head *ch_dlg;
+
+#define PX 5
+#define PY 2
+
+#define FX 40
+#define FY 2
+
+#define BX 6
+#define BY 17
+
+#define TX 40
+#define TY 12
+
+#define PERMISSIONS 12
+#define BUTTONS 6
+
+#define B_MARKED B_USER
+#define B_ALL B_USER+1
+#define B_SETMRK B_USER+2
+#define B_CLRMRK B_USER+3
+
+int mode_change, need_update;
+int c_file, end_chmod;
+
+umode_t and_mask, or_mask, c_stat;
+char *c_fname, *c_fown, *c_fgrp, *c_fperm;
+int c_fsize;
+
+static WLabel *statl;
+static int normal_color;
+static int title_color;
+static int selection_color;
+
+struct {
+ mode_t mode;
+ char *text;
+ int selected;
+ WCheck *check;
+} check_perm[PERMISSIONS] =
+{
+ { S_IXOTH, N_("execute/search by others"), 0, 0, },
+ { S_IWOTH, N_("write by others"), 0, 0, },
+ { S_IROTH, N_("read by others"), 0, 0, },
+ { S_IXGRP, N_("execute/search by group"), 0, 0, },
+ { S_IWGRP, N_("write by group"), 0, 0, },
+ { S_IRGRP, N_("read by group"), 0, 0, },
+ { S_IXUSR, N_("execute/search by owner"), 0, 0, },
+ { S_IWUSR, N_("write by owner"), 0, 0, },
+ { S_IRUSR, N_("read by owner"), 0, 0, },
+ { S_ISVTX, N_("sticky bit"), 0, 0, },
+ { S_ISGID, N_("set group ID on execution"), 0, 0, },
+ { S_ISUID, N_("set user ID on execution"), 0, 0, },
+};
+
+struct {
+ int ret_cmd, flags, y, x;
+ char *text;
+} chmod_but[BUTTONS] =
+{
+ { B_CANCEL, NORMAL_BUTTON, 2, 33, N_("&Cancel") },
+ { B_ENTER, DEFPUSH_BUTTON, 2, 17, N_("&Set") },
+ { B_CLRMRK, NORMAL_BUTTON, 0, 42, N_("C&lear marked") },
+ { B_SETMRK, NORMAL_BUTTON, 0, 27, N_("S&et marked") },
+ { B_MARKED, NORMAL_BUTTON, 0, 12, N_("&Marked all") },
+ { B_ALL, NORMAL_BUTTON, 0, 0, N_("Set &all") },
+};
+
+#ifdef HAVE_X
+static void chmod_toggle_select (void)
+{
+#ifdef HAVE_TK
+ char *wn = (char *) ch_dlg->current->widget->wdata;
+ int id = ch_dlg->current->dlg_id -BUTTONS + single_set * 2;
+
+ check_perm [id].selected ^= 1;
+
+ tk_evalf ("%s configure -color $setup(%s)",
+ wn+1, check_perm [id].selected ? "marked":"black");
+#endif
+}
+
+#else
+static void chmod_toggle_select (void)
+{
+ int Id = ch_dlg->current->dlg_id - BUTTONS + single_set * 2;
+
+ attrset (normal_color);
+ check_perm[Id].selected ^= 1;
+
+ dlg_move (ch_dlg, PY + PERMISSIONS - Id, PX + 1);
+ addch ((check_perm[Id].selected) ? '*' : ' ');
+ dlg_move (ch_dlg, PY + PERMISSIONS - Id, PX + 3);
+}
+
+static void chmod_refresh (void)
+{
+ attrset (COLOR_NORMAL);
+ dlg_erase (ch_dlg);
+
+ draw_box (ch_dlg, 1, 2, 20 - single_set, 66);
+ draw_box (ch_dlg, PY, PX, PERMISSIONS + 2, 33);
+ draw_box (ch_dlg, FY, FX, 10, 25);
+
+ dlg_move (ch_dlg, FY + 1, FX + 2);
+ addstr (_("Name"));
+ dlg_move (ch_dlg, FY + 3, FX + 2);
+ addstr (_("Permissions (Octal)"));
+ dlg_move (ch_dlg, FY + 5, FX + 2);
+ addstr (_("Owner name"));
+ dlg_move (ch_dlg, FY + 7, FX + 2);
+ addstr (_("Group name"));
+
+ attrset (title_color);
+ dlg_move (ch_dlg, 1, 28);
+ addstr (_(" Chmod command "));
+ dlg_move (ch_dlg, PY, PX + 1);
+ addstr (_(" Permission "));
+ dlg_move (ch_dlg, FY, FX + 1);
+ addstr (_(" File "));
+
+ attrset (selection_color);
+
+ dlg_move (ch_dlg, TY, TX);
+ addstr (_("Use SPACE to change"));
+ dlg_move (ch_dlg, TY + 1, TX);
+ addstr (_("an option, ARROW KEYS"));
+ dlg_move (ch_dlg, TY + 2, TX);
+ addstr (_("to move between options"));
+ dlg_move (ch_dlg, TY + 3, TX);
+ addstr (_("and T or INS to mark"));
+}
+#endif
+
+static int chmod_callback (Dlg_head *h, int Par, int Msg)
+{
+ char buffer [10];
+
+ switch (Msg) {
+ case DLG_ACTION:
+ if (Par >= BUTTONS - single_set * 2){
+ c_stat ^= check_perm[Par - BUTTONS + single_set * 2].mode;
+ sprintf (buffer, "%o", c_stat);
+ label_set_text (statl, buffer);
+ chmod_toggle_select ();
+ mode_change = 1;
+ }
+ break;
+
+ case DLG_KEY:
+ if ((Par == 'T' || Par == 't' || Par == KEY_IC) &&
+ ch_dlg->current->dlg_id >= BUTTONS - single_set * 2) {
+ chmod_toggle_select ();
+ if (Par == KEY_IC)
+ dlg_one_down (ch_dlg);
+ return 1;
+ }
+ break;
+#ifndef HAVE_X
+ case DLG_DRAW:
+ chmod_refresh ();
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void init_chmod (void)
+{
+ int i;
+
+ do_refresh ();
+ end_chmod = c_file = need_update = 0;
+ single_set = (cpanel->marked < 2) ? 2 : 0;
+
+ if (use_colors){
+ normal_color = COLOR_NORMAL;
+ title_color = COLOR_HOT_NORMAL;
+ selection_color = COLOR_NORMAL;
+ } else {
+ normal_color = NORMAL_COLOR;
+ title_color = SELECTED_COLOR;
+ selection_color = SELECTED_COLOR;
+ }
+
+ ch_dlg = create_dlg (0, 0, 22 - single_set, 70, dialog_colors,
+ chmod_callback, "[Chmod]", "chmod", DLG_CENTER);
+
+ x_set_dialog_title (ch_dlg, _("Chmod command"));
+
+#define XTRACT(i) BY+chmod_but[i].y-single_set, BX+chmod_but[i].x, \
+ chmod_but[i].ret_cmd, chmod_but[i].flags, _(chmod_but[i].text), 0, 0, NULL
+
+ tk_new_frame (ch_dlg, "b.");
+ for (i = 0; i < BUTTONS; i++) {
+ if (i == 2 && single_set)
+ break;
+ else
+ add_widgetl (ch_dlg, button_new (XTRACT (i)), XV_WLAY_RIGHTOF);
+ }
+
+
+#define XTRACT2(i) 0, _(check_perm [i].text), NULL
+ tk_new_frame (ch_dlg, "c.");
+ for (i = 0; i < PERMISSIONS; i++) {
+ check_perm[i].check = check_new (PY + (PERMISSIONS - i), PX + 2,
+ XTRACT2 (i));
+ add_widget (ch_dlg, check_perm[i].check);
+ }
+}
+
+int stat_file (char *filename, struct stat *st)
+{
+ if (mc_stat (filename, st))
+ return 0;
+ if (!(S_ISREG(st->st_mode) || S_ISDIR(st->st_mode) ||
+ S_ISLNK(st->st_mode)))
+ return 0;
+
+ return 1;
+}
+
+static void chmod_done (void)
+{
+ if (need_update)
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+static char *next_file (void)
+{
+ while (!cpanel->dir.list[c_file].f.marked)
+ c_file++;
+
+ return cpanel->dir.list[c_file].fname;
+}
+
+static void do_chmod (struct stat *sf)
+{
+ sf->st_mode &= and_mask;
+ sf->st_mode |= or_mask;
+ if (mc_chmod (cpanel->dir.list [c_file].fname, sf->st_mode) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chmod \"%s\" \n %s "),
+ cpanel->dir.list [c_file].fname, unix_error_string (errno));
+
+ do_file_mark (cpanel, c_file, 0);
+}
+
+static void apply_mask (struct stat *sf)
+{
+ char *fname;
+
+ need_update = end_chmod = 1;
+ do_chmod (sf);
+
+ do {
+ fname = next_file ();
+ if (!stat_file (fname, sf))
+ return;
+ c_stat = sf->st_mode;
+
+ do_chmod (sf);
+ } while (cpanel->marked);
+}
+
+void chmod_cmd (void)
+{
+ char buffer [10];
+ char *fname;
+ int i;
+ struct stat sf_stat;
+
+ if (!vfs_current_is_local ()) {
+ if (vfs_current_is_extfs ()) {
+ message (1, _(" Oops... "),
+ _(" I can't run the Chmod command on an extfs "));
+ return;
+ } else if (vfs_current_is_tarfs ()) {
+ message (1, _(" Oops... "),
+ (" I can't run the Chmod command on a tarfs "));
+ return;
+ }
+ }
+
+ do { /* do while any files remaining */
+ init_chmod ();
+ if (cpanel->marked)
+ fname = next_file (); /* next marked file */
+ else
+ fname = selection (cpanel)->fname; /* single file */
+
+ if (!stat_file (fname, &sf_stat)){ /* get status of file */
+ destroy_dlg (ch_dlg);
+ break;
+ }
+
+ c_stat = sf_stat.st_mode;
+ mode_change = 0; /* clear changes flag */
+
+ /* set check buttons */
+ for (i = 0; i < PERMISSIONS; i++){
+ check_perm[i].check->state = (c_stat & check_perm[i].mode) ? 1 : 0;
+ check_perm[i].selected = 0;
+ }
+
+ tk_new_frame (ch_dlg, "l.");
+ /* Set the labels */
+ c_fname = name_trunc (fname, 21);
+ add_widget (ch_dlg, label_new (FY+2, FX+2, c_fname, NULL));
+ c_fown = name_trunc (get_owner (sf_stat.st_uid), 21);
+ add_widget (ch_dlg, label_new (FY+6, FX+2, c_fown, NULL));
+ c_fgrp = name_trunc (get_group (sf_stat.st_gid), 21);
+ add_widget (ch_dlg, label_new (FY+8, FX+2, c_fgrp, NULL));
+ sprintf (buffer, "%o", c_stat);
+ statl = label_new (FY+4, FX+2, buffer, NULL);
+ add_widget (ch_dlg, statl);
+ tk_end_frame ();
+
+ run_dlg (ch_dlg); /* retrieve an action */
+
+ /* do action */
+ switch (ch_dlg->ret_value){
+ case B_ENTER:
+ if (mode_change)
+ if (mc_chmod (fname, c_stat) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chmod \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ need_update = 1;
+ break;
+
+ case B_CANCEL:
+ end_chmod = 1;
+ break;
+
+ case B_ALL:
+ case B_MARKED:
+ and_mask = or_mask = 0;
+ and_mask = ~and_mask;
+
+ for (i = 0; i < PERMISSIONS; i++) {
+ if (check_perm[i].selected || ch_dlg->ret_value == B_ALL)
+ if (check_perm[i].check->state & C_BOOL)
+ or_mask |= check_perm[i].mode;
+ else
+ and_mask &= ~check_perm[i].mode;
+ }
+
+ apply_mask (&sf_stat);
+ break;
+
+ case B_SETMRK:
+ and_mask = or_mask = 0;
+ and_mask = ~and_mask;
+
+ for (i = 0; i < PERMISSIONS; i++) {
+ if (check_perm[i].selected)
+ or_mask |= check_perm[i].mode;
+ }
+
+ apply_mask (&sf_stat);
+ break;
+ case B_CLRMRK:
+ and_mask = or_mask = 0;
+ and_mask = ~and_mask;
+
+ for (i = 0; i < PERMISSIONS; i++) {
+ if (check_perm[i].selected)
+ and_mask &= ~check_perm[i].mode;
+ }
+
+ apply_mask (&sf_stat);
+ break;
+ }
+
+ if (cpanel->marked && ch_dlg->ret_value!=B_CANCEL) {
+ do_file_mark (cpanel, c_file, 0);
+ need_update = 1;
+ }
+ destroy_dlg (ch_dlg);
+ } while (cpanel->marked && !end_chmod);
+ chmod_done ();
+}
+
+void ch1_cmd (int id)
+{
+ if (advanced_chfns)
+ chown_advanced_cmd ();
+ else
+ chmod_cmd ();
+}
+
+void ch2_cmd (int id)
+{
+ if (advanced_chfns)
+ chown_advanced_cmd ();
+ else
+ chown_cmd ();
+}
+
--- /dev/null
+#ifndef __CHMOD_H
+#define __CHMOD_H
+void chmod_cmd (void);
+int stat_file (char *, struct stat *);
+void ch1_cmd (int id);
+void ch2_cmd (int id);
+
+extern Dlg_head *ch_dlg;
+
+extern umode_t c_stat;
+extern char *c_fname, *c_fown, *c_fgrp, *c_fperm;
+extern int c_fsize;
+
+#endif
--- /dev/null
+/* Chown command -- for the Midnight Commander
+ Copyright (C) 1994 Radek Doulik
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> /* For malloc() */
+#include <errno.h> /* For errno on SunOS systems */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <pwd.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "tty.h"
+#include "mad.h"
+#include "util.h" /* Needed for the externs */
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+
+/* Needed for the extern declarations of integer parameters */
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "chmod.h"
+#include "main.h"
+#include "chown.h"
+#include "wtools.h" /* For init_box_colors */
+#include "../vfs/vfs.h"
+
+#define UX 5
+#define UY 2
+
+#define GX 27
+#define GY 2
+
+#define BX 5
+#define BY 15
+
+#define TX 50
+#define TY 2
+
+#define BUTTONS 5
+
+#define B_SETALL B_USER
+#define B_SETUSR B_USER + 1
+#define B_SETGRP B_USER + 2
+
+/* struct stat *sf_stat; */
+static int need_update, end_chown;
+static int current_file;
+static int single_set;
+static WListbox *l_user, *l_group;
+
+static struct {
+ int ret_cmd, flags, y, x;
+ char *text;
+} chown_but[BUTTONS] = {
+ { B_CANCEL, NORMAL_BUTTON, 0, 54, N_("&Cancel") },
+ { B_ENTER, DEFPUSH_BUTTON, 0, 44, N_("&Set") },
+ { B_SETUSR, NORMAL_BUTTON, 0, 30, N_("Set &users") },
+ { B_SETGRP, NORMAL_BUTTON, 0, 15, N_("Set &groups") },
+ { B_SETALL, NORMAL_BUTTON, 0, 3, N_("Set &all") },
+};
+
+#define LABELS 5
+static struct {
+ int y, x;
+ WLabel *l;
+} chown_label [LABELS] = {
+{ TY+2, TX+2 },
+{ TY+4, TX+2 },
+{ TY+6, TX+2 },
+{ TY+8, TX+2 },
+{ TY+10,TX+2 }
+};
+
+#ifndef HAVE_X
+static void chown_refresh (void)
+{
+ attrset (COLOR_NORMAL);
+ dlg_erase (ch_dlg);
+
+ draw_box (ch_dlg, 1, 2, 16, 70);
+ draw_box (ch_dlg, UY, UX, 12, 21);
+ draw_box (ch_dlg, GY, GX, 12, 21);
+ draw_box (ch_dlg, TY, TX, 12, 19);
+
+ attrset (COLOR_NORMAL);
+ dlg_move (ch_dlg, TY + 1, TX + 1);
+ addstr (N_(" Name "));
+ dlg_move (ch_dlg, TY + 3, TX + 1);
+ addstr (N_(" Owner name "));
+ dlg_move (ch_dlg, TY + 5, TX + 1);
+ addstr (N_(" Group name "));
+ dlg_move (ch_dlg, TY + 7, TX + 1);
+ addstr (N_(" Size "));
+ dlg_move (ch_dlg, TY + 9, TX + 1);
+ addstr (N_(" Permission "));
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (ch_dlg, 1, 28);
+ addstr (N_(" Chown command "));
+ dlg_move (ch_dlg, UY, UX + 1);
+ addstr (N_(" User name "));
+ dlg_move (ch_dlg, GY, GX + 1);
+ addstr (N_(" Group name "));
+ dlg_move (ch_dlg, TY, TX + 1);
+ addstr (N_(" File "));
+}
+#endif
+
+static char *next_file (void)
+{
+ while (!cpanel->dir.list[current_file].f.marked)
+ current_file++;
+
+ return cpanel->dir.list[current_file].fname;
+}
+
+static int chown_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+#ifndef HAVE_X
+ case DLG_DRAW:
+ chown_refresh ();
+ break;
+#endif
+ }
+ return 0;
+}
+
+static int l_call (void *data)
+{
+ return 1;
+}
+
+static void init_chown (void)
+{
+ int i;
+ struct passwd *l_pass;
+ struct group *l_grp;
+
+ do_refresh ();
+ end_chown = need_update = current_file = 0;
+ single_set = (cpanel->marked < 2) ? 3 : 0;
+
+ ch_dlg = create_dlg (0, 0, 18, 74, dialog_colors, chown_callback,
+ "[Chown]", "chown", DLG_CENTER);
+
+#define XTRACT(i) BY+chown_but[i].y, BX+chown_but[i].x, chown_but[i].ret_cmd, chown_but[i].flags, _(chown_but[i].text), 0, 0, NULL
+
+ tk_new_frame (ch_dlg, "b.");
+ for (i = 0; i < BUTTONS-single_set; i++)
+ add_widget (ch_dlg, button_new (XTRACT (i)));
+
+ /* Add the widgets for the file information */
+#define LX(i) chown_label [i].y, chown_label [i].x, "", NULL
+ tk_new_frame (ch_dlg, "l.");
+ for (i = 0; i < LABELS; i++){
+ chown_label [i].l = label_new (LX (i));
+ add_widget (ch_dlg, chown_label [i].l);
+ }
+
+ /* get new listboxes */
+ l_user = listbox_new (UY + 1, UX + 1, 19, 10, 0, l_call, NULL);
+ l_group = listbox_new (GY + 1, GX + 1, 19, 10, 0, l_call, NULL);
+
+ listbox_add_item (l_user, 0, 0, _("<Unknown user>"), NULL); /* add fields for unknown names (numbers) */
+ listbox_add_item (l_group, 0, 0, _("<Unknown group>"), NULL);
+
+ setpwent (); /* get and put user names in the listbox */
+ while ((l_pass = getpwent ())) {
+ listbox_add_item (l_user, 0, 0, l_pass->pw_name, NULL);
+ }
+ endpwent ();
+
+ setgrent (); /* get and put group names in the listbox */
+ while ((l_grp = getgrent ())) {
+ listbox_add_item (l_group, 0, 0, l_grp->gr_name, NULL);
+ }
+ endgrent ();
+
+ tk_new_frame (ch_dlg, "f.");
+ add_widget (ch_dlg, l_group);
+ tk_new_frame (ch_dlg, "g.");
+ add_widget (ch_dlg, l_user); /* add listboxes to the dialogs */
+ tk_end_frame ();
+}
+
+void chown_done (void)
+{
+ if (need_update)
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+static inline void do_chown (uid_t u, gid_t g)
+{
+ if (mc_chown (cpanel->dir.list [current_file].fname, u, g) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chown \"%s\" \n %s "),
+ cpanel->dir.list [current_file].fname, unix_error_string (errno));
+
+ do_file_mark (cpanel, current_file, 0);
+}
+
+static void apply_chowns (uid_t u, gid_t g)
+{
+ char *fname;
+
+ need_update = end_chown = 1;
+ do_chown (u,g);
+
+ do {
+ fname = next_file ();
+
+ do_chown (u,g);
+ } while (cpanel->marked);
+}
+
+#define chown_label(n,txt) label_set_text (chown_label [n].l, txt)
+
+void chown_cmd (void)
+{
+ char *fname;
+ struct stat sf_stat;
+ WLEntry *fe;
+ uid_t new_user;
+ gid_t new_group;
+ char buffer [15];
+
+ if (!vfs_current_is_local ()) {
+ if (vfs_current_is_extfs ()) {
+ message (1, _(" Oops... "),
+ _(" I can't run the Chown command on an extfs "));
+ return;
+ } else if (vfs_current_is_tarfs ()) {
+ message (1, _(" Oops... "),
+ _(" I can't run the Chown command on a tarfs "));
+ return;
+ }
+ }
+
+ do { /* do while any files remaining */
+ init_chown ();
+ new_user = new_group = -1;
+
+ if (cpanel->marked)
+ fname = next_file (); /* next marked file */
+ else
+ fname = selection (cpanel)->fname; /* single file */
+
+ if (!stat_file (fname, &sf_stat)){ /* get status of file */
+ destroy_dlg (ch_dlg);
+ break;
+ }
+
+ /* select in listboxes */
+ fe = listbox_search_text (l_user, get_owner(sf_stat.st_uid));
+ if (fe)
+ listbox_select_entry (l_user, fe);
+
+ fe = listbox_search_text (l_group, get_group(sf_stat.st_gid));
+ if (fe)
+ listbox_select_entry (l_group, fe);
+
+ chown_label (0, name_trunc (fname, 15));
+ chown_label (1, name_trunc (get_owner (sf_stat.st_uid), 15));
+ chown_label (2, name_trunc (get_group (sf_stat.st_gid), 15));
+ sprintf (buffer, "%d", c_fsize);
+ chown_label (3, buffer);
+ chown_label (4, string_perm (sf_stat.st_mode));
+
+ run_dlg (ch_dlg);
+
+ switch (ch_dlg->ret_value) {
+ case B_CANCEL:
+ end_chown = 1;
+ break;
+
+ case B_SETUSR:
+ {
+ struct passwd *user;
+
+ user = getpwnam (l_user->current->text);
+ if (user){
+ new_user = user->pw_uid;
+ apply_chowns (new_user, new_group);
+ }
+ break;
+ }
+ case B_SETGRP:
+ {
+ struct group *grp;
+
+ grp = getgrnam (l_group->current->text);
+ if (grp){
+ new_group = grp->gr_gid;
+ apply_chowns (new_user, new_group);
+ }
+ break;
+ }
+ case B_SETALL:
+ case B_ENTER:
+ {
+ struct group *grp;
+ struct passwd *user;
+
+ grp = getgrnam (l_group->current->text);
+ if (grp)
+ new_group = grp->gr_gid;
+ user = getpwnam (l_user->current->text);
+ if (user)
+ new_user = user->pw_uid;
+ if (ch_dlg->ret_value==B_ENTER) {
+ need_update = 1;
+ if (mc_chown (fname, new_user, new_group) == -1)
+ message (1, MSG_ERROR, _(" Couldn't chown \"%s\" \n %s "),
+ fname, unix_error_string (errno));
+ } else
+ apply_chowns (new_user, new_group);
+ break;
+ }
+ }
+
+ if (cpanel->marked && ch_dlg->ret_value != B_CANCEL){
+ do_file_mark (cpanel, current_file, 0);
+ need_update = 1;
+ }
+ destroy_dlg (ch_dlg);
+ } while (cpanel->marked && !end_chown);
+
+ chown_done ();
+}
--- /dev/null
+#ifndef __CHOWN_H
+#define __CHOWN_H
+
+void chown_cmd (void);
+void chown_advanced_cmd (void);
+
+#endif
--- /dev/null
+/* Routines invoked by a function key
+ They normally operate on the current panel.
+
+ Copyright (C) 1994, 1995 Miguel de Icaza
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#ifdef __os2__
+# define INCL_DOSFILEMGR
+# define INCL_DOSMISC
+# define INCL_DOSERROR
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include "tty.h"
+#include <stdio.h>
+#include <stdlib.h> /* getenv (), rand */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#if defined (__MINGW32__) || defined(_MSC_VER)
+#include <sys/time.h___>
+#else
+#include <time.h>
+#endif
+#include <malloc.h>
+#include <string.h>
+#include <fcntl.h> /* open, O_RDWR */
+#include <errno.h>
+
+#ifdef OS2_NT
+# include <io.h>
+#endif
+
+#ifdef USE_NETCODE
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+#endif
+#include "mad.h"
+#include "dir.h"
+#include "util.h"
+#include "panel.h"
+#include "cmd.h" /* Our definitions */
+#include "view.h" /* view() */
+#include "dialog.h" /* query_dialog, message */
+#include "file.h" /* the file operations */
+#include "find.h" /* do_find */
+#include "hotlist.h"
+#include "tree.h"
+#include "subshell.h" /* use_subshell */
+#include "cons.saver.h"
+#include "global.h"
+#include "dlg.h" /* required by wtools.h */
+#include "widget.h" /* required by wtools.h */
+#include "wtools.h" /* listbox */
+#include "command.h" /* for input_w */
+#include "win.h" /* do_exit_ca_mode */
+#include "layout.h" /* get_current/other_type */
+#include "ext.h" /* regex_command */
+#include "view.h" /* view */
+#include "key.h" /* get_key_code */
+#include "help.h" /* interactive_display */
+#include "fs.h"
+#include "boxes.h" /* cd_dialog */
+#include "color.h"
+#include "user.h"
+#include "setup.h"
+#include "x.h"
+#include "profile.h"
+
+#define MIDNIGHT
+#ifdef USE_INTERNAL_EDIT
+ extern int edit (const char *file, int line);
+#endif
+#include "../vfs/vfs.h"
+#define WANT_WIDGETS
+#include "main.h" /* global variables, global functions */
+#ifndef MAP_FILE
+# define MAP_FILE 0
+#endif
+
+#ifdef HAVE_TK
+# include "tkscreen.h"
+#endif
+
+/* If set and you don't have subshell support,then C-o will give you a shell */
+int output_starts_shell = 0;
+
+/* Source routing destination */
+int source_route = 0;
+
+/* If set, use the builtin editor */
+int use_internal_edit = 1;
+
+/* Ugly hack in order to distinguish between left and right panel in menubar */
+int is_right;
+#define MENU_PANEL_IDX (is_right ? 1 : 0)
+
+
+#ifndef PORT_HAS_FILTER_CHANGED
+# define x_filter_changed(p)
+#endif
+
+/* This is used since the parameter panel on some of the commands */
+/* defined in this file may receive a 0 parameter if they are invoked */
+/* The drop down menu */
+
+WPanel *get_a_panel (WPanel *panel)
+{
+ if (panel)
+ return panel;
+ if (get_current_type () == view_listing){
+ return cpanel;
+ } else
+ return other_panel;
+}
+
+/* view_file (filename, normal, internal)
+ *
+ * Inputs:
+ * filename: The file name to view
+ * plain_view: If set does not do any fancy pre-processing (no filtering) and
+ * always invokes the internal viewer.
+ * internal: If set uses the internal viewer, otherwise an external viewer.
+ */
+int view_file_at_line (char *filename, int plain_view, int internal, int start_line)
+{
+ static char *viewer = 0;
+ int move_dir = 0;
+
+
+ if (plain_view) {
+ int changed_hex_mode = 0;
+ int changed_nroff_flag = 0;
+ int changed_magic_flag = 0;
+
+ altered_hex_mode = 0;
+ altered_nroff_flag = 0;
+ altered_magic_flag = 0;
+ if (default_hex_mode)
+ changed_hex_mode = 1;
+ if (default_nroff_flag)
+ changed_nroff_flag = 1;
+ if (default_magic_flag)
+ changed_magic_flag = 1;
+ default_hex_mode = 0;
+ default_nroff_flag = 0;
+ default_magic_flag = 0;
+ view (0, filename, &move_dir, start_line);
+ if (changed_hex_mode && !altered_hex_mode)
+ default_hex_mode = 1;
+ if (changed_nroff_flag && !altered_nroff_flag)
+ default_nroff_flag = 1;
+ if (changed_magic_flag && !altered_magic_flag)
+ default_magic_flag = 1;
+ repaint_screen ();
+ return move_dir;
+ }
+ if (internal){
+ char view_entry [32];
+
+ if (start_line != 0)
+ sprintf (view_entry, "View:%d", start_line);
+ else
+ strcpy (view_entry, "View");
+
+ if (!regex_command (filename, view_entry, NULL, &move_dir)){
+ view (0, filename, &move_dir, start_line);
+ repaint_screen ();
+ }
+ } else {
+ char *localcopy;
+
+ if (!viewer){
+ viewer = getenv ("PAGER");
+ if (!viewer)
+ viewer = "view";
+ }
+ /* The file may be a non local file, get a copy */
+ if (!vfs_file_is_local (filename)){
+ localcopy = mc_getlocalcopy (filename);
+ if (localcopy == NULL){
+ message (1, MSG_ERROR, _(" Can not fetch a local copy of %s "), filename);
+ return 0;
+ }
+ execute_internal (viewer, localcopy);
+ mc_ungetlocalcopy (filename, localcopy, 0);
+ } else
+ execute_internal (viewer, filename);
+ }
+ return move_dir;
+}
+
+int
+view_file (char *filename, int plain_view, int internal)
+{
+ return view_file_at_line (filename, plain_view, internal, 0);
+}
+
+/* scan_for_file (panel, idx, direction)
+ *
+ * Inputs:
+ * panel: pointer to the panel on which we operate
+ * idx: starting file.
+ * direction: 1, or -1
+ */
+static int scan_for_file (WPanel *panel, int idx, int direction)
+{
+ int i = idx + direction;
+
+ while (i != idx){
+ if (i < 0)
+ i = panel->count - 1;
+ if (i == panel->count)
+ i = 0;
+ if (!S_ISDIR (panel->dir.list [i].buf.st_mode))
+ return i;
+ i += direction;
+ }
+ return i;
+}
+
+/* do_view: Invoked as the F3/F13 key. */
+static void do_view_cmd (WPanel *panel, int normal)
+{
+ int dir, file_idx;
+ panel = get_a_panel (panel);
+
+ /* Directories are viewed by changing to them */
+ if (S_ISDIR (selection (panel)->buf.st_mode) ||
+ link_isdir (selection (panel))){
+ if (confirm_view_dir && (panel->marked || panel->dirs_marked)){
+ if (query_dialog (_(" CD "), _("Files tagged, want to cd?"),
+ 0, 2, _("&Yes"), _("&No")) == 1){
+ return;
+ }
+ }
+ do_cd (selection (panel)->fname, cd_exact);
+ return;
+
+ }
+
+ file_idx = panel->selected;
+ while (1) {
+ char *filename;
+
+ filename = panel->dir.list [file_idx].fname;
+
+ dir = view_file (filename, normal, use_internal_view);
+ if (dir == 0)
+ break;
+ file_idx = scan_for_file (panel, file_idx, dir);
+ }
+}
+
+void view_cmd (WPanel *panel)
+{
+ do_view_cmd (panel, 0);
+}
+
+void view_simple_cmd (WPanel *panel)
+{
+ do_view_cmd (panel, 1);
+}
+
+void filtered_view_cmd (WPanel *panel)
+{
+ char *command;
+
+ panel = get_a_panel (panel);
+ command = input_dialog (_(" Filtered view "), _(" Filter command and arguments:"),
+ selection (panel)->fname);
+ if (!command)
+ return;
+
+ view (command, "", 0, 0);
+
+ free (command);
+}
+
+void filtered_view_cmd_cpanel (void)
+{
+ filtered_view_cmd (cpanel);
+}
+
+void do_edit_at_line (const char *what, int start_line)
+{
+ static char *editor = 0;
+
+#ifdef USE_INTERNAL_EDIT
+ if (use_internal_edit){
+ edit (what, start_line);
+ reread_cmd ();
+ return;
+ }
+#endif
+ if (!editor){
+ editor = getenv ("EDITOR");
+ if (!editor)
+ editor = get_default_editor ();
+ }
+ execute_internal (editor, what);
+ reread_cmd ();
+}
+
+void
+do_edit (const char *what)
+{
+ do_edit_at_line (what, 1);
+}
+
+void edit_cmd (WPanel *panel)
+{
+ panel = get_a_panel(panel);
+ if (!regex_command (selection (panel)->fname, "Edit", NULL, 0))
+ do_edit (selection (panel)->fname);
+}
+
+void edit_cmd_new (WPanel *panel)
+{
+ do_edit ("");
+}
+
+void copy_cmd (void)
+{
+ save_cwds_stat ();
+ if (panel_operate (cpanel, OP_COPY, NULL)){
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+ }
+}
+
+void ren_cmd (void)
+{
+ save_cwds_stat ();
+ if (panel_operate (cpanel, OP_MOVE, NULL)){
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+ }
+}
+
+void copymove_cmd_with_default (int copy, char *thedefault)
+{
+ save_cwds_stat ();
+ if (panel_operate (cpanel, copy ? OP_COPY : OP_MOVE, thedefault)){
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+ }
+}
+
+void mkdir_cmd (WPanel *panel)
+{
+ char *dir;
+
+ panel = get_a_panel (panel);
+ dir = input_expand_dialog (_(" Mkdir "), _(" Enter directory name:") , "");
+
+ if (!dir)
+ return;
+
+ save_cwds_stat ();
+ if (my_mkdir (dir, 0777) == 0){
+ update_panels (UP_OPTIMIZE, dir);
+ repaint_screen ();
+ select_item (cpanel);
+ free (dir);
+ return;
+ }
+ free (dir);
+ message (1, MSG_ERROR, " %s ", unix_error_string (errno));
+}
+
+void delete_cmd (void)
+{
+ save_cwds_stat ();
+
+ if (panel_operate (cpanel, OP_DELETE, NULL)){
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+ }
+}
+
+void find_cmd (void)
+{
+ do_find ();
+}
+
+void
+set_panel_filter_to (WPanel *p, char *allocated_filter_string)
+{
+ if (p->filter){
+ free (p->filter);
+ p->filter = 0;
+ }
+ if (!(allocated_filter_string [0] == '*' && allocated_filter_string [1] == 0))
+ p->filter = allocated_filter_string;
+ else
+ free (allocated_filter_string);
+ reread_cmd ();
+ x_filter_changed (p);
+}
+
+/* Set a given panel filter expression */
+void set_panel_filter (WPanel *p)
+{
+ char *reg_exp;
+ char *x;
+
+ x = p->filter ? p->filter : easy_patterns ? "*" : ".";
+
+ reg_exp = input_dialog (_(" Filter "), _(" Set expression for filtering filenames"), x);
+ if (!reg_exp)
+ return;
+ set_panel_filter_to (p, reg_exp);
+}
+
+/* Invoked from the left/right menus */
+void filter_cmd (void)
+{
+ WPanel *p;
+
+ if (!SELECTED_IS_PANEL)
+ return;
+
+ p = MENU_PANEL;
+ set_panel_filter (p);
+}
+
+void reread_cmd (void)
+{
+ int flag;
+
+ mad_check (__FILE__, __LINE__);
+ if (get_current_type () == view_listing &&
+ get_other_type () == view_listing)
+ flag = strcmp (cpanel->cwd, opanel->cwd) ? UP_ONLY_CURRENT : 0;
+ else
+ flag = UP_ONLY_CURRENT;
+
+ update_panels (UP_RELOAD|flag, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+/* Panel sorting related routines */
+void do_re_sort (WPanel *panel)
+{
+ char *filename;
+ int i;
+
+ panel = get_a_panel (panel);
+ filename = strdup (selection (cpanel)->fname);
+ unselect_item (panel);
+ do_sort (&panel->dir, panel->sort_type, panel->count-1, panel->reverse, panel->case_sensitive);
+ panel->selected = -1;
+ for (i = panel->count; i; i--){
+ if (!strcmp (panel->dir.list [i-1].fname, filename)){
+ panel->selected = i-1;
+ break;
+ }
+ }
+ free (filename);
+ cpanel->top_file = cpanel->selected - ITEMS (cpanel)/2;
+ if (cpanel->top_file < 0)
+ cpanel->top_file = 0;
+ select_item (panel);
+ panel_update_contents (panel);
+}
+
+void reverse_selection_cmd_panel (WPanel *panel)
+{
+ file_entry *file;
+ int i;
+
+ for (i = 0; i < panel->count; i++){
+ file = &panel->dir.list [i];
+ if (S_ISDIR (file->buf.st_mode))
+ continue;
+ do_file_mark (panel, i, !file->f.marked);
+ }
+ paint_panel (panel);
+}
+
+void reverse_selection_cmd (void)
+{
+ reverse_selection_cmd_panel (cpanel);
+}
+
+void select_cmd_panel (WPanel *panel)
+{
+ char *reg_exp, *reg_exp_t;
+ int i;
+ int c;
+ int dirflag = 0;
+
+ reg_exp = input_dialog (_(" Select "), "", easy_patterns ? "*" : ".");
+ if (!reg_exp)
+ return;
+
+ reg_exp_t = reg_exp;
+
+ /* Check if they specified a directory */
+ if (*reg_exp_t == PATH_SEP){
+ dirflag = 1;
+ reg_exp_t++;
+ }
+ if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
+ dirflag = 1;
+ reg_exp_t [strlen(reg_exp_t) - 1] = 0;
+ }
+
+ for (i = 0; i < panel->count; i++){
+ if (!strcmp (panel->dir.list [i].fname, ".."))
+ continue;
+ if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
+ if (!dirflag)
+ continue;
+ } else {
+ if (dirflag)
+ continue;
+ }
+ c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
+ if (c == -1){
+ message (1, MSG_ERROR, _(" Malformed regular expression "));
+ free (reg_exp);
+ return;
+ }
+ if (c){
+ do_file_mark (panel, i, 1);
+ }
+ }
+ paint_panel (panel);
+ free (reg_exp);
+}
+
+void select_cmd (void)
+{
+ select_cmd_panel (cpanel);
+}
+
+void unselect_cmd_panel (WPanel *panel)
+{
+ char *reg_exp, *reg_exp_t;
+ int i;
+ int c;
+ int dirflag = 0;
+
+ reg_exp = input_dialog (_(" Unselect "),"", easy_patterns ? "*" : ".");
+ if (!reg_exp)
+ return;
+
+ reg_exp_t = reg_exp;
+
+ /* Check if they specified directory matching */
+ if (*reg_exp_t == PATH_SEP){
+ dirflag = 1;
+ reg_exp_t ++;
+ }
+ if (reg_exp_t [strlen(reg_exp_t) - 1] == PATH_SEP){
+ dirflag = 1;
+ reg_exp_t [strlen(reg_exp_t) - 1] = 0;
+ }
+ for (i = 0; i < panel->count; i++){
+ if (!strcmp (panel->dir.list [i].fname, ".."))
+ continue;
+ if (S_ISDIR (panel->dir.list [i].buf.st_mode)){
+ if (!dirflag)
+ continue;
+ } else {
+ if (dirflag)
+ continue;
+ }
+ c = regexp_match (reg_exp_t, panel->dir.list [i].fname, match_file);
+ if (c == -1){
+ message (1, MSG_ERROR, _(" Malformed regular expression "));
+ free (reg_exp);
+ return;
+ }
+ if (c){
+ do_file_mark (panel, i, 0);
+ }
+ }
+ paint_panel (panel);
+ free (reg_exp);
+}
+
+void unselect_cmd (void)
+{
+ unselect_cmd_panel (cpanel);
+}
+
+/* Check if the file exists */
+/* If not copy the default */
+static int check_for_default(char *default_file, char *file)
+{
+ struct stat s;
+ if (mc_stat (file, &s)){
+ if (mc_stat (default_file, &s)){
+ return -1;
+ }
+ create_op_win (OP_COPY, 0);
+ file_mask_defaults ();
+ copy_file_file (default_file, file, 1);
+ destroy_op_win ();
+ }
+ return 0;
+}
+
+void ext_cmd (void)
+{
+ char *buffer;
+ char *extdir;
+ int dir;
+
+ dir = 0;
+ if (geteuid () == 0){
+ dir = query_dialog (_("Extension file edit"),
+ _(" Which extension file you want to edit? "), 0, 2,
+ _("&User"), _("&System Wide"));
+ }
+ extdir = concat_dir_and_file (mc_home, MC_LIB_EXT);
+
+ if (dir == 0){
+ buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
+ check_for_default (extdir, buffer);
+ do_edit (buffer);
+ free (buffer);
+ } else if (dir == 1)
+ do_edit (extdir);
+
+ free (extdir);
+ flush_extension_file ();
+}
+
+void menu_edit_cmd (void)
+{
+ char *buffer;
+ char *menufile;
+ int dir = 0;
+
+ dir = query_dialog (
+ _("Menu file edit"),
+ _(" Which menu file will you edit? "),
+ 0, geteuid() ? 2 : 3,
+ _("&Local"), _("&Home"), _("&System Wide")
+ );
+
+ menufile = concat_dir_and_file(mc_home, MC_GLOBAL_MENU);
+
+ switch (dir){
+ case 0:
+ buffer = strdup (MC_LOCAL_MENU);
+ check_for_default (menufile, buffer);
+ break;
+
+ case 1:
+ buffer = concat_dir_and_file (home_dir, MC_HOME_MENU);
+ check_for_default (menufile, buffer);
+ break;
+
+ case 2:
+ buffer = concat_dir_and_file (mc_home, MC_GLOBAL_MENU);
+ break;
+
+ default:
+ free (menufile);
+ return;
+ }
+ do_edit (buffer);
+ if (dir == 0)
+ chmod(buffer, 0600);
+ free (buffer);
+ free (menufile);
+}
+
+void quick_chdir_cmd (void)
+{
+ char *target;
+
+ target = hotlist_cmd (LIST_HOTLIST);
+ if (!target)
+ return;
+
+ if (get_current_type () == view_tree)
+ tree_chdir (the_tree, target);
+ else
+ do_cd (target, cd_exact);
+ free (target);
+}
+
+#ifdef USE_VFS
+void reselect_vfs (void)
+{
+ char *target;
+
+ target = hotlist_cmd (LIST_VFSLIST);
+ if (!target)
+ return;
+
+ do_cd (target, cd_exact);
+ free (target);
+}
+#endif
+
+static int compare_files (char *name1, char *name2, long size)
+{
+ int file1, file2;
+ char *data1, *data2;
+ int result = -1; /* Different by default */
+
+ file1 = open (name1, O_RDONLY);
+ if (file1 >= 0){
+ file2 = open (name2, O_RDONLY);
+ if (file2 >= 0){
+#ifdef HAVE_MMAP
+ /* Ugly if jungle */
+ data1 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file1, 0);
+ if (data1 != (char*) -1){
+ data2 = mmap (0, size, PROT_READ, MAP_FILE | MAP_PRIVATE, file2, 0);
+ if (data2 != (char*) -1){
+ rotate_dash ();
+ result = memcmp (data1, data2, size);
+ munmap (data2, size);
+ }
+ munmap (data1, size);
+ }
+#else
+ /* Don't have mmap() :( Even more ugly :) */
+ char buf1[BUFSIZ], buf2[BUFSIZ];
+ int n1, n2;
+ rotate_dash ();
+ do
+ {
+ while((n1 = read(file1,buf1,BUFSIZ)) == -1 && errno == EINTR);
+ while((n2 = read(file2,buf2,BUFSIZ)) == -1 && errno == EINTR);
+ } while (n1 == n2 && n1 == BUFSIZ && !memcmp(buf1,buf2,BUFSIZ));
+ result = (n1 != n2) || memcmp(buf1,buf2,n1);
+#endif
+ close (file2);
+ }
+ close (file1);
+ }
+ return result;
+}
+
+enum CompareMode {
+ compare_quick, compare_size_only, compare_thourough
+};
+
+static void
+compare_dir (WPanel *panel, WPanel *other, enum CompareMode mode)
+{
+ int i, j;
+ char *src_name, *dst_name;
+
+ panel = get_a_panel (panel);
+
+ /* No marks by default */
+ panel->marked = 0;
+ panel->total = 0;
+ panel->dirs_marked = 0;
+
+ /* Handle all files in the panel */
+ for (i = 0; i < panel->count; i++){
+ file_entry *source = &panel->dir.list[i];
+
+ /* Default: unmarked */
+ file_mark (panel, i, 0);
+
+ /* Skip directories */
+ if (S_ISDIR (source->buf.st_mode))
+ continue;
+
+ /* Search the corresponding entry from the other panel */
+ for (j = 0; j < other->count; j++){
+ if (strcmp (source->fname,
+ other->dir.list[j].fname) == 0)
+ break;
+ }
+ if (j >= other->count)
+ /* Not found -> mark */
+ do_file_mark (panel, i, 1);
+ else {
+ /* Found */
+ file_entry *target = &other->dir.list[j];
+
+ if (mode != compare_size_only){
+ /* Older version is not marked */
+ if (source->buf.st_mtime < target->buf.st_mtime)
+ continue;
+ }
+
+ /* Newer version with different size is marked */
+ if (source->buf.st_size != target->buf.st_size){
+ do_file_mark (panel, i, 1);
+ continue;
+
+ }
+ if (mode == compare_size_only)
+ continue;
+
+ if (mode == compare_quick){
+ /* Thorough compare off, compare only time stamps */
+ /* Mark newer version, don't mark version with the same date */
+ if (source->buf.st_mtime > target->buf.st_mtime){
+ do_file_mark (panel, i, 1);
+ }
+ continue;
+ }
+
+ /* Thorough compare on, do byte-by-byte comparison */
+ src_name = get_full_name (panel->cwd, source->fname);
+ dst_name = get_full_name (other->cwd, target->fname);
+ if (compare_files (src_name, dst_name, source->buf.st_size))
+ do_file_mark (panel, i, 1);
+ free (src_name);
+ free (dst_name);
+ }
+ } /* for (i ...) */
+}
+
+void compare_dirs_cmd (void)
+{
+ enum CompareMode thorough_flag = compare_quick;
+
+ thorough_flag = query_dialog (_(" Compare directories "), _(" Select compare method: "),
+ 0, 3, _("&Quick"), _("&Size only"), _("&Thorough"), _("&Cancel"));
+ if (thorough_flag < 0 || thorough_flag > 2)
+ return;
+ if (get_current_type () == view_listing &&
+ get_other_type () == view_listing){
+ compare_dir (cpanel, opanel, thorough_flag);
+ compare_dir (opanel, cpanel, thorough_flag);
+ paint_panel (cpanel);
+ paint_panel (opanel);
+ } else {
+ message (1, MSG_ERROR, _(" Both panels should be on the listing view mode to use this command "));
+ }
+}
+
+void history_cmd (void)
+{
+ Listbox *listbox;
+ Hist *current;
+
+ if (input_w (cmdline)->need_push){
+ if (push_history (input_w (cmdline), input_w (cmdline)->buffer) == 2)
+ input_w (cmdline)->need_push = 0;
+ }
+ if (!input_w (cmdline)->history){
+ message (1, MSG_ERROR, _(" The command history is empty "));
+ return;
+ }
+ current = input_w (cmdline)->history;
+ while (current->prev)
+ current = current->prev;
+ listbox = create_listbox_window (60, 10, _(" Command history "),
+ "[Command Menu]");
+ while (current){
+ LISTBOX_APPEND_TEXT (listbox, 0, current->text,
+ current);
+ current = current->next;
+ }
+ run_dlg (listbox->dlg);
+ if (listbox->dlg->ret_value == B_CANCEL)
+ current = NULL;
+ else
+ current = listbox->list->current->data;
+ destroy_dlg (listbox->dlg);
+ free (listbox);
+
+ if (!current)
+ return;
+ input_w (cmdline)->history = current;
+ assign_text (input_w (cmdline), input_w (cmdline)->history->text);
+ update_input (input_w (cmdline), 1);
+}
+
+#if !defined(HAVE_XVIEW) && !defined(HAVE_GNOME)
+void swap_cmd (void)
+{
+ swap_panels ();
+ touchwin (stdscr);
+ repaint_screen ();
+}
+#endif
+
+void
+view_other_cmd (void)
+{
+ static int message_flag = TRUE;
+#ifdef HAVE_SUBSHELL_SUPPORT
+ char *new_dir = NULL;
+ char **new_dir_p;
+#endif
+
+ if (!xterm_flag && !console_flag && !use_subshell){
+ if (message_flag)
+ message (1, MSG_ERROR, _(" Not an xterm or Linux console; \n"
+ " the panels cannot be toggled. "));
+ message_flag = FALSE;
+ } else {
+#ifndef HAVE_X
+ if (use_mouse_p)
+ shut_mouse ();
+ if (clear_before_exec)
+ clr_scr ();
+ if (alternate_plus_minus)
+ numeric_keypad_mode ();
+#endif
+#ifndef HAVE_SLANG
+ /* With slang we don't want any of this, since there
+ * is no mc_raw_mode supported
+ */
+ reset_shell_mode ();
+ noecho ();
+#endif
+ keypad(stdscr, FALSE);
+ endwin ();
+ if (!status_using_ncurses)
+ do_exit_ca_mode ();
+ mc_raw_mode ();
+ if (console_flag)
+ restore_console ();
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell){
+ new_dir_p = vfs_current_is_local () ? &new_dir : NULL;
+ if (invoke_subshell (NULL, VISIBLY, new_dir_p))
+ quiet_quit_cmd(); /* User did `exit' or `logout': quit MC quietly */
+ } else
+#endif
+ {
+ if (output_starts_shell){
+ fprintf (stderr,
+ _("Type `exit' to return to the Midnight Commander\n\r\n\r"));
+ my_system (EXECUTE_AS_SHELL, shell, NULL);
+ } else
+ get_key_code (0);
+ }
+ if (console_flag)
+ handle_console (CONSOLE_SAVE);
+
+ if (!status_using_ncurses)
+ do_enter_ca_mode ();
+
+ reset_prog_mode ();
+ keypad(stdscr, TRUE);
+#ifndef HAVE_X
+ if (use_mouse_p)
+ init_mouse ();
+ if (alternate_plus_minus)
+ application_keypad_mode ();
+#endif
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell){
+ load_prompt (0, 0);
+ if (new_dir)
+ do_possible_cd (new_dir);
+ if (console_flag && output_lines)
+ show_console_contents (output_start_y,
+ LINES-keybar_visible-output_lines-1,
+ LINES-keybar_visible-1);
+ }
+#endif
+ touchwin (stdscr);
+
+ /* prevent screen flash when user did 'exit' or 'logout' within
+ subshell */
+ if (!quit)
+ repaint_screen ();
+ }
+}
+
+#ifndef OS2_NT
+static void
+do_link (int symbolic_link, char *fname)
+{
+ struct stat s;
+ char *dest, *src;
+ int stat_r;
+
+ if (!symbolic_link){
+ stat_r = mc_stat (fname, &s);
+ if (stat_r != 0){
+ message (1, MSG_ERROR, _(" Couldn't stat %s \n %s "),
+ fname, unix_error_string (errno));
+ return;
+ }
+ if (!S_ISREG (s.st_mode))
+ return;
+ }
+
+ if (!symbolic_link){
+ src = copy_strings (_(" Link "), name_trunc (fname, 46),
+ _(" to:"), NULL);
+ dest = input_expand_dialog (_(" Link "), src, "");
+ free (src);
+ if (!dest)
+ return;
+ if (!*dest) {
+ free (dest);
+ return;
+ }
+ save_cwds_stat ();
+ if (-1 == mc_link (fname, dest))
+ message (1, MSG_ERROR, _(" link: %s "), unix_error_string (errno));
+ } else {
+#ifdef OLD_SYMLINK_VERSION
+ symlink_dialog (fname, "", &dest, &src);
+#else
+ /* suggest the full path for symlink */
+ char s[MC_MAXPATHLEN];
+ char d[MC_MAXPATHLEN];
+
+ strcpy(s, cpanel->cwd);
+ if ( ! ((s[0] == '/') && (s[1] == 0)))
+ strcat(s, "/");
+ strcat(s, fname);
+ if (get_other_type () == view_listing)
+ strcpy(d, opanel->cwd);
+ else
+ strcpy (d,"");
+
+ if ( ! ((d[0] == '/') && (d[1] == 0)))
+ strcat(d, "/");
+ symlink_dialog (s, d, &dest, &src);
+#endif
+ if (!dest || !*dest) {
+ if (src)
+ free (src);
+ if (dest)
+ free (dest);
+ return;
+ }
+ if (src){
+ if (*src) {
+ save_cwds_stat ();
+ if (-1 == mc_symlink (dest, src))
+ message (1, MSG_ERROR, _(" symlink: %s "),
+ unix_error_string (errno));
+ }
+ free (src);
+ }
+ }
+ free (dest);
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+void link_cmd (void)
+{
+ do_link (0, selection (cpanel)->fname);
+}
+
+void symlink_cmd (void)
+{
+ do_link (1, selection (cpanel)->fname);
+}
+
+void edit_symlink_cmd (void)
+{
+ if (S_ISLNK (selection (cpanel)->buf.st_mode)) {
+ char buffer [MC_MAXPATHLEN], *p = selection (cpanel)->fname;
+ int i;
+ char *dest, *q = copy_strings (_(" Symlink "), name_trunc (p, 32), _(" points to:"), NULL);
+
+ i = readlink (p, buffer, MC_MAXPATHLEN);
+ if (i > 0) {
+ buffer [i] = 0;
+ dest = input_expand_dialog (_(" Edit symlink "), q, buffer);
+ if (dest) {
+ if (*dest && strcmp (buffer, dest)) {
+ save_cwds_stat ();
+ mc_unlink (p);
+ if (-1 == mc_symlink (dest, p))
+ message (1, MSG_ERROR, _(" edit symlink: %s "),
+ unix_error_string (errno));
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+ }
+ free (dest);
+ }
+ }
+ free (q);
+ }
+}
+
+void other_symlink_cmd (void)
+{
+ char *dest, *q, *p, *r, *s, *t;
+
+ if (get_other_type () != view_listing)
+ return;
+
+ if (!strcmp (selection (opanel)->fname, ".."))
+ return;
+ p = concat_dir_and_file (cpanel->cwd, selection (cpanel)->fname);
+ r = concat_dir_and_file (opanel->cwd, selection (cpanel)->fname);
+
+ q = copy_strings (_(" Link symbolically "), name_trunc (p, 32), _(" to:"), NULL);
+ dest = input_expand_dialog (_(" Relative symlink "), q, r);
+ if (dest) {
+ if (*dest) {
+ t = strrchr (dest, PATH_SEP);
+ if (t) {
+ t[1] = 0;
+ s = diff_two_paths (dest, p);
+ t[1] = PATH_SEP;
+ if (s) {
+ save_cwds_stat ();
+ if (-1 == mc_symlink (dest, s))
+ message (1, MSG_ERROR, _(" relative symlink: %s "),
+ unix_error_string (errno));
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+ free (s);
+ }
+ }
+ }
+ free (dest);
+ }
+ free (q);
+ free (p);
+ free (r);
+}
+#endif
+
+void help_cmd (void)
+{
+ char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
+ interactive_display (hlpfile, "[main]");
+ free (hlpfile);
+}
+
+void view_panel_cmd (void)
+{
+ view_cmd (cpanel);
+}
+
+void edit_panel_cmd (void)
+{
+ edit_cmd (cpanel);
+}
+
+void mkdir_panel_cmd (void)
+{
+ mkdir_cmd (cpanel);
+}
+
+/* Returns a random hint */
+char *get_random_hint (void)
+{
+ char *data, *result, *eol;
+ char *hintfile;
+ int len;
+ int start;
+
+ /* Do not change hints more often than one minute */
+
+#ifdef SCO_FLAVOR
+ static time_t last;
+ time_t now;
+
+ time (&now);
+ if ((now - last) < 60)
+ return strdup ("");
+ last = now;
+#else
+ static int last_sec;
+ static struct timeval tv;
+
+ gettimeofday (&tv, NULL);
+ if (!(tv.tv_sec> last_sec+60))
+ return strdup ("");
+ last_sec = tv.tv_sec;
+#endif
+
+ hintfile = concat_dir_and_file (mc_home, MC_HINT);
+ data = load_file (hintfile);
+ free (hintfile);
+ if (!data)
+ return 0;
+
+#ifdef SCO_FLAVOR
+ srand ((short) now);
+#else
+ srand (tv.tv_sec);
+#endif
+ /* get a random entry */
+ len = strlen (data);
+ start = rand () % len;
+
+ for (;start; start--){
+ if (data [start] == '\n'){
+ start++;
+ break;
+ }
+ }
+ eol = strchr (&data [start], '\n');
+ if (eol)
+ *eol = 0;
+ result = strdup (&data [start]);
+ free (data);
+ return result;
+}
+
+#ifndef USE_VFS
+#ifdef USE_NETCODE
+#undef USE_NETCODE
+#endif
+#endif
+
+#ifdef USE_NETCODE
+
+static char *machine_str = N_(" Enter machine name (F1 for details): ");
+
+static void nice_cd (char *text, char *xtext, char *help, char *prefix, int to_home)
+{
+ char *machine;
+ char *cd_path;
+
+ if (!SELECTED_IS_PANEL)
+ return;
+
+ machine = input_dialog_help (text,
+ xtext,
+ help, "");
+ if (!machine)
+ return;
+
+ if (strncmp (prefix, machine, strlen (prefix)) == 0)
+ cd_path = copy_strings (machine, to_home ? "/~/" : NULL, NULL);
+ else
+ cd_path = copy_strings (prefix, machine, to_home ? "/~/" : NULL, NULL);
+
+ if (do_panel_cd (MENU_PANEL, cd_path, 0))
+ directory_history_add (MENU_PANEL, (MENU_PANEL)->cwd);
+ else
+ message (1, MSG_ERROR, N_(" Could not chdir to %s "), cd_path);
+ free (cd_path);
+ free (machine);
+}
+
+void netlink_cmd (void)
+{
+ nice_cd (_(" Link to a remote machine "), _(machine_str),
+ "[Network File System]", "mc:", 1);
+}
+
+void ftplink_cmd (void)
+{
+ nice_cd (_(" FTP to machine "), _(machine_str),
+ "[FTP File System]", "ftp://", 1);
+}
+
+#ifdef HAVE_SETSOCKOPT
+void source_routing (void)
+{
+ char *source;
+ struct hostent *hp;
+
+ source = input_dialog (_(" Socket source routing setup "),
+ _(" Enter host name to use as a source routing hop: ")n,
+ "");
+ if (!source)
+ return;
+
+ hp = gethostbyname (source);
+ if (!hp){
+ message (1, _(" Host name "), _(" Error while looking up IP address "));
+ return;
+ }
+ source_route = *((int *)hp->h_addr);
+}
+#endif /* HAVE_SETSOCKOPT */
+#endif /* USE_NETCODE */
+
+#ifdef USE_EXT2FSLIB
+void undelete_cmd (void)
+{
+ nice_cd (_(" Undelete files on an ext2 file system "),
+ _(" Enter the file system name where you want to run the\n "
+ " undelete file system on: (F1 for details)"),
+ "[Undelete File System]", "undel:", 0);
+}
+#endif
+
+void quick_cd_cmd (void)
+{
+ char *p = cd_dialog ();
+
+ if (p && *p) {
+ char *q = copy_strings ("cd ", p, NULL);
+
+ do_cd_command (q);
+ free (q);
+ }
+ if (p)
+ free (p);
+}
+
+#ifdef SCO_FLAVOR
+#undef DUSUM_USEB
+#undef DUSUM_FACTOR
+#endif /* SCO_FLAVOR */
+
+#ifdef HAVE_DUSUM
+void dirsizes_cmd (void)
+{
+ WPanel *panel = cpanel;
+ int i, j = 0;
+ char *cmd, *p, *q, *r;
+ FILE *f;
+#ifdef DUSUM_USEB
+# define dirsizes_command "du -s -b "
+#else
+# define dirsizes_command "du -s "
+#endif
+#ifndef DUSUM_FACTOR
+# define DUSUM_FACTOR 512
+#endif
+
+ if (!vfs_current_is_local ())
+ return;
+ for (i = 0; i < panel->count; i++)
+ if (S_ISDIR (panel->dir.list [i].buf.st_mode))
+ j += strlen (panel->dir.list [i].fname) + 1;
+ if (!j)
+ return;
+ cmd = xmalloc (strlen (dirsizes_command) + j + 1, "dirsizes_cmd");
+ strcpy (cmd, dirsizes_command);
+ p = strchr (cmd, 0);
+ for (i = 0; i < panel->count; i++)
+ if (S_ISDIR (panel->dir.list [i].buf.st_mode) &&
+ strcmp (panel->dir.list [i].fname, "..")) {
+ strcpy (p, panel->dir.list [i].fname);
+ p = strchr (p, 0);
+ *(p++) = ' ';
+ }
+ *(--p) = 0;
+ open_error_pipe ();
+ f = popen (cmd, "r");
+ free (cmd);
+ if (f != NULL) {
+ /* Assume that du will display the directories in the order
+ * I've passed to it :(
+ */
+ i = 0;
+ p = xmalloc (1024, "dirsizes_cmd");
+ while (fgets (p, 1024, f)) {
+ j = atoi (p) * DUSUM_FACTOR;
+ for (q = p; *q && *q != ' ' && *q != '\t'; q++);
+ while (*q == ' ' || *q == '\t')
+ q++;
+ r = strchr (q, '\n');
+ if (r == NULL)
+ r = strchr (q, 0);
+ for (; i < panel->count; i++)
+ if (S_ISDIR (panel->dir.list [i].buf.st_mode))
+ if (!strncmp (q, panel->dir.list [i].fname,
+ r - q)) {
+ if (panel->dir.list [i].f.marked)
+ panel->total += j -
+ ((panel->has_dir_sizes) ? panel->dir.list [i].buf.st_size : 0);
+ panel->dir.list [i].buf.st_size = j;
+ break;
+ }
+ if (i == panel->count)
+ break;
+ }
+ free (p);
+ if (pclose (f) < 0)
+#ifndef SCO_FLAVOR
+ message (0, _("Show directory sizes"), _("Pipe close failed"));
+ else
+#else /* SCO_FLAVOR */
+ /*
+ ** SCO reports about error while all seems to be ok. Just ignore it...
+ ** (alex@bcs.zaporizhzhe.ua)
+ */
+ ;
+#endif /* SCO_FLAVOR */
+ panel->has_dir_sizes = 1;
+ close_error_pipe (0, 0);
+ paint_panel (panel);
+ } else
+ close_error_pipe (1, _("Cannot invoke du command."));
+}
+#endif
+
+void
+save_setup_cmd (void)
+{
+ char *str;
+
+ save_setup ();
+ sync_profiles ();
+ str = copy_strings ( _(" Setup saved to ~/"), PROFILE_NAME, NULL);
+
+#ifdef HAVE_GNOME
+ set_hintbar (str);
+#else
+ message (0, _(" Setup "), str);
+#endif
+ free (str);
+}
+
+void
+configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status)
+{
+ int err;
+
+ p->user_mini_status = use_msformat;
+ p->list_type = view_type;
+
+ if (view_type == list_user || use_msformat){
+ free (p->user_format);
+ p->user_format = user;
+
+ free (p->user_status_format [view_type]);
+ p->user_status_format [view_type] = status;
+
+ err = set_panel_formats (p);
+
+ if (err){
+ if (err & 0x01){
+ free (p->user_format);
+ p->user_format = strdup (DEFAULT_USER_FORMAT);
+ }
+
+ if (err & 0x02){
+ free (p->user_status_format [view_type]);
+ p->user_status_format [view_type] = strdup (DEFAULT_USER_FORMAT);
+ }
+ }
+ }
+ else {
+ free (user);
+ free (status);
+ }
+
+ set_panel_formats (p);
+ paint_panel (p);
+
+ do_refresh ();
+}
+
+#ifndef HAVE_GNOME
+void
+info_cmd_no_menu (void)
+{
+ set_display_type (cpanel == left_panel ? 1 : 0, view_info);
+}
+
+void
+quick_cmd_no_menu (void)
+{
+ set_display_type (cpanel == left_panel ? 1 : 0, view_quick);
+}
+
+void
+switch_to_listing (int panel_index)
+{
+ if (get_display_type (panel_index) != view_listing)
+ set_display_type (panel_index, view_listing);
+}
+
+void
+listing_cmd (void)
+{
+ int view_type, use_msformat;
+ char *user, *status;
+ WPanel *p;
+ int display_type;
+
+ display_type = get_display_type (MENU_PANEL_IDX);
+ if (display_type == view_listing)
+ p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
+ else
+ p = 0;
+
+ view_type = display_box (p, &user, &status, &use_msformat, MENU_PANEL_IDX);
+
+ if (view_type == -1)
+ return;
+
+ switch_to_listing (MENU_PANEL_IDX);
+
+ p = MENU_PANEL_IDX == 0 ? left_panel : right_panel;
+
+ configure_panel_listing (p, view_type, use_msformat, user, status);
+}
+
+void
+tree_cmd (void)
+{
+ set_display_type (MENU_PANEL_IDX, view_tree);
+}
+
+void
+info_cmd (void)
+{
+ set_display_type (MENU_PANEL_IDX, view_info);
+}
+
+void
+quick_view_cmd (void)
+{
+ set_display_type (MENU_PANEL_IDX, view_quick);
+}
+#endif
+
+/* Handle the tree internal listing modes switching */
+static int
+set_basic_panel_listing_to (int panel_index, int listing_mode)
+{
+ WPanel *p = (WPanel *) get_panel_widget (panel_index);
+
+#ifndef HAVE_GNOME
+ switch_to_listing (panel_index);
+#endif
+ p->list_type = listing_mode;
+ if (set_panel_formats (p))
+ return 0;
+
+ paint_panel (p);
+ do_refresh ();
+ return 1;
+}
+
+void
+toggle_listing_cmd (void)
+{
+ int current = get_current_index ();
+ WPanel *p = (WPanel *) get_panel_widget (current);
+ int list_mode = p->list_type;
+ int m;
+
+ switch (list_mode){
+ case list_full:
+ case list_brief:
+ m = list_long;
+ break;
+ case list_long:
+ m = list_user;
+ break;
+ default:
+ m = list_full;
+ }
+ if (set_basic_panel_listing_to (current, m))
+ return;
+ set_basic_panel_listing_to (current, list_full);
+}
+
--- /dev/null
+#ifndef __CMD_H
+#define __CMD_H
+void netlink_cmd (void);
+void ftplink_cmd (void);
+void undelete_cmd (void);
+void help_cmd (void);
+void dirsizes_cmd (void);
+int view_file_at_line (char *filename, int plain_view, int internal,
+ int start_line);
+int view_file (char *filename, int normal, int internal);
+void view_cmd (WPanel *panel);
+void view_simple_cmd (WPanel *panel);
+void filtered_view_cmd (WPanel *panel);
+void filtered_view_cmd_cpanel (void);
+void do_edit (const char *what);
+void do_edit_at_line (const char *what, int start_line);
+void edit_cmd (WPanel *panel);
+void edit_cmd_new (WPanel *panel);
+void copy_cmd (void);
+void ren_cmd (void);
+void reselect_vfs (void);
+void copymove_cmd_with_default (int copy, char *thedefault);
+void mkdir_cmd (WPanel *panel);
+void delete_cmd (void);
+void find_cmd (void);
+void tree_mode_cmd (void);
+void filter_cmd (void);
+void set_panel_filter (WPanel *panel);
+void set_panel_filter_to (WPanel *p, char *allocated_filter_string);
+void reread_cmd (void);
+void do_re_sort (WPanel *panel);
+void quick_view_cmd (void);
+void tree_view_cmd (void);
+void ext_cmd (void);
+void menu_edit_cmd (void);
+void quick_chdir_cmd (void);
+void compare_dirs_cmd (void);
+void history_cmd (void);
+void tree_cmd (void);
+void link_cmd (void);
+void symlink_cmd (void);
+void edit_symlink_cmd (void);
+void other_symlink_cmd (void);
+void reverse_selection_cmd_panel (WPanel *);
+void unselect_cmd_panel (WPanel *);
+void select_cmd_panel (WPanel *);
+void reverse_selection_cmd (void);
+void unselect_cmd (void);
+void select_cmd (void);
+void swap_cmd (void);
+void view_other_cmd (void);
+void mkdir_panel_cmd (void);
+void edit_panel_cmd (void);
+void view_panel_cmd (void);
+void quick_cd_cmd (void);
+void save_setup_cmd (void);
+char *get_random_hint (void);
+void source_routing (void);
+
+/* Display mode code */
+void info_cmd (void);
+void tree_cmd (void);
+void listing_cmd (void);
+void sort_cmd (void);
+void switch_to_listing (int panel_index);
+void quick_cmd_no_menu (void);
+void info_cmd_no_menu (void);
+void quick_view_cmd (void);
+void toggle_listing_cmd (void);
+void configure_panel_listing (WPanel *p, int view_type, int use_msformat, char *user, char *status);
+#endif /* __CMD_H */
--- /dev/null
+/* Color setup
+ Copyright (C) 1994 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "mad.h"
+#include "setup.h" /* For the externs */
+#include "color.h"
+#include "x.h"
+
+/* "$Id: color.c,v 1.1 2001/12/30 09:55:26 sedwards Exp $" */
+
+/* To avoid excessive calls to ncurses' has_colors () */
+int hascolors = 0;
+
+/* Set to force black and white display at program startup */
+int disable_colors = 0;
+
+/* Set if we are actually using colors */
+int use_colors = 0;
+
+int dialog_colors [4];
+
+#define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
+
+
+
+#ifdef HAVE_GNOME
+# define CTYPE GdkColor *
+void init_pair (int, CTYPE, CTYPE);
+#else
+# ifdef HAVE_SLANG
+# define CTYPE char *
+# else
+# define CTYPE int
+# define color_map_fg(n) (color_map[n].fg % COLORS)
+# define color_map_bg(n) (color_map[n].bg % COLORS)
+# endif
+#endif
+
+struct colorpair {
+ char *name; /* Name of the entry */
+ CTYPE fg; /* foreground color */
+ CTYPE bg; /* background color */
+};
+
+#ifndef color_map_fg
+# define color_map_fg(n) color_map[n].fg
+# define color_map_bg(n) color_map[n].bg
+#endif
+
+struct colorpair color_map [] = {
+ { "normal=", 0, 0 }, /* normal */
+ { "selected=", 0, 0 }, /* selected */
+ { "marked=", 0, 0 }, /* marked */
+ { "markselect=", 0, 0 }, /* marked/selected */
+ { "errors=", 0, 0 }, /* errors */
+ { "menu=", 0, 0 }, /* menu entry */
+ { "reverse=", 0, 0 }, /* reverse */
+
+ /* Dialog colors */
+ { "dnormal=", 0, 0 }, /* Dialog normal */
+ { "dfocus=", 0, 0 }, /* Dialog focused */
+ { "dhotnormal=", 0, 0 }, /* Dialog normal/hot */
+ { "dhotfocus=", 0, 0 }, /* Dialog focused/hot */
+
+ { "viewunderline=", 0, 0 }, /* _\b? sequence in view */
+ { "menusel=", 0, 0 }, /* Menu selected color */
+ { "menuhot=", 0, 0 }, /* Color for menu hotkeys */
+ { "menuhotsel=", 0, 0 }, /* Menu hotkeys/selected entry */
+
+ { "helpnormal=", 0, 0 }, /* Help normal */
+ { "helpitalic=", 0, 0 }, /* Italic in help */
+ { "helpbold=", 0, 0 }, /* Bold in help */
+ { "helplink=", 0, 0 }, /* Not selected hyperlink */
+ { "helpslink=", 0, 0 }, /* Selected hyperlink */
+
+ { "gauge=", 0, 0 }, /* Color of the progress bar (percentage) */
+ { "input=", 0, 0 },
+
+ /* Per file types colors */
+ { "directory=", 0, 0 },
+ { "execute=", 0, 0 },
+ { "link=", 0, 0 },
+ { "device=", 0, 0 },
+ { "special=", 0, 0 },
+ { "core=", 0, 0 },
+};
+
+struct color_table_s {
+ char *name;
+ int value;
+};
+
+
+struct color_table_s color_table [] = {
+ { "black", COLOR_BLACK },
+ { "gray", COLOR_BLACK | A_BOLD },
+ { "red", COLOR_RED },
+ { "brightred", COLOR_RED | A_BOLD },
+ { "green", COLOR_GREEN },
+ { "brightgreen", COLOR_GREEN | A_BOLD },
+ { "brown", COLOR_YELLOW },
+ { "yellow", COLOR_YELLOW | A_BOLD },
+ { "blue", COLOR_BLUE },
+ { "brightblue", COLOR_BLUE | A_BOLD },
+ { "magenta", COLOR_MAGENTA },
+ { "brightmagenta", COLOR_MAGENTA | A_BOLD },
+ { "cyan", COLOR_CYAN },
+ { "brightcyan", COLOR_CYAN | A_BOLD },
+ { "lightgray", COLOR_WHITE },
+ { "white", COLOR_WHITE | A_BOLD }
+};
+
+#ifdef HAVE_GNOME
+void get_color (char *cpp, CTYPE *colp);
+#else
+# ifdef HAVE_SLANG
+# define color_value(i) color_table [i].name
+# define color_name(i) color_table [i].name
+# else
+# define color_value(i) color_table [i].value
+# define color_name(i) color_table [i].name
+# endif
+
+static void get_color (char *cpp, CTYPE *colp)
+{
+ int i;
+
+ for (i = 0; i < ELEMENTS(color_table); i++){
+ if (strcmp (cpp, color_name (i)) == 0){
+ *colp = color_value (i);
+ return;
+ }
+ }
+}
+#endif /* HAVE_GNOME */
+
+static void get_two_colors (char **cpp, struct colorpair *colorpairp)
+{
+ char *p = *cpp;
+ int state;
+
+ state = 0;
+
+ for (; *p; p++){
+ if (*p == ':'){
+ *p = 0;
+ get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
+ *p = ':';
+ *cpp = p + 1;
+ return;
+ }
+
+ if (*p == ','){
+ state = 1;
+ *p = 0;
+ get_color (*cpp, &colorpairp->fg);
+ *p = ',';
+ *cpp = p + 1;
+ }
+ }
+ get_color (*cpp, state ? &colorpairp->bg : &colorpairp->fg);
+}
+
+void configure_colors_string (char *the_color_string)
+{
+ char *color_string, *p;
+ int i, found;
+
+ if (!the_color_string)
+ return;
+
+ p = color_string = strdup (the_color_string);
+ while (color_string && *color_string){
+ while (*color_string == ' ' || *color_string == '\t')
+ color_string++;
+
+ found = 0;
+ for (i = 0; i < ELEMENTS(color_map); i++){
+ int klen = strlen (color_map [i].name);
+
+ if (strncmp (color_string, color_map [i].name, klen) == 0){
+ color_string += klen;
+ get_two_colors (&color_string, &color_map [i]);
+ found = 1;
+ }
+ }
+ if (!found){
+ while (*color_string && *color_string != ':')
+ color_string++;
+ if (*color_string)
+ color_string++;
+ }
+ }
+ free (p);
+}
+
+static void configure_colors (void)
+{
+ extern char *command_line_colors;
+#ifndef HAVE_TK
+#ifndef HAVE_XVIEW
+ extern char *default_edition_colors;
+
+ configure_colors_string (default_edition_colors);
+#endif
+#endif
+ configure_colors_string (setup_color_string);
+ configure_colors_string (term_color_string);
+ configure_colors_string (getenv ("MC_COLOR_TABLE"));
+ configure_colors_string (command_line_colors);
+}
+
+#ifndef HAVE_SLANG
+#define MAX_PAIRS 30
+int attr_pairs [MAX_PAIRS];
+#endif
+
+static void
+load_dialog_colors (void)
+{
+ dialog_colors [0] = COLOR_NORMAL;
+ dialog_colors [1] = COLOR_FOCUS;
+ dialog_colors [2] = COLOR_HOT_NORMAL;
+ dialog_colors [3] = COLOR_HOT_FOCUS;
+}
+
+#ifdef HAVE_X
+void
+init_colors (void)
+{
+ int i;
+
+ use_colors = 1;
+ start_color ();
+ configure_colors ();
+ for (i = 0; i < ELEMENTS (color_map); i++)
+ init_pair (i+1, color_map_fg(i), color_map_bg(i));
+ load_dialog_colors ();
+}
+#else
+void init_colors (void)
+{
+ int i;
+
+ hascolors = has_colors ();
+
+ if (!disable_colors && hascolors){
+ use_colors = 1;
+ }
+
+ if (use_colors){
+ start_color ();
+ configure_colors ();
+
+#ifndef HAVE_SLANG
+ if (ELEMENTS (color_map) > MAX_PAIRS){
+ /* This message should only be seen by the developers */
+ fprintf (stderr,
+ "Too many defined colors, resize MAX_PAIRS on color.c");
+ exit (1);
+ }
+#endif
+
+#if defined HAVE_SLANG && !defined(OS2_NT)
+ if (use_colors) { /* Hack to make COLOR_PAIR(31) be the default fg/bg
+ of the terminal */
+ char *Norm_Vid = SLtt_tgetstr ("me");
+
+ if (Norm_Vid == NULL)
+ Norm_Vid = SLtt_tgetstr ("se");
+ if (Norm_Vid == NULL)
+ Norm_Vid = "\033[0m";
+ SLtt_set_color_esc (31, Norm_Vid);
+ }
+#endif
+
+ for (i = 0; i < ELEMENTS (color_map); i++){
+ init_pair (i+1, color_map_fg(i), color_map_bg(i));
+
+#ifndef HAVE_SLANG
+ /*
+ * As a convenience, for the SVr4 curses configuration, we have
+ * OR'd the A_BOLD attribute to the color number. We'll need that
+ * later, to set the attribute with the colors.
+ */
+ attr_pairs [i+1] = color_map [i].fg & A_BOLD;
+#endif
+ }
+ }
+ load_dialog_colors ();
+}
+#endif
+
+void toggle_color_mode (void)
+{
+ if (hascolors)
+ use_colors = !use_colors;
+}
+
--- /dev/null
+#ifndef __COLOR_H
+#define __COLOR_H
+
+void init_colors (void);
+void toggle_color_mode (void);
+void configure_colors_string (char *color_string);
+
+extern int hascolors;
+extern int use_colors;
+extern int disable_colors;
+
+extern int attr_pairs [];
+#ifdef HAVE_GNOME
+# define MY_COLOR_PAIR(x) x
+# define PORT_COLOR(co,bw) co
+#else
+# ifdef HAVE_SLANG
+# define MY_COLOR_PAIR(x) COLOR_PAIR(x)
+# else
+# define MY_COLOR_PAIR(x) (COLOR_PAIR(x) | attr_pairs [x])
+# endif
+#define PORT_COLOR(co,bw) (use_colors?co:bw)
+#endif
+
+#define NORMAL_COLOR (PORT_COLOR (MY_COLOR_PAIR (1), 0))
+#define SELECTED_COLOR (PORT_COLOR (MY_COLOR_PAIR (2),A_REVERSE))
+#define MARKED_COLOR (PORT_COLOR (MY_COLOR_PAIR (3),A_BOLD))
+#ifdef HAVE_SLANG
+#define MARKED_SELECTED_COLOR (PORT_COLOR (MY_COLOR_PAIR (4),(SLtt_Use_Ansi_Colors ? A_BOLD_REVERSE : A_REVERSE | A_BOLD)))
+#else
+#define MARKED_SELECTED_COLOR (PORT_COLOR (MY_COLOR_PAIR (4),A_REVERSE | A_BOLD))
+#endif
+#define ERROR_COLOR (PORT_COLOR (MY_COLOR_PAIR (5),0))
+#define MENU_ENTRY_COLOR (PORT_COLOR (MY_COLOR_PAIR (6),A_REVERSE))
+#define REVERSE_COLOR (PORT_COLOR (MY_COLOR_PAIR(7),A_REVERSE))
+#define Q_SELECTED_COLOR (PORT_COLOR (SELECTED_COLOR, 0))
+#define Q_UNSELECTED_COLOR REVERSE_COLOR
+#define VIEW_UNDERLINED_COLOR (PORT_COLOR (MY_COLOR_PAIR(12),A_UNDERLINE))
+#define MENU_SELECTED_COLOR (PORT_COLOR (MY_COLOR_PAIR(13),A_BOLD))
+#define MENU_HOT_COLOR (PORT_COLOR (MY_COLOR_PAIR(14),0))
+#define MENU_HOTSEL_COLOR (PORT_COLOR (MY_COLOR_PAIR(15),0))
+
+/*
+ * This should be selectable independently. Default has to be black background
+ * foreground does not matter at all.
+ */
+#define GAUGE_COLOR (PORT_COLOR (MY_COLOR_PAIR(21),0))
+#define INPUT_COLOR (PORT_COLOR (MY_COLOR_PAIR(22),0))
+
+#ifdef HAVE_SLANG
+# define DEFAULT_COLOR (PORT_COLOR (MY_COLOR_PAIR(31),0))
+# else
+# define DEFAULT_COLOR A_NORMAL
+#endif
+#define HELP_NORMAL_COLOR (PORT_COLOR (MY_COLOR_PAIR(16),A_REVERSE))
+#define HELP_ITALIC_COLOR (PORT_COLOR (MY_COLOR_PAIR(17),A_REVERSE))
+#define HELP_BOLD_COLOR (PORT_COLOR (MY_COLOR_PAIR(18),A_REVERSE))
+#define HELP_LINK_COLOR (PORT_COLOR (MY_COLOR_PAIR(19),0))
+#define HELP_SLINK_COLOR (PORT_COLOR (MY_COLOR_PAIR(20),A_BOLD))
+
+extern int sel_mark_color [4];
+extern int dialog_colors [4];
+
+#define COLOR_NORMAL (PORT_COLOR (MY_COLOR_PAIR (8),A_REVERSE))
+#define COLOR_FOCUS (PORT_COLOR (MY_COLOR_PAIR (9),A_BOLD))
+#define COLOR_HOT_NORMAL (PORT_COLOR (MY_COLOR_PAIR (10),0))
+#define COLOR_HOT_FOCUS (PORT_COLOR (MY_COLOR_PAIR (11),0))
+
+/* Add this to color panel, on BW all pairs are normal */
+#define STALLED_COLOR (PORT_COLOR (MY_COLOR_PAIR (12),0))
+
+#define DIRECTORY_COLOR (PORT_COLOR (MY_COLOR_PAIR (23),0))
+#define EXECUTABLE_COLOR (PORT_COLOR (MY_COLOR_PAIR (24),0))
+#define LINK_COLOR (PORT_COLOR (MY_COLOR_PAIR (25),0))
+#define DEVICE_COLOR (PORT_COLOR (MY_COLOR_PAIR (26),0))
+#define SPECIAL_COLOR (PORT_COLOR (MY_COLOR_PAIR (27),0))
+#define CORE_COLOR (PORT_COLOR (MY_COLOR_PAIR (28),0))
+
+#endif /* __COLOR_H */
+
--- /dev/null
+/* Command line widget.
+ Copyright (C) 1995 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This widget is derived from the WInput widget, it's used to cope
+ with all the magic of the command input line, we depend on some
+ help from the program's callback.
+
+*/
+
+#include <config.h>
+#include <errno.h>
+#include "tty.h"
+#include "fs.h"
+#include <malloc.h>
+#include <string.h>
+#include <stdlib.h>
+#include "mad.h"
+#include "dlg.h"
+#include "widget.h"
+#include "command.h"
+#include "complete.h" /* completion constants */
+#include "global.h" /* home_dir */
+#include "dialog.h" /* message () */
+#include "dir.h" /* required by panel.h */
+#include "panel.h" /* view_tree enum. Also, needed by main.h */
+#include "main.h" /* do_cd */
+#include "layout.h" /* for command_prompt variable */
+#include "user.h" /* expand_format */
+#include "subshell.h"
+#include "tree.h" /* for tree_chdir */
+#include "color.h"
+#include "../vfs/vfs.h"
+
+/* This holds the command line */
+WCommand *cmdline;
+
+/*Tries variable substitution, and if a variable CDPATH
+of the form e.g. CDPATH=".:~:/usr" exists, we try then all the paths which
+are mentioned there. Also, we do not support such extraordinary things as
+${var:-value}, etc. Use the eval cd 'path' command instead.
+Bugs: No quoting occurrs here, so ${VAR} and $VAR will be always
+substituted. I think we can encourage users to use in such extreme
+cases instead of >cd path< command a >eval cd 'path'< command, which works
+as they might expect :)
+FIXME: Perhaps we should do wildcard matching as well? */
+static int examine_cd (char *path)
+{
+ char *p;
+ int result;
+ char *q = xmalloc (MC_MAXPATHLEN + 10, "examine_cd"), *r, *s, *t, c;
+
+ /* Variable expansion */
+ for (p = path, r = q; *p && r < q + MC_MAXPATHLEN; ) {
+ if (*p != '$' || (p [1] == '[' || p [1] == '('))
+ *(r++)=*(p++);
+ else {
+ p++;
+ if (*p == '{') {
+ p++;
+ s = strchr (p, '}');
+ } else
+ s = NULL;
+ if (s == NULL)
+ s = strchr (p, PATH_SEP);
+ if (s == NULL)
+ s = strchr (p, 0);
+ c = *s;
+ *s = 0;
+ t = getenv (p);
+ *s = c;
+ if (t == NULL) {
+ *(r++) = '$';
+ if (*(p - 1) != '$')
+ *(r++) = '{';
+ } else {
+ if (r + strlen (t) < q + MC_MAXPATHLEN) {
+ strcpy (r, t);
+ r = strchr (r, 0);
+ }
+ if (*s == '}')
+ p = s + 1;
+ else
+ p = s;
+ }
+ }
+ }
+ *r = 0;
+
+ result = do_cd (q, cd_parse_command);
+
+ /* CDPATH handling */
+ if (*q != PATH_SEP && !result) {
+ p = getenv ("CDPATH");
+ if (p == NULL)
+ c = 0;
+ else
+ c = ':';
+ while (!result && c == ':') {
+ s = strchr (p, ':');
+ if (s == NULL)
+ s = strchr (p, 0);
+ c = *s;
+ *s = 0;
+ if (*p) {
+ r = concat_dir_and_file (p, q);
+ result = do_cd (r, cd_parse_command);
+ free (r);
+ }
+ *s = c;
+ p = s + 1;
+ }
+ }
+ free (q);
+ return result;
+}
+
+/* Execute the cd command on the command line */
+void do_cd_command (char *cmd)
+{
+ int len;
+
+ /* Any final whitespace should be removed here
+ (to see why, try "cd fred "). */
+ /* NOTE: I think we should not remove the extra space,
+ that way, we can cd into hidden directories */
+ len = strlen (cmd) - 1;
+ while (len >= 0 &&
+ (cmd [len] == ' ' || cmd [len] == '\t' || cmd [len] == '\n')){
+ cmd [len] = 0;
+ len --;
+ }
+
+ if (cmd [2] == 0)
+ cmd = "cd ";
+
+ if (get_current_type () == view_tree){
+ if (cmd [0] == 0){
+ tree_chdir (the_tree, home_dir);
+ } else if (strcmp (cmd+3, "..") == 0){
+ char *dir = cpanel->cwd;
+ int len = strlen (dir);
+ while (len && dir [--len] != PATH_SEP);
+ dir [len] = 0;
+ if (len)
+ tree_chdir (the_tree, dir);
+ else
+ tree_chdir (the_tree, PATH_SEP_STR);
+ } else if (cmd [3] == PATH_SEP){
+ tree_chdir (the_tree, cmd+3);
+ } else {
+ char *old = cpanel->cwd;
+ char *new;
+ new = concat_dir_and_file (old, cmd+3);
+ tree_chdir (the_tree, new);
+ free (new);
+ }
+ } else
+ if (!examine_cd (&cmd [3])) {
+ message (1, MSG_ERROR, _(" Can't chdir to '%s' \n %s "),
+ &cmd [3], unix_error_string (errno));
+ return;
+ }
+}
+
+/* Returns 1 if the we could handle the enter, 0 if not */
+static int enter (WCommand *cmdline)
+{
+ Dlg_head *old_dlg;
+
+ if (command_prompt && strlen (input_w (cmdline)->buffer)){
+ char *cmd;
+
+ /* Any initial whitespace should be removed at this point */
+ cmd = input_w (cmdline)->buffer;
+ while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
+ cmd++;
+
+ if (strncmp (cmd, "cd ", 3) == 0 || strcmp (cmd, "cd") == 0){
+ do_cd_command (cmd);
+ new_input (input_w (cmdline));
+ return MSG_HANDLED;
+ }
+#ifdef OS2_NT
+ else if ( (strncmp (cmd, "set ", 4) == 0 || strncmp (cmd, "Set ", 4) == 0 || strncmp (cmd, "SET ", 4) == 0) && strchr(cmd,'=') ){
+ cmd+=4;
+ while (*cmd == ' ' || *cmd == '\t' || *cmd == '\n')
+ cmd++;
+ _putenv(cmd);
+ new_input (input_w (cmdline));
+ return MSG_HANDLED;
+ }
+#endif
+ else {
+ char *command, *s;
+ int i, j;
+
+ if (!vfs_current_is_local ())
+ return MSG_NOT_HANDLED;
+ command = xmalloc (strlen (cmd) + 1, "main, enter");
+ command [0] = 0;
+ for (i = j = 0; i < strlen (cmd); i ++){
+ if (cmd [i] == '%'){
+ i ++;
+ s = expand_format (cmd [i], 1);
+ command = realloc (command, strlen (command) + strlen (s)
+ + strlen (cmd) - i + 1);
+ strcat (command, s);
+ free (s);
+ j = strlen (command);
+ } else {
+ command [j] = cmd [i];
+ j ++;
+ }
+ command [j] = 0;
+ }
+ old_dlg = current_dlg;
+ current_dlg = 0;
+ new_input (input_w (cmdline));
+ execute (command);
+ free (command);
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (quit & SUBSHELL_EXIT){
+ quiet_quit_cmd ();
+ return MSG_HANDLED;
+ }
+ if (use_subshell)
+ load_prompt (0, 0);
+#endif
+
+ current_dlg = old_dlg;
+ }
+ }
+ return MSG_HANDLED;
+}
+
+static int command_callback (Dlg_head *h, WCommand *cmd, int msg, int par)
+{
+ switch (msg){
+ case WIDGET_FOCUS:
+ /* We refuse the focus always: needed not to unselect the panel */
+ return MSG_NOT_HANDLED;
+
+ case WIDGET_KEY:
+ /* Special case: we handle the enter key */
+ if (par == '\n'){
+ return enter (cmd);
+ }
+ }
+ return (*cmd->old_callback)(h, cmd, msg, par);
+}
+
+WCommand *command_new (int y, int x, int cols)
+{
+ WInput *in;
+ WCommand *cmd = xmalloc (sizeof (WCommand), "command_new");
+
+ in = input_new (y, x, DEFAULT_COLOR, cols, "", "cmdline");
+ cmd->input = *in;
+ free (in);
+
+ /* Add our hooks */
+ cmd->old_callback = (callback_fn) cmd->input.widget.callback;
+ cmd->input.widget.callback = (int (*) (Dlg_head *, void *, int, int))
+ command_callback;
+
+ cmd->input.completion_flags |= INPUT_COMPLETE_COMMANDS;
+ return cmd;
+}
+
+
--- /dev/null
+#ifndef __COMMAND_H
+#define __COMMAND_H
+
+typedef struct {
+ WInput input;
+ callback_fn old_callback;
+} WCommand;
+
+WCommand *command_new (int y, int x, int len);
+
+/* Return the Input * from a WCommand */
+#define input_w(x) (&(x->input))
+
+extern WCommand *cmdline;
+
+void do_cd_command (char *cmd);
+
+#endif /* __COMMAND_H */
--- /dev/null
+/* Input line filename/username/hostname/variable/command completion.
+ (Let mc type for you...)
+
+ Copyright (C) 1995 The Free Software Foundation
+
+ Written by: 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
+#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
+# ifdef __os2__
+# include "dirent.h"
+# else
+# include <dirent.h>
+# endif
+# define NLENGTH(dirent) (strlen ((dirent)->d_name))
+#else
+# define dirent direct
+# define NLENGTH(dirent) ((dirent)->d_namlen)
+
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef OS2_NT
+# include <pwd.h>
+#endif
+
+#include "global.h"
+#include "mad.h"
+#include "util.h"
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h"
+#include "wtools.h"
+#include "complete.h"
+#include "main.h"
+#include "key.h" /* XCTRL and ALT macros */
+
+/* This flag is used in filename_completion_function */
+int ignore_filenames = 0;
+
+/* This flag is used by command_completion_function */
+/* to hint the filename_completion_function */
+int look_for_executables = 0;
+
+char *filename_completion_function (char *text, int state)
+{
+ static DIR *directory;
+ static char *filename = NULL;
+ static char *dirname = NULL;
+ static char *users_dirname = NULL;
+ static int filename_len;
+ int isdir = 1, isexec = 0;
+
+ struct dirent *entry = NULL;
+
+ /* If we're starting the match process, initialize us a bit. */
+ if (!state){
+ char *temp;
+
+ if (dirname)
+ free (dirname);
+ if (filename)
+ free (filename);
+ if (users_dirname)
+ free (users_dirname);
+
+ filename = strdup (text);
+ if (!*text)
+ text = ".";
+ dirname = strdup (text);
+
+ temp = strrchr (dirname, PATH_SEP);
+
+ if (temp){
+ strcpy (filename, ++temp);
+ *temp = 0;
+ }
+ else
+ strcpy (dirname, ".");
+
+ /* We aren't done yet. We also support the "~user" syntax. */
+
+ /* Save the version of the directory that the user typed. */
+ users_dirname = strdup (dirname);
+ {
+ char *temp_dirname;
+
+ temp_dirname = tilde_expand (dirname);
+ if (!temp_dirname){
+ free (dirname);
+ free (users_dirname);
+ free (filename);
+ dirname = users_dirname = filename = NULL;
+ return NULL;
+ }
+ free (dirname);
+ dirname = temp_dirname;
+ canonicalize_pathname (dirname);
+ /* Here we should do something with variable expansion
+ and `command`.
+ Maybe a dream - UNIMPLEMENTED yet. */
+ }
+ directory = opendir (dirname);
+ filename_len = strlen (filename);
+ }
+
+ /* Now that we have some state, we can read the directory. */
+
+ while (directory && (entry = readdir (directory))){
+ /* Special case for no filename.
+ All entries except "." and ".." match. */
+ if (!filename_len){
+ if (!strcmp (entry->d_name, ".") || !strcmp (entry->d_name, ".."))
+ continue;
+ } else {
+ /* Otherwise, if these match up to the length of filename, then
+ it may be a match. */
+ if ((entry->d_name[0] != filename[0]) ||
+ ((NLENGTH (entry)) < filename_len) ||
+ strncmp (filename, entry->d_name, filename_len))
+ continue;
+ }
+ isdir = 1; isexec = 0;
+ {
+ char *tmp = xmalloc (3 + strlen (dirname) + NLENGTH (entry), "Filename completion");
+ struct stat tempstat;
+
+ strcpy (tmp, dirname);
+ strcat (tmp, PATH_SEP_STR);
+ strcat (tmp, entry->d_name);
+ canonicalize_pathname (tmp);
+ /* Unix version */
+ if (!stat (tmp, &tempstat)){
+ uid_t my_uid = getuid ();
+ gid_t my_gid = getgid ();
+
+ if (!S_ISDIR (tempstat.st_mode)){
+ isdir = 0;
+ if ((!my_uid && (tempstat.st_mode & 0111)) ||
+ (my_uid == tempstat.st_uid && (tempstat.st_mode & 0100)) ||
+ (my_gid == tempstat.st_gid && (tempstat.st_mode & 0010)) ||
+ (tempstat.st_mode & 0001))
+ isexec = 1;
+ }
+ }
+ free (tmp);
+ }
+ switch (look_for_executables)
+ {
+ case 2: if (!isexec)
+ continue;
+ break;
+ case 1: if (!isexec && !isdir)
+ continue;
+ break;
+ }
+ if (ignore_filenames && !isdir)
+ continue;
+ break;
+ }
+
+ if (!entry){
+ if (directory){
+ closedir (directory);
+ directory = NULL;
+ }
+ if (dirname){
+ free (dirname);
+ dirname = NULL;
+ }
+ if (filename){
+ free (filename);
+ filename = NULL;
+ }
+ if (users_dirname){
+ free (users_dirname);
+ users_dirname = NULL;
+ }
+ return NULL;
+ } else {
+ char *temp;
+
+ if (users_dirname && (users_dirname[0] != '.' || users_dirname[1])){
+ int dirlen = strlen (users_dirname);
+ temp = xmalloc (3 + dirlen + NLENGTH (entry), "Filename completion");
+ strcpy (temp, users_dirname);
+ /* We need a `/' at the end. */
+ if (users_dirname[dirlen - 1] != PATH_SEP){
+ temp[dirlen] = PATH_SEP;
+ temp[dirlen + 1] = 0;
+ }
+ strcat (temp, entry->d_name);
+ } else {
+ temp = xmalloc (2 + NLENGTH (entry), "Filename completion");
+ strcpy (temp, entry->d_name);
+ }
+ if (isdir)
+ strcat (temp, PATH_SEP_STR);
+ return temp;
+ }
+}
+
+/* We assume here that text[0] == '~' , if you want to call it in another way,
+ you have to change the code */
+#ifdef OS2_NT
+char *username_completion_function (char *text, int state)
+{
+ return NULL;
+}
+#else
+char *username_completion_function (char *text, int state)
+{
+ static struct passwd *entry;
+ static int userlen;
+
+ if (!state){ /* Initialization stuff */
+ setpwent ();
+ userlen = strlen (text + 1);
+ }
+ while ((entry = getpwent ()) != NULL){
+ /* Null usernames should result in all users as possible completions. */
+ if (!userlen)
+ break;
+ else if (text[1] == entry->pw_name[0] &&
+ !strncmp (text + 1, entry->pw_name, userlen))
+ break;
+ }
+
+ if (!entry){
+ endpwent ();
+ return NULL;
+ } else {
+ char *temp = xmalloc (3 + strlen (entry->pw_name), "Username completion");
+
+ *temp = '~';
+ strcpy (temp + 1, entry->pw_name);
+ strcat (temp, PATH_SEP_STR);
+ return temp;
+ }
+}
+
+extern char **environ;
+#endif /* OS2_NT */
+
+/* We assume text [0] == '$' and want to have a look at text [1], if it is
+ equal to '{', so that we should append '}' at the end */
+char *variable_completion_function (char *text, int state)
+{
+ static char **env_p;
+ static int varlen, isbrace;
+ char *p = 0;
+
+ if (!state){ /* Initialization stuff */
+ isbrace = (text [1] == '{');
+ varlen = strlen (text + 1 + isbrace);
+ env_p = environ;
+ }
+
+ while (*env_p){
+ p = strchr (*env_p, '=');
+ if (p && p - *env_p >= varlen && !strncmp (text + 1 + isbrace, *env_p, varlen))
+ break;
+ env_p++;
+ }
+
+ if (!*env_p)
+ return NULL;
+ else {
+ char *temp = xmalloc (2 + 2 * isbrace + p - *env_p, "Variable completion");
+
+ *temp = '$';
+ if (isbrace)
+ temp [1] = '{';
+ strncpy (temp + 1 + isbrace, *env_p, p - *env_p);
+ if (isbrace)
+ strcpy (temp + 2 + (p - *env_p), "}");
+ else
+ temp [1 + p - *env_p] = 0;
+ env_p++;
+ return temp;
+ }
+}
+
+#define whitespace(c) ((c) == ' ' || (c) == '\t')
+#define cr_whitespace(c) (whitespace (c) || (c) == '\n' || (c) == '\r')
+
+static char **hosts = NULL;
+static char **hosts_p = NULL;
+static int hosts_alloclen = 0;
+static void fetch_hosts (char *filename)
+{
+ FILE *file = fopen (filename, "r");
+ char *temp, buffer[256], *name;
+ register int i, start;
+
+ if (!file)
+ return;
+
+ while ((temp = fgets (buffer, 255, file)) != NULL){
+ /* Skip to first character. */
+ for (i = 0; buffer[i] && cr_whitespace (buffer[i]); i++);
+ /* Ignore comments... */
+ if (buffer[i] == '#')
+ continue;
+ /* Handle $include. */
+ if (!strncmp (buffer + i, "$include ", 9)){
+ char *includefile = buffer + i + 9;
+ char *t;
+
+ /* Find start of filename. */
+ while (*includefile && whitespace (*includefile))
+ includefile++;
+ t = includefile;
+
+ /* Find end of filename. */
+ while (*t && !cr_whitespace (*t))
+ t++;
+ *t = '\0';
+
+ fetch_hosts (includefile);
+ continue;
+ }
+
+ /* Skip IP #s. */
+ for (; buffer[i] && !cr_whitespace (buffer[i]); i++);
+
+ /* Get the host names separated by white space. */
+ while (buffer[i] && buffer[i] != '#'){
+ for (; i && cr_whitespace (buffer[i]); i++);
+ if (buffer[i] == '#')
+ continue;
+ for (start = i; buffer[i] && !cr_whitespace (buffer[i]); i++);
+ if (i - start == 0)
+ continue;
+ name = (char *) xmalloc (i - start + 1, "Hostname completion");
+ strncpy (name, buffer + start, i - start);
+ name [i - start] = 0;
+ {
+ char **host_p;
+
+ if (hosts_p - hosts >= hosts_alloclen){
+ int j = hosts_p - hosts;
+
+ hosts = realloc ((void *)hosts, ((hosts_alloclen += 30) + 1) * sizeof (char *));
+ hosts_p = hosts + j;
+ }
+ for (host_p = hosts; host_p < hosts_p; host_p++)
+ if (!strcmp (name, *host_p))
+ break; /* We do not want any duplicates */
+ if (host_p == hosts_p){
+ *(hosts_p++) = name;
+ *hosts_p = NULL;
+ } else
+ free (name);
+ }
+ }
+ }
+ fclose (file);
+}
+
+char *hostname_completion_function (char *text, int state)
+{
+ static char **host_p;
+ static int textstart, textlen;
+
+ if (!state){ /* Initialization stuff */
+ char *p;
+
+ if (hosts != NULL){
+ for (host_p = hosts; *host_p; host_p++)
+ free (*host_p);
+ free (hosts);
+ }
+ hosts = (char **) xmalloc (((hosts_alloclen = 30) + 1) * sizeof (char *), "Hostname completion");
+ *hosts = NULL;
+ hosts_p = hosts;
+ fetch_hosts ((p = getenv ("HOSTFILE")) ? p : "/etc/hosts");
+ host_p = hosts;
+ textstart = (*text == '@') ? 1 : 0;
+ textlen = strlen (text + textstart);
+ }
+
+ while (*host_p){
+ if (!textlen)
+ break; /* Match all of them */
+ else if (!strncmp (text + textstart, *host_p, textlen))
+ break;
+ host_p++;
+ }
+
+ if (!*host_p){
+ for (host_p = hosts; *host_p; host_p++)
+ free (*host_p);
+ free (hosts);
+ hosts = NULL;
+ return NULL;
+ } else {
+ char *temp = xmalloc (2 + strlen (*host_p), "Hostname completion");
+
+ if (textstart)
+ *temp = '@';
+ strcpy (temp + textstart, *host_p);
+ host_p++;
+ return temp;
+ }
+}
+
+/* This is the function to call when the word to complete is in a position
+ where a command word can be found. It looks around $PATH, looking for
+ commands that match. It also scans aliases, function names, and the
+ table of shell built-ins. */
+char *command_completion_function (char *text, int state)
+{
+ static int isabsolute;
+ static int phase;
+ static int text_len;
+ static char **words;
+ static char *path;
+ static char *cur_path;
+ static char *cur_word;
+ static int init_state;
+ static char *bash_reserved [] = { "if", "then", "else", "elif", "fi",
+ "case", "esac", "for", "select", "while",
+ "until", "do", "done", "in", "function" , 0};
+ static char *bash_builtins [] = { "alias", "bg", "bind", "break", "builtin",
+ "cd", "command", "continue", "declare",
+ "dirs", "echo", "enable", "eval", "exec",
+ "exit", "export", "fc", "fg", "getopts",
+ "hash", "help", "history", "jobs", "kill",
+ "let", "local", "logout", "popd", "pushd",
+ "pwd", "read", "readonly", "return", "set",
+ "shift", "source", "suspend", "test",
+ "times", "trap", "type", "typeset",
+ "ulimit", "umask", "unalias", "unset",
+ "wait" , 0};
+ char *p, *found;
+
+ if (!state){ /* Initialize us a little bit */
+ isabsolute = strchr (text, PATH_SEP) != 0;
+ look_for_executables = isabsolute ? 1 : 2;
+ if (!isabsolute){
+ words = bash_reserved;
+ phase = 0;
+ text_len = strlen (text);
+ p = getenv ("PATH");
+ if (!p)
+ path = NULL;
+ else {
+ path = xmalloc (strlen (p) + 2, "Command completion");
+ strcpy (path, p);
+ path [strlen (p) + 1] = 0;
+ p = strchr (path, PATH_ENV_SEP);
+ while (p){
+ *p = 0;
+ p = strchr (p + 1, PATH_ENV_SEP);
+ }
+ }
+ }
+ }
+
+ if (isabsolute){
+ p = filename_completion_function (text, state);
+ if (!p)
+ look_for_executables = 0;
+ return p;
+ }
+
+ found = NULL;
+ switch (phase){
+ case 0: /* Reserved words */
+ while (*words){
+ if (!strncmp (*words, text, text_len))
+ return strdup (*(words++));
+ words++;
+ }
+ phase++;
+ words = bash_builtins;
+ case 1: /* Builtin commands */
+ while (*words){
+ if (!strncmp (*words, text, text_len))
+ return strdup (*(words++));
+ words++;
+ }
+ phase++;
+ if (!path)
+ break;
+ cur_path = path;
+ cur_word = NULL;
+ case 2: /* And looking through the $PATH */
+ while (!found){
+ if (!cur_word){
+ char *expanded;
+
+ if (!*cur_path)
+ break;
+ expanded = tilde_expand (cur_path);
+ if (!expanded){
+ free (path);
+ path = NULL;
+ return NULL;
+ }
+ p = canonicalize_pathname (expanded);
+ cur_word = xmalloc (strlen (p) + 2 + text_len, "Command completion");
+ strcpy (cur_word, p);
+ if (cur_word [strlen (cur_word) - 1] != PATH_SEP)
+ strcat (cur_word, PATH_SEP_STR);
+ strcat (cur_word, text);
+ free (p);
+ cur_path = strchr (cur_path, 0) + 1;
+ init_state = state;
+ }
+ found = filename_completion_function (cur_word, state - init_state);
+ if (!found){
+ free (cur_word);
+ cur_word = NULL;
+ }
+ }
+ }
+
+ if (!found){
+ look_for_executables = 0;
+ if (path)
+ free (path);
+ return NULL;
+ }
+ if ((p = strrchr (found, PATH_SEP)) != NULL){
+ p++;
+ p = strdup (p);
+ free (found);
+ return p;
+ }
+ return found;
+
+}
+
+int match_compare (const void *a, const void *b)
+{
+ return strcmp (*(char **)a, *(char **)b);
+}
+
+/* Returns an array of char * matches with the longest common denominator
+ in the 1st entry. Then a NULL terminated list of different possible
+ completions follows.
+ You have to supply your own CompletionFunction with the word you
+ want to complete as the first argument and an count of previous matches
+ as the second.
+ In case no matches were found we return NULL. */
+char **completion_matches (char *text, CompletionFunction entry_function)
+{
+ /* Number of slots in match_list. */
+ int match_list_size;
+
+ /* The list of matches. */
+ char **match_list = (char **) xmalloc (((match_list_size = 30) + 1) * sizeof (char *), "completion match list");
+
+ /* Number of matches actually found. */
+ int matches = 0;
+
+ /* Temporary string binder. */
+ char *string;
+
+ match_list[1] = NULL;
+
+ while ((string = (*entry_function) (text, matches)) != NULL){
+ if (matches + 1 == match_list_size)
+ match_list = (char **) realloc (match_list, ((match_list_size += 30) + 1) * sizeof (char *));
+ match_list[++matches] = string;
+ match_list[matches + 1] = NULL;
+ }
+
+ /* If there were any matches, then look through them finding out the
+ lowest common denominator. That then becomes match_list[0]. */
+ if (matches)
+ {
+ register int i = 1;
+ int low = 4096; /* Count of max-matched characters. */
+
+ /* If only one match, just use that. */
+ if (matches == 1){
+ match_list[0] = match_list[1];
+ match_list[1] = (char *)NULL;
+ } else {
+ int j;
+
+ qsort (match_list + 1, matches, sizeof (char *), match_compare);
+
+ /* And compare each member of the list with
+ the next, finding out where they stop matching.
+ If we find two equal strings, we have to put one away... */
+
+ j = i + 1;
+ while (j < matches + 1)
+ {
+ register int c1, c2, si;
+
+ for (si = 0;(c1 = match_list [i][si]) && (c2 = match_list [j][si]); si++)
+ if (c1 != c2) break;
+
+ if (!c1 && !match_list [j][si]){ /* Two equal strings */
+ free (match_list [j]);
+ j++;
+ if (j > matches)
+ break;
+ } else
+ if (low > si) low = si;
+ if (i + 1 != j) /* So there's some gap */
+ match_list [i + 1] = match_list [j];
+ i++; j++;
+ }
+ matches = i;
+ match_list [matches + 1] = NULL;
+ match_list[0] = xmalloc (low + 1, "Completion matching list");
+ strncpy (match_list[0], match_list[1], low);
+ match_list[0][low] = 0;
+ }
+ } else { /* There were no matches. */
+ free (match_list);
+ match_list = NULL;
+ }
+ return match_list;
+}
+
+int check_is_cd (char *text, int start, int flags)
+{
+ char *p, *q = text + start;
+
+ for (p = text; *p && p < q && (*p == ' ' || *p == '\t'); p++);
+ if (((flags & INPUT_COMPLETE_COMMANDS) &&
+ !strncmp (p, "cd", 2) && (p [2] == ' ' || p [2] == '\t') &&
+ p + 2 < q) ||
+ (flags & INPUT_COMPLETE_CD))
+ return 1;
+ return 0;
+}
+
+/* Returns an array of matches, or NULL if none. */
+char **try_complete (char *text, int *start, int *end, int flags)
+{
+ int in_command_position = 0, i;
+ char *word, c;
+ char **matches = NULL;
+ char *command_separator_chars = ";|&{(`";
+ char *p = NULL, *q = NULL, *r = NULL;
+ int is_cd = check_is_cd (text, *start, flags);
+
+ ignore_filenames = 0;
+ c = text [*end];
+ text [*end] = 0;
+ word = strdup (text + *start);
+ text [*end] = c;
+
+ /* Determine if this could be a command word. It is if it appears at
+ the start of the line (ignoring preceding whitespace), or if it
+ appears after a character that separates commands. And we have to
+ be in a INPUT_COMPLETE_COMMANDS flagged Input line. */
+ if (!is_cd && (flags & INPUT_COMPLETE_COMMANDS)){
+ i = *start - 1;
+ while (i > -1 && (text[i] == ' ' || text[i] == '\t'))
+ i--;
+ if (i < 0)
+ in_command_position++;
+ else if (strchr (command_separator_chars, text[i])){
+ register int this_char, prev_char;
+
+ in_command_position++;
+
+ if (i){
+ /* Handle the two character tokens `>&', `<&', and `>|'.
+ We are not in a command position after one of these. */
+ this_char = text[i];
+ prev_char = text[i - 1];
+
+ if ((this_char == '&' && (prev_char == '<' || prev_char == '>')) ||
+ (this_char == '|' && prev_char == '>'))
+ in_command_position = 0;
+ else if (i > 0 && text [i-1] == '\\') /* Quoted */
+ in_command_position = 0;
+ }
+ }
+ }
+
+ if (flags & INPUT_COMPLETE_COMMANDS)
+ p = strrchr (word, '`');
+ if (flags & (INPUT_COMPLETE_COMMANDS | INPUT_COMPLETE_VARIABLES))
+ q = strrchr (word, '$');
+ if (flags & INPUT_COMPLETE_HOSTNAMES)
+ r = strrchr (word, '@');
+ if (q && q [1] == '(' && INPUT_COMPLETE_COMMANDS){
+ if (q > p)
+ p = q + 1;
+ q = NULL;
+ }
+
+ /* Command substitution? */
+ if (p > q && p > r){
+ matches = completion_matches (p + 1, command_completion_function);
+ if (matches)
+ *start += p + 1 - word;
+ }
+
+ /* Variable name? */
+ else if (q > p && q > r){
+ matches = completion_matches (q, variable_completion_function);
+ if (matches)
+ *start += q - word;
+ }
+
+ /* Starts with '@', then look through the known hostnames for
+ completion first. */
+ else if (r > p && r > q){
+ matches = completion_matches (r, hostname_completion_function);
+ if (matches)
+ *start += r - word;
+ }
+
+ /* Starts with `~' and there is no slash in the word, then
+ try completing this word as a username. */
+ if (!matches && *word == '~' && (flags & INPUT_COMPLETE_USERNAMES) && !strchr (word, PATH_SEP))
+ matches = completion_matches (word, username_completion_function);
+
+
+ /* And finally if this word is in a command position, then
+ complete over possible command names, including aliases, functions,
+ and command names. */
+ if (!matches && in_command_position)
+ matches = completion_matches (word, command_completion_function);
+
+ else if (!matches && (flags & INPUT_COMPLETE_FILENAMES)){
+ if (is_cd)
+ ignore_filenames = 1;
+ matches = completion_matches (word, filename_completion_function);
+ ignore_filenames = 0;
+ if (!matches && is_cd && *word != PATH_SEP && *word != '~'){
+ char *p, *q = text + *start;
+
+ for (p = text; *p && p < q && (*p == ' ' || *p == '\t'); p++);
+ if (!strncmp (p, "cd", 2))
+ for (p += 2; *p && p < q && (*p == ' ' || *p == '\t'); p++);
+ if (p == q){
+ char *cdpath = getenv ("CDPATH");
+ char c, *s, *r;
+
+ if (cdpath == NULL)
+ c = 0;
+ else
+ c = ':';
+ while (!matches && c == ':'){
+ s = strchr (cdpath, ':');
+ if (s == NULL)
+ s = strchr (cdpath, 0);
+ c = *s;
+ *s = 0;
+ if (*cdpath){
+ r = concat_dir_and_file (cdpath, word);
+ ignore_filenames = 1;
+ matches = completion_matches (r, filename_completion_function);
+ ignore_filenames = 0;
+ free (r);
+ }
+ *s = c;
+ cdpath = s + 1;
+ }
+ }
+ }
+ }
+
+ if (word)
+ free (word);
+
+ return matches;
+}
+
+void free_completions (WInput *in)
+{
+ char **p;
+
+ if (!in->completions)
+ return;
+ for (p=in->completions; *p; p++)
+ free (*p);
+ free (in->completions);
+ in->completions = NULL;
+}
+
+static int query_height, query_width;
+static WInput *input;
+static int start, end, min_end;
+
+static int insert_text (WInput *in, char *text, int len)
+{
+ len = min (len, strlen (text)) + start - end;
+ if (strlen (in->buffer) + len >= in->current_max_len){
+ /* Expand the buffer */
+ char *narea = realloc(in->buffer, in->current_max_len + len + in->field_len);
+ if (narea){
+ in->buffer = narea;
+ in->current_max_len += len + in->field_len;
+ }
+ }
+ if (strlen (in->buffer)+1 < in->current_max_len){
+ if (len > 0){
+ int i, l = strlen (&in->buffer [end]);
+ for (i = l + 1; i >= 0; i--)
+ in->buffer [end + len + i] = in->buffer [end + i];
+ } else if (len < 0){
+ char *p = in->buffer + end + len, *q = in->buffer + end;
+ while (*q)
+ *(p++) = *(q++);
+ *p = 0;
+ }
+ strncpy (in->buffer + start, text, len - start + end);
+ in->point += len;
+ update_input (in, 1);
+ end += len;
+ }
+ return len != 0;
+}
+
+static int query_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+ case DLG_DRAW:
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 0, 0, query_height, query_width);
+ break;
+
+ case DLG_KEY:
+ switch (Par) {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ h->ret_value = 0;
+ dlg_stop (h);
+ return 1;
+
+ case 0177:
+ case KEY_BACKSPACE:
+ case XCTRL('h'):
+ if (end == min_end){
+ h->ret_value = 0;
+ dlg_stop (h);
+ return 1;
+ } else {
+ WLEntry *e, *e1;
+
+ e1 = e = ((WListbox *)(h->current->widget))->list;
+ do {
+ if (!strncmp (input->buffer + start, e1->text, end - start - 1)){
+ listbox_select_entry((WListbox *)(h->current->widget), e1);
+ handle_char (input, Par);
+ end--;
+ send_message (h, h->current->widget,
+ WIDGET_DRAW, 0);
+ break;
+ }
+ e1 = e1->next;
+ } while (e != e1);
+ }
+ return 1;
+
+ default:
+ if (Par > 0xff || !is_printable (Par)){
+ if (is_in_input_map (input, Par) == 2){
+ if (end == min_end)
+ return 1;
+ h->ret_value = B_USER; /* This means we want to refill the
+ list box and start again */
+ dlg_stop (h);
+ return 1;
+ } else
+ return 0;
+ } else {
+ WLEntry *e, *e1;
+ int need_redraw = 0;
+ int low = 4096;
+ char *last_text = NULL;
+
+ e1 = e = ((WListbox *)(h->current->widget))->list;
+ do {
+ if (!strncmp (input->buffer + start, e1->text, end - start)){
+ if (e1->text [end - start] == Par){
+ if (need_redraw){
+ register int c1, c2, si;
+
+ for (si = end - start + 1;
+ (c1 = last_text [si]) &&
+ (c2 = e1->text [si]); si++)
+ if (c1 != c2)
+ break;
+ if (low > si)
+ low = si;
+ last_text = e1->text;
+ need_redraw = 2;
+ } else {
+ need_redraw = 1;
+ listbox_select_entry((WListbox *)(h->current->widget), e1);
+ last_text = e1->text;
+ }
+ }
+ }
+ e1 = e1->next;
+ } while (e != e1);
+ if (need_redraw == 2){
+ insert_text (input, last_text, low);
+ send_message (h, h->current->widget,WIDGET_DRAW,0);
+ } else if (need_redraw == 1){
+ h->ret_value = B_ENTER;
+ dlg_stop (h);
+ }
+ }
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+static int querylist_callback (void *data)
+{
+ return 1;
+}
+
+#define DO_INSERTION 1
+#define DO_QUERY 2
+/* Returns 1 if the user would like to see us again */
+int complete_engine (WInput *in, int what_to_do)
+{
+ if (in->completions && in->point != end)
+ free_completions (in);
+ if (!in->completions){
+ end = in->point;
+ for (start = end ? end - 1 : 0; start > -1; start--)
+ if (strchr (" \t;|<>", in->buffer [start]))
+ break;
+ if (start < end)
+ start++;
+ in->completions = try_complete (in->buffer, &start, &end, in->completion_flags);
+ }
+ if (in->completions){
+ if (what_to_do & DO_INSERTION) {
+ if (insert_text (in, in->completions [0], strlen (in->completions [0]))){
+ if (in->completions [1])
+ beep ();
+ } else
+ beep ();
+ }
+ if ((what_to_do & DO_QUERY) && in->completions [1]) {
+ int maxlen = 0, i, count = 0;
+ int x, y, w, h;
+ int start_x, start_y;
+ char **p, *q;
+ Dlg_head *query_dlg;
+ WListbox *query_list;
+
+ for (p=in->completions + 1; *p; count++, p++)
+ if ((i = strlen (*p)) > maxlen)
+ maxlen = i;
+ start_x = in->widget.x;
+ start_y = in->widget.y;
+ if (start_y - 2 >= count) {
+ y = start_y - 2 - count;
+ h = 2 + count;
+ } else {
+ if (start_y >= LINES - start_y - 1) {
+ y = 0;
+ h = start_y;
+ } else {
+ y = start_y + 1;
+ h = LINES - start_y - 1;
+ }
+ }
+ x = start - in->first_shown - 2 + start_x;
+ w = maxlen + 4;
+ if (x + w > COLS)
+ x = COLS - w;
+ if (x < 0)
+ x = 0;
+ if (x + w > COLS)
+ w = COLS;
+ input = in;
+ min_end = end;
+ query_height = h;
+ query_width = w;
+ query_dlg = create_dlg (y, x, query_height, query_width,
+ dialog_colors, query_callback,
+ "[Completion-query]", "complete", DLG_NONE);
+ query_list = listbox_new (1, 1, w - 2, h - 2, 0, querylist_callback, NULL);
+ add_widget (query_dlg, query_list);
+ for (p = in->completions + 1; *p; p++)
+ listbox_add_item (query_list, 0, 0, *p, NULL);
+ run_dlg (query_dlg);
+ q = NULL;
+ if (query_dlg->ret_value == B_ENTER){
+ listbox_get_current (query_list, &q, NULL);
+ if (q)
+ insert_text (in, q, strlen (q));
+ }
+ if (q || end != min_end)
+ free_completions (in);
+ i = query_dlg->ret_value; /* B_USER if user wants to start over again */
+ destroy_dlg (query_dlg);
+ if (i == B_USER)
+ return 1;
+ }
+ } else
+ beep ();
+ return 0;
+}
+
+void complete (WInput *in)
+{
+ if (in->completions)
+ while (complete_engine (in, DO_QUERY));
+ else if (show_all_if_ambiguous){
+ complete_engine (in, DO_INSERTION);
+ while (complete_engine (in, DO_QUERY));
+ } else
+ complete_engine (in, DO_INSERTION);
+}
--- /dev/null
+#ifndef __COMPLETE_H
+#define __COMPLETE_H
+
+#define INPUT_COMPLETE_FILENAMES 1
+#define INPUT_COMPLETE_HOSTNAMES 2
+#define INPUT_COMPLETE_COMMANDS 4
+#define INPUT_COMPLETE_VARIABLES 8
+#define INPUT_COMPLETE_USERNAMES 16
+#define INPUT_COMPLETE_CD 32
+
+typedef char *CompletionFunction (char *, int);
+
+void free_completions (WInput *);
+void complete (WInput *);
+
+#endif /* __COMPLETE_H */
--- /dev/null
+/* Client interface for General purpose Linux console save/restore server
+ Copyright (C) 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* The cons saver can't have a pid of 1, used to prevent bunches of */
+/*#ifdef linux */
+#include <config.h>
+
+int cons_saver_pid = 1;
+extern int rxvt_extensions;
+signed char console_flag = 0;
+
+#if defined(linux) || defined(__linux__)
+
+#include "tty.h"
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/types.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#include <signal.h>
+#include "util.h"
+#include "win.h"
+#include "cons.saver.h"
+#include "main.h"
+
+static int pipefd1 [2] = {-1, -1}, pipefd2 [2] = {-1, -1};
+
+void show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
+{
+ unsigned char message = 0;
+ unsigned short bytes = 0;
+ int i;
+
+ standend ();
+
+ if (look_for_rxvt_extensions ()) {
+ show_rxvt_contents (starty, begin_line, end_line);
+ return;
+ }
+
+ /* Is tty console? */
+ if (!console_flag)
+ return;
+ /* Paranoid: Is the cons.saver still running? */
+ if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)){
+ cons_saver_pid = 0;
+ console_flag = 0;
+ return;
+ }
+
+ /* Send command to the console handler */
+ message = CONSOLE_CONTENTS;
+ write (pipefd1[1], &message, 1);
+ /* Check for outdated cons.saver */
+ read (pipefd2[0], &message, 1);
+ if (message != CONSOLE_CONTENTS)
+ return;
+
+ /* Send the range of lines that we want */
+ write (pipefd1[1], &begin_line, 1);
+ write (pipefd1[1], &end_line, 1);
+ /* Read the corresponding number of bytes */
+ read (pipefd2[0], &bytes, 2);
+
+ /* Read the bytes and output them */
+ for (i = 0; i < bytes; i++){
+ if ((i % COLS) == 0)
+ move (starty+(i/COLS), 0);
+ read (pipefd2[0], &message, 1);
+ addch (message);
+ }
+
+ /* Read the value of the console_flag */
+ read (pipefd2[0], &message, 1);
+}
+
+void handle_console (unsigned char action)
+{
+ char *tty_name;
+ char *mc_conssaver;
+ int status;
+
+ switch (action){
+ case CONSOLE_INIT:
+ if (look_for_rxvt_extensions ())
+ return;
+ /* Close old pipe ends in case it is the 2nd time we run cons.saver */
+ close (pipefd1[1]);
+ close (pipefd2[0]);
+ /* Create two pipes for communication */
+ pipe (pipefd1);
+ pipe (pipefd2);
+ /* Get the console saver running */
+ cons_saver_pid = fork ();
+ if (cons_saver_pid < 0){
+ /* Can't fork */
+ /* Delete pipes */
+ close (pipefd1[1]);
+ close (pipefd1[0]);
+ close (pipefd2[1]);
+ close (pipefd2[0]);
+ console_flag = 0;
+ } else if (cons_saver_pid > 0){
+ /* Parent */
+ /* Close the extra pipe ends */
+ close (pipefd1[0]);
+ close (pipefd2[1]);
+ /* Was the child successful? */
+ read (pipefd2[0], &console_flag, 1);
+ if (!console_flag){
+ close (pipefd1[1]);
+ close (pipefd2[0]);
+ waitpid (cons_saver_pid, &status, 0);
+ }
+ } else {
+ /* Child */
+ /* Close the extra pipe ends */
+ close (pipefd1[1]);
+ close (pipefd2[0]);
+ tty_name = ttyname (0);
+ /* Bind the pipe 0 to the standard input */
+ close (0);
+ dup (pipefd1[0]);
+ close (pipefd1[0]);
+ /* Bind the pipe 1 to the standard output */
+ close (1);
+ dup (pipefd2[1]);
+ close (pipefd2[1]);
+ /* Bind standard error to /dev/null */
+ close (2);
+ open ("/dev/null", O_WRONLY);
+ /* Exec the console save/restore handler */
+ mc_conssaver = concat_dir_and_file (mc_home, "bin/cons.saver");
+ execl (mc_conssaver, "cons.saver", tty_name, NULL);
+ /* Exec failed */
+ console_flag = 0;
+ write (1, &console_flag, 1);
+ close (1);
+ close (0);
+ exit (3);
+ } /* if (cons_saver_pid ...) */
+ break;
+
+ case CONSOLE_DONE:
+ case CONSOLE_SAVE:
+ case CONSOLE_RESTORE:
+ if (look_for_rxvt_extensions ())
+ return;
+ /* Is tty console? */
+ if (!console_flag)
+ return;
+ /* Paranoid: Is the cons.saver still running? */
+ if (cons_saver_pid < 1 || kill (cons_saver_pid, SIGCONT)){
+ cons_saver_pid = 0;
+ console_flag = 0;
+ return;
+ }
+ /* Send command to the console handler */
+ write (pipefd1[1], &action, 1);
+ if (action != CONSOLE_DONE){
+ /* Wait the console handler to do its job */
+ read (pipefd2[0], &console_flag, 1);
+ }
+ if (action == CONSOLE_DONE || !console_flag){
+ /* We are done -> Let's clean up */
+ close (pipefd1 [1]);
+ close (pipefd2 [0]);
+ waitpid (cons_saver_pid, &status, 0);
+ console_flag = 0;
+ }
+ break;
+ default:
+ /* Nothing */
+ }
+}
+
+#endif /* #ifdef linux */
+
+#ifdef SCO_FLAVOR
+/*
+** SCO console save/restore handling routines
+** Copyright (C) 1997 Alex Tkachenko <alex@bcs.zaporizhzhe.ua>
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/vid.h>
+#include <sys/console.h>
+#include <sys/vtkd.h>
+#include <memory.h>
+#include <signal.h>
+#include "tty.h"
+#include "util.h"
+#include "color.h"
+#include "cons.saver.h"
+
+static int FD_OUT = 2;
+
+static unsigned short* vidbuf = NULL;
+static unsigned short* screen = NULL;
+static int height = 0, width = 0, saved_attr = 0;
+static int mode = 0;
+
+#define SIG_ACQUIRE 21 /* originally: handset, line status change (?) */
+
+static int
+vt_active()
+{
+ struct vid_info vi;
+ int adapter = ioctl(FD_OUT, CONS_CURRENT, 0);
+
+ vi.size = sizeof(struct vid_info);
+ ioctl(FD_OUT, CONS_GETINFO, &(vi));
+ return (vi.m_num == ioctl(FD_OUT,CONSADP,adapter));
+}
+
+static void
+console_acquire_vt()
+{
+ struct vt_mode smode;
+
+ signal(SIG_ACQUIRE, SIG_DFL);
+ smode.mode = VT_AUTO;
+ smode.waitv = smode.relsig = smode.acqsig = smode.frsig = 0;
+ ioctl(FD_OUT, VT_SETMODE, &smode);
+ ioctl(FD_OUT, VT_RELDISP, VT_ACKACQ);
+}
+
+static void
+console_shutdown()
+{
+ if (!console_flag)
+ {
+ return;
+ }
+ if (screen != NULL)
+ {
+ free(screen);
+ }
+ console_flag = 0;
+}
+
+static void
+console_save()
+{
+ struct m6845_info mi;
+
+ if (!console_flag)
+ {
+ return;
+ }
+
+ if (!vt_active())
+ {
+ struct vt_mode smode;
+
+ /*
+ ** User switched out of our vt. Let's wait until we get SIG_ACQUIRE,
+ ** otherwise we could save wrong screen image
+ */
+ signal(SIG_ACQUIRE, console_acquire_vt);
+ smode.mode = VT_PROCESS;
+ smode.waitv = 0;
+ smode.waitv = smode.relsig = smode.acqsig = smode.frsig = SIG_ACQUIRE;
+ ioctl(FD_OUT, VT_SETMODE, &smode);
+
+ pause();
+ }
+
+ saved_attr = ioctl(FD_OUT, GIO_ATTR, 0);
+
+ vidbuf = (unsigned short*) ioctl(FD_OUT, MAPCONS, 0);
+
+ mi.size = sizeof(struct m6845_info);
+ ioctl(FD_OUT, CONS_6845INFO, &mi);
+
+ {
+ unsigned short* start = vidbuf + mi.screen_top;
+ memcpy(screen, start, width * height * 2);
+ }
+
+ write(FD_OUT,"\0337",2); /* save cursor position */
+}
+
+static void
+console_restore()
+{
+ struct m6845_info mi;
+ unsigned short* start;
+
+ if (!console_flag)
+ {
+ return;
+ }
+
+ write (FD_OUT, "\033[2J", 4);
+
+ mi.size = sizeof(struct m6845_info);
+ ioctl(FD_OUT, CONS_6845INFO, &mi);
+
+ start = vidbuf + mi.screen_top;
+ memcpy(start, screen, width * height * 2);
+ write(FD_OUT,"\0338",2); /* restore cursor position */
+}
+
+static void
+console_init()
+{
+ struct vid_info vi;
+ int adapter = ioctl(FD_OUT, CONS_CURRENT, 0);
+
+ console_flag = 0;
+
+ if (adapter != -1)
+ {
+ vi.size = sizeof(struct vid_info);
+ ioctl(FD_OUT, CONS_GETINFO, &(vi));
+
+ if (vt_active())
+ {
+ console_flag = 1;
+
+ height = vi.mv_rsz;
+ width = vi.mv_csz;
+
+ screen = (unsigned short*) xmalloc(height * width * 2,"console_init");
+ if (screen == NULL)
+ {
+ console_shutdown();
+ return;
+ }
+ console_save();
+ mode = ioctl(FD_OUT, CONS_GET, 0);
+ ioctl(FD_OUT, MODESWITCH | mode, 0);
+ console_restore();
+ }
+ }
+}
+
+void
+handle_console (unsigned char action)
+{
+ if (look_for_rxvt_extensions ())
+ return;
+ switch (action){
+ case CONSOLE_INIT:
+ console_init();
+ break;
+
+ case CONSOLE_DONE:
+ console_shutdown();
+ break;
+
+ case CONSOLE_SAVE:
+ console_save();
+ break;
+
+ case CONSOLE_RESTORE:
+ console_restore();
+ break;
+ default:
+ /* Nothing */;
+ }
+}
+
+void
+show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
+{
+ register int i, len = (end_line - begin_line) * width;
+
+ if (look_for_rxvt_extensions ()) {
+ show_rxvt_contents (starty, begin_line, end_line);
+ return;
+ }
+ attrset(DEFAULT_COLOR);
+ for (i = 0; i < len; i++)
+ {
+ if ((i % width) == 0)
+ move (starty+(i/width), 0);
+ addch ((unsigned char)screen[width*starty + i]);
+ }
+}
+
+#endif /* SCO_FLAVOR */
+
+
+#if !defined(linux) && !defined(__linux__) && !defined(SCO_FLAVOR)
+
+#include "tty.h"
+
+void show_console_contents (int starty, unsigned char begin_line, unsigned char end_line)
+{
+ standend ();
+
+ if (look_for_rxvt_extensions ()) {
+ show_rxvt_contents (starty, begin_line, end_line);
+ return;
+ }
+ console_flag = 0;
+}
+
+void handle_console (unsigned char action)
+{
+ look_for_rxvt_extensions ();
+}
+
+#endif /* !defined(linux) && !defined(__linux__) && !defined(SCO_FLAVOR) */
+
+
--- /dev/null
+#if defined(linux) || defined(__linux__)
+
+/* General purpose Linux console screen save/restore server
+ Copyright (C) 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+ Original idea from Unix Interactive Tools version 3.2b (tty.c)
+ This code requires root privileges.
+ You may want to make the cons.saver setuid root.
+ The code should be safe even if it is setuid but who knows?
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <termios.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h> /* For isdigit() */
+typedef struct WINDOW WINDOW;
+#include "cons.saver.h"
+
+#define cmd_input 0
+#define cmd_output 1
+
+/* Meaning of console_flag:
+ -1 == to be detected,
+ 0 == not a console
+ 1 == is a console, Linux < 1.1.67 (black & white)
+ 2 == is a console, Linux >= 1.1.67 (color)
+ 3 == is a console, Linux >= 1.1.92 (color, use /dev/vcsa$num
+ */
+static signed char console_flag = -1;
+/*
+ Meaning of console_fd:
+ -1 == not opened,
+ >=0 == opened
+ */
+static int console_fd = -1;
+static char *tty_name;
+static int len;
+static char *buffer = NULL;
+static int buffer_size = 0;
+static int columns, rows;
+static char vcs_name [40];
+static int vcs_fd;
+
+static void dwrite (int fd, char *buffer)
+{
+ write (fd, buffer, strlen (buffer));
+}
+
+static void tty_getsize ()
+{
+ struct winsize winsz;
+
+ winsz.ws_col = winsz.ws_row = 0;
+ ioctl (console_fd, TIOCGWINSZ, &winsz);
+ if (winsz.ws_col && winsz.ws_row){
+ columns = winsz.ws_col;
+ rows = winsz.ws_row;
+ } else {
+ /* Never happens (I think) */
+ dwrite (2, "TIOCGWINSZ failed\n");
+ columns = 80;
+ rows = 25;
+ console_flag = 0;
+ }
+}
+
+inline void tty_cursormove(int y, int x)
+{
+ char buffer [20];
+
+ /* Standard ANSI escape sequence for cursor positioning */
+ sprintf (buffer,"\33[%d;%dH", y + 1, x + 1);
+ dwrite (console_fd, buffer);
+}
+
+int check_file (char *filename, int check_console, char **msg)
+{
+ int fd;
+ struct stat stat_buf;
+
+ /* Avoiding race conditions: use of fstat makes sure that
+ both 'open' and 'stat' operate on the same file */
+
+ *msg = 0;
+
+ fd = open (filename, O_RDWR);
+ if (fd == -1)
+ return -1;
+
+ if (fstat (fd, &stat_buf) == -1)
+ return -1;
+
+ /* Must be character device */
+ if (!S_ISCHR (stat_buf.st_mode)){
+ *msg = "Not a character device";
+ return -1;
+ }
+
+#ifdef DEBUG
+ fprintf (stderr, "Device: %x\n", stat_buf.st_rdev);
+#endif
+ if (check_console){
+ /* Second time: must be console */
+ if ((stat_buf.st_rdev & 0xff00) != 0x0400){
+ *msg = "Not a console";
+ return -1;
+ }
+
+ if ((stat_buf.st_rdev & 0x00ff) > 63){
+ *msg = "Minor device number too big";
+ return -1;
+ }
+
+ /* Must be owned by the user */
+ if (stat_buf.st_uid != getuid ()){
+ *msg = "Not a owner";
+ return -1;
+ }
+ }
+
+ /* Everything seems to be okay */
+ return fd;
+}
+
+/* Detect console */
+/* Because the name of the tty is supplied by the user and this
+ can be a setuid program a lot of checks has to done to avoid
+ creating a security hole */
+char *detect_console (void)
+{
+ char *msg;
+ int xlen;
+
+ /* Must be console */
+ /* Handle the case for /dev/tty?? */
+ if (tty_name[len-5] == 't')
+ xlen = len - 1;
+ else
+ xlen = len;
+
+ /* General: /dev/ttyn */
+ if (tty_name[xlen - 5] != '/' ||
+ tty_name[xlen - 4] != 't' ||
+ tty_name[xlen - 3] != 't' ||
+ tty_name[xlen - 2] != 'y' ||
+ !isdigit(tty_name[xlen - 1]) ||
+ !isdigit(tty_name[len - 1]))
+ return "Doesn't look like console";
+
+ sprintf (vcs_name, "/dev/vcsa%s", tty_name + xlen - 1);
+ vcs_fd = check_file (vcs_name, 0, &msg);
+ console_fd = check_file (tty_name, 1, &msg);
+
+#ifdef DEBUG
+ fprintf (stderr, "vcs_fd = %d console_fd = %d\n", vcs_fd, console_fd);
+#endif
+
+ if (vcs_fd != -1){
+ console_flag = 3;
+ }
+
+ if (console_fd == -1)
+ return msg;
+
+ return NULL;
+}
+
+void save_console (void)
+{
+ int i;
+
+ if (!console_flag)
+ return;
+ buffer [1] = tty_name [len-1] - '0';
+ if (console_flag >= 2){
+ /* Linux >= 1.1.67 */
+ /* Get screen contents and cursor position */
+ buffer [0] = 8;
+ if (console_flag == 2){
+ if ((i = ioctl (console_fd, TIOCLINUX, buffer)) == -1){
+ /* Oops, this is not Linux 1.1.67 */
+ console_flag = 1;
+ }
+ } else {
+ lseek (vcs_fd, 0, 0);
+ read (vcs_fd, buffer, buffer_size);
+ }
+ }
+ if (console_flag == 1){
+ int index, x, y;
+
+ /* Linux < 1.1.67 */
+ /* Get screen contents */
+ buffer [0] = 0;
+ if (ioctl(console_fd, TIOCLINUX, buffer) == -1){
+ buffer[0] = buffer[1] = 0;
+
+ /* Linux bug: bad ioctl on console 8 */
+ if (ioctl(console_fd, TIOCLINUX, buffer) == -1){
+ /* Oops, this is not a console after all */
+ console_flag = 0;
+ return;
+ }
+ }
+ /* Select the beginning of the bottommost empty line
+ to be the cursor position */
+ index = 2 + rows * columns;
+ for (y = rows - 1; y >= 0; y--)
+ for (x = columns - 1; x >= 0; x--)
+ if (buffer[--index] != ' ')
+ goto non_space_found;
+ non_space_found:
+ buffer[0] = y + 1;
+ buffer[1] = 0;
+ /*tty_cursormove(y + 1, 0);*/
+ }
+}
+
+void restore_console (void)
+{
+ if (!console_flag)
+ return;
+ if (console_flag == 2){
+ /* Linux >= 1.1.67 */
+ /* Restore screen contents and cursor position */
+ buffer [0] = 9;
+ buffer [1] = tty_name [len-1] - '0';
+ ioctl (console_fd, TIOCLINUX, buffer);
+ }
+ if (console_flag == 3){
+ lseek (vcs_fd, 0, 0);
+ write (vcs_fd, buffer, buffer_size);
+ }
+ if (console_flag == 1){
+ /* Clear screen */
+ write(console_fd, "\033[H\033[2J", 7);
+ /* Output saved screen contents */
+ write(console_fd, buffer + 2, rows * columns);
+ /* Move the cursor to the previously selected position */
+ tty_cursormove(buffer[0], buffer[1]);
+ }
+}
+
+void send_contents ()
+{
+ unsigned char begin_line=0, end_line=0;
+ int index, x, y;
+ int lastline;
+ unsigned char message;
+ unsigned short bytes;
+ int bytes_per_char;
+
+ bytes_per_char = console_flag == 1 ? 1 : 2;
+
+ /* Calculate the number of used lines */
+ if (console_flag == 2 || console_flag == 1 || console_flag == 3){
+ index = (2 + rows * columns) * bytes_per_char;
+ for (y = rows - 1; y >= 0; y--)
+ for (x = columns - 1; x >= 0; x--){
+ index -= bytes_per_char;
+ if (buffer[index] != ' ')
+ goto non_space_found;
+ }
+ non_space_found:
+ lastline = y + 1;
+ } else
+ return;
+
+ /* Inform the invoker that we can handle this command */
+ message = CONSOLE_CONTENTS;
+ write (cmd_output, &message, 1);
+
+ /* Read the range of lines wanted */
+ read (cmd_input, &begin_line, 1);
+ read (cmd_input, &end_line, 1);
+ if (begin_line > lastline)
+ begin_line = lastline;
+ if (end_line > lastline)
+ end_line = lastline;
+
+ /* Tell the invoker how many bytes it will be */
+ bytes = (end_line - begin_line) * columns;
+ write (cmd_output, &bytes, 2);
+
+ /* Send the contents */
+ for (index = (2 + begin_line * columns) * bytes_per_char;
+ index < (2 + end_line * columns) * bytes_per_char;
+ index += bytes_per_char)
+ write (cmd_output, buffer + index, 1);
+
+ /* All done */
+}
+
+int main (int argc, char **argv)
+{
+ char *error;
+ unsigned char action = 0;
+
+ if (argc != 2){
+ /* Wrong number of arguments */
+
+ dwrite (2, "Usage: cons.saver <ttyname>\n");
+ console_flag = 0;
+ write (cmd_output, &console_flag, 1);
+ return 3;
+ }
+
+ /* Lose the control terminal */
+ setsid ();
+
+ /* Check that the argument is a legal console */
+ tty_name = argv [1];
+ len = strlen(tty_name);
+ error = detect_console ();
+
+ if (error){
+ /* Not a console -> no need for privileges */
+ setuid (getuid ());
+ dwrite (2, error);
+ console_flag = 0;
+ if (console_fd >= 0)
+ close (console_fd);
+ } else {
+ /* Console was detected */
+ if (console_flag != 3)
+ console_flag = 2; /* Default to Linux >= 1.1.67 */
+ /* Allocate buffer for screen image */
+ tty_getsize ();
+ buffer_size = 4 + 2 * columns * rows;
+ buffer = (char*) malloc (buffer_size);
+ }
+
+ /* If using /dev/vcs*, we don't need anymore the console fd */
+ if (console_flag == 3)
+ close (console_fd);
+
+ /* Inform the invoker about the result of the tests */
+ write (cmd_output, &console_flag, 1);
+
+ /* Read commands from the invoker */
+ while (console_flag && read (cmd_input, &action, 1)){
+ /* Handle command */
+ switch (action){
+ case CONSOLE_DONE:
+ console_flag = 0;
+ continue; /* Break while loop instead of switch clause */
+ case CONSOLE_SAVE:
+ save_console ();
+ break;
+ case CONSOLE_RESTORE:
+ restore_console ();
+ break;
+ case CONSOLE_CONTENTS:
+ send_contents ();
+ break;
+ } /* switch (action) */
+
+ /* Inform the invoker that command is handled */
+ write (cmd_output, &console_flag, 1);
+ } /* while (read ...) */
+
+ if (buffer)
+ free (buffer);
+ return 0;
+}
+
+#else
+
+#error The Linux console screen saver works only on Linux.
+
+#endif /* #ifdef linux */
--- /dev/null
+#ifndef __CONS_SAVER_H
+#define __CONS_SAVER_H
+
+#ifndef HAVE_X
+enum {
+ CONSOLE_INIT = '1',
+ CONSOLE_DONE,
+ CONSOLE_SAVE,
+ CONSOLE_RESTORE,
+ CONSOLE_CONTENTS
+};
+
+extern signed char console_flag;
+
+void show_console_contents (int starty, unsigned char begin_line, unsigned char end_line);
+void handle_console (unsigned char action);
+
+void show_rxvt_contents (int starty, unsigned char y1, unsigned char y2);
+int look_for_rxvt_extensions (void);
+
+/* Used only in the principal program */
+extern int cons_saver_pid;
+
+#else /* HAVE_X */
+# define console_flag 0
+# define show_console_contents(w,f,l) { }
+# define handle_console(x) { }
+#endif
+
+#endif /* __CONS_SAVER_H */
--- /dev/null
+#! /usr/bin/awk -f
+# This is an awk script which does dependencies. We do NOT want it to
+# recursively follow #include directives.
+# We only add to dependencies those files which are inside of the rootdir
+# tree :)
+
+#
+# Surely there is a more elegant way to see if a file exists. Anyone know
+# what it is?
+#
+function fileExists(f, TMP, dummy, result) {
+ if(result=FILEHASH[f]) {
+ if(result=="Yes") {
+ return "Yes"
+ } else {return ""}
+ }
+ ERRNO = getline dummy < f
+ if(ERRNO >= 0) {
+ close(f)
+ return FILEHASH[f]="Yes"
+ } else {
+ FILEHASH[f]="No"
+ return ""
+ }
+}
+
+function Canonic(path) {
+ while (path ~ "/[^/]*/\\.\\./")
+ gsub("/[^/]*/\\.\\./","/",path)
+ return path
+}
+
+BEGIN{
+ hasdep=0
+ objprefix=""
+ USEDC=0
+ if(dolib) {
+ # dolib = "libdirectory libname"
+ split(dolib, dlib)
+ I=0
+ rootdir=srcdir
+ sub("/$","",rootdir)
+ sub("/[^/]*$","",rootdir)
+ while (getline > 0) {
+ if ($0 ~ "OBJS") {
+ objs=$0
+ } else if ($0 ~ "^/.*\\.h: \\\\$") {
+ sub(": \\\\$","",$0)
+ USED[USEDC]=$0
+ ++USEDC
+ }
+ }
+ sub("^OBJS=[ ]*\"[ ]*","",objs)
+ sub("\"[ ]*","",objs)
+ split(objs, obj)
+ printf "%s: ", dlib[2]
+ sub("/$","", dlib[1])
+ objprefix=dlib[1]"/"
+ for (fname in obj) {
+ fullname=dlib[1]"/"obj[fname]
+ printf " \\\n %s", fullname
+ sub("\\.o$",".c",obj[fname])
+ ARGV[ARGC]=obj[fname]
+ ++ARGC
+ }
+ printf "\n"
+ }
+ if(!hpath) {
+ print "hpath is not set"
+ exit 1
+ }
+ if(!srcdir) {
+ print "srcdir is not set"
+ exit 1
+ }
+ sub("[/ ]*$","",srcdir)
+ srcdir=srcdir"/"
+ sub("^\./$","",srcdir)
+ split(hpath, parray)
+ for(path in parray) {
+ sub("^-I","",parray[path])
+ sub("[/ ]*$","",parray[path])
+ parray[path]=Canonic(parray[path])
+ }
+ for(path in ARGV) {
+ USED[USEDC]=Canonic(srcdir""ARGV[path])
+ ++USEDC
+ }
+}
+
+/^#[ ]*include[ ]*[<"][^ ]*[>"]/{
+ found=0
+ if(LASTFILE!=FILENAME) {
+ if (hasdep) {
+ print cmd
+ hasdep=0
+ }
+ cmd=""
+ LASTFILE=FILENAME
+ depname=FILENAME
+ relpath=FILENAME
+ sub("\\.c$",".o: ",depname)
+ if (depname==FILENAME) {
+ depname=srcdir""depname
+ depname=Canonic(depname)
+ cmd="\n\t@touch "depname
+ } else
+ depname=objprefix""depname
+ sub("\\.h$",".h: ",depname)
+ if(relpath ~ "^\\." ) {
+ sub("[^/]*$","", relpath)
+ relpath=relpath"/"
+ sub("//","/", relpath)
+ } else {
+ relpath=""
+ }
+ }
+ fname=$0
+ sub("^#[ ]*include[ ]*[<\"]","",fname)
+ sub("[>\"].*","",fname)
+ if(fileExists(relpath""fname)) {
+ found=1
+ if (!hasdep) {
+ printf "%s", depname
+ hasdep=1
+ }
+ fullname=Canonic(srcdir""relpath""fname)
+ printf " \\\n %s", fullname
+ if(fname ~ "^\\." ) {
+ partname=relpath""fname
+ afound=0
+ for(name in USED) {
+ if (USED[name] == fullname) {
+ afound=1
+ break
+ }
+ }
+ if (!afound) {
+ ARGV[ARGC]=partname
+ ++ARGC
+ USED[USEDC]=fullname
+ ++USEDC
+ }
+ }
+ } else {
+ for(path in parray) {
+ if(fileExists(parray[path]"/"fname)) {
+ found=1
+ if (!hasdep) {
+ printf "%s", depname
+ hasdep=1
+ }
+ printf " \\\n %s", parray[path]"/"fname
+ }
+ }
+ }
+}
+
+END{
+ if (hasdep) {
+ print cmd
+ }
+}
--- /dev/null
+/* Dialog managing.
+ Copyright (C) 1994 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <stdio.h>
+#include <stdlib.h> /* For free() */
+#include <stdarg.h>
+#include <sys/types.h>
+#include <string.h>
+#include "x.h"
+#include "mad.h"
+#include "global.h"
+#include "util.h"
+#include "dialog.h"
+#include "color.h"
+#include "win.h"
+#include "mouse.h"
+#include "main.h"
+#include "key.h" /* For mi_getch() */
+#include "dlg.h" /* draw_box, yes I know, it's silly */
+#include "background.h" /* we_are_background definition */
+
+/* "$Id: dialog.c,v 1.1 2001/12/30 09:55:26 sedwards Exp $" */
+
+Refresh *refresh_list = 0;
+
+void push_refresh (void (*new_refresh)(void *), void *parameter, int flags)
+{
+ Refresh *new;
+
+ new = xmalloc (sizeof (Refresh), "push_refresh");
+ new->next = (struct Refresh *) refresh_list;
+ new->refresh_fn = new_refresh;
+ new->parameter = parameter;
+ new->flags = flags;
+ refresh_list = new;
+}
+
+void pop_refresh (void)
+{
+ Refresh *old;
+
+ if (!refresh_list)
+ fprintf (stderr, _("\n\n\nrefresh stack underflow!\n\n\n"));
+ else {
+ old = refresh_list;
+ refresh_list = refresh_list->next;
+ free (old);
+ }
+}
+
+static void do_complete_refresh (Refresh *refresh_list)
+{
+ if (!refresh_list)
+ return;
+
+ if (refresh_list->flags != REFRESH_COVERS_ALL)
+ do_complete_refresh (refresh_list->next);
+
+ (*(refresh_list->refresh_fn))(refresh_list->parameter);
+}
+
+void do_refresh (void)
+{
+ if (we_are_background)
+ return;
+ if (!refresh_list)
+ return;
+ else {
+ if (fast_refresh)
+ (*(refresh_list->refresh_fn))(refresh_list->parameter);
+ else {
+ do_complete_refresh (refresh_list);
+ }
+ }
+}
+
+/* Poor man's window puts, it doesn't handle auto-wrap */
+void my_wputs (int y, int x, char *text)
+{
+ char p;
+
+ move (y, x);
+ while ((p = *text++) != 0){
+ if (p == '\n')
+ move (++y, x);
+ else
+ addch ((unsigned char)p);
+ }
+}
+
--- /dev/null
+#ifndef __DIALOG_H
+#define __DIALOG_H
+
+#include "dlg.h"
+
+#define MSG_ERROR ((char *) -1)
+Dlg_head *message (int error, char *header, char *text, ...);
+
+int query_dialog (char *header, char *text, int flags, int count, ...);
+
+enum {
+ D_NORMAL = 0,
+ D_ERROR = 1,
+ D_INSERT = 2
+} /* dialog options */;
+
+/* The refresh stack */
+typedef struct Refresh {
+ void (*refresh_fn)(void *);
+ void *parameter;
+ int flags;
+ struct Refresh *next;
+} Refresh;
+
+/* We search under the stack until we find a refresh function that covers */
+/* the complete screen, and from this point we go up refreshing the */
+/* individual regions */
+
+enum {
+ REFRESH_COVERS_PART, /* If the refresh fn convers only a part */
+ REFRESH_COVERS_ALL /* If the refresh fn convers all the screen */
+};
+
+void push_refresh (void (*new_refresh)(void *), void *data, int flags);
+void pop_refresh (void);
+void do_refresh (void);
+void my_wputs (int y, int x, char *text);
+char *input_dialog (char *header, char *text, char *def_text);
+char *input_expand_dialog (char *header, char *text, char *def_text);
+
+extern Refresh *refresh_list;
+
+#endif /* __DIALOG_H */
--- /dev/null
+/* Directory routines
+ Copyright (C) 1994 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include "fs.h"
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include "x.h"
+#include "mad.h"
+#include "global.h"
+#define DIR_H_INCLUDE_HANDLE_DIRENT
+#include "dir.h"
+#include "util.h"
+#include "tree.h"
+#include "../vfs/vfs.h"
+
+/* "$Id: dir.c,v 1.1 2001/12/30 09:55:26 sedwards Exp $" */
+
+/* If true show files starting with a dot */
+int show_dot_files = 1;
+
+/* If true show files ending in ~ */
+int show_backups = 0;
+
+/* If false then directories are shown separately from files */
+int mix_all_files = 0;
+
+/* Reverse flag */
+static int reverse = 1;
+
+/* Are the files sorted case sensitively? */
+static int case_sensitive = OS_SORT_CASE_SENSITIVE_DEFAULT;
+
+#define MY_ISDIR(x) ( (S_ISDIR (x->buf.st_mode) || x->f.link_to_dir) ? 1 : 0)
+
+sort_orders_t sort_orders [SORT_TYPES_TOTAL] = {
+ { N_("&Unsorted"), unsorted },
+ { N_("&Name"), sort_name },
+ { N_("&Extension"), sort_ext },
+ { N_("&Modify time"), sort_time },
+ { N_("&Access time"), sort_atime },
+ { N_("&Change time"), sort_ctime },
+ { N_("&Size"), sort_size },
+ { N_("&Inode"), sort_inode },
+
+ /* New sort orders */
+ { N_("&Type"), sort_type },
+ { N_("&Links"), sort_links },
+ { N_("N&GID"), sort_ngid },
+ { N_("N&UID"), sort_nuid },
+ { N_("&Owner"), sort_owner },
+ { N_("&Group"), sort_group }
+};
+
+#define string_sortcomp(a,b) (case_sensitive ? strcmp (a,b) : strcasecmp (a,b))
+
+int
+unsorted (const file_entry *a, const file_entry *b)
+{
+ return 0;
+}
+
+int
+sort_name (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return string_sortcomp (a->fname, b->fname) * reverse;
+ return bd-ad;
+}
+
+int
+sort_ext (const file_entry *a, const file_entry *b)
+{
+ char *exta, *extb;
+ int r;
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files){
+ exta = extension (a->fname);
+ extb = extension (b->fname);
+ r = string_sortcomp (exta, extb);
+ if (r)
+ return r * reverse;
+ else
+ return sort_name (a, b);
+ } else
+ return bd-ad;
+}
+
+int
+sort_owner (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return string_sortcomp (get_owner (a->buf.st_uid), get_owner (a->buf.st_uid)) * reverse;
+ return bd-ad;
+}
+
+int
+sort_group (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return string_sortcomp (get_group (a->buf.st_gid), get_group (a->buf.st_gid)) * reverse;
+ return bd-ad;
+}
+
+int
+sort_time (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (a->buf.st_mtime - b->buf.st_mtime) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_ctime (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (a->buf.st_ctime - b->buf.st_ctime) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_atime (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (a->buf.st_atime - b->buf.st_atime) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_inode (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (a->buf.st_ino - b->buf.st_ino) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_size (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (b->buf.st_size - a->buf.st_size) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_links (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (b->buf.st_nlink - a->buf.st_nlink) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_ngid (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (b->buf.st_gid - a->buf.st_gid) * reverse;
+ else
+ return bd-ad;
+}
+
+int
+sort_nuid (const file_entry *a, const file_entry *b)
+{
+ int ad = MY_ISDIR (a);
+ int bd = MY_ISDIR (b);
+
+ if (ad == bd || mix_all_files)
+ return (b->buf.st_uid - a->buf.st_uid) * reverse;
+ else
+ return bd-ad;
+}
+
+inline static int
+file_type_to_num (const file_entry *fe)
+{
+ const struct stat *s = &fe->buf;
+
+ if (S_ISDIR (s->st_mode))
+ return 0;
+ if (S_ISLNK (s->st_mode)){
+ if (fe->f.link_to_dir)
+ return 1;
+ if (fe->f.stalled_link)
+ return 2;
+ else
+ return 3;
+ }
+ if (S_ISSOCK (s->st_mode))
+ return 4;
+ if (S_ISCHR (s->st_mode))
+ return 5;
+ if (S_ISBLK (s->st_mode))
+ return 6;
+ if (S_ISFIFO (s->st_mode))
+ return 7;
+ if (is_exe (s->st_mode))
+ return 8;
+ return 9;
+}
+
+int
+sort_type (const file_entry *a, const file_entry *b)
+{
+ int aa = file_type_to_num (a);
+ int bb = file_type_to_num (b);
+
+ return bb-aa;
+}
+
+
+void
+do_sort (dir_list *list, sortfn *sort, int top, int reverse_f, int case_sensitive_f)
+{
+ int i;
+ file_entry tmp_fe;
+
+ for (i = 0; i < top + 1; i++) { /* put ".." first in list */
+ if (!strcmp (list->list [i].fname, "..")) {
+ if (i > 0) { /* swap [i] and [0] */
+ memcpy (&tmp_fe, &(list->list [0]), sizeof (file_entry));
+ memcpy (&(list->list [0]), &(list->list [i]), sizeof (file_entry));
+ memcpy (&(list->list [i]), &tmp_fe, sizeof (file_entry));
+ }
+ break;
+ }
+ }
+
+ reverse = reverse_f ? -1 : 1;
+ case_sensitive = case_sensitive_f;
+ qsort (&(list->list) [1], top, sizeof (file_entry), sort);
+}
+
+void clean_dir (dir_list *list, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++){
+ free (list->list [i].fname);
+ list->list [i].fname = 0;
+ if (list->list [i].cache != NULL) {
+ free (list->list [i].cache);
+ list->list [i].cache = NULL;
+ }
+ }
+}
+
+static int
+add_dotdot_to_list (dir_list *list, int index)
+{
+ char buffer [MC_MAXPATHLEN + MC_MAXPATHLEN];
+ char *p, *s;
+ int i = 0;
+
+ /* Need to grow the *list? */
+ if (index == list->size) {
+ list->list = realloc (list->list, sizeof (file_entry) *
+ (list->size + RESIZE_STEPS));
+ if (!list->list)
+ return 0;
+ list->size += RESIZE_STEPS;
+ }
+
+ (list->list) [index].fnamelen = 2;
+ (list->list) [index].fname = strdup ("..");
+ (list->list) [index].cache = NULL;
+ (list->list) [index].f.link_to_dir = 0;
+ (list->list) [index].f.stalled_link = 0;
+
+ /* FIXME: We need to get the panel definition! to use file_mark */
+ (list->list) [index].f.marked = 0;
+ mc_get_current_wd (buffer, sizeof (buffer) - 1 );
+ if (buffer [strlen (buffer) - 1] == PATH_SEP)
+ buffer [strlen (buffer) - 1] = 0;
+ for (;;) {
+ strcat (buffer, PATH_SEP_STR "..");
+ p = vfs_canon (buffer);
+ if (mc_stat (p, &((list->list) [index].buf)) != -1){
+ free (p);
+ break;
+ }
+ i = 1;
+ if ((s = vfs_path (p)) && !strcmp (s, PATH_SEP_STR)){
+ free (p);
+ return 1;
+ }
+ strcpy (buffer, p);
+ free (p);
+ }
+
+/* Commented out to preserve a usable '..'. What's the purpose of this
+ * three lines? (Norbert) */
+#if 0
+ if (i) { /* So there is bogus information on the .. directory's stat */
+ (list->list) [index].buf.st_mode &= ~0444;
+ }
+#endif
+ return 1;
+}
+
+/* Used to set up a directory list when there is no access to a directory */
+int set_zero_dir (dir_list *list)
+{
+ return (add_dotdot_to_list (list, 0));
+}
+
+/* If you change handle_dirent then check also handle_path. */
+/* Return values: -1 = failure, 0 = don't add, 1 = add to the list */
+int handle_dirent (dir_list *list, char *filter, struct dirent *dp,
+ struct stat *buf1, int next_free, int *link_to_dir,
+ int *stalled_link)
+{
+ if (dp->d_name [0] == '.' && dp->d_name [1] == 0)
+ return 0;
+ if (!show_dot_files){
+ if (dp->d_name [0] == '.'){
+ if (!(dp->d_name [1] == 0))
+ if (!(dp->d_name [1] == '.' && NLENGTH (dp) == 2))
+ return 0;
+ }
+ }
+ if (!show_backups && dp->d_name [NLENGTH (dp)-1] == '~')
+ return 0;
+ if (mc_lstat (dp->d_name, buf1) == -1)
+ return 0;
+
+ if (S_ISDIR (buf1->st_mode))
+ tree_check (dp->d_name);
+
+ /* A link to a file or a directory? */
+ *link_to_dir = 0;
+ *stalled_link = 0;
+ if (S_ISLNK(buf1->st_mode)){
+ struct stat buf2;
+ if (!mc_stat (dp->d_name, &buf2))
+ *link_to_dir = S_ISDIR(buf2.st_mode) != 0;
+ else
+ *stalled_link = 1;
+ }
+ if (!(S_ISDIR(buf1->st_mode) || *link_to_dir) && filter &&
+ !regexp_match (filter, dp->d_name, match_file))
+ return 0;
+
+ /* Need to grow the *list? */
+ if (next_free == list->size){
+ list->list = realloc (list->list, sizeof (file_entry) *
+ (list->size + RESIZE_STEPS));
+ if (!list->list)
+ return -1;
+ list->size += RESIZE_STEPS;
+ }
+ return 1;
+}
+
+/* handle_path is a simplified handle_dirent. The difference is that
+ handle_path doesn't pay attention to show_dot_files and show_backups.
+ Moreover handle_path can't be used with a filemask.
+ If you change handle_path then check also handle_dirent. */
+/* Return values: -1 = failure, 0 = don't add, 1 = add to the list */
+int handle_path (dir_list *list, char *path,
+ struct stat *buf1, int next_free, int *link_to_dir,
+ int *stalled_link)
+{
+ if (path [0] == '.' && path [1] == 0)
+ return 0;
+ if (mc_lstat (path, buf1) == -1)
+ return 0;
+
+ if (S_ISDIR (buf1->st_mode))
+ tree_check (path);
+
+ /* A link to a file or a directory? */
+ *link_to_dir = 0;
+ *stalled_link = 0;
+ if (S_ISLNK(buf1->st_mode)){
+ struct stat buf2;
+ if (!mc_stat (path, &buf2))
+ *link_to_dir = S_ISDIR(buf2.st_mode) != 0;
+ else
+ *stalled_link = 1;
+ }
+
+ /* Need to grow the *list? */
+ if (next_free == list->size){
+ list->list = realloc (list->list, sizeof (file_entry) *
+ (list->size + RESIZE_STEPS));
+ if (!list->list)
+ return -1;
+ list->size += RESIZE_STEPS;
+ }
+ return 1;
+}
+
+int do_load_dir(dir_list *list, sortfn *sort, int reverse, int case_sensitive, char *filter)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int status, link_to_dir, stalled_link;
+ int next_free = 0;
+ struct stat buf;
+ int dotdot_found = 0;
+
+ start_tree_check (NULL);
+
+ dirp = mc_opendir (".");
+ if (!dirp){
+ return set_zero_dir (list);
+ }
+ for (dp = mc_readdir (dirp); dp; dp = mc_readdir (dirp)){
+ status = handle_dirent (list, filter, dp, &buf, next_free, &link_to_dir,
+ &stalled_link);
+ if (status == 0)
+ continue;
+ if (status == -1)
+ return next_free;
+ list->list [next_free].fnamelen = NLENGTH (dp);
+ list->list [next_free].fname = strdup (dp->d_name);
+ list->list [next_free].cache = NULL;
+ list->list [next_free].f.marked = 0;
+ list->list [next_free].f.link_to_dir = link_to_dir;
+ list->list [next_free].f.stalled_link = stalled_link;
+ list->list [next_free].buf = buf;
+ if (strcmp (dp->d_name, ".." ) == 0)
+ dotdot_found = 1;
+ next_free++;
+ if (!(next_free % 32))
+ rotate_dash ();
+ }
+
+ if (next_free) {
+ if (!dotdot_found)
+ add_dotdot_to_list (list, next_free++);
+ do_sort (list, sort, next_free-1, reverse, case_sensitive);
+ }
+ else
+ return set_zero_dir (list);
+
+ mc_closedir (dirp);
+ end_tree_check (NULL);
+ return next_free;
+}
+
+int link_isdir (file_entry *file)
+{
+ struct stat b;
+
+ if (S_ISLNK (file->buf.st_mode)){
+ mc_stat (file->fname, &b);
+ if (S_ISDIR (b.st_mode))
+ return 1;
+ }
+ return 0;
+}
+
+int if_link_is_exe (file_entry *file)
+{
+ struct stat b;
+
+ if (S_ISLNK (file->buf.st_mode)){
+ mc_stat (file->fname, &b);
+ return is_exe (b.st_mode);
+ }
+ return 1;
+}
+
+static dir_list dir_copy = { 0, 0 };
+
+static void alloc_dir_copy (int size)
+{
+ int i;
+
+ if (dir_copy.size < size){
+ if (dir_copy.list){
+
+ for (i = 0; i < dir_copy.size; i++) {
+ if (dir_copy.list [i].fname)
+ free (dir_copy.list [i].fname);
+ if (dir_copy.list [i].cache)
+ free (dir_copy.list [i].cache);
+ }
+ free (dir_copy.list);
+ dir_copy.list = 0;
+ }
+
+ dir_copy.list = xmalloc (sizeof (file_entry) * size, "alloc_dir_copy");
+ for (i = 0; i < size; i++) {
+ dir_copy.list [i].fname = 0;
+ dir_copy.list [i].cache = NULL;
+ }
+ dir_copy.size = size;
+ }
+}
+
+/* If filter is null, then it is a match */
+int do_reload_dir (dir_list *list, sortfn *sort, int count, int rev,
+ int case_sensitive, char *filter)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ int next_free = 0;
+ int i, found, status, link_to_dir, stalled_link;
+ struct stat buf;
+ int tmp_len; /* For optimisation */
+ int dotdot_found = 0;
+
+ start_tree_check (NULL);
+ dirp = mc_opendir (".");
+ if (!dirp) {
+ clean_dir (list, count);
+ return set_zero_dir (list);
+ }
+
+ alloc_dir_copy (list->size);
+ for (i = 0; i < count; i++){
+ dir_copy.list [i].fnamelen = list->list [i].fnamelen;
+ dir_copy.list [i].fname = list->list [i].fname;
+ dir_copy.list [i].cache = list->list [i].cache;
+ dir_copy.list [i].f.marked = list->list [i].f.marked;
+ dir_copy.list [i].f.link_to_dir = list->list [i].f.link_to_dir;
+ dir_copy.list [i].f.stalled_link = list->list [i].f.stalled_link;
+ }
+
+ for (dp = mc_readdir (dirp); dp; dp = mc_readdir (dirp)){
+ status = handle_dirent (list, filter, dp, &buf, next_free, &link_to_dir,
+ &stalled_link);
+ if (status == 0)
+ continue;
+ if (status == -1) {
+ mc_closedir (dirp);
+ /* Norbert (Feb 12, 1997):
+ Just in case someone finds this memory leak:
+ -1 means big trouble (at the moment no memory left),
+ I don't bother with further cleanup because if one gets to
+ this point he will have more problems than a few memory
+ leaks and because one 'clean_dir' would not be enough (and
+ because I don't want to spent the time to make it working,
+ IMHO it's not worthwhile).
+ clean_dir (&dir_copy, count);
+ */
+ return next_free;
+ }
+
+ tmp_len = NLENGTH (dp);
+ for (found = i = 0; i < count; i++)
+ if (tmp_len == dir_copy.list [i].fnamelen
+ && !strcmp (dp->d_name, dir_copy.list [i].fname)){
+ list->list [next_free].f.marked = dir_copy.list [i].f.marked;
+ found = 1;
+ break;
+ }
+
+ if (!found)
+ list->list [next_free].f.marked = 0;
+
+ list->list [next_free].fnamelen = tmp_len;
+ list->list [next_free].fname = strdup (dp->d_name);
+ list->list [next_free].cache = NULL;
+ list->list [next_free].f.link_to_dir = link_to_dir;
+ list->list [next_free].f.stalled_link = stalled_link;
+ list->list [next_free].buf = buf;
+ if (strcmp (dp->d_name, ".." ) == 0)
+ dotdot_found = 1;
+ next_free++;
+ if (!(next_free % 16))
+ rotate_dash ();
+ }
+ mc_closedir (dirp);
+ end_tree_check (NULL);
+ if (next_free) {
+ if (!dotdot_found)
+ add_dotdot_to_list (list, next_free++);
+ do_sort (list, sort, next_free-1, rev, case_sensitive);
+ }
+ else
+ next_free = set_zero_dir (list);
+ clean_dir (&dir_copy, count);
+ return next_free;
+}
+
+char *sort_type_to_name (sortfn *sort_fn)
+{
+ int i;
+
+ for (i = 0; i < SORT_TYPES; i++)
+ if ((sortfn *) (sort_orders [i].sort_fn) == sort_fn)
+ return _(sort_orders [i].sort_name);
+
+ return _("Unknown");
+}
+
+sortfn *sort_name_to_type (char *sname)
+{
+ int i;
+
+ for (i = 0; i < SORT_TYPES; i++)
+ if (strcasecmp (sort_orders [i].sort_name, sname) == 0)
+ return (sortfn *) sort_orders [i].sort_fn;
+
+ /* default case */
+ return (sortfn *) sort_name;
+}
+
--- /dev/null
+#ifndef __DIR_H
+#define __DIR_H
+
+#define MIN_FILES 128
+#define RESIZE_STEPS 128
+
+typedef struct {
+
+ /* File attributes */
+
+ int fnamelen;
+ char *fname;
+ struct stat buf;
+
+ /* Flags */
+ struct {
+ unsigned int marked:1; /* File marked in pane window */
+ unsigned int exists:1; /* Use for rereading file */
+ unsigned int link_to_dir:1; /* If this is a link, does it point to directory? */
+ unsigned int stalled_link:1; /* If this is a symlink and points to Charon's land */
+ } f;
+ char *cache;
+} file_entry;
+
+typedef struct {
+ file_entry *list;
+ int size;
+} dir_list;
+
+typedef int sortfn (const void *, const void *);
+int do_load_dir (dir_list *list, sortfn *sort, int reverse, int case_sensitive, char *filter);
+void do_sort (dir_list *list, sortfn *sort, int top, int reverse, int case_sensitive);
+dir_list *do_collect_stat (dir_list *dir, int top);
+int do_reload_dir (dir_list *list, sortfn *sort, int count, int reverse, int case_sensitive, char *filter);
+void clean_dir (dir_list *list, int count);
+int set_zero_dir (dir_list *list);
+
+#ifdef DIR_H_INCLUDE_HANDLE_DIRENT
+int handle_dirent (dir_list *list, char *filter, struct dirent *dp,
+ struct stat *buf1, int next_free, int *link_to_dir, int *stalled_link);
+int handle_path (dir_list *list, char *path, struct stat *buf1, int next_free,
+ int *link_to_dir, int *stalled_link);
+#endif
+
+/* Sorting functions */
+int unsorted (const file_entry *a, const file_entry *b);
+int sort_name (const file_entry *a, const file_entry *b);
+int sort_ext (const file_entry *a, const file_entry *b);
+int sort_time (const file_entry *a, const file_entry *b);
+int sort_atime (const file_entry *a, const file_entry *b);
+int sort_ctime (const file_entry *a, const file_entry *b);
+int sort_size (const file_entry *a, const file_entry *b);
+int sort_inode (const file_entry *a, const file_entry *b);
+int sort_type (const file_entry *a, const file_entry *b);
+int sort_links (const file_entry *a, const file_entry *b);
+int sort_nuid (const file_entry *a, const file_entry *b);
+int sort_ngid (const file_entry *a, const file_entry *b);
+int sort_owner (const file_entry *a, const file_entry *b);
+int sort_group (const file_entry *a, const file_entry *b);
+
+/* SORT_TYPES is used to build the nice dialog box entries */
+#define SORT_TYPES 8
+
+/* This is the number of sort types not available in that dialog box */
+#define SORT_TYPES_EXTRA 6
+
+/* The total, used by Tk version */
+#define SORT_TYPES_TOTAL (SORT_TYPES + SORT_TYPES_EXTRA)
+
+typedef struct {
+ char *sort_name;
+ int (*sort_fn)(const file_entry *, const file_entry *);
+} sort_orders_t;
+
+extern sort_orders_t sort_orders [SORT_TYPES_TOTAL];
+
+int link_isdir (file_entry *);
+int if_link_is_exe (file_entry *file);
+
+extern int show_backups;
+extern int show_dot_files;
+extern int show_backups;
+extern int mix_all_files;
+
+char *sort_type_to_name (sortfn *);
+sortfn *sort_name_to_type (char *type);
+
+#endif /* __DIR_H */
--- /dev/null
+/* Dlg box features module for the Midnight Commander
+ Copyright (C) 1994, 1995 Radek Doulik, Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+/* "$Id: dlg.c,v 1.1 2001/12/30 09:55:26 sedwards Exp $" */
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include <ctype.h>
+#include "tty.h"
+#include <stdarg.h>
+#include "mad.h"
+#include "x.h"
+#include "util.h"
+#include "menu.h"
+#include "global.h"
+#include "win.h"
+#include "color.h"
+#include "mouse.h"
+#include "help.h"
+#include "key.h" /* For mi_getch() */
+#include "dlg.h"
+#include "dialog.h" /* For push_refresh() and pop_refresh() */
+#include "layout.h"
+#include "main.h"
+
+/* This is the current frame, used to group Tk packings */
+char *the_frame = "";
+
+#define waddc(w,y1,x1,c) move (w->y+y1, w->x+x1); addch (c)
+
+/* Primitive way to check if the the current dialog is our dialog */
+/* This is needed by async routines like load_prompt */
+Dlg_head *current_dlg = 0;
+
+/* A hook list for idle events */
+Hook *idle_hook = 0;
+
+#ifndef PORT_HAS_SET_IDLE
+# define x_set_idle(d,x)
+#endif
+
+#ifndef PORT_HAS_DIALOG_STOP
+# define x_dialog_stop(d)
+#endif
+
+static void slow_box (Dlg_head *h, int y, int x, int ys, int xs)
+{
+ move (h->y+y, h->x+x);
+ hline (' ', xs);
+ vline (' ', ys);
+ move (h->y+y, h->x+x+xs-1);
+ vline (' ', ys);
+ move (h->y+y+ys-1, h->x+x);
+ hline (' ', xs);
+}
+
+/* draw box in window */
+void draw_box (Dlg_head *h, int y, int x, int ys, int xs)
+{
+ extern int slow_terminal;
+
+ if (slow_terminal){
+ slow_box (h, y, x, ys, xs);
+ return;
+ }
+
+#ifndef HAVE_SLANG
+ waddc (h, y, x, ACS_ULCORNER);
+ hline (ACS_HLINE, xs - 2);
+ waddc (h, y + ys - 1, x, ACS_LLCORNER);
+ hline (ACS_HLINE, xs - 2);
+
+ waddc (h, y, x + xs - 1, ACS_URCORNER);
+ waddc (h, y + ys - 1, x + xs - 1, ACS_LRCORNER);
+
+ move (h->y+y+1, h->x+x);
+ vline (ACS_VLINE, ys - 2);
+ move (h->y+y+1, h->x+x+xs-1);
+ vline (ACS_VLINE, ys - 2);
+#else
+ SLsmg_draw_box (h->y+y, h->x+x, ys, xs);
+#endif
+}
+
+/* draw box in window */
+void draw_double_box (Dlg_head *h, int y, int x, int ys, int xs)
+{
+#ifndef HAVE_SLANG
+ draw_box (h, y, x, ys, xs);
+#else
+ SLsmg_draw_double_box (h->y+y, h->x+x, ys, xs);
+#endif
+}
+
+void widget_erase (Widget *w)
+{
+ int x, y;
+
+ for (y = 0; y < w->lines; y++){
+ widget_move (w, y, 0);
+ for (x = 0; x < w->cols; x++)
+ addch (' ');
+ }
+}
+
+void dlg_erase (Dlg_head *h)
+{
+ int x, y;
+
+ for (y = 0; y < h->lines; y++){
+ move (y+h->y, h->x); /* FIXME: should test if ERR */
+ for (x = 0; x < h->cols; x++){
+ addch (' ');
+ }
+ }
+}
+
+void init_widget (Widget *w, int y, int x, int lines, int cols,
+ int (*callback)(Dlg_head *, void *, int, int),
+ destroy_fn destroy, mouse_h mouse_handler, char *tkname)
+{
+ w->x = x;
+ w->y = y;
+ w->cols = cols;
+ w->lines = lines;
+ w->color = -1;
+ w->callback = callback;
+ w->destroy = destroy;
+ w->mouse = mouse_handler;
+ w->wdata = 0;
+ w->wcontainer = 0;
+ w->frame = "";
+ w->parent = 0;
+ w->tkname = tkname;
+
+ if (tkname && *tkname == 0){
+ fprintf (stderr, "Got a null string for the tkname\n");
+ abort ();
+ }
+ /* Almost all widgets want to put the cursor in a suitable place */
+ w->options = W_WANT_CURSOR;
+}
+
+int default_proc (Dlg_head *h, int Msg, int Par)
+{
+ switch (Msg){
+
+ case WIDGET_HOTKEY: /* Didn't use the key */
+ return 0;
+
+ case WIDGET_INIT: /* We could tell if something went wrong */
+ return 1;
+
+ case WIDGET_KEY:
+ return 0; /* Didn't use the key */
+
+ case WIDGET_FOCUS: /* We accept FOCUSes */
+ if (h->current)
+ x_focus_widget (h->current);
+ return 1;
+
+ case WIDGET_UNFOCUS: /* We accept loose FOCUSes */
+ if (h->current)
+ x_unfocus_widget (h->current);
+ return 1;
+
+ case WIDGET_DRAW:
+ return 1;
+
+ case WIDGET_DESTROY:
+ return 1;
+
+ case WIDGET_CURSOR:
+ /* Move the cursor to the default widget position */
+ return 1;
+
+ case WIDGET_IDLE:
+ return 1;
+ }
+ printf ("Internal error: unhandled message: %d\n", Msg);
+ return 1;
+}
+
+int default_dlg_callback (Dlg_head *h, int id, int msg)
+{
+ if (msg == DLG_IDLE){
+ dlg_broadcast_msg_to (h, WIDGET_IDLE, 0, W_WANT_IDLE);
+ }
+ return 0;
+}
+
+#ifdef HAVE_X
+int midnight_callback (struct Dlg_head *h, int id, int msg);
+#endif
+Dlg_head *create_dlg (int y1, int x1, int lines, int cols,
+ int *color_set,
+ int (*callback) (struct Dlg_head *, int, int),
+ char *help_ctx, char *name,
+ int flags)
+{
+ Dlg_head *new_d;
+
+ if (flags & DLG_CENTER){
+ y1 = (LINES-lines)/2;
+ x1 = (COLS-cols)/2;
+ }
+ if ((flags & DLG_TRYUP) && (y1 > 3))
+ y1 -= 2;
+
+ new_d = (Dlg_head *) malloc (sizeof (Dlg_head));
+ new_d->current = NULL;
+ new_d->count = 0;
+ new_d->direction = DIR_FORWARD;
+ new_d->color = color_set;
+ new_d->help_ctx = help_ctx;
+ new_d->callback = callback ? callback : default_dlg_callback;
+ new_d->send_idle_msg = 0;
+ new_d->x = x1;
+ new_d->y = y1;
+ new_d->title = 0;
+ new_d->cols = cols;
+ new_d->lines = lines;
+ new_d->refresh_pushed = 0;
+ new_d->has_menubar = 0;
+ new_d->name = name;
+ new_d->raw = 0;
+ new_d->grided = 0;
+ new_d->initfocus = NULL;
+ new_d->running = 0;
+#ifdef HAVE_X
+ if (callback != midnight_callback)
+ new_d->wdata = xtoolkit_create_dialog (new_d, flags);
+ else
+ new_d->wdata = xtoolkit_get_main_dialog (new_d);
+#endif
+ return (new_d);
+}
+
+void set_idle_proc (Dlg_head *d, int state)
+{
+ d->send_idle_msg = state;
+ x_set_idle (d, state);
+}
+
+/* add component to dialog buffer */
+int add_widgetl (Dlg_head *where, void *what, WLay layout)
+{
+ Widget_Item *back;
+ Widget *widget = (Widget *) what;
+
+ /* Only used by Tk */
+ widget->frame = the_frame;
+
+ widget->layout = layout;
+ /* Don't accept 0 widgets, this could be from widgets that could not */
+ /* initialize properly */
+ if (!what)
+ return 0;
+
+ widget->x += where->x;
+ widget->y += where->y;
+
+ if (where->running){
+ Widget_Item *point = where->current;
+
+ where->current = (Widget_Item *) malloc (sizeof (Widget_Item));
+
+ if (point){
+ where->current->next = point->next;
+ where->current->prev = point;
+ point->next->prev = where->current;
+ point->next = where->current;
+ } else {
+ where->current->next = where->current;
+ where->first = where->current;
+ where->current->prev = where->first;
+ where->last = where->current;
+ where->first->next = where->last;
+ }
+ } else {
+ back = where->current;
+ where->current = (Widget_Item *) malloc (sizeof (Widget_Item));
+ if (back){
+ back->prev = where->current;
+ where->current->next = back;
+ } else {
+ where->current->next = where->current;
+ where->first = where->current;
+ }
+
+ where->current->prev = where->first;
+ where->last = where->current;
+ where->first->next = where->last;
+
+ }
+ where->current->dlg_id = where->count;
+ where->current->widget = what;
+ where->current->widget->parent = where;
+
+ where->count++;
+
+ /* If the widget is inserted in a running dialog */
+ if (where->running){
+ send_message (where, widget, WIDGET_INIT, 0);
+ send_message (where, widget, WIDGET_DRAW, 0);
+#ifdef HAVE_GNOME
+ x_add_widget (where, where->current);
+#endif
+ }
+ return (where->count - 1);
+}
+
+int remove_widget (Dlg_head *h, void *what)
+{
+ Widget_Item *first, *p;
+
+ first = p = h->current;
+
+ do {
+ if (p->widget == what){
+ /* Remove links to this Widget_Item */
+ p->prev->next = p->next;
+ p->next->prev = p->prev;
+
+ /* Make sure h->current is always valid */
+ if (p == h->current){
+ h->current = h->current->next;
+ if (h->current == p)
+ h->current = 0;
+ }
+ h->count--;
+ free (p);
+ return 1;
+ }
+ p = p->next;
+ } while (p != first);
+ return 0;
+}
+
+int destroy_widget (Widget *w)
+{
+ send_message (w->parent, w, WIDGET_DESTROY, 0);
+ if (w->destroy)
+ w->destroy (w);
+ free (w);
+ return 1;
+}
+
+int add_widget (Dlg_head *where, void *what)
+{
+ return add_widgetl (where, what, XV_WLAY_DONTCARE);
+}
+
+int send_message (Dlg_head *h, Widget *w, int msg, int par)
+{
+ return (*(w->callback))(h, w, msg, par);
+}
+
+/* broadcast a message to all the widgets in a dialog that have
+ * the options set to flags.
+ */
+void dlg_broadcast_msg_to (Dlg_head *h, int message, int reverse, int flags)
+{
+ Widget_Item *p, *first;
+
+ if (!h->current)
+ return;
+
+ if (reverse)
+ first = p = h->current->prev;
+ else
+ /* FIXME: On XView the layout for the widget->next widget is
+ invoked, and we should change the buttons order on query_dialog
+ in order to use the HAVE_X part of the statement */
+#ifdef HAVE_X
+ first = p = h->current;
+#else
+ first = p = h->current->next;
+#endif
+ do {
+/* if (p->widget->options & flags) */
+ send_message (h, p->widget, message, 0);
+
+ if (reverse)
+ p = p->prev;
+ else
+ p = p->next;
+ } while (first != p);
+}
+
+/* broadcast a message to all the widgets in a dialog */
+void dlg_broadcast_msg (Dlg_head *h, int message, int reverse)
+{
+ dlg_broadcast_msg_to (h, message, reverse, ~0);
+}
+
+int dlg_focus (Dlg_head *h)
+{
+ if (send_message (h, h->current->widget, WIDGET_FOCUS, 0)){
+ (*h->callback) (h, h->current->dlg_id, DLG_FOCUS);
+ return 1;
+ }
+ return 0;
+}
+
+int dlg_unfocus (Dlg_head *h)
+{
+ if (send_message (h, h->current->widget, WIDGET_UNFOCUS, 0)){
+ (*h->callback) (h, h->current->dlg_id, DLG_UNFOCUS);
+ return 1;
+ }
+ return 0;
+}
+
+static void select_a_widget (Dlg_head *h, int down)
+{
+ int direction = h->direction;
+
+ if (!down)
+ direction = !direction;
+
+ do {
+ if (direction)
+ h->current = h->current->next;
+ else
+ h->current = h->current->prev;
+
+ (*h->callback) (h, h->current->dlg_id, DLG_ONE_DOWN);
+ } while (!dlg_focus (h));
+}
+
+/* Return true if the windows overlap */
+int dlg_overlap (Widget *a, Widget *b)
+{
+ if ((b->x >= a->x + a->cols)
+ || (a->x >= b->x + b->cols)
+ || (b->y >= a->y + a->lines)
+ || (a->y >= b->y + b->lines))
+ return 0;
+ return 1;
+}
+
+
+/* Searches a widget, uses the callback as a signature in the dialog h */
+Widget *find_widget_type (Dlg_head *h, callback_fn signature)
+{
+ Widget *w;
+ Widget_Item *item;
+ int i;
+
+ if (!h)
+ return 0;
+
+ w = 0;
+ for (i = 0, item = h->current; i < h->count; i++, item = item->next){
+ if (item->widget->callback == signature){
+ w = item->widget;
+ break;
+ }
+ }
+ return w;
+}
+
+void dlg_one_up (Dlg_head *h)
+{
+ Widget_Item *old;
+
+ old = h->current;
+ /* If it accepts unFOCUSion */
+ if (!dlg_unfocus(h))
+ return;
+
+ select_a_widget (h, 0);
+ if (dlg_overlap (old->widget, h->current->widget)){
+ send_message (h, h->current->widget, WIDGET_DRAW, 0);
+ send_message (h, h->current->widget, WIDGET_FOCUS, 0);
+ }
+}
+
+void dlg_one_down (Dlg_head *h)
+{
+ Widget_Item *old;
+
+ old = h->current;
+ if (!dlg_unfocus (h))
+ return;
+
+ select_a_widget (h, 1);
+ if (dlg_overlap (old->widget, h->current->widget)){
+ send_message (h, h->current->widget, WIDGET_DRAW, 0);
+ send_message (h, h->current->widget, WIDGET_FOCUS, 0);
+ }
+}
+
+int dlg_select_widget (Dlg_head *h, void *w)
+{
+ if (dlg_unfocus (h)){
+ while (h->current->widget != w)
+ h->current = h->current->next;
+ while (!dlg_focus (h))
+ h->current = h->current->next;
+
+ return 1;
+ }
+ return 0;
+}
+
+int send_message_to (Dlg_head *h, Widget *w, int msg, int par)
+{
+ Widget_Item *p = h->current;
+ int v, i;
+
+ v = 0;
+ for (i = 0; i < h->count; i++){
+ if (w == (void *) p->widget){
+ v = send_message (h, p->widget, msg, par);
+ break;
+ }
+ p = p->next;
+ }
+ return v;
+}
+
+#define callback(h) (h->current->widget->callback)
+
+void update_cursor (Dlg_head *h)
+{
+ if (!h->current)
+ return;
+ if (h->current->widget->options & W_WANT_CURSOR)
+ send_message (h, h->current->widget, WIDGET_CURSOR, 0);
+ else {
+ Widget_Item *p = h->current;
+
+ do {
+ if (p->widget->options & W_WANT_CURSOR)
+ if ((*p->widget->callback)(h, p->widget, WIDGET_CURSOR, 0)){
+ x_focus_widget (p);
+ break;
+ }
+ p = p->next;
+ } while (h->current != p);
+ }
+}
+
+/* Redraw the widgets in reverse order, leaving the current widget
+ * as the last one
+ */
+void dlg_redraw (Dlg_head *h)
+{
+ (h->callback)(h, 0, DLG_DRAW);
+
+ dlg_broadcast_msg (h, WIDGET_DRAW, 1);
+
+ update_cursor (h);
+}
+
+void dlg_refresh (void *parameter)
+{
+ dlg_redraw ((Dlg_head *) parameter);
+}
+
+void dlg_stop (Dlg_head *h)
+{
+ h->running = 0;
+ x_dialog_stop (h);
+}
+
+static INLINE void dialog_handle_key (Dlg_head *h, int d_key)
+{
+ char *hlpfile;
+
+ switch (d_key){
+ case KEY_LEFT:
+ case KEY_UP:
+ dlg_one_up (h);
+ break;
+
+ case KEY_RIGHT:
+ case KEY_DOWN:
+ dlg_one_down (h);
+ break;
+
+ case KEY_F(1):
+ hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
+ interactive_display (hlpfile, h->help_ctx);
+ free (hlpfile);
+ do_refresh ();
+ break;
+
+ case XCTRL('z'):
+ suspend_cmd ();
+ /* Fall through */
+
+ case XCTRL('l'):
+#ifndef HAVE_SLANG
+ /* Use this if the refreshes fail */
+ clr_scr ();
+ do_refresh ();
+#else
+ touchwin (stdscr);
+#endif
+ mc_refresh ();
+ doupdate ();
+ break;
+
+ case '\n':
+ case KEY_ENTER:
+ h->ret_value = B_ENTER;
+ h->running = 0;
+ x_dialog_stop (h);
+ break;
+
+ case ESC_CHAR:
+ case KEY_F (10):
+ case XCTRL ('c'):
+ case XCTRL ('g'):
+ h->ret_value = B_CANCEL;
+ dlg_stop (h);
+ break;
+ }
+}
+
+static int dlg_try_hotkey (Dlg_head *h, int d_key)
+{
+ Widget_Item *hot_cur;
+ Widget_Item *previous;
+ int handled, c;
+ extern input_event ();
+
+ /*
+ * Explanation: we don't send letter hotkeys to other widgets if
+ * the currently selected widget is an input line
+ */
+
+ if (h->current->widget->options & W_IS_INPUT){
+ if(d_key < 255 && isalpha(d_key))
+ return 0;
+ }
+
+ /* If it's an alt key, send the message */
+ c = d_key & ~ALT(0);
+ if (d_key & ALT(0) && c < 255 && isalpha(c))
+ d_key = tolower(c);
+
+#ifdef _OS_NT
+ /* .ado: fix problem with file_permission under Win95 */
+ if (d_key == 0) return 0;
+#endif
+
+ handled = 0;
+ if (h->current->widget->options & W_WANT_HOTKEY)
+ handled = callback (h) (h, h->current->widget, WIDGET_HOTKEY, d_key);
+
+ /* If not used, send hotkey to other widgets */
+ if (handled)
+ return handled;
+
+ hot_cur = h->current;
+
+ /* send it to all widgets */
+ do {
+ if (hot_cur->widget->options & W_WANT_HOTKEY)
+ handled |= (*hot_cur->widget->callback)
+ (h, hot_cur->widget, WIDGET_HOTKEY, d_key);
+
+ if (!handled)
+ hot_cur = hot_cur->next;
+ } while (h->current != hot_cur && !handled);
+
+ if (!handled)
+ return 0;
+
+ (*h->callback) (h, 0, DLG_HOTKEY_HANDLED);
+ previous = h->current;
+ if (!dlg_unfocus (h))
+ return handled;
+
+ h->current = hot_cur;
+ if (!dlg_focus (h)){
+ h->current = previous;
+ dlg_focus (h);
+ }
+ return handled;
+}
+
+void dlg_key_event (Dlg_head *h, int d_key)
+{
+ int handled;
+
+ /* TAB used to cycle */
+ if (!h->raw && (d_key == '\t' || d_key == KEY_BTAB))
+ if (d_key == '\t')
+ dlg_one_down (h);
+ else
+ dlg_one_up (h);
+ else {
+
+ /* first can dlg_callback handle the key */
+ handled = (*h->callback) (h, d_key, DLG_KEY);
+
+ /* next try the hotkey */
+ if (!handled)
+ handled = dlg_try_hotkey (h, d_key);
+
+ /* not used - then try widget_callback */
+ if (!handled)
+ handled |= callback (h)(h, h->current->widget, WIDGET_KEY, d_key);
+
+ /* not used- try to use the unhandled case */
+ if (!handled)
+ handled |= (*h->callback) (h, d_key, DLG_UNHANDLED_KEY);
+
+ if (!handled)
+ dialog_handle_key (h, d_key);
+ (*h->callback) (h, d_key, DLG_POST_KEY);
+ }
+}
+
+static INLINE int dlg_mouse_event (Dlg_head *h, Gpm_Event *event)
+{
+ Widget_Item *item;
+ Widget_Item *starting_widget = h->current;
+ Gpm_Event new_event;
+ int x = event->x;
+ int y = event->y;
+ int ret_value;
+
+ /* kludge for the menubar: start at h->first, not current */
+ /* Must be carefull in the insertion order to the dlg list */
+ if (y == 1 && h->has_menubar)
+ starting_widget = h->first;
+
+ item = starting_widget;
+ do {
+ Widget *widget = item->widget;
+
+ item = item->next;
+
+ if (!((x > widget->x) && (x <= widget->x+widget->cols)
+ && (y > widget->y) && (y <= widget->y+widget->lines)))
+ continue;
+
+ new_event = *event;
+ new_event.x -= widget->x;
+ new_event.y -= widget->y;
+
+ ret_value = widget->mouse ? (*widget->mouse) (&new_event, widget) :
+ MOU_NORMAL;
+
+ return ret_value;
+ } while (item != starting_widget);
+ return 0;
+}
+
+/* Run dialog routines */
+
+/* Init the process */
+void init_dlg (Dlg_head *h)
+{
+ int refresh_mode;
+
+ tk_end_frame ();
+
+ /* Initialize dialog manager and widgets */
+ (*h->callback) (h, 0, DLG_INIT);
+ dlg_broadcast_msg (h, WIDGET_INIT, 0);
+
+ if (h->x == 0 && h->y == 0 && h->cols == COLS && h->lines == LINES)
+ refresh_mode = REFRESH_COVERS_ALL;
+ else
+ refresh_mode = REFRESH_COVERS_PART;
+ push_refresh (dlg_refresh, h, refresh_mode);
+ h->refresh_pushed = 1;
+
+ /* Initialize direction */
+ if (!h->direction)
+ h->current = h->first;
+
+ if (h->initfocus != NULL)
+ h->current = h->initfocus;
+
+ h->previous_dialog = current_dlg;
+ current_dlg = h;
+
+ /* Initialize the mouse status */
+ h->mouse_status = 0;
+
+ /* Redraw the screen */
+ dlg_redraw (h);
+
+ while (!dlg_focus (h))
+ h->current = h->current->next;
+
+ h->ret_value = 0;
+ h->running = 1;
+ x_init_dlg (h);
+}
+
+/* Shutdown the run_dlg */
+void dlg_run_done (Dlg_head *h)
+{
+ (*h->callback) (h, h->current->dlg_id, DLG_END);
+ current_dlg = (Dlg_head *) h->previous_dialog;
+ if (current_dlg)
+ x_focus_widget (current_dlg->current);
+}
+
+void dlg_process_event (Dlg_head *h, int key, Gpm_Event *event)
+{
+ if (key == EV_NONE){
+ if (got_interrupt ())
+ key = XCTRL('g');
+ else
+ return;
+ }
+
+ if (key == EV_MOUSE)
+ h->mouse_status = dlg_mouse_event (h, event);
+ else
+ dlg_key_event (h, key);
+}
+
+#ifndef PORT_HAS_FRONTEND_RUN_DLG
+static inline void
+frontend_run_dlg (Dlg_head *h)
+{
+ int d_key;
+ Gpm_Event event;
+
+ event.x = -1;
+ while (h->running) {
+#if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
+ /* It does not work with ncurses before 1.9.9g, it will break */
+ if (winch_flag)
+ change_screen_size ();
+#endif
+ if (is_idle ()){
+ if (idle_hook)
+ execute_hooks (idle_hook);
+
+ while (h->send_idle_msg && is_idle ()){
+ (*h->callback) (h, 0, DLG_IDLE);
+ }
+ }
+
+ update_cursor (h);
+ (*h->callback)(h, 0, DLG_PRE_EVENT);
+
+ /* Clear interrupt flag */
+ got_interrupt ();
+ d_key = get_event (&event, h->mouse_status == MOU_REPEAT, 1);
+
+ dlg_process_event (h, d_key, &event);
+ }
+}
+#endif /* PORT_HAS_FRONTEND_RUN_DLG */
+
+/* Standard run dialog routine
+ * We have to keep this routine small so that we can duplicate it's
+ * behavior on complex routines like the file routines, this way,
+ * they can call the dlg_process_event without rewriting all the code
+ */
+void run_dlg (Dlg_head *h)
+{
+ init_dlg (h);
+ frontend_run_dlg (h);
+ dlg_run_done (h);
+}
+
+void
+destroy_dlg (Dlg_head *h)
+{
+ int i;
+ Widget_Item *c;
+
+ if (h->refresh_pushed)
+ pop_refresh ();
+
+ x_destroy_dlg_start (h);
+ dlg_broadcast_msg (h, WIDGET_DESTROY, 0);
+ c = h->current;
+ for (i = 0; i < h->count; i++){
+ if (c->widget->destroy)
+ c->widget->destroy (c->widget);
+ c = c->next;
+ free (h->current->widget);
+ free (h->current);
+ h->current = c;
+ }
+ if (h->title)
+ free (h->title);
+ x_destroy_dlg (h);
+ free (h);
+ if (refresh_list)
+ do_refresh ();
+}
+
+int std_callback (Dlg_head *h, int Msg, int Par)
+{
+ return 0;
+}
+
+void widget_set_size (Widget *widget, int y, int x, int lines, int cols)
+{
+ widget->x = x;
+ widget->y = y;
+ widget->cols = cols;
+ widget->lines = lines;
+}
+
+/* Replace widget old for widget new in the h dialog */
+void dlg_replace_widget (Dlg_head *h, Widget *old, Widget *new)
+{
+ Widget_Item *p = h->current;
+ int should_focus = 0;
+
+ do {
+ if (p->widget == old){
+
+ if (old == h->current->widget)
+ should_focus = 1;
+
+ /* We found the widget */
+ /* First kill the widget */
+ new->focused = old->focused;
+ new->parent = h;
+ send_message_to (h, old, WIDGET_DESTROY, 0);
+ (*old->destroy) (old);
+
+ /* We insert the new widget */
+ p->widget = new;
+ send_message_to (h, new, WIDGET_INIT, 0);
+ if (should_focus){
+ if (dlg_focus (h) == 0)
+ select_a_widget (h, 1);
+ }
+ send_message_to (h, new, WIDGET_DRAW, 0);
+ break;
+ }
+ p = p->next;
+ } while (p != h->current);
+}
+
+void widget_redraw (Dlg_head *h, Widget_Item *w)
+{
+ Widget_Item *save = h->current;
+
+ h->current = w;
+ (*w->widget->callback)(h, h->current->widget, WIDGET_DRAW, 0);
+ h->current = save;
+}
+
+/* Returns the index of h->current from h->first */
+int dlg_item_number (Dlg_head *h)
+{
+ Widget_Item *p;
+ int i = 0;
+
+ p = h->first;
+
+ do {
+ if (p == h->current)
+ return i;
+ i++;
+ p = p->next;
+ } while (p != h->first);
+ fprintf (stderr, "Internal error: current not in dialog list\n\r");
+ exit (1);
+}
+
+int dlg_select_nth_widget (Dlg_head *h, int n)
+{
+ Widget_Item *w;
+ int i;
+
+ w = h->first;
+ for (i = 0; i < n; i++)
+ w = w->next;
+
+ return dlg_select_widget (h, w->widget);
+}
+
+#ifdef HAVE_TK
+/* Frames must include a trailing dot */
+static void tk_frame_proc (Dlg_head *h, char *frame, int new_frame)
+{
+ char *s = strdup (frame);
+
+ if (frame [strlen (frame)-1] != '.'){
+ fprintf (stderr, "Invalid frame name\n");
+ exit (1);
+ }
+ s [strlen (frame)-1] = 0;
+ the_frame = frame;
+
+ if (new_frame)
+ tk_evalf ("frame %s.%s", (char *)h->wdata, s);
+}
+
+/* If passed a null string, it returns */
+void tk_new_frame (Dlg_head *h, char *frame)
+{
+ if (!*frame)
+ return;
+ tk_frame_proc (h, frame, 1);
+}
+
+void tk_frame (Dlg_head *h, char *frame)
+{
+ tk_frame_proc (h, frame, 0);
+}
+
+void tk_end_frame ()
+{
+ the_frame = "";
+}
+#else
+void tk_new_frame (Dlg_head *h, char *x)
+{
+}
+
+void tk_frame (Dlg_head *h, char *x)
+{
+}
+
+void tk_end_frame (void)
+{
+}
+#endif
+
+#ifndef PORT_HAS_DIALOG_TITLE
+void
+x_set_dialog_title (Dlg_head *h, char *title)
+{
+ h->title = strdup(title);
+}
+#endif
+
--- /dev/null
+#ifndef MC_DLG_H
+#define MC_DLG_H
+#include "mouse.h"
+#include "util.h"
+
+/* Color constants */
+#define FOCUSC h->color[1]
+#define NORMALC h->color[0]
+#define HOT_NORMALC h->color[2]
+#define HOT_FOCUSC h->color[3]
+
+/* Possible directions */
+#define DIR_FORWARD 1
+#define DIR_BACKWARD 0
+
+/* Common return values */
+#define B_EXIT 0
+#define B_CANCEL 1
+#define B_ENTER 2
+#define B_HELP 3
+#define B_USER 100
+
+/* Widget messages */
+enum {
+ WIDGET_INIT, /* Initialize widget */
+ WIDGET_FOCUS, /* Draw widget in focused state */
+ WIDGET_UNFOCUS, /* Draw widget in unfocused state */
+ WIDGET_DRAW, /* Sent to widget to draw themselves */
+ WIDGET_KEY, /* Sent to widgets on key press */
+ WIDGET_HOTKEY, /* Sent to widget to catch preprocess key */
+ WIDGET_DESTROY, /* Sent to widget at destruction time */
+ WIDGET_CURSOR, /* Sent to widget to position the cursor */
+ WIDGET_IDLE, /* Send to widgets with options & W_WANT_IDLE*/
+ WIDGET_USER = 0x100000
+
+} /* Widget_Messages */;
+
+enum {
+ MSG_NOT_HANDLED,
+ MSG_HANDLED
+} /* WRET */;
+
+/* Widgets are expected to answer to the following messages:
+
+ WIDGET_FOCUS: 1 if the accept the focus, 0 if they do not.
+ WIDGET_UNFOCUS: 1 if they accept to release the focus, 0 if they don't.
+ WIDGET_KEY: 1 if they actually used the key, 0 if not.
+ WIDGET_HOTKEY: 1 if they actually used the key, 0 if not.
+*/
+
+/* Dialog messages */
+enum {
+ DLG_KEY, /* Sent on keypress before sending to widget */
+ DLG_INIT, /* Sent on init */
+ DLG_END, /* Sent on shutdown */
+ DLG_ACTION,
+ DLG_DRAW, /* Sent for updating dialog managed area */
+ DLG_FOCUS, /* Sent on give focus to a widget */
+ DLG_UNFOCUS, /* Sent on remove focus from widget */
+ DLG_ONE_UP, /* Sent on selecting next */
+ DLG_ONE_DOWN, /* Sent on selecting prev */
+ DLG_POST_KEY, /* Sent after key has been sent */
+ DLG_IDLE, /* Sent if idle is active */
+ DLG_UNHANDLED_KEY, /* Send if no widget wanted the key */
+ DLG_HOTKEY_HANDLED, /* Send if a child got the hotkey */
+ DLG_PRE_EVENT /* Send before calling get_event */
+} /* Dialog_Messages */;
+
+typedef unsigned long widget_data;
+typedef struct Dlg_head {
+ int *color; /* color set */
+ int count; /* number of widgets */
+ int ret_value;
+
+ /* mouse status */
+ int mouse_status; /* For the autorepeat status of the mouse */
+
+ void *previous_dialog; /* Pointer to the previously running Dlg_head */
+ int refresh_pushed; /* Did the dialog actually run? */
+
+ /* position */
+ int x, y; /* Position relative to screen origin */
+
+ /* Flags */
+ int running;
+ int direction;
+ int send_idle_msg;
+
+ char *name; /* Dialog name Tk code */
+ char *help_ctx;
+
+ /* Internal variables */
+ struct Widget_Item *current, *first, *last;
+ int (*callback) (struct Dlg_head *, int, int);
+
+ struct Widget_Item *initfocus;
+
+ /* Hacks */
+ char *title;
+
+ int cols;
+ int lines;
+ void *data;
+
+ int has_menubar; /* GrossHack: Send events on row 1 to a menubar? */
+ int raw; /* Should the tab key be sent to the dialog? */
+
+ widget_data wdata;
+ int grided; /* Does it use the automatic layout? */
+#ifdef HAVE_GNOME
+ int idle_fn_tag; /* Tag for the idle routine, -1 if none */
+#endif
+} Dlg_head;
+
+/* XView widget layout */
+
+typedef enum {
+ XV_WLAY_DONTCARE, /* Place the widget wherever it is reasonable */
+
+ XV_WLAY_RIGHTOF, /* Place the widget to the right of the last widget
+ * created - note: add_widget creates widgets from
+ * the last to the first one.
+ */
+
+ XV_WLAY_BELOWOF, /* Place it in a column like style */
+
+ XV_WLAY_BELOWCLOSE,/* The same, but without any gap between them */
+
+ XV_WLAY_NEXTROW, /* Place it on the left margin with Y bellow all the
+ * previous widgets
+ */
+
+ XV_WLAY_CENTERROW,/* The same as previous, but when the dialog is
+ * ready to show, tries to center that row of widgets
+ */
+
+ XV_WLAY_NEXTCOLUMN, /* Place it on the top margin with X behind all the
+ * previous widgets
+ */
+
+ XV_WLAY_RIGHTDOWN, /* Place the widget to the right of the last one with
+ * y set so that both y + h and yold + hold are equal.
+ This is usefull if the previous widget was a radio,
+ which has multiple lines */
+ XV_WLAY_EXTENDWIDTH /* Like nextrow, but later on tries to extend the widget
+ * to fit in the frame (only for PANEL_LIST) */
+} WLay;
+
+/* Every Widget must have this as it's first element */
+typedef struct Widget {
+ int x, y;
+ int cols, lines;
+ int color; /* If the widget uses it, the color */
+ int options;
+ int focused; /* Tells if the widget is focused */
+ int (*callback)(Dlg_head *, void *, int, int); /* The callback function */
+ void (*destroy)(void *);
+ mouse_h mouse;
+ struct Dlg_head *parent;
+ widget_data wdata;
+ widget_data wcontainer; /* For children of midnight_dlg, identifies
+ * the frame in which they should reside
+ */
+ char *frame; /* Tk version: frame containing it */
+ char *tkname; /* Tk version: widget name */
+ enum {
+ AREA_TOP,
+ AREA_LEFT,
+ AREA_RIGHT,
+ AREA_BOTTOM
+ } area; /* Used by X platforms, should stay here always because the size
+ of this structure has to be same everywhere :) */
+ WLay layout;
+} Widget;
+
+/* The options for the widgets */
+#define W_WANT_POST_KEY 1
+#define W_WANT_HOTKEY 2
+#define W_WANT_CURSOR 4
+#define W_WANT_IDLE 8
+#define W_IS_INPUT 16
+#define W_PANEL_HIDDEN 32
+
+typedef struct Widget_Item {
+ int dlg_id;
+ struct Widget_Item *next; /* next in circle buffer */
+ struct Widget_Item *prev; /* previous in circle buffer */
+ Widget *widget; /* point to the component */
+} Widget_Item;
+
+/* draw box in window */
+void draw_box (Dlg_head *h, int y, int x, int ys, int xs);
+
+/* doubled line if possible */
+void draw_double_box (Dlg_head *h, int y, int x, int ys, int xs);
+
+/* Creates a dialog head */
+Dlg_head *create_dlg (int y1, int x1, int lines, int cols,
+ int *col,
+ int (*callback) (struct Dlg_head *, int, int),
+ char *help_ctx, char *name, int flags);
+
+/* The flags: */
+#define DLG_NO_TOPLEVEL 32 /* GNOME only: Do not create a toplevel window, user provides it */
+#define DLG_GNOME_APP 16 /* GNOME only: use a gnome-app for the toplevel window */
+#define DLG_NO_TED 8 /* GNOME only: do not manage layout with a GNOME GtkTed widget */
+#define DLG_GRID 4 /* Widgets should be created under .widgets */
+#define DLG_TRYUP 2 /* Try to move two lines up the dialog */
+#define DLG_CENTER 1 /* Center the dialog */
+#define DLG_NONE 0 /* No options */
+int add_widget (Dlg_head *dest, void *Widget);
+int add_widgetl (Dlg_head *dest, void *Widget, WLay layout);
+int remove_widget (Dlg_head *dest, void *Widget);
+int destroy_widget (Widget *w);
+
+/* Runs dialog d */
+void run_dlg (Dlg_head *d);
+
+void dlg_run_done (Dlg_head *h);
+void dlg_process_event (Dlg_head *h, int key, Gpm_Event *event);
+void init_dlg (Dlg_head *h);
+
+/* To activate/deactivate the idle message generation */
+void set_idle_proc (Dlg_head *d, int state);
+
+void dlg_redraw (Dlg_head *h);
+void dlg_refresh (void *parameter);
+void destroy_dlg (Dlg_head *h);
+
+void widget_set_size (Widget *widget, int x1, int y1, int x2, int y2);
+
+void dlg_broadcast_msg_to (Dlg_head *h, int message, int reverse, int flags);
+void dlg_broadcast_msg (Dlg_head *h, int message, int reverse);
+void dlg_mouse (Dlg_head *h, Gpm_Event *event);
+
+typedef void (*destroy_fn)(void *);
+typedef int (*callback_fn)(Dlg_head *, void *, int, int);
+
+void init_widget (Widget *w, int y, int x, int lines, int cols,
+ callback_fn callback, destroy_fn destroy,
+ mouse_h mouse_handler, char *tkname);
+
+/* Various default service provision */
+int default_dlg_callback (Dlg_head *h, int id, int msg);
+int std_callback (Dlg_head *h, int Msg, int Par);
+int default_proc (Dlg_head *h, int Msg, int Par);
+
+#define real_widget_move(w, _y, _x) move((w)->y + _y, (w)->x + _x)
+#define dlg_move(h, _y, _x) move(((Dlg_head *) h)->y + _y, \
+ ((Dlg_head *) h)->x + _x)
+
+#define widget_move(w,y,x) real_widget_move((Widget*)w,y,x)
+
+
+extern Dlg_head *current_dlg;
+extern Hook *idle_hook;
+
+int send_message (Dlg_head *h, Widget *w, int msg, int par);
+int send_message_to (Dlg_head *h, Widget *w, int msg, int par);
+void dlg_replace_widget (Dlg_head *h, Widget *old, Widget *new);
+void widget_redraw (Dlg_head *h, Widget_Item *w);
+int dlg_overlap (Widget *a, Widget *b);
+void widget_erase (Widget *);
+void dlg_erase (Dlg_head *h);
+void dlg_stop (Dlg_head *h);
+
+/* Widget selection */
+int dlg_select_widget (Dlg_head *h, void *widget);
+void dlg_one_up (Dlg_head *h);
+void dlg_one_down (Dlg_head *h);
+int dlg_focus (Dlg_head *h);
+int dlg_unfocus (Dlg_head *h);
+int dlg_select_nth_widget (Dlg_head *h, int n);
+int dlg_item_number (Dlg_head *h);
+Widget *find_widget_type (Dlg_head *h, callback_fn signature);
+
+/* Sets/clear the specified flag in the options field */
+#define widget_option(w,f,i) \
+ w.options = ((i) ? (w.options | (f)) : (w.options & (~(f))))
+
+#define widget_want_cursor(w,i) widget_option(w, W_WANT_CURSOR, i)
+#define widget_want_hotkey(w,i) widget_option(w, W_WANT_HOTKEY, i)
+#define widget_want_postkey(w,i) widget_option(w, W_WANT_POSTKEY, i)
+
+typedef void (*movefn)(void *, int);
+
+/* Layout definitions */
+
+void xv_Layout (void *first_widget, ...);
+void tk_layout (void *first_widget, ...);
+void tk_new_frame (Dlg_head *, char *);
+void tk_frame (Dlg_head *, char *);
+void tk_end_frame ();
+void x_set_dialog_title (Dlg_head *h, char *title);
+
+/* The inner workings of run_dlg, exported for the Tk and XView toolkits */
+void dlg_key_event (Dlg_head *h, int d_key);
+void update_cursor (Dlg_head *h);
+
+#ifdef HAVE_X
+extern Dlg_head *midnight_dlg;
+void x_focus_widget (Widget_Item *p);
+void x_unfocus_widget (Widget_Item *p);
+void x_init_dlg (Dlg_head *h);
+void x_destroy_dlg (Dlg_head *h);
+void x_destroy_dlg_start (Dlg_head *h);
+void x_set_idle (Dlg_head *h, int enable_idle);
+void x_dialog_stop (Dlg_head *h);
+#else
+# define x_focus_widget(x) {}
+# define x_unfocus_widget(x) {}
+# define x_init_dlg(x) {}
+# define x_destroy_dlg(x) {}
+# define x_destroy_dlg_start(x) {}
+#endif
+
+#endif /* MC_DLG_H */
--- /dev/null
+/* Extension dependent execution.
+ Copyright (C) 1994, 1995 The Free Software Foundation
+
+ Written by: 1995 Jakub Jelinek
+ 1994 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#ifdef __os2__
+# include <io.h>
+#endif
+
+#include "tty.h"
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <malloc.h>
+#include <string.h>
+#include <errno.h>
+#include "mad.h"
+#include "user.h"
+#include "main.h"
+#include "fs.h"
+#include "util.h"
+#include "dialog.h"
+#include "global.h"
+#include "ext.h"
+#include "view.h"
+#include "main.h"
+#include "../vfs/vfs.h"
+#include "x.h"
+
+#include "cons.saver.h"
+#include "layout.h"
+#ifdef SCO_FLAVOR
+#include <sys/wait.h>
+#endif /* SCO_FLAVOR */
+
+/* "$Id: ext.c,v 1.1 2001/12/30 09:55:26 sedwards Exp $" */
+
+/* If set, we execute the file command to check the file type */
+int use_file_to_check_type = 1;
+
+/* This variable points to a copy of the mc.ext file in memory
+ * With this we avoid loading/parsing the file each time we
+ * need it
+ */
+static char *data = NULL;
+
+#ifdef OS2_NT
+
+__declspec(dllimport) __stdcall unsigned GetTempPathA(unsigned,char*);
+
+static char tmpcmdfilename[255];
+char *gettmpcmdname(){
+ int i,fd;
+ char TmpPath[255];
+ memset(TmpPath,0,255);
+ memset(tmpcmdfilename,0,255);
+ GetTempPathA(255,TmpPath);
+ for(i=0;i<32000;++i){
+ sprintf(tmpcmdfilename,"%stmp%d.bat",TmpPath,i);
+ if((fd=_open(tmpcmdfilename,_O_RDONLY)) != -1)
+ _close(fd);
+ else if (errno == ENOENT)
+ break;
+ }
+ return tmpcmdfilename;
+}
+#endif
+
+void
+flush_extension_file (void)
+{
+ if (data){
+ free (data);
+ data = NULL;
+ }
+
+}
+
+typedef char *(*quote_func_t)(const char *name, int i);
+
+static char *
+quote_block (quote_func_t quote_func, char **quoting_block)
+{
+ char **p = quoting_block;
+ char *result = 0;
+ char *tail = 0;
+ int current_len = 0;
+
+ for (p = quoting_block; *p; p++){
+ int temp_len;
+ char *temp = quote_func (*p, 0);
+
+ temp_len = strlen (temp);
+ current_len += temp_len + 2;
+ result = realloc (result, current_len);
+ if (!tail)
+ tail = result;
+ strcpy (tail, temp);
+ strcat (tail, " ");
+ tail += temp_len + 1;
+ free (temp);
+ }
+
+ return result;
+}
+
+static void
+exec_extension (char *filename, char *data, char **drops, int *move_dir, int start_line)
+{
+ char *file_name;
+ int cmd_file_fd;
+ FILE *cmd_file;
+ int expand_prefix_found = 0;
+ int parameter_found = 0;
+ char prompt [80];
+ int run_view = 0;
+ int def_hex_mode = default_hex_mode, changed_hex_mode = 0;
+ int def_nroff_flag = default_nroff_flag, changed_nroff_flag = 0;
+ int written_nonspace = 0;
+ int is_cd = 0;
+ char buffer [1024];
+ char *p = 0;
+ char *localcopy = NULL;
+ int do_local_copy;
+ time_t localmtime = 0;
+ struct stat mystat;
+ quote_func_t quote_func = name_quote;
+
+ /* Avoid making a local copy if we are doing a cd */
+ if (!vfs_file_is_local(filename))
+ do_local_copy = 1;
+ else
+ do_local_copy = 0;
+
+ /* Note: this has to be done after the getlocalcopy call,
+ * since it uses tmpnam as well
+ */
+#ifdef OS2_NT
+ file_name = strdup (gettmpcmdname ());
+#else
+ file_name = strdup (tmpnam (NULL));
+#endif
+ if ((cmd_file_fd = open (file_name, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600)) == -1){
+ message (1, MSG_ERROR, _(" Can't create temporary command file \n %s "),
+ unix_error_string (errno));
+ return;
+ }
+ cmd_file = fdopen (cmd_file_fd, "w");
+#ifdef OS2_NT
+ fprintf (cmd_file, "REM #!%s\n", shell);
+#else
+ fprintf (cmd_file, "#!%s\n", shell);
+#endif
+ prompt [0] = 0;
+ for (;*data && *data != '\n'; data++){
+ if (parameter_found){
+ if (*data == '}'){
+ char *parameter;
+ parameter_found = 0;
+ parameter = input_dialog (_(" Parameter "), prompt, "");
+ if (!parameter){
+ /* User canceled */
+ fclose (cmd_file);
+ unlink (file_name);
+ if (localcopy) {
+ mc_ungetlocalcopy (filename, localcopy, 0);
+ }
+ free (file_name);
+ return;
+ }
+ fputs (parameter, cmd_file);
+ written_nonspace = 1;
+ free (parameter);
+ } else {
+ int len = strlen (prompt);
+
+ if (len < sizeof (prompt) - 1){
+ prompt [len] = *data;
+ prompt [len+1] = 0;
+ }
+ }
+ } else if (expand_prefix_found){
+ expand_prefix_found = 0;
+ if (*data == '{')
+ parameter_found = 1;
+ else {
+ int i = check_format_view (data);
+ char *v;
+
+ if (i){
+ data += i - 1;
+ run_view = 1;
+ } else if ((i = check_format_cd (data)) > 0) {
+ is_cd = 1;
+ quote_func = fake_name_quote;
+ do_local_copy = 0;
+ p = buffer;
+ data += i - 1;
+ } else if ((i = check_format_var (data, &v)) > 0 && v){
+ fputs (v, cmd_file);
+ free (v);
+ data += i;
+ } else {
+ char *text;
+
+ if (*data == 'f'){
+ if (do_local_copy){
+ localcopy = mc_getlocalcopy (filename);
+ if (localcopy == NULL) {
+ fclose(cmd_file);
+ unlink(file_name);
+ free(file_name);
+ return;
+ }
+ mc_stat (localcopy, &mystat);
+ localmtime = mystat.st_mtime;
+ text = (*quote_func) (localcopy, 0);
+ } else {
+ text = (*quote_func) (filename, 0);
+ }
+ } else if (*data == 'q') {
+ text = quote_block (quote_func, drops);
+ } else
+ text = expand_format (*data, !is_cd);
+ if (!is_cd)
+ fputs (text, cmd_file);
+ else {
+ strcpy (p, text);
+ p = strchr (p, 0);
+ }
+ free (text);
+ written_nonspace = 1;
+ }
+ }
+ } else {
+ if (*data == '%')
+ expand_prefix_found = 1;
+ else {
+ if (*data != ' ' && *data != '\t')
+ written_nonspace = 1;
+ if (is_cd)
+ *(p++) = *data;
+ else
+ fputc (*data, cmd_file);
+ }
+ }
+ } /* for */
+ fputc ('\n', cmd_file);
+ fclose (cmd_file);
+ chmod (file_name, S_IRWXU);
+ if (run_view){
+ altered_hex_mode = 0;
+ altered_nroff_flag = 0;
+ if (def_hex_mode != default_hex_mode)
+ changed_hex_mode = 1;
+ if (def_nroff_flag != default_nroff_flag)
+ changed_nroff_flag = 1;
+
+ /* If we've written whitespace only, then just load filename
+ * into view
+ */
+ if (written_nonspace)
+ view (file_name, filename, move_dir, start_line);
+ else
+ view (0, filename, move_dir, start_line);
+ if (changed_hex_mode && !altered_hex_mode)
+ default_hex_mode = def_hex_mode;
+ if (changed_nroff_flag && !altered_nroff_flag)
+ default_nroff_flag = def_nroff_flag;
+ repaint_screen ();
+ } else if (is_cd) {
+ char *q;
+ *p = 0;
+ p = buffer;
+ while (*p == ' ' && *p == '\t')
+ p++;
+
+ /* Search last non-space character. Start search at the end in order
+ not to short filenames containing spaces. */
+ q = p + strlen (p) - 1;
+ while (q >= p && (*q == ' ' || *q == '\t'))
+ q--;
+ q[1] = 0;
+ do_cd (p, cd_parse_command);
+ } else {
+ shell_execute (file_name, EXECUTE_INTERNAL | EXECUTE_TEMPFILE);
+ if (console_flag)
+ {
+ handle_console (CONSOLE_SAVE);
+ if (output_lines && keybar_visible)
+ {
+ show_console_contents (output_start_y,
+ LINES-keybar_visible-output_lines-1,
+ LINES-keybar_visible-1);
+
+ }
+ }
+
+#ifdef OLD_CODE
+ if (vfs_current_is_local ())
+ shell_execute (file_name, EXECUTE_INTERNAL);
+ else
+ message (1, _(" Warning "), _(" Can't execute commands on a Virtual File System directory "));
+#endif
+ }
+#ifndef PORT_DOES_BACKGROUND_EXEC
+ unlink (file_name);
+#endif
+ if (localcopy) {
+ mc_stat (localcopy, &mystat);
+ mc_ungetlocalcopy (filename, localcopy, localmtime != mystat.st_mtime);
+ }
+ free (file_name);
+}
+
+#ifdef FILE_L
+# define FILE_CMD "file -L "
+#else
+# define FILE_CMD "file "
+#endif
+
+/* The second argument is action, i.e. Open, View, Edit, Drop, or NULL if
+ * we want regex_command to return a list of all user defined actions.
+ * Third argument is space separated list of dropped files (for actions
+ * other then Drop it should be NULL);
+ *
+ * This function returns:
+ *
+ * If action != NULL, then it returns "Success" (not allocated) if it ran
+ * some command or NULL if not.
+ *
+ * If action == NULL, it returns NULL if there are no user defined commands
+ * or an allocated space separated list of user defined Actions.
+ *
+ * If action == "Icon", we are doing again something special. We return
+ * icon name and we set the variable regex_command_title to Title for
+ * that icon.
+ *
+ * If action == "View" then a parameter is checked in the form of "View:%d",
+ * if the value for %d exists, then the viewer is started up at that line number.
+ */
+char *regex_command_title = NULL;
+char *regex_command (char *filename, char *action, char **drops, int *move_dir)
+{
+ char *extension_file;
+ char *p, *q, *r, c;
+ char *buffer;
+ int file_len = strlen (filename);
+ int found = 0;
+ char content_string [2048];
+ int content_shift = 0;
+ char *to_return = NULL;
+ int old_patterns;
+ struct stat mystat;
+ int asked_file;
+ int view_at_line_number;
+ char *include_target;
+ int include_target_len;
+
+#ifdef FILE_STDIN
+ int file_supports_stdin = 1;
+#else
+ int file_supports_stdin = 0;
+#endif
+
+ /* Check for the special View:%d parameter */
+ if (action && strncmp (action, "View:", 5) == 0){
+ view_at_line_number = atoi (action + 5);
+ action [4] = 0;
+ } else {
+ view_at_line_number = 0;
+ }
+ /* Have we asked file for the file contents? */
+ asked_file = 0;
+
+ if (data == NULL) {
+ int home_error = 0;
+
+ buffer = concat_dir_and_file (home_dir, MC_USER_EXT);
+ if (exist_file (buffer))
+ extension_file = buffer;
+ else
+check_stock_mc_ext:
+ extension_file = concat_dir_and_file (mc_home, MC_LIB_EXT);
+ if ((data = load_file (extension_file)) == NULL) {
+ free (buffer);
+ return 0;
+ }
+ if (!strstr (data, "default/")) {
+ if (!strstr (data, "regex/") && !strstr (data, "shell/") &&
+ !strstr (data, "type/")) {
+ free (data);
+ data = NULL;
+ if (extension_file == buffer) {
+ home_error = 1;
+ goto check_stock_mc_ext;
+ } else {
+ char *msg;
+ char *msg2;
+ msg = copy_strings(" ", mc_home, MC_LIB_EXT, _(" file error"), NULL);
+ msg2 = copy_strings(_("Format of the "),
+ mc_home,
+("mc.ext file has changed\n\
+with version 3.0. It seems that installation\n\
+failed. Please fetch a fresh new copy from the\n\
+Midnight Commander package or in case you don't\n\
+have any, get it from ftp://ftp.nuclecu.unam.mx."), 0);
+ message (1, msg, msg2);
+ free (msg);
+ free (msg2);
+ free (buffer);
+ return 0;
+ }
+ }
+ }
+ if (home_error) {
+ char *msg;
+ char *msg2;
+ msg = copy_strings(" ~/", MC_USER_EXT, _(" file error "), NULL);
+ msg2 = copy_strings(_("Format of the ~/"), MC_USER_EXT, _(" file has changed\n\
+with version 3.0. You may want either to\n\
+copy it from "), mc_home, _("mc.ext or use that\n\
+file as an example of how to write it.\n\
+"), mc_home, _("mc.ext will be used for this moment."), 0);
+ message (1, msg, msg2);
+ free (msg);
+ free (msg2);
+ }
+ free (buffer);
+ }
+ mc_stat (filename, &mystat);
+
+ if (regex_command_title){
+ free (regex_command_title);
+ regex_command_title = NULL;
+ }
+ old_patterns = easy_patterns;
+ easy_patterns = 0; /* Real regular expressions are needed :) */
+ include_target = NULL;
+ for (p = data; *p; p++) {
+ for (q = p; *q == ' ' || *q == '\t'; q++)
+ ;
+ if (*q == '\n' || !*q)
+ p = q; /* empty line */
+ if (*p == '#') /* comment */
+ while (*p && *p != '\n')
+ p++;
+ if (*p == '\n')
+ continue;
+ if (!*p)
+ break;
+ if (p == q) { /* i.e. starts in the first column, should be
+ * keyword/descNL
+ */
+ if (found && action == NULL) /* We have already accumulated all
+ * the user actions
+ */
+ break;
+ found = 0;
+ q = strchr (p, '\n');
+ if (q == NULL)
+ q = strchr (p, 0);
+ c = *q;
+ *q = 0;
+ if (include_target){
+ if ((strncmp (p, "include/", 8) == 0) &&
+ (strncmp (p+8, include_target, include_target_len) == 0))
+ found = 1;
+ } else if (!strncmp (p, "regex/", 6)) {
+ p += 6;
+ /* Do not transform shell patterns, you can use shell/ for
+ * that
+ */
+ if (regexp_match (p, filename, match_normal))
+ found = 1;
+ } else if (!strncmp (p, "directory/", 10)) {
+ if (S_ISDIR (mystat.st_mode) && regexp_match (p+10, filename, match_normal))
+ found = 1;
+ } else if (!strncmp (p, "shell/", 6)) {
+ p += 6;
+ if (*p == '.') {
+ if (!strncmp (p, filename + file_len - (q - p),
+ q - p))
+ found = 1;
+ } else {
+ if (q - p == file_len && !strncmp (p, filename, q - p))
+ found = 1;
+ }
+ } else if (!strncmp (p, "type/", 5)) {
+ int islocal = vfs_file_is_local (filename);
+ p += 5;
+
+ if (islocal || file_supports_stdin) {
+ char *pp;
+ int hasread = use_file_to_check_type;
+
+ if (asked_file || !use_file_to_check_type)
+ goto match_file_output;
+
+ hasread = 0;
+ if (islocal) {
+ char *tmp = name_quote (filename, 0);
+ char *command =
+ copy_strings (FILE_CMD, tmp, NULL);
+ FILE *f = popen (command, "r");
+
+ free (tmp);
+ free (command);
+ if (f != NULL) {
+ hasread = (fgets (content_string, 2047, f)
+ != NULL);
+ if (!hasread)
+ content_string [0] = 0;
+ pclose (f);
+#ifdef SCO_FLAVOR
+ /*
+ ** SCO 3.2 does has a buggy pclose(), so
+ ** <command> become zombie (alex)
+ */
+ waitpid(-1,NULL,WNOHANG);
+#endif /* SCO_FLAVOR */
+ }
+ } else {
+#ifdef _OS_NT
+ message (1, " Win32 ", " Unimplemented file prediction ");
+#else
+ int pipehandle, remotehandle;
+ pid_t p;
+
+ remotehandle = mc_open (filename, O_RDONLY);
+ if (remotehandle != -1) {
+ /* 8192 is HOWMANY hardcoded value in the file-3.14
+ * sources. Tell me if any other file uses larger
+ * chunk from beginning
+ */
+ pipehandle = mc_doublepopen
+ (remotehandle, 8192, &p,"file", "file", "-", NULL);
+ if (pipehandle != -1) {
+ int i;
+ while ((i = read (pipehandle, content_string
+ + hasread, 2047 - hasread)) > 0)
+ hasread += i;
+ mc_doublepclose (pipehandle, p);
+ content_string [hasread] = 0;
+ }
+ mc_close (remotehandle);
+ }
+#endif /* _OS_NT */
+ }
+ asked_file = 1;
+match_file_output:
+ if (hasread) {
+ if ((pp = strchr (content_string, '\n')) != 0)
+ *pp = 0;
+ if (islocal && !strncmp (content_string,
+ filename, file_len)) {
+ content_shift = file_len;
+ if (content_string [content_shift] == ':')
+ for (content_shift++;
+ content_string [content_shift] == ' ';
+ content_shift++);
+ } else if (!islocal
+ && !strncmp (content_string,
+ "standard input:", 15)) {
+ for (content_shift = 15;
+ content_string [content_shift] == ' ';
+ content_shift++);
+ }
+ if (content_string &&
+ regexp_match (p, content_string +
+ content_shift, match_normal)){
+ found = 1;
+ }
+ }
+ }
+ } else if (!strncmp (p, "default/", 8)) {
+ p += 8;
+ found = 1;
+ }
+ *q = c;
+ p = q;
+ if (!*p)
+ break;
+ } else { /* List of actions */
+ p = q;
+ q = strchr (p, '\n');
+ if (q == NULL)
+ q = strchr (p, 0);
+ if (found) {
+ r = strchr (p, '=');
+ if (r != NULL) {
+ c = *r;
+ *r = 0;
+ if (strcmp (p, "Include") == 0){
+ char *t;
+
+ include_target = p + 8;
+ t = strchr (include_target, '\n');
+ if (t) *t = 0;
+ include_target_len = strlen (include_target);
+ if (t) *t = '\n';
+
+ *r = c;
+ p = q;
+ found = 0;
+
+ if (!*p)
+ break;
+ continue;
+ }
+ if (action == NULL) {
+ if (strcmp (p, "Open") &&
+ strcmp (p, "View") &&
+ strcmp (p, "Edit") &&
+ strcmp (p, "Drop") &&
+ strcmp (p, "Icon") &&
+ strcmp (p, "Include") &&
+ strcmp (p, "Title")) {
+ /* I.e. this is a name of a user defined action */
+ static char *q;
+
+ if (to_return == NULL) {
+ to_return = xmalloc (512, "Action list");
+ q = to_return;
+ } else
+ *(q++) = '='; /* Mark separator */
+ strcpy (q, p);
+ q = strchr (q, 0);
+ }
+ *r = c;
+ } else if (!strcmp (action, "Icon")) {
+ if (!strcmp (p, "Icon") && to_return == NULL) {
+ *r = c;
+ c = *q;
+ *q = 0;
+ to_return = strdup (r + 1);
+ } else if (!strcmp (p, "Title") && regex_command_title == NULL) {
+ *r = c;
+ c = *q;
+ *q = 0;
+ regex_command_title = strdup (r + 1);
+ } else {
+ *r = c;
+ c = *q;
+ }
+ *q = c;
+ if (to_return != NULL && regex_command_title != NULL)
+ break;
+ } else if (!strcmp (action, p)) {
+ *r = c;
+ for (p = r + 1; *p == ' ' || *p == '\t'; p++)
+ ;
+
+ /* Empty commands just stop searching
+ * through, they don't do anything
+ *
+ * We need to copy the filename because exec_extension
+ * may end up invoking update_panels thus making the
+ * filename parameter invalid (ie, most of the time,
+ * we get filename as a pointer from cpanel->dir).
+ */
+ if (p < q) {
+ char *filename_copy = strdup (filename);
+ exec_extension (filename_copy, r + 1, drops, move_dir, view_at_line_number);
+ free (filename_copy);
+
+ to_return = "Success";
+ }
+ break;
+ } else
+ *r = c;
+ }
+ }
+ p = q;
+ if (!*p)
+ break;
+ }
+ }
+ easy_patterns = old_patterns;
+ return to_return;
+}
--- /dev/null
+#ifndef __EXT_H
+#define __EXT_H
+
+char *regex_command (char *filename, char *action, char **drops, int *move_dir);
+
+/* Call it after the user has edited the mc.ext file,
+ * to flush the cached mc.ext file
+ */
+void flush_extension_file (void);
+
+#ifdef OS2_NT
+# define MC_USER_EXT "mc.ext"
+# define MC_LIB_EXT "mc.ext"
+#else
+# define MC_USER_EXT ".mc/ext"
+# define MC_LIB_EXT "mc.ext"
+#endif
+#endif
--- /dev/null
+/* This just computes a nice value for the features variable */
+
+#ifndef VERSION
+# define VERSION "undefined"
+#endif
+
+char *features =
+ "Edition: "
+#ifdef HAVE_X
+# ifdef HAVE_XVIEW
+ "XView"
+# else
+ "Tk"
+# endif
+#else
+ "text mode"
+#endif
+ ".\n"
+
+#ifdef USE_VFS
+ "Virtual File System: tarfs, extfs"
+#ifdef USE_NETCODE
+ ", ftpfs"
+# ifdef HSC_PROXY
+ " (proxies: hsc proxy)"
+# endif
+ ", mcfs"
+# ifdef USE_TERMNET
+ " (with termnet support)"
+# endif
+#endif
+#ifdef USE_EXT2FSLIB
+ ", undelfs"
+#endif
+ ".\n"
+#endif
+
+#ifdef USE_INTERNAL_EDIT
+ "With builtin Editor\n"
+#endif
+
+ "Using "
+#ifdef HAVE_SLANG
+# ifdef HAVE_SYSTEM_SLANG
+ "system-installed "
+# endif
+ "S-lang library with "
+
+# ifdef SLANG_TERMINFO
+ "terminfo"
+# else
+# ifdef USE_TERMCAP
+ "termcap"
+# else
+ "an unknown terminal"
+# endif
+# endif
+ " database"
+#else
+# ifdef USE_NCURSES
+ "the ncurses library"
+# else
+ "some unknown curses library"
+# endif
+#endif
+ "\n"
+#ifdef HAVE_SUBSHELL_SUPPORT
+ "With subshell support: "
+# ifdef SUBSHELL_OPTIONAL
+ "optional"
+# else
+ "as default"
+# endif
+ "\n"
+#endif
+
+#ifdef HAVE_DUSUM
+ "With DUSUM command\n"
+#endif
+
+#ifdef WITH_BACKGROUND
+ "With support for background operations\n"
+#endif
+;
+
+static const int status_mouse_support =
+#ifdef HAVE_LIBGPM
+ 1;
+#else
+ 0;
+#endif
+
+const int status_using_ncurses =
+#ifdef HAVE_SLANG
+ 0;
+#else
+#ifdef USE_NCURSES
+ 1;
+#else
+ 0;
+#endif
+#endif
+
+
--- /dev/null
+/* {{{ Copyright */
+
+/* File managing. Important notes on this file:
+
+ About the use of dialogs in this file:
+ If you want to add a new dialog box (or call a routine that pops
+ up a dialog box), you have to provide a wrapper for background
+ operations (ie, background operations have to up-call to the parent
+ process).
+
+ For example, instead of using the message() routine, in this
+ file, you should use one of the stubs that call message with the
+ proper number of arguments (ie, message_1s, message_2s and so on).
+
+ Actually, that is a rule that should be followed by any routines
+ that may be called from this module.
+
+*/
+
+/* File managing
+ Copyright (C) 1994, 1995, 1996 The Free Software Foundation
+
+ Written by: 1994, 1995 Janne Kukonlehto
+ 1994, 1995 Fred Leeflang
+ 1994, 1995, 1996 Miguel de Icaza
+ 1995, 1996 Jakub Jelinek
+ 1997 Norbert Warmuth
+ 1998 Pavel Machek
+
+ The copy code was based in GNU's cp, and was written by:
+ Torbjorn Granlund, David MacKenzie, and Jim Meyering.
+
+ The move code was based in GNU's mv, and was written by:
+ Mike Parker and David MacKenzie.
+
+ Janne Kukonlehto added much error recovery to them for being used
+ in an interactive program.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* }}} */
+
+/* {{{ Include files */
+
+#include <config.h>
+/* Hack: the vfs code should not rely on this */
+#define WITH_FULL_PATHS 1
+
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#ifdef OS2_NT
+# include <io.h>
+#endif
+
+#include <errno.h>
+#include "tty.h"
+#include <ctype.h>
+#include <malloc.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#ifdef SCO_FLAVOR
+# include <sys/timeb.h> /* alex: for struct timeb, used in time.h */
+#endif /* SCO_FLAVOR */
+#if defined (__MINGW32__) || defined(_MSC_VER)
+#include <sys/time.h___>
+#else
+#include <time.h>
+#endif
+#include <utime.h>
+#include "mad.h"
+#include "regex.h"
+#include "util.h"
+#include "dialog.h"
+#include "global.h"
+/* Needed by query_replace */
+#include "color.h"
+#include "win.h"
+#include "dlg.h"
+#include "widget.h"
+#define WANT_WIDGETS
+#include "main.h" /* WANT_WIDGETS-> we get the the_hint def */
+#include "file.h"
+#include "layout.h"
+#include "widget.h"
+#include "wtools.h"
+#include "background.h"
+
+/* Needed for current_panel, other_panel and WTree */
+#include "dir.h"
+#include "panel.h"
+#include "tree.h"
+#include "key.h"
+#include "../vfs/vfs.h"
+
+#include "x.h"
+
+/* }}} */
+
+#if USE_VFS && USE_NETCODE
+extern
+#else
+static
+#endif
+
+int do_reget;
+
+/* rcsid [] = "$Id: file.c,v 1.1 2001/12/30 09:55:25 sedwards Exp $" */
+int verbose = 1;
+
+/* Recursive operation on subdirectories */
+int dive_into_subdirs = 0;
+
+/* When moving directories cross filesystem boundaries delete the successfull
+ copied files when all files below the directory and its subdirectories
+ were processed.
+ If erase_at_end is zero files will be deleted immediately after their
+ successful copy (Note: this behaviour is not tested and at the moment
+ it can't be changed at runtime) */
+int erase_at_end = 1;
+
+/* Preserve the original files' owner, group, permissions, and
+ timestamps (owner, group only as root). */
+int preserve;
+
+/* The value of the "preserve Attributes" checkbox in the copy file dialog.
+ We can't use the value of "preserve" because it can change in order to
+ preserve file attributs when moving files across filesystem boundaries
+ (we want to keep the value of the checkbox between copy operations). */
+int op_preserve = 1;
+
+/* If running as root, preserve the original uid/gid
+ (we don't want to try chwon for non root)
+ preserve_uidgid = preserve && uid == 0 */
+int preserve_uidgid = 0;
+
+/* The bits to preserve in created files' modes on file copy */
+int umask_kill = 0777777;
+
+/* If on, it gets a little scrict with dangerous operations */
+int know_not_what_am_i_doing = 0;
+
+int stable_symlinks = 0;
+
+/* The next two are not static, since they are used on background.c */
+/* Controls appending to files, shared with filequery.c */
+int do_append = 0;
+
+/* With ETA on we have extra screen space */
+int eta_extra = 0;
+
+/* result from the recursive query */
+int recursive_result;
+
+/* The estimated time of arrival in seconds */
+double eta_secs;
+
+/* Used to save the hint line */
+static int last_hint_line;
+
+/* mapping operations into names */
+char *operation_names [] = { "Copy", "Move", "Delete" };
+
+/* This is a hard link cache */
+struct link {
+ struct link *next;
+ vfs *vfs;
+ dev_t dev;
+ ino_t ino;
+ short linkcount;
+ umode_t st_mode;
+ char name[1];
+};
+
+/* the hard link cache */
+struct link *linklist = NULL;
+
+/* the files-to-be-erased list */
+struct link *erase_list;
+
+/* In copy_dir_dir we use two additional single linked lists: The first -
+ variable name `parent_dirs' - holds information about already copied
+ directories and is used to detect cyclic symbolic links.
+ The second (`dest_dirs' below) holds information about just created
+ target directories and is used to detect when an directory is copied
+ into itself (we don't want to copy infinitly).
+ Both lists don't use the linkcount and name structure members of struct
+ link. */
+struct link *dest_dirs = 0;
+
+struct re_pattern_buffer rx;
+struct re_registers regs;
+static char *dest_mask = NULL;
+
+/* To symlinks the difference between `follow Links' checked and not
+ checked is the stat call used (mc_stat resp. mc_lstat) */
+int (*xstat)(char *, struct stat *) = mc_lstat;
+
+static int op_follow_links = 0;
+
+/* File operate window sizes */
+#define WX 62
+#define WY 10
+#define BY 10
+#define WX_ETA_EXTRA 12
+
+#define FCOPY_GAUGE_X 14
+#define FCOPY_LABEL_X 5
+
+/* Used for button result values */
+enum {
+ REPLACE_YES = B_USER,
+ REPLACE_NO,
+ REPLACE_APPEND,
+ REPLACE_ALWAYS,
+ REPLACE_UPDATE,
+ REPLACE_NEVER,
+ REPLACE_ABORT,
+ REPLACE_SIZE,
+ REPLACE_REGET
+};
+
+enum {
+ RECURSIVE_YES,
+ RECURSIVE_NO,
+ RECURSIVE_ALWAYS,
+ RECURSIVE_NEVER,
+ RECURSIVE_ABORT
+};
+
+/* Pointer to the operate dialog */
+static Dlg_head *op_dlg;
+int showing_eta;
+int showing_bps;
+unsigned long bps = 0, bps_time = 0;
+
+static char *op_names [] = { N_(" Copy "), N_(" Move "), N_(" Delete ") };
+static int selected_button;
+static int last_percentage [3];
+
+/* Replace dialog: color set, descriptor and filename */
+static int replace_colors [4];
+static Dlg_head *replace_dlg;
+static char *replace_filename;
+static int replace_result;
+
+static struct stat *s_stat, *d_stat;
+
+static int recursive_erase (char *s);
+static int erase_file (char *s);
+
+/* Describe the components in the panel operations window */
+static WLabel *FileLabel [2];
+static WLabel *FileString [2];
+static WLabel *ProgressLabel [3];
+static WGauge *ProgressGauge [3];
+static WLabel *eta_label;
+static WLabel *bps_label;
+static WLabel *stalled_label;
+
+/* }}} */
+
+/* {{{ File progress display routines */
+
+#ifndef HAVE_X
+static int
+check_buttons (void)
+{
+ int c;
+ Gpm_Event event;
+
+ c = get_event (&event, 0, 0);
+ if (c == EV_NONE)
+ return FILE_CONT;
+ dlg_process_event (op_dlg, c, &event);
+ switch (op_dlg->ret_value) {
+ case FILE_SKIP:
+ return FILE_SKIP;
+ break;
+ case B_CANCEL:
+ case FILE_ABORT:
+ return FILE_ABORT;
+ break;
+ default:
+ return FILE_CONT;
+ }
+}
+#else
+
+#ifdef HAVE_TK
+static int
+check_buttons (void)
+{
+ tk_dispatch_all ();
+ if (op_dlg->running)
+ return FILE_CONT;
+}
+#endif /* HAVE_TK */
+
+#ifdef HAVE_XVIEW
+static int
+check_buttons (void)
+{
+ xv_dispatch_something ();
+ if (op_dlg->running)
+ return FILE_CONT;
+}
+#endif /* HAVE_XVIEW */
+
+#ifdef HAVE_GNOME
+#include <gtk/gtk.h>
+static int
+check_buttons (void)
+{
+ x_flush_events ();
+
+ if (op_dlg->running)
+ return FILE_CONT;
+
+ if (op_dlg->ret_value == B_CANCEL)
+ return FILE_ABORT;
+ else
+ return op_dlg->ret_value;
+}
+#endif /* HAVE_GNOME */
+
+#endif /* HAVE_X */
+
+static int
+op_win_callback (struct Dlg_head *h, int id, int msg)
+{
+ switch (msg){
+#ifndef HAVE_X
+ case DLG_DRAW:
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 1, 2, h->lines-2, h->cols-4);
+ return 1;
+#endif
+ }
+ return 0;
+}
+
+void
+create_op_win (int op, int with_eta)
+{
+ int i, x_size;
+ int minus = verbose ? 0 : 3;
+ int eta_offset = with_eta ? (WX_ETA_EXTRA) / 2 : 0;
+
+#ifdef HAVE_XVIEW
+ char *sixty = " ";
+ char *fifteen = " ";
+#else
+ char *sixty = "";
+ char *fifteen = "";
+#endif
+ replace_result = 0;
+ recursive_result = 0;
+ showing_eta = with_eta;
+ showing_bps = with_eta;
+ eta_extra = with_eta ? WX_ETA_EXTRA : 0;
+ x_size = (WX + 4) + eta_extra;
+
+ op_dlg = create_dlg (0, 0, WY-minus+4, x_size, dialog_colors,
+ op_win_callback, "", "opwin", DLG_CENTER);
+
+#ifndef HAVE_X
+ last_hint_line = the_hint->widget.y;
+ if ((op_dlg->y + op_dlg->lines) > last_hint_line)
+ the_hint->widget.y = op_dlg->y + op_dlg->lines+1;
+#endif
+
+ x_set_dialog_title (op_dlg, "");
+
+ tk_new_frame (op_dlg, "b.");
+ add_widgetl (op_dlg, button_new (BY-minus, WX - 19 + eta_offset, FILE_ABORT,
+ NORMAL_BUTTON, _("&Abort"), 0, 0, "abort"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, button_new (BY-minus, 14 + eta_offset, FILE_SKIP,
+ NORMAL_BUTTON, _("&Skip"), 0, 0, "skip"),
+ XV_WLAY_CENTERROW);
+
+ tk_new_frame (op_dlg, "2.");
+ add_widgetl (op_dlg, ProgressGauge [2] = gauge_new (7, FCOPY_GAUGE_X, 0, 100, 0, "g-1"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, ProgressLabel [2] = label_new (7, FCOPY_LABEL_X, fifteen, "l-1"),
+ XV_WLAY_NEXTROW);
+ add_widgetl (op_dlg, bps_label = label_new (7, WX, "", "bps-label"), XV_WLAY_NEXTROW);
+
+ tk_new_frame (op_dlg, "1.");
+ add_widgetl (op_dlg, ProgressGauge [1] = gauge_new (8, FCOPY_GAUGE_X, 0, 100, 0, "g-2"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, ProgressLabel [1] = label_new (8, FCOPY_LABEL_X, fifteen, "l-2"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, stalled_label = label_new (8, WX, "", "stalled"), XV_WLAY_NEXTROW);
+
+ tk_new_frame (op_dlg, "0.");
+ add_widgetl (op_dlg, ProgressGauge [0] = gauge_new (6, FCOPY_GAUGE_X, 0, 100, 0, "g-3"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, ProgressLabel [0] = label_new (6, FCOPY_LABEL_X, fifteen, "l-3"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, eta_label = label_new (6, WX, "", "eta_label"), XV_WLAY_NEXTROW);
+
+ tk_new_frame (op_dlg, "f1.");
+ add_widgetl (op_dlg, FileString [1] = label_new (4, FCOPY_GAUGE_X, sixty, "fs-l-1"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, FileLabel [1] = label_new (4, FCOPY_LABEL_X, fifteen, "fs-l-2"),
+ XV_WLAY_NEXTROW);
+ tk_new_frame (op_dlg, "f0.");
+ add_widgetl (op_dlg, FileString [0] = label_new (3, FCOPY_GAUGE_X, sixty, "fs-x-1"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (op_dlg, FileLabel [0] = label_new (3, FCOPY_LABEL_X, fifteen, "fs-x-2"),
+ XV_WLAY_NEXTROW);
+
+ /* We will manage the dialog without any help, that's why
+ we have to call init_dlg */
+ init_dlg (op_dlg);
+ op_dlg->running = 1;
+ selected_button = FILE_SKIP;
+ for (i = 0; i < 3; i++)
+ last_percentage [i] = -99;
+}
+
+void
+destroy_op_win (void)
+{
+#ifdef HAVE_XVIEW
+ xtoolkit_kill_dialog (op_dlg);
+#endif
+ dlg_run_done (op_dlg);
+ destroy_dlg (op_dlg);
+#ifndef HAVE_X
+ the_hint->widget.y = last_hint_line;
+#endif
+}
+
+static int
+show_no_bar (int n)
+{
+ if (n >= 0) {
+ label_set_text (ProgressLabel [n], "");
+ gauge_show (ProgressGauge [n], 0);
+ }
+ return check_buttons ();
+}
+
+#ifndef HAVE_X
+#define truncFileString(s) name_trunc (s, eta_extra + 47)
+#else
+#define truncFileString(s) s
+#endif
+
+static int
+show_source (char *s)
+{
+ if (s != NULL){
+
+#ifdef WITH_FULL_PATHS
+ int i = strlen (cpanel->cwd);
+
+ /* We remove the full path we have added before */
+ if (!strncmp (s, cpanel->cwd, i)){
+ if (s[i] == PATH_SEP)
+ s += i + 1;
+ }
+#endif /* WITH_FULL_PATHS */
+
+ label_set_text (FileLabel [0], _("Source"));
+ label_set_text (FileString [0], truncFileString (s));
+ return check_buttons ();
+ } else {
+ label_set_text (FileLabel [0], "");
+ label_set_text (FileString [0], "");
+ return check_buttons ();
+ }
+}
+
+static int
+show_target (char *s)
+{
+ if (s != NULL){
+ label_set_text (FileLabel [1], _("Target"));
+ label_set_text (FileString [1], truncFileString (s));
+ return check_buttons ();
+ } else {
+ label_set_text (FileLabel [1], "");
+ label_set_text (FileString [1], "");
+ return check_buttons ();
+ }
+}
+
+static int
+show_deleting (char *s)
+{
+ label_set_text (FileLabel [0], _("Deleting"));
+ label_set_text (FileString [0], truncFileString (s));
+ return check_buttons ();
+}
+
+static int
+show_bar (int n, long done, long total)
+{
+ gauge_set_value (ProgressGauge [n], (int) total, (int) done);
+ gauge_show (ProgressGauge [n], 1);
+ return check_buttons ();
+}
+
+static void
+file_eta_show ()
+{
+ int eta_hours, eta_mins, eta_s;
+ char eta_buffer [30];
+
+ if (!showing_eta)
+ return;
+
+ eta_hours = eta_secs / (60 * 60);
+ eta_mins = (eta_secs - (eta_hours * 60 * 60)) / 60;
+ eta_s = eta_secs - ((eta_hours * 60 * 60) + eta_mins * 60 );
+ sprintf (eta_buffer, "ETA %d:%02d.%02d", eta_hours, eta_mins, eta_s);
+ label_set_text (eta_label, eta_buffer);
+}
+
+static void
+file_bps_show ()
+{
+ char bps_buffer [30];
+
+ if (!showing_bps)
+ return;
+
+ if (bps > 1024){
+ if (bps > 1024*1024){
+ sprintf (bps_buffer, "%.2f MBS", bps / (1024*1024.0));
+ } else
+ sprintf (bps_buffer, "%.2f KBS", bps / 1024.0);
+ } else
+ sprintf (bps_buffer, "%ld BPS", bps);
+ label_set_text (bps_label, bps_buffer);
+}
+
+static int
+show_file_progress (long done, long total)
+{
+ if (!verbose)
+ return check_buttons ();
+ if (total > 0){
+ label_set_text (ProgressLabel [0], _("File"));
+ file_eta_show ();
+ file_bps_show ();
+ return show_bar (0, done, total);
+ } else
+ return show_no_bar (0);
+}
+
+static int
+show_count_progress (long done, long total)
+{
+ if (!verbose)
+ return check_buttons ();
+ if (total > 0){
+ label_set_text (ProgressLabel [1], _("Count"));
+ return show_bar (1, done, total);
+ } else
+ return show_no_bar (1);
+}
+
+static int
+show_bytes_progress (long done, long total)
+{
+ if (!verbose)
+ return check_buttons ();
+ if (total > 0){
+ label_set_text (ProgressLabel [2], _("Bytes"));
+ return show_bar (2, done, total);
+ } else
+ return show_no_bar (2);
+}
+
+/* }}} */
+
+
+/* {{{ Copy routines */
+
+enum CaseConvs { NO_CONV=0, UP_CHAR=1, LOW_CHAR=2, UP_SECT=4, LOW_SECT=8 };
+
+int
+convert_case (int c, enum CaseConvs *conversion)
+{
+ if (*conversion & UP_CHAR){
+ *conversion &= ~UP_CHAR;
+ return toupper (c);
+ } else if (*conversion & LOW_CHAR){
+ *conversion &= ~LOW_CHAR;
+ return tolower (c);
+ } else if (*conversion & UP_SECT){
+ return toupper (c);
+ } else if (*conversion & LOW_SECT){
+ return tolower (c);
+ } else
+ return c;
+}
+
+static int transform_error = 0;
+static char *
+do_transform_source (char *source)
+{
+ int j, k, l, len;
+ char *fnsource = x_basename (source);
+ int next_reg;
+ enum CaseConvs case_conv = NO_CONV;
+ static char fntarget [MC_MAXPATHLEN];
+
+ len = strlen (fnsource);
+ j = re_match (&rx, fnsource, len, 0, ®s);
+ if (j != len) {
+ transform_error = FILE_SKIP;
+ return NULL;
+ }
+ for (next_reg = 1, j = 0, k = 0; j < strlen (dest_mask); j++) {
+ switch (dest_mask [j]) {
+ case '\\':
+ j++;
+ if (! isdigit (dest_mask [j])){
+ /* Backslash followed by non-digit */
+ switch (dest_mask [j]){
+ case 'U':
+ case_conv |= UP_SECT;
+ case_conv &= ~LOW_SECT;
+ break;
+ case 'u':
+ case_conv |= UP_CHAR;
+ break;
+ case 'L':
+ case_conv |= LOW_SECT;
+ case_conv &= ~UP_SECT;
+ break;
+ case 'l':
+ case_conv |= LOW_CHAR;
+ break;
+ case 'E':
+ case_conv = NO_CONV;
+ break;
+ default:
+ /* Backslash as quote mark */
+ fntarget [k++] = convert_case (dest_mask [j], &case_conv);
+ }
+ break;
+ } else {
+ /* Backslash followed by digit */
+ next_reg = dest_mask [j] - '0';
+ /* Fall through */
+ }
+
+ case '*':
+ if (next_reg < 0 || next_reg >= RE_NREGS
+ || regs.start [next_reg] < 0) {
+ message_1s (1, MSG_ERROR, _(" Invalid target mask "));
+ transform_error = FILE_ABORT;
+ return NULL;
+ }
+ for (l = regs.start [next_reg]; l < regs.end [next_reg]; l++)
+ fntarget [k++] = convert_case (fnsource [l], &case_conv);
+ next_reg ++;
+ break;
+
+ default:
+ fntarget [k++] = convert_case (dest_mask [j], &case_conv);
+ break;
+ }
+ }
+ fntarget [k] = 0;
+ return fntarget;
+}
+
+static char *
+transform_source (char *source)
+{
+ char *s = strdup (source);
+ char *q;
+
+ /* We remove \n from the filename since regex routines would use \n as an anchor */
+ /* this is just to be allowed to maniupulate file names with \n on it */
+ for (q = s; *q; q++){
+ if (*q == '\n')
+ *q = ' ';
+ }
+ q = do_transform_source (s);
+ free (s);
+ return q;
+}
+
+void
+free_linklist (struct link **linklist)
+{
+ struct link *lp, *lp2;
+
+ for (lp = *linklist; lp != NULL; lp = lp2){
+ lp2 = lp -> next;
+ free (lp);
+ }
+ *linklist = NULL;
+}
+
+#ifdef USE_VFS
+int
+is_in_linklist (struct link *lp, char *path, struct stat *sb)
+{
+ ino_t ino = sb->st_ino;
+ dev_t dev = sb->st_dev;
+ vfs *vfs = vfs_type (path);
+
+ while (lp) {
+ if (lp->vfs == vfs && lp->ino == ino && lp->dev == dev )
+ return 1;
+ lp = lp->next;
+ }
+ return 0;
+}
+#else
+int
+is_in_linklist (struct link *lp, char *path, struct stat *sb)
+{
+ ino_t ino = sb->st_ino;
+ dev_t dev = sb->st_dev;
+
+ while (lp) {
+ if (lp->ino == ino && lp->dev == dev )
+ return 1;
+ lp = lp->next;
+ }
+ return 0;
+}
+#endif
+
+/* Returns 0 if the inode wasn't found in the cache and 1 if it was found
+ and a hardlink was succesfully made */
+int
+check_hardlinks (char *src_name, char *dst_name, struct stat *pstat)
+{
+ struct link *lp;
+ vfs *my_vfs = vfs_type (src_name);
+ ino_t ino = pstat->st_ino;
+ dev_t dev = pstat->st_dev;
+ struct stat link_stat;
+ char *p;
+
+ if (vfs_file_is_ftp (src_name))
+ return 0;
+ for (lp = linklist; lp != NULL; lp = lp -> next)
+ if (lp->vfs == my_vfs && lp->ino == ino && lp->dev == dev){
+ if (!mc_stat (lp->name, &link_stat) && link_stat.st_ino == ino &&
+ link_stat.st_dev == dev && vfs_type (lp->name) == my_vfs){
+ p = strchr (lp->name, 0) + 1; /* i.e. where the `name' file
+ was copied to */
+ if (vfs_type (dst_name) == vfs_type (p)){
+ if (!mc_stat (p, &link_stat)){
+ if (!mc_link (p, dst_name))
+ return 1;
+ }
+ }
+ }
+ /* FIXME: Announce we couldn't make the hardlink */
+ return 0;
+ }
+ lp = (struct link *) xmalloc (sizeof (struct link) + strlen (src_name)
+ + strlen (dst_name) + 1, "Hardlink cache");
+ if (lp){
+ lp->vfs = my_vfs;
+ lp->ino = ino;
+ lp->dev = dev;
+ strcpy (lp->name, src_name);
+ p = strchr (lp->name, 0) + 1;
+ strcpy (p, dst_name);
+ lp->next = linklist;
+ linklist = lp;
+ }
+ return 0;
+}
+
+/* Duplicate the contents of the symbolic link src_path in dst_path.
+ Try to make a stable symlink if the option "stable symlink" was
+ set in the file mask dialog.
+ If dst_path is an existing symlink it will be deleted silently
+ (upper levels take already care of existing files at dst_path).
+ */
+static int
+make_symlink (char *src_path, char *dst_path)
+{
+ char link_target[MC_MAXPATHLEN];
+ int len;
+ int return_status;
+ struct stat sb;
+ int dst_is_symlink;
+
+ if (mc_lstat (dst_path, &sb) == 0 && S_ISLNK (sb.st_mode))
+ dst_is_symlink = 1;
+ else
+ dst_is_symlink = 0;
+
+ retry_src_readlink:
+ len = mc_readlink (src_path, link_target, MC_MAXPATHLEN);
+ if (len < 0) {
+ return_status = file_error
+ (_(" Cannot read source link \"%s\" \n %s "), src_path);
+ if (return_status == FILE_RETRY)
+ goto retry_src_readlink;
+ return return_status;
+ }
+ link_target[len] = 0;
+
+ if (stable_symlinks && (!vfs_file_is_local (src_path) ||
+ !vfs_file_is_local (dst_path))) {
+ message_1s (1, MSG_ERROR, _(" Cannot make stable symlinks across "
+ "non-local filesystems: \n\n"
+ " Option Stable Symlinks will be disabled "));
+ stable_symlinks = 0;
+ }
+
+ if (stable_symlinks && *link_target != PATH_SEP) {
+ char *p, *q, *r, *s;
+
+ p = strdup (src_path);
+ r = strrchr (p, PATH_SEP);
+ if (r) {
+ r[1] = 0;
+ if (*dst_path == PATH_SEP)
+ q = strdup (dst_path);
+ else
+ q = copy_strings (p, dst_path, 0);
+ r = strrchr (q, PATH_SEP);
+ if (r) {
+ r[1] = 0;
+ s = copy_strings (p, link_target, NULL);
+ strcpy (link_target, s);
+ free (s);
+ s = diff_two_paths (q, link_target);
+ if (s) {
+ strcpy (link_target, s);
+ free (s);
+ }
+ }
+ free (q);
+ }
+ free (p);
+ }
+ retry_dst_symlink:
+ if (mc_symlink (link_target, dst_path) == 0)
+ /* Success */
+ return FILE_CONT;
+ /*
+ * if dst_exists, it is obvious that this had failed.
+ * We can delete the old symlink and try again...
+ */
+ if (dst_is_symlink) {
+ if (!mc_unlink (dst_path))
+ if (mc_symlink (link_target, dst_path) == 0)
+ /* Success */
+ return FILE_CONT;
+ }
+ return_status = file_error
+ (_(" Cannot create target symlink \"%s\" \n %s "), dst_path);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_symlink;
+ return return_status;
+}
+
+
+int
+copy_file_file (char *src_path, char *dst_path, int ask_overwrite)
+{
+#ifndef OS2_NT
+ uid_t src_uid;
+ gid_t src_gid;
+#endif
+ char *buf = 0;
+ int buf_size = 8*1024;
+ int dest_desc = 0;
+ int source_desc;
+ int n_read;
+ int n_written;
+ int src_mode; /* The mode of the source file */
+ struct stat sb, sb2;
+ struct utimbuf utb;
+ int dst_exists = 0;
+ long n_read_total = 0;
+ long file_size;
+ int return_status, temp_status;
+ int do_remote_copy = 0;
+ int appending = 0;
+ /* bitmask used to remember which resourses we should release on return
+ A single goto label is much easier to handle than a bunch of gotos ;-). */
+ unsigned resources = 0;
+
+ return_status = FILE_RETRY;
+
+ if (show_source (src_path) == FILE_ABORT
+ || show_target (dst_path) == FILE_ABORT)
+ return FILE_ABORT;
+ mc_refresh ();
+
+ retry_dst_stat:
+ if (mc_stat (dst_path, &sb2) == 0){
+ if (S_ISDIR (sb2.st_mode)){
+ return_status = file_error (_(" Cannot overwrite directory \"%s\" \n %s "),
+ dst_path);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_stat;
+ return return_status;
+ }
+ dst_exists = 1;
+ }
+
+ retry_src_xstat:
+ if ((*xstat)(src_path, &sb)){
+ return_status = file_error (_(" Cannot stat source file \"%s\" \n %s "),
+ src_path);
+ if (return_status == FILE_RETRY)
+ goto retry_src_xstat;
+ return return_status;
+ }
+
+ if (dst_exists){
+ /* .ado: For OS/2 or NT: no st_ino exists, it is better to just try to
+ * overwrite the target file
+ */
+#ifndef OS2_NT
+ /* Destination already exists */
+ if (sb.st_dev == sb2.st_dev && sb.st_ino == sb2.st_ino){
+ message_3s (1, MSG_ERROR, _(" `%s' and `%s' are the same file. "),
+ src_path, dst_path);
+ do_refresh ();
+ return FILE_SKIP;
+ }
+#endif
+
+ /* Should we replace destination? */
+ if (ask_overwrite) {
+ if (vfs_file_is_ftp (src_path))
+ do_reget = -1;
+ else
+ do_reget = 0;
+
+ return_status = query_replace (dst_path, &sb, &sb2);
+ if (return_status != FILE_CONT)
+ return return_status;
+ }
+ }
+
+ if (!do_append) {
+ /* .ado: OS2 and NT don't have hardlinks */
+#ifndef OS2_NT
+ /* Check the hardlinks */
+ if (!op_follow_links && sb.st_nlink > 1 &&
+ check_hardlinks (src_path, dst_path, &sb) == 1) {
+ /* We have made a hardlink - no more processing is necessary */
+ return return_status;
+ }
+
+ if (S_ISLNK (sb.st_mode))
+ return make_symlink (src_path, dst_path);
+
+#endif /* !OS_NT */
+
+ if (S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode) || S_ISFIFO (sb.st_mode)
+ || S_ISSOCK (sb.st_mode)){
+ retry_mknod:
+ if (mc_mknod (dst_path, sb.st_mode & umask_kill, sb.st_rdev) < 0){
+ return_status = file_error
+ (_(" Cannot create special file \"%s\" \n %s "), dst_path);
+ if (return_status == FILE_RETRY)
+ goto retry_mknod;
+ return return_status;
+ }
+ /* Success */
+
+#ifndef OS2_NT
+ retry_mknod_uidgid:
+ if (preserve_uidgid && mc_chown (dst_path, sb.st_uid, sb.st_gid)){
+ temp_status = file_error
+ (_(" Cannot chown target file \"%s\" \n %s "), dst_path);
+ if (temp_status == FILE_RETRY)
+ goto retry_mknod_uidgid;
+ return temp_status;
+ }
+#endif
+#ifndef __os2__
+ retry_mknod_chmod:
+ if (preserve && mc_chmod (dst_path, sb.st_mode & umask_kill) < 0){
+ temp_status = file_error (_(" Cannnot chmod target file \"%s\" \n %s "), dst_path);
+ if (temp_status == FILE_RETRY)
+ goto retry_mknod_chmod;
+ return temp_status;
+ }
+#endif
+ return FILE_CONT;
+ }
+ }
+
+ if (!do_append && !vfs_file_is_local (src_path) && vfs_file_is_local (dst_path)){
+ mc_setctl (src_path, MCCTL_SETREMOTECOPY, dst_path);
+ }
+ retry_src_open:
+ if ((source_desc = mc_open (src_path, O_RDONLY)) < 0){
+ return_status = file_error
+ (_(" Cannot open source file \"%s\" \n %s "), src_path);
+ if (return_status == FILE_RETRY)
+ goto retry_src_open;
+ do_append = 0;
+ return return_status;
+ }
+
+ resources |= 1;
+ do_remote_copy = mc_ctl (source_desc, MCCTL_ISREMOTECOPY, 0);
+
+ if (!do_remote_copy) {
+ retry_src_fstat:
+ if (mc_fstat (source_desc, &sb)){
+ return_status = file_error
+ (_(" Cannot fstat source file \"%s\" \n %s "), src_path);
+ if (return_status == FILE_RETRY)
+ goto retry_src_fstat;
+ do_append = 0;
+ goto ret;
+ }
+#if 0
+ /* Im not sure if we can delete this. sb is already filled by
+ (*xstat)() - Norbert. */
+ } else {
+ retry_src_rstat:
+ if (mc_stat (src_path, &sb)){
+ return_status = file_error
+ (_(" Cannot stat source file \"%s\" \n %s "), src_path);
+ if (return_status == FILE_RETRY)
+ goto retry_src_rstat;
+ do_append = 0;
+ goto ret;
+ }
+#endif
+ }
+ src_mode = sb.st_mode;
+#ifndef OS2_NT
+ src_uid = sb.st_uid;
+ src_gid = sb.st_gid;
+#endif
+ utb.actime = sb.st_atime;
+ utb.modtime = sb.st_mtime;
+ file_size = sb.st_size;
+
+ /* Create the new regular file with small permissions initially,
+ do not create a security hole. */
+
+ if (!do_remote_copy) {
+ retry_dst_open:
+ if ((do_append &&
+ (dest_desc = mc_open (dst_path, O_WRONLY | O_APPEND)) < 0) ||
+ (!do_append &&
+ (dest_desc = mc_open (dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)) {
+ return_status = file_error
+ (_(" Cannot create target file \"%s\" \n %s "), dst_path);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_open;
+ do_append = 0;
+ goto ret;
+ }
+ resources |= 2; /* dst_path exists/dst_path opened */
+ resources |= 4; /* remove short file */
+ }
+ appending = do_append;
+ do_append = 0;
+
+ if (!do_remote_copy) {
+ retry_dst_fstat:
+ /* Find out the optimal buffer size. */
+ if (mc_fstat (dest_desc, &sb)){
+ return_status = file_error
+ (_(" Cannot fstat target file \"%s\" \n %s "), dst_path);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_fstat;
+ goto ret;
+ }
+ buf_size = 8*1024;
+
+ buf = (char *) xmalloc (buf_size, "copy_file_file");
+ }
+
+ return_status = show_file_progress (0, file_size);
+ mc_refresh ();
+ if (return_status != FILE_CONT)
+ goto ret;
+
+ if (!do_remote_copy){
+ for (;;){
+ retry_src_read:
+ n_read = mc_read (source_desc, buf, buf_size);
+ if (n_read < 0){
+ return_status = file_error
+ (_(" Cannot read source file \"%s\" \n %s "), src_path);
+ if (return_status == FILE_RETRY)
+ goto retry_src_read;
+ goto ret;
+ }
+ if (n_read == 0)
+ break;
+
+ n_read_total += n_read;
+
+ retry_dst_write:
+ n_written = mc_write (dest_desc, buf, n_read);
+ if (n_written < n_read){
+ return_status = file_error
+ (_(" Cannot write target file \"%s\" \n %s "), dst_path);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_write;
+ goto ret;
+ }
+ return_status = show_file_progress (n_read_total, file_size);
+ mc_refresh ();
+ if (return_status != FILE_CONT)
+ goto ret;
+ }
+ } else {
+ struct timeval tv_current;
+ struct timeval tv_transfer_start;
+ struct timeval tv_last_update;
+ struct timeval tv_last_input;
+ int i, size, secs, update_secs;
+ long dt;
+ char *stalled_msg;
+
+ gettimeofday (&tv_transfer_start, (struct timezone *) NULL);
+ tv_last_update = tv_transfer_start;
+ eta_secs = 0.0;
+
+ for (i = 1; i;) {
+ switch (size = mc_ctl (source_desc, MCCTL_REMOTECOPYCHUNK, 8192)) {
+ case MCERR_TARGETOPEN:
+ message_1s (1, MSG_ERROR, _(" Can't open target file "));
+ goto ret;
+ case MCERR_READ:
+ goto ret;
+ case MCERR_WRITE:
+ message_1s (1, MSG_ERROR, _(" Can't write to local target file "));
+ goto ret;
+ case MCERR_DATA_ON_STDIN:
+ break;
+ case MCERR_FINISH:
+ resources |= 8;
+ i = 0;
+ break;
+ }
+
+ /* the first time we reach this line the target file has been created
+ or truncated and we actually have a short target file.
+ Do we really want to delete the target file when the ftp transfer
+ fails? If we don't delete it we would be able to use reget later.
+ (Norbert) */
+ resources |= 4; /* remove short file */
+
+ if (i && size != MCERR_DATA_ON_STDIN){
+ n_read_total += size;
+
+ /* Windows NT ftp servers report that files have no
+ * permissions: -------, so if we happen to have actually
+ * read something, we should fix the permissions.
+ */
+ if (!(src_mode &
+ ((S_IRUSR|S_IWUSR|S_IXUSR) /* user */
+ |(S_IXOTH|S_IWOTH|S_IROTH) /* other */
+ |(S_IXGRP|S_IWGRP|S_IRGRP)))) /* group */
+ src_mode = S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP;
+
+ gettimeofday (&tv_last_input, NULL);
+ }
+ /* Timed operations: */
+ gettimeofday (&tv_current, NULL);
+
+ /* 1. Update rotating dash after some time (hardcoded to 2 seconds) */
+ secs = (tv_current.tv_sec - tv_last_update.tv_sec);
+ if (secs > 2){
+ rotate_dash ();
+ tv_last_update = tv_current;
+ }
+
+ /* 2. Check for a stalled condition */
+ update_secs = (tv_current.tv_sec - tv_last_input.tv_sec);
+ stalled_msg = "";
+ if (update_secs > 4){
+ stalled_msg = _("(stalled)");
+ }
+
+ /* 3. Compute ETA */
+ if (secs > 2 || eta_secs == 0.0){
+ dt = (tv_current.tv_sec - tv_transfer_start.tv_sec);
+
+ if (n_read_total){
+ eta_secs = ((dt / (double) n_read_total) * file_size) - dt;
+ bps = n_read_total / ((dt < 1) ? 1 : dt);
+ } else
+ eta_secs = 0.0;
+ }
+
+ /* 4. Compute BPS rate */
+ if (secs > 2){
+ bps_time = (tv_current.tv_sec - tv_transfer_start.tv_sec);
+ if (bps_time < 1)
+ bps_time = 1;
+ bps = n_read_total / bps_time;
+ }
+
+ label_set_text (stalled_label, stalled_msg);
+
+ return_status = show_file_progress (n_read_total, file_size);
+ mc_refresh ();
+ if (return_status != FILE_CONT)
+ goto ret;
+ }
+ }
+ resources &= ~4; /* copy successful, don't remove target file */
+
+ret:
+ if (buf)
+ free (buf);
+
+ retry_src_close:
+ if ((resources & 1) && mc_close (source_desc) < 0){
+ temp_status = file_error
+ (_(" Cannot close source file \"%s\" \n %s "), src_path);
+ if (temp_status == FILE_RETRY)
+ goto retry_src_close;
+ if (temp_status == FILE_ABORT)
+ return_status = temp_status;
+ }
+
+ retry_dst_close:
+ if ((resources & 2) && mc_close (dest_desc) < 0){
+ temp_status = file_error
+ (_(" Cannot close target file \"%s\" \n %s "), dst_path);
+ if (temp_status == FILE_RETRY)
+ goto retry_dst_close;
+ return_status = temp_status;
+ }
+
+ if (resources & 4) {
+ /* Remove short file */
+ mc_unlink (dst_path);
+ if (do_remote_copy) {
+ mc_ctl (source_desc, MCCTL_FINISHREMOTE, -1);
+ }
+ } else if (resources & (2|8)) {
+ /* no short file and destination file exists */
+#ifndef OS2_NT
+ if (!appending && preserve_uidgid) {
+ retry_dst_chown:
+ if (mc_chown (dst_path, src_uid, src_gid)){
+ temp_status = file_error
+ (_(" Cannot chown target file \"%s\" \n %s "), dst_path);
+ if (temp_status == FILE_RETRY)
+ goto retry_dst_chown;
+ return_status = temp_status;
+ }
+ }
+#endif
+
+ /* .ado: according to the XPG4 standard, the file must be closed before
+ * chmod can be invoked
+ */
+ retry_dst_chmod:
+ if (!appending && mc_chmod (dst_path, src_mode & umask_kill)){
+ temp_status = file_error
+ (_(" Cannot chmod target file \"%s\" \n %s "), dst_path);
+ if (temp_status == FILE_RETRY)
+ goto retry_dst_chmod;
+ return_status = temp_status;
+ }
+
+ if (!appending && preserve)
+ mc_utime (dst_path, &utb);
+ }
+ return return_status;
+}
+
+/*
+ * I think these copy_*_* functions should have a return type.
+ * anyway, this function *must* have two directories as arguments.
+ */
+/* FIXME: This function needs to check the return values of the
+ function calls */
+int
+copy_dir_dir (char *s, char *d, int toplevel, int move_over, int delete,
+ struct link *parent_dirs)
+{
+#ifdef __os2__
+ DIR *next;
+#else
+ struct dirent *next;
+#endif
+ struct stat buf, cbuf;
+ DIR *reading;
+ char *path, *mdpath, *dest_file, *dest_dir;
+ int return_status = FILE_CONT;
+ struct utimbuf utb;
+ struct link *lp;
+
+ /* First get the mode of the source dir */
+ retry_src_stat:
+ if ((*xstat) (s, &cbuf)){
+ return_status = file_error (_(" Cannot stat source directory \"%s\" \n %s "), s);
+ if (return_status == FILE_RETRY)
+ goto retry_src_stat;
+ return return_status;
+ }
+
+ if (is_in_linklist (dest_dirs, s, &cbuf)) {
+ /* Don't copy a directory we created before (we don't want to copy
+ infinitely if a directory is copied into itself) */
+ /* FIXME: should there be an error message and FILE_SKIP? - Norbert */
+ return FILE_CONT;
+ }
+
+/* Hmm, hardlink to directory??? - Norbert */
+/* FIXME: In this step we should do something
+ in case the destination already exist */
+ /* Check the hardlinks */
+ if (preserve && cbuf.st_nlink > 1 && check_hardlinks (s, d, &cbuf) == 1) {
+ /* We have made a hardlink - no more processing is necessary */
+ return return_status;
+ }
+
+ if (!S_ISDIR (cbuf.st_mode)){
+ return_status = file_error (_(" Source directory \"%s\" is not a directory \n %s "), s);
+ if (return_status == FILE_RETRY)
+ goto retry_src_stat;
+ return return_status;
+ }
+
+#ifndef OS2_NT
+ if (is_in_linklist (parent_dirs, s, &cbuf)) {
+ /* we found a cyclic symbolic link */
+ message_2s (1, MSG_ERROR, _(" Cannot copy cyclic symbolic link \n `%s' "), s);
+ return FILE_SKIP;
+ }
+#endif
+
+ lp = xmalloc (sizeof (struct link), "parent_dirs");
+ lp->vfs = vfs_type (s);
+ lp->ino = cbuf.st_ino;
+ lp->dev = cbuf.st_dev;
+ lp->next = parent_dirs;
+ parent_dirs = lp;
+
+ /* Now, check if the dest dir exists, if not, create it. */
+ if (mc_stat (d, &buf)){
+ /* Here the dir doesn't exist : make it !*/
+
+ if (move_over) {
+ if (mc_rename (s, d) == 0) {
+ free (parent_dirs);
+ return FILE_CONT;
+ }
+ }
+ dest_dir = copy_strings (d, 0);
+ } else {
+ /*
+ * If the destination directory exists, we want to copy the whole
+ * directory, but we only want this to happen once.
+ *
+ * Escape sequences added to the * to avoid compiler warnings.
+ * so, say /bla exists, if we copy /tmp/\* to /bla, we get /bla/tmp/\*
+ * or ( /bla doesn't exist ) /tmp/\* to /bla -> /bla/\*
+ */
+#if 1
+/* Again, I'm getting curious. Is not d already what we wanted, incl.
+ * masked source basename? Is not this just a relict of the past versions?
+ * I'm afraid this will lead into a two level deep dive :(
+ *
+ * I think this is indeed the problem. I can not remember any case where
+ * we actually would like that behaviour -miguel
+ *
+ * It's a documented feature (option `Dive into subdir if exists' in the
+ * copy/move dialog). -Norbert
+ */
+ if (toplevel && dive_into_subdirs){
+ dest_dir = concat_dir_and_file (d, x_basename (s));
+ } else
+#endif
+ {
+ dest_dir = copy_strings (d, 0);
+ goto dont_mkdir;
+ }
+ }
+ retry_dst_mkdir:
+ if (my_mkdir (dest_dir, (cbuf.st_mode & umask_kill) | S_IRWXU)){
+ return_status = file_error (_(" Cannot create target directory \"%s\" \n %s "), dest_dir);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_mkdir;
+ goto ret;
+ }
+
+ lp = xmalloc (sizeof (struct link), "dest_dirs");
+ mc_stat (dest_dir, &buf);
+ lp->vfs = vfs_type (dest_dir);
+ lp->ino = buf.st_ino;
+ lp->dev = buf.st_dev;
+ lp->next = dest_dirs;
+ dest_dirs = lp;
+
+#ifndef OS2_NT
+ if (preserve_uidgid) {
+ retry_dst_chown:
+ if (mc_chown (dest_dir, cbuf.st_uid, cbuf.st_gid)){
+ return_status = file_error
+ (_(" Cannot chown target directory \"%s\" \n %s "), dest_dir);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_chown;
+ goto ret;
+ }
+ }
+#endif
+
+ dont_mkdir:
+ /* open the source dir for reading */
+ if ((reading = mc_opendir (s)) == 0){
+ goto ret;
+ }
+
+ while ((next = mc_readdir (reading)) && return_status != FILE_ABORT){
+ /*
+ * Now, we don't want '.' and '..' to be created / copied at any time
+ */
+ if (!strcmp (next->d_name, "."))
+ continue;
+ if (!strcmp (next->d_name, ".."))
+ continue;
+
+ /* get the filename and add it to the src directory */
+ path = concat_dir_and_file (s, next->d_name);
+
+ (*xstat)(path, &buf);
+ if (S_ISDIR (buf.st_mode)){
+ mdpath = concat_dir_and_file (dest_dir, next->d_name);
+ /*
+ * From here, we just intend to recursively copy subdirs, not
+ * the double functionality of copying different when the target
+ * dir already exists. So, we give the recursive call the flag 0
+ * meaning no toplevel.
+ */
+ return_status = copy_dir_dir (path, mdpath, 0, 0, delete, parent_dirs);
+ free (mdpath);
+ } else {
+ dest_file = concat_dir_and_file (dest_dir, x_basename (path));
+ return_status = copy_file_file (path, dest_file, 1);
+ free (dest_file);
+ }
+ if (delete && return_status == FILE_CONT) {
+ if (erase_at_end) {
+ static struct link *tail;
+ lp = xmalloc (sizeof (struct link) + strlen (path), "erase_list");
+ strcpy (lp->name, path);
+ lp->st_mode = buf.st_mode;
+ lp->next = 0;
+ if (erase_list) {
+ tail->next = lp;
+ tail = lp;
+ } else
+ erase_list = tail = lp;
+ } else {
+ if (S_ISDIR (buf.st_mode)) {
+ return_status = erase_dir_iff_empty (path);
+ } else
+ return_status = erase_file (path);
+ }
+ }
+
+#ifdef __os2__
+ /* The OS/2 mc_readdir returns a block of memory DIR
+ * next should be freed: .ado
+ */
+ if (!next)
+ free (next);
+#endif
+ free (path);
+ }
+ mc_closedir (reading);
+
+ /* .ado: Directories can not have permission set in OS/2 */
+#ifndef __os2__
+ if (preserve) {
+ mc_chmod (dest_dir, cbuf.st_mode & umask_kill);
+ utb.actime = cbuf.st_atime;
+ utb.modtime = cbuf.st_mtime;
+ mc_utime(dest_dir, &utb);
+ }
+
+#endif
+ret:
+ free (dest_dir);
+ free (parent_dirs);
+ return return_status;
+}
+
+/* }}} */
+
+/* {{{ Move routines */
+
+int
+move_file_file (char *s, char *d)
+{
+ struct stat src_stats, dst_stats;
+ int return_status = FILE_CONT;
+
+ if (show_source (s) == FILE_ABORT
+ || show_target (d) == FILE_ABORT)
+ return FILE_ABORT;
+
+ mc_refresh ();
+
+ retry_src_lstat:
+ if (mc_lstat (s, &src_stats) != 0){
+ /* Source doesn't exist */
+ return_status = file_error (_(" Cannot stat file \"%s\" \n %s "), s);
+ if (return_status == FILE_RETRY)
+ goto retry_src_lstat;
+ return return_status;
+ }
+
+ if (mc_lstat (d, &dst_stats) == 0){
+ /* Destination already exists */
+ /* .ado: for OS/2 and NT, no st_ino exists */
+#ifndef OS2_NT
+ if (src_stats.st_dev == dst_stats.st_dev
+ && src_stats.st_ino == dst_stats.st_ino){
+ int msize = COLS - 36;
+ char st[MC_MAXPATHLEN];
+ char dt[MC_MAXPATHLEN];
+
+ if (msize < 0)
+ msize = 40;
+ msize /= 2;
+
+ strcpy (st, name_trunc (s, msize));
+ strcpy (dt, name_trunc (d, msize));
+ message_3s (1, MSG_ERROR, _(" `%s' and `%s' are the same file "),
+ st, dt );
+ do_refresh ();
+ return FILE_SKIP;
+ }
+#endif /* OS2_NT */
+ if (S_ISDIR (dst_stats.st_mode)){
+ message_2s (1, MSG_ERROR, _(" Cannot overwrite directory `%s' "), d);
+ do_refresh ();
+ return FILE_SKIP;
+ }
+
+ if (confirm_overwrite){
+ if (vfs_file_is_ftp (s))
+ do_reget = -1;
+ else
+ do_reget = 0;
+
+ return_status = query_replace (d, &src_stats, &dst_stats);
+ if (return_status != FILE_CONT)
+ return return_status;
+ }
+ /* Ok to overwrite */
+ }
+#if 0
+ retry_rename:
+#endif
+ if (!do_append) {
+ if (S_ISLNK (src_stats.st_mode) && stable_symlinks) {
+ if ((return_status = make_symlink (s, d)) == FILE_CONT)
+ goto retry_src_remove;
+ else
+ return return_status;
+ }
+
+ if (mc_rename (s, d) == 0)
+ return FILE_CONT;
+ }
+#if 0
+/* Comparison to EXDEV seems not to work in nfs if you're moving from
+ one nfs to the same, but on the server it is on two different
+ filesystems. Then nfs returns EIO instead of EXDEV.
+ Hope it will not hurt if we always in case of error try to copy/delete. */
+ else
+ errno = EXDEV; /* Hack to copy (append) the file and then delete it */
+
+ if (errno != EXDEV){
+ return_status = files_error (_(" Cannot move file \"%s\" to \"%s\" \n %s "), s, d);
+ if (return_status == FILE_RETRY)
+ goto retry_rename;
+ return return_status;
+ }
+#endif
+
+ /* Failed because filesystem boundary -> copy the file instead */
+ if ((return_status = copy_file_file (s, d, 0)) != FILE_CONT)
+ return return_status;
+ if ((return_status = show_source (NULL)) != FILE_CONT
+ || (return_status = show_file_progress (0, 0)) != FILE_CONT)
+ return return_status;
+
+ mc_refresh ();
+
+ retry_src_remove:
+ if (mc_unlink (s)){
+ return_status = file_error (_(" Cannot remove file \"%s\" \n %s "), s);
+ if (return_status == FILE_RETRY)
+ goto retry_src_remove;
+ return return_status;
+ }
+
+ return FILE_CONT;
+}
+
+int
+move_dir_dir (char *s, char *d)
+{
+ struct stat sbuf, dbuf, destbuf;
+ struct link *lp;
+ char *destdir;
+ int return_status;
+ int move_over = 0;
+
+ if (show_source (s) == FILE_ABORT
+ || show_target (d) == FILE_ABORT)
+ return FILE_ABORT;
+
+ mc_refresh ();
+
+ mc_stat (s, &sbuf);
+ if (mc_stat (d, &dbuf))
+ destdir = copy_strings (d, 0); /* destination doesn't exist */
+ else if (!dive_into_subdirs) {
+ destdir = copy_strings (d, 0);
+ move_over = 1;
+ } else
+ destdir = concat_dir_and_file (d, x_basename (s));
+
+ /* Check if the user inputted an existing dir */
+ retry_dst_stat:
+ if (!mc_stat (destdir, &destbuf)){
+ if (move_over) {
+ if ((return_status = copy_dir_dir (s, destdir, 0, 1, 1, 0)) != FILE_CONT)
+ goto ret;
+ goto oktoret;
+ } else {
+ if (S_ISDIR (destbuf.st_mode))
+ return_status = file_error (_(" Cannot overwrite directory \"%s\" %s "), destdir);
+ else
+ return_status = file_error (_(" Cannot overwrite file \"%s\" %s "), destdir);
+ if (return_status == FILE_RETRY)
+ goto retry_dst_stat;
+ }
+ free (destdir);
+ return return_status;
+ }
+
+ retry_rename:
+ if (mc_rename (s, destdir) == 0){
+ return_status = FILE_CONT;
+ goto ret;
+ }
+/* .ado: Drive, Do we need this anymore? */
+#ifdef WIN32
+ else {
+ /* EXDEV: cross device; does not work everywhere */
+ if (toupper(s[0]) != toupper(destdir[0]))
+ goto w32try;
+ }
+#endif
+
+ if (errno != EXDEV){
+ return_status = files_error (_(" Cannot move directory \"%s\" to \"%s\" \n %s "), s, d);
+ if (return_status == FILE_RETRY)
+ goto retry_rename;
+ goto ret;
+ }
+
+w32try:
+ /* Failed because of filesystem boundary -> copy dir instead */
+ if ((return_status = copy_dir_dir (s, destdir, 0, 0, 1, 0)) != FILE_CONT)
+ goto ret;
+oktoret:
+ if ((return_status = show_source (NULL)) != FILE_CONT
+ || (return_status = show_file_progress (0, 0)) != FILE_CONT)
+ goto ret;
+
+ mc_refresh ();
+ if (erase_at_end) {
+ for ( ; erase_list && return_status != FILE_ABORT; ) {
+ if (S_ISDIR (erase_list->st_mode)) {
+ return_status = erase_dir_iff_empty (erase_list->name);
+ } else
+ return_status = erase_file (erase_list->name);
+ lp = erase_list;
+ erase_list = erase_list->next;
+ free (lp);
+ }
+ }
+ erase_dir_iff_empty (s);
+
+ ret:
+ free (destdir);
+ for ( ; erase_list; ) {
+ lp = erase_list;
+ erase_list = erase_list->next;
+ free (lp);
+ }
+ return return_status;
+}
+
+/* }}} */
+
+/* {{{ Erase routines */
+
+static int
+erase_file (char *s)
+{
+ int return_status;
+
+ if (show_deleting (s) == FILE_ABORT)
+ return FILE_ABORT;
+
+ mc_refresh ();
+
+ retry_unlink:
+ if (mc_unlink (s)){
+ return_status = file_error (_(" Cannot delete file \"%s\" \n %s "), s);
+ if (return_status == FILE_RETRY)
+ goto retry_unlink;
+ return return_status;
+ }
+ return FILE_CONT;
+}
+
+static int
+recursive_erase (char *s)
+{
+ struct dirent *next;
+ struct stat buf;
+ DIR *reading;
+ char *path;
+ int return_status = FILE_CONT;
+
+ if (!strcmp (s, ".."))
+ return 1;
+
+ reading = mc_opendir (s);
+
+ if (!reading)
+ return 1;
+
+ while ((next = mc_readdir (reading)) && return_status == FILE_CONT){
+ if (!strcmp (next->d_name, "."))
+ continue;
+ if (!strcmp (next->d_name, ".."))
+ continue;
+ path = concat_dir_and_file (s, next->d_name);
+ if (mc_lstat (path, &buf)){
+ free (path);
+ return 1;
+ }
+ if (S_ISDIR (buf.st_mode))
+ return_status = (recursive_erase (path) != FILE_CONT);
+ else
+ return_status = erase_file (path);
+ free (path);
+ /* .ado: OS/2 returns a block of memory DIR to next and must be freed */
+#ifdef __os2__
+ if (!next)
+ free (next);
+#endif
+ }
+ mc_closedir (reading);
+ if (return_status != FILE_CONT)
+ return return_status;
+ if (show_deleting (s) == FILE_ABORT)
+ return FILE_ABORT;
+ mc_refresh ();
+ retry_rmdir:
+ if (my_rmdir (s)){
+ return_status = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
+ if (return_status == FILE_RETRY)
+ goto retry_rmdir;
+ return return_status;
+ }
+ return FILE_CONT;
+}
+
+/* Return -1 on error, 1 if there are no entries besides "." and ".."
+ in the directory path points to, 0 else. */
+static int
+check_dir_is_empty(char *path)
+{
+ DIR *dir;
+ struct dirent *d;
+ int i;
+
+ dir = mc_opendir (path);
+ if (!dir)
+ return -1;
+
+ for (i = 1, d = mc_readdir (dir); d; d = mc_readdir (dir)) {
+ if (d->d_name[0] == '.' && (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0')))
+ continue; /* "." or ".." */
+ i = 0;
+ break;
+ }
+
+ mc_closedir (dir);
+ return i;
+}
+
+int
+erase_dir (char *s)
+{
+ int error;
+
+ if (strcmp (s, "..") == 0)
+ return FILE_SKIP;
+
+ if (strcmp (s, ".") == 0)
+ return FILE_SKIP;
+
+ if (show_deleting (s) == FILE_ABORT)
+ return FILE_ABORT;
+ mc_refresh ();
+
+ /* The old way to detect a non empty directory was:
+ error = my_rmdir (s);
+ if (error && (errno == ENOTEMPTY || errno == EEXIST))) {
+ For the linux user space nfs server (nfs-server-2.2beta29-2)
+ we would have to check also for EIO. I hope the new way is
+ fool proof. (Norbert)
+ */
+ error = check_dir_is_empty (s);
+ if (error == 0) { /* not empty */
+ error = query_recursive (s);
+ if (error == FILE_CONT)
+ return recursive_erase (s);
+ else
+ return error;
+ }
+
+ retry_rmdir:
+ error = my_rmdir (s);
+ if (error == -1){
+ error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
+ if (error == FILE_RETRY)
+ goto retry_rmdir;
+ return error;
+ }
+ return FILE_CONT;
+}
+
+int
+erase_dir_iff_empty (char *s)
+{
+ int error;
+
+ if (strcmp (s, "..") == 0)
+ return FILE_SKIP;
+
+ if (strcmp (s, ".") == 0)
+ return FILE_SKIP;
+
+ if (show_deleting (s) == FILE_ABORT)
+ return FILE_ABORT;
+ mc_refresh ();
+
+ if (1 != check_dir_is_empty (s)) /* not empty or error */
+ return FILE_CONT;
+
+ retry_rmdir:
+ error = my_rmdir (s);
+ if (error) {
+ error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s);
+ if (error == FILE_RETRY)
+ goto retry_rmdir;
+ return error;
+ }
+ return FILE_CONT;
+}
+
+/* }}} */
+
+/* {{{ Panel operate routines */
+
+/* Returns currently selected file or the first marked file if there is one */
+static char *
+get_file (WPanel *panel, struct stat *stat_buf)
+{
+ int i;
+
+ /* No problem with Gnome, as get_current_type never returns view_tree there */
+ if (get_current_type () == view_tree){
+ WTree *tree = (WTree *)get_panel_widget (get_current_index ());
+
+ mc_stat (tree->selected_ptr->name, stat_buf);
+ return tree->selected_ptr->name;
+ }
+
+ if (panel->marked){
+ for (i = 0; i < panel->count; i++)
+ if (panel->dir.list [i].f.marked){
+ *stat_buf = panel->dir.list [i].buf;
+ return panel->dir.list [i].fname;
+ }
+ } else {
+ *stat_buf = panel->dir.list [panel->selected].buf;
+ return panel->dir.list [panel->selected].fname;
+ }
+ fprintf (stderr, _(" Internal error: get_file \n"));
+ mi_getch ();
+ return "";
+}
+
+static int
+is_wildcarded (char *p)
+{
+ for (; *p; p++) {
+ if (*p == '*')
+ return 1;
+ else if (*p == '\\' && p [1] >= '1' && p [1] <= '9')
+ return 1;
+ }
+ return 0;
+}
+
+/* Sets all global variables used by copy_file_file/move_file_file to a
+ resonable default
+ (file_mask_dialog sets these global variables interactively)
+ */
+void
+file_mask_defaults (void)
+{
+ stable_symlinks = 0;
+ op_follow_links = 0;
+ dive_into_subdirs = 0;
+ xstat = mc_lstat;
+
+ preserve = 1;
+ umask_kill = 0777777;
+ preserve_uidgid = (geteuid () == 0) ? 1 : 0;
+}
+
+#define FMDY 13
+#define FMD_XLEN 64
+static int fmd_xlen = FMD_XLEN, fmd_i18n_flag = 0;
+static QuickWidget fmd_widgets [] = {
+
+#define FMCB0 FMDC
+#define FMCB12 0
+#define FMCB11 1
+ /* follow symlinks and preserve Attributes must be the first */
+ { quick_checkbox, 3, 64, 8, FMDY, N_("preserve &Attributes"), 9, 0,
+ &op_preserve, 0, XV_WLAY_BELOWCLOSE, "preserve" },
+ { quick_checkbox, 3, 64, 7, FMDY, N_("follow &Links"), 7, 0,
+ &op_follow_links, 0, XV_WLAY_BELOWCLOSE, "follow" },
+#ifdef HAVE_XVIEW
+#define FMDI1 5
+#define FMDI2 2
+#define FMDC 4
+ { quick_input, 3, 64, 6, FMDY, "", 58, 0,
+ 0, 0, XV_WLAY_BELOWCLOSE, "input2" },
+#endif
+ { quick_label, 3, 64, 5, FMDY, N_("to:"), 0, 0, 0, 0, XV_WLAY_BELOWOF,"to"},
+ { quick_checkbox, 37, 64, 4, FMDY, N_("&Using shell patterns"), 0, 0,
+ 0/* &source_easy_patterns */, 0, XV_WLAY_BELOWCLOSE, "using-shell" },
+ { quick_input, 3, 64, 3, FMDY, "", 58,
+ 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-def" },
+#ifndef HAVE_XVIEW
+#define FMDI1 4
+#define FMDI2 5
+#define FMDC 3
+ { quick_input, 3, 64, 6, FMDY, "", 58, 0,
+ 0, 0, XV_WLAY_BELOWCLOSE, "input2" },
+#endif
+#define FMDI0 6
+ { quick_label, 3, 64, 2, FMDY, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "ql" },
+#define FMBRGT 7
+ { quick_button, 42, 64, 9, FMDY, N_("&Cancel"), 0, B_CANCEL, 0, 0, XV_WLAY_DONTCARE,
+ "cancel" },
+#undef SKIP
+#ifdef WITH_BACKGROUND
+# define SKIP 5
+# define FMCB21 11
+# define FMCB22 10
+# define FMBLFT 9
+# define FMBMID 8
+ { quick_button, 25, 64, 9, FMDY, N_("&Background"), 0, B_USER, 0, 0, XV_WLAY_DONTCARE, "back" },
+#else /* WITH_BACKGROUND */
+# define SKIP 4
+# define FMCB21 10
+# define FMCB22 9
+# define FMBLFT 8
+# undef FMBMID
+#endif
+ { quick_button, 14, 64, 9, FMDY, N_("&Ok"), 0, B_ENTER, 0, 0, XV_WLAY_NEXTROW, "ok" },
+ { quick_checkbox, 42, 64, 8, FMDY, N_("&Stable Symlinks"), 0, 0,
+ &stable_symlinks, 0, XV_WLAY_BELOWCLOSE, "stab-sym" },
+ { quick_checkbox, 31, 64, 7, FMDY, N_("&Dive into subdir if exists"), 0, 0,
+ &dive_into_subdirs, 0, XV_WLAY_BELOWOF, "dive" },
+ { 0 } };
+
+void
+fmd_init_i18n()
+{
+#ifdef ENABLE_NLS
+
+ register int i;
+ int len;
+
+ for (i = sizeof (op_names) / sizeof (op_names[0]); i--;)
+ op_names [i] = _(op_names [i]);
+
+ i = sizeof (fmd_widgets) / sizeof (fmd_widgets [0]) - 1;
+ while (i--)
+ if (fmd_widgets [i].text[0] != '\0')
+ fmd_widgets [i].text = _(fmd_widgets [i].text);
+
+ len = strlen (fmd_widgets [FMCB11].text)
+ + strlen (fmd_widgets [FMCB21].text) + 15;
+ fmd_xlen = max (fmd_xlen, len);
+
+ len = strlen (fmd_widgets [FMCB12].text)
+ + strlen (fmd_widgets [FMCB22].text) + 15;
+ fmd_xlen = max (fmd_xlen, len);
+
+ len = strlen (fmd_widgets [FMBRGT].text)
+ + strlen (fmd_widgets [FMBLFT].text) + 11;
+
+#ifdef FMBMID
+ len += strlen (fmd_widgets [FMBMID].text) + 6;
+#endif
+
+ fmd_xlen = max (fmd_xlen, len + 4);
+
+ len = (fmd_xlen - (len + 6)) / 2;
+ i = fmd_widgets [FMBLFT].relative_x = len + 3;
+ i += strlen (fmd_widgets [FMBLFT].text) + 8;
+
+#ifdef FMBMID
+ fmd_widgets [FMBMID].relative_x = i;
+ i += strlen (fmd_widgets [FMBMID].text) + 6;
+#endif
+
+ fmd_widgets [FMBRGT].relative_x = i;
+
+#define chkbox_xpos(i) \
+ fmd_widgets [i].relative_x = fmd_xlen - strlen (fmd_widgets [i].text) - 6
+
+ chkbox_xpos(FMCB0);
+ chkbox_xpos(FMCB21);
+ chkbox_xpos(FMCB22);
+
+ if (fmd_xlen != FMD_XLEN)
+ {
+ i = sizeof (fmd_widgets) / sizeof (fmd_widgets [0]) - 1;
+ while (i--)
+ fmd_widgets [i].x_divisions = fmd_xlen;
+
+ fmd_widgets [FMDI1].hotkey_pos =
+ fmd_widgets [FMDI2].hotkey_pos = fmd_xlen - 6;
+ }
+#undef chkbox_xpos
+#endif /* ENABLE_NLS */
+
+ fmd_i18n_flag = 1;
+}
+
+char *
+file_mask_dialog (int operation, char *text, char *def_text, int only_one, int *do_background)
+{
+ int source_easy_patterns = easy_patterns;
+ char *source_mask, *orig_mask, *dest_dir;
+ const char *error;
+ struct stat buf;
+ int val;
+
+ QuickDialog Quick_input;
+
+ if (!fmd_i18n_flag)
+ fmd_init_i18n();
+
+ stable_symlinks = 0;
+ fmd_widgets [FMDC].result = &source_easy_patterns;
+ fmd_widgets [FMDI1].text = easy_patterns ? "*" : "^\\(.*\\)$";
+ Quick_input.xlen = fmd_xlen;
+ Quick_input.xpos = -1;
+ Quick_input.title = op_names [operation];
+ Quick_input.help = "[Mask Copy/Rename]";
+ Quick_input.ylen = FMDY;
+ Quick_input.i18n = 1;
+
+ if (operation == OP_COPY) {
+ Quick_input.class = "quick_file_mask_copy";
+ Quick_input.widgets = fmd_widgets;
+ } else { /* operation == OP_MOVE */
+ Quick_input.class = "quick_file_mask_move";
+ Quick_input.widgets = fmd_widgets + 2;
+ }
+ fmd_widgets [FMDI0].text = text;
+ fmd_widgets [FMDI2].text = def_text;
+ fmd_widgets [FMDI2].str_result = &dest_dir;
+ fmd_widgets [FMDI1].str_result = &source_mask;
+
+ *do_background = 0;
+ask_file_mask:
+
+ if ((val = quick_dialog_skip (&Quick_input, SKIP)) == B_CANCEL)
+ return 0;
+
+ if (op_follow_links && operation != OP_MOVE)
+ xstat = mc_stat;
+ else
+ xstat = mc_lstat;
+
+ if (op_preserve || operation == OP_MOVE) {
+ preserve = 1;
+ umask_kill = 0777777;
+ preserve_uidgid = (geteuid () == 0) ? 1 : 0;
+ }
+ else {
+ int i;
+ preserve = preserve_uidgid = 0;
+ i = umask (0);
+ umask (i);
+ umask_kill = i ^ 0777777;
+ }
+
+ orig_mask = source_mask;
+ if (!dest_dir || !*dest_dir) {
+ if (source_mask)
+ free (source_mask);
+ return dest_dir;
+ }
+ if (source_easy_patterns) {
+ source_easy_patterns = easy_patterns;
+ easy_patterns = 1;
+ source_mask = convert_pattern (source_mask, match_file, 1);
+ easy_patterns = source_easy_patterns;
+ error = re_compile_pattern (source_mask, strlen (source_mask), &rx);
+ free (source_mask);
+ } else
+ error = re_compile_pattern (source_mask, strlen (source_mask), &rx);
+
+ if (error) {
+ message_3s (1, MSG_ERROR, _("Invalid source pattern `%s' \n %s "),
+ orig_mask, error);
+ if (orig_mask)
+ free (orig_mask);
+ goto ask_file_mask;
+ }
+ if (orig_mask)
+ free (orig_mask);
+ dest_mask = strrchr (dest_dir, PATH_SEP);
+ if (dest_mask == NULL)
+ dest_mask = dest_dir;
+ else
+ dest_mask++;
+ orig_mask = dest_mask;
+ if (!*dest_mask || (!dive_into_subdirs && !is_wildcarded (dest_mask) &&
+ (!only_one || (!mc_stat (dest_dir, &buf) && S_ISDIR (buf.st_mode)))) ||
+ (dive_into_subdirs && ((!only_one && !is_wildcarded (dest_mask)) ||
+ (only_one && !mc_stat (dest_dir, &buf) && S_ISDIR (buf.st_mode)))))
+ dest_mask = strdup ("*");
+ else {
+ dest_mask = strdup (dest_mask);
+ *orig_mask = 0;
+ }
+ if (!*dest_dir) {
+ free (dest_dir);
+ dest_dir = strdup ("./");
+ }
+ if (val == B_USER)
+ *do_background = 1;
+ return dest_dir;
+}
+
+/*
+ * This array introduced to avoid translation problems. The former (op_names)
+ * is assumed to be nouns, suitable in dialog box titles; this one should
+ * contain whatever is used in prompt itself (i.e. in russian, it's verb).
+ * Notice first symbol - it is to fool gettext and force these strings to
+ * be different for it. First symbol is skipped while building a prompt.
+ * (I don't use spaces around the words, because someday they could be
+ * dropped, when widgets get smarter)
+ */
+static char *op_names1 [] = { N_("1Copy"), N_("1Move"), N_("1Delete") };
+
+/*
+ * These are formats for building a prompt. Parts encoded as follows:
+ * %o - operation from op_names1
+ * %f - file/files or files/directories, as appropriate
+ * %m - "with source mask" or question mark for delete
+ * %s - source name (truncated)
+ * %d - number of marked files
+ */
+static char* one_format = N_("%o %f \"%s\"%m");
+static char* many_format = N_("%o %d %f%m");
+
+static char* prompt_parts [] =
+{
+ N_("file"), N_("files"), N_("directory"), N_("directories"),
+ N_("files/directories"), N_(" with source mask:")
+};
+
+static char*
+generate_prompt(char* cmd_buf, WPanel* panel, int operation, int only_one,
+ struct stat* src_stat)
+{
+ register char *sp, *cp;
+ register int i;
+ char format_string [200];
+ char *dp = format_string;
+ char* source = NULL;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+ if (!i18n_flag)
+ {
+ if (!fmd_i18n_flag)
+ fmd_init_i18n(); /* to get proper fmd_xlen */
+
+ for (i = sizeof (op_names1) / sizeof (op_names1 [0]); i--;)
+ op_names1 [i] = _(op_names1 [i]);
+
+ for (i = sizeof (prompt_parts) / sizeof (prompt_parts [0]); i--;)
+ prompt_parts [i] = _(prompt_parts [i]);
+
+ one_format = _(one_format);
+ many_format = _(many_format);
+ i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ sp = only_one ? one_format : many_format;
+
+ if (only_one)
+ source = get_file (panel, src_stat);
+
+ while (*sp)
+ {
+ switch (*sp)
+ {
+ case '%':
+ cp = NULL;
+ switch (sp[1])
+ {
+ case 'o':
+ cp = op_names1 [operation] + 1;
+ break;
+ case 'm':
+ cp = operation == OP_DELETE ? "?" : prompt_parts [5];
+ break;
+ case 'f':
+ if (only_one)
+ {
+ cp = S_ISDIR (src_stat->st_mode) ?
+ prompt_parts [2] : prompt_parts [0];
+ }
+ else
+ {
+ cp = (panel->marked == panel->dirs_marked)
+ ? prompt_parts [3]
+ : (panel->dirs_marked ? prompt_parts [4]
+ : prompt_parts [1]);
+ }
+ break;
+ default:
+ *dp++ = *sp++;
+ }
+ if (cp)
+ {
+ sp += 2;
+ while (*cp)
+ *dp++ = *cp++;
+ }
+ break;
+ default:
+ *dp++ = *sp++;
+ }
+ }
+ *dp = '\0';
+
+ if (only_one)
+ {
+ i = fmd_xlen - strlen(format_string) - 4;
+ sprintf (cmd_buf, format_string, name_trunc (source, i));
+ }
+ else
+ {
+ sprintf (cmd_buf, format_string, panel->marked);
+ i = strlen (cmd_buf) + 6 - fmd_xlen;
+ if (i > 0)
+ {
+ fmd_xlen += i;
+ fmd_init_i18n(); /* to recalculate positions of child widgets */
+ }
+ }
+
+ return source;
+}
+
+
+/* Returns 1 if did change the directory structure,
+ Returns 0 if user aborted */
+int
+panel_operate (void *source_panel, int operation, char *thedefault)
+{
+ WPanel *panel = source_panel;
+#ifdef WITH_FULL_PATHS
+ char *source_with_path = NULL;
+#else
+# define source_with_path source
+#endif
+ char *source = NULL;
+ char *dest = NULL;
+ char *temp = NULL;
+ int only_one = (get_current_type () == view_tree) || (panel->marked <= 1);
+ struct stat src_stat, dst_stat;
+ int i, value;
+ long marked, total;
+ long count = 0, bytes = 0;
+ int dst_result;
+ int do_bg; /* do background operation? */
+
+ do_bg = 0;
+ rx.buffer = NULL;
+ free_linklist (&linklist);
+ free_linklist (&dest_dirs);
+ if (get_current_type () == view_listing)
+ if (!panel->marked && !strcmp (selection (panel)->fname, "..")){
+ message (1, MSG_ERROR, _(" Can't operate on \"..\"! "));
+ return 0;
+ }
+
+ if (operation < OP_COPY || operation > OP_DELETE)
+ return 0;
+
+ /* Generate confirmation prompt */
+ source = generate_prompt(cmd_buf, panel, operation, only_one, &src_stat);
+
+ /* Show confirmation dialog */
+ if (operation == OP_DELETE && confirm_delete){
+ if (know_not_what_am_i_doing)
+ query_set_sel (1);
+ i = query_dialog (_(op_names [operation]), cmd_buf,
+ D_ERROR, 2, _("&Yes"), _("&No"));
+ if (i != 0)
+ return 0;
+ } else if (operation != OP_DELETE) {
+ char *dest_dir;
+
+ if (thedefault != NULL)
+ dest_dir = thedefault;
+ else if (get_other_type () == view_listing)
+ dest_dir = opanel->cwd;
+ else
+ dest_dir = panel->cwd;
+
+ rx.buffer = (char *) xmalloc (MC_MAXPATHLEN, "mask copying");
+ rx.allocated = MC_MAXPATHLEN;
+ rx.translate = 0;
+ dest = file_mask_dialog (operation, cmd_buf, dest_dir, only_one, &do_bg);
+ if (!dest) {
+ free (rx.buffer);
+ return 0;
+ }
+ if (!*dest){
+ free (rx.buffer);
+ free (dest);
+ return 0;
+ }
+ }
+
+#ifdef WITH_BACKGROUND
+ /* Did the user select to do a background operation? */
+ if (do_bg){
+ int v;
+
+ v = do_background (copy_strings (operation_names [operation], ": ", panel->cwd, 0));
+ if (v == -1){
+ message (1, MSG_ERROR, _(" Sorry, I could not put the job in background "));
+ }
+
+ /* If we are the parent */
+ if (v == 1){
+ vfs_force_expire (panel->cwd);
+ vfs_force_expire (dest);
+ return 0;
+ }
+ }
+#endif
+ /* Initialize things */
+ /* We turn on ETA display if the source is an ftp file system */
+ create_op_win (operation, vfs_file_is_ftp (panel->cwd));
+ ftpfs_hint_reread (0);
+
+ /* Now, let's do the job */
+ /* This code is only called by the tree and panel code */
+ if (only_one){
+ /* One file: FIXME mc_chdir will take user out of any vfs */
+ if (operation != OP_COPY && get_current_type () == view_tree)
+ mc_chdir (PATH_SEP_STR);
+
+ /* The source and src_stat variables have been initialized before */
+#ifdef WITH_FULL_PATHS
+ source_with_path = concat_dir_and_file (panel->cwd, source);
+#endif
+
+ if (operation == OP_DELETE){
+ /* Delete operation */
+ if (S_ISDIR (src_stat.st_mode))
+ value = erase_dir (source_with_path);
+ else
+ value = erase_file (source_with_path);
+ } else {
+ /* Copy or move operation */
+ temp = transform_source (source_with_path);
+ if (temp == NULL) {
+ value = transform_error;
+ } else {
+ temp = get_full_name (dest, temp);
+ free (dest);
+ dest = temp;
+ temp = 0;
+
+ switch (operation){
+ case OP_COPY:
+ /* we use op_follow_links only with OP_COPY,
+ */
+ (*xstat) (source_with_path, &src_stat);
+ if (S_ISDIR (src_stat.st_mode))
+ value = copy_dir_dir (source_with_path, dest, 1, 0, 0, 0);
+ else
+ value = copy_file_file (source_with_path, dest, 1);
+ break;
+ case OP_MOVE:
+ if (S_ISDIR (src_stat.st_mode))
+ value = move_dir_dir (source_with_path, dest);
+ else
+ value = move_file_file (source_with_path, dest);
+ break;
+ default:
+ value = FILE_CONT;
+ message_1s (1, _(" Internal failure "), _(" Unknown file operation "));
+ }
+ }
+ } /* Copy or move operation */
+
+ if (value == FILE_CONT)
+ unmark_files (panel);
+
+ } else {
+ /* Many files */
+
+ if (operation != OP_DELETE){
+ /* Check destination for copy or move operation */
+ retry_many_dst_stat:
+ dst_result = mc_stat (dest, &dst_stat);
+ if (dst_result == 0 && !S_ISDIR (dst_stat.st_mode)){
+ if (file_error (_(" Destination \"%s\" must be a directory \n %s "), dest) == FILE_RETRY)
+ goto retry_many_dst_stat;
+ goto clean_up;
+ }
+ }
+
+ /* Initialize variables for progress bars */
+ marked = panel->marked;
+ total = panel->total;
+
+ /* Loop for every file */
+ for (i = 0; i < panel->count; i++){
+ if (!panel->dir.list [i].f.marked)
+ continue; /* Skip the unmarked ones */
+ source = panel->dir.list [i].fname;
+ src_stat = panel->dir.list [i].buf; /* Inefficient, should we use pointers? */
+#ifdef WITH_FULL_PATHS
+ if (source_with_path)
+ free (source_with_path);
+ source_with_path = concat_dir_and_file (panel->cwd, source);
+#endif
+ if (operation == OP_DELETE){
+ /* Delete operation */
+ if (S_ISDIR (src_stat.st_mode))
+ value = erase_dir (source_with_path);
+ else
+ value = erase_file (source_with_path);
+ } else {
+ /* Copy or move operation */
+ if (temp)
+ free (temp);
+ temp = transform_source (source_with_path);
+ if (temp == NULL) {
+ value = transform_error;
+ } else {
+ temp = get_full_name (dest, temp);
+ switch (operation){
+ case OP_COPY:
+ /* we use op_follow_links only with OP_COPY,
+ */
+ (*xstat) (source_with_path, &src_stat);
+ if (S_ISDIR (src_stat.st_mode))
+ value = copy_dir_dir (source_with_path, temp, 1, 0, 0, 0);
+ else
+ value = copy_file_file (source_with_path, temp, 1);
+ free_linklist (&dest_dirs);
+ break;
+ case OP_MOVE:
+ if (S_ISDIR (src_stat.st_mode))
+ value = move_dir_dir (source_with_path, temp);
+ else
+ value = move_file_file (source_with_path, temp);
+ break;
+ default:
+ message_1s (1, _(" Internal failure "),
+ _(" Unknown file operation "));
+ goto clean_up;
+ }
+ }
+ } /* Copy or move operation */
+
+ if (value == FILE_ABORT)
+ goto clean_up;
+ if (value == FILE_CONT){
+ do_file_mark (panel, i, 0);
+ }
+ count ++;
+ if (show_count_progress (count, marked) == FILE_ABORT)
+ goto clean_up;
+ bytes += src_stat.st_size;
+ if (verbose &&
+ show_bytes_progress (bytes, total) == FILE_ABORT)
+ goto clean_up;
+ if (operation != OP_DELETE && verbose
+ && show_file_progress (0, 0) == FILE_ABORT)
+ goto clean_up;
+ mc_refresh ();
+ } /* Loop for every file */
+ } /* Many files */
+
+ clean_up:
+ /* Clean up */
+ destroy_op_win ();
+ ftpfs_hint_reread (1);
+ free_linklist (&linklist);
+ free_linklist (&dest_dirs);
+#if WITH_FULL_PATHS
+ if (source_with_path)
+ free (source_with_path);
+#endif
+ if (dest)
+ free (dest);
+ if (temp)
+ free (temp);
+ if (rx.buffer) {
+ free (rx.buffer);
+ rx.buffer = NULL;
+ }
+ if (dest_mask) {
+ free (dest_mask);
+ dest_mask = NULL;
+ }
+
+#ifdef WITH_BACKGROUND
+ /* Let our parent know we are saying bye bye */
+ if (we_are_background){
+ vfs_shut ();
+ tell_parent (MSG_CHILD_EXITING);
+ exit (1);
+ }
+#endif
+ return 1;
+}
+
+/* }}} */
+
+/* {{{ Query/status report routines */
+
+static int
+real_do_file_error (enum OperationMode mode, char *error)
+{
+ int result;
+ char *msg;
+
+ msg = mode == Foreground ? MSG_ERROR : _(" Background process error ");
+ result = query_dialog (msg, error, D_ERROR, 3, _("&Skip"), _("&Retry"), _("&Abort"));
+
+ switch (result){
+ case 0:
+ do_refresh ();
+ return FILE_SKIP;
+ case 1:
+ do_refresh ();
+ return FILE_RETRY;
+ case 2:
+ default:
+ return FILE_ABORT;
+ }
+}
+
+/* Report error with one file */
+int
+file_error (char *format, char *file)
+{
+ sprintf (cmd_buf, format,
+ name_trunc (file, 30), unix_error_string (errno));
+ return do_file_error (cmd_buf);
+}
+
+/* Report error with two files */
+int
+files_error (char *format, char *file1, char *file2)
+{
+ char nfile1 [16];
+ char nfile2 [16];
+
+ strcpy (nfile1, name_trunc (file1, 15));
+ strcpy (nfile2, name_trunc (file2, 15));
+
+ sprintf (cmd_buf, format, nfile1, nfile2, unix_error_string (errno));
+ return do_file_error (cmd_buf);
+}
+
+static char *format = N_("Target file \"%s\" already exists!");
+static int
+replace_callback (struct Dlg_head *h, int Id, int Msg)
+{
+#ifndef HAVE_X
+
+ switch (Msg){
+ case DLG_DRAW:
+ dialog_repaint (h, ERROR_COLOR, ERROR_COLOR);
+ break;
+ }
+#endif
+ return 0;
+}
+
+#ifdef HAVE_X
+#define X_TRUNC 128
+#else
+#define X_TRUNC 52
+#endif
+
+/*
+ * FIXME: probably it is better to replace this with quick dialog machinery,
+ * but actually I'm not familiar with it and have not much time :(
+ * alex
+ */
+static struct
+{
+ char* text;
+ int ypos, xpos;
+ int value; /* 0 for labels */
+ char* tkname;
+ WLay layout;
+}
+rd_widgets [] =
+{
+ {N_("Target file \"%s\" already exists!"),
+ 3, 4, 0, "target-e", XV_WLAY_CENTERROW},
+ {N_("&Abort"), BY + 3, 25, REPLACE_ABORT, "abort", XV_WLAY_CENTERROW},
+ {N_("if &Size differs"),
+ BY + 1, 28, REPLACE_SIZE, "if-size", XV_WLAY_RIGHTOF},
+ {N_("non&E"), BY, 47, REPLACE_NEVER, "none", XV_WLAY_RIGHTOF},
+ {N_("&Update"), BY, 36, REPLACE_UPDATE, "update", XV_WLAY_RIGHTOF},
+ {N_("al&L"), BY, 28, REPLACE_ALWAYS, "all", XV_WLAY_RIGHTOF},
+ {N_("Overwrite all targets?"),
+ BY, 4, 0, "over-label", XV_WLAY_CENTERROW},
+ {N_("&Reget"), BY - 1, 28, REPLACE_REGET, "reget", XV_WLAY_RIGHTOF},
+ {N_("ap&Pend"), BY - 2, 45, REPLACE_APPEND, "append", XV_WLAY_RIGHTOF},
+ {N_("&No"), BY - 2, 37, REPLACE_NO, "no", XV_WLAY_RIGHTOF},
+ {N_("&Yes"), BY - 2, 28, REPLACE_YES, "yes", XV_WLAY_RIGHTOF},
+ {N_("Overwrite this target?"),
+ BY - 2, 4, 0, "overlab", XV_WLAY_CENTERROW},
+ {N_("Target date: %s, size %d"),
+ 6, 4, 0, "target-date",XV_WLAY_CENTERROW},
+ {N_("Source date: %s, size %d"),
+ 5, 4, 0, "source-date",XV_WLAY_CENTERROW}
+};
+
+#define ADD_RD_BUTTON(i)\
+ add_widgetl (replace_dlg,\
+ button_new (rd_widgets [i].ypos, rd_widgets [i].xpos, rd_widgets [i].value,\
+ NORMAL_BUTTON, rd_widgets [i].text, 0, 0, rd_widgets [i].tkname), \
+ rd_widgets [i].layout)
+
+#define ADD_RD_LABEL(i,p1,p2)\
+ sprintf (buffer, rd_widgets [i].text, p1, p2);\
+ add_widgetl (replace_dlg,\
+ label_new (rd_widgets [i].ypos, rd_widgets [i].xpos, buffer, rd_widgets [i].tkname),\
+ rd_widgets [i].layout)
+
+static void
+init_replace (enum OperationMode mode)
+{
+ char buffer [128];
+ static int rd_xlen = 60, rd_trunc = X_TRUNC;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag;
+ if (!i18n_flag)
+ {
+ int l1, l2, l, row;
+ register int i = sizeof (rd_widgets) / sizeof (rd_widgets [0]);
+ while (i--)
+ rd_widgets [i].text = _(rd_widgets [i].text);
+
+ /*
+ *longest of "Overwrite..." labels
+ * (assume "Target date..." are short enough)
+ */
+ l1 = max (strlen (rd_widgets [6].text), strlen (rd_widgets [11].text));
+
+ /* longest of button rows */
+ i = sizeof (rd_widgets) / sizeof (rd_widgets [0]);
+ for (row = l = l2 = 0; i--;)
+ {
+ if (rd_widgets [i].value != 0)
+ {
+ if (row != rd_widgets [i].ypos)
+ {
+ row = rd_widgets [i].ypos;
+ l2 = max (l2, l);
+ l = 0;
+ }
+ l += strlen (rd_widgets [i].text) + 4;
+ }
+ }
+ l2 = max (l2, l); /* last row */
+ rd_xlen = max (rd_xlen, l1 + l2 + 8);
+ rd_trunc = rd_xlen - 6;
+
+ /* Now place buttons */
+ l1 += 5; /* start of first button in the row */
+ i = sizeof (rd_widgets) / sizeof (rd_widgets [0]);
+
+ for (l = l1, row = 0; --i > 1;)
+ {
+ if (rd_widgets [i].value != 0)
+ {
+ if (row != rd_widgets [i].ypos)
+ {
+ row = rd_widgets [i].ypos;
+ l = l1;
+ }
+ rd_widgets [i].xpos = l;
+ l += strlen (rd_widgets [i].text) + 4;
+ }
+ }
+ /* Abort button is centered */
+ rd_widgets [1].xpos = (rd_xlen - strlen (rd_widgets [1].text) - 3) / 2;
+
+ }
+#endif /* ENABLE_NLS */
+
+ replace_colors [0] = ERROR_COLOR;
+ replace_colors [1] = COLOR_NORMAL;
+ replace_colors [2] = ERROR_COLOR;
+ replace_colors [3] = COLOR_NORMAL;
+
+ replace_dlg = create_dlg (0, 0, 16, rd_xlen, replace_colors, replace_callback,
+ "[ Replace ]", "replace", DLG_CENTER);
+
+ x_set_dialog_title (replace_dlg,
+ mode == Foreground ? _(" File exists ") : _(" Background process: File exists "));
+
+
+ ADD_RD_LABEL(0, name_trunc (replace_filename, rd_trunc - strlen (rd_widgets [0].text)), 0 );
+ ADD_RD_BUTTON(1);
+
+ tk_new_frame (replace_dlg, "a.");
+
+ ADD_RD_BUTTON(2);
+ ADD_RD_BUTTON(3);
+ ADD_RD_BUTTON(4);
+ ADD_RD_BUTTON(5);
+ ADD_RD_LABEL(6,0,0);
+
+ /* "this target..." widgets */
+ tk_new_frame (replace_dlg, "p.");
+ if (!S_ISDIR (d_stat->st_mode)){
+ if ((do_reget == -1 && d_stat->st_size && s_stat->st_size > d_stat->st_size))
+ ADD_RD_BUTTON(7);
+
+ ADD_RD_BUTTON(8);
+ }
+ ADD_RD_BUTTON(9);
+ ADD_RD_BUTTON(10);
+ ADD_RD_LABEL(11,0,0);
+
+ tk_new_frame (replace_dlg, "i.");
+ ADD_RD_LABEL(12, file_date (d_stat->st_mtime), (int) d_stat->st_size);
+ ADD_RD_LABEL(13, file_date (s_stat->st_mtime), (int) s_stat->st_size);
+ tk_end_frame ();
+}
+
+static int
+real_query_replace (enum OperationMode mode, char *destname, struct stat *_s_stat,
+ struct stat *_d_stat)
+{
+ if (replace_result < REPLACE_ALWAYS){
+ replace_filename = destname;
+ s_stat = _s_stat;
+ d_stat = _d_stat;
+ init_replace (mode);
+ run_dlg (replace_dlg);
+ replace_result = replace_dlg->ret_value;
+ if (replace_result == B_CANCEL)
+ replace_result = REPLACE_ABORT;
+ destroy_dlg (replace_dlg);
+ }
+
+ switch (replace_result){
+ case REPLACE_UPDATE:
+ do_refresh ();
+ if (_s_stat->st_mtime > _d_stat->st_mtime)
+ return FILE_CONT;
+ else
+ return FILE_SKIP;
+
+ case REPLACE_SIZE:
+ do_refresh ();
+ if (_s_stat->st_size == _d_stat->st_size)
+ return FILE_SKIP;
+ else
+ return FILE_CONT;
+
+ case REPLACE_REGET:
+ do_reget = _d_stat->st_size;
+
+ case REPLACE_APPEND:
+ do_append = 1;
+
+ case REPLACE_YES:
+ case REPLACE_ALWAYS:
+ do_refresh ();
+ return FILE_CONT;
+ case REPLACE_NO:
+ case REPLACE_NEVER:
+ do_refresh ();
+ return FILE_SKIP;
+ case REPLACE_ABORT:
+ default:
+ return FILE_ABORT;
+ }
+}
+
+int
+real_query_recursive (enum OperationMode mode, char *s)
+{
+ char *confirm, *text;
+
+ if (recursive_result < RECURSIVE_ALWAYS){
+ char *msg =
+ mode == Foreground ? _("\n Directory not empty. \n Delete it recursively? ")
+ : _("\n Background process: Directory not empty \n Delete it recursively? ");
+ text = copy_strings (" Delete: ", name_trunc (s, 30), " ", 0);
+
+ if (know_not_what_am_i_doing)
+ query_set_sel (1);
+ recursive_result = query_dialog (text, msg, D_ERROR, 5,
+ _("&Yes"), _("&No"), _("a&ll"), _("non&E"), _("&Abort"));
+
+
+ if (recursive_result != RECURSIVE_ABORT)
+ do_refresh ();
+ free (text);
+ if (know_not_what_am_i_doing && (recursive_result == RECURSIVE_YES
+ || recursive_result == RECURSIVE_ALWAYS)){
+ text = copy_strings (_(" Type 'yes' if you REALLY want to delete "),
+ recursive_result == RECURSIVE_YES
+ ? name_trunc (s, 19) : _("all the directories "), " ", 0);
+ confirm = input_dialog (mode == Foreground ? _(" Recursive Delete ")
+ : _(" Background process: Recursive Delete "),
+ text, "no");
+ do_refresh ();
+ if (!confirm || strcmp (confirm, "yes"))
+ recursive_result = RECURSIVE_NEVER;
+ free (confirm);
+ free (text);
+ }
+ }
+ switch (recursive_result){
+ case RECURSIVE_YES:
+ case RECURSIVE_ALWAYS:
+ return FILE_CONT;
+ case RECURSIVE_NO:
+ case RECURSIVE_NEVER:
+ return FILE_SKIP;
+ case RECURSIVE_ABORT:
+ default:
+ return FILE_ABORT;
+ }
+}
+
+#ifdef WITH_BACKGROUND
+int
+do_file_error (char *str)
+{
+ return call_1s (real_do_file_error, str);
+}
+
+int
+query_recursive (char *s)
+{
+ return call_1s (real_query_recursive, s);
+}
+
+int
+query_replace (char *destname, struct stat *_s_stat, struct stat *_d_stat)
+{
+ if (we_are_background)
+ return parent_call ((void *)real_query_replace, 3, strlen(destname), destname,
+ sizeof (struct stat), _s_stat, sizeof(struct stat), _d_stat);
+ else
+ return real_query_replace (Foreground, destname, _s_stat, _d_stat);
+}
+
+#else
+do_file_error (char *str)
+{
+ return real_do_file_error (Foreground, str);
+}
+
+int
+query_recursive (char *s)
+{
+ return real_query_recursive (Foreground, s);
+}
+
+int
+query_replace (char *destname, struct stat *_s_stat, struct stat *_d_stat)
+{
+ return real_query_replace (Foreground, destname, _s_stat, _d_stat);
+}
+
+#endif
+
+/*
+ Cause emacs to enter folding mode for this file:
+ Local variables:
+ end:
+*/
--- /dev/null
+#ifndef __FILE_H
+#define __FILE_H
+
+enum { OP_COPY, OP_MOVE, OP_DELETE };
+enum { FILE_CONT, FILE_RETRY, FILE_SKIP, FILE_ABORT };
+
+extern int verbose;
+extern int know_not_what_am_i_doing;
+
+struct link;
+
+int copy_file_file (char *s, char *d, int ask_overwrite);
+int move_file_file (char *s, char *d);
+int erase_dir (char *s);
+int erase_dir_iff_empty (char *s);
+int move_dir_dir (char *s, char *d);
+int copy_dir_dir (char *s, char *d, int toplevel, int move_over, int delete, struct link *parent_dirs);
+
+void create_op_win (int op, int with_eta);
+void destroy_op_win (void);
+void refresh_op_win (void);
+int panel_operate (void *source_panel, int op, char *thedefault);
+void file_mask_defaults (void);
+
+extern int dive_into_subdirs;
+
+/* Error reporting routines */
+ /* Skip/Retry/Abort routine */
+ int do_file_error (char *error);
+
+ /* Report error with one file */
+ int file_error (char *format, char *file);
+
+ /* Report error with two files */
+ int files_error (char *format, char *file1, char *file2);
+
+ /* This one just displays buf */
+ int do_file_error (char *buf);
+
+/* Query routines */
+ /* Replace existing file */
+ int query_replace (char *destname, struct stat *_s_stat, struct stat *_d_stat);
+
+ /* Query recursive delete */
+ int query_recursive (char *s);
+
+/* Callback routine for background activity */
+int background_attention (int fd, void *info);
+extern int background_wait;
+
+#endif
--- /dev/null
+/* Find file command for the Midnight Commander
+ Copyright (C) The Free Software Foundation
+ Written 1995 by Miguel de Icaza
+
+ Complete rewrote.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <string.h>
+#include <stdio.h>
+#ifdef OS2_NT
+# include <io.h>
+#endif
+#include "fs.h"
+#include <malloc.h> /* For free() */
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include "global.h"
+#include "mad.h"
+#include "util.h"
+#include "win.h"
+#include "color.h"
+#include "global.h"
+
+extern int verbose; /* Should be in a more sensible header file */
+
+/* Dialog manager and widgets */
+#include "dlg.h"
+#include "widget.h"
+
+#include "dialog.h" /* For do_refresh() */
+#define DIR_H_INCLUDE_HANDLE_DIRENT
+#include "dir.h"
+#include "panel.h" /* current_panel */
+#include "main.h" /* do_cd, try_to_select */
+#include "wtools.h"
+#include "tree.h"
+#include "cmd.h" /* view_file_at_line */
+#include "../vfs/vfs.h"
+
+#ifdef HAVE_XVIEW
+#include "xvmain.h"
+#endif
+
+#ifndef PORT_HAS_FLUSH_EVENTS
+# define x_flush_events()
+#endif
+
+/* Size of the find parameters window */
+#define FIND_Y 12
+static int FIND_X = 50;
+
+/* Size of the find window */
+#define FIND2_Y LINES-4
+static int FIND2_X = 64;
+
+#ifdef HAVE_X
+# define FIND2_X_USE 35
+#else
+# define FIND2_X_USE FIND2_X-20
+#endif
+
+/* A couple of extra messages we need */
+enum {
+ B_STOP = B_USER + 1,
+ B_AGAIN,
+ B_PANELIZE,
+ B_TREE,
+ B_VIEW
+};
+
+/* A list of directories to be ignores, separated with ':' */
+char *find_ignore_dirs = 0;
+
+static Dlg_head *find_dlg; /* The dialog */
+static WInput *in_start; /* Start path */
+static WInput *in_name; /* Pattern to search */
+static WInput *in_with; /* text inside filename */
+static WListbox *find_list; /* Listbox with the file list */
+static int running = 0; /* nice flag */
+static WButton *stop_button; /* pointer to the stop button */
+static WLabel *status_label; /* Finished, Searching etc. */
+static char *find_pattern; /* Pattern to search */
+static char *content_pattern; /* pattern to search inside files */
+static int count; /* Number of files displayed */
+static int matches; /* Number of matches */
+static int is_start; /* Status of the start/stop toggle button */
+int max_loops_in_idle = 10;
+static char *old_dir;
+
+/* For nice updating */
+static char *rotating_dash = "|/-\\";
+
+/* This keeps track of the directory stack */
+typedef struct dir_stack {
+ char *name;
+ struct dir_stack *prev;
+} dir_stack ;
+
+dir_stack *dir_stack_base = 0;
+
+static struct {
+ char* text;
+ int len; /* length including space and brackets */
+ int x;
+} fbuts [] = {
+ { N_("&Suspend"), 11, 29 },
+ { N_("Con&tinue"), 12, 29 },
+ { N_("&Chdir"), 11, 3 },
+ { N_("&Again"), 9, 17 },
+ { N_("&Quit"), 8, 43 },
+ { N_("Pane&lize"), 12, 3 },
+ { N_("&View - F3"), 13, 20 },
+ { N_("&Edit - F4"), 13, 38 }
+};
+
+/*
+ * find_parameters: gets information from the user
+ *
+ * If the return value is true, then the following holds:
+ *
+ * START_DIR and PATTERN are pointers to char * and upon return they
+ * contain the information provided by the user.
+ *
+ * CONTENT holds a strdup of the contents specified by the user if he
+ * asked for them or 0 if not (note, this is different from the
+ * behavior for the other two parameters.
+ *
+ */
+
+static int
+find_parameters (char **start_dir, char **pattern, char **content)
+{
+ int return_value;
+ char *temp_dir;
+ static char *in_contents = NULL;
+ static char *in_start_dir = NULL;
+ static char *in_start_name = NULL;
+
+ static char* labs[] = {N_("Start at:"), N_("Filename:"), N_("Content: ")};
+ static char* buts[] = {N_("&Ok"), N_("&Tree"), N_("&Cancel")};
+ static int ilen = 30, istart = 14;
+ static int b0 = 3, b1 = 16, b2 = 36;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+
+ if (!i18n_flag)
+ {
+ register int i = sizeof(labs)/sizeof(labs[0]);
+ int l1, maxlen = 0;
+
+ while (i--)
+ {
+ l1 = strlen (labs [i] = _(labs [i]));
+ if (l1 > maxlen)
+ maxlen = l1;
+ }
+ i = maxlen + ilen + 7;
+ if (i > FIND_X)
+ FIND_X = i;
+
+ for (i = sizeof(buts)/sizeof(buts[0]), l1 = 0; i--; )
+ {
+ l1 += strlen (buts [i] = _(buts [i]));
+ }
+ l1 += 21;
+ if (l1 > FIND_X)
+ FIND_X = l1;
+
+ ilen = FIND_X - 7 - maxlen; /* for the case of very long buttons :) */
+ istart = FIND_X - 3 - ilen;
+
+ b1 = b0 + strlen(buts[0]) + 7;
+ b2 = FIND_X - (strlen(buts[2]) + 6);
+
+ i18n_flag = 1;
+ }
+
+#endif /* ENABLE_NLS */
+
+find_par_start:
+ if (!in_start_dir)
+ in_start_dir = strdup (".");
+ if (!in_start_name)
+ in_start_name = strdup (easy_patterns ? "*" : ".");
+ if (!in_contents)
+ in_contents = strdup ("");
+
+ find_dlg = create_dlg (0, 0, FIND_Y, FIND_X, dialog_colors,
+ common_dialog_callback, "[Find File]", "findfile",
+ DLG_CENTER | DLG_GRID);
+ x_set_dialog_title (find_dlg, _("Find File"));
+
+ add_widgetl (find_dlg, button_new (9, b2, B_CANCEL, NORMAL_BUTTON,
+ buts[2], 0 ,0, "cancel"), XV_WLAY_RIGHTOF);
+#ifndef HAVE_GNOME
+ add_widgetl (find_dlg, button_new (9, b1, B_TREE, NORMAL_BUTTON,
+ buts[1], 0, 0, "tree"), XV_WLAY_RIGHTOF);
+#endif
+ add_widgetl (find_dlg, button_new (9, b0, B_ENTER, DEFPUSH_BUTTON,
+ buts[0], 0, 0, "ok"), XV_WLAY_CENTERROW);
+
+ in_with = input_new (7, istart, INPUT_COLOR, ilen, in_contents, "content");
+ add_widgetl (find_dlg, in_with, XV_WLAY_BELOWOF);
+
+ in_name = input_new (5, istart, INPUT_COLOR, ilen, in_start_name, "name");
+ add_widgetl (find_dlg, in_name, XV_WLAY_BELOWOF);
+
+ in_start = input_new (3, istart, INPUT_COLOR, ilen, in_start_dir, "start");
+ add_widgetl (find_dlg, in_start, XV_WLAY_NEXTCOLUMN);
+
+ add_widgetl (find_dlg, label_new (7, 3, labs[2], "label-cont"), XV_WLAY_BELOWOF);
+ add_widgetl (find_dlg, label_new (5, 3, labs[1], "label-file"), XV_WLAY_BELOWOF);
+ add_widgetl (find_dlg, label_new (3, 3, labs[0], "label-start"), XV_WLAY_NEXTCOLUMN);
+
+ run_dlg (find_dlg);
+ if (find_dlg->ret_value == B_CANCEL)
+ return_value = 0;
+ else if (find_dlg->ret_value == B_TREE){
+ temp_dir = strdup (in_start->buffer);
+ destroy_dlg (find_dlg);
+ free (in_start_dir);
+ if (strcmp (temp_dir, ".") == 0){
+ free (temp_dir);
+ temp_dir = strdup (cpanel->cwd);
+ }
+ in_start_dir = tree (temp_dir);
+ if (in_start_dir)
+ free (temp_dir);
+ else
+ in_start_dir = temp_dir;
+ /* Warning: Dreadful goto */
+ goto find_par_start;
+ } else {
+ return_value = 1;
+ *start_dir = strdup (in_start->buffer);
+ *pattern = strdup (in_name->buffer);
+
+ free (in_contents);
+ if (in_with->buffer [0]){
+ *content = strdup (in_with->buffer);
+ in_contents = strdup (*content);
+ } else
+ *content = in_contents = NULL;
+
+ free (in_start_dir);
+ in_start_dir = strdup (*start_dir);
+ free (in_start_name);
+ in_start_name = strdup (*pattern);
+ }
+
+ destroy_dlg (find_dlg);
+
+ return return_value;
+}
+
+static void
+push_directory (char *dir)
+{
+ dir_stack *new;
+
+ new = xmalloc (sizeof (dir_stack), "find: push_directory");
+ new->name = strdup (dir);
+ new->prev = dir_stack_base;
+ dir_stack_base = new;
+}
+
+static char*
+pop_directory (void)
+{
+ char *name;
+ dir_stack *next;
+
+ if (dir_stack_base){
+ name = dir_stack_base->name;
+ next = dir_stack_base->prev;
+ free (dir_stack_base);
+ dir_stack_base = next;
+ return name;
+ } else
+ return 0;
+}
+
+static void
+insert_file (char *dir, char *file)
+{
+ char *tmp_name;
+ static char *dirname;
+ int i;
+
+ if (dir [0] == PATH_SEP && dir [1] == PATH_SEP)
+ dir++;
+ i = strlen (dir);
+ if (i){
+ if (dir [i - 1] != PATH_SEP){
+ dir [i] = PATH_SEP;
+ dir [i + 1] = 0;
+ }
+ }
+
+ if (old_dir){
+ if (strcmp (old_dir, dir)){
+ free (old_dir);
+ old_dir = strdup (dir);
+ dirname = listbox_add_item (find_list, 0, 0, dir, 0);
+ }
+ } else {
+ old_dir = strdup (dir);
+ dirname = listbox_add_item (find_list, 0, 0, dir, 0);
+ }
+
+ tmp_name = copy_strings (" ", file, 0);
+ listbox_add_item (find_list, 0, 0, tmp_name, dirname);
+ free (tmp_name);
+}
+
+static void
+find_add_match (Dlg_head *h, char *dir, char *file)
+{
+ int p = ++matches & 7;
+
+ insert_file (dir, file);
+
+ /* Scroll nicely */
+ if (!p)
+ listbox_select_last (find_list, 1);
+ else
+ listbox_select_last (find_list, 0);
+
+#ifndef HAVE_X
+ /* Updates the current listing */
+ send_message (h, &find_list->widget, WIDGET_DRAW, 0);
+ if (p == 7)
+ mc_refresh ();
+#endif
+}
+
+char *
+locate_egrep (void)
+{
+ char *paths [] = {
+ "/bin/egrep",
+ "/usr/bin/egrep",
+ "/sbin/egrep",
+ "/usr/sbin/egrep",
+ NULL
+ };
+ struct stat s;
+ char **p;
+
+ for (p = &paths [0]; *p; p++){
+ if (stat (*p, &s) == 0)
+ return *p;
+ }
+ return "egrep";
+}
+
+/*
+ * search_content:
+ *
+ * Search with egrep the global (FIXME) content_pattern string in the
+ * DIRECTORY/FILE. It will add the found entries to the find listbox.
+ */
+void
+search_content (Dlg_head *h, char *directory, char *filename)
+{
+ struct stat s;
+ char buffer [128];
+ char *fname, *p;
+ int file_fd, pipe, ignoring;
+ char c;
+ int i;
+ pid_t pid;
+ static char *egrep_path;
+
+ fname = get_full_name (directory, filename);
+
+ if (mc_stat (fname, &s) != 0 && !S_ISREG (s.st_mode)){
+ free (fname);
+ return;
+ }
+ if (!S_ISREG (s.st_mode)){
+ free (fname);
+ return;
+ }
+
+ file_fd = mc_open (fname, O_RDONLY);
+ free (fname);
+
+ if (file_fd == -1)
+ return;
+
+ if (!egrep_path)
+ egrep_path = locate_egrep ();
+
+#ifndef GREP_STDIN
+ pipe = mc_doublepopen (file_fd, -1, &pid, egrep_path, egrep_path, "-n", content_pattern, NULL);
+#else /* GREP_STDIN */
+ pipe = mc_doublepopen (file_fd, -1, &pid, egrep_path, egrep_path, "-n", content_pattern, "-", NULL);
+#endif /* GREP STDIN */
+
+ if (pipe == -1){
+ mc_close (file_fd);
+ return;
+ }
+
+ sprintf (buffer, _("Grepping in %s"), name_trunc (filename, FIND2_X_USE));
+
+ label_set_text (status_label, buffer);
+ mc_refresh ();
+ p = buffer;
+ ignoring = 0;
+
+ enable_interrupt_key ();
+ got_interrupt ();
+ while (1){
+ i = read (pipe, &c, 1);
+ if (i != 1)
+ break;
+
+ if (c == '\n'){
+ p = buffer;
+ ignoring = 0;
+ }
+ if (ignoring)
+ continue;
+
+ if (c == ':'){
+ char *the_name;
+
+ *p = 0;
+ ignoring = 1;
+ the_name = copy_strings (buffer, ":", filename, NULL);
+ find_add_match (h, directory, the_name);
+ free (the_name);
+ } else {
+ if (p - buffer < (sizeof (buffer)-1) && ISASCII (c) && isdigit (c))
+ *p++ = c;
+ else
+ *p = 0;
+ }
+ }
+ disable_interrupt_key ();
+ if (i == -1)
+ message (1, _(" Find/read "), _(" Problem reading from child "));
+
+ mc_doublepclose (pipe, pid);
+ mc_close (file_fd);
+}
+
+static void
+do_search (struct Dlg_head *h)
+{
+ static struct dirent *dp = 0;
+ static DIR *dirp = 0;
+ static char directory [MC_MAXPATHLEN+2];
+ struct stat tmp_stat;
+ static int pos;
+ static int subdirs_left = 0;
+ char *tmp_name; /* For bulding file names */
+
+ if (!h) { /* someone forces me to close dirp */
+ if (dirp) {
+ mc_closedir (dirp);
+ dirp = 0;
+ }
+ dp = 0;
+ return;
+ }
+
+ do_search_begin:
+ while (!dp){
+
+ if (dirp){
+ mc_closedir (dirp);
+ dirp = 0;
+ }
+
+ while (!dirp){
+ char *tmp;
+
+#ifndef HAVE_X
+ attrset (REVERSE_COLOR);
+#endif
+ while (1) {
+ tmp = pop_directory ();
+ if (!tmp){
+ running = 0;
+ label_set_text (status_label, _("Finished"));
+ set_idle_proc (h, 0);
+ return;
+ }
+ if (find_ignore_dirs){
+ char *temp_dir = copy_strings (":", tmp, ":", 0);
+ if (strstr (find_ignore_dirs, temp_dir))
+ free (tmp);
+ else
+ break;
+ } else
+ break;
+ }
+
+ strcpy (directory, tmp);
+ free (tmp);
+
+ if (verbose){
+ char buffer [50];
+
+ sprintf (buffer, _("Searching %s"), name_trunc (directory, FIND2_X_USE));
+ label_set_text (status_label, buffer);
+ }
+ dirp = mc_opendir (directory);
+ mc_stat (directory, &tmp_stat);
+ subdirs_left = tmp_stat.st_nlink - 2;
+ /* Commented out as unnecessary
+ if (subdirs_left < 0)
+ subdirs_left = MAXINT;
+ */
+ }
+ dp = mc_readdir (dirp);
+ }
+
+ if (strcmp (dp->d_name, ".") == 0 ||
+ strcmp (dp->d_name, "..") == 0){
+ dp = mc_readdir (dirp);
+#ifdef HAVE_XVIEW
+ xv_post_proc (h, (void (*)(void *))do_search, (void *)h);
+#endif
+ return;
+ }
+
+ tmp_name = get_full_name (directory, dp->d_name);
+
+ if (subdirs_left){
+ mc_lstat (tmp_name, &tmp_stat);
+ if (S_ISDIR (tmp_stat.st_mode)){
+ push_directory (tmp_name);
+ subdirs_left--;
+ }
+ }
+
+ if (regexp_match (find_pattern, dp->d_name, match_file)){
+ if (content_pattern)
+ search_content (h, directory, dp->d_name);
+ else
+ find_add_match (h, directory, dp->d_name);
+ }
+
+ free (tmp_name);
+ dp = mc_readdir (dirp);
+
+ /* Displays the nice dot */
+ count++;
+ if (!(count & 31)){
+ if (verbose){
+#ifndef HAVE_X
+ pos = (pos + 1) % 4;
+ attrset (NORMALC);
+ dlg_move (h, FIND2_Y-6, FIND2_X - 4);
+ addch (rotating_dash [pos]);
+ mc_refresh ();
+ }
+ } else
+ goto do_search_begin;
+#else
+ }
+ }
+#ifdef HAVE_XVIEW
+ xv_post_proc (h, (void (*)(void *))do_search, (void *)h);
+#endif
+#endif
+ x_flush_events ();
+}
+
+static int
+view_edit_currently_selected_file (int unparsed_view, int edit)
+{
+ WLEntry *entry = find_list->current;
+ char *dir, *fullname, *filename;
+ int line;
+
+ if (!entry)
+ return MSG_NOT_HANDLED;
+
+ dir = entry->data;
+
+ if (!entry->text || !dir)
+ return MSG_NOT_HANDLED;
+
+ if (content_pattern){
+ filename = strchr (entry->text + 4, ':') + 1;
+ line = atoi (entry->text + 4);
+ } else {
+ filename = entry->text + 4;
+ line = 0;
+ }
+ if (dir [0] == '.' && dir [1] == 0)
+ fullname = strdup (filename);
+ else if (dir [0] == '.' && dir [1] == PATH_SEP)
+ fullname = get_full_name (dir+2, filename);
+ else
+ fullname = get_full_name (dir, filename);
+
+ if (edit)
+ do_edit_at_line (fullname, line);
+ else
+ view_file_at_line (fullname, unparsed_view, use_internal_view, line);
+ free (fullname);
+ return MSG_HANDLED;
+}
+
+static int
+find_callback (struct Dlg_head *h, int id, int Msg)
+{
+ switch (Msg){
+#ifndef HAVE_X
+ case DLG_DRAW:
+ common_dialog_repaint (h);
+ break;
+#endif
+
+ case DLG_KEY:
+ if (id == KEY_F(3) || id == KEY_F(13)){
+ int unparsed_view = (id == KEY_F(13));
+ return view_edit_currently_selected_file (unparsed_view, 0);
+ }
+ if (id == KEY_F(4)){
+ return view_edit_currently_selected_file (0, 1);
+ }
+ return MSG_NOT_HANDLED;
+
+ case DLG_IDLE:
+ do_search (h);
+ break;
+ }
+ return 0;
+}
+
+/* Handles the Stop/Start button in the find window */
+static int
+start_stop (int button, void *extra)
+{
+ running = is_start;
+ set_idle_proc (find_dlg, running);
+ is_start = !is_start;
+
+ label_set_text (status_label, is_start ? _("Stopped") : _("Searching"));
+ button_set_text (stop_button, fbuts [is_start].text);
+
+ return 0;
+}
+
+/* Handle view command, when invoked as a button */
+static int
+find_do_view_file (int button, void *extra)
+{
+ view_edit_currently_selected_file (0, 0);
+ return 0;
+}
+
+/* Handle edit command, when invoked as a button */
+static int
+find_do_edit_file (int button, void *extra)
+{
+ view_edit_currently_selected_file (0, 1);
+ return 0;
+}
+
+static void
+init_find_vars (void)
+{
+ char *dir;
+
+ if (old_dir){
+ free (old_dir);
+ old_dir = 0;
+ }
+ count = 0;
+ matches = 0;
+
+ /* Remove all the items in the stack */
+ while ((dir = pop_directory ()) != NULL)
+ free (dir);
+}
+
+static int
+find_file (char *start_dir, char *pattern, char *content, char **dirname, char **filename)
+{
+ int return_value = 0;
+ char *dir;
+ char *dir_tmp, *file_tmp;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+ if (!i18n_flag)
+ {
+ register int i = sizeof (fbuts) / sizeof (fbuts[0]);
+ while (i--)
+ fbuts [i].len = strlen (fbuts [i].text = _(fbuts [i].text)) + 3;
+ fbuts [2].len += 2; /* DEFPUSH_BUTTON */
+ i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ /*
+ * Dynamically place buttons centered within current window size
+ */
+ {
+ int l0 = max (fbuts[0].len, fbuts[1].len);
+ int l1 = fbuts[2].len + fbuts[3].len + l0 + fbuts[4].len;
+ int l2 = fbuts[5].len + fbuts[6].len + fbuts[7].len;
+ int r1, r2;
+
+ FIND2_X = COLS - 16;
+
+ /* Check, if both button rows fit within FIND2_X */
+ if (l1 + 9 > FIND2_X) FIND2_X = l1 + 9;
+ if (l2 + 8 > FIND2_X) FIND2_X = l2 + 8;
+
+ /* compute amount of space between buttons for each row */
+ r1 = (FIND2_X - 4 - l1) % 5;
+ l1 = (FIND2_X - 4 - l1) / 5;
+ r2 = (FIND2_X - 4 - l2) % 4;
+ l2 = (FIND2_X - 4 - l2) / 4;
+
+ /* ...and finally, place buttons */
+ fbuts [2].x = 2 + r1/2 + l1;
+ fbuts [3].x = fbuts [2].x + fbuts [2].len + l1;
+ fbuts [0].x = fbuts [3].x + fbuts [3].len + l1;
+ fbuts [4].x = fbuts [0].x + l0 + l1;
+ fbuts [5].x = 2 + r2/2 + l2;
+ fbuts [6].x = fbuts [5].x + fbuts [5].len + l2;
+ fbuts [7].x = fbuts [6].x + fbuts [6].len + l2;
+ }
+
+ find_dlg = create_dlg (0, 0, FIND2_Y, FIND2_X, dialog_colors,
+ find_callback, "[Find File]", "mfind", DLG_CENTER | DLG_GRID);
+
+ x_set_dialog_title (find_dlg, _("Find file"));
+
+ add_widgetl (find_dlg,
+ button_new (FIND2_Y-3, fbuts[7].x, B_VIEW, NORMAL_BUTTON,
+ fbuts[7].text, find_do_edit_file, find_dlg, "button-edit"), 0);
+ add_widgetl (find_dlg,
+ button_new (FIND2_Y-3, fbuts[6].x, B_VIEW, NORMAL_BUTTON,
+ fbuts[6].text, find_do_view_file, find_dlg, "button-view"), 0);
+ add_widgetl (find_dlg,
+ button_new (FIND2_Y-3, fbuts[5].x, B_PANELIZE, NORMAL_BUTTON,
+ fbuts[5].text, 0, 0, "button-panelize"), XV_WLAY_CENTERROW);
+
+ add_widgetl (find_dlg,
+ button_new (FIND2_Y-4, fbuts[4].x, B_CANCEL, NORMAL_BUTTON,
+ fbuts[4].text, 0, 0, "button-quit"), XV_WLAY_RIGHTOF);
+ stop_button = button_new (FIND2_Y-4, fbuts[0].x, B_STOP, NORMAL_BUTTON,
+ fbuts[0].text, start_stop, find_dlg, "start-stop");
+ add_widgetl (find_dlg, stop_button, XV_WLAY_RIGHTOF);
+ add_widgetl (find_dlg,
+ button_new (FIND2_Y-4, fbuts[3].x, B_AGAIN, NORMAL_BUTTON,
+ fbuts[3].text, 0, 0, "button-again"), XV_WLAY_RIGHTOF);
+ add_widgetl (find_dlg,
+ button_new (FIND2_Y-4, fbuts[2].x, B_ENTER, DEFPUSH_BUTTON,
+ fbuts[2].text, 0, 0, "button-chdir"), XV_WLAY_CENTERROW);
+
+ status_label = label_new (FIND2_Y-6, 4, _("Searching"), "label-search");
+ add_widgetl (find_dlg, status_label, XV_WLAY_BELOWOF);
+
+ find_list = listbox_new (2, 2, FIND2_X-4, FIND2_Y-9, listbox_finish, 0, "listbox");
+ add_widgetl (find_dlg, find_list, XV_WLAY_EXTENDWIDTH);
+
+ /* FIXME: Need to cleanup this, this ought to be passed non-globaly */
+ find_pattern = pattern;
+ content_pattern = content;
+
+ set_idle_proc (find_dlg, 1);
+ init_find_vars ();
+ push_directory (start_dir);
+
+#ifdef HAVE_XVIEW
+ xv_post_proc (find_dlg, (void (*)(void *))do_search, (void *)find_dlg);
+#endif
+ run_dlg (find_dlg);
+
+ return_value = find_dlg->ret_value;
+
+ /* Remove all the items in the stack */
+ while ((dir = pop_directory ()) != NULL)
+ free (dir);
+
+ listbox_get_current (find_list, &file_tmp, &dir_tmp);
+
+ if (dir_tmp)
+ *dirname = strdup (dir_tmp);
+ if (file_tmp)
+ *filename = strdup (file_tmp);
+ if (return_value == B_PANELIZE && *filename){
+ int status, link_to_dir, stalled_link;
+ int next_free = 0;
+ int i;
+ struct stat buf;
+ WLEntry *entry = find_list->list;
+ dir_list *list = &cpanel->dir;
+ char *dir, *name;
+
+ for (i = 0; entry && i < find_list->count; entry = entry->next, i++){
+ char *filename;
+
+ if (content_pattern)
+ filename = strchr (entry->text+4, ':')+1;
+ else
+ filename = entry->text+4;
+
+ if (!entry->text || !entry->data)
+ continue;
+ dir = entry->data;
+ if (dir [0] == '.' && dir [1] == 0)
+ name = strdup (filename);
+ else if (dir [0] == '.' && dir [1] == PATH_SEP)
+ name = get_full_name (dir + 2, filename);
+ else
+ name = get_full_name (dir, filename);
+ status = handle_path (list, name, &buf, next_free, &link_to_dir,
+ &stalled_link);
+ if (status == 0) {
+ free (name);
+ continue;
+ }
+ if (status == -1) {
+ free (name);
+ break;
+ }
+
+ /* don't add files more than once to the panel */
+ if (content_pattern && next_free > 0){
+ if (strcmp (list->list [next_free-1].fname, name) == 0) {
+ free (name);
+ continue;
+ }
+ }
+
+ if (!next_free) /* first turn i.e clean old list */
+ clean_dir (list, cpanel->count);
+ list->list [next_free].fnamelen = strlen (name);
+ list->list [next_free].fname = name;
+ list->list [next_free].cache = NULL;
+ file_mark (cpanel, next_free, 0);
+ list->list [next_free].f.link_to_dir = link_to_dir;
+ list->list [next_free].f.stalled_link = stalled_link;
+ list->list [next_free].buf = buf;
+ next_free++;
+ if (!(next_free & 15))
+ rotate_dash ();
+ }
+ if (next_free){
+ cpanel->count = next_free;
+ cpanel->is_panelized = 1;
+ cpanel->dirs_marked = 0;
+ cpanel->has_dir_sizes = 0;
+ cpanel->marked = 0;
+ cpanel->total = 0;
+ cpanel->top_file = 0;
+ cpanel->selected = 0;
+
+ if (start_dir [0] == PATH_SEP){
+ strcpy (cpanel->cwd, PATH_SEP_STR);
+ chdir (PATH_SEP_STR);
+ }
+ }
+ }
+
+ set_idle_proc (find_dlg, 0);
+ destroy_dlg (find_dlg);
+ do_search (0); /* force do_search to release resources */
+ if (old_dir){
+ free (old_dir);
+ old_dir = 0;
+ }
+ return return_value;
+}
+
+void
+do_find (void)
+{
+ char *start_dir, *pattern, *content;
+ char *filename, *dirname;
+ int v, dir_and_file_set;
+ int done = 0;
+
+ while (!done){
+ if (!find_parameters (&start_dir, &pattern, &content))
+ break;
+
+ dirname = filename = NULL;
+ is_start = 0;
+ v = find_file (start_dir, pattern, content, &dirname, &filename);
+ free (start_dir);
+ free (pattern);
+
+ if (v == B_ENTER){
+ if (dirname || filename){
+ if (dirname){
+ do_cd (dirname, cd_exact);
+ if (filename)
+ try_to_select (cpanel, filename + (content ?
+ (strchr (filename + 4, ':') - filename + 1) : 4) );
+ } else if (filename)
+ do_cd (filename, cd_exact);
+ paint_panel (cpanel);
+ select_item (cpanel);
+ }
+ if (dirname)
+ free (dirname);
+ if (filename)
+ free (filename);
+ break;
+ }
+ if (content)
+ free (content);
+ dir_and_file_set = dirname && filename;
+ if (dirname) free (dirname);
+ if (filename) free (filename);
+ if (v == B_CANCEL)
+ break;
+
+ if (v == B_PANELIZE){
+ if (dir_and_file_set){
+ try_to_select (cpanel, NULL);
+ paint_panel (cpanel);
+ }
+ break;
+ }
+ }
+}
+
--- /dev/null
+#ifndef __FIND_H
+#define __FIND_H
+
+#define MAX_FIND_MENU 4 /* Maximum Menu */
+#define MAX_FIND_FLINES 11 /* Size of Window Where files are stored */
+#define MAX_FIND_TLINES 4 /* Size of Window Where Menu and text .. */
+#define MAX_FIND_COLS 48 /* Length of Windows */
+#define FIND_DIALOG_SIZE MAX_FIND_FLINES+MAX_FIND_TLINES
+ /* Total size of the whole dialog */
+
+typedef struct find_list{
+ int selected; /* Selection field */
+ int ypos; /* For Scrolling */
+ int isdir; /* For adding a '\t' on FALSE */
+ char *fname; /* Name of the file */
+ char *path; /* For changing panel */
+ struct find_list *up;
+ struct find_list *down;
+}find_list;
+
+typedef struct FStack{ /* The Stack will be used to store */
+ char *dir_name; /* the directories to search */
+ struct FStack *next; /* single-linked */
+}FStack;
+
+void do_find(void);
+#endif
--- /dev/null
+/* HLP converter
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+ Copyright (C) 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "help.h"
+
+#define BUFFER_SIZE 256
+
+static int width; /* Output width in characters */
+static int col = 0; /* Current output column */
+static FILE *toc_file; /* TOC file */
+static int out_row = 1; /* Current output row */
+static int in_row = 0; /* Current input row */
+static int indent = 1;
+static int curindent = 1;
+static int freshnl = 1;
+static int firstlen = 0;
+static int verbatim = 0;
+
+/* Report error in input */
+void print_error (char *message)
+{
+ fprintf (stderr, "fixhlp: %s at row %d\n", message, in_row);
+}
+
+/* Change output line */
+void newline (void)
+{
+ out_row ++;
+ col = indent;
+ curindent = indent;
+ printf("\n%*s", indent, "");
+ freshnl = 1;
+ firstlen = 0;
+}
+
+/* Calculate the length of string */
+int string_len (char *buffer)
+{
+ static int anchor_flag = 0; /* Flag: Inside hypertext anchor name */
+ static int link_flag = 0; /* Flag: Inside hypertext link target name */
+ int i; /* Index */
+ int c; /* Current character */
+ int len = 0; /* Result: the length of the string */
+
+ for (i = 0; i < strlen (buffer); i ++)
+ {
+ c = buffer [i];
+ if (c == CHAR_LINK_POINTER)
+ link_flag = 1; /* Link target name starts */
+ else if (c == CHAR_LINK_END)
+ link_flag = 0; /* Link target name ends */
+ else if (c == CHAR_NODE_END){
+ /* Node anchor name starts */
+ anchor_flag = 1;
+ /* Ugly hack to prevent loss of one space */
+ len ++;
+ }
+ /* Don't add control characters to the length */
+ if (c < 32)
+ continue;
+ /* Attempt to handle backslash quoting */
+ /* Increase length if not inside anchor name or link target name */
+ if (!anchor_flag && !link_flag)
+ len ++;
+ if (anchor_flag && c == ']'){
+ /* Node anchor name ends */
+ anchor_flag = 0;
+ }
+ }
+ return len;
+}
+
+/* Output the string */
+void print_string (char *buffer)
+{
+ int len; /* The length of current word */
+ int i; /* Index */
+ int c; /* Current character */
+ char *p;
+
+ /* Split into words */
+ if (verbatim) {
+ printf ("%s", buffer);
+ newline ();
+ return;
+ }
+ p = strchr (buffer, CHAR_LINK_POINTER);
+ if (p) {
+ char *q;
+
+ *p = 0;
+ print_string (buffer);
+ q = strchr (p + 1, CHAR_LINK_END);
+ if (q) {
+ *q = 0;
+ printf ("%c%s%c", CHAR_LINK_POINTER, p + 1, CHAR_LINK_END);
+ print_string (q + 1);
+ } else {
+ /* Error, but try to handle it somehow */
+ printf ("%c", CHAR_LINK_END);
+ }
+ return;
+ }
+ buffer = strtok (buffer, " \t\n");
+ /* Repeat for each word */
+ while (buffer){
+ /* Skip empty strings */
+ if (strlen (buffer) > 0){
+ len = string_len (buffer);
+ /* Change the line if about to break the right margin */
+ if (col + len >= width)
+ newline ();
+ /* Words are separated by spaces */
+ if (col > curindent){
+ printf (" ");
+ col ++;
+ }
+ printf ("%s", buffer);
+ /* Increase column */
+ col += len;
+ }
+ /* Get the next word */
+ buffer = strtok (NULL, " \t\n");
+ } /* while */
+ if (freshnl) {
+ firstlen = col - curindent;
+ freshnl = 0;
+ }
+}
+
+/* Like print_string but with printf-like syntax */
+void printf_string (char *format, ...)
+{
+ va_list args;
+ char buffer [BUFFER_SIZE];
+
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ print_string (buffer);
+}
+
+int main (int argc, char **argv)
+{
+ int len; /* Length of input line */
+ char buffer [BUFFER_SIZE]; /* Input line */
+ int i, j;
+ char *p;
+ int ignore_newline = 0;
+
+ /* Validity check for arguments */
+ if (argc != 3 || (width = atoi (argv[1])) <= 10){
+ fprintf (stderr, _("Usage: fixhlp <width> <tocname>\n"));
+ return 3;
+ }
+
+ if ((toc_file = fopen (argv[2], "w")) == NULL) {
+ fprintf (stderr, _("fixhlp: Cannot open toc for writing"));
+ return 4;
+ }
+ fprintf (toc_file, _("\04[Contents]\n Topics:\n\n"));
+
+ /* Repeat for each input line */
+ while (!feof (stdin)){
+ /* Read a line */
+ if (!fgets (buffer, BUFFER_SIZE, stdin)){
+ break;
+ }
+ in_row ++;
+ len = strlen (buffer);
+ /* Remove terminating newline */
+ if (buffer [len-1] == '\n')
+ {
+ len --;
+ buffer [len] = 0;
+ }
+ if (!buffer[0]) {
+ if (ignore_newline)
+ ignore_newline = 0;
+ else
+ newline ();
+ } else {
+ if (buffer [0] == 4 && buffer [1] == '[') {
+ for (p = buffer + 2; *p == ' '; p++);
+ fprintf (toc_file, "%*s\01 %s \02%s\03\n", p - buffer + 1, "", p, p);
+ printf ("\04[%s]\n %s", p, p);
+ } else if (buffer [0] == CHAR_RESERVED && buffer [1] == '"') {
+ continue;
+ } else {
+ char *p, *q;
+ int i;
+
+ for (p = buffer, q = strchr (p, CHAR_RESERVED); q != NULL;
+ p = q + 1, q = strchr (p, CHAR_RESERVED)) {
+ *q = 0;
+ if (*p)
+ print_string (p);
+ q++;
+ if (*q == '/')
+ ignore_newline = 1;
+ else if (*q == 'v')
+ verbatim = 1;
+ else if (*q == 'n')
+ verbatim = 0;
+ else {
+ indent = *q - '0';
+ if (ignore_newline) {
+ i = firstlen;
+ if (i > indent - curindent - 1)
+ ignore_newline = 0;
+ else {
+ i = indent - curindent - i - 1;
+ printf ("%*s", i, "");
+ col += i;
+ }
+ }
+ }
+ }
+ print_string (p);
+ }
+ }
+ }
+
+ /* All done */
+ newline ();
+ return 0;
+}
--- /dev/null
+/* Include file to use opendir/closedir/readdir */
+
+#ifndef __FS_H
+#define __FS_H
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifndef OS2_NT
+#include <sys/param.h>
+#endif
+#include <sys/stat.h>
+
+#ifndef MAXPATHLEN
+# define MC_MAXPATHLEN 4096
+#else
+# define MC_MAXPATHLEN MAXPATHLEN
+#endif
+
+/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
+#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
+# ifdef __os2__
+# include "dirent.h"
+# else
+# include <dirent.h>
+# endif
+# define NLENGTH(dirent) (strlen ((dirent)->d_name))
+# define DIRENT_LENGTH_COMPUTED 1
+#else
+# define dirent direct
+# define NLENGTH(dirent) ((dirent)->d_namlen)
+
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
+
+#endif
--- /dev/null
+/* fsusage.c -- return space usage of mounted filesystems
+ Copyright (C) 1991, 1992 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 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#if !defined(NO_INFOMOUNT) || defined(__QNX__)
+
+#if defined(__QNX__)
+#define STAT_STATFS4
+#endif
+
+#include <sys/types.h>
+
+#include "fsusage.h"
+
+int statfs (); /* We leave the type ambiguous intentionally here */
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_MOUNT_H
+#include <sys/mount.h>
+#endif
+
+#ifdef HAVE_SYS_VFS_H
+#include <sys/vfs.h>
+#endif
+
+#ifdef HAVE_SYS_FILSYS_H
+#include <sys/filsys.h> /* SVR2. */
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_SYS_STATFS_H
+#include <sys/statfs.h>
+#endif
+
+#ifdef HAVE_DUSTAT_H /* AIX PS/2. */
+#include <sys/dustat.h>
+#endif
+
+#ifdef HAVE_SYS_STATVFS_H /* SVR4. */
+#include <sys/statvfs.h>
+#endif
+
+/* Return the number of TOSIZE-byte blocks used by
+ BLOCKS FROMSIZE-byte blocks, rounding away from zero.
+ TOSIZE must be positive. Return -1 if FROMSIZE is not positive. */
+
+long fs_adjust_blocks (long blocks, int fromsize, int tosize)
+{
+ if (tosize <= 0)
+ abort ();
+ if (fromsize <= 0)
+ return -1;
+
+ if (fromsize == tosize) /* E.g., from 512 to 512. */
+ return blocks;
+ else if (fromsize > tosize) /* E.g., from 2048 to 512. */
+ return blocks * (fromsize / tosize);
+ else /* E.g., from 256 to 512. */
+ return (blocks + (blocks < 0 ? -1 : 1)) / (tosize / fromsize);
+}
+
+/* Fill in the fields of FSP with information about space usage for
+ the filesystem on which PATH resides.
+ Return 0 if successful, -1 if not. */
+
+int get_fs_usage (char *path, struct fs_usage *fsp)
+{
+#ifdef STAT_STATFS3_OSF1
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
+ return -1;
+#define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_fsize, 512)
+#endif /* STAT_STATFS3_OSF1 */
+
+#ifdef STAT_STATFS2_FS_DATA /* Ultrix. */
+ struct fs_data fsd;
+
+ if (statfs (path, &fsd) != 1)
+ return -1;
+#define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), 1024, 512)
+ fsp->fsu_blocks = CONVERT_BLOCKS (fsd.fd_req.btot);
+ fsp->fsu_bfree = CONVERT_BLOCKS (fsd.fd_req.bfree);
+ fsp->fsu_bavail = CONVERT_BLOCKS (fsd.fd_req.bfreen);
+ fsp->fsu_files = fsd.fd_req.gtot;
+ fsp->fsu_ffree = fsd.fd_req.gfree;
+#endif
+
+#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_bsize, 512)
+#endif
+
+#ifdef STAT_STATFS2_FSIZE /* 4.4BSD. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd) < 0)
+ return -1;
+#define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_fsize, 512)
+#endif
+
+#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX. */
+ struct statfs fsd;
+
+ if (statfs (path, &fsd, sizeof fsd, 0) < 0)
+ return -1;
+ /* Empirically, the block counts on most SVR3 and SVR3-derived
+ systems seem to always be in terms of 512-byte blocks,
+ no matter what value f_bsize has. */
+#if _AIX
+#define CONVERT_BLOCKS(b) fs_adjust_blocks ((b), fsd.f_bsize, 512)
+#else
+#define CONVERT_BLOCKS(b) (b)
+#ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx. */
+#ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
+#define f_bavail f_bfree
+#endif
+#endif
+#endif
+#endif
+
+#ifdef STAT_STATVFS /* SVR4. */
+ struct statvfs fsd;
+
+ if (statvfs (path, &fsd) < 0)
+ return -1;
+ /* f_frsize isn't guaranteed to be supported. */
+#define CONVERT_BLOCKS(b) \
+ fs_adjust_blocks ((b), fsd.f_frsize ? fsd.f_frsize : fsd.f_bsize, 512)
+#endif
+
+#if defined(CONVERT_BLOCKS) && !defined(STAT_STATFS2_FS_DATA) && !defined(STAT_READ_FILSYS) /* !Ultrix && !SVR2. */
+ fsp->fsu_blocks = CONVERT_BLOCKS (fsd.f_blocks);
+ fsp->fsu_bfree = CONVERT_BLOCKS (fsd.f_bfree);
+ fsp->fsu_bavail = CONVERT_BLOCKS (fsd.f_bavail);
+ fsp->fsu_files = fsd.f_files;
+ fsp->fsu_ffree = fsd.f_ffree;
+#endif
+
+ return 0;
+}
+
+#if defined(_AIX) && defined(_I386)
+/* AIX PS/2 does not supply statfs. */
+
+int statfs (char *path, struct statfs *fsb)
+{
+ struct stat stats;
+ struct dustat fsd;
+
+ if (stat (path, &stats))
+ return -1;
+ if (dustat (stats.st_dev, 0, &fsd, sizeof (fsd)))
+ return -1;
+ fsb->f_type = 0;
+ fsb->f_bsize = fsd.du_bsize;
+ fsb->f_blocks = fsd.du_fsize - fsd.du_isize;
+ fsb->f_bfree = fsd.du_tfree;
+ fsb->f_bavail = fsd.du_tfree;
+ fsb->f_files = (fsd.du_isize - 2) * fsd.du_inopb;
+ fsb->f_ffree = fsd.du_tinode;
+ fsb->f_fsid.val[0] = fsd.du_site;
+ fsb->f_fsid.val[1] = fsd.du_pckno;
+ return 0;
+}
+#endif /* _AIX && _I386 */
+#endif /* NO_INFOMOUNT */
--- /dev/null
+/* fsusage.h -- declarations for filesystem space usage info
+ Copyright (C) 1991, 1992 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 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __FSUSAGE_H
+#define __FSUSAGE_H
+
+/* Space usage statistics for a filesystem. Blocks are 512-byte. */
+struct fs_usage
+{
+ long fsu_blocks; /* Total blocks. */
+ long fsu_bfree; /* Free blocks available to superuser. */
+ long fsu_bavail; /* Free blocks available to non-superuser. */
+ long fsu_files; /* Total file nodes. */
+ long fsu_ffree; /* Free file nodes. */
+};
+
+
+extern int get_fs_usage (char *path, struct fs_usage *fsp);
+#endif
--- /dev/null
+#!/usr/bin/perl
+# Since we use a linear search trought the block and the license and
+# the warranty are quite big, we leave them at the end of the help file,
+# the index will be consulted quite frequently, so we put it at the beginning.
+
+@help_file = <>;
+
+foreach $line (@help_file){
+ if ($line =~ /\x4\[(.*)\]/ && $line !~ /\x4\[main\]/){
+ $nodes[$node_count++] = $1;
+ $line =~ s/(\x4\[) */$1/;
+ }
+}
+
+print "\x4[Contents]\nTopics:\n\n";
+foreach $node (@nodes){
+ if (length $node){
+ $node =~ m/^( *)(.*)$/;
+ printf (" %s\x1 %s \x2%s\x3", $1, $2, $2);
+ }
+ print "\n";
+}
+#foreach $line (@help_file){
+# $line =~ s/%NEW_NODE%/\004/g;
+#}
+print @help_file;
--- /dev/null
+#ifndef __GLOBAL_H
+#define __GLOBAL_H
+
+extern char *home_dir;
+
+#ifdef min
+#undef min
+#endif
+
+#ifdef max
+#undef max
+#endif
+
+#define min(x,y) (x>y ? y: x)
+#define max(x,y) (x>y ? x: y)
+
+void refresh_screen (void *);
+
+#ifndef HAVE_STRDUP
+char *strdup (const char *);
+#endif
+
+/* AIX compiler doesn't understand '\e' */
+#define ESC_CHAR '\033'
+#define ESC_STR "\033"
+
+#ifdef USE_BSD_CURSES
+# define xgetch x_getch
+#else
+# define xgetch getch
+#endif
+
+#endif
--- /dev/null
+/* Hypertext file browser.
+ Copyright (C) 1994, 1995 Miguel de Icaza.
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Implements the hypertext file viewer.
+ The hypertext file is a file that may have one or more nodes. Each
+ node ends with a ^D character and starts with a bracket, then the
+ name of the node and then a closing bracket.
+
+ Links in the hypertext file are specified like this: the text that
+ will be highlighted should have a leading ^A, then it comes the
+ text, then a ^B indicating that highlighting is done, then the name
+ of the node you want to link to and then a ^C.
+
+ The file must contain a ^D at the beginning and at the end of the
+ file or the program will not be able to detect the end of file.
+
+ Lazyness/widgeting attack: This file does use the dialog manager
+ and uses mainly the dialog to achieve the help work. there is only
+ one specialized widget and it's only used to forward the mouse messages
+ to the appropiate routine.
+
+*/
+
+#include <config.h>
+#include "tty.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <malloc.h>
+#include <errno.h>
+#include "mad.h"
+#include "color.h"
+#include "util.h"
+#include "dialog.h"
+#include "win.h"
+#include "global.h"
+#include "mouse.h"
+#include "key.h" /* For mi_getch() */
+#include "help.h"
+#include "layout.h" /* keybar_visible */
+#include "x.h"
+#include "dlg.h" /* For Dlg_head */
+#include "widget.h" /* For Widget */
+
+#ifdef HAVE_TK
+# include "tkmain.h"
+#endif
+
+#define MAXLINKNAME 80
+#define HISTORY_SIZE 20
+#define HELP_WINDOW_WIDTH 62
+
+/* "$Id: help.c,v 1.1 2001/12/30 09:55:25 sedwards Exp $" */
+
+static char *data; /* Pointer to the loaded data file */
+static int help_lines = 18; /* Lines in help viewer */
+static int history_ptr; /* For the history queue */
+static char *main; /* The main node */
+static char *last_shown = 0; /* Last byte shown in a screen */
+static int end_of_node = 0; /* Flag: the last character of the node shown? */
+char *currentpoint, *startpoint;
+static char *selected_item;
+
+/* The widget variables */
+static Dlg_head *whelp;
+
+static struct {
+ char *page; /* Pointer to the selected page */
+ char *link; /* Pointer to the selected link */
+} history [HISTORY_SIZE];
+
+/* Link areas for the mouse */
+typedef struct Link_Area {
+ int x1, y1, x2, y2;
+ char *link_name;
+ struct Link_Area *next;
+} Link_Area;
+
+static Link_Area *link_area = NULL;
+static int inside_link_area = 0;
+
+static int help_callback (struct Dlg_head *h, int id, int msg);
+
+#ifdef OS2_NT
+struct {
+ int acscode;
+ int pccode;
+} acs2pc_table [] = {
+ { 'q', 0xC4 },
+ { 'x', 0xB3 },
+ { 'l', 0xDA },
+ { 'k', 0xBF },
+ { 'm', 0xC0 },
+ { 'j', 0xD9 },
+ { 'a', 0xB0 },
+ { 'u', 0xB4 },
+ { 't', 0xC3 },
+ { 'w', 0xC2 },
+ { 'v', 0xC1 },
+ { 'n', 0xC5 },
+ { 0, 0 } };
+
+static int acs2pc (int acscode)
+{
+ int i;
+
+ for (i = 0; acs2pc_table[i].acscode != 0; i++)
+ if (acscode == acs2pc_table[i].acscode) {
+ return acs2pc_table[i].pccode;
+ }
+ return 0;
+}
+#endif
+
+/* returns the position where text was found in the start buffer */
+/* or 0 if not found */
+char *search_string (char *start, char *text)
+{
+ char *d = text;
+ char *e = start;
+
+ /* fmt sometimes replaces a space with a newline in the help file */
+ /* Replace the newlines in the link name with spaces to correct the situation */
+ while (*d){
+ if (*d == '\n')
+ *d = ' ';
+ d++;
+ }
+ /* Do search */
+ for (d = text; *e; e++){
+ if (*d == *e)
+ d++;
+ else
+ d = text;
+ if (!*d)
+ return e+1;
+ }
+ return 0;
+}
+
+/* Searches text in the buffer pointed by start. Search ends */
+/* if the CHAR_NODE_END is found in the text. Returns 0 on failure */
+static char *search_string_node (char *start, char *text)
+{
+ char *d = text;
+ char *e = start;
+
+ if (!start)
+ return 0;
+
+ for (; *e && *e != CHAR_NODE_END; e++){
+ if (*d == *e)
+ d++;
+ else
+ d = text;
+ if (!*d)
+ return e+1;
+ }
+ return 0;
+}
+
+/* Searches the_char in the buffer pointer by start and searches */
+/* it can search forward (direction = 1) or backward (direction = -1) */
+static char *search_char_node (char *start, char the_char, int direction)
+{
+ char *e;
+
+ e = start;
+
+ for (; *e && (*e != CHAR_NODE_END); e += direction){
+ if (*e == the_char)
+ return e;
+ }
+ return 0;
+}
+
+/* Returns the new current pointer when moved lines lines */
+static char *move_forward2 (char *c, int lines)
+{
+ char *p;
+ int line;
+
+ currentpoint = c;
+ for (line = 0, p = currentpoint; *p && *p != CHAR_NODE_END; p++){
+ if (line == lines)
+ return currentpoint = p;
+ if (*p == '\n')
+ line++;
+ }
+ return currentpoint = c;
+}
+
+static char *move_backward2 (char *c, int lines)
+{
+ char *p;
+ int line;
+
+ currentpoint = c;
+ for (line = 0, p = currentpoint; *p && p >= data; p--){
+ if (*p == CHAR_NODE_END)
+ {
+ /* We reached the beginning of the node */
+ /* Skip the node headers */
+ while (*p != ']') p++;
+ return currentpoint = p + 2;
+ }
+ if (*(p - 1) == '\n')
+ line++;
+ if (line == lines)
+ return currentpoint = p;
+ }
+ return currentpoint = c;
+}
+
+static void move_forward (int i)
+{
+ if (end_of_node)
+ return;
+ currentpoint = move_forward2 (currentpoint, i);
+}
+
+static void move_backward (int i)
+{
+ currentpoint = move_backward2 (currentpoint, ++i);
+}
+
+static void move_to_top (int dummy)
+{
+ while (currentpoint > data && *currentpoint != CHAR_NODE_END)
+ currentpoint--;
+ while (*currentpoint != ']')
+ currentpoint++;
+ currentpoint = currentpoint + 1;
+ selected_item = NULL;
+}
+
+static void move_to_bottom (int dummy)
+{
+ while (*currentpoint && *currentpoint != CHAR_NODE_END)
+ currentpoint++;
+ currentpoint--;
+ move_backward (help_lines - 1);
+}
+
+char *help_follow_link (char *start, char *selected_item)
+{
+ char link_name [MAXLINKNAME];
+ char *p;
+ int i = 0;
+
+ if (!selected_item)
+ return start;
+
+ for (p = selected_item; *p && *p != CHAR_NODE_END && *p != CHAR_LINK_POINTER; p++)
+ ;
+ if (*p == CHAR_LINK_POINTER){
+ link_name [0] = '[';
+ for (i = 1; *p != CHAR_LINK_END && *p && *p != CHAR_NODE_END && i < MAXLINKNAME-3; )
+ link_name [i++] = *++p;
+ link_name [i-1] = ']';
+ link_name [i] = 0;
+ p = search_string (data, link_name);
+ if (p)
+ return p;
+ }
+ return _(" Help file format error\n\x4"); /* */
+}
+
+static char *select_next_link (char *start, char *current_link)
+{
+ char *p;
+
+ if (!current_link)
+ return 0;
+
+ p = search_string_node (current_link, STRING_LINK_END);
+ if (!p)
+ return NULL;
+ p = search_string_node (p, STRING_LINK_START);
+ if (!p)
+ return NULL;
+ return p - 1;
+}
+
+static char *select_prev_link (char *start, char *current_link)
+{
+ char *p;
+
+ if (!current_link)
+ return 0;
+
+ p = current_link - 1;
+ if (p <= start)
+ return 0;
+
+ p = search_char_node (p, CHAR_LINK_START, -1);
+ return p;
+}
+
+static void start_link_area (int x, int y, char *link_name)
+{
+ Link_Area *new;
+
+ if (inside_link_area)
+ message (0, _(" Warning "), _(" Internal bug: Double start of link area "));
+
+ /* Allocate memory for a new link area */
+ new = (Link_Area*) xmalloc (sizeof (Link_Area), "Help, link_area");
+ new->next = link_area;
+ link_area = new;
+
+ /* Save the beginning coordinates of the link area */
+ link_area->x1 = x;
+ link_area->y1 = y;
+
+ /* Save the name of the destination anchor */
+ link_area->link_name = link_name;
+
+ inside_link_area = 1;
+}
+
+static void end_link_area (int x, int y)
+{
+ if (inside_link_area){
+ /* Save the end coordinates of the link area */
+ link_area->x2 = x;
+ link_area->y2 = y;
+
+ inside_link_area = 0;
+ }
+}
+
+static void clear_link_areas (void)
+{
+ Link_Area *current;
+
+ while (link_area){
+ current = link_area;
+ link_area = current -> next;
+ free (current);
+ }
+ inside_link_area = 0;
+}
+
+static void show (Dlg_head *h, char *paint_start)
+{
+ char *p;
+ int col, line, c;
+ int painting = 1;
+ int acs; /* Flag: Alternate character set active? */
+ int repeat_paint;
+ int active_col, active_line;/* Active link position */
+
+ do {
+
+ line = col = acs = active_col = active_line = repeat_paint = 0;
+
+ clear_link_areas ();
+ if (selected_item < paint_start)
+ selected_item = NULL;
+
+ for (p = paint_start; *p != CHAR_NODE_END && line < help_lines; p++){
+ c = *p;
+ switch (c){
+ case CHAR_LINK_START:
+ if (selected_item == NULL)
+ selected_item = p;
+ if (p == selected_item){
+ attrset (HELP_SLINK_COLOR);
+
+ /* Store the coordinates of the link */
+ active_col = col + 2;
+ active_line = line + 2;
+ }
+ else
+ attrset (HELP_LINK_COLOR);
+ start_link_area (col, line, p);
+ break;
+ case CHAR_LINK_POINTER:
+ painting = 0;
+ end_link_area (col - 1, line);
+ break;
+ case CHAR_LINK_END:
+ painting = 1;
+ attrset (HELP_NORMAL_COLOR);
+ break;
+ case CHAR_ALTERNATE:
+ acs = 1;
+ break;
+ case CHAR_NORMAL:
+ acs = 0;
+ break;
+ case CHAR_VERSION:
+ dlg_move (h, line+2, col+2);
+ addstr (VERSION);
+ col += strlen (VERSION);
+ break;
+ case CHAR_BOLD_ON:
+ attrset (HELP_BOLD_COLOR);
+ break;
+ case CHAR_ITALIC_ON:
+ attrset (HELP_ITALIC_COLOR);
+ break;
+ case CHAR_BOLD_OFF:
+ attrset (HELP_NORMAL_COLOR);
+ break;
+ case '\n':
+ line++;
+ col = 0;
+ break;
+ case '\t':
+ col = (col/8 + 1) * 8;
+ break;
+ case CHAR_MCLOGO:
+ case CHAR_TEXTONLY_START:
+ case CHAR_TEXTONLY_END:
+ break;
+ case CHAR_XONLY_START:
+ while (*p && *p != CHAR_NODE_END && *p != CHAR_XONLY_END)
+ p++;
+ if (*p == CHAR_NODE_END || !*p)
+ p--;
+ break;
+ default:
+ if (!painting)
+ continue;
+ if (col > HELP_WINDOW_WIDTH-1)
+ continue;
+
+ dlg_move (h, line+2, col+2);
+ if (acs){
+ if (c == ' ' || c == '.')
+ addch (c);
+ else
+#ifndef OS2_NT
+#ifndef HAVE_SLANG
+ addch (acs_map [c]);
+#else
+ SLsmg_draw_object (h->y + line + 2, h->x + col + 2, c);
+#endif
+#else
+ addch (acs2pc (c));
+#endif /* OS2_NT */
+ } else
+ addch (c);
+ col++;
+ break;
+ }
+ }
+ last_shown = p;
+ end_of_node = line < help_lines;
+ attrset (HELP_NORMAL_COLOR);
+ if (selected_item >= last_shown){
+ if (link_area != NULL){
+ selected_item = link_area->link_name;
+ repeat_paint = 1;
+ }
+ else
+ selected_item = NULL;
+ }
+ } while (repeat_paint);
+
+ /* Position the cursor over a nice link */
+ if (active_col)
+ dlg_move (h, active_line, active_col);
+}
+
+static int help_event (Gpm_Event *event, Widget *w)
+{
+ Link_Area *current_area;
+
+ if (! (event->type & GPM_UP))
+ return 0;
+
+ /* The event is relative to the dialog window, adjust it: */
+ event->y -= 2;
+
+ if (event->buttons & GPM_B_RIGHT){
+ currentpoint = startpoint = history [history_ptr].page;
+ selected_item = history [history_ptr].link;
+ history_ptr--;
+ if (history_ptr < 0)
+ history_ptr = HISTORY_SIZE-1;
+
+ help_callback (w->parent, 0, DLG_DRAW);
+ return 0;
+ }
+
+ /* Test whether the mouse click is inside one of the link areas */
+ current_area = link_area;
+ while (current_area)
+ {
+ /* Test one line link area */
+ if (event->y == current_area->y1 && event->x >= current_area->x1 &&
+ event->y == current_area->y2 && event->x <= current_area->x2)
+ break;
+ /* Test two line link area */
+ if (current_area->y1 + 1 == current_area->y2){
+ /* The first line */
+ if (event->y == current_area->y1 && event->x >= current_area->x1)
+ break;
+ /* The second line */
+ if (event->y == current_area->y2 && event->x <= current_area->x2)
+ break;
+ }
+ /* Mouse will not work with link areas of more than two lines */
+
+ current_area = current_area -> next;
+ }
+
+ /* Test whether a link area was found */
+ if (current_area){
+ /* The click was inside a link area -> follow the link */
+ history_ptr = (history_ptr+1) % HISTORY_SIZE;
+ history [history_ptr].page = currentpoint;
+ history [history_ptr].link = current_area->link_name;
+ currentpoint = startpoint = help_follow_link (currentpoint, current_area->link_name);
+ selected_item = NULL;
+ } else{
+ if (event->y < 0)
+ move_backward (help_lines - 1);
+ else if (event->y >= help_lines)
+ move_forward (help_lines - 1);
+ else if (event->y < help_lines/2)
+ move_backward (1);
+ else
+ move_forward (1);
+ }
+
+ /* Show the new node */
+ help_callback (w->parent, 0, DLG_DRAW);
+
+ return 0;
+}
+
+/* show help */
+void help_help_cmd (Dlg_head *h)
+{
+ history_ptr = (history_ptr+1) % HISTORY_SIZE;
+ history [history_ptr].page = currentpoint;
+ history [history_ptr].link = selected_item;
+ currentpoint = startpoint = search_string (data, "[How to use help]") + 1;
+ selected_item = NULL;
+#ifndef HAVE_XVIEW
+ help_callback (h, 0, DLG_DRAW);
+#endif
+}
+
+void help_index_cmd (Dlg_head *h)
+{
+ char *new_item;
+
+ history_ptr = (history_ptr+1) % HISTORY_SIZE;
+ history [history_ptr].page = currentpoint;
+ history [history_ptr].link = selected_item;
+ currentpoint = startpoint = search_string (data, "[Help]") + 1;
+
+ if (!(new_item = search_string (data, "[Contents]")))
+ message (1, MSG_ERROR, _(" Can't find node [Contents] in help file "));
+ else
+ currentpoint = startpoint = new_item + 1;
+ selected_item = NULL;
+#ifndef HAVE_XVIEW
+ help_callback (h, 0, DLG_DRAW);
+#endif
+}
+
+static void quit_cmd (void *x)
+{
+ Dlg_head *h = (Dlg_head *) x;
+
+ dlg_stop (x);
+}
+
+static void prev_node_cmd (Dlg_head *h)
+{
+ currentpoint = startpoint = history [history_ptr].page;
+ selected_item = history [history_ptr].link;
+ history_ptr--;
+ if (history_ptr < 0)
+ history_ptr = HISTORY_SIZE-1;
+
+#ifndef HAVE_XVIEW
+ help_callback (h, 0, DLG_DRAW);
+#endif
+}
+
+static int md_callback (Dlg_head *h, Widget *w, int msg, int par)
+{
+ return default_proc (h, msg, par);
+}
+
+static Widget *mousedispatch_new (int y, int x, int yl, int xl)
+{
+ Widget *w = xmalloc (sizeof (Widget), "disp_new");
+
+ init_widget (w, y, x, yl, xl,
+ (callback_fn) md_callback, 0, (mouse_h) help_event, NULL);
+
+ return w;
+}
+
+static int help_handle_key (struct Dlg_head *h, int c)
+{
+ char *new_item;
+
+ if (c != KEY_UP && c != KEY_DOWN &&
+ check_movement_keys (c, 1, help_lines, currentpoint,
+ (movefn) move_backward2,
+ (movefn) move_forward2,
+ (movefn) move_to_top,
+ (movefn) move_to_bottom))
+ /* Nothing */;
+ else switch (c){
+ case 'l':
+ case KEY_LEFT:
+ prev_node_cmd (h);
+ break;
+
+ case '\n':
+ case KEY_RIGHT:
+ /* follow link */
+ if (!selected_item){
+#ifdef WE_WANT_TO_GO_BACKWARD_ON_KEY_RIGHT
+ /* Is there any reason why the right key would take us
+ * backward if there are no links selected?, I agree
+ * with Torben than doing nothing in this case is better
+ */
+ /* If there are no links, go backward in history */
+ history_ptr--;
+ if (history_ptr < 0)
+ history_ptr = HISTORY_SIZE-1;
+
+ currentpoint = startpoint = history [history_ptr].page;
+ selected_item = history [history_ptr].link;
+#endif
+ } else {
+ history_ptr = (history_ptr+1) % HISTORY_SIZE;
+ history [history_ptr].page = currentpoint;
+ history [history_ptr].link = selected_item;
+ currentpoint = startpoint = help_follow_link (currentpoint, selected_item) + 1;
+ }
+ selected_item = NULL;
+ break;
+
+ case KEY_DOWN:
+ case '\t':
+ /* select next link */
+ new_item = select_next_link (startpoint, selected_item);
+ if (new_item){
+ selected_item = new_item;
+ if (selected_item >= last_shown){
+ if (c == KEY_DOWN)
+ move_forward (1);
+ else
+ selected_item = NULL;
+ }
+ } else if (c == KEY_DOWN)
+ move_forward (1);
+ else
+ selected_item = NULL;
+ break;
+
+ case KEY_UP:
+ case ALT ('\t'):
+ /* select previous link */
+ new_item = select_prev_link (startpoint, selected_item);
+ selected_item = new_item;
+ if (selected_item < currentpoint || selected_item >= last_shown){
+ if (c == KEY_UP)
+ move_backward (1);
+ else{
+ if (link_area != NULL)
+ selected_item = link_area->link_name;
+ else
+ selected_item = NULL;
+ }
+ }
+ break;
+
+ case 'n':
+ /* Next node */
+ new_item = currentpoint;
+ while (*new_item && *new_item != CHAR_NODE_END)
+ new_item++;
+ if (*++new_item == '['){
+ while (*new_item != ']')
+ new_item++;
+ currentpoint = new_item + 2;
+ selected_item = NULL;
+ }
+ break;
+
+ case 'p':
+ /* Previous node */
+ new_item = currentpoint;
+ while (new_item > data + 1 && *new_item != CHAR_NODE_END)
+ new_item--;
+ new_item--;
+ while (new_item > data && *new_item != CHAR_NODE_END)
+ new_item--;
+ while (*new_item != ']')
+ new_item++;
+ currentpoint = new_item + 2;
+ selected_item = NULL;
+ break;
+
+ case 'c':
+ help_index_cmd (h);
+ break;
+
+ case ESC_CHAR:
+ case XCTRL('g'):
+ dlg_stop (h);
+ break;
+
+ default:
+ return 0;
+
+ }
+ help_callback (h, 0, DLG_DRAW);
+ return 1;
+}
+
+static int help_callback (struct Dlg_head *h, int id, int msg)
+{
+ switch (msg){
+ case DLG_DRAW:
+ attrset (HELP_NORMAL_COLOR);
+ dlg_erase (h);
+ draw_box (h, 1, 1, help_lines+2, HELP_WINDOW_WIDTH+2);
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 1, (HELP_WINDOW_WIDTH - 1) / 2);
+ addstr (_(" Help "));
+ attrset (HELP_NORMAL_COLOR);
+ show (h, currentpoint);
+ break;
+
+ case DLG_KEY:
+ return help_handle_key (h, id);
+ }
+ return 0;
+}
+
+void interactive_display_finish (void)
+{
+ clear_link_areas ();
+ free (data);
+}
+
+void interactive_display (char *filename, char *node)
+{
+ WButtonBar *help_bar;
+ Widget *md;
+
+ if ((data = load_file (filename)) == 0){
+ message (1, MSG_ERROR, _(" Can't open file %s \n %s "),
+ filename, unix_error_string (errno));
+ return;
+ }
+ if (!(main = search_string (data, node))){
+ message (1, MSG_ERROR, _(" Can't find node %s in help file "), node);
+ interactive_display_finish ();
+ return;
+ }
+
+#ifndef HAVE_X
+ if (help_lines > LINES - 4)
+ help_lines = LINES - 4;
+
+ whelp = create_dlg (0, 0, help_lines+4, HELP_WINDOW_WIDTH+4, dialog_colors,
+ help_callback, "[Help]", "help", DLG_TRYUP|DLG_CENTER);
+
+ /* allow us to process the tab key */
+ whelp->raw = 1;
+
+#endif
+ selected_item = search_string_node (main, STRING_LINK_START) - 1;
+ currentpoint = startpoint = main + 1;
+
+ for (history_ptr = HISTORY_SIZE; history_ptr;){
+ history_ptr--;
+ history [history_ptr].page = currentpoint;
+ history [history_ptr].link = selected_item;
+ }
+
+#ifndef HAVE_X
+ help_bar = buttonbar_new (keybar_visible);
+ help_bar->widget.y -= whelp->y;
+ help_bar->widget.x -= whelp->x;
+
+ md = mousedispatch_new (1, 1, help_lines, HELP_WINDOW_WIDTH-2);
+
+ add_widget (whelp, help_bar);
+ add_widget (whelp, md);
+
+ define_label_data (whelp, (Widget *)NULL, 1, _("Help"),
+ (buttonbarfn) help_help_cmd, whelp);
+ define_label_data (whelp, (Widget *)NULL, 2, _("Index"),
+ (buttonbarfn) help_index_cmd,whelp);
+ define_label_data (whelp, (Widget *)NULL, 3, _("Prev"),
+ (buttonbarfn) prev_node_cmd, whelp);
+ define_label (whelp, (Widget *) NULL, 4, "", 0);
+ define_label (whelp, (Widget *) NULL, 5, "", 0);
+ define_label (whelp, (Widget *) NULL, 6, "", 0);
+ define_label (whelp, (Widget *) NULL, 7, "", 0);
+ define_label (whelp, (Widget *) NULL, 8, "", 0);
+ define_label (whelp, (Widget *) NULL, 9, "", 0);
+ define_label_data (whelp, (Widget *) NULL, 10, _("Quit"), quit_cmd, whelp);
+
+ run_dlg (whelp);
+ interactive_display_finish ();
+ destroy_dlg (whelp);
+#else
+ x_interactive_display ();
+#endif
+}
+
--- /dev/null
+#ifndef __HELP_H
+#define __HELP_H
+
+/* This file is included by help.c and man2hlp.c */
+
+/* Some useful constants */
+#define CHAR_NODE_END '\04'
+#define CHAR_LINK_START '\01'
+#define CHAR_LINK_POINTER '\02'
+#define CHAR_LINK_END '\03'
+#define CHAR_ALTERNATE '\05'
+#define CHAR_NORMAL '\06'
+#define CHAR_VERSION '\07'
+#define CHAR_BOLD_ON '\010'
+#define CHAR_BOLD_OFF '\013'
+#define CHAR_MCLOGO '\014'
+#define CHAR_TEXTONLY_START '\016'
+#define CHAR_TEXTONLY_END '\017'
+#define CHAR_XONLY_START '\020'
+#define CHAR_XONLY_END '\021'
+#define CHAR_TITLE_ON '\022'
+#define CHAR_TITLE_OFF '\023'
+#define CHAR_ITALIC_ON '\024'
+#define CHAR_RESERVED '\025'
+#define STRING_LINK_START "\01"
+#define STRING_LINK_POINTER "\02"
+#define STRING_LINK_END "\03"
+#define STRING_NODE_END "\04"
+
+void interactive_display (char *filename, char *node);
+char *help_follow_link (char *start, char *selected_item);
+#endif /* __HELP_H */
--- /dev/null
+/* Directory hotlist -- for the Midnight Commander
+ Copyright (C) 1994, 1995, 1996, 1997 the Free Software Foundation.
+
+ Written by:
+ 1994 Radek Doulik
+ 1995 Janne Kukonlehto
+ 1996 Andrej Borsenkow
+ 1997 Norbert Warmuth
+
+ Janne did the original Hotlist code, Andrej made the groupable
+ hotlist; the move hotlist and revamped the file format and made
+ it stronger.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> /* For malloc() */
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef SCO_FLAVOR
+# include <sys/timeb.h> /* alex: for struct timeb, used in time.h */
+#endif /* SCO_FLAVOR */
+#include <time.h>
+#ifndef OS2_NT
+# include <grp.h>
+# include <pwd.h>
+#else
+# include <io.h>
+#endif
+#include "tty.h"
+#include "mad.h"
+#include "util.h" /* Needed for the externs */
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+#include "setup.h" /* For profile_bname */
+#include "profile.h" /* Load/save directories hotlist */
+
+#include "../vfs/vfs.h"
+/* Needed for the extern declarations of integer parameters */
+#include "wtools.h"
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "main.h"
+#include "global.h"
+#include "hotlist.h"
+#include "key.h"
+#include "command.h"
+
+#ifdef HAVE_TK
+# include "tkwidget.h"
+#endif
+
+#define UX 5
+#define UY 2
+
+#define BX UX
+#define BY LINES-6
+
+#define BUTTONS (sizeof(hotlist_but)/sizeof(struct _hotlist_but))
+#define LABELS 3
+#define B_ADD_CURRENT B_USER
+#define B_REMOVE (B_USER + 1)
+#define B_NEW_GROUP (B_USER + 2)
+#define B_NEW_ENTRY (B_USER + 3)
+#define B_UP_GROUP (B_USER + 4)
+#define B_INSERT (B_USER + 5)
+#define B_APPEND (B_USER + 6)
+#define B_MOVE (B_USER + 7)
+
+static WListbox *l_hotlist;
+static WListbox *l_movelist;
+
+static Dlg_head *hotlist_dlg;
+static Dlg_head *movelist_dlg;
+
+static WLabel *pname, *pname_group, *movelist_group;
+
+enum HotListType {
+ HL_TYPE_GROUP,
+ HL_TYPE_ENTRY,
+ HL_TYPE_COMMENT
+};
+
+static struct {
+ /*
+ * these parameters are intended to be user configurable
+ */
+ int expanded; /* expanded view of all groups at startup */
+
+ /*
+ * these reflect run time state
+ */
+
+ int loaded; /* hotlist is loaded */
+ int readonly; /* hotlist readonly */
+ int file_error; /* parse error while reading file */
+ int running; /* we are running dlg (and have to
+ update listbox */
+ int moving; /* we are in moving hotlist currently */
+ int modified; /* hotlist was modified */
+ int type; /* LIST_HOTLIST || LIST_VFSLIST */
+} hotlist_state;
+
+struct _hotlist_but {
+ int ret_cmd, flags, y, x;
+ char *text;
+ char *tkname;
+ int type;
+} hotlist_but[] = {
+ { B_MOVE, NORMAL_BUTTON, 1, 42, N_("&Move"), "move", LIST_HOTLIST},
+ { B_REMOVE, NORMAL_BUTTON, 1, 30, N_("&Remove"), "r", LIST_HOTLIST},
+ { B_APPEND, NORMAL_BUTTON, 1, 15, N_("&Append"), "e", LIST_MOVELIST},
+ { B_INSERT, NORMAL_BUTTON, 1, 0, N_("&Insert"), "g", LIST_MOVELIST},
+ { B_NEW_ENTRY, NORMAL_BUTTON, 1, 15, N_("New &Entry"), "e", LIST_HOTLIST},
+ { B_NEW_GROUP, NORMAL_BUTTON, 1, 0, N_("New &Group"), "g", LIST_HOTLIST},
+ { B_CANCEL, NORMAL_BUTTON, 0, 53, N_("&Cancel"), "cc", LIST_HOTLIST|LIST_VFSLIST|LIST_MOVELIST},
+ { B_UP_GROUP, NORMAL_BUTTON, 0, 42, N_("&Up"), "up", LIST_HOTLIST|LIST_MOVELIST},
+ { B_ADD_CURRENT, NORMAL_BUTTON, 0, 20, N_("&Add current"),"ad", LIST_HOTLIST},
+ { B_ENTER, DEFPUSH_BUTTON, 0, 0, N_("Change &To"), "ct", LIST_HOTLIST|LIST_VFSLIST|LIST_MOVELIST},
+};
+
+/* Directory hotlist */
+static struct hotlist{
+ enum HotListType type;
+ char *directory;
+ char *label;
+ struct hotlist *head;
+ struct hotlist *up;
+ struct hotlist *next;
+} *hotlist = NULL;
+
+struct hotlist *current_group;
+
+static void remove_from_hotlist (struct hotlist *entry);
+void add_new_group_cmd (void);
+
+static struct hotlist *new_hotlist (void)
+{
+ struct hotlist *hl;
+
+ hl = xmalloc (sizeof (struct hotlist), "new-hotlist");
+ hl->type = 0;
+ hl->directory =
+ hl->label = 0;
+ hl->head =
+ hl->up =
+ hl->next = 0;
+
+ return hl;
+}
+
+#ifndef HAVE_X
+static void hotlist_refresh (Dlg_head *dlg)
+{
+ dialog_repaint (dlg, COLOR_NORMAL, COLOR_HOT_NORMAL);
+ attrset (COLOR_NORMAL);
+ draw_box (dlg, 2, 5,
+ dlg->lines - (hotlist_state.moving ? 6 : 10),
+ dlg->cols - (UX*2));
+ if (!hotlist_state.moving)
+ draw_box (dlg, dlg->lines-8, 5, 3, dlg->cols - (UX*2));
+}
+#endif
+
+/* If current->data is 0, then we are dealing with a VFS pathname */
+static INLINE void update_path_name ()
+{
+ char *text, *p;
+ WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
+ Dlg_head *dlg = hotlist_state.moving ? movelist_dlg : hotlist_dlg;
+
+ if (list->current){
+ if (list->current->data != 0) {
+ struct hotlist *hlp = (struct hotlist *)list->current->data;
+
+ if (hlp->type == HL_TYPE_ENTRY)
+ text = hlp->directory;
+ else
+ text = _("Subgroup - press ENTER to see list");
+
+#ifndef HAVE_X
+ p = copy_strings (" ", current_group->label, " ", (char *)0);
+ if (!hotlist_state.moving)
+ label_set_text (pname_group, name_trunc (p, dlg->cols - (UX*2+4)));
+ else
+ label_set_text (movelist_group, name_trunc (p, dlg->cols - (UX*2+4)));
+ free (p);
+#endif
+ } else {
+ text = list->current->text;
+ }
+ } else {
+ text = "";
+ }
+ if (!hotlist_state.moving)
+ label_set_text (pname, name_trunc (text, dlg->cols - (UX*2+4)));
+ dlg_redraw (dlg);
+}
+
+#define CHECK_BUFFER \
+do { \
+ int i; \
+\
+ if ((i = strlen (current->label) + 3) > buflen) { \
+ free (buf); \
+ buf = xmalloc (buflen = 1024 * (i/1024 + 1), "fill_listbox"); \
+ } \
+ buf[0] = '\0'; \
+} while (0)
+
+static void fill_listbox (void)
+{
+ struct hotlist *current = current_group->head;
+ static char *buf;
+ static int buflen;
+
+ if (!buf)
+ buf = xmalloc (buflen = 1024, "fill_listbox");
+ buf[0] = '\0';
+
+ while (current){
+ switch (current->type) {
+ case HL_TYPE_GROUP:
+ {
+ CHECK_BUFFER;
+ strcat (strcat (buf, "->"), current->label);
+ if (hotlist_state.moving)
+ listbox_add_item (l_movelist, 0, 0, buf, current);
+ else
+ listbox_add_item (l_hotlist, 0, 0, buf, current);
+ }
+ break;
+ case HL_TYPE_ENTRY:
+ if (hotlist_state.moving)
+ listbox_add_item (l_movelist, 0, 0, current->label, current);
+ else
+ listbox_add_item (l_hotlist, 0, 0, current->label, current);
+ break;
+ }
+ current = current->next;
+ }
+}
+
+#undef CHECK_BUFFER
+
+static void
+unlink_entry (struct hotlist *entry)
+{
+ struct hotlist *current = current_group->head;
+
+ if (current == entry)
+ current_group->head = entry->next;
+ else
+ while (current && current->next != entry)
+ current = current->next;
+ if (current)
+ current->next = entry->next;
+ entry->next =
+ entry->up = 0;
+}
+
+static void add_new_entry_cmd (void);
+static void init_movelist (int, struct hotlist *);
+
+static int hotlist_button_callback (int action, void *data)
+{
+ switch (action) {
+ case B_MOVE:
+ {
+ struct hotlist *saved = current_group;
+ struct hotlist *item;
+ struct hotlist *moveto_item = 0;
+ struct hotlist *moveto_group = 0;
+ int ret;
+
+ if (!l_hotlist->current)
+ return 0; /* empty group - nothing to do */
+ item = l_hotlist->current->data;
+ hotlist_state.moving = 1;
+ init_movelist (LIST_MOVELIST, item);
+ run_dlg (movelist_dlg);
+ ret = movelist_dlg->ret_value;
+ hotlist_state.moving = 0;
+ if (l_movelist->current)
+ moveto_item = l_movelist->current->data;
+ moveto_group = current_group;
+ destroy_dlg (movelist_dlg);
+ current_group = saved;
+ if (ret == B_CANCEL)
+ return 0;
+ if (moveto_item == item)
+ return 0; /* If we insert/append a before/after a
+ it hardly changes anything ;) */
+ unlink_entry (item);
+ listbox_remove_current (l_hotlist, 1);
+ item->up = moveto_group;
+ if (!moveto_group->head)
+ moveto_group->head = item;
+ else if (!moveto_item) { /* we have group with just comments */
+ struct hotlist *p = moveto_group->head;
+
+ /* skip comments */
+ while (p->next)
+ p = p->next;
+ p->next = item;
+ } else if (ret == B_ENTER || ret == B_APPEND)
+ if (!moveto_item->next)
+ moveto_item->next = item;
+ else {
+ item->next = moveto_item->next;
+ moveto_item->next = item;
+ }
+ else if (moveto_group->head == moveto_item) {
+ moveto_group->head = item;
+ item->next = moveto_item;
+ } else {
+ struct hotlist *p = moveto_group->head;
+
+ while (p->next != moveto_item)
+ p = p->next;
+ item->next = p->next;
+ p->next = item;
+ }
+ listbox_remove_list (l_hotlist);
+ fill_listbox ();
+#ifdef HAVE_X
+ x_listbox_select_nth (l_hotlist, 0);
+#endif
+ repaint_screen ();
+ hotlist_state.modified = 1;
+ return 0;
+ break;
+ }
+ case B_REMOVE:
+ if (l_hotlist->current)
+ remove_from_hotlist (l_hotlist->current->data);
+ return 0;
+ break;
+
+ case B_NEW_GROUP:
+ add_new_group_cmd ();
+ return 0;
+ break;
+
+ case B_ADD_CURRENT:
+ add2hotlist_cmd ();
+ return 0;
+ break;
+
+ case B_NEW_ENTRY:
+ add_new_entry_cmd ();
+ return 0;
+ break;
+
+ case B_ENTER:
+ {
+ WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
+ if (list->current){
+ if (list->current->data) {
+ struct hotlist *hlp = (struct hotlist*) list->current->data;
+ if (hlp->type == HL_TYPE_ENTRY)
+ return 1;
+ else {
+ listbox_remove_list (list);
+ current_group = hlp;
+ fill_listbox ();
+ return 0;
+ }
+ } else
+ return 1;
+ }
+ }
+ /* Fall through if list empty - just go up */
+
+ case B_UP_GROUP:
+ {
+ WListbox *list = hotlist_state.moving ? l_movelist : l_hotlist;
+ listbox_remove_list (list);
+ current_group = current_group->up;
+ fill_listbox ();
+#ifdef HAVE_X
+ x_listbox_select_nth (list, 0);
+#endif
+ return 0;
+ break;
+ }
+
+ default:
+ return 1;
+ break;
+
+ }
+}
+
+static int hotlist_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+#ifndef HAVE_X
+ case DLG_DRAW:
+ hotlist_refresh (h);
+ break;
+#endif
+
+ case DLG_UNHANDLED_KEY:
+ switch (Par) {
+ case '\n':
+ if (ctrl_pressed())
+ goto l1;
+ case KEY_ENTER:
+ case KEY_RIGHT:
+ if (hotlist_button_callback (B_ENTER, 0)) {
+ h->ret_value = B_ENTER;
+ dlg_stop (h);
+ };
+ return 1;
+ break;
+ case KEY_LEFT:
+ if (hotlist_state.type != LIST_VFSLIST )
+ return !hotlist_button_callback (B_UP_GROUP, 0);
+ else
+ return 0;
+ break;
+l1:
+ case ALT('\n'):
+ case ALT('\r'):
+ if (!hotlist_state.moving)
+ {
+ if (l_hotlist->current){
+ if (l_hotlist->current->data) {
+ struct hotlist *hlp = (struct hotlist*) l_hotlist->current->data;
+ if (hlp->type == HL_TYPE_ENTRY) {
+ char *tmp = copy_strings( "cd ", hlp->directory, NULL);
+ stuff (input_w (cmdline), tmp, 0);
+ free (tmp);
+ dlg_stop (h);
+ h->ret_value = B_CANCEL;
+ return 1;
+ }
+ }
+ }
+ }
+ return 1; /* ignore key */
+ default:
+ return 0;
+ }
+ break;
+
+ case DLG_POST_KEY:
+ if (hotlist_state.moving)
+ dlg_select_widget (movelist_dlg, l_movelist);
+ else
+ dlg_select_widget (hotlist_dlg, l_hotlist);
+ /* always stay on hotlist */
+ /* fall through */
+
+ case DLG_INIT:
+ attrset (MENU_ENTRY_COLOR);
+ update_path_name ();
+ break;
+ }
+ return 0;
+}
+
+static int l_call (void *l)
+{
+ WListbox *list = (WListbox *) l;
+ Dlg_head *dlg = hotlist_state.moving ? movelist_dlg : hotlist_dlg;
+
+ if (list->current){
+ if (list->current->data) {
+ struct hotlist *hlp = (struct hotlist*) list->current->data;
+ if (hlp->type == HL_TYPE_ENTRY) {
+ dlg->ret_value = B_ENTER;
+ dlg_stop (dlg);
+ return listbox_finish;
+ } else {
+ hotlist_button_callback (B_ENTER, (void *)0);
+ hotlist_callback (dlg, '\n', DLG_POST_KEY);
+ return listbox_nothing;
+ }
+ } else {
+ dlg->ret_value = B_ENTER;
+ dlg_stop (dlg);
+ return listbox_finish;
+ }
+ }
+
+ hotlist_button_callback (B_UP_GROUP, (void *)0);
+ hotlist_callback (dlg, 'u', DLG_POST_KEY);
+ return listbox_nothing;
+}
+
+static void add_name_to_list (char *path)
+{
+ listbox_add_item (l_hotlist, 0, 0, path, 0);
+}
+
+/*
+ * Expands all button names (once) and recalculates button positions.
+ * returns number of columns in the dialog box, which is 10 chars longer
+ * then buttonbar.
+ *
+ * If common width of the window (i.e. in xterm) is less than returned
+ * width - sorry :) (anyway this did not handled in previous version too)
+ */
+static int
+init_i18n_stuff(int list_type, int cols)
+{
+ register int i;
+ static char* cancel_but = "&Cancel";
+
+#ifdef ENABLE_NLS
+ static int hotlist_i18n_flag = 0;
+
+ if (!hotlist_i18n_flag)
+ {
+ i = sizeof (hotlist_but) / sizeof (hotlist_but [0]);
+ while (i--)
+ hotlist_but [i].text = _(hotlist_but [i].text);
+
+ cancel_but = _(cancel_but);
+ hotlist_i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ /* Dynamic resizing of buttonbars */
+ {
+ int len[2], count[2]; /* at most two lines of buttons */
+ int cur_x[2], row;
+
+ i = sizeof (hotlist_but) / sizeof (hotlist_but [0]);
+ len[0] = len[1] = count[0] = count[1] = 0;
+
+ /* Count len of buttonbars, assuming 2 extra space between buttons */
+ while (i--)
+ {
+ if (! (hotlist_but[i].type & list_type))
+ continue;
+
+ row = hotlist_but [i].y;
+ ++count [row];
+ len [row] += strlen (hotlist_but [i].text) + 5;
+ if (hotlist_but [i].flags == DEFPUSH_BUTTON)
+ len [row] += 2;
+ }
+ len[0] -= 2;
+ len[1] -= 2;
+
+ cols = max(cols, max(len[0], len[1]));
+
+ /* arrange buttons */
+
+ cur_x[0] = cur_x[1] = 0;
+ i = sizeof (hotlist_but) / sizeof (hotlist_but [0]);
+ while (i--)
+ {
+ if (! (hotlist_but[i].type & list_type))
+ continue;
+
+ row = hotlist_but [i].y;
+
+ if (hotlist_but [i].x != 0)
+ {
+ /* not first int the row */
+ if (!strcmp (hotlist_but [i].text, cancel_but))
+ hotlist_but [i].x =
+ cols - strlen (hotlist_but [i].text) - 13;
+ else
+ hotlist_but [i].x = cur_x [row];
+ }
+
+ cur_x [row] += strlen (hotlist_but [i].text) + 2
+ + (hotlist_but [i].flags == DEFPUSH_BUTTON ? 5 : 3);
+ }
+ }
+
+ return cols;
+}
+
+static void init_hotlist (int list_type)
+{
+ int i;
+ int hotlist_cols = init_i18n_stuff (list_type, COLS - 6);
+
+ do_refresh ();
+
+ hotlist_state.expanded = GetPrivateProfileInt ("HotlistConfig",
+ "expanded_view_of_groups", 0, profile_name);
+
+ hotlist_dlg = create_dlg (0, 0, LINES-2, hotlist_cols, dialog_colors,
+ hotlist_callback,
+ list_type == LIST_VFSLIST ? "[vfshot]" : "[Hotlist]",
+ list_type == LIST_VFSLIST ? "vfshot" : "hotlist",
+ DLG_CENTER|DLG_GRID);
+ x_set_dialog_title (hotlist_dlg,
+ list_type == LIST_VFSLIST ? _("Active VFS directories") : _("Directory hotlist"));
+
+#define XTRACT(i) BY+hotlist_but[i].y, BX+hotlist_but[i].x, hotlist_but[i].ret_cmd, hotlist_but[i].flags, hotlist_but[i].text, hotlist_button_callback, 0, hotlist_but[i].tkname
+
+ for (i = 0; i < BUTTONS; i++){
+ if (hotlist_but[i].type & list_type)
+ add_widgetl (hotlist_dlg, button_new (XTRACT (i)), (i == BUTTONS - 1) ?
+ XV_WLAY_CENTERROW : XV_WLAY_RIGHTOF);
+ }
+#undef XTRACT
+
+ /* We add the labels.
+ * pname will hold entry's pathname;
+ * pname_group will hold name of current group
+ */
+ pname = label_new (UY-11+LINES, UX+2, "", "the-lab");
+ add_widget (hotlist_dlg, pname);
+#ifndef HAVE_X
+ if (!hotlist_state.moving) {
+ add_widget (hotlist_dlg, label_new (UY-12+LINES, UX+1, _(" Directory path "), NULL));
+
+ /* This one holds the displayed pathname */
+ pname_group = label_new (UY, UX+1, _(" Directory label "), NULL);
+ add_widget (hotlist_dlg, pname_group);
+ }
+#endif
+ /* get new listbox */
+ l_hotlist = listbox_new (UY + 1, UX + 1, COLS-2*UX-8, LINES-14, listbox_cback, l_call, "listbox");
+
+ /* Fill the hotlist with the active VFS or the hotlist */
+ if (list_type == LIST_VFSLIST){
+ listbox_add_item (l_hotlist, 0, 0, home_dir, 0);
+ vfs_fill_names (add_name_to_list);
+ } else
+ fill_listbox ();
+
+ add_widgetl (hotlist_dlg, l_hotlist, XV_WLAY_EXTENDWIDTH);
+ /* add listbox to the dialogs */
+}
+
+static void init_movelist (int list_type, struct hotlist *item)
+{
+ int i;
+ char *hdr = copy_strings (_("Moving "), item->label, 0);
+ int movelist_cols = init_i18n_stuff (list_type, COLS - 6);
+
+ do_refresh ();
+
+ movelist_dlg = create_dlg (0, 0, LINES-6, movelist_cols, dialog_colors,
+ hotlist_callback, "[Hotlist]",
+ "movelist",
+ DLG_CENTER|DLG_GRID);
+ x_set_dialog_title (movelist_dlg, hdr);
+ free (hdr);
+
+#define XTRACT(i) BY-4+hotlist_but[i].y, BX+hotlist_but[i].x, hotlist_but[i].ret_cmd, hotlist_but[i].flags, hotlist_but[i].text, hotlist_button_callback, 0, hotlist_but[i].tkname
+
+ for (i = 0; i < BUTTONS; i++){
+ if (hotlist_but[i].type & list_type)
+ add_widgetl (movelist_dlg, button_new (XTRACT (i)), (i == BUTTONS - 1) ?
+ XV_WLAY_CENTERROW : XV_WLAY_RIGHTOF);
+ }
+
+#undef XTRACT
+
+ /* We add the labels. We are interested in the last one,
+ * that one will hold the path name label
+ */
+#ifndef HAVE_X
+ movelist_group = label_new (UY, UX+1, _(" Directory label "), NULL);
+ add_widget (movelist_dlg, movelist_group);
+#endif
+ /* get new listbox */
+ l_movelist = listbox_new (UY + 1, UX + 1,
+ movelist_dlg->cols - 2*UX - 2, movelist_dlg->lines - 8,
+ listbox_cback, l_call, "listbox");
+
+ fill_listbox ();
+
+ add_widgetl (movelist_dlg, l_movelist, XV_WLAY_EXTENDWIDTH);
+ /* add listbox to the dialogs */
+}
+
+static void hotlist_done (void)
+{
+ destroy_dlg (hotlist_dlg);
+ if (0)
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+static char *
+find_group_section (struct hotlist *grp)
+{
+ return copy_strings (grp->directory, ".Group", (char *)0);
+
+}
+
+
+/* 1.11.96 bor: added pos parameter to control placement of new item.
+ see widget.c, listbox_add_item()
+ now hotlist is in unsorted mode
+ */
+static struct hotlist *
+add2hotlist (char *label, char *directory, enum HotListType type, int pos)
+{
+ struct hotlist *current;
+ struct hotlist *new;
+
+ if (l_hotlist && l_hotlist->current)
+ current = l_hotlist->current->data;
+
+ new = new_hotlist ();
+
+ new->type = type;
+ new->label = label;
+ new->directory = directory;
+ new->up = current_group;
+
+ if (!current_group->head) { /* first element in group */
+ current_group->head = new;
+ } else if (pos == 2) { /* should be appended after current*/
+ new->next = current->next;
+ current->next = new;
+ } else if (pos == 1 &&
+ current == current_group->head) {
+ /* should be inserted before first item */
+ new->next = current;
+ current_group->head = new;
+ } else if (pos == 1) { /* befor current */
+ struct hotlist *p = current_group->head;
+
+ while (p->next != current)
+ p = p->next;
+
+ new->next = current;
+ p->next = new;
+ } else { /* append at the end */
+ struct hotlist *p = current_group->head;
+
+ while (p->next)
+ p = p->next;
+
+ p->next = new;
+ }
+
+ if (hotlist_state.running && type != HL_TYPE_COMMENT) {
+ if (type == HL_TYPE_GROUP) {
+ char *lbl = copy_strings ("->", new->label, (char *)0);
+
+ listbox_add_item (l_hotlist, pos, 0, lbl, new);
+ free (lbl);
+ } else
+ listbox_add_item (l_hotlist, pos, 0, new->label, new);
+ listbox_select_entry (l_hotlist, l_hotlist->current);
+ }
+ return new;
+
+}
+
+/*
+ * Support routine for add_new_entry_input()/add_new_group_input()
+ * Change positions of buttons (first three widgets).
+ *
+ * This is just a quick hack. Accurate procedure must take care of
+ * internationalized label lengths and total buttonbar length...assume
+ * 64 is longer anyway.
+ */
+static void add_widgets_i18n(QuickWidget* qw, int len)
+{
+ int i, l[3], space, cur_x;
+
+ for (i = 0; i < 3; i++)
+ {
+ qw [i].text = _(qw [i].text);
+ l[i] = strlen (qw [i].text) + 3;
+ }
+ space = (len - 4 - l[0] - l[1] - l[2]) / 4;
+
+ for (cur_x = 2 + space, i = 3; i--; cur_x += l[i] + space)
+ {
+ qw [i].relative_x = cur_x;
+ qw [i].x_divisions = len;
+ }
+}
+
+static int add_new_entry_input (char *header, char *text1, char *text2, char *help, char **r1, char **r2)
+{
+ QuickDialog Quick_input;
+ QuickWidget quick_widgets [] = {
+ { quick_button, 55, 80, 4, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
+ XV_WLAY_DONTCARE, "button-cancel" },
+ { quick_button, 30, 80, 4, 0, N_("&Insert"), 0, B_INSERT, 0, 0,
+ XV_WLAY_DONTCARE, "button-insert" },
+ { quick_button, 10, 80, 4, 0, N_("&Append"), 0, B_APPEND, 0, 0,
+ XV_WLAY_DONTCARE, "button-append" },
+ { quick_input, 4, 80, 4, 0, "",58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-pth" },
+ { quick_label, 3, 80, 3, 0, 0, 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-pth" },
+ { quick_input, 4, 80, 3, 0, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-lbl" },
+ { quick_label, 3, 80, 2, 0, 0, 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-lbl" },
+ { 0 } };
+
+ int len;
+ int i;
+ int lines1, lines2;
+ char *my_str1, *my_str2;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+#endif /* ENABLE_NLS */
+
+ len = max (strlen (header), msglen (text1, &lines1));
+ len = max (len, msglen (text2, &lines2)) + 4;
+ len = max (len, 64);
+
+#ifdef ENABLE_NLS
+ if (!i18n_flag)
+ {
+ add_widgets_i18n(quick_widgets, len);
+ i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ Quick_input.xlen = len;
+ Quick_input.xpos = -1;
+ Quick_input.title = header;
+ Quick_input.help = help;
+ Quick_input.class = "hotlist_new_entry";
+ Quick_input.i18n = 0;
+ quick_widgets [6].text = text1;
+ quick_widgets [4].text = text2;
+ quick_widgets [5].text = *r1;
+ quick_widgets [3].text = *r2;
+
+ for (i = 0; i < 7; i++)
+ quick_widgets [i].y_divisions = lines1+lines2+7;
+ Quick_input.ylen = lines1 + lines2 + 7;
+
+ quick_widgets [0].relative_y += (lines1 + lines2);
+ quick_widgets [1].relative_y += (lines1 + lines2);
+ quick_widgets [2].relative_y += (lines1 + lines2);
+ quick_widgets [3].relative_y += (lines1);
+ quick_widgets [4].relative_y += (lines1);
+
+ quick_widgets [5].str_result = &my_str1;
+ quick_widgets [3].str_result = &my_str2;
+
+ Quick_input.widgets = quick_widgets;
+ if ((i = quick_dialog (&Quick_input)) != B_CANCEL){
+ *r1 = *(quick_widgets [5].str_result);
+ *r2 = *(quick_widgets [3].str_result);
+ return i;
+ } else
+ return 0;
+}
+
+static void add_new_entry_cmd (void)
+{
+ char *title = 0, *url = 0;
+ int ret;
+
+ /* Take current directory as default value for input fields */
+ title = url = cpanel->cwd;
+
+ ret = add_new_entry_input (_("New hotlist entry"), _("Directory label"), _("Directory path"),
+ "[Hotlist]", &title, &url);
+
+ if (!ret || !title || !*title || !url || !*url)
+ return;
+
+ if (ret == B_ENTER || ret == B_APPEND)
+ add2hotlist (strdup (title), strdup (url), HL_TYPE_ENTRY, 2);
+ else
+ add2hotlist (strdup (title), strdup (url), HL_TYPE_ENTRY, 1);
+
+ hotlist_state.modified = 1;
+}
+
+static int add_new_group_input (char *header, char *label, char **result)
+{
+ int ret;
+ QuickDialog Quick_input;
+ QuickWidget quick_widgets [] = {
+ { quick_button, 55, 80, 1, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
+ XV_WLAY_DONTCARE, "button-cancel" },
+ { quick_button, 30, 80, 1, 0, N_("&Insert"), 0, B_INSERT, 0, 0,
+ XV_WLAY_DONTCARE, "button-insert" },
+ { quick_button, 10, 80, 1, 0, N_("&Append"), 0, B_APPEND, 0, 0,
+ XV_WLAY_DONTCARE, "button-append" },
+ { quick_input, 4, 80, 0, 0, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input" },
+ { quick_label, 3, 80, 2, 0, 0, 0, 0, 0, 0, XV_WLAY_DONTCARE, "label" },
+ { 0 } };
+
+ int len;
+ int i;
+ int lines;
+ char *my_str;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+#endif /* ENABLE_NLS */
+
+ len = max (strlen (header), msglen (label, &lines)) + 4;
+ len = max (len, 64);
+
+#ifdef ENABLE_NLS
+ if (!i18n_flag)
+ {
+ add_widgets_i18n(quick_widgets, len);
+ i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ Quick_input.xlen = len;
+ Quick_input.xpos = -1;
+ Quick_input.title = header;
+ Quick_input.help = "[Hotlist]";
+ Quick_input.class = "hotlist_new_group";
+ Quick_input.i18n = 0;
+ quick_widgets [4].text = label;
+
+ for (i = 0; i < 5; i++)
+ quick_widgets [i].y_divisions = lines+6;
+ Quick_input.ylen = lines + 6;
+
+ for (i = 0; i < 4; i++)
+ quick_widgets [i].relative_y += 2 + lines;
+
+ quick_widgets [3].str_result = &my_str;
+ quick_widgets [3].text = "";
+
+ Quick_input.widgets = quick_widgets;
+ if ((ret = quick_dialog (&Quick_input)) != B_CANCEL){
+ *result = *(quick_widgets [3].str_result);
+ return ret;
+ } else
+ return 0;
+}
+
+void add_new_group_cmd (void)
+{
+ char *label;
+ int ret;
+
+ ret = add_new_group_input (_(" New hotlist group "), _("Name of new group"), &label);
+ if (!ret || !label || !*label)
+ return;
+
+ if (ret == B_ENTER || ret == B_APPEND)
+ add2hotlist (label, 0, HL_TYPE_GROUP, 2);
+ else
+ add2hotlist (label, 0, HL_TYPE_GROUP, 1);
+
+ hotlist_state.modified = 1;
+}
+
+void add2hotlist_cmd (void)
+{
+ char *prompt, *label;
+ char* cp = _("Label for \"%s\":");
+ int l = strlen(cp);
+
+ prompt = xmalloc (strlen (cpanel->cwd) + l, "add2hotlist_cmd");
+ sprintf (prompt, cp, name_trunc (cpanel->cwd, COLS-2*UX-(l+8)));
+ label = input_dialog (_(" Add to hotlist "), prompt, cpanel->cwd);
+ free (prompt);
+ if (!label || !*label)
+ return;
+
+ add2hotlist (label, strdup (cpanel->cwd), HL_TYPE_ENTRY, 0);
+ hotlist_state.modified = 1;
+}
+
+static void remove_group (struct hotlist *grp)
+{
+ struct hotlist *current = grp->head;
+
+ while (current) {
+ struct hotlist *next = current->next;
+
+ if (current->type == HL_TYPE_GROUP)
+ remove_group (current);
+
+ if (current->label)
+ free (current->label);
+ if (current->directory)
+ free (current->directory);
+ free (current);
+
+ current = next;
+ }
+
+}
+
+static void remove_from_hotlist (struct hotlist *entry)
+{
+ if (entry->type == HL_TYPE_GROUP) {
+ if (entry->head) {
+ char *header;
+ int result;
+
+ header = copy_strings (_(" Remove: "),
+ name_trunc (entry->label, 30),
+ " ",
+ 0);
+ result = query_dialog (header, _("\n Group not empty.\n Remove it?"),
+ D_ERROR, 2,
+ _("&No"), _("&Yes"));
+ free (header);
+
+ if (!result)
+ return;
+ }
+
+ remove_group (entry);
+ }
+
+ unlink_entry (entry);
+
+ if (entry->label)
+ free (entry->label);
+ if (entry->directory)
+ free (entry->directory);
+ free (entry);
+ /* now remove list entry from screen */
+ listbox_remove_current (l_hotlist, 1);
+ hotlist_state.modified = 1;
+}
+
+char *hotlist_cmd (int vfs_or_hotlist)
+{
+ char *target = NULL;
+
+ hotlist_state.type = vfs_or_hotlist;
+ load_hotlist ();
+
+ init_hotlist (vfs_or_hotlist);
+
+ /* display file info */
+ attrset (SELECTED_COLOR);
+
+ hotlist_state.running = 1;
+ run_dlg (hotlist_dlg);
+ hotlist_state.running = 0;
+ save_hotlist ();
+
+ switch (hotlist_dlg->ret_value) {
+ case B_CANCEL:
+ break;
+
+ case B_ENTER:
+ if (l_hotlist->current->data) {
+ struct hotlist *hlp = (struct hotlist*) l_hotlist->current->data;
+ target = strdup (hlp->directory);
+ } else
+ target = strdup (l_hotlist->current->text);
+ break;
+ }
+
+ hotlist_done ();
+ return target;
+}
+
+void load_group (struct hotlist *grp)
+{
+ void *profile_keys;
+ char *key, *value;
+ char *group_section;
+ struct hotlist *current = 0;
+
+ group_section = find_group_section (grp);
+
+ profile_keys = profile_init_iterator (group_section, profile_name);
+
+ current_group = grp;
+
+ while (profile_keys){
+ profile_keys = profile_iterator_next (profile_keys, &key, &value);
+ add2hotlist (strdup (value), strdup (key), HL_TYPE_GROUP, 0);
+ }
+ free (group_section);
+
+ profile_keys = profile_init_iterator (grp->directory, profile_name);
+
+ while (profile_keys){
+ profile_keys = profile_iterator_next (profile_keys, &key, &value);
+ add2hotlist (strdup (value), strdup (key), HL_TYPE_ENTRY, 0);
+ }
+
+ for (current = grp->head; current; current = current->next)
+ load_group (current);
+}
+
+#define TKN_GROUP 0
+#define TKN_ENTRY 1
+#define TKN_STRING 2
+#define TKN_URL 3
+#define TKN_ENDGROUP 4
+#define TKN_COMMENT 5
+#define TKN_EOL 125
+#define TKN_EOF 126
+#define TKN_UNKNOWN 127
+
+static char *tkn_buf;
+static int tkn_buf_length;
+static int tkn_length;
+
+static char *hotlist_file_name;
+static FILE *hotlist_file;
+static time_t hotlist_file_mtime;
+
+static int hot_skip_blanks ()
+{
+ int c;
+
+ while ((c = getc (hotlist_file)) != EOF && c != '\n' && isspace (c))
+ ;
+ return c;
+
+}
+
+static int hot_next_token ()
+{
+ int c;
+
+#define CHECK_BUF() \
+do { \
+ if (tkn_length == tkn_buf_length) \
+ tkn_buf = tkn_buf ? (realloc (tkn_buf, tkn_buf_length += 1024)) \
+ : (malloc (tkn_buf_length = 1024)); \
+} while (0)
+
+ tkn_length = 0;
+
+again:
+ c = hot_skip_blanks ();
+ switch (c) {
+ case EOF:
+ return TKN_EOF;
+ break;
+ case '\n':
+ return TKN_EOL;
+ break;
+ case '#':
+ while ((c = getc (hotlist_file)) != EOF && c != '\n') {
+ if (c == EOF)
+ return TKN_EOF;
+ if (c != '\n') {
+ CHECK_BUF();
+ tkn_buf[tkn_length++] = c == '\n' ? ' ' : c;
+ }
+ }
+ CHECK_BUF();
+ tkn_buf[tkn_length] = '\0';
+ return TKN_COMMENT;
+ break;
+ case '"':
+ while ((c = getc (hotlist_file)) != EOF && c != '"') {
+ if (c == '\\')
+ if ((c = getc (hotlist_file)) == EOF)
+ return TKN_EOF;
+ CHECK_BUF();
+ tkn_buf[tkn_length++] = c == '\n' ? ' ' : c;
+ }
+ if (c == EOF)
+ return TKN_EOF;
+ CHECK_BUF();
+ tkn_buf[tkn_length] = '\0';
+ return TKN_STRING;
+ break;
+ case '\\':
+ if ((c = getc (hotlist_file)) == EOF)
+ return TKN_EOF;
+ if (c == '\n')
+ goto again;
+
+ /* fall through; it is taken as normal character */
+
+ default:
+ do {
+ CHECK_BUF();
+ tkn_buf[tkn_length++] = toupper(c);
+ } while ((c = fgetc (hotlist_file)) != EOF && isalnum (c));
+ if (c != EOF)
+ ungetc (c, hotlist_file);
+ CHECK_BUF();
+ tkn_buf[tkn_length] = '\0';
+ if (strncmp (tkn_buf, "GROUP", tkn_length) == 0)
+ return TKN_GROUP;
+ else if (strncmp (tkn_buf, "ENTRY", tkn_length) == 0)
+ return TKN_ENTRY;
+ else if (strncmp (tkn_buf, "ENDGROUP", tkn_length) == 0)
+ return TKN_ENDGROUP;
+ else if (strncmp (tkn_buf, "URL", tkn_length) == 0)
+ return TKN_URL;
+ else
+ return TKN_UNKNOWN;
+ break;
+ }
+}
+
+#define SKIP_TO_EOL { \
+int _tkn; \
+while ((_tkn = hot_next_token ()) != TKN_EOF && _tkn != TKN_EOL) ; \
+}
+
+#define CHECK_TOKEN(_TKN_) \
+if ((tkn = hot_next_token ()) != _TKN_) { \
+ hotlist_state.readonly = 1; \
+ hotlist_state.file_error = 1; \
+ while (tkn != TKN_EOL && tkn != TKN_EOF) \
+ tkn = hot_next_token (); \
+break; \
+}
+
+static void
+hot_load_group (struct hotlist * grp)
+{
+ int tkn;
+ struct hotlist *new_grp;
+ char *label, *url;
+
+ current_group = grp;
+
+ while ((tkn = hot_next_token()) != TKN_ENDGROUP)
+ switch (tkn) {
+ case TKN_GROUP:
+ CHECK_TOKEN(TKN_STRING);
+ new_grp = add2hotlist (strdup (tkn_buf), 0, HL_TYPE_GROUP, 0);
+ SKIP_TO_EOL;
+ hot_load_group (new_grp);
+ current_group = grp;
+ break;
+ case TKN_ENTRY:
+ CHECK_TOKEN(TKN_STRING);
+ label = strdup (tkn_buf);
+ CHECK_TOKEN(TKN_URL);
+ CHECK_TOKEN(TKN_STRING);
+ url = strdup (tkn_buf);
+ add2hotlist (label, url, HL_TYPE_ENTRY, 0);
+ SKIP_TO_EOL;
+ break;
+ case TKN_COMMENT:
+ label = strdup (tkn_buf);
+ add2hotlist (label, 0, HL_TYPE_COMMENT, 0);
+ break;
+ case TKN_EOF:
+ hotlist_state.readonly = 1;
+ hotlist_state.file_error = 1;
+ return;
+ break;
+ case TKN_EOL:
+ /* skip empty lines */
+ break;
+ default:
+ hotlist_state.readonly = 1;
+ hotlist_state.file_error = 1;
+ SKIP_TO_EOL;
+ break;
+ }
+ SKIP_TO_EOL;
+}
+
+static void
+hot_load_file (struct hotlist * grp)
+{
+ int tkn;
+ struct hotlist *new_grp;
+ char *label, *url;
+
+ current_group = grp;
+
+ while ((tkn = hot_next_token())!= TKN_EOF)
+ switch (tkn) {
+ case TKN_GROUP:
+ CHECK_TOKEN(TKN_STRING);
+ new_grp = add2hotlist (strdup (tkn_buf), 0, HL_TYPE_GROUP, 0);
+ SKIP_TO_EOL;
+ hot_load_group (new_grp);
+ current_group = grp;
+ break;
+ case TKN_ENTRY:
+ CHECK_TOKEN(TKN_STRING);
+ label = strdup (tkn_buf);
+ CHECK_TOKEN(TKN_URL);
+ CHECK_TOKEN(TKN_STRING);
+ url = strdup (tkn_buf);
+ add2hotlist (label, url, HL_TYPE_ENTRY, 0);
+ SKIP_TO_EOL;
+ break;
+ case TKN_COMMENT:
+ label = strdup (tkn_buf);
+ add2hotlist (label, 0, HL_TYPE_COMMENT, 0);
+ break;
+ case TKN_EOL:
+ /* skip empty lines */
+ break;
+ default:
+ hotlist_state.readonly = 1;
+ hotlist_state.file_error = 1;
+ SKIP_TO_EOL;
+ break;
+ }
+}
+
+void
+clean_up_hotlist_groups (char *section)
+{
+ char *grp_section;
+ void *profile_keys;
+ char *key, *value;
+
+ grp_section = copy_strings (section, ".Group", (char *)0);
+ if (profile_has_section (section, profile_name))
+ profile_clean_section (section, profile_name);
+ if (profile_has_section (grp_section, profile_name)) {
+ profile_keys = profile_init_iterator (grp_section, profile_name);
+
+ while (profile_keys) {
+ profile_keys = profile_iterator_next (profile_keys, &key, &value);
+ clean_up_hotlist_groups (key);
+ }
+ profile_clean_section (grp_section, profile_name);
+ }
+ free (grp_section);
+}
+
+
+
+void load_hotlist (void)
+{
+ char *grp_section;
+ int has_old_list = 0;
+ int remove_old_list = 0;
+ struct stat stat_buf;
+
+ if (hotlist_state.loaded) {
+ stat (hotlist_file_name, &stat_buf);
+ if (hotlist_file_mtime < stat_buf.st_mtime)
+ done_hotlist ();
+ else
+ return;
+ }
+
+ if (!hotlist_file_name)
+ hotlist_file_name = concat_dir_and_file (home_dir, HOTLIST_FILENAME);
+
+ hotlist = new_hotlist ();
+ hotlist->type = HL_TYPE_GROUP;
+ hotlist->label = strdup (_(" Top level group "));
+ hotlist->up = hotlist;
+ /*
+ * compatibility :-(
+ */
+ hotlist->directory = strdup ("Hotlist");
+
+ grp_section = copy_strings ("Hotlist", ".Group", (char *)0);
+ has_old_list = profile_has_section ("Hotlist", profile_name) ||
+ profile_has_section (grp_section, profile_name);
+ free (grp_section);
+
+ if ((hotlist_file = fopen (hotlist_file_name, "r")) == 0) {
+ int result;
+ char *msg;
+
+ msg = copy_strings (_("Hotlist is now kept in file ~/"), HOTLIST_FILENAME,
+ _("MC will load hotlist from ~/"), PROFILE_NAME,
+ _(" and then delete [Hotlist] section there"), NULL);
+ message (0, _(" Hotlist Load "), msg);
+ free (msg);
+
+ load_group (hotlist);
+ hotlist_state.loaded = 1;
+ /*
+ * just to be shure we got copy
+ */
+ hotlist_state.modified = 1;
+ result = save_hotlist ();
+ hotlist_state.modified = 0;
+ if (result) {
+ remove_old_list = 1;
+ } else {
+ char *msg;
+
+ msg = copy_strings (_("MC was unable to write ~/"), HOTLIST_FILENAME,
+ _(" file, your old hotlist entries were not deleted"), NULL);
+
+ message (D_ERROR, _(" Hotlist Load "), msg);
+ free (msg);
+ }
+ } else {
+ hot_load_file (hotlist);
+ fclose (hotlist_file);
+ hotlist_state.loaded = 1;
+ if (has_old_list) {
+ int result;
+ char *msg;
+
+ msg = copy_strings (
+ _("You have ~/"), HOTLIST_FILENAME, _(" file and [Hotlist] section in ~/"), PROFILE_NAME, "\n",
+ _("Your ~/"), HOTLIST_FILENAME, _(" most probably was created\n"),
+ _("by an earlier development version of MC\nand is more actual than ~/"),
+ PROFILE_NAME, _(" entries\n\n"),
+ _("You can choose between\n\n"
+ " Remove - remove old hotlist entries from ~/"), PROFILE_NAME, "\n",
+ _(" Keep - keep your old entries; you will be asked\n"
+ " the same question next time\n"
+ " Merge - add old entries to hotlist as group \"Entries from ~/"),
+ PROFILE_NAME, "\"\n\n", NULL);
+
+ result = query_dialog (_(" Hotlist Load "),
+ msg, D_ERROR, 3, _("&Remove"), _("&Keep"), _("&Merge"));
+ if (result == 0)
+ remove_old_list = 1;
+ else if (result == 2) {
+ struct hotlist *grp = hotlist->head;
+ struct hotlist *old;
+
+ hotlist->head = 0;
+ load_group (hotlist);
+
+ old = new_hotlist ();
+ old->type = HL_TYPE_GROUP;
+ old->label = copy_strings (_(" Entries from ~/"), PROFILE_NAME, NULL);
+ old->up = hotlist;
+ old->head = hotlist->head;
+ old->next = grp;
+ hotlist->head = old;
+ hotlist_state.modified = 1;
+ if (!save_hotlist ()){
+ char *str;
+
+ str = copy_strings (_("MC was unable to write ~/"), HOTLIST_FILENAME,
+ _(" file your old hotlist entries were not deleted"), NULL);
+
+ message (D_ERROR, _(" Hotlist Load "), str);
+ free (str);
+ } else
+ remove_old_list = 1;
+ hotlist_state.modified = 0;
+ }
+ }
+ }
+
+ if (remove_old_list) {
+ clean_up_hotlist_groups ("Hotlist");
+ sync_profiles ();
+ }
+
+ stat (hotlist_file_name, &stat_buf);
+ hotlist_file_mtime = stat_buf.st_mtime;
+ current_group = hotlist;
+}
+
+void save_group (struct hotlist *grp)
+{
+ struct hotlist *current = grp->head;
+ char *group_section;
+
+ group_section = find_group_section (grp);
+
+ profile_clean_section (group_section, profile_name);
+ for (;current && current->type == HL_TYPE_GROUP; current = current->next){
+ WritePrivateProfileString (group_section,
+ current->directory,
+ current->label,
+ profile_name);
+ }
+ free (group_section);
+
+ for (current = grp->head;
+ current && current->type == HL_TYPE_GROUP;
+ current = current->next)
+ save_group (current);
+
+ profile_clean_section (grp->directory, profile_name);
+ for (;current; current = current->next){
+ WritePrivateProfileString (grp->directory,
+ current->directory,
+ current->label,
+ profile_name);
+ }
+}
+
+static int list_level = 0;
+
+void hot_save_group (struct hotlist *grp)
+{
+ struct hotlist *current = grp->head;
+ int i;
+ char *s;
+
+#define INDENT(n) \
+do { \
+ for (i = 0; i < n; i++) \
+ putc (' ', hotlist_file); \
+} while (0)
+
+ for (;current; current = current->next)
+ switch (current->type) {
+ case HL_TYPE_GROUP:
+ INDENT (list_level);
+ fputs ("GROUP \"", hotlist_file);
+ for (s = current->label; *s; s++) {
+ if (*s == '"')
+ putc ('\\', hotlist_file);
+ else if (*s == '\\')
+ putc ('\\', hotlist_file);
+ putc (*s, hotlist_file);
+ }
+ fputs ("\"\n", hotlist_file);
+ list_level += 2;
+ hot_save_group (current);
+ list_level -= 2;
+ INDENT (list_level);
+ fputs ("ENDGROUP\n", hotlist_file);
+ break;
+ case HL_TYPE_ENTRY:
+ INDENT(list_level);
+ fputs ("ENTRY \"", hotlist_file);
+ for (s = current->label; *s; s++) {
+ if (*s == '"')
+ putc ('\\', hotlist_file);
+ else if (*s == '\\')
+ putc ('\\', hotlist_file);
+ putc (*s, hotlist_file);
+ }
+ fputs ("\" URL \"", hotlist_file);
+ for (s = current->directory; *s; s++) {
+ if (*s == '"')
+ putc ('\\', hotlist_file);
+ else if (*s == '\\')
+ putc ('\\', hotlist_file);
+ putc (*s, hotlist_file);
+ }
+ fputs ("\"\n", hotlist_file);
+ break;
+ case HL_TYPE_COMMENT:
+ fprintf (hotlist_file, "#%s\n", current->label);
+ break;
+
+ }
+}
+
+int save_hotlist (void)
+{
+ int saved = 0;
+ struct stat stat_buf;
+
+ if (!hotlist_state.readonly && hotlist_state.modified && hotlist_file_name) {
+ char *fbak = copy_strings (hotlist_file_name, ".bak", 0);
+
+ rename (hotlist_file_name, fbak);
+ if ((hotlist_file = fopen (hotlist_file_name, "w")) != 0) {
+ if (stat (fbak, &stat_buf) == 0)
+ chmod (hotlist_file_name, stat_buf.st_mode);
+ else
+ chmod (hotlist_file_name, S_IRUSR | S_IWUSR);
+ hot_save_group (hotlist);
+ fflush (hotlist_file);
+ fclose (hotlist_file);
+ stat (hotlist_file_name, &stat_buf);
+ hotlist_file_mtime = stat_buf.st_mtime;
+ saved = 1;
+ hotlist_state.modified = 0;
+ } else
+ rename (fbak, hotlist_file_name);
+ free (fbak);
+ }
+
+ return saved;
+}
+
+void done_hotlist (void)
+{
+ remove_group (hotlist);
+ hotlist_state.loaded = 0;
+ if (hotlist->label)
+ free (hotlist->label);
+ if (hotlist->directory)
+ free (hotlist->directory);
+ free (hotlist);
+ if (hotlist_file_name)
+ free (hotlist_file_name);
+ hotlist_file_name = 0;
+ hotlist = current_group = 0;
+ l_hotlist = 0;
+ current_group = 0;
+}
+
+
--- /dev/null
+#ifndef __HOTLIST_H
+#define __HOTLIST_H
+
+#define LIST_VFSLIST 0x01
+#define LIST_HOTLIST 0x02
+#define LIST_MOVELIST 0x04
+
+void add2hotlist_cmd (void);
+char *hotlist_cmd (int list_vfs);
+void load_hotlist (void);
+int save_hotlist (void);
+void done_hotlist (void);
+
+#endif
--- /dev/null
+/* GNOME already handles the intenrationalization issues */
+#ifndef _MC_I18N_H_
+#define _MC_I18N_H_
+
+ /* Stubs that do something close enough. */
+#define textdomain(String) (String)
+#define gettext(String) (String)
+#define dgettext(Domain,Message) (Message)
+#define dcgettext(Domain,Message,Type) (Message)
+#define bindtextdomain(Domain,Directory) (Domain)
+#define _(String) (String)
+#define N_(String) (String)
+
+#endif /* _MC_I18N_H_ */
--- /dev/null
+/* Panel managing.
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+ Copyright (C) 1995 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include "tty.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <malloc.h>
+#include "mad.h"
+#include "util.h" /* statfs calls */
+#include "mouse.h" /* Gpm_Event */
+#include "color.h"
+#include "dlg.h"
+#include "info.h"
+#include "dir.h" /* required by panel */
+#include "panel.h" /* for the panel structure */
+#include "main.h" /* opanel, cpanel definitions */
+#include "win.h" /* print_bytesize */
+#include "layout.h"
+#include "key.h" /* is_idle() */
+
+#ifdef HAVE_TK
+# include "tkmain.h"
+# include "tkinfo.h"
+#endif
+
+/* Have we called the init_my_statfs routine? */
+static int initialized;
+struct my_statfs myfs_stats;
+
+static int info_event (Gpm_Event *event, WInfo *info)
+{
+ return 0;
+}
+
+static void info_box (Dlg_head *h, WInfo *info)
+{
+ standend ();
+ if (hascolors)
+ attrset (NORMAL_COLOR);
+ widget_erase (&info->widget);
+ draw_double_box (h, info->widget.y, info->widget.x,
+ info->widget.lines, info->widget.cols);
+}
+
+#ifndef VERSION
+# define VERSION "undefined"
+#endif
+
+void info_show_info (WInfo *info)
+{
+ struct stat buf;
+
+#ifndef HAVE_X
+ if (!is_idle ())
+ return;
+
+ info_box (info->widget.parent, info);
+ attrset (MARKED_COLOR);
+ widget_move (&info->widget, 1, 3);
+ printw (_("Midnight Commander %s"), VERSION);
+ attrset (NORMAL_COLOR);
+ widget_move (&info->widget, 2, 1);
+ /* .ado: info->widget.x has wrong value (==0) on NT and OS/2, why? */
+#if !defined(OS2_NT)
+ hline (ACS_HLINE|NORMAL_COLOR, info->widget.x-2);
+#endif
+#endif
+ if (get_current_type () != view_listing)
+ return;
+
+ if (!info->ready)
+ return;
+
+ my_statfs (&myfs_stats, cpanel->cwd);
+ buf = cpanel->dir.list [cpanel->selected].buf;
+#ifdef OS2_NT
+ /* .ado: for OS/2 and NT, st_dev must > 0 */
+ if ((signed char) buf.st_dev < 0)
+ return;
+#endif
+
+#ifndef HAVE_X
+ /* Print only lines which fit */
+ switch (info->widget.y-2){
+ /* Note: all cases are fall-throughs */
+
+ default:
+
+ case 16:
+ widget_move (&info->widget, 16, 3);
+ if (myfs_stats.nfree >0 || myfs_stats.nodes > 0)
+ printw (_("Free nodes %d (%d%%) of %d"),
+ myfs_stats.nfree,
+ myfs_stats.total
+ ? 100 * myfs_stats.nfree / myfs_stats.nodes : 0,
+ myfs_stats.nodes);
+ else
+ addstr (_("No node information"));
+
+ case 15:
+ widget_move (&info->widget, 15, 3);
+ if (myfs_stats.avail > 0 || myfs_stats.total > 0){
+ addstr (_("Free space "));
+ print_bytesize (myfs_stats.avail, 1);
+ printw (_(" (%d%%) of "), myfs_stats.total
+ ? 100 * myfs_stats.avail / myfs_stats.total : 0);
+ print_bytesize (myfs_stats.total, 1);
+ } else
+ addstr (_("No space information"));
+
+ case 14:
+ widget_move (&info->widget, 14, 3);
+ printw (_("Type: %s "), myfs_stats.typename ? myfs_stats.typename : _("non-local vfs"));
+ if (myfs_stats.type != 0xffff && myfs_stats.type != 0xffffffff)
+ printw (" (%Xh)", myfs_stats.type);
+
+ case 13:
+ widget_move (&info->widget, 13, 3);
+ printw (_("Device: %s"),
+ name_trunc (myfs_stats.device, info->widget.cols - 15));
+ case 12:
+ widget_move (&info->widget, 12, 3);
+ printw (_("Filesystem: %s"),
+ name_trunc (myfs_stats.mpoint, info->widget.cols - 15));
+
+ case 11:
+ widget_move (&info->widget, 11, 3);
+ printw (_("Accessed: %s"), file_date (buf.st_atime));
+
+ case 10:
+ widget_move (&info->widget, 10, 3);
+ printw (_("Modified: %s"), file_date (buf.st_mtime));
+
+ case 9:
+ widget_move (&info->widget, 9, 3);
+ printw (_("Created: %s"), file_date (buf.st_ctime));
+
+ case 8:
+ widget_move (&info->widget, 8, 3);
+#if 0
+#ifdef HAVE_ST_RDEV
+ if (buf.st_rdev)
+ printw ("Inode dev: major: %d, minor: %d",
+ buf.st_rdev >> 8, buf.st_rdev & 0xff);
+ else
+#endif
+#endif
+ {
+ printw (_("Size: "));
+ print_bytesize (buf.st_size, 0);
+#ifdef HAVE_ST_BLOCKS
+ printw (_(" (%d blocks)"), buf.st_blocks);
+#endif
+ }
+
+ case 7:
+ widget_move (&info->widget, 7, 3);
+ printw (_("Owner: %s/%s"), get_owner (buf.st_uid),
+ get_group (buf.st_gid));
+
+ case 6:
+ widget_move (&info->widget, 6, 3);
+ printw (_("Links: %d"), buf.st_nlink);
+
+ case 5:
+ widget_move (&info->widget, 5, 3);
+ printw (_("Mode: %s (%04o)"),
+ string_perm (buf.st_mode), buf.st_mode & 07777);
+
+ case 4:
+ widget_move (&info->widget, 4, 3);
+ printw (_("Location: %Xh:%Xh"), buf.st_dev, buf.st_ino);
+
+ case 3:
+ widget_move (&info->widget, 3, 2);
+ /* .ado: fname is invalid if selected == 0 && ifno called from current panel */
+ if (cpanel->selected){
+ printw (_("File: %s"),
+ name_trunc (cpanel->dir.list [cpanel->selected].fname,
+ info->widget.cols - 15));
+ } else
+ printw (_("File: None"));
+
+ case 2:
+ case 1:
+ case 0:
+ ;
+ } /* switch */
+#else /* HAVE_X */
+ x_show_info (info, &myfs_stats, &buf);
+#endif
+}
+
+static void info_hook (void *data)
+{
+ WInfo *info = (WInfo *) data;
+ Widget *other_widget;
+
+ other_widget = get_panel_widget (get_current_index ());
+ if (!other_widget)
+ return;
+ if (dlg_overlap (&info->widget, other_widget))
+ return;
+
+ info->ready = 1;
+ info_show_info (info);
+}
+
+static void info_destroy (WInfo *info)
+{
+ delete_hook (&select_file_hook, info_hook);
+}
+
+static int info_callback (Dlg_head *h, WInfo *info, int msg, int par)
+{
+ switch (msg){
+
+ case WIDGET_INIT:
+ add_hook (&select_file_hook, info_hook, info);
+ info->ready = 0;
+#ifdef HAVE_X
+ x_create_info (h, h->wdata, info);
+#endif
+ break;
+
+#ifndef HAVE_X
+ case WIDGET_DRAW:
+ info_hook (info);
+ info_show_info (info);
+ return 1;
+#endif
+
+ case WIDGET_FOCUS:
+ return 0;
+ }
+ return default_proc (h, msg, par);
+}
+
+WInfo *info_new ()
+{
+ WInfo *info = xmalloc (sizeof (WInfo), "panel_info");
+
+ init_widget (&info->widget, 0, 0, 0, 0, (callback_fn)
+ info_callback, (destroy_fn) info_destroy,
+ (mouse_h) info_event, NULL);
+
+ /* We do not want the cursor */
+ widget_want_cursor (info->widget, 0);
+
+ if (!initialized){
+ initialized = 1;
+ init_my_statfs ();
+ }
+
+ return info;
+}
+
--- /dev/null
+#ifndef __INFO_H
+#define __INFO_H
+
+typedef struct {
+ Widget widget;
+ int ready;
+} WInfo;
+
+WInfo *info_new ();
+
+#endif
--- /dev/null
+/* Keyboard support routines.
+
+ Copyright (C) 1994,1995 the Free Software Foundation.
+
+ Written by: 1994, 1995 Miguel de Icaza.
+ 1994, 1995 Janne Kukonlehto.
+ 1995 Jakub Jelinek.
+ 1997 Norbert Warmuth
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <sys/types.h> /* FD_ZERO et al */
+#ifndef SCO_FLAVOR
+ /* alex: sys/select.h defines struct timeval */
+# include <sys/time.h> /* struct timeval */
+#endif /* SCO_FLAVOR */
+#if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#include "tty.h"
+#include <ctype.h>
+#include <errno.h>
+#include <malloc.h>
+#include "util.h" /* For xmalloc prototype */
+#include "mad.h" /* The memory debugger */
+#include "global.h"
+#include "mouse.h"
+#include "key.h"
+#include "main.h"
+#include "file.h"
+#include "win.h"
+#include "cons.saver.h"
+#include "../vfs/vfs.h"
+
+#ifdef __linux__
+# if defined(__GLIBC__) && (__GLIBC__ < 2)
+# include <linux/termios.h> /* This is needed for TIOCLINUX */
+# else
+# include <termios.h>
+# endif
+# include <sys/ioctl.h>
+#endif
+
+#include "x.h"
+
+/* "$Id: key.c,v 1.1 2001/12/30 09:55:25 sedwards Exp $" */
+
+/* This macros were stolen from gpm 0.15 */
+#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
+#define DIF_TIME(t1,t2) ((t2.tv_sec -t1.tv_sec) *1000+ \
+ (t2.tv_usec-t1.tv_usec)/1000)
+
+/* timeout for old_esc_mode in usec */
+#define ESCMODE_TIMEOUT 1000000
+
+int mou_auto_repeat = 100;
+int double_click_speed = 250;
+int old_esc_mode = 0;
+
+int use_8th_bit_as_meta = 1;
+
+#ifndef HAVE_X
+typedef struct key_def {
+ char ch; /* Holds the matching char code */
+ int code; /* The code returned, valid if child == NULL */
+ struct key_def *next;
+ struct key_def *child; /* sequence continuation */
+ int action; /* optional action to be done. Now used only
+ to mark that we are just after the first
+ Escape */
+} key_def;
+
+/* This holds all the key definitions */
+static key_def *keys = 0;
+#endif
+
+static int input_fd;
+static fd_set select_set;
+static int disabled_channels = 0; /* Disable channels checking */
+int xgetch_second (void);
+
+#ifndef PORT_HAS_FILE_HANDLERS
+/* File descriptor monitoring add/remove routines */
+typedef struct SelectList {
+ int fd;
+ select_fn callback;
+ void *info;
+ struct SelectList *next;
+} SelectList;
+
+SelectList *select_list = 0;
+
+void add_select_channel (int fd, select_fn callback, void *info)
+{
+ SelectList *new;
+
+ new = xmalloc (sizeof (SelectList), "add_select_channel");
+ new->fd = fd;
+ new->callback = callback;
+ new->info = info;
+ new->next = select_list;
+ select_list = new;
+}
+
+void delete_select_channel (int fd)
+{
+ SelectList *p = select_list;
+ SelectList *prev = 0;
+
+ while (p){
+ if (p->fd == fd){
+ if (prev)
+ prev->next = p->next;
+ else
+ select_list = p->next;
+ free (p);
+ }
+ prev = p;
+ p = p->next;
+ }
+}
+
+inline static int add_selects (fd_set *select_set)
+{
+ SelectList *p;
+ int top_fd = 0;
+
+ if (disabled_channels)
+ return 0;
+
+ for (p = select_list; p; p = p->next){
+ FD_SET (p->fd, select_set);
+ if (p->fd > top_fd)
+ top_fd = p->fd;
+ }
+ return top_fd;
+}
+
+static void check_selects (fd_set *select_set)
+{
+ SelectList *p;
+
+ if (disabled_channels)
+ return;
+
+ for (p = select_list; p; p = p->next)
+ if (FD_ISSET (p->fd, select_set))
+ (*p->callback)(p->fd, p->info);
+}
+#endif
+
+void channels_down (void)
+{
+ disabled_channels ++;
+}
+
+void channels_up (void)
+{
+ if (!disabled_channels)
+ fprintf (stderr,
+ "Error: channels_up called with disabled_channels = 0\n");
+ disabled_channels--;
+}
+
+typedef struct {
+ int code;
+ char *seq;
+ int action;
+} key_define_t;
+
+#ifndef HAVE_X
+key_define_t mc_bindings [] = {
+ { KEY_END, ESC_STR ">", MCKEY_NOACTION },
+ { KEY_HOME, ESC_STR "<", MCKEY_NOACTION },
+
+#ifdef linux
+ /* Incredible, but many Linuxes still have old databases */
+ { KEY_IC, ESC_STR "[2~", MCKEY_NOACTION },
+#endif
+ { 0, 0, MCKEY_NOACTION },
+};
+
+/* Broken terminfo and termcap databases on xterminals */
+key_define_t xterm_key_defines [] = {
+ { KEY_F(1), ESC_STR "OP", MCKEY_NOACTION },
+ { KEY_F(2), ESC_STR "OQ", MCKEY_NOACTION },
+ { KEY_F(3), ESC_STR "OR", MCKEY_NOACTION },
+ { KEY_F(4), ESC_STR "OS", MCKEY_NOACTION },
+ { KEY_F(1), ESC_STR "[11~", MCKEY_NOACTION },
+ { KEY_F(2), ESC_STR "[12~", MCKEY_NOACTION },
+ { KEY_F(3), ESC_STR "[13~", MCKEY_NOACTION },
+ { KEY_F(4), ESC_STR "[14~", MCKEY_NOACTION },
+ { KEY_F(5), ESC_STR "[15~", MCKEY_NOACTION },
+ { KEY_F(6), ESC_STR "[17~", MCKEY_NOACTION },
+ { KEY_F(7), ESC_STR "[18~", MCKEY_NOACTION },
+ { KEY_F(8), ESC_STR "[19~", MCKEY_NOACTION },
+ { KEY_F(9), ESC_STR "[20~", MCKEY_NOACTION },
+ { KEY_F(10), ESC_STR "[21~", MCKEY_NOACTION },
+ { 0, 0, MCKEY_NOACTION },
+};
+
+key_define_t mc_default_keys [] = {
+ { ESC_CHAR, ESC_STR, MCKEY_ESCAPE },
+ { ESC_CHAR, ESC_STR ESC_STR, MCKEY_NOACTION },
+ { 0, 0, MCKEY_NOACTION },
+};
+#endif
+
+void define_sequences (key_define_t *kd)
+{
+#ifndef HAVE_X
+ int i;
+
+ for (i = 0; kd [i].code; i++)
+ define_sequence(kd [i].code, kd [i].seq, kd [i].action);
+#endif
+}
+
+/* This has to be called before slang_init or whatever routine
+ calls any define_sequence */
+void init_key (void)
+{
+#ifndef HAVE_X
+ char *term = (char *) getenv ("TERM");
+
+ /* This has to be the first define_sequence */
+ /* So, we can assume that the first keys member has ESC */
+ define_sequences (mc_default_keys);
+
+ /* Terminfo on irix does not have some keys */
+ if ((!strncmp (term, "iris-ansi", 9)) || (!strncmp (term, "xterm", 5)))
+ define_sequences (xterm_key_defines);
+
+ define_sequences (mc_bindings);
+
+ /* load some additional keys (e.g. direct Alt-? support) */
+ load_xtra_key_defines();
+
+#ifdef __QNX__
+ if (strncmp(term, "qnx", 3) == 0){
+ /* Modify the default value of use_8th_bit_as_meta: we would
+ * like to provide a working mc for a newbie who knows nothing
+ * about [Options|Display bits|Full 8 bits input]...
+ *
+ * Don't use 'meta'-bit, when we are dealing with a
+ * 'qnx*'-type terminal: clear the default value!
+ * These terminal types use 0xFF as an escape character,
+ * so use_8th_bit_as_meta==1 must not be enabled!
+ *
+ * [mc-4.1.21+,slint.c/getch(): the DEC_8BIT_HACK stuff
+ * is not used now (doesn't even depend on use_8th_bit_as_meta
+ * as in mc-3.1.2)...GREAT!...no additional code is required!]
+ */
+ use_8th_bit_as_meta = 0;
+ }
+#endif /* __QNX__ */
+#endif /* !HAVE_X */
+}
+
+/* This has to be called after SLang_init_tty/slint_init */
+void init_key_input_fd (void)
+{
+#ifndef HAVE_X
+#ifdef HAVE_SLANG
+ input_fd = SLang_TT_Read_FD;
+#endif
+#endif /* !HAVE_X */
+}
+
+
+#ifndef HAVE_X
+void xmouse_get_event (Gpm_Event *ev)
+{
+ int btn;
+ static struct timeval tv1 = { 0, 0 }; /* Force first click as single */
+ static struct timeval tv2;
+ static int clicks;
+
+ /* Decode Xterm mouse information to a GPM style event */
+
+ /* Variable btn has following meaning: */
+ /* 0 = btn1 dn, 1 = btn2 dn, 2 = btn3 dn, 3 = btn up */
+ btn = xgetch () - 32;
+
+ /* There seems to be no way of knowing which button was released */
+ /* So we assume all the buttons were released */
+
+ if (btn == 3){
+ ev->type = GPM_UP | (GPM_SINGLE << clicks);
+ ev->buttons = 0;
+ GET_TIME (tv1);
+ clicks = 0;
+ } else {
+ ev->type = GPM_DOWN;
+ GET_TIME (tv2);
+ if (tv1.tv_sec && (DIF_TIME (tv1,tv2) < double_click_speed)){
+ clicks++;
+ clicks %= 3;
+ } else
+ clicks = 0;
+
+ switch (btn) {
+ case 0:
+ ev->buttons = GPM_B_LEFT;
+ break;
+ case 1:
+ ev->buttons = GPM_B_MIDDLE;
+ break;
+ case 2:
+ ev->buttons = GPM_B_RIGHT;
+ break;
+ default:
+ /* Nothing */
+ break;
+ }
+ }
+ /* Coordinates are 33-based */
+ /* Transform them to 1-based */
+ ev->x = xgetch () - 32;
+ ev->y = xgetch () - 32;
+}
+
+static key_def *create_sequence (char *seq, int code, int action)
+{
+ key_def *base, *p, *attach;
+
+ for (base = attach = NULL; *seq; seq++){
+ p = xmalloc (sizeof (key_def), "create_sequence");
+ if (!base) base = p;
+ if (attach) attach->child = p;
+
+ p->ch = *seq;
+ p->code = code;
+ p->child = p->next = NULL;
+ if (!seq[1])
+ p->action = action;
+ else
+ p->action = MCKEY_NOACTION;
+ attach = p;
+ }
+ return base;
+}
+
+/* The maximum sequence length (32 + null terminator) */
+static int seq_buffer [33];
+static int *seq_append = 0;
+
+static int push_char (int c)
+{
+ if (!seq_append)
+ seq_append = seq_buffer;
+
+ if (seq_append == &(seq_buffer [sizeof (seq_buffer)-2]))
+ return 0;
+ *(seq_append++) = c;
+ *seq_append = 0;
+ return 1;
+}
+#endif /* !HAVE_X */
+
+void define_sequence (int code, char *seq, int action)
+{
+#ifndef HAVE_X
+ key_def *base;
+
+ if (strlen (seq) > sizeof (seq_buffer)-1)
+ return;
+
+ for (base = keys; (base != 0) && *seq; ){
+ if (*seq == base->ch){
+ if (base->child == 0){
+ if (*(seq+1)){
+ base->child = create_sequence (seq+1, code, action);
+ return;
+ } else {
+ /* The sequence clashes */
+ return;
+ }
+ } else {
+ base = base->child;
+ seq++;
+ }
+ } else {
+ if (base->next)
+ base = base->next;
+ else {
+ base->next = create_sequence (seq, code, action);
+ return;
+ }
+ }
+ }
+ keys = create_sequence (seq, code, action);
+#endif
+}
+
+#ifndef HAVE_X
+static int *pending_keys;
+#endif
+
+int correct_key_code (int c)
+{
+ /* This is needed on some OS that do not support ncurses and */
+ /* do some magic after read()ing the data */
+ if (c == '\r')
+ return '\n';
+
+#ifdef IS_AIX
+ if (c == KEY_SCANCEL)
+ return '\t';
+#endif
+
+ if (c == KEY_F(0))
+ return KEY_F(10);
+
+ if (!alternate_plus_minus)
+ switch (c) {
+ case KEY_KP_ADD: c = '+'; break;
+ case KEY_KP_SUBTRACT: c = '-'; break;
+ case KEY_KP_MULTIPLY: c = '*'; break;
+ }
+
+ return c;
+}
+
+int get_key_code (int no_delay)
+{
+#ifndef HAVE_X
+ int c;
+ static key_def *this = NULL, *parent;
+ static struct timeval esctime = { -1, -1 };
+ static int lastnodelay = -1;
+
+ if (no_delay != lastnodelay) {
+ this = NULL;
+ lastnodelay = no_delay;
+ }
+
+ pend_send:
+ if (pending_keys){
+ int d = *pending_keys++;
+ check_pend:
+ if (!*pending_keys){
+ pending_keys = 0;
+ seq_append = 0;
+ }
+ if (d == ESC_CHAR && pending_keys){
+ d = ALT(*pending_keys++);
+ goto check_pend;
+ }
+ if ((d & 0x80) && use_8th_bit_as_meta)
+ d = ALT(d & 0x7f);
+ this = NULL;
+ return correct_key_code (d);
+ }
+
+ nodelay_try_again:
+ if (no_delay) {
+#ifdef BUGGY_CURSES
+ wtimeout(stdscr, 500);
+#else
+ nodelay (stdscr, TRUE);
+#endif
+ }
+ c = xgetch ();
+ if (no_delay) {
+#ifdef BUGGY_CURSES
+ notimeout (stdscr, TRUE);
+#else
+ nodelay (stdscr, FALSE);
+#endif
+ if (c == ERR) {
+ if (this != NULL && parent != NULL &&
+ parent->action == MCKEY_ESCAPE && old_esc_mode) {
+ struct timeval current, timeout;
+
+ if (esctime.tv_sec == -1)
+ return ERR;
+ GET_TIME (current);
+ timeout.tv_sec = ESCMODE_TIMEOUT / 1000000 + esctime.tv_sec;
+ timeout.tv_usec = ESCMODE_TIMEOUT % 1000000 + esctime.tv_usec;
+ if (timeout.tv_usec > 1000000) {
+ timeout.tv_usec -= 1000000;
+ timeout.tv_sec++;
+ }
+ if (current.tv_sec < timeout.tv_sec)
+ return ERR;
+ if (current.tv_sec == timeout.tv_sec &&
+ current.tv_usec < timeout.tv_usec)
+ return ERR;
+ this = NULL;
+ pending_keys = seq_append = NULL;
+ return ESC_CHAR;
+ }
+ return ERR;
+ }
+ } else if (c == ERR){
+ /* Maybe we got an incomplete match.
+ This we do only in delay mode, since otherwise
+ xgetch can return ERR at any time. */
+ if (seq_append) {
+ pending_keys = seq_buffer;
+ goto pend_send;
+ }
+ this = NULL;
+ return ERR;
+ }
+
+ /* Search the key on the root */
+ if (!no_delay || this == NULL) {
+ this = keys;
+ parent = NULL;
+
+ if ((c & 0x80) && use_8th_bit_as_meta) {
+ c &= ~0x7f;
+
+ /* The first sequence defined starts with esc */
+ parent = keys;
+ this = keys->child;
+ }
+ }
+ while (this){
+ if (c == this->ch){
+ if (this->child){
+ if (!push_char (c)){
+ pending_keys = seq_buffer;
+ goto pend_send;
+ }
+ parent = this;
+ this = this->child;
+ if (parent->action == MCKEY_ESCAPE && old_esc_mode) {
+ if (no_delay) {
+ GET_TIME (esctime);
+ if (this == NULL) {
+ /* Shouldn't happen */
+ fprintf (stderr, "Internal error\n");
+ exit (1);
+ }
+ goto nodelay_try_again;
+ }
+ esctime.tv_sec = -1;
+ c = xgetch_second ();
+ if (c == ERR) {
+ pending_keys = seq_append = NULL;
+ this = NULL;
+ return ESC_CHAR;
+ }
+ } else {
+ if (no_delay)
+ goto nodelay_try_again;
+ c = xgetch ();
+ }
+ } else {
+ /* We got a complete match, return and reset search */
+ int code;
+
+ pending_keys = seq_append = NULL;
+ code = this->code;
+ this = NULL;
+ return correct_key_code (code);
+ }
+ } else {
+ if (this->next)
+ this = this->next;
+ else {
+ if (parent != NULL && parent->action == MCKEY_ESCAPE) {
+ /* This is just to save a lot of define_sequences */
+ if (isalpha(c)
+ || (c == '\n') || (c == '\t') || (c == XCTRL('h'))
+ || (c == KEY_BACKSPACE) || (c == '!') || (c == '\r')
+ || c == 127 || c == '+' || c == '-' || c == '\\'
+ || c == '?')
+ c = ALT(c);
+ else if (isdigit(c))
+ c = KEY_F (c-'0');
+ else if (c == ' ')
+ c = ESC_CHAR;
+ pending_keys = seq_append = NULL;
+ this = NULL;
+ return correct_key_code (c);
+ }
+ /* Did not find a match or {c} was changed in the if above,
+ so we have to return everything we had skipped
+ */
+ push_char (c);
+ pending_keys = seq_buffer;
+ goto pend_send;
+ }
+ }
+ }
+ this = NULL;
+ return correct_key_code (c);
+#else
+ return ERR;
+#endif /* HAVE_X */
+}
+
+#ifndef PORT_HAS_FILE_HANDLERS
+/* If set timeout is set, then we wait 0.1 seconds, else, we block */
+void try_channels (int set_timeout)
+{
+ struct timeval timeout;
+ static fd_set select_set;
+ struct timeval *timeptr;
+ int v;
+
+ while (1){
+ FD_ZERO (&select_set);
+ FD_SET (input_fd, &select_set); /* Add stdin */
+ add_selects (&select_set);
+
+ if (set_timeout){
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 100000;
+ timeptr = &timeout;
+ } else
+ timeptr = 0;
+
+ v = select (FD_SETSIZE, &select_set, NULL, NULL, timeptr);
+ if (v > 0){
+ check_selects (&select_set);
+ if (FD_ISSET (input_fd, &select_set))
+ return;
+ }
+ }
+}
+
+#ifndef HAVE_X
+/* Workaround for System V Curses vt100 bug */
+static int getch_with_delay (void)
+{
+ int c;
+
+ /* This routine could be used on systems without mouse support,
+ so we need to do the select check :-( */
+ while (1){
+ if (!pending_keys)
+ try_channels (0);
+
+ /* Try to get a character */
+ c = get_key_code (0);
+ if (c != ERR)
+ break;
+ /* Failed -> wait 0.1 secs and try again */
+ try_channels (1);
+ }
+ /* Success -> return the character */
+ return c;
+}
+#endif /* !HAVE_X */
+
+#ifndef HAVE_LIBGPM
+#define gpm_flag 0
+#endif
+#endif /* !HAVE_FILE_HANDLERS */
+
+extern int max_dirt_limit;
+
+/* Returns a character read from stdin with appropriate interpretation */
+/* Also takes care of generated mouse events */
+/* Returns EV_MOUSE if it is a mouse event */
+/* Returns EV_NONE if non-blocking or interrupt set and nothing was done */
+int get_event (Gpm_Event *event, int redo_event, int block)
+{
+#ifndef HAVE_X
+ int c;
+ static int flag; /* Return value from select */
+#ifdef HAVE_LIBGPM
+ static Gpm_Event ev; /* Mouse event */
+#endif
+ struct timeval timeout;
+ struct timeval *time_addr = NULL;
+ static int dirty = 3;
+
+ if ((dirty == 3) || is_idle ()){
+ mc_refresh ();
+ doupdate ();
+ dirty = 1;
+ } else
+ dirty++;
+
+ vfs_timeout_handler ();
+
+ /* Ok, we use (event->x < 0) to signal that the event does not contain
+ a suitable position for the mouse, so we can't use show_mouse_pointer
+ on it.
+ */
+ if (event->x > 0){
+ show_mouse_pointer (event->x, event->y);
+ if (!redo_event)
+ event->x = -1;
+ }
+
+ /* Repeat if using mouse */
+ while ((xmouse_flag || gpm_flag) && !pending_keys)
+ {
+ if (xmouse_flag || gpm_flag)
+ {
+ FD_ZERO (&select_set);
+ FD_SET (input_fd, &select_set);
+ add_selects (&select_set);
+
+#ifdef HAVE_LIBGPM
+ if (gpm_flag) {
+ FD_SET (gpm_fd, &select_set);
+ }
+#endif
+
+ if (redo_event){
+ timeout.tv_usec = mou_auto_repeat * 1000;
+ timeout.tv_sec = 0;
+
+ time_addr = &timeout;
+ } else {
+ int seconds;
+
+ if ((seconds = vfs_timeouts ())){
+ /* the timeout could be improved and actually be
+ * the number of seconds until the next vfs entry
+ * timeouts in the stamp list.
+ */
+
+ timeout.tv_sec = seconds;
+ timeout.tv_usec = 0;
+ time_addr = &timeout;
+ } else
+ time_addr = NULL;
+ }
+
+ if (!block){
+ time_addr = &timeout;
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ }
+ enable_interrupt_key ();
+ flag = select (FD_SETSIZE, &select_set, NULL, NULL, time_addr);
+ disable_interrupt_key ();
+
+ /* select timed out: it could be for any of the following reasons:
+ * redo_event -> it was because of the MOU_REPEAT handler
+ * !block -> we did not block in the select call
+ * else -> 10 second timeout to check the vfs status.
+ */
+ if (flag == 0){
+ if (redo_event)
+ return EV_MOUSE;
+ if (!block)
+ return EV_NONE;
+ vfs_timeout_handler ();
+ }
+ if (flag == -1 && errno == EINTR)
+ return EV_NONE;
+
+ check_selects (&select_set);
+
+ if (FD_ISSET (input_fd, &select_set))
+ break;
+ }
+#ifdef HAVE_LIBGPM
+ if (gpm_flag && FD_ISSET (gpm_fd, &select_set)){
+ if (gpm_flag){
+ Gpm_GetEvent (&ev);
+ Gpm_FitEvent (&ev);
+ }
+ *event = ev;
+ return EV_MOUSE;
+ }
+#endif
+ }
+# ifndef HAVE_SLANG
+ flag = is_wintouched(stdscr);
+ untouchwin (stdscr);
+# endif
+
+ c = block ? getch_with_delay () : get_key_code(1);
+
+# ifndef HAVE_SLANG
+ if (flag)
+ touchwin (stdscr);
+# endif
+
+ if (c == MCKEY_MOUSE) { /* Mouse event */
+ xmouse_get_event (event);
+ return EV_MOUSE;
+ }
+
+ return c;
+#else
+ return EV_NONE;
+#endif /* HAVE_X */
+}
+
+#ifndef PORT_HAS_GETCH
+/* Returns a key press, mouse events are discarded */
+int mi_getch ()
+{
+ Gpm_Event ev;
+ int key;
+
+ ev.x = -1;
+ while ((key = get_event (&ev, 0, 1)) == 0)
+ ;
+ return key;
+}
+#endif
+
+int xgetch_second (void)
+{
+ fd_set Read_FD_Set;
+ int c;
+ struct timeval timeout;
+
+ timeout.tv_sec = ESCMODE_TIMEOUT / 1000000;
+ timeout.tv_usec = ESCMODE_TIMEOUT % 1000000;
+#ifdef BUGGY_CURSES
+ wtimeout(stdscr, 500);
+#else
+ nodelay (stdscr, TRUE);
+#endif
+ FD_ZERO (&Read_FD_Set);
+ FD_SET (input_fd, &Read_FD_Set);
+ select (FD_SETSIZE, &Read_FD_Set, NULL, NULL, &timeout);
+ c = xgetch ();
+#ifdef BUGGY_CURSES
+ notimeout (stdscr, TRUE);
+#else
+ nodelay (stdscr, FALSE);
+#endif
+ return c;
+}
+
+#ifndef HAVE_X
+void learn_store_key (char *buffer, char **p, int c)
+{
+ if (*p - buffer > 253)
+ return;
+ if (c == ESC_CHAR) {
+ *(*p)++ = '\\';
+ *(*p)++ = 'e';
+ } else if (c < ' ') {
+ *(*p)++ = '^';
+ *(*p)++ = c + 'a' - 1;
+ } else if (c == '^') {
+ *(*p)++ = '^';
+ *(*p)++ = '^';
+ } else
+ *(*p)++ = (char) c;
+}
+
+char *learn_key (void)
+{
+/* LEARN_TIMEOUT in usec */
+#define LEARN_TIMEOUT 200000
+
+ fd_set Read_FD_Set;
+ struct timeval endtime;
+ struct timeval timeout;
+ int c = xgetch ();
+ char buffer [256];
+ char *p = buffer;
+
+ while (c == ERR)
+ c = xgetch (); /* Sanity check, should be unnecessary */
+ learn_store_key (buffer, &p, c);
+ GET_TIME (endtime);
+ endtime.tv_usec += LEARN_TIMEOUT;
+ if (endtime.tv_usec > 1000000) {
+ endtime.tv_usec -= 1000000;
+ endtime.tv_sec++;
+ }
+#ifdef BUGGY_CURSES
+ wtimeout(stdscr, 500);
+#else
+ nodelay (stdscr, TRUE);
+#endif
+ for (;;) {
+ while ((c = xgetch ()) == ERR) {
+ GET_TIME (timeout);
+ timeout.tv_usec = endtime.tv_usec - timeout.tv_usec;
+ if (timeout.tv_usec < 0)
+ timeout.tv_sec++;
+ timeout.tv_sec = endtime.tv_sec - timeout.tv_sec;
+ if (timeout.tv_sec >= 0 && timeout.tv_usec > 0) {
+ FD_ZERO (&Read_FD_Set);
+ FD_SET (input_fd, &Read_FD_Set);
+ select (FD_SETSIZE, &Read_FD_Set, NULL, NULL, &timeout);
+ } else
+ break;
+ }
+ if (c == ERR)
+ break;
+ learn_store_key (buffer, &p, c);
+ }
+#ifdef BUGGY_CURSES
+ notimeout (stdscr, TRUE);
+#else
+ nodelay (stdscr, FALSE);
+#endif
+ *p = 0;
+ return strdup (buffer);
+}
+
+/* xterm and linux console only: set keypad to numeric or application
+ mode. Only in application keypad mode it's possible to distinguish
+ the '+' key and the '+' on the keypad ('*' and '-' ditto)*/
+void
+numeric_keypad_mode (void)
+{
+ if (console_flag || xterm_flag) {
+ fprintf (stdout, "\033>");
+ fflush (stdout);
+ }
+}
+
+void
+application_keypad_mode (void)
+{
+ if (console_flag || xterm_flag) {
+ fprintf (stdout, "\033=");
+ fflush (stdout);
+ }
+}
+
+#endif /* !HAVE_X */
+
+/* A function to check if we're idle.
+ Currently checks only for key presses.
+ We could also check the mouse. */
+int is_idle (void)
+{
+ /* Check for incoming key presses *
+ * If there are any we say we're busy */
+
+ fd_set select_set;
+ struct timeval timeout;
+ FD_ZERO (&select_set);
+ FD_SET (0, &select_set);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ select (FD_SETSIZE, &select_set, 0, 0, &timeout);
+ return ! FD_ISSET (0, &select_set);
+}
+
+
+int get_modifier ()
+{
+#ifdef __linux__
+ unsigned char modifiers;
+
+ modifiers = 6;
+
+ if (ioctl (0, TIOCLINUX, &modifiers) < 0)
+ return 0;
+
+ return (int) modifiers;
+#else
+ return 0;
+#endif
+}
+
+int ctrl_pressed ()
+{
+#ifdef __linux__
+ if (get_modifier () & CONTROL_PRESSED)
+ return 1;
+#endif
+ return 0;
+}
+
+#ifdef HAVE_MAD
+#ifndef HAVE_X
+void k_dispose (key_def *k)
+{
+ if (!k)
+ return;
+ k_dispose (k->child);
+ k_dispose (k->next);
+ free (k);
+}
+
+void s_dispose (SelectList *sel)
+{
+ if (!sel)
+ return;
+
+ s_dispose (sel->next);
+ free (sel);
+}
+
+void done_key ()
+{
+ k_dispose (keys);
+ s_dispose (select_list);
+}
+
+#else
+
+void done_key ()
+{
+}
+
+#endif /* HAVE_X */
+#endif /* HAVE_MAD */
--- /dev/null
+#ifndef __KEY_H
+#define __KEY_H
+
+void init_key (void);
+void init_key_input_fd (void);
+void done_key (void);
+int get_event (Gpm_Event *event, int redo_event, int block);
+int is_idle (void);
+int ctrl_pressed ();
+
+#ifndef PORT_HAS_GETCH
+int mi_getch (void);
+#endif
+/* Possible return values from get_event: */
+#define EV_MOUSE -2
+#define EV_NONE -1
+
+/* Used to get the modifier information */
+/* Currently, it just works on the Linux console */
+#ifdef _OS_NT
+# ifndef SHIFT_PRESSED
+# define SHIFT_PRESSED 0x0010
+# endif
+#else
+# define SHIFT_PRESSED 1
+#endif
+#define ALTR_PRESSED 2
+#define CONTROL_PRESSED 4
+#define ALTL_PRESSED 8
+int get_modifier ();
+
+extern int double_click_speed;
+extern int old_esc_mode;
+extern int irix_fn_keys;
+extern int use_8th_bit_as_meta;
+
+/* While waiting for input, the program can select on more than one file */
+
+typedef int (*select_fn)(int fd, void *info);
+
+/* Channel manipulation */
+void add_select_channel (int fd, select_fn callback, void *info);
+void delete_select_channel (int fd);
+void remove_select_channel (int fd);
+
+/* Activate/deactivate the channel checking */
+void channels_up (void);
+void channels_down (void);
+
+/* Abort/Quit chars */
+int is_abort_char (int c);
+int is_quit_char (int c);
+
+#define XCTRL(x) ((x) & 31)
+#define ALT(x) (0x200 | (unsigned int)(x))
+
+/* To define sequences and return codes */
+#define MCKEY_NOACTION 0
+#define MCKEY_ESCAPE 1
+
+/* Return code for the mouse sequence */
+#define MCKEY_MOUSE -2
+
+void do_define_key (int code, char *strcap);
+void define_sequence (int code, char *seq, int action);
+
+/* internally used in key.c, defined in keyxtra.c */
+void load_xtra_key_defines (void);
+
+/* Learn a single key */
+char *learn_key (void);
+
+/* Returns a key code (interpreted) */
+int get_key_code (int nodelay);
+
+typedef struct {
+ int code;
+ char *name;
+ char *longname;
+} key_code_name_t;
+
+extern key_code_name_t key_name_conv_tab [];
+extern int we_are_background;
+
+/* Set keypad mode (xterm and linux console only) */
+#ifndef HAVE_X
+ void numeric_keypad_mode (void);
+ void application_keypad_mode (void);
+#endif
+
+#endif /* __KEY_H */
--- /dev/null
+/* {{{ Copyright */
+
+/* Additional keyboard support routines.
+
+ Copyright (C) 1998 the Free Software Foundation.
+
+ Written by: 1998, Gyorgy Tamasi
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* }}} */
+
+/*
+ * PURPOSE:
+ *
+ * We would like to support the direct ALT-?/META-? and some other 'extra'
+ * keyboard functionality provided by some terminals under some OSes (and
+ * not supported by the 'learn keys...' facility of 'mc'.
+ * (First target platform: QNX.)
+ *
+ * REMARK:
+ *
+ * Implementation strategy: we don't want to rely on a specific terminal
+ * information database management API (termcap,terminfo,SLang,...), so we
+ * try to define a superset of the possible key identifiers here.
+ *
+ */
+#include <config.h>
+#include "mouse.h" /* required before key.h */
+#include "key.h"
+#include "myslang.h"
+
+
+#ifdef __QNX__
+
+/* select implementation: use QNX/term interface */
+#define __USE_QNX_TI
+
+/* implementation specific _TE() definition */
+#ifdef __USE_QNX_TI
+
+/* include QNX/term.h (not NCURSES/term.h!) */
+#if __WATCOMC__ > 1000
+ #include <sys/term.h>
+#else
+ #include <term.h>
+#endif
+#include <stdlib.h> /* getenv() */
+
+/* fieldname -> index conversion */
+#define __QTISX(_qtisn) \
+ (((int)(&((struct _strs*)0)->_qtisn))/sizeof(charoffset))
+
+/* define the OS/implementation-specific __TK() format */
+#define __TK(_tis,_tcs,_tisx,_qtisn) __QTISX(_qtisn)
+
+#endif /* __USE_QNX_TI */
+
+#endif /* __QNX__ */
+
+
+/* {{{ */
+
+/* general key definitions:
+ *
+ * format:
+ *
+ * terminfo name,
+ * termcap name,
+ * index in the terminfo string table (ncurses),
+ * field name in the QNX terminfo strings struct
+ */
+
+#define Key_backspace __TK("kbs", "kb", 55, _ky_backspace )
+#define Key_catab __TK("ktbc", "ka", 56, _ky_catab )
+#define Key_clear __TK("kclr", "kC", 57, _ky_clear )
+#define Key_ctab __TK("kctab", "kt", 58, _ky_ctab )
+#define Key_dc __TK("kdch1", "kD", 59, _ky_dc )
+#define Key_dl __TK("kdl1", "kL", 60, _ky_dl )
+#define Key_down __TK("kcud1", "kd", 61, _ky_down )
+#define Key_eic __TK("krmir", "kM", 62, _ky_eic )
+#define Key_eol __TK("kel", "kE", 63, _ky_eol )
+#define Key_eos __TK("ked", "kS", 64, _ky_eos )
+#define Key_f0 __TK("kf0", "k0", 65, _ky_f0 )
+#define Key_f1 __TK("kf1", "k1", 66, _ky_f1 )
+#define Key_f10 __TK("kf10", "k;", 67, _ky_f10 )
+#define Key_f2 __TK("kf2", "k2", 68, _ky_f2 )
+#define Key_f3 __TK("kf3", "k3", 69, _ky_f3 )
+#define Key_f4 __TK("kf4", "k4", 70, _ky_f4 )
+#define Key_f5 __TK("kf5", "k5", 71, _ky_f5 )
+#define Key_f6 __TK("kf6", "k6", 72, _ky_f6 )
+#define Key_f7 __TK("kf7", "k7", 73, _ky_f7 )
+#define Key_f8 __TK("kf8", "k8", 74, _ky_f8 )
+#define Key_f9 __TK("kf9", "k9", 75, _ky_f9 )
+#define Key_home __TK("khome", "kh", 76, _ky_home )
+#define Key_ic __TK("kich1", "kI", 77, _ky_ic )
+#define Key_il __TK("kil1", "kA", 78, _ky_il )
+#define Key_left __TK("kcub1", "kl", 79, _ky_left )
+#define Key_ll __TK("kll", "kH", 80, _ky_ll )
+#define Key_npage __TK("knp", "kN", 81, _ky_npage )
+#define Key_ppage __TK("kpp", "kP", 82, _ky_ppage )
+#define Key_right __TK("kcuf1", "kr", 83, _ky_right )
+#define Key_sf __TK("kind", "kF", 84, _ky_sf )
+#define Key_sr __TK("kri", "kR", 85, _ky_sr )
+#define Key_stab __TK("khts", "kT", 86, _ky_stab )
+#define Key_up __TK("kcuu1", "ku", 87, _ky_up )
+#define Key_a1 __TK("ka1", "K1", 139, _ky_a1 )
+#define Key_a3 __TK("ka3", "K3", 140, _ky_a3 )
+#define Key_b2 __TK("kb2", "K2", 141, _ky_b2 )
+#define Key_c1 __TK("kc1", "K4", 142, _ky_c1 )
+#define Key_c3 __TK("kc3", "K5", 143, _ky_c3 )
+#define Key_btab __TK("kcbt", "kB", 148, _ky_btab )
+#define Key_beg __TK("kbeg", "@1", 158, _ky_beg )
+#define Key_cancel __TK("kcan", "@2", 159, _ky_cancel )
+#define Key_close __TK("kclo", "@3", 160, _ky_close )
+#define Key_command __TK("kcmd", "@4", 161, _ky_command )
+#define Key_copy __TK("kcpy", "@5", 162, _ky_copy )
+#define Key_create __TK("kcrt", "@6", 163, _ky_create )
+#define Key_end __TK("kend", "@7", 164, _ky_end )
+#define Key_enter __TK("kent", "@8", 165, _ky_enter )
+#define Key_exit __TK("kext", "@9", 166, _ky_exit )
+#define Key_find __TK("kfnd", "@0", 167, _ky_find )
+#define Key_help __TK("khlp", "%1", 168, _ky_help )
+#define Key_mark __TK("kmrk", "%2", 169, _ky_mark )
+#define Key_message __TK("kmsg", "%3", 170, _ky_message )
+#define Key_move __TK("kmov", "%4", 171, _ky_move )
+#define Key_next __TK("knxt", "%5", 172, _ky_next )
+#define Key_open __TK("kopn", "%6", 173, _ky_open )
+#define Key_options __TK("kopt", "%7", 174, _ky_options )
+#define Key_previous __TK("kprv", "%8", 175, _ky_previous )
+#define Key_print __TK("kprt", "%9", 176, _ky_print )
+#define Key_redo __TK("krdo", "%0", 177, _ky_redo )
+#define Key_reference __TK("kref", "&1", 178, _ky_reference )
+#define Key_refresh __TK("krfr", "&2", 179, _ky_refresh )
+#define Key_replace __TK("krpl", "&3", 180, _ky_replace )
+#define Key_restart __TK("krst", "&4", 181, _ky_restart )
+#define Key_resume __TK("kres", "&5", 182, _ky_resume )
+#define Key_save __TK("ksav", "&6", 183, _ky_save )
+#define Key_suspend __TK("kspd", "&7", 184, _ky_suspend )
+#define Key_undo __TK("kund", "&8", 185, _ky_undo )
+#define Key_sbeg __TK("kBEG", "&9", 186, _ky_sbeg )
+#define Key_scancel __TK("kCAN", "&0", 187, _ky_scancel )
+#define Key_scommand __TK("kCMD", "*1", 188, _ky_scommand )
+#define Key_scopy __TK("kCPY", "*2", 189, _ky_scopy )
+#define Key_screate __TK("kCRT", "*3", 190, _ky_screate )
+#define Key_sdc __TK("kDC", "*4", 191, _ky_sdc )
+#define Key_sdl __TK("kDL", "*5", 192, _ky_sdl )
+#define Key_select __TK("kslt", "*6", 193, _ky_select )
+#define Key_send __TK("kEND", "*7", 194, _ky_send )
+#define Key_seol __TK("kEOL", "*8", 195, _ky_seol )
+#define Key_sexit __TK("kEXT", "*9", 196, _ky_sexit )
+#define Key_sfind __TK("kFND", "*0", 197, _ky_sfind )
+#define Key_shelp __TK("kHLP", "#1", 198, _ky_shelp )
+#define Key_shome __TK("kHOM", "#2", 199, _ky_shome )
+#define Key_sic __TK("kIC", "#3", 200, _ky_sic )
+#define Key_sleft __TK("kLFT", "#4", 201, _ky_sleft )
+#define Key_smessage __TK("kMSG", "%a", 202, _ky_smessage )
+#define Key_smove __TK("kMOV", "%b", 203, _ky_smove )
+#define Key_snext __TK("kNXT", "%c", 204, _ky_snext )
+#define Key_soptions __TK("kOPT", "%d", 205, _ky_soptions )
+#define Key_sprevious __TK("kPRV", "%e", 206, _ky_sprevious )
+#define Key_sprint __TK("kPRT", "%f", 207, _ky_sprint )
+#define Key_sredo __TK("kRDO", "%g", 208, _ky_sredo )
+#define Key_sreplace __TK("kRPL", "%h", 209, _ky_sreplace )
+#define Key_sright __TK("kRIT", "%i", 210, _ky_sright )
+#define Key_srsume __TK("kRES", "%j", 211, _ky_srsume )
+#define Key_ssave __TK("kSAV", "!1", 212, _ky_ssave )
+#define Key_ssuspend __TK("kSPD", "!2", 213, _ky_ssuspend )
+#define Key_sundo __TK("kUND", "!3", 214, _ky_sundo )
+#define Key_f11 __TK("kf11", "F1", 216, _ky_f11 )
+#define Key_f12 __TK("kf12", "F2", 217, _ky_f12 )
+#define Key_f13 __TK("kf13", "F3", 218, _ky_f13 )
+#define Key_f14 __TK("kf14", "F4", 219, _ky_f14 )
+#define Key_f15 __TK("kf15", "F5", 220, _ky_f15 )
+#define Key_f16 __TK("kf16", "F6", 221, _ky_f16 )
+#define Key_f17 __TK("kf17", "F7", 222, _ky_f17 )
+#define Key_f18 __TK("kf18", "F8", 223, _ky_f18 )
+#define Key_f19 __TK("kf19", "F9", 224, _ky_f19 )
+#define Key_f20 __TK("kf20", "FA", 225, _ky_f20 )
+#define Key_f21 __TK("kf21", "FB", 226, _ky_f21 )
+#define Key_f22 __TK("kf22", "FC", 227, _ky_f22 )
+#define Key_f23 __TK("kf23", "FD", 228, _ky_f23 )
+#define Key_f24 __TK("kf24", "FE", 229, _ky_f24 )
+#define Key_f25 __TK("kf25", "FF", 230, _ky_f25 )
+#define Key_f26 __TK("kf26", "FG", 231, _ky_f26 )
+#define Key_f27 __TK("kf27", "FH", 232, _ky_f27 )
+#define Key_f28 __TK("kf28", "FI", 233, _ky_f28 )
+#define Key_f29 __TK("kf29", "FJ", 234, _ky_f29 )
+#define Key_f30 __TK("kf30", "FK", 235, _ky_f30 )
+#define Key_f31 __TK("kf31", "FL", 236, _ky_f31 )
+#define Key_f32 __TK("kf32", "FM", 237, _ky_f32 )
+#define Key_f33 __TK("kf33", "FN", 238, _ky_f33 )
+#define Key_f34 __TK("kf34", "FO", 239, _ky_f34 )
+#define Key_f35 __TK("kf35", "FP", 240, _ky_f35 )
+#define Key_f36 __TK("kf36", "FQ", 241, _ky_f36 )
+#define Key_f37 __TK("kf37", "FR", 242, _ky_f37 )
+#define Key_f38 __TK("kf38", "FS", 243, _ky_f38 )
+#define Key_f39 __TK("kf39", "FT", 244, _ky_f39 )
+#define Key_f40 __TK("kf40", "FU", 245, _ky_f40 )
+#define Key_f41 __TK("kf41", "FV", 246, _ky_f41 )
+#define Key_f42 __TK("kf42", "FW", 247, _ky_f42 )
+#define Key_f43 __TK("kf43", "FX", 248, _ky_f43 )
+#define Key_f44 __TK("kf44", "FY", 249, _ky_f44 )
+#define Key_f45 __TK("kf45", "FZ", 250, _ky_f45 )
+#define Key_f46 __TK("kf46", "Fa", 251, _ky_f46 )
+#define Key_f47 __TK("kf47", "Fb", 252, _ky_f47 )
+#define Key_f48 __TK("kf48", "Fc", 253, _ky_f48 )
+#define Key_f49 __TK("kf49", "Fd", 254, _ky_f49 )
+#define Key_f50 __TK("kf50", "Fe", 255, _ky_f50 )
+#define Key_f51 __TK("kf51", "Ff", 256, _ky_f51 )
+#define Key_f52 __TK("kf52", "Fg", 257, _ky_f52 )
+#define Key_f53 __TK("kf53", "Fh", 258, _ky_f53 )
+#define Key_f54 __TK("kf54", "Fi", 259, _ky_f54 )
+#define Key_f55 __TK("kf55", "Fj", 260, _ky_f55 )
+#define Key_f56 __TK("kf56", "Fk", 261, _ky_f56 )
+#define Key_f57 __TK("kf57", "Fl", 262, _ky_f57 )
+#define Key_f58 __TK("kf58", "Fm", 263, _ky_f58 )
+#define Key_f59 __TK("kf59", "Fn", 264, _ky_f59 )
+#define Key_f60 __TK("kf60", "Fo", 265, _ky_f60 )
+#define Key_f61 __TK("kf61", "Fp", 266, _ky_f61 )
+#define Key_f62 __TK("kf62", "Fq", 267, _ky_f62 )
+#define Key_f63 __TK("kf63", "Fr", 268, _ky_f63 )
+
+/* }}} */
+
+#ifdef __QNX__
+
+/* don't force pre-defining of base keys under QNX */
+#define FORCE_BASE_KEY_DEFS 0
+
+/* OS specific key aliases */
+#define Key_alt_a Key_clear
+#define Key_alt_b Key_stab
+#define Key_alt_c Key_close
+#define Key_alt_d Key_catab
+#define Key_alt_e Key_message
+#define Key_alt_f Key_find
+#define Key_alt_g Key_refresh
+#define Key_alt_h Key_help
+#define Key_alt_i Key_move
+#define Key_alt_j Key_restart
+#define Key_alt_k Key_options
+#define Key_alt_l Key_reference
+#define Key_alt_m Key_mark
+#define Key_alt_n Key_sbeg
+#define Key_alt_o Key_open
+#define Key_alt_p Key_resume
+#define Key_alt_q Key_save
+#define Key_alt_r Key_replace
+#define Key_alt_s Key_scopy
+#define Key_alt_t Key_screate
+#define Key_alt_u Key_undo
+#define Key_alt_v Key_sdl
+#define Key_alt_w Key_sexit
+#define Key_alt_x Key_sfind
+#define Key_alt_y Key_shelp
+#define Key_alt_z Key_soptions
+
+#define Key_ctl_enter Key_enter
+#define Key_ctl_tab Key_ctab
+
+#define Key_alt_tab Key_ctl_tab /* map ALT-TAB to CTRL-TAB */
+#define Key_alt_enter Key_ctl_enter /* map ALT-ENTER to CTRL-ENTER */
+
+#ifdef __USE_QNX_TI
+
+/* OS/implementation specific key-define struct */
+typedef struct qnx_key_define_s {
+ int mc_code;
+ int str_idx;
+} qnx_key_define_t;
+
+/* define current xtra_key_define_t (enable OS/implementation) */
+#define xtra_key_define_t qnx_key_define_t
+
+#endif /* __USE_QNX_TI */
+
+#endif /* __QNX__ */
+
+
+#ifdef xtra_key_define_t
+
+#ifndef FORCE_BASE_KEY_DEFS
+#define FORCE_BASE_KEY_DEFS 0
+#endif
+
+/* general key define table */
+xtra_key_define_t xtra_key_defines[] = {
+#if FORCE_BASE_KEY_DEFS
+ {KEY_BACKSPACE,Key_backspace},
+ {KEY_LEFT, Key_left },
+ {KEY_RIGHT, Key_right },
+ {KEY_UP, Key_up },
+ {KEY_DOWN, Key_down },
+ {KEY_NPAGE, Key_npage },
+ {KEY_PPAGE, Key_ppage },
+ {KEY_HOME, Key_home },
+ {KEY_END, Key_end },
+ {KEY_DC, Key_dc },
+ {KEY_IC, Key_ic },
+ {KEY_F(1), Key_f1 },
+ {KEY_F(2), Key_f2 },
+ {KEY_F(3), Key_f3 },
+ {KEY_F(4), Key_f4 },
+ {KEY_F(5), Key_f5 },
+ {KEY_F(6), Key_f6 },
+ {KEY_F(7), Key_f7 },
+ {KEY_F(8), Key_f8 },
+ {KEY_F(9), Key_f9 },
+ {KEY_F(10), Key_f10 },
+ {KEY_F(11), Key_f11 },
+ {KEY_F(12), Key_f12 },
+ {KEY_F(13), Key_f13 },
+ {KEY_F(14), Key_f14 },
+ {KEY_F(15), Key_f15 },
+ {KEY_F(16), Key_f16 },
+ {KEY_F(17), Key_f17 },
+ {KEY_F(18), Key_f18 },
+ {KEY_F(19), Key_f19 },
+ {KEY_F(20), Key_f20 },
+#endif
+ {ALT('a'), Key_alt_a },
+ {ALT('b'), Key_alt_b },
+ {ALT('c'), Key_alt_c },
+ {ALT('d'), Key_alt_d },
+ {ALT('e'), Key_alt_e },
+ {ALT('f'), Key_alt_f },
+ {ALT('g'), Key_alt_g },
+ {ALT('h'), Key_alt_h },
+ {ALT('i'), Key_alt_i },
+ {ALT('j'), Key_alt_j },
+ {ALT('k'), Key_alt_k },
+ {ALT('l'), Key_alt_l },
+ {ALT('m'), Key_alt_m },
+ {ALT('n'), Key_alt_n },
+ {ALT('o'), Key_alt_o },
+ {ALT('p'), Key_alt_p },
+ {ALT('q'), Key_alt_q },
+ {ALT('r'), Key_alt_r },
+ {ALT('s'), Key_alt_s },
+ {ALT('t'), Key_alt_t },
+ {ALT('u'), Key_alt_u },
+ {ALT('v'), Key_alt_v },
+ {ALT('w'), Key_alt_w },
+ {ALT('x'), Key_alt_x },
+ {ALT('y'), Key_alt_y },
+ {ALT('z'), Key_alt_z },
+
+ {ALT('\n'), Key_alt_enter},
+ {ALT('\t'), Key_alt_tab }
+};
+
+#endif /* xtra_key_define_t */
+
+
+#ifdef __QNX__
+
+#ifdef __USE_QNX_TI
+
+#define __CT (__cur_term)
+#define __QTISOFFS(_qtisx) (((charoffset*)(&__CT->_strs))[_qtisx])
+#define __QTISSTR(_qtisx) (&__CT->_strtab[0]+__QTISOFFS(_qtisx))
+
+void load_qnx_key_defines (void)
+{
+ static int _qnx_keys_defined = 0;
+
+ if (!_qnx_keys_defined) {
+ int idx, str_idx;
+ int term_setup_ok;
+
+ __setupterm(NULL, fileno(stdout), &term_setup_ok);
+ if (term_setup_ok != 1)
+ return;
+
+ for (idx = 0;
+ idx < sizeof(xtra_key_defines) / sizeof(xtra_key_defines[0]);
+ idx++) {
+ str_idx = xtra_key_defines[idx].str_idx;
+ if (__QTISOFFS(str_idx)) {
+ if (*__QTISSTR(str_idx)) {
+ define_sequence(
+ xtra_key_defines[idx].mc_code,
+ __QTISSTR(str_idx),
+ MCKEY_NOACTION);
+ }
+ }
+ }
+ _qnx_keys_defined = 1;
+ }
+}
+
+#endif /* __USE_QNX_TI */
+
+#endif /* __QNX__ */
+
+
+/* called from key.c/init_key() */
+void load_xtra_key_defines (void)
+{
+#ifdef __QNX__
+ load_qnx_key_defines();
+#endif
+}
+
+
--- /dev/null
+/* Panel layout module for the Midnight Commander
+ Copyright (C) 1995 the Free Software Foundation
+
+ Written: 1995 Janne Kukonlehto
+ 1995 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/param.h> /* Required by tree.h */
+#include <sys/types.h>
+#include <sys/stat.h>
+#if (!defined(__IBMC__) && !defined(__IBMCPP__)) && !defined(OS2_NT)
+# include <termios.h>
+ /*
+ * If TIOCGWINSZ supported, make it available here, because window-
+ * resizing code depends on it...
+ */
+# ifdef __QNX__ /* Maybe not only QNX-specific... */
+# include <sys/ioctl.h>
+# endif
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <signal.h>
+#include "tty.h"
+#include "mad.h"
+#include "util.h" /* Needed for the externs */
+#include "win.h"
+#include "color.h"
+#include "key.h"
+
+#include "dlg.h"
+#include "widget.h"
+#include "command.h"
+
+#include "dialog.h" /* For do_refresh() */
+#include "profile.h" /* For sync_profiles() */
+#include "mouse.h"
+#define WANT_WIDGETS
+#include "main.h"
+#include "subshell.h" /* For use_subshell and resize_subshell() */
+#include "tree.h"
+#include "menu.h"
+
+/* Needed for the extern declarations of integer parameters */
+#include "dir.h"
+#include "panel.h" /* The Panel widget */
+#include "file.h"
+#include "cons.saver.h"
+#include "layout.h"
+#include "info.h" /* The Info widget */
+#include "view.h" /* The view widget */
+
+#define WANT_DEFAULTS
+#include "setup.h" /* For save_setup() */
+
+#include "x.h"
+
+/* "$Id: layout.c,v 1.1 2001/12/30 09:55:24 sedwards Exp $" */
+
+/* Controls the display of the rotating dash on the verbose mode */
+int nice_rotating_dash = 1;
+
+/* If set, then we have to call the layout_change routine from main */
+int layout_do_change = 0;
+
+/* Set if the panels are split horizontally */
+int horizontal_split = 0;
+
+/* Set if the window has changed it's size */
+int winch_flag = 0;
+
+/* Set if the split is the same */
+int equal_split = 1;
+
+/* First panel size if the panel are not split equally */
+int first_panel_size = 0;
+
+/* The number of output lines shown (if available) */
+int output_lines = 0;
+
+/* Set if the command prompt is to be displayed */
+int command_prompt = 1;
+
+/* Set if the nice and usefull keybar is visible */
+int keybar_visible = 1;
+
+/* Set if the nice message (hint) bar is visible */
+int message_visible = 1;
+
+/* Set if you want the message bar shown in xterm title bar to save space */
+int xterm_hintbar = 0;
+
+/* The starting line for the output of the subprogram */
+int output_start_y = 0;
+
+/* The maximum number of views managed by the set_display_type routine */
+/* Must be at least two (for current and other). Please note that until */
+/* Janne gets around this, we will only manage two of them :-) */
+#define MAX_VIEWS 2
+
+struct {
+ int type;
+ Widget *widget;
+} panels [MAX_VIEWS];
+
+/* These variables are used to avoid updating the information unless */
+/* we need it */
+static int old_first_panel_size;
+static int old_horizontal_split;
+static int old_output_lines;
+
+/* Internal variables */
+static int _horizontal_split;
+static int _equal_split;
+static int _first_panel_size;
+static int _menubar_visible;
+static int _output_lines;
+static int _command_prompt;
+static int _keybar_visible;
+static int _message_visible;
+static int _xterm_hintbar;
+static int _permission_mode;
+static int _filetype_mode;
+
+static int height;
+
+#define MINWIDTH 10
+#define MINHEIGHT 5
+
+#define BY 12
+
+#define B_2LEFT B_USER
+#define B_2RIGHT B_USER + 1
+#define B_PLUS B_USER + 2
+#define B_MINUS B_USER + 3
+
+static Dlg_head *layout_dlg;
+
+static char *s_split_direction [2] = {
+ N_("&Vertical"),
+ N_("&Horizontal")
+};
+WRadio *radio_widget;
+
+static struct {
+ char *text;
+ int *variable;
+ WCheck *widget;
+ char *tkname;
+} check_options [] = {
+ { N_("&Xterm hintbar"), &xterm_hintbar, 0, "h" },
+ { N_("h&Intbar visible"), &message_visible, 0, "v" },
+ { N_("&Keybar visible"), &keybar_visible, 0, "k" },
+ { N_("command &Prompt"), &command_prompt, 0, "p" },
+ { N_("show &Mini status"), &show_mini_info, 0, "m" },
+ { N_("menu&Bar visible"), &menubar_visible, 0, "me" },
+ { N_("&Equal split"), &equal_split, 0, "eq" },
+ { N_("pe&Rmissions"), &permission_mode, 0, "pr" },
+ { N_("&File types"), &filetype_mode, 0, "ft" },
+ { 0, 0, 0, 0 }
+};
+
+static int first_width, second_width;
+static char *layout_title, *title1, *title2, *title3, *output_lines_label;
+
+static WButton *bleft_widget, *bright_widget;
+
+static void _check_split (void)
+{
+ if (_horizontal_split){
+ if (_equal_split)
+ _first_panel_size = height / 2;
+ else if (_first_panel_size < MINHEIGHT)
+ _first_panel_size = MINHEIGHT;
+ else if (_first_panel_size > height - MINHEIGHT)
+ _first_panel_size = height - MINHEIGHT;
+ } else {
+ if (_equal_split)
+ _first_panel_size = COLS / 2;
+ else if (_first_panel_size < MINWIDTH)
+ _first_panel_size = MINWIDTH;
+ else if (_first_panel_size > COLS - MINWIDTH)
+ _first_panel_size = COLS - MINWIDTH;
+ }
+}
+
+static void update_split (void)
+{
+ /* Check split has to be done before testing if it changed, since
+ it can change due to calling _check_split() as well*/
+ _check_split ();
+
+ /* To avoid setting the cursor to the wrong place */
+ if ((old_first_panel_size == _first_panel_size) &&
+ (old_horizontal_split == _horizontal_split)){
+ return;
+ }
+
+ old_first_panel_size = _first_panel_size;
+ old_horizontal_split = _horizontal_split;
+
+ attrset (COLOR_NORMAL);
+ dlg_move (layout_dlg, 6, 6);
+ printw ("%03d", _first_panel_size);
+ dlg_move (layout_dlg, 6, 18);
+ if (_horizontal_split)
+ printw ("%03d", height - _first_panel_size);
+ else
+ printw ("%03d", COLS - _first_panel_size);
+}
+
+static int b2left_cback (int action, void *data)
+{
+ if (_equal_split){
+ /* Turn equal split off */
+ _equal_split = 0;
+ check_options [6].widget->state = check_options [6].widget->state & ~C_BOOL;
+ dlg_select_widget (layout_dlg, check_options [6].widget);
+ dlg_select_widget (layout_dlg, bleft_widget);
+ }
+ _first_panel_size++;
+ return 0;
+}
+
+static int b2right_cback (int action, void *data)
+{
+ if (_equal_split){
+ /* Turn equal split off */
+ _equal_split = 0;
+ check_options [6].widget->state = check_options [6].widget->state & ~C_BOOL;
+ dlg_select_widget (layout_dlg, check_options [6].widget);
+ dlg_select_widget (layout_dlg, bright_widget);
+ }
+ _first_panel_size--;
+ return 0;
+}
+
+static int bplus_cback (int action, void *data)
+{
+ if (_output_lines < 99)
+ _output_lines++;
+ return 0;
+}
+
+static int bminus_cback (int action, void *data)
+{
+ if (_output_lines > 0)
+ _output_lines--;
+ return 0;
+}
+
+static int layout_callback (struct Dlg_head *h, int Id, int Msg)
+{
+ switch (Msg){
+ case DLG_DRAW:
+#ifndef HAVE_X
+ /*When repainting the whole dialog (e.g. with C-l) we have to
+ update everything*/
+ old_first_panel_size = -1;
+ old_horizontal_split = -1;
+ old_output_lines = -1;
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 1, 2, h->lines - 2, h->cols - 4);
+ draw_box (h, 2, 4, 6, first_width);
+ draw_box (h, 8, 4, 4, first_width);
+ draw_box (h, 2, 5 + first_width, 10, second_width);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 1, (h->cols - strlen(layout_title))/2);
+ addstr (layout_title);
+ dlg_move (h, 2, 5);
+ addstr (title1);
+ dlg_move (h, 8, 5);
+ addstr (title2);
+ dlg_move (h, 2, 6 + first_width);
+ addstr (title3);
+ update_split ();
+ dlg_move (h, 6, 13);
+ addch ('=');
+ if (console_flag){
+ if (old_output_lines != _output_lines){
+ old_output_lines = _output_lines;
+ attrset (COLOR_NORMAL);
+ dlg_move (h, 9, 16 + first_width);
+ addstr (output_lines_label);
+ dlg_move (h, 9, 10 + first_width);
+ printw ("%02d", _output_lines);
+ }
+ }
+#endif
+ break;
+
+ case DLG_POST_KEY:
+ _filetype_mode = check_options [8].widget->state & C_BOOL;
+ _permission_mode = check_options [7].widget->state & C_BOOL;
+#ifndef HAVE_X
+ _equal_split = check_options [6].widget->state & C_BOOL;
+#endif
+ _menubar_visible = check_options [5].widget->state & C_BOOL;
+ _command_prompt = check_options [4].widget->state & C_BOOL;
+ _keybar_visible = check_options [2].widget->state & C_BOOL;
+ _message_visible = check_options [1].widget->state & C_BOOL;
+ _xterm_hintbar = check_options [0].widget->state & C_BOOL;
+ if (console_flag){
+ int minimum;
+ if (_output_lines < 0)
+ _output_lines = 0;
+ height = LINES - _keybar_visible - _command_prompt -
+ _menubar_visible - _output_lines - _message_visible;
+ if (_message_visible && _xterm_hintbar && xterm_flag) height++;
+ minimum = MINHEIGHT * (1 + _horizontal_split);
+ if (height < minimum){
+ _output_lines -= minimum - height;
+ height = minimum;
+ }
+ } else {
+ height = LINES - _keybar_visible - _command_prompt -
+ _menubar_visible - _output_lines - _message_visible;
+ if (_message_visible && _xterm_hintbar && xterm_flag) height++;
+ }
+ if (_horizontal_split != radio_widget->sel){
+ _horizontal_split = radio_widget->sel;
+ if (_horizontal_split)
+ _first_panel_size = height / 2;
+ else
+ _first_panel_size = COLS / 2;
+ }
+ update_split ();
+ if (console_flag){
+ if (old_output_lines != _output_lines){
+ old_output_lines = _output_lines;
+ attrset (COLOR_NORMAL);
+ dlg_move (h, 9, 10 + first_width);
+ printw ("%02d", _output_lines);
+ }
+ }
+ break;
+
+ case DLG_END:
+ break;
+ }
+ return 0;
+}
+
+static void init_layout (void)
+{
+ static int i18n_layt_flag = 0;
+ static int b1, b2, b3;
+ int i = sizeof (s_split_direction) / sizeof(char*) ;
+ char* ok_button = _("&Ok");
+ char* cancel_button = _("&Cancel");
+ char* save_button = _("&Save");
+
+ if (!i18n_layt_flag)
+ {
+ register int l1;
+
+ first_width = 19; /* length of line with '<' '>' buttons */
+
+ layout_title = _(" Layout ");
+ title1 = _(" Panel split ");
+ title2 = _(" Highlight... ");
+ title3 = _(" Other options ");
+ output_lines_label = _("output lines");
+
+ while (i--)
+ {
+ s_split_direction [i] = _(s_split_direction [i]);
+ l1 = strlen (s_split_direction [i]) + 7;
+ if (l1 > first_width)
+ first_width = l1;
+ }
+
+ for (i = 0; i <= 8; i++)
+ {
+ check_options[i].text = _(check_options[i].text);
+ l1 = strlen (check_options[i].text) + 7;
+ if (l1 > first_width)
+ first_width = l1;
+ }
+
+ l1 = strlen (title1) + 1;
+ if (l1 > first_width)
+ first_width = l1;
+
+ l1 = strlen (title2) + 1;
+ if (l1 > first_width)
+ first_width = l1;
+
+
+ second_width = strlen (title3) + 1;
+ for (i = 0; i < 6; i++)
+ {
+ check_options[i].text = _(check_options[i].text);
+ l1 = strlen (check_options[i].text) + 7;
+ if (l1 > second_width)
+ second_width = l1;
+ }
+ if (console_flag)
+ {
+ l1 = strlen (output_lines_label) + 13;
+ if (l1 > second_width)
+ second_width = l1;
+ }
+
+ /*
+ * alex@bcs.zp.ua:
+ * To be completely correct, one need to check if layout_title
+ * does not exceed dialog length and total length of 3 buttons
+ * allows their placement in one row. But assuming this dialog
+ * is wide enough, I don't include such a tests.
+ *
+ * Now the last thing to do - properly space buttons...
+ */
+ l1 = 11 + strlen (ok_button) /* 14 - all brackets and inner space */
+ + strlen (save_button) /* notice: it is 3 char less because */
+ + strlen (cancel_button); /* of '&' char in button text */
+
+ i = (first_width + second_width - l1) / 4;
+ b1 = 5 + i;
+ b2 = b1 + strlen(ok_button) + i + 6;
+ b3 = b2 + strlen(save_button) + i + 4;
+
+ i18n_layt_flag = 1;
+ }
+
+ layout_dlg = create_dlg (0, 0, 15, first_width + second_width + 9,
+ dialog_colors, layout_callback,
+ "[Layout]", "layout", DLG_CENTER | DLG_GRID);
+
+ x_set_dialog_title (layout_dlg, _("Layout"));
+
+ add_widgetl (layout_dlg,
+ button_new (BY, b3, B_CANCEL, NORMAL_BUTTON, cancel_button, 0, 0, "c"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (layout_dlg,
+ button_new (BY, b2, B_EXIT, NORMAL_BUTTON, save_button, 0, 0, "s"),
+ XV_WLAY_RIGHTOF);
+ add_widgetl (layout_dlg,
+ button_new (BY, b1, B_ENTER, DEFPUSH_BUTTON, ok_button, 0, 0, "o"),
+ XV_WLAY_CENTERROW);
+#ifndef HAVE_X
+ if (console_flag){
+ add_widget (layout_dlg,
+ button_new (9, 12 + first_width, B_MINUS, NARROW_BUTTON, "&-",
+ bminus_cback, 0, NULL));
+ add_widget (layout_dlg,
+ button_new (9, 7 + first_width, B_PLUS, NARROW_BUTTON, "&+",
+ bplus_cback, 0, NULL));
+ }
+#endif
+
+#define XTRACT(i) *check_options[i].variable, check_options[i].text, check_options[i].tkname
+
+ for (i = 0; i < 6; i++){
+ check_options [i].widget = check_new (8 - i, 7 + first_width, XTRACT(i));
+ add_widgetl (layout_dlg, check_options [i].widget, XV_WLAY_BELOWCLOSE);
+ }
+#ifdef HAVE_XVIEW
+ add_widgetl (layout_dlg, label_new (2, 7 + first_width, _("Other options"), "oo"),
+ XV_WLAY_NEXTCOLUMN);
+ add_widgetl (layout_dlg, label_new (8, 5, _("Highlight..."), "hl"),
+ XV_WLAY_NEXTCOLUMN);
+ add_widgetl (layout_dlg, label_new (2, 5, _("Panel split"), "ps"),
+ XV_WLAY_NEXTCOLUMN);
+#endif
+ check_options [8].widget = check_new (10, 6, XTRACT(8));
+ add_widgetl (layout_dlg, check_options [8].widget, XV_WLAY_BELOWCLOSE);
+ check_options [7].widget = check_new (9, 6, XTRACT(7));
+ add_widgetl (layout_dlg, check_options [7].widget, XV_WLAY_BELOWCLOSE);
+
+ _filetype_mode = filetype_mode;
+ _permission_mode = permission_mode;
+ _equal_split = equal_split;
+ _menubar_visible = menubar_visible;
+ _command_prompt = command_prompt;
+ _keybar_visible = keybar_visible;
+ _message_visible = message_visible;
+ _xterm_hintbar = xterm_hintbar;
+#ifndef HAVE_X
+ bright_widget = button_new(6, 15, B_2RIGHT, NARROW_BUTTON, "&>", b2right_cback, 0, ">");
+ add_widgetl (layout_dlg, bright_widget, XV_WLAY_RIGHTOF);
+ bleft_widget = button_new (6, 9, B_2LEFT, NARROW_BUTTON, "&<", b2left_cback, 0, "<");
+ add_widgetl (layout_dlg, bleft_widget, XV_WLAY_RIGHTOF);
+ check_options [6].widget = check_new (5, 6, XTRACT(6));
+#endif
+ old_first_panel_size = -1;
+ old_horizontal_split = -1;
+ old_output_lines = -1;
+
+ _first_panel_size = first_panel_size;
+ _output_lines = output_lines;
+#ifndef HAVE_X
+ add_widget (layout_dlg, check_options [6].widget);
+ radio_widget = radio_new (3, 6, 2, s_split_direction, 1, "r");
+ add_widget (layout_dlg, radio_widget);
+ radio_widget->sel = horizontal_split;
+#endif
+}
+
+void layout_change (void)
+{
+ setup_panels ();
+ layout_do_change = 0;
+#ifndef HAVE_X
+ /* re-init the menu, because perhaps there was a change in the way
+ how the panel are split (horizontal/vertical). */
+ done_menu();
+ init_menu();
+ menubar_arrange(the_menubar);
+#endif
+}
+
+void layout_cmd (void)
+{
+ int result;
+ int i;
+
+ init_layout ();
+ run_dlg (layout_dlg);
+ result = layout_dlg->ret_value;
+
+ if (result == B_ENTER || result == B_EXIT){
+ for (i = 0; check_options [i].text; i++)
+ if (check_options [i].widget)
+ *check_options [i].variable = check_options [i].widget->state & C_BOOL;
+#ifndef HAVE_X
+ horizontal_split = radio_widget->sel;
+ first_panel_size = _first_panel_size;
+ output_lines = _output_lines;
+ layout_do_change = 1;
+#endif
+ }
+ if (result == B_EXIT){
+ save_layout ();
+ sync_profiles ();
+ }
+
+ destroy_dlg (layout_dlg);
+ if (layout_do_change)
+ layout_change ();
+}
+
+static void check_split (void)
+{
+ if (horizontal_split){
+ if (equal_split)
+ first_panel_size = height / 2;
+ else if (first_panel_size < MINHEIGHT)
+ first_panel_size = MINHEIGHT;
+ else if (first_panel_size > height - MINHEIGHT)
+ first_panel_size = height - MINHEIGHT;
+ } else {
+ if (equal_split)
+ first_panel_size = COLS / 2;
+ else if (first_panel_size < MINWIDTH)
+ first_panel_size = MINWIDTH;
+ else if (first_panel_size > COLS - MINWIDTH)
+ first_panel_size = COLS - MINWIDTH;
+ }
+}
+
+int panel_event (Gpm_Event *event, WPanel *panel);
+int menu_bar_event (Gpm_Event *event, void *);
+extern char *prompt;
+
+#ifndef HAVE_X
+#ifdef HAVE_SLANG
+void init_curses ()
+{
+ extern int force_ugly_line_drawing;
+ extern int SLtt_Has_Alt_Charset;
+ SLtt_get_terminfo ();
+#ifndef OS2_NT
+ if (force_ugly_line_drawing)
+ SLtt_Has_Alt_Charset = 0;
+#endif
+ SLsmg_init_smg ();
+ do_enter_ca_mode ();
+ init_colors ();
+ keypad (stdscr, TRUE);
+ nodelay (stdscr, FALSE);
+}
+#else
+void init_curses (void)
+{
+ initscr();
+ if (!status_using_ncurses)
+ do_enter_ca_mode ();
+ mc_raw_mode ();
+ noecho ();
+ keypad (stdscr, TRUE);
+ nodelay (stdscr, FALSE);
+ init_colors ();
+}
+#endif /* ! HAVE_SLANG */
+void done_screen ()
+{
+ if (!(quit & SUBSHELL_EXIT))
+ clr_scr ();
+ reset_shell_mode ();
+ mc_noraw_mode ();
+ if (use_mouse_p)
+ shut_mouse ();
+ keypad (stdscr, FALSE);
+}
+#else
+void init_curses ()
+{
+}
+void done_screen ()
+{
+}
+#endif /* HAVE_X */
+
+void panel_do_cols (int index)
+{
+ if (get_display_type (index) == view_listing)
+ set_panel_formats ((WPanel *) panels [index].widget);
+ else {
+ panel_update_cols (panels [index].widget, frame_half);
+ }
+}
+
+#ifdef HAVE_X
+void
+setup_panels (void)
+{
+ Widget *w = panels [0].widget;
+
+ winput_set_origin (&cmdline->input, 0, 60);
+
+ /* Only needed by the startup code */
+ if (panels [0].type == view_listing){
+ x_panel_set_size (0);
+ }
+
+ if (panels [1].type == view_listing){
+ x_panel_set_size (1);
+ }
+
+ load_hint ();
+#ifdef HAVE_XVIEW
+ panel_do_cols (0);
+ panel_do_cols (1);
+#endif
+}
+
+#else
+
+void setup_panels (void)
+{
+ int start_y;
+ int promptl; /* the prompt len */
+
+ if (console_flag){
+ int minimum;
+ if (output_lines < 0)
+ output_lines = 0;
+ height = LINES - keybar_visible - command_prompt - menubar_visible
+ - output_lines - message_visible;
+ if (message_visible && xterm_hintbar && xterm_flag) height++;
+ minimum = MINHEIGHT * (1 + horizontal_split);
+ if (height < minimum){
+ output_lines -= minimum - height;
+ height = minimum;
+ }
+ } else {
+ height = LINES - menubar_visible - command_prompt -
+ keybar_visible - message_visible;
+ if (message_visible && xterm_hintbar && xterm_flag) height++;
+ }
+ check_split ();
+ start_y = menubar_visible;
+
+ /* The column computing is defered until panel_do_cols */
+ if (horizontal_split){
+ widget_set_size (panels [0].widget, start_y, 0,
+ first_panel_size, 0);
+
+ widget_set_size (panels [1].widget, start_y+first_panel_size, 0,
+ height-first_panel_size, 0);
+ } else {
+ int first_x = first_panel_size;
+
+ widget_set_size (panels [0].widget, start_y, 0,
+ height, 0);
+
+ widget_set_size (panels [1].widget, start_y, first_x,
+ height, 0);
+
+ }
+ panel_do_cols (0);
+ panel_do_cols (1);
+
+ promptl = strlen (prompt);
+
+ widget_set_size (&the_menubar->widget, 0, 0, 1, COLS);
+
+ if (command_prompt) {
+ widget_set_size (&cmdline->input.widget,
+ LINES-1-keybar_visible, promptl,
+ 1, COLS-promptl-(keybar_visible ? 0 : 1));
+ winput_set_origin (&cmdline->input, promptl, COLS-promptl-(keybar_visible ? 0 : 1));
+ widget_set_size (&the_prompt->widget,
+ LINES-1-keybar_visible, 0,
+ 1, promptl);
+ } else {
+ widget_set_size (&cmdline->input.widget, 0, 0, 0, 0);
+ winput_set_origin (&cmdline->input, 0, 0);
+ widget_set_size (&the_prompt->widget, LINES, COLS, 0, 0);
+ }
+
+ widget_set_size (&the_bar->widget, LINES-1, 0, 1, COLS);
+ the_bar->visible = keybar_visible;
+
+ /* Output window */
+ if (console_flag && output_lines){
+ output_start_y = LINES -command_prompt-keybar_visible-
+ output_lines;
+ show_console_contents (output_start_y,
+ LINES-output_lines-keybar_visible-1,
+ LINES-keybar_visible-1);
+ }
+ if (message_visible && (!xterm_hintbar || !xterm_flag))
+ widget_set_size (&the_hint->widget, height+start_y, 0, 1,COLS);
+ else
+ widget_set_size (&the_hint->widget, 0, 0, 0, 0);
+
+ load_hint ();
+}
+#endif
+
+void flag_winch (int dummy)
+{
+ winch_flag = 1;
+}
+
+void edit_adjust_size (Dlg_head * h);
+
+#ifdef PORT_NEEDS_CHANGE_SCREEN_SIZE
+void low_level_change_screen_size (void)
+{
+#if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
+#if defined TIOCGWINSZ && !defined SCO_FLAVOR
+ struct winsize winsz;
+
+ winsz.ws_col = winsz.ws_row = 0;
+ /* Ioctl on the STDIN_FILENO */
+ ioctl (0, TIOCGWINSZ, &winsz);
+ if (winsz.ws_col && winsz.ws_row){
+#if defined(NCURSES_VERSION) && defined(HAVE_RESIZETERM)
+ resizeterm(winsz.ws_row, winsz.ws_col);
+ clearok(stdscr,TRUE); /* FIXME: sigwinch's should use a semaphore! */
+#else
+ COLS = winsz.ws_col;
+ LINES = winsz.ws_row;
+#endif
+#ifdef HAVE_SUBSHELL_SUPPORT
+ resize_subshell ();
+#endif
+ }
+#endif /* TIOCGWINSZ && !SCO_FLAVOR */
+#endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
+}
+
+void change_screen_size (void)
+{
+#if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
+#if defined TIOCGWINSZ && !defined SCO_FLAVOR
+ extern Dlg_head *view_dlg;
+ extern Dlg_head *edit_dlg;
+
+#ifndef NCURSES_VERSION
+ mc_noraw_mode ();
+ endwin ();
+#endif
+ low_level_change_screen_size ();
+ check_split ();
+#ifndef NCURSES_VERSION
+ /* XSI Curses spec states that portable applications shall not invoke
+ * initscr() more than once. This kludge could be done within the scope
+ * of the specification by using endwin followed by a refresh (in fact,
+ * more than one curses implementation does this); it is guaranteed to work
+ * only with slang.
+ */
+ init_curses ();
+#endif
+ setup_panels ();
+ if (current_dlg == view_dlg)
+ view_adjust_size (view_dlg);
+#ifdef USE_INTERNAL_EDIT
+ if (current_dlg == edit_dlg)
+ edit_adjust_size (edit_dlg);
+#endif
+
+#ifdef RESIZABLE_MENUBAR
+ menubar_arrange(the_menubar);
+#endif
+
+ /* Now, force the redraw */
+ do_refresh ();
+ touchwin (stdscr);
+#endif /* TIOCGWINSZ && !SCO_FLAVOR */
+#endif /* defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4 */
+ winch_flag = 0;
+}
+#endif /* HAVE_X */
+
+extern int verbose;
+static int ok_to_refresh = 1;
+
+void use_dash (int flag)
+{
+ if (flag)
+ ok_to_refresh++;
+ else
+ ok_to_refresh--;
+}
+
+void set_hintbar(char *str)
+{
+#ifndef HAVE_X
+ if (xterm_flag && xterm_hintbar) {
+ fprintf (stderr, "\33]0;mc - %s\7", str);
+ } else
+#endif
+ {
+ label_set_text (the_hint, str);
+ if (ok_to_refresh > 0)
+ refresh();
+ }
+}
+
+void print_vfs_message(char *msg, ...)
+{
+ va_list ap;
+ char str[128];
+
+ va_start(ap, msg);
+ vsprintf(str, msg, ap);
+ va_end(ap);
+ if (midnight_shutdown || !the_hint || !the_hint->widget.parent)
+ return;
+
+ if (message_visible || (xterm_flag && xterm_hintbar)) {
+ set_hintbar(str);
+ }
+}
+
+void rotate_dash (void)
+{
+#ifndef HAVE_X
+ static char rotating_dash [] = "|/-\\";
+ static int pos = 0;
+
+ if (!nice_rotating_dash || (ok_to_refresh <= 0))
+ return;
+
+ if (pos >= sizeof (rotating_dash)-1)
+ pos = 0;
+ move (0, COLS-1);
+ addch (rotating_dash [pos]);
+ mc_refresh ();
+ pos++;
+#endif
+}
+
+void remove_dash (void)
+{
+#ifndef HAVE_X
+ if (!nice_rotating_dash)
+ return;
+
+ /* Currently, it's much nicer with the CPU to do this instead of
+ calling do_refresh.
+
+ I should implement a routine called invalidate_region that would
+ send a draw message only to the affected views. But for now
+ this is fine.
+ */
+
+ move (0, COLS-1);
+ addch (' ');
+#endif
+}
+
+char *get_nth_panel_name (int num)
+{
+ static char buffer [20];
+
+ if (!num)
+ return "New Left Panel";
+ else if (num == 1)
+ return "New Right Panel";
+ else {
+ sprintf (buffer, "%ith Panel", num);
+ return buffer;
+ }
+}
+
+/* I wonder if I should start to use the folding mode than Dugan uses */
+/* */
+/* This is the centralized managing of the panel display types */
+/* This routine takes care of destroying and creating new widgets */
+/* Please note that it could manage MAX_VIEWS, not just left and right */
+/* Currently nothing in the code takes advantage of this and has hard- */
+/* coded values for two panels only */
+
+/* Set the num-th panel to the view type: type */
+/* This routine also keeps at least one WPanel object in the screen */
+/* since a lot of routines depend on the current_panel variable */
+void set_display_type (int num, int type)
+{
+ int x, y, cols, lines;
+ int the_other; /* Index to the other panel */
+ char *file_name = 0; /* For Quick view */
+ Widget *new_widget, *old_widget;
+ WPanel *the_other_panel;
+
+ x =y = cols = lines = 0;
+ old_widget = 0;
+ if (num >= MAX_VIEWS){
+ fprintf (stderr, "Could not allocate more that %d views\n", MAX_VIEWS);
+ abort ();
+ }
+
+ /* Check that we will have a WPanel * at least */
+ the_other = 0;
+ if (type != view_listing){
+ the_other = num == 0 ? 1 : 0;
+
+ if (panels [the_other].type != view_listing)
+ return;
+
+ }
+
+ /* Get rid of it */
+ if (panels [num].widget){
+ Widget *w = panels [num].widget;
+ WPanel *panel = (WPanel *) panels [num].widget;
+
+ x = w->x;
+ y = w->y;
+ cols = w->cols;
+ lines = w->lines;
+ old_widget = panels [num].widget;
+
+ if (panels [num].type == view_listing){
+ if (panel->frame_size == frame_full && type != view_listing){
+ cols = COLS - first_panel_size;
+ if (num == 1)
+ x = first_panel_size;
+ }
+ }
+#ifdef HAVE_TK
+ tk_evalf ("container_clean %s", panel->widget.wcontainer);
+#endif
+ }
+
+ new_widget = 0;
+
+ switch (type){
+ case view_listing:
+ new_widget = (Widget *) panel_new (get_nth_panel_name (num));
+ break;
+
+ case view_info:
+ new_widget = (Widget *) info_new ();
+
+ break;
+
+ case view_tree:
+ new_widget = (Widget *) tree_new (1, 0, 0, 0, 0);
+ break;
+
+ case view_quick:
+ new_widget = (Widget *) view_new (0, 0, 0, 0, 1);
+ the_other_panel = (WPanel *) panels [the_other].widget;
+ if (the_other_panel)
+ file_name =
+ the_other_panel->dir.list[the_other_panel->selected].fname;
+ else
+ file_name = "";
+
+ view_init ((WView *) new_widget, 0, file_name, 0);
+ break;
+ }
+ panels [num].type = type;
+ panels [num].widget = (Widget *) new_widget;
+
+ /* We set the same size the old widget had */
+ widget_set_size ((Widget *) new_widget, y, x, lines, cols);
+
+ /* We wanna the new widget at the same position */
+ /* XView sets wcontainer to !0 <- Not XView, but we, when we create it */
+ /* Ok, the XView support code does it */
+ if (old_widget && old_widget->wcontainer){
+ new_widget->wcontainer = old_widget->wcontainer;
+ new_widget->area = old_widget->area;
+ }
+
+ /* We use replace to keep the circular list of the dialog in the */
+ /* same state. Maybe we could just kill it and then replace it */
+ if (midnight_dlg && old_widget){
+ dlg_replace_widget (midnight_dlg, old_widget, panels [num].widget);
+ }
+ if (type == view_listing){
+ if (num == 0)
+ left_panel = (WPanel *) new_widget;
+ else
+ right_panel = (WPanel *) new_widget;
+ }
+
+ if (type == view_tree)
+ the_tree = (WTree *) new_widget;
+
+ /* Prevent current_panel's value from becoming invalid.
+ * It's just a quick hack to prevent segfaults. Comment out and
+ * try following:
+ * - select left panel
+ * - invoke menue left/tree
+ * - as long as you stay in the left panel almost everything that uses
+ * cpanel causes segfault, e.g. C-Enter, C-x c, ...
+ */
+
+ if (type != view_listing)
+ if (cpanel == (WPanel *) old_widget)
+ current_panel = num == 0 ? right_panel : left_panel;
+}
+
+#ifndef HAVE_XVIEW
+/* This routine is deeply sticked to the two panels idea.
+ What should it do in more panels. ANSWER - don't use it
+ in any multiple panels environment. */
+void swap_panels ()
+{
+ Widget tmp;
+ Widget *tmp_widget;
+ WPanel panel;
+ WPanel *panel1, *panel2;
+ int tmp_type;
+
+#if 0
+#ifdef HAVE_PORTABLE_TOKEN_PASTING
+#define panelswap(e) panel.##e = panel1->##e; panel1->##e = panel2->##e; panel2->##e = panel.##e;
+#define panelswapstr(e) strcpy (panel.##e, panel1->##e); strcpy (panel1->##e, panel2->##e); strcpy (panel2->##e, panel.##e);
+#else
+#define panelswap(e) panel./**/e = panel1->/**/e; panel1->/**/e = panel2->/**/e; panel2->/**/e = panel./**/e;
+#define panelswapstr(e) strcpy (panel./**/e, panel1->/**/e); strcpy (panel1->/**/e, panel2->/**/e); strcpy (panel2->/**/e, panel./**/e);
+#endif
+#endif
+
+#define panelswap(x) panel. x = panel1-> x; panel1-> x = panel2-> x; panel2-> x = panel. x;
+
+#define panelswapstr(e) strcpy (panel. e, panel1-> e); \
+ strcpy (panel1-> e, panel2-> e); \
+ strcpy (panel2-> e, panel. e);
+ panel1 = (WPanel *) panels [0].widget;
+ panel2 = (WPanel *) panels [1].widget;
+ if (panels [0].type == view_listing && panels [1].type == view_listing) {
+ /* Change everything except format/sort/panel_name etc. */
+ panelswap (dir);
+ panelswap (active);
+ panelswapstr (cwd);
+ panelswapstr (lwd);
+ panelswap (count);
+ panelswap (marked);
+ panelswap (dirs_marked);
+ panelswap (total);
+ panelswap (top_file);
+ panelswap (selected);
+ panelswap (is_panelized);
+ panelswap (dir_stat);
+
+ panel1->searching = 0;
+ panel2->searching = 0;
+ if (cpanel == panel1)
+ current_panel = panel2;
+ else
+ current_panel = panel1;
+ if (midnight_dlg->current->widget == panels [0].widget)
+ dlg_select_widget (midnight_dlg, (void *) panels [1].widget);
+ else if (midnight_dlg->current->widget == panels [1].widget)
+ dlg_select_widget (midnight_dlg, (void *) panels [0].widget);
+ } else {
+ WPanel *tmp_panel;
+
+ tmp_panel=right_panel;
+ right_panel=left_panel;
+ left_panel=tmp_panel;
+
+ if (panels [0].type == view_listing) {
+ if (!strcmp (panel1->panel_name, get_nth_panel_name (0))) {
+ free (panel1->panel_name);
+ panel1->panel_name = strdup (get_nth_panel_name (1));
+ }
+ }
+ if (panels [1].type == view_listing) {
+ if (!strcmp (panel2->panel_name, get_nth_panel_name (1))) {
+ free (panel2->panel_name);
+ panel2->panel_name = strdup (get_nth_panel_name (0));
+ }
+ }
+
+ tmp.x = panels [0].widget->x;
+ tmp.y = panels [0].widget->y;
+ tmp.cols = panels [0].widget->cols;
+ tmp.lines = panels [0].widget->lines;
+
+ panels [0].widget->x = panels [1].widget->x;
+ panels [0].widget->y = panels [1].widget->y;
+ panels [0].widget->cols = panels [1].widget->cols;
+ panels [0].widget->lines = panels [1].widget->lines;
+
+ panels [1].widget->x = tmp.x;
+ panels [1].widget->y = tmp.y;
+ panels [1].widget->cols = tmp.cols;
+ panels [1].widget->lines = tmp.lines;
+
+ tmp_widget = panels [0].widget;
+ panels [0].widget = panels [1].widget;
+ panels [1].widget = tmp_widget;
+ tmp_type = panels [0].type;
+ panels [0].type = panels [1].type;
+ panels [1].type = tmp_type;
+ }
+}
+#endif
+
+int get_display_type (int index)
+{
+ return panels [index].type;
+}
+
+Widget *get_panel_widget (int index)
+{
+ return panels [index].widget;
+}
+
+int get_current_index (void)
+{
+ if (panels [0].widget == ((Widget *) cpanel))
+ return 0;
+ else
+ return 1;
+}
+
+int get_other_index (void)
+{
+ return !get_current_index ();
+}
+
+/* Returns the view type for the current panel/view */
+int get_current_type (void)
+{
+ if (panels [0].widget == (Widget *) cpanel)
+ return panels [0].type;
+ else
+ return panels [1].type;
+}
+
+/* Returns the view type of the unselected panel */
+int get_other_type (void)
+{
+ if (panels [0].widget == (Widget *) cpanel)
+ return panels [1].type;
+ else
+ return panels [0].type;
+}
+
--- /dev/null
+#ifndef __LAYOUT_H
+#define __LAYOUT_H
+
+#include "dlg.h"
+
+void layout_cmd (void);
+void init_curses (void);
+void done_screen (void);
+void setup_panels (void);
+void destroy_panels (void);
+void move_resize_panel (void);
+void flag_winch (int dummy);
+void change_screen_size (void);
+void layout_change (void);
+void set_display_type (int num, int type);
+void swap_panels (void);
+int get_display_type (int index);
+int get_current_type (void);
+int get_other_type (void);
+int get_current_index (void);
+int get_other_index (void);
+char *get_nth_panel_name (int num);
+
+Widget *get_panel_widget (int index);
+
+void set_hintbar (char *str);
+
+extern int winch_flag;
+extern int equal_split;
+extern int first_panel_size;
+extern int output_lines;
+extern int command_prompt;
+extern int keybar_visible;
+extern int layout_do_change;
+extern int output_start_y;
+extern int message_visible;
+extern int xterm_hintbar;
+
+extern int horizontal_split;
+extern int nice_rotating_dash;
+
+#endif /* __LAYOUT_H */
--- /dev/null
+/* Learn keys
+ Copyright (C) 1995 The Free Software Foundation
+
+ Written by: 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> /* For malloc() */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include "tty.h"
+#include "mad.h"
+#include "util.h" /* Needed for the externs and convert_controls */
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+#include "profile.h" /* Save profile */
+#include "key.h"
+#include "setup.h"
+#include "main.h"
+#define UX 4
+#define UY 3
+
+#define BY UY + 17
+
+#define ROWS 13
+#define COLSHIFT 23
+
+#define BUTTONS 2
+
+struct {
+ int ret_cmd, flags, y, x;
+ unsigned int hotkey;
+ char *text;
+} learn_but[BUTTONS] = {
+ { B_CANCEL, NORMAL_BUTTON, 0, 39, 'C', N_("&Cancel") },
+ { B_ENTER, DEFPUSH_BUTTON, 0, 25, 'S', N_("&Save") }
+};
+
+static Dlg_head *learn_dlg;
+typedef struct {
+ Widget *button;
+ Widget *label;
+ int ok;
+ char *sequence;
+} learnkey;
+static learnkey *learnkeys = NULL;
+static int learn_total;
+static int learnok;
+static int learnchanged;
+static char* learn_title = N_(" Learn keys ");
+
+#ifndef HAVE_X
+static void learn_refresh (void)
+{
+ attrset (COLOR_NORMAL);
+ dlg_erase (learn_dlg);
+
+ draw_box (learn_dlg, 1, 2, learn_dlg->lines - 2, learn_dlg->cols - 4);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (learn_dlg, 1, (learn_dlg->cols - strlen (learn_title)) / 2);
+ addstr (learn_title);
+}
+#endif
+
+static int learn_button (int action, void *param)
+{
+ unsigned char *seq;
+ Dlg_head *d = message (D_INSERT | 1, _(" Teach me a key "),
+_("Please press the %s\n"
+"and then wait until this message disappears.\n\n"
+"Then, press it again to see if OK appears\n"
+"next to its button.\n\n"
+"If you want to escape, press a single Escape key\n"
+"and wait as well."),
+ _(key_name_conv_tab [action - B_USER].longname));
+ mc_refresh ();
+ if (learnkeys [action - B_USER].sequence != NULL) {
+ free (learnkeys [action - B_USER].sequence);
+ learnkeys [action - B_USER].sequence = NULL;
+ }
+ seq = learn_key ();
+
+ if (seq){
+ /* Esc hides the dialog and do not allow definitions of
+ * regular characters
+ */
+ if (*seq && strcmp (seq, "\\e") && strcmp (seq, "\\e\\e")
+ && strcmp (seq, "^m" )
+ && (seq [1] || (*seq < ' ' || *seq > '~'))){
+
+ learnchanged = 1;
+ learnkeys [action - B_USER].sequence = seq;
+ seq = convert_controls (seq);
+ define_sequence (key_name_conv_tab [action - B_USER].code, seq,
+ MCKEY_NOACTION);
+ } else {
+ message (0, _(" Cannot accept this key "),
+ _(" You have entered \"%s\""), seq);
+ }
+
+ free (seq);
+ }
+
+ dlg_run_done (d);
+ destroy_dlg (d);
+ dlg_select_widget (learn_dlg, learnkeys [action - B_USER].button);
+ return 0; /* Do not kill learn_dlg */
+}
+
+static int learn_move (int right)
+{
+ int i, totalcols;
+
+ totalcols = (learn_total - 1) / ROWS + 1;
+ for (i = 0; i < learn_total; i++)
+ if (learnkeys [i].button == learn_dlg->current->widget) {
+ if (right) {
+ if (i < learn_total - ROWS)
+ i += ROWS;
+ else
+ i %= ROWS;
+ } else {
+ if (i / ROWS)
+ i -= ROWS;
+ else if (i + (totalcols - 1) * ROWS >= learn_total)
+ i += (totalcols - 2) * ROWS;
+ else
+ i += (totalcols - 1) * ROWS;
+ }
+ dlg_select_widget (learn_dlg, (void *) learnkeys [i].button);
+ return 1;
+ }
+ return 0;
+}
+
+static int learn_check_key (int c)
+{
+ int i;
+
+ for (i = 0; i < learn_total; i++) {
+ if (key_name_conv_tab [i].code == c) {
+ if (!learnkeys [i].ok) {
+ dlg_select_widget (learn_dlg, learnkeys [i].button);
+ label_set_text ((WLabel *) learnkeys [i].label,
+ _("OK"));
+ learnkeys [i].ok = 1;
+ learnok++;
+ if (learnok >= learn_total) {
+ learn_dlg->ret_value = B_CANCEL;
+ if (learnchanged) {
+ if (query_dialog (learn_title,
+ _("It seems that all your keys already\n"
+ "work fine. That's great."),
+ 1, 2, _("&Save"), _("&Discard")) == 0)
+ learn_dlg->ret_value = B_ENTER;
+ } else {
+ message (1, learn_title,
+ _("Great! You have a complete terminal database!\n"
+ "All your keys work well."));
+ }
+ dlg_stop (learn_dlg);
+ }
+ return 1;
+ }
+ }
+ }
+ switch (c) {
+ case KEY_LEFT:
+ case 'h':
+ return learn_move (0);
+ case KEY_RIGHT:
+ case 'l':
+ return learn_move (1);
+ case 'j':
+ dlg_one_down (learn_dlg);
+ return 1;
+ case 'k':
+ dlg_one_up (learn_dlg);
+ return 1;
+ }
+
+ /* Prevent from disappearing if a non-defined sequence is pressed
+ and contains s or c. Use ALT('s') or ALT('c'). */
+ if (c < 255 && isalpha(c))
+ {
+ c = toupper(c);
+ for (i = 0; i < BUTTONS; i++)
+ if (c == learn_but [i].hotkey)
+ return 1;
+ }
+
+ return 0;
+}
+
+static int learn_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+ case DLG_DRAW:
+ learn_refresh ();
+ break;
+ case DLG_KEY:
+ return learn_check_key (Par);
+ }
+ return 0;
+}
+
+static void init_learn (void)
+{
+ int x, y, i, j;
+ key_code_name_t *key;
+ char buffer [22];
+ static int i18n_flag = 0;
+
+ do_refresh ();
+
+#ifdef ENABLE_NLS
+ if (!i18n_flag)
+ {
+ char* cp;
+
+ learn_but [0].text = _(learn_but [0].text);
+ learn_but [0].x = 78 / 2 + 4;
+
+ learn_but [1].text = _(learn_but [1].text);
+ learn_but [1].x = 78 / 2 - (strlen (learn_but [1].text) + 9);
+
+ for (i = 0; i < BUTTONS; i++)
+ {
+ cp = strchr(learn_but [i].text, '&');
+ if (cp != NULL && *++cp != '\0')
+ learn_but [i].hotkey = toupper(*cp);
+ }
+
+ learn_title = _(learn_title);
+ i18n_flag = 1;
+ }
+#endif /* ENABLE_NLS */
+
+ learn_dlg = create_dlg (0, 0, 23, 78, dialog_colors,
+ learn_callback, "[Learn keys]", "Learn keys",
+ DLG_CENTER);
+ x_set_dialog_title (learn_dlg, _("Learn keys"));
+
+#define XTRACT(i) BY+learn_but[i].y, learn_but[i].x, learn_but[i].ret_cmd, learn_but[i].flags, _(learn_but[i].text), 0, 0, NULL
+
+ for (i = 0; i < BUTTONS; i++)
+ add_widget (learn_dlg, button_new (XTRACT (i)));
+
+ x = UX;
+ y = UY;
+ for (key = key_name_conv_tab, j = 0; key->name != NULL &&
+ strcmp (key->name, "kpleft"); key++, j++);
+ learnkeys = (learnkey *) xmalloc (sizeof (learnkey) * j, "Learn keys");
+ x += ((j - 1) / ROWS) * COLSHIFT;
+ y += (j - 1) % ROWS;
+ learn_total = j;
+ learnok = 0;
+ learnchanged = 0;
+ for (i = j - 1, key = key_name_conv_tab + j - 1; i >= 0; i--, key--) {
+ learnkeys [i].ok = 0;
+ learnkeys [i].sequence = NULL;
+ sprintf (buffer, "%-16s", _(key->longname));
+ add_widget (learn_dlg, learnkeys [i].button = (Widget *)
+ button_new (y, x, B_USER + i, NARROW_BUTTON, buffer, learn_button, 0, NULL));
+ add_widget (learn_dlg, learnkeys [i].label = (Widget *)
+ label_new (y, x + 19, "", NULL));
+ if (i % 13)
+ y--;
+ else {
+ x -= COLSHIFT;
+ y = UY + ROWS - 1;
+ }
+ }
+ add_widget (learn_dlg,
+ label_new (UY+14, 5, _("Press all the keys mentioned here. After you have done it, check"), NULL));
+ add_widget (learn_dlg,
+ label_new (UY+15, 5, _("which keys are not marked with OK. Press space on the missing"), NULL));
+ add_widget (learn_dlg,
+ label_new (UY+16, 5, _("key, or click with the mouse to define it. Move around with Tab."), NULL));
+}
+
+static void learn_done (void)
+{
+ destroy_dlg (learn_dlg);
+ repaint_screen ();
+}
+
+void learn_save (void)
+{
+ int i;
+ int profile_changed = 0;
+ char *section = copy_strings ("terminal:", getenv ("TERM"), NULL);
+
+ for (i = 0; i < learn_total; i++) {
+ if (learnkeys [i].sequence != NULL) {
+ profile_changed = 1;
+ WritePrivateProfileString (section, key_name_conv_tab [i].name,
+ learnkeys [i].sequence, profile_name);
+ }
+ }
+
+ /* On the one hand no good idea to save the complete setup but
+ * without 'Auto save setup' the new key-definitions will not be
+ * saved unless the user does an 'Options/Save Setup'.
+ * On the other hand a save-button that does not save anything to
+ * disk is much worse.
+ */
+ if (profile_changed)
+ sync_profiles ();
+}
+
+void learn_keys (void)
+{
+ int save_old_esc_mode = old_esc_mode;
+ int save_alternate_plus_minus = alternate_plus_minus;
+
+ old_esc_mode = 0; /* old_esc_mode cannot work in learn keys dialog */
+ alternate_plus_minus = 1; /* don't translate KP_ADD, KP_SUBTRACT and
+ KP_MULTIPLY to '+', '-' and '*' in
+ correct_key_code */
+#ifndef HAVE_X
+ application_keypad_mode ();
+#endif
+ init_learn ();
+
+ run_dlg (learn_dlg);
+
+ old_esc_mode = save_old_esc_mode;
+ alternate_plus_minus = save_alternate_plus_minus;
+
+#ifndef HAVE_X
+ if (!alternate_plus_minus)
+ numeric_keypad_mode ();
+
+#endif
+
+ switch (learn_dlg->ret_value) {
+ case B_ENTER:
+ learn_save ();
+ break;
+ }
+
+ learn_done ();
+}
+
--- /dev/null
+#ifndef __LEARN_H
+#define __LEARN_H
+
+void learn_keys (void);
+
+#endif
--- /dev/null
+/* Directory panel listing format editor -- for the Midnight Commander
+ Copyright (C) 1994, 1995 The Free Software Foundation
+
+ Written by: 1994 Radek Doulik
+ 1995 Janne Kukonlehto
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> /* For malloc() */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifndef OS2_NT
+# include <grp.h>
+# include <pwd.h>
+#endif
+#include "tty.h"
+#include "mad.h"
+#include "util.h" /* Needed for the externs */
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+#include "wtools.h"
+
+/* Needed for the extern declarations of integer parameters */
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "main.h"
+#include "global.h"
+#include "listmode.h"
+
+#define UX 5
+#define UY 2
+
+#define BX 5
+#define BY 18
+
+#define BUTTONS 4
+#define LABELS 4
+#define B_ADD B_USER
+#define B_REMOVE B_USER + 1
+
+static WListbox *l_listmode;
+
+static Dlg_head *listmode_dlg;
+
+static WLabel *pname;
+
+static char *listmode_section = "[Listing format edit]";
+
+static char *s_genwidth [2] = {"Half width", "Full width"};
+WRadio *radio_genwidth;
+static char *s_columns [2] = {"One column", "Two columns"};
+WRadio *radio_columns;
+static char *s_justify [3] =
+{"Left justified", "Default justification", "Right justified"};
+WRadio *radio_justify;
+static char *s_itemwidth [3] =
+{"Free width", "Fixed width", "Growable width"};
+WRadio *radio_itemwidth;
+
+struct {
+ int ret_cmd, flags, y, x;
+ char *text;
+} listmode_but[BUTTONS] = {
+ { B_CANCEL, NORMAL_BUTTON, 0, 53, "&Cancel" },
+ { B_ADD, NORMAL_BUTTON, 0, 22, "&Add item"},
+ { B_REMOVE, NORMAL_BUTTON, 0, 10, "&Remove" },
+ { B_ENTER, DEFPUSH_BUTTON, 0, 0, "&Ok" },
+};
+
+#define B_PLUS B_USER
+#define B_MINUS B_USER+1
+
+struct {
+ int y, x;
+ char *text;
+} listmode_text [LABELS] = {
+ { UY, UX + 1, " General options " },
+ { UY+4, UX+1, " Items "},
+ { UY+4, UX+21, " Item options" },
+ { UY+13, UX+22, "Item width:" }
+};
+
+#ifndef HAVE_X
+static void listmode_refresh (void)
+{
+ attrset (COLOR_NORMAL);
+ dlg_erase (listmode_dlg);
+
+ draw_box (listmode_dlg, 1, 2, 20, 70);
+ draw_box (listmode_dlg, UY, UX, 4, 63);
+ draw_box (listmode_dlg, UY + 4, UX, 11, 18);
+ draw_box (listmode_dlg, UY + 4, UX+20, 11, 43);
+}
+#endif
+
+static int bplus_cback (int action, void *data)
+{
+ return 0;
+}
+
+static int bminus_cback (int action, void *data)
+{
+ return 0;
+}
+
+static int listmode_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+#ifndef HAVE_X
+ case DLG_DRAW:
+ listmode_refresh ();
+ break;
+#endif
+
+ case DLG_POST_KEY:
+ /* fall */
+ case DLG_INIT:
+ attrset (COLOR_NORMAL);
+ dlg_move (h, UY+13, UX+35);
+ printw ("%02d", 99);
+ attrset (MENU_ENTRY_COLOR);
+ break;
+ }
+ return 0;
+}
+
+static int l_call (void *data)
+{
+ return 1;
+}
+
+static void init_listmode (char *oldlistformat)
+{
+ int i;
+ char *s;
+ int format_width = 0;
+ int format_columns = 0;
+
+ do_refresh ();
+
+ listmode_dlg = create_dlg (0, 0, 22, 74, dialog_colors,
+ listmode_callback, listmode_section, "listmode",
+ DLG_CENTER);
+ x_set_dialog_title (listmode_dlg, "Listing format edit");
+
+#define XTRACT(i) BY+listmode_but[i].y, BX+listmode_but[i].x, listmode_but[i].ret_cmd, listmode_but[i].flags, listmode_but[i].text, 0, 0, NULL
+
+ for (i = 0; i < BUTTONS; i++)
+ add_widgetl (listmode_dlg, button_new (XTRACT (i)), (i == BUTTONS - 1) ?
+ XV_WLAY_CENTERROW : XV_WLAY_RIGHTOF);
+
+ /* We add the labels. */
+ for (i = 0; i < LABELS; i++){
+ pname = label_new (listmode_text [i].y,
+ listmode_text [i].x, listmode_text [i].text, NULL);
+ add_widget (listmode_dlg, pname);
+ }
+
+ add_widget (listmode_dlg, button_new (UY+13, UX+37, B_MINUS, NORMAL_BUTTON,
+ "&-", bminus_cback, 0, NULL));
+ add_widget (listmode_dlg, button_new (UY+13, UX+34, B_PLUS, NORMAL_BUTTON,
+ "&+", bplus_cback, 0, NULL));
+ radio_itemwidth = radio_new (UY+9, UX+22, 3, s_itemwidth, 1, NULL);
+ add_widget (listmode_dlg, radio_itemwidth);
+ radio_itemwidth = 0;
+ radio_justify = radio_new (UY+5, UX+22, 3, s_justify, 1, NULL);
+ add_widget (listmode_dlg, radio_justify);
+ radio_justify->sel = 1;
+
+ /* get new listbox */
+ l_listmode = listbox_new (UY + 5, UX + 1, 16, 9, 0, l_call, NULL);
+
+ if (strncmp (oldlistformat, "full ", 5) == 0){
+ format_width = 1;
+ oldlistformat += 5;
+ }
+ if (strncmp (oldlistformat, "half ", 5) == 0){
+ oldlistformat += 5;
+ }
+ if (strncmp (oldlistformat, "2 ", 2) == 0){
+ format_columns = 1;
+ oldlistformat += 2;
+ }
+ if (strncmp (oldlistformat, "1 ", 2) == 0){
+ oldlistformat += 2;
+ }
+ s = strtok (oldlistformat, ",");
+
+ while (s){
+ listbox_add_item (l_listmode, 0, 0, s, NULL);
+ s = strtok (NULL, ",");
+ }
+
+ /* add listbox to the dialogs */
+ add_widgetl (listmode_dlg, l_listmode, XV_WLAY_EXTENDWIDTH);
+
+ radio_columns = radio_new (UY+1, UX+32, 2, s_columns, 1, NULL);
+ add_widget (listmode_dlg, radio_columns);
+ radio_columns->sel = format_columns;
+ radio_genwidth = radio_new (UY+1, UX+2, 2, s_genwidth, 1, NULL);
+ add_widget (listmode_dlg, radio_genwidth);
+ radio_genwidth->sel = format_width;
+}
+
+static void listmode_done (void)
+{
+ destroy_dlg (listmode_dlg);
+ if (0)
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ repaint_screen ();
+}
+
+char *select_new_item (void)
+{
+ /* NOTE: The following array of possible items must match the
+ formats array in screen.c. Better approach might be to make the
+ formats array global */
+ char *possible_items [] =
+ { "name", "size", "type", "mtime", "perm", "mode", "|", "nlink",
+ "owner", "group", "atime", "ctime", "space", "mark",
+ "inode", NULL };
+
+ int i;
+ Listbox *mylistbox;
+
+ mylistbox = create_listbox_window (12, 20, " Add listing format item ", listmode_section);
+ for (i = 0; possible_items [i]; i++){
+ listbox_add_item (mylistbox->list, 0, 0, possible_items [i], NULL);
+ }
+
+ i = run_listbox (mylistbox);
+ if (i >= 0)
+ return possible_items [i];
+ else
+ return NULL;
+}
+
+char *collect_new_format (void)
+{
+ char *newformat;
+ int i;
+ char *last;
+ char *text, *extra;
+
+ newformat = xmalloc (1024, "collect_new_format");
+ if (radio_genwidth->sel)
+ strcpy (newformat, "full ");
+ else
+ strcpy (newformat, "half ");
+ if (radio_columns->sel)
+ strcat (newformat, "2 ");
+ last = NULL;
+ for (i = 0;;i++){
+ listbox_select_by_number (l_listmode, i);
+ listbox_get_current (l_listmode, &text, &extra);
+ if (text == last)
+ break;
+ if (last != NULL)
+ strcat (newformat, ",");
+ strcat (newformat, text);
+ last = text;
+ }
+ return newformat;
+}
+
+char *listmode_edit (char *oldlistformat)
+{
+ char *newformat = NULL;
+ char *s;
+
+ s = strdup (oldlistformat);
+ init_listmode (s);
+ free (s);
+
+ while (newformat == NULL)
+ {
+ /* display file info */
+ attrset (SELECTED_COLOR);
+
+ run_dlg (listmode_dlg);
+
+ switch (listmode_dlg->ret_value) {
+ case B_CANCEL:
+ newformat = strdup (oldlistformat);
+ break;
+
+ case B_ADD:
+ s = select_new_item ();
+ if (s)
+ listbox_add_item (l_listmode, 0, 0, s, NULL);
+ break;
+
+ case B_REMOVE:
+ listbox_remove_current (l_listmode, 0);
+ break;
+
+ case B_ENTER:
+ newformat = collect_new_format ();
+ break;
+ }
+ }
+
+ listmode_done ();
+ return newformat;
+}
--- /dev/null
+#ifndef __LISTMODE_H
+#define __LISTMODE_H
+
+char *listmode_edit (char*);
+
+#endif
--- /dev/null
+/* The Memory Allocation Debugging system
+ Copyright (C) 1994 Janne Kukonlehto.
+
+ To use MAD define HAVE_MAD and include "mad.h" in all the *.c files.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "mad.h"
+#undef malloc
+#undef calloc
+#undef realloc
+#undef xmalloc
+#undef strdup
+#undef free
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <signal.h> /* For kill() */
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* For getpid() */
+#endif
+
+/* Here to avoid non empty translation units */
+#ifdef HAVE_MAD
+
+/* Maximum number of memory area handles,
+ increase this if you run out of handles */
+#define MAD_MAX_AREAS 3000
+/* Maximum file name length */
+#define MAD_MAX_FILE 50
+/* Signature for detecting overwrites */
+#define MAD_SIGNATURE (('M'<<24)|('a'<<16)|('d'<<8)|('S'))
+
+typedef struct {
+ int in_use;
+ long *start_sig;
+ char file [MAD_MAX_FILE];
+ int line;
+ void *data;
+ long *end_sig;
+} mad_mem_area;
+
+static mad_mem_area mem_areas [MAD_MAX_AREAS];
+void *watch_free_pointer = 0;
+
+/* This function is only called by the mad_check function */
+static void mad_abort (char *message, int area, char *file, int line)
+{
+ fprintf (stderr, "MAD: %s in area %d.\r\n", message, area);
+ fprintf (stderr, " Allocated in file \"%s\" at line %d.\r\n",
+ mem_areas [area].file, mem_areas [area].line);
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ fprintf (stderr, "MAD: Core dumping...\r\n");
+ kill (getpid (), 3);
+}
+
+/* Checks all the allocated memory areas.
+ This is called everytime memory is allocated or freed.
+ You can also call it anytime you think memory might be corrupted. */
+void mad_check (char *file, int line)
+{
+ int i;
+
+ for (i = 0; i < MAD_MAX_AREAS; i++){
+ if (! mem_areas [i].in_use)
+ continue;
+ if (*(mem_areas [i].start_sig) != MAD_SIGNATURE)
+ mad_abort ("Overwrite error: Bad start signature", i, file, line);
+ if (*(mem_areas [i].end_sig) != MAD_SIGNATURE)
+ mad_abort ("Overwrite error: Bad end signature", i, file, line);
+ }
+}
+
+/* Allocates a memory area. Used instead of malloc and calloc. */
+void *mad_alloc (int size, char *file, int line)
+{
+ int i;
+ char *area;
+
+ mad_check (file, line);
+
+ for (i = 0; i < MAD_MAX_AREAS; i++){
+ if (! mem_areas [i].in_use)
+ break;
+ }
+ if (i >= MAD_MAX_AREAS){
+ fprintf (stderr, "MAD: Out of memory area handles. Increase the value of MAD_MAX_AREAS.\r\n");
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ fprintf (stderr, "MAD: Aborting...\r\n");
+ abort ();
+ }
+
+ mem_areas [i].in_use = 1;
+ size = (size + 3) & (~3); /* Alignment */
+ area = (char*) malloc (size + 2 * sizeof (long));
+ if (!area){
+ fprintf (stderr, "MAD: Out of memory.\r\n");
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ fprintf (stderr, "MAD: Aborting...\r\n");
+ abort ();
+ }
+
+ mem_areas [i].start_sig = (long*) area;
+ mem_areas [i].data = (area + sizeof (long));
+ mem_areas [i].end_sig = (long*) (area + size + sizeof (long));
+ *(mem_areas [i].start_sig) = MAD_SIGNATURE;
+ *(mem_areas [i].end_sig) = MAD_SIGNATURE;
+
+ if (strlen (file) >= MAD_MAX_FILE)
+ file [MAD_MAX_FILE - 1] = 0;
+ strcpy (mem_areas [i].file, file);
+ mem_areas [i].line = line;
+
+ return mem_areas [i].data;
+}
+
+/* Reallocates a memory area. Used instead of realloc. */
+void *mad_realloc (void *ptr, int newsize, char *file, int line)
+{
+ int i;
+ char *area;
+
+ if (!ptr)
+ return (mad_alloc (newsize, file, line));
+
+ mad_check (file, line);
+
+ for (i = 0; i < MAD_MAX_AREAS; i++){
+ if (! mem_areas [i].in_use)
+ continue;
+ if (mem_areas [i].data == ptr)
+ break;
+ }
+ if (i >= MAD_MAX_AREAS){
+ fprintf (stderr, "MAD: Attempted to realloc unallocated pointer: %p.\r\n", ptr);
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ fprintf (stderr, "MAD: Aborting...\r\n");
+ abort ();
+ }
+
+ newsize = (newsize + 3) & (~3); /* Alignment */
+ area = (char*) realloc (mem_areas [i].start_sig, newsize + 2 * sizeof (long));
+ if (!area){
+ fprintf (stderr, "MAD: Out of memory.\r\n");
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ fprintf (stderr, "MAD: Aborting...\r\n");
+ abort ();
+ }
+
+ mem_areas [i].start_sig = (long*) area;
+ mem_areas [i].data = (area + sizeof (long));
+ mem_areas [i].end_sig = (long*) (area + newsize + sizeof (long));
+ *(mem_areas [i].start_sig) = MAD_SIGNATURE;
+ *(mem_areas [i].end_sig) = MAD_SIGNATURE;
+
+ if (strlen (file) >= MAD_MAX_FILE)
+ file [MAD_MAX_FILE - 1] = 0;
+ strcpy (mem_areas [i].file, file);
+ mem_areas [i].line = line;
+
+ return mem_areas [i].data;
+}
+
+/* Duplicates a character string. Used instead of strdup. */
+char *mad_strdup (const char *s, char *file, int line)
+{
+ char *t;
+
+ t = (char *) mad_alloc (strlen (s) + 1, file, line);
+ strcpy (t, s);
+ return t;
+}
+
+/* Frees a memory area. Used instead of free. */
+void mad_free (void *ptr, char *file, int line)
+{
+ int i;
+
+ mad_check (file, line);
+
+ if (watch_free_pointer && ptr == watch_free_pointer){
+ printf ("watch free pointer found\n");
+ }
+
+ if (ptr == NULL){
+ fprintf (stderr, "MAD: Attempted to free a NULL pointer in file \"%s\" at line %d.\n",
+ file, line);
+ return;
+ }
+
+ for (i = 0; i < MAD_MAX_AREAS; i++){
+ if (! mem_areas [i].in_use)
+ continue;
+ if (mem_areas [i].data == ptr)
+ break;
+ }
+ if (i >= MAD_MAX_AREAS){
+ fprintf (stderr, "MAD: Attempted to free an unallocated pointer: %p.\r\n", ptr);
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ fprintf (stderr, "MAD: Aborting...\r\n");
+ abort ();
+ }
+
+ free (mem_areas [i].start_sig);
+ mem_areas [i].in_use = 0;
+}
+
+/* Outputs a list of unfreed memory areas,
+ to be called as a last thing before exiting */
+void mad_finalize (char *file, int line)
+{
+ int i;
+
+ mad_check (file, line);
+
+ /* Following can be commented out if you don't want to see the
+ memory leaks of the Midnight Commander */
+#if 1
+ for (i = 0; i < MAD_MAX_AREAS; i++){
+ if (! mem_areas [i].in_use)
+ continue;
+ fprintf (stderr, "MAD: Unfreed pointer: %p.\n", mem_areas [i].data);
+ fprintf (stderr, " Allocated in file \"%s\" at line %d.\r\n",
+ mem_areas [i].file, mem_areas [i].line);
+ fprintf (stderr, " Discovered in file \"%s\" at line %d.\r\n",
+ file, line);
+ }
+#endif
+}
+
+#endif /* HAVE_MAD */
--- /dev/null
+#ifndef __MAD_H
+#define __MAD_H
+
+#ifdef HAVE_MAD
+# define INLINE
+#else
+# ifndef INLINE
+# define INLINE inline
+# endif
+#endif
+
+#ifdef HAVE_MAD
+
+/* The Memory Allocation Debugging system */
+
+/* GNU headers define this as macros */
+#ifdef malloc
+# undef malloc
+#endif
+
+#ifdef calloc
+# undef calloc
+#endif
+
+#define malloc(x) mad_alloc (x, __FILE__, __LINE__)
+#define calloc(x, y) mad_alloc (x * y, __FILE__, __LINE__)
+#define realloc(x, y) mad_realloc (x, y, __FILE__, __LINE__)
+#define xmalloc(x, y) mad_alloc (x, __FILE__, __LINE__)
+#define strdup(x) mad_strdup (x, __FILE__, __LINE__)
+#define free(x) mad_free (x, __FILE__, __LINE__)
+
+void mad_check (char *file, int line);
+void *mad_alloc (int size, char *file, int line);
+void *mad_realloc (void *ptr, int newsize, char *file, int line);
+char *mad_strdup (const char *s, char *file, int line);
+void mad_free (void *ptr, char *file, int line);
+void mad_finalize (char *file, int line);
+#else
+
+#define mad_finalize(x, y)
+#define mad_check(file,line)
+
+#endif /* HAVE_MAD */
+
+#endif /* __MAD_H */
--- /dev/null
+/* Main program for the Midnight Commander
+ Copyright (C) 1994, 1995, 1996, 1997 The Free Software Foundation
+
+ Written by: 1994, 1995, 1996, 1997 Miguel de Icaza
+ 1994, 1995 Janne Kukonlehto
+ 1997 Norbert Warmuth
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <locale.h>
+
+#ifdef _OS_NT
+# include <windows.h>
+#endif
+
+#ifdef __os2__
+# define INCL_DOS
+# define INCL_DOSFILEMGR
+# define INCL_DOSERRORS
+# include <os2.h>
+#endif
+
+#include "tty.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+
+#include <sys/stat.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
+#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION)
+# include <dirent.h>
+# define NLENGTH(dirent) (strlen ((dirent)->d_name))
+#else
+# define dirent direct
+# define NLENGTH(dirent) ((dirent)->d_namlen)
+
+# ifdef HAVE_SYS_NDIR_H
+# include <sys/ndir.h>
+# endif /* HAVE_SYS_NDIR_H */
+
+# ifdef HAVE_SYS_DIR_H
+# include <sys/dir.h>
+# endif /* HAVE_SYS_DIR_H */
+
+# ifdef HAVE_NDIR_H
+# include <ndir.h>
+# endif /* HAVE_NDIR_H */
+#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */
+
+#if HAVE_SYS_WAIT_H
+# include <sys/wait.h> /* For waitpid() */
+#endif
+
+#include <errno.h>
+#ifndef OS2_NT
+# include <pwd.h>
+#endif
+#include <ctype.h>
+#include <fcntl.h> /* For O_RDWR */
+#include <signal.h>
+
+/* Program include files */
+#include "x.h"
+#include "mad.h"
+#include "dir.h"
+#include "color.h"
+#include "global.h"
+#include "util.h"
+#include "dialog.h"
+#include "menu.h"
+#include "file.h"
+#include "panel.h"
+#include "main.h"
+#include "win.h"
+#include "user.h"
+#include "mem.h"
+#include "mouse.h"
+#include "option.h"
+#include "tree.h"
+#include "cons.saver.h"
+#include "subshell.h"
+#include "key.h" /* For init_key() and mi_getch() */
+#include "setup.h" /* save_setup() */
+#include "profile.h" /* free_profiles() */
+#include "boxes.h"
+#include "layout.h"
+#include "cmd.h" /* Normal commands */
+#include "hotlist.h"
+#include "panelize.h"
+#ifndef __os2__
+# include "learn.h"
+#endif
+#include "listmode.h"
+#include "background.h"
+#include "ext.h" /* For flush_extension_file() */
+
+/* Listbox for the command history feature */
+#include "widget.h"
+#include "command.h"
+#include "wtools.h"
+#include "complete.h" /* For the free_completion */
+
+#include "chmod.h"
+#include "chown.h"
+
+#ifdef OS2_NT
+# include <io.h>
+# include <drive.h>
+#endif
+
+#include "../vfs/vfs.h"
+#include "../vfs/extfs.h"
+
+
+#include "popt.h"
+
+/* "$Id: main.c,v 1.1 2001/12/30 09:55:24 sedwards Exp $" */
+
+/* When the modes are active, left_panel, right_panel and tree_panel */
+/* Point to a proper data structure. You should check with the functions */
+/* get_current_type and get_other_type the types of the panels before using */
+/* This pointer variables */
+
+/* The structures for the panels */
+WPanel *left_panel;
+WPanel *right_panel;
+
+/* The pointer to the tree */
+WTree *the_tree;
+
+/* The Menubar */
+WMenu *the_menubar;
+
+/* Pointers to the selected and unselected panel */
+WPanel *current_panel = NULL;
+
+/* Set when we want use advanced chmod command instead of chmod and/or chown */
+int advanced_chfns = 0;
+
+/* Set when main loop should be terminated */
+volatile int quit = 0;
+
+/* Set if you want the possible completions dialog for the first time */
+int show_all_if_ambiguous = 0;
+
+/* Set when cd symlink following is desirable (bash mode) */
+int cd_symlinks = 1;
+
+/* If set then dialogs just clean the screen when refreshing, else */
+/* they do a complete refresh, refreshing all the parts of the program */
+int fast_refresh = 0;
+
+/* If true, marking a files moves the cursor down */
+int mark_moves_down = 1;
+
+/* If true, at startup the user-menu is invoked */
+int auto_menu = 0;
+
+/* If true, use + and \ keys normally and select/unselect do if M-+ / M-\ and M--
+ and keypad + / - */
+int alternate_plus_minus = 0;
+
+/* If true, then the +, - and \ keys have their special meaning only if the
+ * command line is emtpy, otherwise they behave like regular letters
+ */
+int only_leading_plus_minus = 1;
+
+/* If true, after executing a command, wait for a keystroke */
+enum { pause_never, pause_on_dumb_terminals, pause_always };
+
+int pause_after_run = pause_on_dumb_terminals;
+
+/* It true saves the setup when quitting */
+int auto_save_setup = 1;
+
+/* If true, be eight bit clean */
+int eight_bit_clean = 0;
+
+/* If true, then display chars 0-255, else iso-8859-1,
+ requires eight_bit_clean */
+int full_eight_bits = 0;
+
+/* If true use the internal viewer */
+int use_internal_view = 1;
+
+/* Have we shown the fast-reload warning in the past? */
+int fast_reload_w = 0;
+
+/* Move page/item? When clicking on the top or bottom of a panel */
+int mouse_move_pages = 1;
+
+/* If true: l&r arrows are used to chdir if the input line is empty */
+int navigate_with_arrows = 0;
+
+/* If it is set, the commander will iconify itself when executing a program */
+int iconify_on_exec = 1;
+
+/* If true use +, -, | for line drawing */
+int force_ugly_line_drawing = 0;
+
+/* If true message "The shell is already running a command" never */
+int force_subshell_execution = 0;
+
+/* If true program softkeys (HP terminals only) on startup and after every
+ command ran in the subshell to the description found in the termcap/terminfo
+ database */
+int reset_hp_softkeys = 0;
+
+/* The prompt */
+char *prompt = 0;
+
+/* The widget where we draw the prompt */
+WLabel *the_prompt;
+
+/* The hint bar */
+WLabel *the_hint;
+
+/* The button bar */
+WButtonBar *the_bar;
+
+#ifdef HAVE_X
+WButtonBar *the_bar2;
+#endif
+
+/* For slow terminals */
+int slow_terminal = 0;
+
+/* use mouse? */
+int use_mouse_p = GPM_MOUSE;
+
+/* If true, assume we are running on an xterm terminal */
+static int force_xterm = 0;
+
+/* Controls screen clearing before an exec */
+int clear_before_exec = 1;
+
+/* Asks for confirmation before deleting a file */
+int confirm_delete = 1;
+
+/* Asks for confirmation before overwriting a file */
+int confirm_overwrite = 1;
+
+/* Asks for confirmation before executing a program by pressing enter */
+int confirm_execute = 0;
+
+/* Asks for confirmation before leaving the program */
+int confirm_exit = 1;
+
+/* Asks for confirmation when using F3 to view a directory and there
+ are tagged files */
+int confirm_view_dir = 0;
+
+/* This flag indicates if the pull down menus by default drop down */
+int drop_menus = 0;
+
+/* The dialog handle for the main program */
+Dlg_head *midnight_dlg;
+
+/* Subshell: if set, then the prompt was not saved on CONSOLE_SAVE */
+/* We need to paint it after CONSOLE_RESTORE, see: load_prompt */
+int update_prompt = 0;
+
+/* The name which was used to invoke mc */
+char *program_name;
+
+/* The home directory */
+char *home_dir;
+
+/* The value of the other directory, only used when loading the setup */
+char *other_dir = 0;
+char *this_dir = 0;
+
+/* If true, then print on stdout the last directory we were at */
+static int print_last_wd = 0;
+static char *last_wd_string;
+static int print_last_revert = 0;
+
+/* On OS/2 and on Windows NT, we need a batch file to do the -P magic */
+#ifdef OS2_NT
+static char *batch_file_name = 0;
+#endif
+
+/* widget colors for the midnight commander */
+int midnight_colors [4];
+
+/* Force colors, only used by Slang */
+int force_colors = 0;
+
+/* colors specified on the command line: they override any other setting */
+char *command_line_colors;
+
+/* File name to view if argument was supplied */
+char *view_one_file = 0;
+
+/* File name to view if argument was supplied */
+char *edit_one_file = 0;
+
+/* Used so that widgets know if they are being destroyed or
+ shut down */
+int midnight_shutdown = 0;
+
+/* to show nice prompts */
+static int last_paused = 0;
+
+/* Only used at program boot */
+int boot_current_is_left = 1;
+
+/* Used for keeping track of the original stdout */
+int stdout_fd = 0;
+
+/* The user's shell */
+char *shell;
+
+/* mc_home: The home of MC */
+char *mc_home;
+
+/* if on, it displays the information that files have been moved to ~/.mc */
+int show_change_notice = 0;
+
+char cmd_buf [512];
+
+/* Used during argument processing */
+int finish_program = 0;
+
+/* Forward declarations */
+char *get_mc_lib_dir ();
+int panel_event (Gpm_Event *event, WPanel *panel);
+int menu_bar_event (Gpm_Event *event, void *);
+static void menu_cmd (void);
+
+#ifndef HAVE_GNOME
+WPanel *
+get_current_panel ()
+{
+ return current_panel;
+}
+
+WPanel *
+get_other_panel ()
+{
+ return (WPanel *) get_panel_widget (get_other_index ());
+}
+#endif
+
+void
+try_to_select (WPanel *panel, char *name)
+{
+ Xtry_to_select (panel, name);
+ select_item (panel);
+ display_mini_info (panel);
+}
+
+/*
+ * cd_try_to_select:
+ *
+ * If we moved to the parent directory move the selection pointer to
+ * the old directory name
+ */
+void
+cd_try_to_select (WPanel *panel)
+{
+ char *p, *q;
+ int i, j = 4;
+
+ if (strlen (panel->lwd) > strlen (panel->cwd)
+ && strncmp (panel->cwd, panel->lwd, strlen (panel->cwd)) == 0
+ && strchr (panel->lwd + strlen (panel->cwd) + 1, PATH_SEP) == 0)
+ try_to_select (panel, panel->lwd);
+ else
+#ifdef USE_VFS
+ if ((!strncmp (panel->lwd, "tar:", 4) &&
+ !strncmp (panel->lwd + 4, panel->cwd, strlen (panel->cwd))) ||
+ ((i = extfs_prefix_to_type (panel->lwd)) != -1 &&
+ !strncmp (panel->lwd + (j = strlen (extfs_get_prefix (i)) + 1),
+ panel->cwd, strlen (panel->cwd)))) {
+ p = strdup (panel->lwd + j + strlen (panel->cwd));
+ q = strchr (p, PATH_SEP);
+ if (q != NULL && (q != p || (q = strchr (q + 1, PATH_SEP)) != NULL))
+ *q = 0;
+ try_to_select (panel, p);
+ free (p);
+ } else
+#endif
+ try_to_select (panel, NULL);
+}
+
+void
+reload_panelized (WPanel *panel)
+{
+ int i, j;
+ dir_list *list = &panel->dir;
+
+ if (panel != cpanel)
+ mc_chdir (panel->cwd);
+
+ for (i = 0, j = 0; i < panel->count; i++){
+ if (list->list [i].f.marked) {
+ /* Unmark the file in advance. In case the following mc_lstat
+ * fails we are done, else we have to mark the file again
+ * (Note: do_file_mark depends on a valid "list->list [i].buf").
+ * IMO that's the best way to update the panel's summary status
+ * -- Norbert
+ */
+ do_file_mark (panel, i, 0);
+ }
+ if (mc_lstat (list->list [i].fname, &list->list [i].buf)){
+ free (list->list [i].fname);
+ continue;
+ }
+ if (list->list [i].f.marked)
+ do_file_mark (panel, i, 1);
+ if (j != i)
+ list->list [j] = list->list [i];
+ j++;
+ }
+ if (j == 0)
+ panel->count = set_zero_dir (list);
+ else
+ panel->count = j;
+
+ if (panel != cpanel)
+ mc_chdir (cpanel->cwd);
+}
+
+void
+update_one_panel_widget (WPanel *panel, int force_update, char *current_file)
+{
+ int free_pointer;
+
+ if (force_update & UP_RELOAD){
+ panel->is_panelized = 0;
+
+ ftpfs_flushdir ();
+ bzero (&(panel->dir_stat), sizeof (panel->dir_stat));
+ }
+
+ /* If current_file == -1 (an invalid pointer) then preserve selection */
+ if (current_file == UP_KEEPSEL){
+ free_pointer = 1;
+ current_file = strdup (panel->dir.list [panel->selected].fname);
+ } else
+ free_pointer = 0;
+
+ if (panel->is_panelized)
+ reload_panelized (panel);
+ else
+ panel_reload (panel);
+
+ try_to_select (panel, current_file);
+ panel->dirty = 1;
+
+ if (free_pointer)
+ free (current_file);
+}
+
+#ifndef PORT_HAS_UPDATE_PANELS
+void
+update_one_panel (int which, int force_update, char *current_file)
+{
+ WPanel *panel;
+
+ if (get_display_type (which) != view_listing)
+ return;
+
+ panel = (WPanel *) get_panel_widget (which);
+ update_one_panel_widget (panel, force_update, current_file);
+}
+
+/* This routine reloads the directory in both panels. It tries to
+ * select current_file in current_panel and other_file in other_panel.
+ * If current_file == -1 then it automatically sets current_file and
+ * other_file to the currently selected files in the panels.
+ *
+ * if force_update has the UP_ONLY_CURRENT bit toggled on, then it
+ * will not reload the other panel.
+*/
+void
+update_panels (int force_update, char *current_file)
+{
+ int reload_other = !(force_update & UP_ONLY_CURRENT);
+ WPanel *panel;
+
+ update_one_panel (get_current_index (), force_update, current_file);
+ if (reload_other)
+ update_one_panel (get_other_index (), force_update, UP_KEEPSEL);
+
+ if (get_current_type () == view_listing)
+ panel = (WPanel *) get_panel_widget (get_current_index ());
+ else
+ panel = (WPanel *) get_panel_widget (get_other_index ());
+
+ mc_chdir (panel->cwd);
+}
+#endif
+
+#ifdef WANT_PARSE
+static void select_by_index (WPanel *panel, int i);
+
+/* Called by parse_control_file */
+static int index_by_name (file_entry *list, int count)
+{
+ char *name;
+ int i;
+
+ name = strtok (NULL, " \t\n");
+ if (!name || !*name)
+ return -1;
+ for (i = 0; i < count; i++){
+ if (strcmp (name, list[i].fname) == 0)
+ return i;
+ }
+ return -1;
+}
+
+/* Called by parse_control_file */
+static void select_by_index (WPanel *panel, int i)
+{
+ if (i >= panel->count)
+ return;
+
+ unselect_item (panel);
+ panel->selected = i;
+
+#ifndef HAVE_X
+ while (panel->selected - panel->top_file >= ITEMS (panel)){
+ /* Scroll window half screen */
+ panel->top_file += ITEMS (panel)/2;
+ paint_dir (panel);
+ select_item (panel);
+ }
+ while (panel->selected < panel->top_file){
+ /* Scroll window half screen */
+ panel->top_file -= ITEMS (panel)/2;
+ if (panel->top_file < 0) panel->top_file = 0;
+ paint_dir (panel);
+ }
+#endif
+ select_item (panel);
+}
+
+/* Called by my_system
+ No error reporting, just exits on the first sign of trouble */
+static void parse_control_file (void)
+{
+ char *data, *current;
+ WPanel *panel;
+ file_entry *list;
+ int i;
+ FILE *file;
+ struct stat s;
+
+ if ((file = fopen (control_file, "r")) == NULL){
+ return;
+ }
+ /* Use of fstat prevents race conditions */
+ if (fstat (fileno (file), &s) != 0){
+ fclose (file);
+ return;
+ }
+#ifndef OS2_NT
+ /* Security: Check that the user owns the control file to prevent
+ other users from playing tricks on him/her. */
+ if (s.st_uid != getuid ()){
+ fclose (file);
+ return;
+ }
+#endif
+ data = (char *) xmalloc (s.st_size+1, "main, parse_control_file");
+ if (!data){
+ fclose (file);
+ return;
+ }
+ if (s.st_size != fread (data, 1, s.st_size, file)){
+ free (data);
+ fclose (file);
+ return;
+ }
+ data [s.st_size] = 0;
+ fclose (file);
+
+ /* The Control file has now been loaded to memory -> start parsing. */
+ current = strtok (data, " \t\n");
+ while (current && *current){
+ if (isupper (*current)){
+ if (get_other_type () != view_listing)
+ break;
+ else
+ panel = other_panel;
+ } else
+ panel = cpanel;
+
+ list = panel->dir.list;
+ *current = tolower (*current);
+
+ if (strcmp (current, "clear_tags") == 0){
+ unmark_files (panel);
+ } else if (strcmp (current, "tag") == 0){
+ i = index_by_name (list, panel->count);
+ if (i >= 0) {
+ do_file_mark (panel, i, 1);
+ }
+ } else if (strcmp (current, "untag") == 0){
+ i = index_by_name (list, panel->count);
+ if (i >= 0){
+ do_file_mark (panel, i, 0);
+ }
+ } else if (strcmp (current, "select") == 0){
+ i = index_by_name (list, panel->count);
+ if (i >= 0){
+ select_by_index (panel, i);
+ }
+ } else if (strcmp (current, "change_panel") == 0){
+ change_panel ();
+ } else if (strcmp (current, "cd") == 0){
+ int change = 0;
+ current = strtok (NULL, " \t\n");
+ if (!current) break;
+ if (cpanel != panel){
+ change_panel ();
+ change = 1;
+ }
+ do_cd (current, cd_parse_command);
+ if (change)
+ change_panel ();
+ } else {
+ /* Unknown command -> let's give up */
+ break;
+ }
+ current = strtok (NULL, " \t\n");
+ }
+
+ free (data);
+ paint_panel (cpanel);
+ paint_panel (opanel);
+}
+#else
+#define parse_control_file()
+#endif /* WANT_PARSE */
+
+/* Sets up the terminal before executing a program */
+static void
+pre_exec (void)
+{
+ use_dash (0);
+ edition_pre_exec ();
+}
+
+/* Save current stat of directories to avoid reloading the panels */
+/* when no modifications have taken place */
+void
+save_cwds_stat (void)
+{
+ if (fast_reload){
+ mc_stat (cpanel->cwd, &(cpanel->dir_stat));
+ if (get_other_type () == view_listing)
+ mc_stat (opanel->cwd, &(opanel->dir_stat));
+ }
+}
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+void
+do_possible_cd (char *new_dir)
+{
+ if (!do_cd (new_dir, cd_exact))
+ message (1, _(" Warning "),
+ _(" The Commander can't change to the directory that \n"
+ " the subshell claims you are in. Perhaps you have \n"
+ " deleted your working directory, or given yourself \n"
+ " extra access permissions with the \"su\" command? "));
+}
+
+void
+do_update_prompt ()
+{
+ if (update_prompt){
+ printf ("%s", subshell_prompt);
+ fflush (stdout);
+ update_prompt = 0;
+ }
+}
+#endif
+
+void
+restore_console (void)
+{
+ handle_console (CONSOLE_RESTORE);
+}
+
+void
+exec_shell ()
+{
+ do_execute (shell, 0, 0);
+}
+
+void
+do_execute (const char *shell, const char *command, int flags)
+{
+#ifdef HAVE_SUBSHELL_SUPPORT
+ char *new_dir = NULL;
+#endif
+
+#ifdef USE_VFS
+ char *old_vfs_dir = 0;
+
+ if (!vfs_current_is_local ())
+ old_vfs_dir = strdup (vfs_get_current_dir ());
+#endif
+
+ save_cwds_stat ();
+ pre_exec ();
+ if (console_flag)
+ restore_console ();
+
+#ifndef __os2__
+ unlink (control_file);
+#endif
+ if (!use_subshell && !(flags & EXECUTE_INTERNAL)){
+ printf ("%s%s%s\n", last_paused ? "\r\n":"", prompt, command);
+ last_paused = 0;
+ }
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell && !(flags & EXECUTE_INTERNAL)){
+ do_update_prompt ();
+
+ /* We don't care if it died, higher level takes care of this */
+#ifdef USE_VFS
+ invoke_subshell (command, VISIBLY, old_vfs_dir ? 0 : &new_dir);
+#else
+ invoke_subshell (command, VISIBLY, &new_dir);
+#endif
+ } else
+#endif
+ my_system (flags, shell, command);
+
+#ifndef HAVE_GNOME
+ if (!(flags & EXECUTE_INTERNAL)){
+ if ((pause_after_run == pause_always ||
+ (pause_after_run == pause_on_dumb_terminals &&
+ !xterm_flag && !console_flag)) && !quit){
+ printf (_("Press any key to continue..."));
+ last_paused = 1;
+ fflush (stdout);
+ mc_raw_mode ();
+ xgetch ();
+ }
+ if (console_flag){
+ if (output_lines && keybar_visible) {
+ putchar('\n');
+ fflush(stdout);
+ }
+ }
+ }
+#endif
+
+ if (console_flag)
+ handle_console (CONSOLE_SAVE);
+ edition_post_exec ();
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (new_dir)
+ do_possible_cd (new_dir);
+
+#endif
+#ifdef USE_VFS
+ if (old_vfs_dir){
+ mc_chdir (old_vfs_dir);
+ free (old_vfs_dir);
+ }
+#endif
+
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+
+ parse_control_file ();
+#ifndef __os2__
+ unlink (control_file);
+#endif
+ do_refresh ();
+ use_dash (TRUE);
+}
+
+/* Executes a command */
+void
+shell_execute (char *command, int flags)
+{
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell)
+ if (subshell_state == INACTIVE || force_subshell_execution)
+ do_execute (shell, command, flags | EXECUTE_AS_SHELL);
+ else
+ message (1, MSG_ERROR, _(" The shell is already running a command "));
+ else
+#endif
+ do_execute (shell, command, flags | EXECUTE_AS_SHELL);
+}
+
+void
+execute (char *command)
+{
+ shell_execute (command, 0);
+}
+
+void
+change_panel (void)
+{
+ free_completions (input_w (cmdline));
+ dlg_one_down (midnight_dlg);
+}
+
+static int
+quit_cmd_internal (int quiet)
+{
+ int q = quit;
+
+ if (quiet || !confirm_exit){
+ q = 1;
+ } else {
+ if (query_dialog (_(" The Midnight Commander "),
+ _(" Do you really want to quit the Midnight Commander? "),
+ 0, 2, _("&Yes"), _("&No")) == 0)
+ q = 1;
+ }
+ if (q){
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (!use_subshell)
+ midnight_dlg->running = 0;
+ else
+ if ((q = exit_subshell ()))
+#endif
+ midnight_dlg->running = 0;
+ }
+ if (q)
+ quit |= 1;
+ return quit;
+}
+
+int quit_cmd (void)
+{
+ quit_cmd_internal (0);
+ return quit;
+}
+
+int quiet_quit_cmd (void)
+{
+ print_last_revert = 1;
+ quit_cmd_internal (1);
+ return quit;
+}
+
+/*
+ * Touch window and refresh window functions
+ */
+
+/* This routine untouches the first line on both panels in order */
+/* to avoid the refreshing the menu bar */
+
+#ifdef HAVE_X
+void
+untouch_bar (void)
+{
+}
+
+void
+repaint_screen (void)
+{
+ do_refresh ();
+}
+
+#else /* HAVE_X */
+void
+untouch_bar (void)
+{
+ do_refresh ();
+}
+
+void
+repaint_screen (void)
+{
+ do_refresh ();
+ mc_refresh ();
+}
+#endif /* HAVE_X */
+
+/* Wrapper for do_subshell_chdir, check for availability of subshell */
+void
+subshell_chdir (char *directory)
+{
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell){
+ if (vfs_current_is_local ())
+ do_subshell_chdir (directory, 0, 1);
+ }
+#endif
+}
+
+void
+directory_history_add (WPanel * panel, char *s)
+{
+ if (!panel->dir_history) {
+ panel->dir_history = malloc (sizeof (Hist));
+ memset (panel->dir_history, 0, sizeof (Hist));
+ panel->dir_history->text = strdup (s);
+ return;
+ }
+ if (!strcmp (panel->dir_history->text, s))
+ return;
+ if (panel->dir_history->next) {
+ if (panel->dir_history->next->text) {
+ free (panel->dir_history->next->text);
+ panel->dir_history->next->text = 0;
+ }
+ } else {
+ panel->dir_history->next = malloc (sizeof (Hist));
+ memset (panel->dir_history->next, 0, sizeof (Hist));
+ panel->dir_history->next->prev = panel->dir_history;
+ }
+ panel->dir_history = panel->dir_history->next;
+ panel->dir_history->text = strdup (s);
+
+ panel_update_marks (panel);
+}
+
+/* Changes the current panel directory */
+int
+_do_panel_cd (WPanel *panel, char *new_dir, enum cd_enum cd_type)
+{
+ char *directory, *olddir;
+ char temp [MC_MAXPATHLEN];
+#ifdef USE_VFS
+ vfs *oldvfs;
+ vfsid oldvfsid;
+ struct vfs_stamping *parent;
+#endif
+ olddir = strdup (panel->cwd);
+
+ /* Convert *new_path to a suitable pathname, handle ~user */
+
+ if (cd_type == cd_parse_command){
+ while (*new_dir == ' ')
+ new_dir++;
+
+ if (!strcmp (new_dir, "-")){
+ strcpy (temp, panel->lwd);
+ new_dir = temp;
+ }
+ }
+ directory = *new_dir ? new_dir : home_dir;
+
+ if (mc_chdir (directory) == -1){
+ strcpy (panel->cwd, olddir);
+ free (olddir);
+ return 0;
+ }
+
+ /* Success: save previous directory, shutdown status of previous dir */
+ strcpy (panel->lwd, olddir);
+ free_completions (input_w (cmdline));
+
+ mc_get_current_wd (panel->cwd, sizeof (panel->cwd) - 2);
+
+#ifdef USE_VFS
+ oldvfs = vfs_type (olddir);
+ oldvfsid = vfs_ncs_getid (oldvfs, olddir, &parent);
+ vfs_add_noncurrent_stamps (oldvfs, oldvfsid, parent);
+ vfs_rm_parents (parent);
+#endif
+ free (olddir);
+
+ subshell_chdir (panel->cwd);
+
+ /* Reload current panel */
+ clean_dir (&panel->dir, panel->count);
+ panel->count = do_load_dir (&panel->dir, panel->sort_type,
+ panel->reverse, panel->case_sensitive, panel->filter);
+ panel->top_file = 0;
+ panel->selected = 0;
+ panel->marked = 0;
+ panel->dirs_marked = 0;
+ panel->total = 0;
+ panel->searching = 0;
+ cd_try_to_select (panel);
+ load_hint ();
+ panel_update_contents (panel);
+ return 1;
+}
+
+int
+do_panel_cd (WPanel *panel, char *new_dir, enum cd_enum cd_type)
+{
+ int r;
+
+ r = _do_panel_cd (panel, new_dir, cd_type);
+ if (r)
+ directory_history_add (cpanel, cpanel->cwd);
+ return r;
+}
+
+int
+do_cd (char *new_dir, enum cd_enum exact)
+{
+ return (do_panel_cd (cpanel, new_dir, exact));
+}
+
+void
+directory_history_next (WPanel * panel)
+{
+ if (!panel->dir_history->next)
+ return;
+ if (_do_panel_cd (panel, panel->dir_history->next->text, cd_exact))
+ panel->dir_history = panel->dir_history->next;
+ panel_update_marks (panel);
+}
+
+void
+directory_history_prev (WPanel * panel)
+{
+ if (!panel->dir_history->prev)
+ return;
+ if (_do_panel_cd (panel, panel->dir_history->prev->text, cd_exact))
+ panel->dir_history = panel->dir_history->prev;
+ panel_update_marks (panel);
+}
+
+void
+directory_history_list (WPanel * panel)
+{
+ char *s;
+/* must be at least two to show a history */
+ if (panel->dir_history) {
+ if (panel->dir_history->prev || panel->dir_history->next) {
+ s = show_hist (panel->dir_history, panel->widget.x, panel->widget.y);
+ if (s) {
+ int r;
+ r = _do_panel_cd (panel, s, cd_exact);
+ if (r)
+ directory_history_add (panel, panel->cwd);
+ free (s);
+ }
+ }
+ }
+}
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+int
+load_prompt (int fd, void *unused)
+{
+ if (!read_subshell_prompt (QUIETLY))
+ return 0;
+
+ if (command_prompt){
+ int prompt_len;
+
+ prompt = strip_ctrl_codes (subshell_prompt);
+ prompt_len = strlen (prompt);
+
+ /* Check for prompts too big */
+ if (prompt_len > COLS - 8) {
+ prompt [COLS - 8 ] = 0;
+ prompt_len = COLS - 8;
+ }
+ label_set_text (the_prompt, prompt);
+ winput_set_origin ((WInput *)cmdline, prompt_len, COLS-prompt_len);
+
+ /* since the prompt has changed, and we are called from one of the
+ * get_event channels, the prompt updating does not take place
+ * automatically: force a cursor update and a screen refresh
+ */
+ if (current_dlg == midnight_dlg){
+ update_cursor (midnight_dlg);
+ mc_refresh ();
+ }
+ }
+ update_prompt = 1;
+ return 0;
+}
+#endif
+
+/* The user pressed the enter key */
+int
+menu_bar_event (Gpm_Event *event, void *x)
+{
+ if (event->type != GPM_DOWN)
+ return MOU_NORMAL;
+
+ return MOU_ENDLOOP;
+}
+
+/* Used to emulate Lynx's entering leaving a directory with the arrow keys */
+int
+maybe_cd (int char_code, int move_up_dir)
+{
+ if (navigate_with_arrows){
+ if (!input_w (cmdline)->buffer [0]){
+ if (!move_up_dir){
+ do_cd ("..", cd_exact);
+ return 1;
+ }
+ if (S_ISDIR (selection (cpanel)->buf.st_mode)
+ || link_isdir (selection (cpanel))){
+ do_cd (selection (cpanel)->fname, cd_exact);
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+void
+set_sort_to (WPanel *p, sortfn *sort_order)
+{
+ p->sort_type = sort_order;
+
+ /* The directory is already sorted, we have to load the unsorted stuff */
+ if (sort_order == (sortfn *) unsorted){
+ char *current_file;
+
+ current_file = strdup (cpanel->dir.list [cpanel->selected].fname);
+ panel_reload (cpanel);
+ try_to_select (cpanel, current_file);
+ free (current_file);
+ }
+ do_re_sort (p);
+}
+
+void
+sort_cmd (void)
+{
+ WPanel *p;
+ sortfn *sort_order;
+
+ if (!SELECTED_IS_PANEL)
+ return;
+
+ p = MENU_PANEL;
+ sort_order = sort_box (p->sort_type, &p->reverse, &p->case_sensitive);
+
+ if (sort_order == 0)
+ return;
+
+ p->sort_type = sort_order;
+
+ /* The directory is already sorted, we have to load the unsorted stuff */
+ if (sort_order == (sortfn *) unsorted){
+ char *current_file;
+
+ current_file = strdup (cpanel->dir.list [cpanel->selected].fname);
+ panel_reload (cpanel);
+ try_to_select (cpanel, current_file);
+ free (current_file);
+ }
+ do_re_sort (p);
+}
+
+static void
+tree_box (void)
+{
+ char *sel_dir;
+
+ sel_dir = tree (selection (cpanel)->fname);
+ if (sel_dir){
+ do_cd(sel_dir, cd_exact);
+ free (sel_dir);
+ }
+}
+
+#if SOMEDAY_WE_WILL_FINISH_THIS_CODE
+static void
+ listmode_cmd (void)
+{
+ char *newmode;
+ newmode = listmode_edit ("half <type,>name,|,size:8,|,perm:4+");
+ message (0, " Listing format edit ", " New mode is \"%s\" ", newmode);
+ free (newmode);
+}
+#endif
+
+#ifdef HAVE_GNOME
+void init_menu () {};
+void done_menu () {};
+#else
+/* NOTICE: hotkeys specified here are overriden in menubar_paint_idx (alex) */
+static menu_entry PanelMenu [] = {
+ { ' ', N_("&Listing mode..."), 'L', listing_cmd },
+ { ' ', N_("&Quick view C-x q"), 'Q', quick_view_cmd },
+ { ' ', N_("&Info C-x i"), 'I', info_cmd },
+ { ' ', N_("&Tree"), 'T', tree_cmd },
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Sort order..."), 'S', sort_cmd },
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Filter..."), 'F', filter_cmd },
+#ifdef USE_NETCODE
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Network link..."), 'N', netlink_cmd },
+ { ' ', N_("FT&P link..."), 'P', ftplink_cmd },
+#endif
+ { ' ', "", ' ', 0 },
+#ifdef OS2_NT
+ { ' ', N_("&Drive... M-d"), 'D', drive_cmd_a },
+#endif
+ { ' ', N_("&Rescan C-r"), 'R', reread_cmd }
+};
+
+static menu_entry RightMenu [] = {
+ { ' ', N_("&Listing mode..."), 'L', listing_cmd },
+ { ' ', N_("&Quick view C-x q"), 'Q', quick_view_cmd },
+ { ' ', N_("&Info C-x i"), 'I', info_cmd },
+ { ' ', N_("&Tree"), 'T', tree_cmd },
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Sort order..."), 'S', sort_cmd },
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Filter..."), 'F', filter_cmd },
+#ifdef USE_NETCODE
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Network link..."), 'N', netlink_cmd },
+ { ' ', N_("FT&P link..."), 'P', ftplink_cmd },
+#endif
+ { ' ', "", ' ', 0 },
+#ifdef OS2_NT
+ { ' ', N_("&Drive... M-d"), 'D', drive_cmd_b },
+#endif
+ { ' ', N_("&Rescan C-r"), 'R', reread_cmd }
+};
+
+static menu_entry FileMenu [] = {
+ { ' ', N_("&User menu F2"), 'U', user_menu_cmd },
+ { ' ', N_("&View F3"), 'V', view_cmd },
+ { ' ', N_("&Filtered view M-!"), 'F', filtered_view_cmd },
+ { ' ', N_("&Edit F4"), 'E', edit_cmd },
+ { ' ', N_("&Copy F5"), 'C', copy_cmd },
+ { ' ', N_("c&Hmod C-x c"), 'H', chmod_cmd },
+#ifndef OS2_NT
+ { ' ', N_("&Link C-x l"), 'L', link_cmd },
+ { ' ', N_("&SymLink C-x s"), 'S', symlink_cmd },
+ { ' ', N_("edit s&Ymlink C-x C-s"), 'Y', edit_symlink_cmd },
+ { ' ', N_("ch&Own C-x o"), 'O', chown_cmd },
+ { ' ', N_("&Advanced chown "), 'A', chown_advanced_cmd },
+#endif
+ { ' ', N_("&Rename/Move F6"), 'R', ren_cmd },
+ { ' ', N_("&Mkdir F7"), 'M', mkdir_cmd },
+ { ' ', N_("&Delete F8"), 'D', delete_cmd },
+ { ' ', N_("&Quick cd M-c"), 'Q', quick_cd_cmd },
+ { ' ', "", ' ', 0 },
+ { ' ', N_("select &Group M-+"), 'G', select_cmd },
+ { ' ', N_("u&Nselect group M-\\"),'N', unselect_cmd },
+ { ' ', N_("reverse selec&Tion M-*"), 'T', reverse_selection_cmd },
+ { ' ', "", ' ', 0 },
+ { ' ', N_("e&Xit F10"), 'X', (callfn) quit_cmd }
+};
+
+void external_panelize (void);
+static menu_entry CmdMenu [] = {
+ /* I know, I'm lazy, but the tree widget when it's not running
+ * as a panel still has some problems, I have not yet finished
+ * the WTree widget port, sorry.
+ */
+ { ' ', N_("&Directory tree"), 'D', tree_box },
+ { ' ', N_("&Find file M-?"), 'F', find_cmd },
+#ifndef HAVE_XVIEW
+ { ' ', N_("s&Wap panels C-u"), 'W', swap_cmd },
+ { ' ', N_("switch &Panels on/off C-o"), 'P', view_other_cmd },
+#endif
+ { ' ', N_("&Compare directories C-x d"), 'C', compare_dirs_cmd },
+ { ' ', N_("e&Xternal panelize C-x !"), 'X', external_panelize },
+#ifdef HAVE_DUSUM
+ { ' ', N_("show directory s&Izes"), 'I', dirsizes_cmd },
+#endif
+ { ' ', "", ' ', 0 },
+ { ' ', N_("command &History"), 'H', history_cmd },
+ { ' ', N_("di&Rectory hotlist C-\\"), 'R', quick_chdir_cmd },
+#ifdef USE_VFS
+ { ' ', N_("&Active VFS list C-x a"), 'A', reselect_vfs },
+#endif
+#ifdef WITH_BACKGROUND
+ { ' ', N_("&Background jobs C-x j"), 'B', jobs_cmd },
+#endif
+ { ' ', "", ' ', 0 },
+#ifdef USE_EXT2FSLIB
+ { ' ', N_("&Undelete files (ext2fs only)"), 'U', undelete_cmd },
+#endif
+#ifdef VERSION_4
+ { ' ', N_("&Listing format edit"), 'L', listmode_cmd},
+#endif
+ { ' ', N_("&Extension file edit"), 'E', ext_cmd },
+ { ' ', N_("&Menu file edit"), 'M', menu_edit_cmd }
+};
+
+/* Must keep in sync with the constants in menu_cmd */
+static menu_entry OptMenu [] = {
+ { ' ', N_("&Configuration..."), 'C', configure_box },
+ { ' ', N_("&Layout..."), 'L', layout_cmd },
+ { ' ', N_("c&Onfirmation..."), 'O', confirm_box },
+ { ' ', N_("&Display bits..."), 'D', display_bits_box },
+#if !defined(HAVE_X) && !defined(OS2_NT)
+ { ' ', N_("learn &Keys..."), 'K', learn_keys },
+#endif
+#ifdef USE_VFS
+ { ' ', N_("&Virtual FS..."), 'V', configure_vfs },
+#endif
+ { ' ', "", ' ', 0 },
+ { ' ', N_("&Save setup"), 'S', save_setup_cmd }
+};
+
+#define menu_entries(x) sizeof(x)/sizeof(menu_entry)
+
+Menu MenuBar [5];
+#ifndef HAVE_X
+static Menu MenuBarEmpty [5];
+#endif
+
+void
+init_menu (void)
+{
+ int i;
+
+#ifdef HAVE_X
+ MenuBar [0] = create_menu (_(" Left "), PanelMenu, menu_entries (PanelMenu));
+#else
+ MenuBar [0] = create_menu ( horizontal_split ? _(" Above ") : _(" Left "),
+ PanelMenu, menu_entries (PanelMenu));
+#endif
+ MenuBar [1] = create_menu (_(" File "), FileMenu, menu_entries (FileMenu));
+ MenuBar [2] = create_menu (_(" Command "), CmdMenu, menu_entries (CmdMenu));
+ MenuBar [3] = create_menu (_(" Options "), OptMenu, menu_entries (OptMenu));
+#ifndef HAVE_XVIEW
+#ifdef HAVE_X
+ MenuBar [4] = create_menu (_(" Right "), RightMenu, menu_entries (PanelMenu));
+#else
+ MenuBar [4] = create_menu (horizontal_split ? _(" Below ") : _(" Right "),
+ RightMenu, menu_entries (PanelMenu));
+ for (i = 0; i < 5; i++)
+ MenuBarEmpty [i] = create_menu (MenuBar [i]->name, 0, 0);
+#endif /* HAVE_X */
+#endif /* ! HAVE_XVIEW */
+}
+
+void
+done_menu (void)
+{
+ int i;
+
+#ifndef HAVE_XVIEW
+ for (i = 0; i < 5; i++){
+ destroy_menu (MenuBar [i]);
+#ifndef HAVE_X
+ destroy_menu (MenuBarEmpty [i]);
+#endif
+#else
+ for (i = 0; i < 4; i++){
+ destroy_menu (MenuBar [i]);
+#endif
+ }
+}
+#endif
+
+static void
+menu_last_selected_cmd (void)
+{
+ the_menubar->active = 1;
+ the_menubar->dropped = drop_menus;
+ the_menubar->previous_selection = dlg_item_number (midnight_dlg);
+ dlg_select_widget (midnight_dlg, the_menubar);
+}
+
+static void
+menu_cmd (void)
+{
+ if (the_menubar->active)
+ return;
+
+ if (get_current_index () == 0)
+ the_menubar->selected = 0;
+ else
+ the_menubar->selected = 4;
+ menu_last_selected_cmd ();
+}
+
+/* Flag toggling functions */
+void
+toggle_confirm_delete (void)
+{
+ confirm_delete = !confirm_delete;
+}
+
+void
+toggle_fast_reload (void)
+{
+ fast_reload = !fast_reload;
+ if (fast_reload_w == 0 && fast_reload){
+ message (0, _(" Information "),
+ _(" Using the fast reload option may not reflect the exact \n"
+ " directory contents. In this cases you'll need to do a \n"
+ " manual reload of the directory. See the man page for \n"
+ " the details. "));
+ fast_reload_w = 1;
+ }
+}
+
+void
+toggle_mix_all_files (void)
+{
+ mix_all_files = !mix_all_files;
+ update_panels (UP_RELOAD, UP_KEEPSEL);
+}
+
+void
+toggle_show_backup (void)
+{
+ show_backups = !show_backups;
+ update_panels (UP_RELOAD, UP_KEEPSEL);
+}
+
+void
+toggle_show_hidden (void)
+{
+ show_dot_files = !show_dot_files;
+ update_panels (UP_RELOAD, UP_KEEPSEL);
+}
+
+void
+toggle_show_mini_status (void)
+{
+ show_mini_info = !show_mini_info;
+ paint_panel (cpanel);
+ if (get_other_type () == view_listing)
+ paint_panel (opanel);
+}
+
+void
+toggle_align_extensions (void)
+{
+ align_extensions = !align_extensions;
+}
+
+#ifndef PORT_HAS_CREATE_PANELS
+void
+create_panels (void)
+{
+ int current_index;
+ int other_index;
+ int current_mode;
+ int other_mode;
+ char original_dir [1024];
+
+ original_dir [0] = 0;
+
+ if (boot_current_is_left){
+ current_index = 0;
+ other_index = 1;
+ current_mode = startup_left_mode;
+ other_mode = startup_right_mode;
+ } else {
+ current_index = 1;
+ other_index = 0;
+ current_mode = startup_right_mode;
+ other_mode = startup_left_mode;
+ }
+ /* Creates the left panel */
+ if (this_dir){
+ if (other_dir){
+ /* Ok, user has specified two dirs, save the original one,
+ * since we may not be able to chdir to the proper
+ * second directory later
+ */
+ mc_get_current_wd (original_dir, sizeof (original_dir)-2);
+ }
+ mc_chdir (this_dir);
+ }
+ set_display_type (current_index, current_mode);
+
+ /* The other panel */
+ if (other_dir){
+ if (original_dir [0])
+ mc_chdir (original_dir);
+ mc_chdir (other_dir);
+ }
+ set_display_type (other_index, other_mode);
+
+ if (startup_left_mode == view_listing){
+ current_panel = left_panel;
+ } else {
+ if (right_panel)
+ current_panel = right_panel;
+ else
+ current_panel = left_panel;
+ }
+
+ /* Create the nice widgets */
+ cmdline = command_new (0, 0, 0);
+ the_prompt = label_new (0, 0, prompt, NULL);
+ the_prompt->transparent = 1;
+ the_bar = buttonbar_new (keybar_visible);
+
+#ifndef HAVE_GNOME
+ the_hint = label_new (0, 0, 0, NULL);
+ the_hint->transparent = 1;
+ the_hint->auto_adjust_cols = 0;
+ the_hint->widget.cols = COLS;
+#endif
+
+#ifndef HAVE_XVIEW
+ the_menubar = menubar_new (0, 0, COLS, MenuBar, 5);
+#else
+ the_menubar = menubar_new (0, 0, COLS, MenuBar + 1, 3);
+ the_bar2 = buttonbar_new (keybar_visible);
+#endif
+}
+#endif
+
+static void copy_current_pathname (void)
+{
+ if (!command_prompt)
+ return;
+
+ stuff (input_w (cmdline), cpanel->cwd, 0);
+ if (cpanel->cwd [strlen (cpanel->cwd) - 1] != PATH_SEP)
+ stuff (input_w (cmdline), PATH_SEP_STR, 0);
+}
+
+static void copy_other_pathname (void)
+{
+ if (get_other_type () != view_listing)
+ return;
+
+ if (!command_prompt)
+ return;
+
+ stuff (input_w (cmdline), opanel->cwd, 0);
+ if (cpanel->cwd [strlen (opanel->cwd) - 1] != PATH_SEP)
+ stuff (input_w (cmdline), PATH_SEP_STR, 0);
+}
+
+static void copy_readlink (WPanel *panel)
+{
+ if (!command_prompt)
+ return;
+ if (S_ISLNK (selection (panel)->buf.st_mode)) {
+ char buffer [MC_MAXPATHLEN];
+ char *p = concat_dir_and_file (panel->cwd, selection (panel)->fname);
+ int i;
+
+ i = mc_readlink (p, buffer, MC_MAXPATHLEN);
+ free (p);
+ if (i > 0) {
+ buffer [i] = 0;
+ stuff (input_w (cmdline), buffer, 0);
+ }
+ }
+}
+
+static void copy_current_readlink (void)
+{
+ copy_readlink (cpanel);
+}
+
+static void copy_other_readlink (void)
+{
+ if (get_other_type () != view_listing)
+ return;
+ copy_readlink (opanel);
+}
+
+/* Inserts the selected file name into the input line */
+/* Exported so that the command modules uses it */
+void copy_prog_name (void)
+{
+ char *tmp;
+ if (!command_prompt)
+ return;
+
+ if (get_current_type () == view_tree){
+ WTree *tree = (WTree *) get_panel_widget (get_current_index ());
+ tmp = name_quote (tree->selected_ptr->name, 1);
+ } else
+ tmp = name_quote (selection (cpanel)->fname, 1);
+ stuff (input_w (cmdline), tmp, 1);
+ free (tmp);
+}
+
+static void copy_tagged (WPanel *panel)
+{
+ int i;
+
+ if (!command_prompt)
+ return;
+ input_disable_update (input_w (cmdline));
+ if (panel->marked){
+ for (i = 0; i < panel->count; i++)
+ if (panel->dir.list [i].f.marked) {
+ char *tmp = name_quote (panel->dir.list [i].fname, 1);
+ stuff (input_w (cmdline), tmp, 1);
+ free (tmp);
+ }
+ } else {
+ char *tmp = name_quote (panel->dir.list [panel->selected].fname, 1);
+ stuff (input_w (cmdline), tmp, 1);
+ free (tmp);
+ }
+ input_enable_update (input_w (cmdline));
+}
+
+static void copy_current_tagged (void)
+{
+ copy_tagged (cpanel);
+}
+
+static void copy_other_tagged (void)
+{
+ if (get_other_type () != view_listing)
+ return;
+ copy_tagged (opanel);
+}
+
+static void do_suspend_cmd (void)
+{
+ pre_exec ();
+
+ if (console_flag && !use_subshell)
+ restore_console ();
+
+#ifndef OS2_NT
+ {
+ struct sigaction sigtstp_action;
+
+ /* Make sure that the SIGTSTP below will suspend us directly,
+ without calling ncurses' SIGTSTP handler; we *don't* want
+ ncurses to redraw the screen immediately after the SIGCONT */
+ sigaction (SIGTSTP, &startup_handler, &sigtstp_action);
+
+ kill (getpid (), SIGTSTP);
+
+ /* Restore previous SIGTSTP action */
+ sigaction (SIGTSTP, &sigtstp_action, NULL);
+ }
+#endif
+
+ if (console_flag && !use_subshell)
+ handle_console (CONSOLE_SAVE);
+
+ edition_post_exec ();
+}
+
+void suspend_cmd (void)
+{
+ save_cwds_stat ();
+ do_suspend_cmd ();
+ update_panels (UP_OPTIMIZE, UP_KEEPSEL);
+ do_refresh ();
+}
+
+void init_labels (Widget *paneletc)
+{
+ define_label (midnight_dlg, paneletc, 1, _("Help"), help_cmd);
+ define_label (midnight_dlg, paneletc, 2, _("Menu"), user_menu_cmd);
+ define_label (midnight_dlg, paneletc, 9, _("PullDn"), menu_cmd);
+ define_label (midnight_dlg, paneletc, 10, _("Quit"), (voidfn) quit_cmd);
+}
+
+#ifndef HAVE_XVIEW
+static key_map ctl_x_map [] = {
+ { XCTRL('c'), (callfn) quit_cmd },
+#ifdef USE_VFS
+ { 'a', reselect_vfs },
+#endif
+ { 'd', compare_dirs_cmd },
+#ifndef HAVE_GNOME
+ { 'p', copy_current_pathname },
+ { XCTRL('p'), copy_other_pathname },
+ { 't', copy_current_tagged },
+ { XCTRL('t'), copy_other_tagged },
+#endif
+ { 'c', chmod_cmd },
+#ifndef OS2_NT
+ { 'o', chown_cmd },
+ { 'l', link_cmd },
+ { XCTRL('l'), other_symlink_cmd },
+ { 's', symlink_cmd },
+ { XCTRL('s'), edit_symlink_cmd },
+ { 'r', copy_current_readlink },
+ { XCTRL('r'), copy_other_readlink },
+#endif
+#ifndef HAVE_GNOME
+ { 'i', info_cmd_no_menu },
+ { 'q', quick_cmd_no_menu },
+#endif
+ { 'h', add2hotlist_cmd },
+ { '!', external_panelize },
+#ifdef WITH_BACKGROUND
+ { 'j', jobs_cmd },
+#endif
+#ifdef HAVE_SETSOCKOPT
+ { '%', source_routing },
+#endif
+ { 0, 0 }
+};
+
+static int ctl_x_map_enabled = 0;
+
+static void ctl_x_cmd (int ignore)
+{
+ ctl_x_map_enabled = 1;
+}
+
+static void nothing ()
+{
+}
+
+static key_map default_map [] = {
+#ifndef HAVE_GNOME
+ { KEY_F(19), menu_last_selected_cmd },
+ { KEY_F(20), (key_callback) quiet_quit_cmd },
+
+ /* Copy useful information to the command line */
+ { ALT('\n'), copy_prog_name },
+ { ALT('\r'), copy_prog_name },
+ { ALT('a'), copy_current_pathname },
+ { ALT('A'), copy_other_pathname },
+
+ { ALT('c'), quick_cd_cmd },
+
+ /* To access the directory hotlist */
+ { XCTRL('\\'), quick_chdir_cmd },
+
+ /* Suspend */
+ { XCTRL('z'), suspend_cmd },
+#endif
+ /* The filtered view command */
+ { ALT('!'), filtered_view_cmd_cpanel },
+
+ /* Find file */
+ { ALT('?'), find_cmd },
+
+ /* Panel refresh */
+ { XCTRL('r'), reread_cmd },
+
+ { ALT('t'), toggle_listing_cmd },
+
+#ifndef HAVE_X
+ /* Swap panels */
+ { XCTRL('u'), swap_cmd },
+
+ /* View output */
+ { XCTRL('o'), view_other_cmd },
+#endif
+
+ /* Control-X keybindings */
+ { XCTRL('x'), ctl_x_cmd },
+
+ /* Trap dlg's exit commands */
+ { ESC_CHAR, nothing },
+ { XCTRL('c'), nothing },
+ { XCTRL('g'), nothing },
+ { 0, 0 },
+};
+#endif
+
+#ifndef HAVE_X
+static void setup_sigwinch ()
+{
+#ifndef OS2_NT
+ struct sigaction act, oact;
+
+# if defined(HAVE_SLANG) || NCURSES_VERSION_MAJOR >= 4
+# ifdef SIGWINCH
+ act.sa_handler = flag_winch;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+# ifdef SA_RESTART
+ act.sa_flags |= SA_RESTART;
+# endif
+ sigaction (SIGWINCH, &act, &oact);
+# endif
+# endif
+#endif
+}
+
+static void
+setup_pre ()
+{
+ /* Call all the inits */
+#ifndef HAVE_SLANG
+ meta (stdscr, eight_bit_clean);
+#else
+ SLsmg_Display_Eight_Bit = full_eight_bits ? 128 : 160;
+#endif
+}
+#else
+#define setup_pre()
+#define setup_sigwinch()
+#endif
+
+static void
+setup_post ()
+{
+ setup_sigwinch ();
+
+ init_uid_gid_cache ();
+
+#ifndef HAVE_X
+ if (baudrate () < 9600 || slow_terminal){
+ verbose = 0;
+ }
+ if (use_mouse_p)
+ init_mouse ();
+#endif
+
+ midnight_colors [0] = 0;
+ midnight_colors [1] = REVERSE_COLOR; /* FOCUSC */
+ midnight_colors [2] = INPUT_COLOR; /* HOT_NORMALC */
+ midnight_colors [3] = NORMAL_COLOR; /* HOT_FOCUSC */
+}
+
+static void setup_mc (void)
+{
+ setup_pre ();
+ init_menu ();
+ create_panels ();
+
+#ifdef HAVE_GNOME
+ return;
+#endif
+ setup_panels ();
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell)
+ add_select_channel (subshell_pty, load_prompt, 0);
+#endif
+
+ setup_post ();
+}
+
+static void setup_dummy_mc (const char *file)
+{
+ char d[MC_MAXPATHLEN];
+
+ mc_get_current_wd (d, MC_MAXPATHLEN);
+ setup_mc ();
+ mc_chdir (d);
+
+ /* Create a fake current_panel, this is needed because the
+ * expand_format routine will use current panel.
+ */
+ strcpy (cpanel->cwd, d);
+ cpanel->selected = 0;
+ cpanel->count = 1;
+ cpanel->dir.list[0].fname = (char *) file;
+}
+
+static void done_mc ()
+{
+ done_menu ();
+
+ /* Setup shutdown
+ *
+ * We sync the profiles since the hotlist may have changed, while
+ * we only change the setup data if we have the auto save feature set
+ */
+ if (auto_save_setup)
+ save_setup (); /* does also call save_hotlist */
+ else
+ save_hotlist();
+ done_screen ();
+ vfs_add_current_stamps ();
+ if (xterm_flag && xterm_hintbar)
+ set_hintbar(_("Thank you for using GNU Midnight Commander"));
+}
+
+/* This should be called after destroy_dlg since panel widgets
+ * save their state on the profiles
+ */
+static void done_mc_profile ()
+{
+ if (!auto_save_setup)
+ profile_forget_profile (profile_name);
+ sync_profiles ();
+ done_setup ();
+ free_profiles ();
+}
+
+/* This routine only handles cpanel, and opanel, it is easy to
+ * change to use npanels, just loop over the number of panels
+ * and use get_panel_widget (i) and make the test done below
+ */
+void make_panels_dirty ()
+{
+ if (cpanel->dirty)
+ panel_update_contents (cpanel);
+
+ if ((get_other_type () == view_listing) && opanel->dirty)
+ panel_update_contents (opanel);
+}
+
+/* In OS/2 and Windows NT people want to actually type the '\' key frequently */
+#ifdef OS2_NT
+# define check_key_backslash(x) 0
+#else
+# define check_key_backslash(x) ((x) == '\\')
+#endif
+
+int midnight_callback (struct Dlg_head *h, int id, int msg)
+{
+ int i;
+
+ switch (msg){
+#ifndef HAVE_XVIEW
+
+ /* Speed up routine: now, we just set the */
+ case DLG_PRE_EVENT:
+ make_panels_dirty ();
+ return MSG_HANDLED;
+
+ case DLG_KEY:
+ if (ctl_x_map_enabled){
+ ctl_x_map_enabled = 0;
+ for (i = 0; ctl_x_map [i].key_code; i++)
+ if (id == ctl_x_map [i].key_code){
+ (*ctl_x_map [i].fn)(id);
+ return MSG_HANDLED;
+ }
+ }
+
+ if (id == KEY_F(10) && !the_menubar->active){
+ quit_cmd ();
+ return MSG_HANDLED;
+ }
+
+ if (id == '\t')
+ free_completions (input_w (cmdline));
+
+ /* On Linux, we can tell the difference */
+ if (id == '\n' && ctrl_pressed ()){
+ copy_prog_name ();
+ return MSG_HANDLED;
+ }
+
+ if (id == '\n' && input_w (cmdline)->buffer [0]){
+ send_message_to (h, (Widget *) cmdline, WIDGET_KEY, id);
+ return MSG_HANDLED;
+ }
+
+ if ((!alternate_plus_minus || !(console_flag || xterm_flag)) &&
+ !quote && !cpanel->searching) {
+ if(!only_leading_plus_minus) {
+ /* Special treatement, since the input line will eat them */
+ if (id == '+' ) {
+ select_cmd ();
+ return MSG_HANDLED;
+ }
+
+ if (check_key_backslash (id) || id == '-'){
+ unselect_cmd ();
+ return MSG_HANDLED;
+ }
+
+ if (id == '*') {
+ reverse_selection_cmd ();
+ return MSG_HANDLED;
+ }
+ } else if (command_prompt && !strlen (input_w (cmdline)->buffer)) {
+ /* Special treatement '+', '-', '\', '*' only when this is
+ * first char on input line
+ */
+
+ if (id == '+') {
+ select_cmd ();
+ return MSG_HANDLED;
+ }
+
+ if (check_key_backslash (id) || id == '-') {
+ unselect_cmd ();
+ return MSG_HANDLED;
+ }
+
+ if (id == '*') {
+ reverse_selection_cmd ();
+ return MSG_HANDLED;
+ }
+ }
+ }
+ break;
+
+ case DLG_HOTKEY_HANDLED:
+ if (get_current_type () == view_listing)
+ cpanel->searching = 0;
+ break;
+
+ case DLG_UNHANDLED_KEY:
+ if (command_prompt){
+ int v;
+
+ v = send_message_to (h, (Widget *) cmdline, WIDGET_KEY, id);
+ if (v)
+ return v;
+ }
+ if (ctl_x_map_enabled){
+ ctl_x_map_enabled = 0;
+ for (i = 0; ctl_x_map [i].key_code; i++)
+ if (id == ctl_x_map [i].key_code){
+ (*ctl_x_map [i].fn)(id);
+ return MSG_HANDLED;
+ }
+ } else {
+ for (i = 0; default_map [i].key_code; i++){
+ if (id == default_map [i].key_code){
+ (*default_map [i].fn)(id);
+ return MSG_HANDLED;
+ }
+ }
+ }
+ return MSG_NOT_HANDLED;
+
+#endif
+#ifndef HAVE_X
+ /* We handle the special case of the output lines */
+ case DLG_DRAW:
+ attrset (SELECTED_COLOR);
+ if (console_flag && output_lines)
+ show_console_contents (output_start_y,
+ LINES-output_lines-keybar_visible-1,
+ LINES-keybar_visible-1);
+ break;
+#endif
+
+ }
+ return default_dlg_callback (h, id, msg);
+}
+
+#ifdef HAVE_X
+/* This should be rewritten in order to support as many panel containers as
+ the user wants */
+
+#ifndef HAVE_GNOME
+widget_data containers [2];
+int containers_no = 2;
+
+void
+xtoolkit_panel_setup ()
+{
+ containers [0] = x_create_panel_container (0);
+ containers [1] = x_create_panel_container (1);
+ input_w (cmdline)->widget.wcontainer = containers [0];
+ input_w (cmdline)->widget.area = AREA_BOTTOM;
+ the_prompt->widget.wcontainer = containers [0];
+ the_prompt->widget.area = AREA_BOTTOM;
+ the_bar->widget.wcontainer = containers [0];
+ the_bar->widget.area = AREA_TOP;
+#ifdef HAVE_XVIEW
+ the_bar2->widget.wcontainer = containers [1];
+ the_bar2->widget.area = AREA_TOP;
+#endif
+ get_panel_widget (0)->wcontainer = containers [0];
+ get_panel_widget (0)->area = AREA_RIGHT;
+ get_panel_widget (1)->wcontainer = containers [1];
+ get_panel_widget (1)->area = AREA_RIGHT;
+ the_menubar->widget.wcontainer = (widget_data) NULL;
+}
+#else
+# define xtoolkit_panel_setup()
+#endif
+
+#else
+# define xtoolkit_panel_setup()
+#endif
+
+#ifndef PORT_HAS_LOAD_HINT
+void load_hint ()
+{
+ char *hint;
+
+ if (!the_hint->widget.parent)
+ return;
+
+ if (!message_visible && (!xterm_flag || !xterm_hintbar)){
+ label_set_text (the_hint, 0);
+ return;
+ }
+
+ if ((hint = get_random_hint ())){
+ if (*hint)
+ set_hintbar (hint);
+ free (hint);
+ } else {
+ set_hintbar ("The Midnight Commander " VERSION
+ " (C) 1995-1997 the Free Software Foundation");
+ }
+}
+#endif
+
+static void
+setup_panels_and_run_mc ()
+{
+ int first, second;
+
+ xtoolkit_panel_setup ();
+ tk_new_frame (midnight_dlg, "p.");
+#ifndef HAVE_X
+ add_widget (midnight_dlg, the_hint);
+#endif /* HAVE_X */
+ load_hint ();
+ add_widgetl (midnight_dlg, cmdline, XV_WLAY_RIGHTOF);
+ add_widgetl (midnight_dlg, the_prompt, XV_WLAY_DONTCARE);
+ tk_end_frame ();
+ add_widget (midnight_dlg, the_bar);
+#ifdef HAVE_XVIEW
+ add_widget (midnight_dlg, the_bar2);
+#endif
+ if (boot_current_is_left){
+ first = 1;
+ second = 0;
+ } else {
+ first = 0;
+ second = 1;
+ }
+ add_widget (midnight_dlg, get_panel_widget (first));
+ add_widget (midnight_dlg, get_panel_widget (second));
+ add_widget (midnight_dlg, the_menubar);
+
+ init_labels (get_panel_widget (0));
+ init_labels (get_panel_widget (1));
+
+ /* Run the Midnight Commander if no file was specified in the command line */
+ run_dlg (midnight_dlg);
+}
+
+/* result must be free'd (I think this should go in util.c) */
+char *
+prepend_cwd_on_local (char *filename)
+{
+ char *d;
+ int l;
+
+ if (vfs_file_is_local (filename)){
+ if (*filename == PATH_SEP) /* an absolute pathname */
+ return strdup (filename);
+ d = malloc (MC_MAXPATHLEN + strlen (filename) + 2);
+ mc_get_current_wd (d, MC_MAXPATHLEN);
+ l = strlen(d);
+ d[l++] = PATH_SEP;
+ strcpy (d + l, filename);
+ return canonicalize_pathname (d);
+ } else
+ return strdup (filename);
+}
+
+#ifdef USE_INTERNAL_EDIT
+void edit (const char *file_name, int startline);
+
+int
+mc_maybe_editor_or_viewer (void)
+{
+ char *path;
+
+ if (!(view_one_file || edit_one_file))
+ return 0;
+
+ /* Invoke the internal view/edit routine with:
+ * the default processing and forcing the internal viewer/editor
+ */
+ if (view_one_file) {
+ path = prepend_cwd_on_local (view_one_file);
+ setup_dummy_mc (path);
+ view_file (path, 0, 1);
+ }
+#ifdef USE_INTERNAL_EDIT
+ else {
+ path = prepend_cwd_on_local ("");
+ setup_dummy_mc (path);
+ edit (edit_one_file, 1);
+ }
+#endif
+ free (path);
+ midnight_shutdown = 1;
+ done_mc ();
+ return 1;
+}
+
+#endif
+
+static void
+do_nc (void)
+{
+ midnight_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors, midnight_callback, "[main]", "midnight", 0);
+ midnight_dlg->has_menubar = 1;
+
+#ifdef USE_INTERNAL_EDIT
+ /* Check if we were invoked as an editor or file viewer */
+ if (mc_maybe_editor_or_viewer ())
+ return;
+#endif
+
+ setup_mc ();
+
+#ifndef HAVE_GNOME
+ setup_panels_and_run_mc ();
+#endif
+
+ /* Program end */
+ midnight_shutdown = 1;
+
+ /* destroy_dlg destroys even cpanel->cwd, so we have to save a copy :) */
+ if (print_last_wd) {
+ if (!vfs_current_is_local ())
+ last_wd_string = strdup (".");
+ else
+ last_wd_string = strdup (cpanel->cwd);
+ }
+ done_mc ();
+
+#ifndef HAVE_GNOME
+ destroy_dlg (midnight_dlg);
+ current_panel = 0;
+#endif
+ done_mc_profile ();
+}
+
+#include "features.inc"
+
+static void
+version (int verbose)
+{
+ fprintf (stderr, "The Midnight Commander %s\n", VERSION);
+ if (!verbose)
+ return;
+
+#ifndef HAVE_X
+ fprintf (stderr,
+ _("with mouse support on xterm%s.\n"),
+ status_mouse_support ? _(" and the Linux console") : "");
+#endif /* HAVE_X */
+
+ fprintf (stderr, features);
+ if (print_last_wd)
+ write (stdout_fd, ".", 1);
+}
+
+#if defined (_OS_NT)
+/* Windows NT code */
+#define CONTROL_FILE "\\mc.%d.control"
+char control_file [sizeof (CONTROL_FILE) + 8];
+
+void
+OS_Setup ()
+{
+ SetConsoleTitle ("GNU Midnight Commander");
+
+ shell = getenv ("COMSPEC");
+ if (!shell || !*shell)
+ shell = get_default_shell ();
+
+ /* Default opening mode for files is binary, not text (CR/LF translation) */
+#ifndef __EMX__
+ _fmode = O_BINARY;
+#endif
+
+ mc_home = get_mc_lib_dir ();
+}
+
+static void
+sigchld_handler_no_subshell (int sig)
+{
+}
+
+void
+init_sigchld (void)
+{
+}
+
+void
+init_sigfatals (void)
+{
+ /* Nothing to be done on the OS/2, Windows/NT */
+}
+
+
+#elif defined (__os2__)
+/* OS/2 Version */
+# define CONTROL_FILE "\\mc.%d.control"
+char control_file [sizeof (CONTROL_FILE) + 8];
+
+void
+OS_Setup (void)
+{
+ /* .ado: This does not work: */
+ /* DosSMSetTitle ((PSZ) "This is my app"); */
+ /* In DEF: IMPORTS
+ DosSMSetTitle = SESMGR.DOSSMSETTITLE */
+ shell = getenv ("COMSPEC");
+ if (!shell || !*shell)
+ shell = get_default_shell ();
+
+ mc_home = get_mc_lib_dir ();
+}
+
+static void
+sigchld_handler_no_subshell (int sig)
+{
+}
+
+void
+init_sigchld (void)
+{
+}
+
+void
+init_sigfatals (void)
+{
+ /* Nothing to be done on the OS/2, Windows/NT */
+}
+#else
+
+/* Unix version */
+#define CONTROL_FILE "/tmp/mc.%d.control"
+char control_file [sizeof (CONTROL_FILE) + 8];
+
+void
+OS_Setup ()
+{
+ char *termvalue;
+ char *mc_libdir;
+
+ termvalue = getenv ("TERM");
+ if (!termvalue){
+ fprintf (stderr, _("The TERM environment variable is unset!\n"));
+ termvalue = "";
+ }
+#ifndef HAVE_X
+ if (force_xterm || (strncmp (termvalue, "xterm", 5) == 0 || strcmp (termvalue, "dtterm") == 0)){
+ use_mouse_p = XTERM_MOUSE;
+ xterm_flag = 1;
+# ifdef SET_TITLE
+ printf ("\33]0;GNU Midnight Commander\7");
+# endif
+ }
+#endif /* ! HAVE_X */
+ shell = getenv ("SHELL");
+ if (!shell || !*shell)
+ shell = strdup (getpwuid (geteuid ())->pw_shell);
+ if (!shell || !*shell)
+ shell = "/bin/sh";
+
+ sprintf (control_file, CONTROL_FILE, getpid ());
+ my_putenv ("MC_CONTROL_FILE", control_file);
+
+ /* This is the directory, where MC was installed, on Unix this is LIBDIR */
+ /* and can be overriden by the MCHOME environment variable */
+ if ((mc_libdir = getenv ("MCHOME")) != NULL) {
+ mc_home = strdup (mc_libdir);
+ } else {
+ mc_home = strdup (LIBDIR);
+ }
+}
+
+static void
+sigchld_handler_no_subshell (int sig)
+{
+#ifndef HAVE_X
+ int pid, status;
+
+ if (!console_flag)
+ return;
+
+ /* COMMENT: if it were true that after the call to handle_console(..INIT)
+ the value of console_flag never changed, we could simply not install
+ this handler at all if (!console_flag && !use_subshell). */
+
+ /* That comment is no longer true. We need to wait() on a sigchld
+ handler (that's at least what the tarfs code expects currently). */
+
+#ifndef SCO_FLAVOR
+ pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
+
+ if (pid == cons_saver_pid){
+ /* {{{ Someone has stopped or killed cons.saver; restart it */
+
+ if (WIFSTOPPED (status))
+ kill (pid, SIGCONT);
+ else
+ {
+ handle_console (CONSOLE_DONE);
+ handle_console (CONSOLE_INIT);
+ }
+ /* }}} */
+ }
+#endif /* ! SCO_FLAVOR */
+
+ /* If we get here, some other child exited; ignore it */
+#endif /* ! HAVE_X */
+}
+
+#if 0
+void
+mc_fatal_signal (int signum)
+{
+ volatile int x;
+ char cmd;
+ pid_t pid;
+ char *args [4] = { "gdb", NULL, NULL, NULL };
+ char pid [20];
+
+ sprintf (buf, "%d", getpid ());
+ fprintf (stderr,
+ "Midnight Commander fatal error, PID=%d\n"
+ "What to do: [e]xit, [s]tack trace, [a]ttach to process\n", getpid ());
+
+ read (1, &cmd, 1);
+ if (cmd == 'a'){
+ for (x = 1; x;)
+ ;
+ }
+ if (cmd == 's'){
+ args [1] = program_name;
+ args [2] = buf;
+ pid = fork ();
+ if (pid == -1){
+ fprintf (stderr, "Could not fork, exiting\n");
+ exit (0);
+ }
+ if (pid == 0){
+ stack_trace (args);
+ } else {
+ while (1)
+ ;
+ }
+ }
+ exit (0);
+}
+
+void
+init_sigfatals (void)
+{
+ struct sigaction sa;
+
+ sa.sa_hanlder = mc_fatal_signal;
+ sa.sa_mask = 0;
+ sa.sa_flags = 0;
+
+ sigaction (SIGSEGV, &sa, NULL);
+ sigaction (SIGBUS, &sa, NULL);
+ sigaction (SIGFPE, &sa, NULL);
+}
+#else
+#define init_sigfatals()
+#endif
+
+void
+init_sigchld (void)
+{
+ struct sigaction sigchld_action;
+
+ sigchld_action.sa_handler =
+#ifdef HAVE_SUBSHELL_SUPPORT
+ use_subshell ? sigchld_handler :
+#endif
+ sigchld_handler_no_subshell;
+
+ sigemptyset (&sigchld_action.sa_mask);
+
+#ifdef SA_RESTART
+ sigchld_action.sa_flags = SA_RESTART;
+#else
+ sigchld_action.sa_flags = 0;
+#endif
+
+ sigaction (SIGCHLD, &sigchld_action, NULL);
+}
+
+#endif /* _OS_NT, __os2__, UNIX */
+
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ extern int SLtt_Try_Termcap;
+#endif
+
+#ifndef PORT_WANTS_ARGP
+static void
+print_mc_usage (void)
+{
+ version (0);
+ fprintf (stderr,
+ "Usage is:\n\n"
+ "mc [flags] [this_dir] [other_panel_dir]\n\n"
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ "-a, --stickchars Force use of +, -, | for line drawing.\n"
+#endif
+ "-b, --nocolor Force black and white display.\n"
+#ifdef WITH_BACKGROUND
+ "-B, --background [DEVEL-ONLY: Debug the background code]\n"
+#endif
+ "-c, --color Force color mode.\n"
+ "-C, --colors Specify colors (use --help-colors to get a list).\n"
+#ifdef USE_INTERNAL_EDIT
+ "-e, --edit Startup the internal editor.\n"
+#endif
+ "-d, --nomouse Disable mouse support.\n"
+ "-f, --libdir Print configured paths.\n"
+ "-h, --help Shows this help message.\n"
+ "-k, --resetsoft Reset softkeys (HP terminals only) to their terminfo/termcap\n"
+ " default.\n"
+ "-P, --printwd At exit, print the last working directory.\n"
+ "-s, --slow Disables verbose operation (for slow terminals).\n"
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ "-t, --termcap Activate support for the TERMCAP variable.\n"
+#endif
+#ifdef USE_NETCODE
+ "-l, --ftplog file Log ftpfs commands to the file.\n"
+#endif
+#if defined(HAVE_SLANG) && defined(OS2_NT)
+ "-S, --createcmdile Create command file to set default directory upon exit.\n"
+#endif
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+ "-u, --nosubshell Disable the concurrent subshell mode.\n"
+ "-U, --subshell Force the concurrent subshell mode.\n"
+ "-r, --forceexec Force subshell execution.\n"
+#endif
+ "-v, --view fname Start up into the viewer mode.\n"
+ "-V, --version Report version and configuration options.\n"
+ "-x, --xterm Force xterm mouse support and screen save/restore.\n"
+#ifdef HAVE_SUBSHELL_SUPPORT
+ "-X, --dbgsubshell [DEVEL-ONLY: Debug the subshell].\n"
+#endif
+ );
+}
+#endif /* PORT_WANTS_ARGP */
+
+static void
+print_color_usage (void)
+{
+ fprintf (stderr,
+ "--colors KEYWORD={FORE},{BACK}\n\n"
+ "{FORE} and {BACK} can be ommited, and the default will be used\n"
+ "\n"
+ "Keywords:\n"
+ " Global: errors, reverse, gauge, input\n"
+ " File display: normal, selected, marked, markselect\n"
+ " Dialog boxes: dnormal, dfocus, dhotnormal, dhotfocus\n"
+ " Menus: menu, menuhot, menusel, menuhotsel\n"
+ " Help: helpnormal, helpitalic, helplink, helpslink\n"
+ " File types: directory, execute, link, device, special, core\n"
+ "\n"
+ "Colors:\n"
+ " black, gray, red, brightred, green, brightgreen, brown,\n"
+ " yellow, blue, brightblue, magenta, brightmagenta, cyan,\n"
+ " brightcyan, lightgray and white\n\n");
+
+}
+
+
+static void
+probably_finish_program (void)
+{
+ if (finish_program){
+ if (print_last_wd)
+ printf (".");
+ exit (1);
+ }
+}
+
+enum {
+ GEOMETRY_KEY = -1,
+ NOWIN_KEY = -2
+};
+
+static void
+process_args (int c, char *option_arg)
+{
+ switch (c) {
+ case 'V':
+ version (1);
+ finish_program = 1;
+ break;
+
+ case 'c':
+ disable_colors = 0;
+#ifdef HAVE_SLANG
+ force_colors = 1;
+#endif
+ break;
+
+ case 'f':
+ fprintf (stderr, _("Library directory for the Midnight Commander: %s\n"), mc_home);
+ finish_program = 1;
+ break;
+
+ case 'm':
+ fprintf (stderr, _("Option -m is obsolete. Please look at Display Bits... in the Option's menu\n"));
+ finish_program = 1;
+ break;
+
+#ifdef USE_NETCODE
+ case 'l':
+ ftpfs_set_debug (option_arg);
+ break;
+#endif
+
+#ifdef OS2_NT
+ case 'S':
+ print_last_wd = 2;
+ batch_file_name = option_arg;
+ break;
+#endif
+
+ case 'd':
+ use_mouse_p = NO_MOUSE;
+ break;
+
+ case 'X':
+#ifdef HAVE_SUBSHELL_SUPPORT
+ debug_subshell = 1;
+#endif
+ break;
+
+ case 'U':
+#ifdef HAVE_SUBSHELL_SUPPORT
+ use_subshell = 1;
+#endif
+ break;
+
+ case 'u':
+#ifdef HAVE_SUBSHELL_SUPPORT
+ use_subshell = 0;
+#endif
+ break;
+
+ case 'r':
+#ifdef HAVE_SUBSHELL_SUPPORT
+ force_subshell_execution = 1;
+#endif
+ break;
+
+ case 'H':
+ print_color_usage ();
+ finish_program = 1;
+ break;
+
+ case 'h':
+#ifndef PORT_WANTS_ARGP
+ print_mc_usage ();
+ finish_program = 1;
+#endif
+ }
+}
+
+#ifdef PORT_WANTS_ARGP
+static struct argp_option argp_options [] = {
+#ifdef WITH_BACKGROUND
+ { "background", 'B', NULL, 0, N_("[DEVEL-ONLY: Debug the background code]"), 0 },
+#endif
+#if defined(HAVE_SLANG) && defined(OS2_NT)
+ { "createcmdfile", 'S', "CMDFILE", , 0, N_("Create command file to set default directory upon exit."), 1 },
+#endif
+ { "color", 'c', NULL, 0, N_("Force color mode."), 0 },
+ { "colors", 'C', "COLORS", 0, N_("Specify colors (use --help-colors to get a list)."), 1 },
+#ifdef HAVE_SUBSHELL_SUPPORT
+ { "dbgsubshell", 'X', NULL, 0, N_("[DEVEL-ONLY: Debug the subshell."), 0 },
+#endif
+ { "edit", 'e', "EDIT", 0, N_("Startup the internal editor."), 1 },
+ { "help", 'h', NULL, 0, N_("Shows this help message."), 0 },
+ { "help-colors", 'H', NULL, 0, N_("Help on how to specify colors."), 0 },
+#ifdef USE_NETCODE
+ { "ftplog", 'l', "FTPLOG", 0, N_("Log ftpfs commands to the file."), 1 },
+#endif
+ { "libdir", 'f', NULL, 0, N_("Prints out the configured paths."), 0 },
+ { NULL, 'm', NULL, OPTION_HIDDEN, NULL, 0 },
+ { "nocolor", 'b', NULL, 0, N_("Force black and white display."), 0 },
+ { "nomouse", 'd', NULL, 0, N_("Disable mouse support."), 0 },
+#ifdef HAVE_SUBSHELL_SUPPORT
+ { "subshell", 'U', NULL, 0, N_("Force the concurrent subshell mode"), 0 },
+ { "nosubshell", 'u', NULL, 0, N_("Disable the concurrent subshell mode."), 0 },
+ { "forceexec", 'r', NULL, 0, N_("Force subshell execution."), 0 },
+#endif
+ { "printwd", 'P', NULL, 0, N_("At exit, print the last working directory."), 0 },
+ { "resetsoft", 'k', NULL, 0, N_("Reset softkeys (HP terminals only) to their terminfo/termcap default."), 0},
+ { "slow", 's', NULL, 0, N_("Disables verbose operation (for slow terminals)."), 0 },
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ { "stickchars", 'a', NULL, 0, N_("Use simple symbols for line drawing."), 0 },
+#endif
+#ifdef HAVE_SUBSHELL_SUPPORT
+#endif
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ { "termcap", 't', NULL, 0, N_("Activate support for the TERMCAP variable."), 0 },
+#endif
+ { "version", 'V', NULL, 0, N_("Report versionand configuration options."), 0 },
+ { "view", 'v', NULL, 0, N_("Start up into the viewer mode."), 0 },
+ { "xterm", 'x', NULL, 0, N_("Force xterm mouse support and screen save/restore"), 0 },
+ { "geometry", GEOMETRY_KEY, "GEOMETRY", 0, N_("Geometry for the window"), 0 },
+ { "nowindows", NOWIN_KEY, NULL, 0, N_("No windows opened at startup"), 0 },
+ { NULL, 0, NULL, 0, NULL },
+};
+
+GList *directory_list = 0;
+GList *geometry_list = 0;
+int nowindows;
+
+static error_t
+parse_an_arg (int key, char *arg, struct argp_state *state)
+{
+ switch (key){
+#ifdef WITH_BACKGROUND
+ case 'B':
+ background_wait = 1;
+ return 0;
+#endif
+ case 'b':
+ disable_colors = 1;
+ return 0;
+
+ case 'P':
+ print_last_wd = 1;
+ return 0;
+
+ case 'k':
+ reset_hp_softkeys = 1;
+ return 0;
+
+ case 's':
+ slow_terminal = 1;
+ return 0;
+
+ case 'a':
+ force_ugly_line_drawing = 1;
+ return 0;
+
+ case 'x':
+ force_xterm = 1;
+ return 0;
+
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ case 't':
+ SLtt_Try_Termcap = 1;
+ return 0;
+#endif
+
+ case GEOMETRY_KEY:
+ geometry_list = g_list_append (geometry_list, arg);
+ return 0;
+
+ case NOWIN_KEY:
+ nowindows = 1;
+
+ case ARGP_KEY_ARG:
+ break;
+
+ case ARGP_KEY_INIT:
+ case ARGP_KEY_FINI:
+ return 0;
+
+ default:
+ process_args (key, arg);
+ }
+
+ if (arg){
+ if (edit_one_file)
+ edit_one_file = strdup (arg);
+ else if (view_one_file)
+ view_one_file = strdup (arg);
+ else
+ directory_list = g_list_append (directory_list, arg);
+ }
+ return 0;
+}
+
+static struct argp mc_argp_parser = {
+ argp_options, parse_an_arg, N_("[this dir] [other dir]"), NULL, NULL, NULL, NULL
+};
+
+#else
+
+static struct poptOption argumentTable[] = {
+#ifdef WITH_BACKGROUND
+ { "background", 'B', POPT_ARG_NONE, &background_wait, 0 },
+#endif
+#if defined(HAVE_SLANG) && defined(OS2_NT)
+ { "createcmdfile", 'S', POPT_ARG_STRING, NULL, 'S' },
+#endif
+ { "color", 'c', POPT_ARG_NONE, NULL, 'c' },
+ { "colors", 'C', POPT_ARG_STRING, &command_line_colors, 0 },
+#ifdef HAVE_SUBSHELL_SUPPORT
+ { "dbgsubshell", 'X', POPT_ARG_NONE, &debug_subshell, 0 },
+#endif
+ { "edit", 'e', POPT_ARG_STRING, &edit_one_file, 0 },
+
+ { "help", 'h', POPT_ARG_NONE, NULL, 'h' },
+ { "help-colors", 'H', POPT_ARG_NONE, NULL, 'H' },
+#ifdef USE_NETCODE
+ { "ftplog", 'l', POPT_ARG_STRING, NULL, 'l' },
+#endif
+ { "libdir", 'f', POPT_ARG_NONE, NULL, 'f' },
+ { NULL, 'm', POPT_ARG_NONE, NULL, 'm' },
+ { "nocolor", 'b', POPT_ARG_NONE, &disable_colors, 0 },
+ { "nomouse", 'd', POPT_ARG_NONE, NULL, 'd' },
+#ifdef HAVE_SUBSHELL_SUPPORT
+ { "nosubshell", 'u', POPT_ARG_NONE, NULL, 'u' },
+ { "forceexec", 'r', POPT_ARG_NONE, NULL, 'r' },
+#endif
+ { "printwd", 'P', POPT_ARG_NONE, &print_last_wd, 0 },
+ { "resetsoft", 'k', POPT_ARG_NONE, &reset_hp_softkeys, 0 },
+ { "slow", 's', POPT_ARG_NONE, &slow_terminal, 0 },
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ { "stickchars", 'a', 0, &force_ugly_line_drawing, 0 },
+#endif
+#ifdef HAVE_SUBSHELL_SUPPORT
+ { "subshell", 'U', POPT_ARG_NONE, NULL, 'U' },
+#endif
+#if defined(HAVE_SLANG) && !defined(OS2_NT)
+ { "termcap", 't', 0, &SLtt_Try_Termcap, 0 },
+#endif
+ { "version", 'V', POPT_ARG_NONE, NULL, 'V'},
+ { "view", 'v', POPT_ARG_STRING, &view_one_file, 0 },
+ { "xterm", 'x', POPT_ARG_NONE, &force_xterm, 0},
+
+ { NULL, 0, 0, NULL, 0 }
+};
+
+static void
+handle_args (int argc, char *argv [])
+{
+ char *tmp, *option_arg, *base;
+ int c;
+ poptContext optCon;
+
+ optCon = poptGetContext ("mc", argc, argv, argumentTable, 0);
+
+#ifdef USE_TERMCAP
+ SLtt_Try_Termcap = 1;
+#endif
+
+ while ((c = poptGetNextOpt (optCon)) > 0) {
+ option_arg = poptGetOptArg(optCon);
+
+ process_args (c, option_arg);
+ }
+
+ if (c < -1){
+ print_mc_usage ();
+ fprintf(stderr, "%s: %s\n",
+ poptBadOption(optCon, POPT_BADOPTION_NOALIAS),
+ poptStrerror(c));
+ finish_program = 1;
+ }
+
+ probably_finish_program ();
+
+ /* Check for special invocation names mcedit and mcview,
+ * if none apply then set the current directory and the other
+ * directory from the command line arguments
+ */
+ tmp = poptGetArg (optCon);
+ base = x_basename (argv[0]);
+ if (!STRNCOMP (base, "mce", 3) || !STRCOMP(base, "vi")) {
+ edit_one_file = "";
+ if (tmp)
+ edit_one_file = strdup (tmp);
+ } else
+ if (!STRNCOMP (base, "mcv", 3) || !STRCOMP(base, "view")) {
+ if (tmp)
+ view_one_file = strdup (tmp);
+ } else {
+ /* sets the current dir and the other dir */
+ if (tmp) {
+ char buffer[MC_MAXPATHLEN + 2];
+ this_dir = strdup (tmp);
+ mc_get_current_wd (buffer, sizeof (buffer) - 2);
+ if ((tmp = poptGetArg (optCon)))
+ other_dir = strdup (tmp);
+ }
+ }
+ poptFreeContext(optCon);
+}
+#endif
+
+/*
+ * The compatibility_move_mc_files routine is intended to
+ * move all of the hidden .mc files into a private ~/.mc
+ * directory in the home directory, to avoid cluttering the users.
+ *
+ * Previous versions of the program had all of their files in
+ * the $HOME, we are now putting them in $HOME/.mc
+ */
+#ifdef OS2_NT
+# define compatibility_move_mc_files()
+#else
+
+int
+do_mc_filename_rename (char *mc_dir, char *o_name, char *n_name)
+{
+ char *full_o_name = concat_dir_and_file (home_dir, o_name);
+ char *full_n_name = copy_strings (home_dir, MC_BASE, n_name, NULL);
+ int move;
+
+ move = 0 == rename (full_o_name, full_n_name);
+ free (full_o_name);
+ free (full_n_name);
+ return move;
+}
+
+void
+do_compatibility_move (char *mc_dir)
+{
+ struct stat s;
+ int move;
+
+ if (stat (mc_dir, &s) == 0)
+ return;
+ if (errno != ENOENT)
+ return;
+
+ if (mkdir (mc_dir, 0777) == -1)
+ return;
+
+ move = do_mc_filename_rename (mc_dir, ".mc.ini", "ini");
+ move += do_mc_filename_rename (mc_dir, ".mc.hot", "hotlist");
+ move += do_mc_filename_rename (mc_dir, ".mc.ext", "ext");
+ move += do_mc_filename_rename (mc_dir, ".mc.menu", "menu");
+ move += do_mc_filename_rename (mc_dir, ".mc.bashrc", "bashrc");
+ move += do_mc_filename_rename (mc_dir, ".mc.inputrc", "inputrc");
+ move += do_mc_filename_rename (mc_dir, ".mc.tcshrc", "tcshrc");
+ move += do_mc_filename_rename (mc_dir, ".mc.tree", "tree");
+
+ if (!move)
+ return;
+
+ show_change_notice = 1;
+}
+
+void
+compatibility_move_mc_files (void)
+{
+ char *mc_dir = concat_dir_and_file (home_dir, ".mc");
+
+ do_compatibility_move (mc_dir);
+ free (mc_dir);
+}
+#endif
+
+int main (int argc, char *argv [])
+{
+#ifndef OS2_NT
+ /* Backward compatibility: Gives up privileges in case someone
+ installed the mc as setuid */
+ setuid (getuid ());
+#else
+# define LOCALEDIR get_mc_lib_dir ()
+#endif
+#ifdef _OS_NT
+ signal(SIGINT,SIG_IGN); /* Ignore CTRL-C */
+#endif
+ /* We had LC_CTYPE before, LC_ALL includs LC_TYPE as well */
+ setlocale (LC_ALL, "");
+ bindtextdomain ("mc", LOCALEDIR);
+ textdomain ("mc");
+
+ /* Initialize list of all user group for timur_clr_mode */
+ init_groups ();
+
+ OS_Setup ();
+
+ vfs_init ();
+
+#ifdef HAVE_X
+ /* NOTE: This call has to be before any our argument handling :) */
+
+#ifdef HAVE_GNOME
+ session_management_setup (argv [0]);
+ {
+ char *base = x_basename (argv [0]);
+
+ if (base){
+ if (strcmp (base, "mcedit") == 0)
+ edit_one_file = "";
+
+ if (strcmp (base, "mcview") == 0)
+ view_one_file = "";
+ }
+ }
+ gnome_init ("gmc", &mc_argp_parser, argc, argv, 0, NULL);
+ probably_finish_program ();
+#endif
+
+ if (xtoolkit_init (&argc, argv) == -1)
+ exit (1);
+#endif /* HAVE_X */
+
+
+#ifdef HAVE_SLANG
+ SLtt_Ignore_Beep = 1;
+#endif
+
+ /* NOTE: This has to be called before slang_init or whatever routine
+ calls any define_sequence */
+ init_key ();
+
+#ifndef PORT_WANTS_ARGP
+ handle_args (argc, argv);
+#endif
+
+ /* Used to report the last working directory at program end */
+ if (print_last_wd){
+#ifndef OS2_NT
+ stdout_fd = dup (1);
+ close (1);
+ if (open (ttyname (0), O_RDWR) < 0)
+ if (open ("/dev/tty", O_RDWR) < 0) {
+ /* Try if stderr is not redirected as the last chance */
+ char *p = strdup (ttyname (0));
+
+ if (!strcmp (p, ttyname (2)))
+ dup2 (2, 1);
+ else {
+ fprintf (stderr,
+ _("Couldn't open tty line. You have to run mc without the -P flag.\n"
+ "On some systems you may want to run # `which mc`\n"));
+ exit (1);
+ }
+ free (p);
+ }
+#endif
+ }
+
+# ifdef HAVE_X
+ /* This is to avoid subshell trying to restard any child pid
+ * that happends to have cons_saver_pid (a random startup value).
+ * and PID 1 is init, unlikely we could be the parent of it.
+ */
+/* cons_saver_pid = 1; */
+# else
+ /* Must be done before installing the SIGCHLD handler [[FIXME]] */
+ handle_console (CONSOLE_INIT);
+# endif
+
+# ifdef HAVE_SUBSHELL_SUPPORT
+ subshell_get_console_attributes ();
+# endif
+
+ /* Install the SIGCHLD handler; must be done before init_subshell() */
+ init_sigchld ();
+ init_sigfatals ();
+
+ /* This variable is used by the subshell */
+ home_dir = getenv ("HOME");
+ if (!home_dir) {
+#ifndef OS2_NT
+ home_dir = PATH_SEP_STR;
+#else
+ home_dir = mc_home; /* LIBDIR, calculated in OS_Setup() */
+#endif
+ }
+
+ compatibility_move_mc_files ();
+
+# ifdef HAVE_X
+ /* We need this, since ncurses endwin () doesn't restore the signals */
+ save_stop_handler ();
+# endif
+
+ /* Must be done before init_subshell, to set up the terminal size: */
+ /* FIXME: Should be removed and LINES and COLS computed on subshell */
+ slang_init ();
+ /* NOTE: This call has to be after slang_init. It's the small part from
+ the previous init_key which had to be moved after the call of slang_init */
+ init_key_input_fd ();
+
+ load_setup ();
+
+#ifdef HAVE_GNOME
+ init_colors ();
+#else
+ init_curses ();
+#endif
+
+#ifdef HAVE_GNOME
+ use_subshell = 0;
+#endif
+
+# ifdef HAVE_SUBSHELL_SUPPORT
+ /* Done here to ensure that the subshell doesn't */
+ /* inherit the file descriptors opened below, etc */
+
+ if (use_subshell)
+ init_subshell ();
+# endif
+
+# ifndef HAVE_X
+ /* Removing this from the X code let's us type C-c */
+ load_key_defs ();
+
+ /* Also done after init_subshell, to save any shell init file messages */
+ if (console_flag)
+ handle_console (CONSOLE_SAVE);
+
+ if (alternate_plus_minus)
+ application_keypad_mode ();
+# endif
+
+ /* The directory hot list */
+ load_hotlist ();
+
+ if (show_change_notice){
+ message (1, _(" Notice "),
+ _(" The Midnight Commander configuration files \n"
+ " are now stored in the ~/.mc directory, the \n"
+ " files have been moved now\n"));
+ }
+
+# ifdef HAVE_SUBSHELL_SUPPORT
+ if (use_subshell){
+ prompt = strip_ctrl_codes (subshell_prompt);
+ if (!prompt)
+ prompt = "";
+ } else
+# endif
+ prompt = (geteuid () == 0) ? "# " : "$ ";
+
+ /* Program main loop */
+ do_nc ();
+
+ /* Virtual File System shutdown */
+ vfs_shut ();
+
+ /* Delete list of all user groups*/
+ delete_groups ();
+
+ flush_extension_file (); /* does only free memory */
+
+# ifndef HAVE_X
+ /* Miguel, maybe the fix in slang is not required and
+ * it could be done by removing the slang_done_screen.
+ * Do I need to call slang_reset_tty then?
+ */
+ endwin ();
+ slang_shutdown ();
+
+ if (console_flag && !(quit & SUBSHELL_EXIT))
+ restore_console ();
+ if (alternate_plus_minus)
+ numeric_keypad_mode ();
+# endif
+
+#ifndef OS2_NT
+ signal (SIGCHLD, SIG_DFL); /* Disable the SIGCHLD handler */
+#endif
+
+# ifndef HAVE_X
+ if (console_flag)
+ handle_console (CONSOLE_DONE);
+ putchar ('\r'); /* Hack to make shell's prompt start at left of screen */
+# endif
+
+#ifdef _OS_NT
+ /* On NT, home_dir is malloced */
+// free (home_dir);
+#endif
+#if defined(OS2_NT)
+ if (print_last_wd == 2){
+ FILE *bat_file;
+
+ print_last_wd = 0;
+ bat_file = fopen(batch_file_name, "w");
+ if (bat_file != NULL){
+ /* .ado: \r\n for Win95 */
+ fprintf(bat_file, "@echo off\r\n");
+ if (isalpha(last_wd_string[0]))
+ fprintf(bat_file, "%c:\r\n", last_wd_string[0]);
+ fprintf(bat_file, "cd %s\r\n", last_wd_string);
+ fclose(bat_file);
+ }
+ }
+#endif
+ if (print_last_wd) {
+ if (print_last_revert || edit_one_file || view_one_file)
+ write (stdout_fd, ".", 1);
+ else
+ write (stdout_fd, last_wd_string, strlen (last_wd_string));
+ free (last_wd_string);
+ }
+
+#ifdef HAVE_MAD
+ done_key ();
+#endif
+ mad_finalize (__FILE__, __LINE__);
+#ifdef HAVE_X
+ xtoolkit_end ();
+#endif
+ return 0;
+}
--- /dev/null
+#ifndef __MAIN_H
+#define __MAIN_H
+/* Toggling functions */
+void toggle_eight_bit (void);
+void toggle_clean_exec (void);
+void toggle_show_backup (void);
+void toggle_show_hidden (void);
+void toggle_show_mini_status (void);
+void toggle_align_extensions (void);
+void toggle_mix_all_files (void);
+void toggle_fast_reload (void);
+void toggle_confirm_delete (void);
+
+enum {
+ RP_NOCLEAR,
+ RP_CLEAR
+};
+
+#define UP_OPTIMIZE 0
+#define UP_RELOAD 1
+#define UP_ONLY_CURRENT 2
+
+#define UP_KEEPSEL (char *) -1
+
+extern int quote;
+extern volatile int quit;
+
+/* Execute functions: the base and the routines that use it */
+void do_execute (const char *shell, const char *command, int internal_command);
+#define execute_internal(command,args) do_execute (command, args, 1)
+
+/* Execute functions that use the shell to execute */
+void shell_execute (char *command, int flags);
+void execute (char *command);
+
+/* This one executes a shell */
+void exec_shell ();
+
+void subshell_chdir (char *command);
+
+/* See main.c for details on these variables */
+extern int mark_moves_down;
+extern int auto_menu;
+extern int pause_after_run;
+extern int auto_save_setup;
+extern int use_internal_view;
+extern int use_internal_edit;
+#ifdef USE_INTERNAL_EDIT
+extern int option_word_wrap_line_length;
+extern int edit_key_emulation;
+extern int option_tab_spacing;
+extern int option_fill_tabs_with_spaces;
+extern int option_return_does_auto_indent;
+extern int option_backspace_through_tabs;
+extern int option_fake_half_tabs;
+extern int option_save_mode;
+extern int option_backup_ext_int;
+extern int option_auto_para_formatting;
+extern int option_typewriter_wrap;
+extern int edit_confirm_save;
+extern int option_syntax_highlighting;
+#endif /* ! USE_INTERNAL_EDIT */
+extern int fast_reload_w;
+extern int clear_before_exec;
+extern int mou_auto_repeat;
+extern char *other_dir;
+extern int mouse_move_pages;
+extern int mouse_move_pages_viewer;
+extern int eight_bit_clean;
+extern int full_eight_bits;
+extern int confirm_view_dir;
+extern int fast_refresh;
+extern int navigate_with_arrows;
+extern int advanced_chfns;
+extern int drop_menus;
+extern int cd_symlinks;
+extern int show_all_if_ambiguous;
+extern int slow_terminal;
+extern int update_prompt; /* To comunicate with subshell */
+extern int confirm_delete;
+extern int confirm_execute;
+extern int confirm_exit;
+extern int confirm_overwrite;
+extern int iconify_on_exec;
+extern int force_colors;
+extern int boot_current_is_left;
+extern int acs_vline;
+extern int acs_hline;
+extern int use_file_to_check_type;
+extern int searching;
+extern int vfs_use_limit;
+extern int alternate_plus_minus;
+extern int only_leading_plus_minus;
+extern int ftpfs_directory_timeout;
+extern int output_starts_shell;
+extern int midnight_shutdown;
+extern char search_buffer [256];
+extern char cmd_buf [512];
+
+#if HAVE_GNOME
+#define MENU_PANEL get_current_panel ()
+#define SELECTED_IS_PANEL 1
+#else
+/* The menu panels */
+extern int is_right; /* If the selected menu was the right */
+#define MENU_PANEL (is_right ? right_panel : left_panel)
+#define SELECTED_IS_PANEL (get_display_type (is_right ? 1 : 0) == view_listing)
+#endif
+
+/* Useful macros to avoid too much typing */
+#define cpanel get_current_panel()
+#define opanel get_other_panel()
+
+typedef void (*key_callback) ();
+/* FIXME: We have to leave this type ambiguous, because `key_callback'
+ is used both for functions that take an argument and ones that don't.
+ That ought to be cleared up. */
+
+/* The keymaps are of this type */
+typedef struct {
+ int key_code;
+ key_callback fn;
+} key_map;
+
+void update_panels (int force_update, char *current_file);
+void create_panels (void);
+void repaint_screen (void);
+void outrefresh_screen (void);
+void suspend_cmd (void);
+void do_update_prompt (void);
+
+extern char control_file [];
+extern char *shell;
+
+/* FIXME: remove this when using slang */
+extern const int status_using_ncurses;
+
+void clr_scr (void);
+void restore_console (void);
+
+enum cd_enum {
+ cd_parse_command,
+ cd_exact
+};
+
+int do_cd (char *new_dir, enum cd_enum cd_type); /* For find.c */
+void change_panel (void);
+void init_sigchld (void); /* For subshell.c */
+int load_prompt (int fd, void *unused);
+void save_cwds_stat (void);
+void copy_prog_name (void);
+int quiet_quit_cmd (void); /* For cmd.c and command.c */
+int quit_cmd (void);
+
+void untouch_bar (void);
+void touch_bar (void);
+void load_hint (void);
+
+void print_vfs_message(char *msg, ...);
+
+extern char *prompt;
+extern char *mc_home;
+
+int maybe_cd (int char_code, int move_up_dir);
+void do_possible_cd (char *dir);
+
+#ifdef WANT_WIDGETS
+extern WButtonBar *the_bar;
+extern WLabel *the_prompt;
+extern WLabel *the_hint;
+extern Dlg_head *midnight_dlg;
+extern WLabel *process_status;
+#include "menu.h"
+extern WMenu *the_menubar;
+
+extern Dlg_head *midnight_dlg;
+
+/* Back hack to define the following routines only if the client code
+ * has included panel.h
+ */
+#ifdef __PANEL_H
+void directory_history_add (WPanel *panel, char *s);
+int do_panel_cd (WPanel *panel, char *new_dir, enum cd_enum cd_type);
+void update_one_panel_widget (WPanel *panel, int force_update, char *current_file);
+#endif
+
+#endif
+
+void edition_pre_exec (void);
+void edition_post_exec (void);
+
+#ifdef OS2_NT
+# define MC_BASE ""
+#else
+# define MC_BASE "/.mc/"
+#endif
+#endif
--- /dev/null
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+rootdir = $(srcdir)/..
+@MCFG@@MCF@
+
+CFLAGS = $(XCFLAGS)
+CPPFLAGS = $(XCPPFLAGS) -DREGEX_MALLOC
+LDFLAGS = $(XLDFLAGS)
+DEFS = $(XDEFS)
+LIBS = $(XLIBS) @TERMNET@ $(XLIB) @TERMNET@
+OURLIBS = @LVFS@ @LSLANG@ @LEDIT@ @LINTL@
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+SRCS = dir.c util.c main.c screen.c dialog.c key.c keyxdef.c menu.c\
+ file.c win.c color.c help.c find.c profile.c user.c view.c \
+ ext.c mouse.c setup.c dlg.c option.c info.c \
+ tree.c widget.c chmod.c mad.c xcurses.c xslint.c \
+ wtools.c cons.handler.c chown.c subshell.c terms.c boxes.c \
+ hotlist.c achown.c layout.c fsusage.c mountlist.c regex.c \
+ complete.c slint.c command.c cmd.c panelize.c learn.c \
+ listmode.c utilunix.c background.c rxvt.c popt.c \
+ text.c
+
+HDRS = color.h file.h mouse.h user.h dialog.h find.h main.h \
+ util.h dir.h global.h menu.h panel.h win.h mem.h \
+ help.h profile.h dlg.h option.h tree.h info.h \
+ widget.h chmod.h cons.saver.h mad.h wtools.h chown.h \
+ subshell.h view.h setup.h key.h ext.h boxes.h \
+ hotlist.h layout.h fsusage.h mountlist.h regex.h complete.h \
+ myslang.h command.h cmd.h tty.h fs.h panelize.h achown.h \
+ learn.h listmode.h features.inc background.h \
+ x.h popt.h textconf.h i18n.h
+
+OBJS = dir.o util.o screen.o dialog.o key.o keyxdef.o menu.o\
+ file.o win.o color.o help.o find.o profile.o user.o view.o \
+ ext.o mouse.o setup.o dlg.o option.o \
+ tree.o widget.o chmod.o mad.o wtools.o info.o \
+ cons.handler.o chown.o subshell.o terms.o boxes.o \
+ hotlist.o achown.o layout.o fsusage.o mountlist.o \
+ @XCURSES@ @REGEX_O@ complete.o slint.o command.o \
+ cmd.o main.o panelize.o learn.o listmode.o utilunix.o \
+ background.o rxvt.o popt.o text.o
+
+#
+# Distribution variables
+#
+
+DISTFILES = \
+ $(HDRS) $(SRCS) Makefile.in TODO ChangeLog OChangeLog man2hlp.c \
+ gindex.pl xmkdir cons.saver.c ncurses.patch mc.hlp depend.awk \
+ fixhlp.c mfmt.c
+
+# Should be: mc $(srcdir)/mc.hlp but it's remaking it always
+
+all: mc mcmfmt @saver_target@
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(DEFS) $(CFLAGS) $<
+
+cons.saver: cons.saver.o
+ $(CC) -s cons.saver.o -o cons.saver
+
+check:
+ @echo no tests are supplied.
+
+mc: $(OBJS) @LIBVFS@ @LIBSLANG@ @LIBEDIT_A@
+ $(CC) $(LDFLAGS) -o $@ $(OBJS) -L../vfs -L../slang -L../edit $(OURLIBS) $(LIBS)
+
+mfmt: mfmt.o
+ $(CC) $(LDFLAGS) mfmt.o -o mfmt
+
+mcmfmt: mfmt
+ cp mfmt mcmfmt
+
+libvfs.a:
+ cd ../vfs; $(MAKE) libvfs.a
+@PCENTRULE@ -$(RMF) libvfs.a
+@PCENTRULE@ $(LN_S) ../vfs/libvfs.a .
+
+libmcslang.a:
+ cd ../slang; $(MAKE) libmcslang.a
+@PCENTRULE@ -$(RMF) libmcslang.a
+@PCENTRULE@ $(LN_S) ../slang/libmcslang.a .
+
+libedit.a:
+ cd ../edit; $(MAKE) libedit.a
+@PCENTRULE@ -$(RMF) libedit.a
+@PCENTRULE@ $(LN_S) ../edit/libedit.a .
+
+cross:
+ $(MAKE) CC=gcc-linux CPP="gcc-linux -E" \
+ CPPFLAGS="$(CPPFLAGS) -I/usr/local/lib/gcc-lib/i386-linux-linux/include/ncurses "
+
+$(srcdir)/mc.hlp: $(docdir)/mc.1.in $(mclibdir)/xnc.hlp $(srcdir)/gindex.pl
+ $(MAKE) man2hlp
+ ./man2hlp 58 $(docdir)/mc.1.in | cat - $(mclibdir)/xnc.hlp | \
+ perl $(srcdir)/gindex.pl > $(srcdir)/mc.hlp
+
+mc.html: $(docdir)/mc.1.in man2hlp
+ ./man2hlp 0 $(docdir)/mc.1.in > body.html
+ cat index.html body.html > mc.html
+ $(RM) index.html body.html
+
+TAGS: $(SRCS)
+ etags $(SRCS)
+
+clean:
+ $(RMF) mc cons.saver man2hlp fixhlp *.o core a.out mc.html mcmfmt
+ $(RMF) libvfs.a libedit.a libmcslang.a mfmt
+
+realclean: clean
+ $(RMF) .depend
+ $(RMF) TAGS
+ $(RMF) *~
+
+distclean:
+ -$(RMF) $(srcdir)/*~ $(srcdir)/mc $(srcdir)/cons.saver
+ -$(RMF) $(srcdir)/mfmt
+ -$(RMF) $(srcdir)/man2hlp $(srcdir)/fixhlp $(srcdir)/*.o $(srcdir)/core
+ -$(RMF) $(srcdir)/a.out $(srcdir)/mc.html
+ -$(RMF) $(srcdir)/libvfs.a $(srcdir)/libmcslang.a $(srcdir)/libedit.a
+ -if test $(srcdir) = .; then $(MAKE) realclean; fi
+ -$(RMF) $(srcdir)/Makefile
+
+install: mc mfmt @saver@
+ $(INSTALL_PROGRAM) mc $(DESTDIR)$(bindir)/$(binprefix)mc
+ $(INSTALL_PROGRAM) mcmfmt $(DESTDIR)$(bindir)/$(binprefix)mcmfmt
+ $(SEDCMD2) < $(srcdir)/mc.hlp > $(DESTDIR)$(libdir)/$(libprefix)mc.hlp
+
+install.saver: cons.saver
+ $(INSTALL_PROGRAM) -m 4755 cons.saver $(DESTDIR)$(suppbindir)/cons.saver
+
+uninstall:
+ cd $(bindir); $(RMF) $(binprefix)mc
+ cd $(bindir); $(RMF) $(binprefix)mcmfmt
+ cd $(bindir); $(RMF) $(binprefix)cons.saver
+ cd $(libdir); $(RMF) $(libprefix)mc.hlp
+
+distcopy: $(srcdir)/mc.hlp
+ $(CP) $(DISTFILES) ../../mc-$(VERSION)/src
+
+depend dep: mcdep
+
+fastdeploc: @fastdepslang@ @fastdepvfs@
+
+# ***Dependencies***Do not edit***
+@DOTDEPEND@
+# ***End of dependencies***
--- /dev/null
+/* Man page to help file converter
+ Copyright (C) 1994, 1995 Janne Kukonlehto
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include "help.h"
+
+#define BUFFER_SIZE 256
+
+static char *filename; /* The name of the input file */
+static int width; /* Output width in characters */
+static int col = 0; /* Current output column */
+static FILE *index_file; /* HTML index file */
+static int out_row = 1; /* Current output row */
+static int in_row = 0; /* Current input row */
+static int old_heading_level = 0;/* Level of the last heading */
+static int no_split_flag = 0; /* Flag: Don't split section on next ".SH" */
+static int skip_flag = 0; /* Flag: Skip this section.
+ 0 = don't skip,
+ 1 = skipping title,
+ 2 = title skipped, skipping text */
+static int link_flag = 0; /* Flag: Next line is a link */
+static int verbatim_flag = 0; /* Flag: Copy input to output verbatim */
+
+/* Report error in input */
+void print_error (char *message)
+{
+ fprintf (stderr, "man2hlp: %s in file \"%s\" at row %d\n", message, filename, in_row);
+}
+
+/* Change output line */
+void newline (void)
+{
+ out_row ++;
+ col = 0;
+ printf("\n");
+}
+
+/* Calculate the length of string */
+int string_len (char *buffer)
+{
+ static int anchor_flag = 0; /* Flag: Inside hypertext anchor name */
+ static int link_flag = 0; /* Flag: Inside hypertext link target name */
+ int backslash_flag = 0; /* Flag: Backslash quoting */
+ int i; /* Index */
+ int c; /* Current character */
+ int len = 0; /* Result: the length of the string */
+
+ for (i = 0; i < strlen (buffer); i ++)
+ {
+ c = buffer [i];
+ if (c == CHAR_LINK_POINTER)
+ link_flag = 1; /* Link target name starts */
+ else if (c == CHAR_LINK_END)
+ link_flag = 0; /* Link target name ends */
+ else if (c == CHAR_NODE_END){
+ /* Node anchor name starts */
+ anchor_flag = 1;
+ /* Ugly hack to prevent loss of one space */
+ len ++;
+ }
+ /* Don't add control characters to the length */
+ if (c < 32)
+ continue;
+ /* Attempt to handle backslash quoting */
+ if (c == '\\' && !backslash_flag){
+ backslash_flag = 1;
+ continue;
+ }
+ backslash_flag = 0;
+ /* Increase length if not inside anchor name or link target name */
+ if (!anchor_flag && !link_flag)
+ len ++;
+ if (anchor_flag && c == ']'){
+ /* Node anchor name ends */
+ anchor_flag = 0;
+ }
+ }
+ return len;
+}
+
+/* Output the string */
+void print_string (char *buffer)
+{
+ int len; /* The length of current word */
+ int i; /* Index */
+ int c; /* Current character */
+ int backslash_flag = 0;
+
+ /* Skipping lines? */
+ if (skip_flag)
+ return;
+ /* Copying verbatim? */
+ if (verbatim_flag){
+ printf("%s", buffer);
+ return;
+ }
+ if (width){
+ /* HLP format */
+ /* Split into words */
+ buffer = strtok (buffer, " \t\n");
+ /* Repeat for each word */
+ while (buffer){
+ /* Skip empty strings */
+ if (strlen (buffer) > 0){
+ len = string_len (buffer);
+ /* Change the line if about to break the right margin */
+ if (col + len >= width)
+ newline ();
+ /* Words are separated by spaces */
+ if (col > 0){
+ printf (" ");
+ col ++;
+ }
+ /* Attempt to handle backslash quoting */
+ for (i = 0; i < strlen (buffer); i++)
+ {
+ c = buffer [i];
+ if (c == '\\' && !backslash_flag){
+ backslash_flag = 1;
+ continue;
+ }
+ backslash_flag = 0;
+ printf ("%c", c);
+ }
+ /* Increase column */
+ col += len;
+ }
+ /* Get the next word */
+ buffer = strtok (NULL, " \t\n");
+ } /* while */
+ } else {
+ /* HTML format */
+ if (strlen (buffer) > 0){
+ /* Attempt to handle backslash quoting */
+ for (i = 0; i < strlen (buffer); i++)
+ {
+ c = buffer [i];
+ if (c == '\\' && !backslash_flag){
+ backslash_flag = 1;
+ continue;
+ }
+ backslash_flag = 0;
+ printf ("%c", c);
+ }
+ }
+ } /* if (width) */
+}
+
+/* Like print_string but with printf-like syntax */
+void printf_string (char *format, ...)
+{
+ va_list args;
+ char buffer [BUFFER_SIZE];
+
+ va_start (args, format);
+ vsprintf (buffer, format, args);
+ va_end (args);
+ print_string (buffer);
+}
+
+/* Handle all the roff dot commands */
+void handle_command (char *buffer)
+{
+ int i, len, heading_level;
+
+ /* Get the command name */
+ strtok (buffer, " \t");
+ if (strcmp (buffer, ".SH") == 0){
+ /* If we already skipped a section, don't skip another */
+ if (skip_flag == 2){
+ skip_flag = 0;
+ }
+ /* Get the command parameters */
+ buffer = strtok (NULL, "");
+ if (buffer == NULL){
+ print_error ("Syntax error: .SH: no title");
+ return;
+ } else {
+ /* Remove quotes */
+ if (buffer[0] == '"'){
+ buffer ++;
+ len = strlen (buffer);
+ if (buffer[len-1] == '"'){
+ len --;
+ buffer[len] = 0;
+ }
+ }
+ /* Calculate heading level */
+ heading_level = 0;
+ while (buffer [heading_level] == ' ')
+ heading_level ++;
+ /* Heading level must be even */
+ if (heading_level & 1)
+ print_error ("Syntax error: .SH: odd heading level");
+ if (no_split_flag){
+ /* Don't start a new section */
+ if (width){
+ /* HLP format */
+ newline ();
+ print_string (buffer);
+ newline ();
+ newline ();
+ } else {
+ /* HTML format */
+ newline ();
+ printf_string ("<h4>%s</h4>", buffer);
+ newline ();
+ }
+ no_split_flag = 0;
+ }
+ else if (skip_flag){
+ /* Skipping title and marking text for skipping */
+ skip_flag = 2;
+ }
+ else {
+ /* Start a new section */
+ if (width){
+ /* HLP format */
+ printf ("%c[%s]", CHAR_NODE_END, buffer);
+ col ++;
+ newline ();
+ print_string (buffer + heading_level);
+ newline ();
+ newline ();
+ } else {
+ /* HTML format */
+ if (buffer [0]){
+ if (heading_level > old_heading_level){
+ for (i = old_heading_level; i < heading_level; i += 2)
+ fprintf (index_file, "<ul>");
+ } else {
+ for (i = heading_level; i < old_heading_level; i += 2)
+ fprintf (index_file, "</ul>");
+ }
+ old_heading_level = heading_level;
+ printf_string ("<h%d><a name=\"%s\">%s</a></h%d>",
+ heading_level / 2 + 2, buffer + heading_level,
+ buffer + heading_level, heading_level / 2 + 2);
+ newline ();
+ fprintf (index_file, "<li><a href=\"#%s\">%s</a>\n",
+ buffer + heading_level, buffer + heading_level);
+ } else {
+ for (i = 0; i < old_heading_level; i += 2)
+ fprintf (index_file, "</ul>");
+ old_heading_level = 0;
+ fprintf (index_file, "</ul><p><ul>\n");
+ }
+ } /* if (width) */
+ } /* Start new section */
+ } /* Has parameters */
+ } /* Command .SH */
+ else if (strcmp (buffer, ".\\\"DONT_SPLIT\"") == 0){
+ no_split_flag = 1;
+ }
+ else if (strcmp (buffer, ".\\\"SKIP_SECTION\"") == 0){
+ skip_flag = 1;
+ }
+ else if (strcmp (buffer, ".\\\"LINK\"") == 0){
+ /* Next input line is a link */
+ link_flag = 1;
+ }
+ else if (strcmp (buffer, ".\\\"LINK2\"") == 0){
+ /* Next two input lines form a link */
+ link_flag = 2;
+ }
+ else if (strcmp (buffer, ".PP") == 0){
+ /* End of paragraph */
+ if (width){
+ /* HLP format */
+ if (col > 0) newline();
+ } else /* HTML format */
+ print_string ("<p>");
+ newline ();
+ }
+ else if (strcmp (buffer, ".nf") == 0){
+ /* Following input lines are to be handled verbatim */
+ verbatim_flag = 1;
+ if (width){
+ /* HLP format */
+ if (col > 0) newline ();
+ } else {
+ /* HTML format */
+ print_string ("<pre>");
+ newline ();
+ }
+ }
+ else if (strcmp (buffer, ".I") == 0 || strcmp (buffer, ".B") == 0){
+ /* Bold text or italics text */
+ char type = buffer [1];
+
+ buffer = strtok (NULL, "");
+ if (buffer == NULL){
+ print_error ("Syntax error: .I / .B: no text");
+ return;
+ }
+ else {
+ if (!width){
+ /* HTML format */
+ /* Remove quotes */
+ if (buffer[0] == '"'){
+ buffer ++;
+ len = strlen (buffer);
+ if (buffer[len-1] == '"'){
+ len --;
+ buffer[len] = 0;
+ }
+ }
+ printf_string ("<%c>%s</%c>", type, buffer, type);
+ newline ();
+ } else /* HLP format */
+ printf_string ("%c%s%c",
+ (type == 'I') ? CHAR_ITALIC_ON : CHAR_BOLD_ON,
+ buffer, CHAR_BOLD_OFF);
+ }
+ }
+ else if (strcmp (buffer, ".TP") == 0){
+ /* End of paragraph? */
+ if (width){
+ /* HLP format */
+ if (col > 0) newline ();
+ } else {
+ /* HTML format */
+ print_string ("<p>");
+ }
+ newline ();
+ }
+ else {
+ /* Other commands are ignored */
+ }
+}
+
+void handle_link (char *buffer)
+{
+ static char old [80];
+ int len;
+
+ switch (link_flag){
+ case 1:
+ /* Old format link */
+ if (width) /* HLP format */
+ printf_string ("%c%s%c%s%c\n", CHAR_LINK_START, buffer, CHAR_LINK_POINTER, buffer, CHAR_LINK_END);
+ else {
+ /* HTML format */
+ printf_string ("<a href=\"#%s\">%s</a>", buffer, buffer);
+ newline ();
+ }
+ link_flag = 0;
+ break;
+ case 2:
+ /* First part of new format link */
+ strcpy (old, buffer);
+ link_flag = 3;
+ break;
+ case 3:
+ /* Second part of new format link */
+ if (buffer [0] == '.')
+ buffer++;
+ if (buffer [0] == '\\')
+ buffer++;
+ if (buffer [0] == '"')
+ buffer++;
+ len = strlen (buffer);
+ if (len && buffer [len-1] == '"'){
+ buffer [--len] = 0;
+ }
+ if (width) /* HLP format */
+ printf_string ("%c%s%c%s%c\n", CHAR_LINK_START, old, CHAR_LINK_POINTER, buffer, CHAR_LINK_END);
+ else {
+ /* HTML format */
+ printf_string ("<a href=\"#%s\">%s</a>", buffer, old);
+ newline ();
+ }
+ link_flag = 0;
+ break;
+ }
+}
+
+int main (int argc, char **argv)
+{
+ int len; /* Length of input line */
+ FILE *file; /* Input file */
+ char buffer2 [BUFFER_SIZE]; /* Temp input line */
+ char buffer [BUFFER_SIZE]; /* Input line */
+ int i, j;
+
+ /* Validity check for arguments */
+ if (argc != 3 || (strcmp (argv[1], "0") && (width = atoi (argv[1])) <= 10)){
+ fprintf (stderr, "Usage: man2hlp <width> <file.man>\n");
+ fprintf (stderr, "zero width will create a html file instead of a hlp file\n");
+ return 3;
+ }
+
+ /* Open the input file */
+ filename = argv[2];
+ file = fopen (filename, "r");
+ if (file == NULL){
+ sprintf (buffer, "man2hlp: Can't open file \"%s\"", filename);
+ perror (buffer);
+ return 3;
+ }
+
+ if (!width){
+ /* HTML format */
+ index_file = fopen ("index.html", "w");
+ if (index_file == NULL){
+ perror ("man2hlp: Can't open file \"index.html\"");
+ return 3;
+ }
+ fprintf (index_file, "<html><head><title>Midnight Commander manual</title>\n");
+ fprintf (index_file, "</head><body><pre><img src=\"mc.logo.small.gif\" width=180 height=85 align=\"right\" alt=\""
+ " \n"
+ "______________ ____ ____ \n"
+ "|////////////# |//# |//# \n"
+ "|//##+//##+//# |//# |//# \n"
+ "|//# |//# |//# ____ |//# ____ |//# \n"
+ "|//# |//# |//# |//# |//# |//# |//# \n"
+ "|//# |//# |//# +### |//# +### |//# ____ \n"
+ "|//# |//# |//# ____ _____|//# _________ ____ _________ |//#______ _|//#__ \n"
+ "|@@# |@@# |@/# |//# |///////# |///////# |//# |///////# |////////# |/////# \n"
+ "|@@# |@@# |@@# |@/# |//##+//# |//##+//# |//# |//##+//# |//###+//# +#/@### \n"
+ "|@@# |@@# |@@# |@@# |@@# |@@# |@/# |//# |//# |//# |/@# |@@# |@@# |@@# ____\n"
+ "|@@# |@@# |@@# |@@# |@@#_|@@# |@@# |@@# |@@# |@@#_|@@# |@@# |@@# |@@#_|@@#\n"
+ "|@@# |@@# |@@# |@@# |@@@@@@@# |@@# |@@# |@@# |@@@@@@@# |@@# |@@# |@@@@@@@#\n"
+ "+### +### +### +### +######## +### +### +### +####+@@# +### +### +########\n"
+ " _______________________________________|@@# \n"
+ " |@@@@@@@@@@@ C O M M A N D E R @@@@@@@@@@@# \n"
+ " +########################################## \n"
+ " \n"
+ "\"></pre><h1>Manual</h1>\nThis is the manual for Midnight Commander version %s.\n"
+ "This HTML version of the manual has been compiled from the NROFF version at %s.<p>\n",
+ VERSION, __DATE__);
+ fprintf (index_file, "<hr><h2>Contents</h2><ul>\n");
+ }
+
+ /* Repeat for each input line */
+ while (!feof (file)){
+ /* Read a line */
+ if (!fgets (buffer2, BUFFER_SIZE, file)){
+ break;
+ }
+ if (!width){
+ /* HTML format */
+ if (buffer2 [0] == '\\' && buffer2 [1] == '&')
+ i = 2;
+ else
+ i = 0;
+ for (j = 0; i < strlen (buffer2); i++, j++){
+ if (buffer2 [i] == '<'){
+ buffer [j++] = '&';
+ buffer [j++] = 'l';
+ buffer [j++] = 't';
+ buffer [j] = ';';
+ } else if (buffer2 [i] == '>'){
+ buffer [j++] = '&';
+ buffer [j++] = 'g';
+ buffer [j++] = 't';
+ buffer [j] = ';';
+ } else
+ buffer [j] = buffer2 [i];
+ }
+ buffer [j] = 0;
+ } else {
+ /* HLP format */
+ if (buffer2 [0] == '\\' && buffer2 [1] == '&')
+ strcpy (buffer, buffer2 + 2);
+ else
+ strcpy (buffer, buffer2);
+ }
+ in_row ++;
+ len = strlen (buffer);
+ /* Remove terminating newline */
+ if (buffer [len-1] == '\n')
+ {
+ len --;
+ buffer [len] = 0;
+ }
+ if (verbatim_flag){
+ /* Copy the line verbatim */
+ if (strcmp (buffer, ".fi") == 0){
+ verbatim_flag = 0;
+ if (!width) print_string ("</pre>"); /* HTML format */
+ } else {
+ print_string (buffer);
+ newline ();
+ }
+ }
+ else if (link_flag)
+ /* The line is a link */
+ handle_link (buffer);
+ else if (buffer[0] == '.')
+ /* The line is a roff command */
+ handle_command (buffer);
+ else
+ {
+ /* A normal line, just output it */
+ print_string (buffer);
+ if (!width) newline (); /* HTML format */
+ }
+ }
+
+ /* All done */
+ newline ();
+ if (!width){
+ /* HTML format */
+ print_string ("<hr></body></html>");
+ newline ();
+ for (i = 0; i < old_heading_level; i += 2)
+ fprintf (index_file, "</ul>");
+ old_heading_level = 0;
+ fprintf (index_file, "</ul><hr>\n");
+ fclose (index_file);
+ }
+ fclose (file);
+ return 0;
+}
--- /dev/null
+\ 4[Contents]
+Topics:
+
+ \ 1 DESCRIPTION \ 2DESCRIPTION\ 3
+ \ 1 OPTIONS \ 2OPTIONS\ 3
+ \ 1 Overview \ 2Overview\ 3
+ \ 1 Mouse Support \ 2Mouse Support\ 3
+
+ \ 1 Keys \ 2Keys\ 3
+ \ 1 Miscellaneous Keys \ 2Miscellaneous Keys\ 3
+ \ 1 Directory Panels \ 2Directory Panels\ 3
+ \ 1 Shell Command Line \ 2Shell Command Line\ 3
+ \ 1 General Movement Keys \ 2General Movement Keys\ 3
+ \ 1 Input Line Keys \ 2Input Line Keys\ 3
+
+ \ 1 Menu Bar \ 2Menu Bar\ 3
+ \ 1 Left and Right Menus \ 2Left and Right Menus\ 3
+ \ 1 Listing Mode... \ 2Listing Mode...\ 3
+ \ 1 Sort Order... \ 2Sort Order...\ 3
+ \ 1 Filter... \ 2Filter...\ 3
+ \ 1 Reread \ 2Reread\ 3
+ \ 1 File Menu \ 2File Menu\ 3
+ \ 1 Quick cd \ 2Quick cd\ 3
+ \ 1 Command Menu \ 2Command Menu\ 3
+ \ 1 Directory Tree \ 2Directory Tree\ 3
+ \ 1 Find File \ 2Find File\ 3
+ \ 1 External panelize \ 2External panelize\ 3
+ \ 1 Hotlist \ 2Hotlist\ 3
+ \ 1 Extension File Edit \ 2Extension File Edit\ 3
+ \ 1 Background jobs \ 2Background jobs\ 3
+ \ 1 Menu File Edit \ 2Menu File Edit\ 3
+ \ 1 Options Menu \ 2Options Menu\ 3
+ \ 1 Configuration \ 2Configuration\ 3
+ \ 1 Display bits \ 2Display bits\ 3
+ \ 1 Confirmation \ 2Confirmation\ 3
+ \ 1 Learn keys \ 2Learn keys\ 3
+ \ 1 Virtual FS \ 2Virtual FS\ 3
+ \ 1 Layout \ 2Layout\ 3
+ \ 1 Save Setup \ 2Save Setup\ 3
+
+ \ 1 Executing operating system commands \ 2Executing operating system commands\ 3
+ \ 1 The cd internal command \ 2The cd internal command\ 3
+ \ 1 Macro Substitution \ 2Macro Substitution\ 3
+ \ 1 The subshell support \ 2The subshell support\ 3
+ \ 1 Controlling Midnight Commander \ 2Controlling Midnight Commander\ 3
+ \ 1 Chmod \ 2Chmod\ 3
+ \ 1 Chown \ 2Chown\ 3
+ \ 1 File Operations \ 2File Operations\ 3
+ \ 1 Mask Copy/Rename \ 2Mask Copy/Rename\ 3
+ \ 1 Internal File Viewer \ 2Internal File Viewer\ 3
+ \ 1 Internal File Editor \ 2Internal File Editor\ 3
+ \ 1 Completion \ 2Completion\ 3
+ \ 1 Virtual File System \ 2Virtual File System\ 3
+ \ 1 FTP File System \ 2FTP File System\ 3
+ \ 1 Tar File System \ 2Tar File System\ 3
+ \ 1 Network File System \ 2Network File System\ 3
+ \ 1 Undelete File System \ 2Undelete File System\ 3
+ \ 1 Colors \ 2Colors\ 3
+ \ 1 Special Settings \ 2Special Settings\ 3
+ \ 1 Terminal databases \ 2Terminal databases\ 3
+
+ \ 1 FILES \ 2FILES\ 3
+ \ 1 AVAILABILITY \ 2AVAILABILITY\ 3
+ \ 1 SEE ALSO \ 2SEE ALSO\ 3
+ \ 1 AUTHORS \ 2AUTHORS\ 3
+ \ 1 BUGS \ 2BUGS\ 3
+ \ 1 License \ 2License\ 3
+ \ 1 QueryBox \ 2QueryBox\ 3
+ \ 1 How to use help \ 2How to use help\ 3
+\ 4[DESCRIPTION]
+DESCRIPTION
+
+The Midnight Commander is a directory browser/file manager
+for Unix-like operating systems.\ 4[OPTIONS]
+OPTIONS
+
+
+\14"-a"\v Disables the usage of graphic characters for line
+drawing.
+
+\14"-b"\v Forces black and white display.
+
+\14"-c"\v Force color mode, please check the section \ 1Colors\ 2Colors\ 3 for
+more information.
+
+\14"-C arg"\v Used to specify a different color set in the
+command line. The format of arg is documented in the
+\ 1Colors\ 2Colors\ 3 section.
+
+\14"-d"\v Disables mouse support.
+
+\14"-f"\v Displays the compiled-in search paths for Midnight
+Commander files.
+
+\14"-k"\v Reset softkeys to their default from the
+termcap/terminfo database. Only useful on HP terminals
+when the function keys don't work.
+
+\14"-l file" \v Save the ftpfs dialog with the server in file.
+
+\14"-P"\v At program end, the Midnight Commander will print the
+last working directory; this, along with the shell
+function below, will allow you to browse through your
+directories and automatically move to the last directory
+you were in (thanks to Torben Fjerdingstad and Sergey for
+contributing this function and the code which implements
+this option).
+
+bash and zsh users:
+
+mc ()
+{
+ MC=/tmp/mc$$-"$RANDOM"
+ @prefix@/bin/mc -P "$@" > "$MC"
+ cd "`cat $MC`"
+ rm "$MC"
+ unset MC;
+}
+
+tcsh users:
+alias mc 'setenv MC `@prefix@/bin/mc -P \!*`; cd $MC; unsetenv MC'
+
+I know the bash function could be shorter for zsh and bash
+but the backquotes on bash won't accept your suspension
+the program with C-z.
+
+\14"-s"\v Turns on the slow terminal mode, in this mode the
+program will not draw expensive line drawing characters
+and will toggle verbose mode off.
+
+\14"-t"\v Used only if the code was compiled with Slang and
+terminfo: it makes the Midnight Commander use the value of
+the \bTERMCAP\v variable for the terminal information instead
+of the information on the system wide terminal database
+
+\14"-u"\v Disables the use of a concurrent shell (only makes
+sense if the Midnight Commander has been built with
+concurrent shell support).
+
+\14"-U"\v Enables the use of the concurrent shell support (only
+makes sense if the Midnight Commander was built with the
+subshell support set as an optional feature).
+
+\14"-v file"\v Enters the internal viewer to view the file
+specified.
+
+\14"-V"\v Displays the version of the program.
+
+\14"-x"\v Forces xterm mode. Used when running on xterm-capable
+terminals (two screen modes, and able to send mouse escape
+sequences).
+
+If specified, the first path name is the directory to show
+in the selected panel; the second path name is the
+directory to be shown in the other panel.
+
+\ 4[Overview]
+Overview
+
+The screen of the Midnight Commander is divided into four
+parts. Almost all of the screen space is taken up by two
+directory panels. By default, the second bottommost line
+of the screen is the shell command line, and the bottom
+line shows the function key labels. The topmost line is
+the \ 1menu bar line.\ 2Menu Bar\ 3 The menu bar line may not be visible,
+but appears if you click the topmost line with the mouse
+or press the F9 key.
+
+The Midnight Commander provides a view of two directories
+at the same time. One of the panels is the current panel
+(a selection bar is in the current panel). Almost all
+operations take place on the current panel. Some file
+operations like Rename and Copy by default use the
+directory of the unselected panel as a destination (don't
+worry, they always ask you for confirmation first). For
+more information, see the sections on the \ 1Directory
+Panels,\ 2Directory Panels\ 3 the \ 1Left and Right Menus\ 2Left and Right Menus\ 3 and the \ 1File Menu.\ 2File Menu\ 3
+
+You can execute system commands from the Midnight
+Commander by simply typing them. Everything you type will
+appear on the shell command line, and when you press Enter
+the Midnight Commander will execute the command line you
+typed; read the \ 1Shell Command Line\ 2Shell Command Line\ 3 and \ 1Input Line Keys\ 2Input Line Keys\ 3
+sections to learn more about the command line.
+
+\ 4[Mouse Support]
+Mouse Support
+
+The Midnight Commander comes with mouse support. It is
+activated whenever you are running on an \bxterm(1)\v terminal
+(it even works if you take a telnet or rlogin connection
+to another machine from the xterm) or if you are running
+on a Linux console and have the \bgpm\v mouse server running.
+
+When you left click on a file in the directory panels,
+that file is selected; if you click with the right button,
+the file is marked (or unmarked, depending on the previous
+state).
+
+Double-clicking on a file will try to execute the command
+if it is an executable program; and if the \ 1extension file\ 2Extension File
+Edit\ 3has a program specified for the file's extension, the
+specified program is executed.
+
+Also, it is possible to execute the commands assigned to
+the function key labels by clicking on them.
+
+If a mouse button is clicked on the top frame line of the
+directory panel, it is scrolled one pageful backward.
+Correspondingly, a click on the bottom frame line will
+cause a scroll of one pageful forward. This frame line
+method works also in the \ 1Help Viewer\ 2Help\ 3 and the \ 1Directory
+Tree.\ 2Directory Tree\ 3
+
+The default auto repeat rate for the mouse buttons is 400
+milliseconds. This may be changed to other values by
+editing the \ 1~/.mc/ini\ 2Save Setup\ 3 file and changing the
+\14mouse_repeat_rate\v parameter.
+
+If you are running the Commander with the mouse support,
+you can bypass the Commander and get the default mouse
+behavior (cutting and pasting text) by holding down the
+Shift key.\ 4[]
+
+
+\ 4[Keys]
+Keys
+
+Some commands in the Midnight Commander involve the use of
+the \14Control\v (sometimes labeled CTRL or CTL) and the \14Meta\v
+(sometimes labeled ALT or even Compose) keys. In this
+manual we will use the following abbreviations:
+
+C-<chr> means hold the Control key while typing the
+character <chr>. Thus C-f would be: hold the Control key
+and type f.
+
+M-<chr> means hold the Meta or Alt key down while typing
+<chr>. If there is no Meta or Alt key, type ESC, release
+it, then type the character <chr>.
+
+All input lines in the Midnight Commander use an
+approximation to the GNU Emacs editor's key bindings.
+
+There are many sections which tell about the keys. The
+following are the most important.
+
+The \ 1File Menu\ 2File Menu\ 3 section documents the keyboard shortcuts
+for the commands appearing in the File menu. This section
+includes the function keys. Most of these commands perform
+some action, usually on the selected file or the tagged
+files.
+
+The \ 1Directory Panels\ 2Directory Panels\ 3 section documents the keys which
+select a file or tag files as a target for a later action
+(the action is usually one from the file menu).
+
+The \ 1Shell Command Line\ 2Shell Command Line\ 3 section list the keys which are
+used for entering and editing command lines. Most of these
+copy file names and such from the directory panels to the
+command line (to avoid excessive typing) or access the
+command line history.
+
+\ 1Input Line Keys\ 2Input Line Keys\ 3 are used for editing input lines. This
+means both the command line and the input lines in the
+query dialogs.
+
+\ 4[Miscellaneous Keys]
+Miscellaneous Keys
+
+Here are some keys which don't fall into any of the other
+categories:
+
+\bEnter.\v If there is some text in the command line (the one
+at the bottom of the panels), then that command is
+executed. If there is no text in the command line then if
+the selection bar is over a directory the Midnight
+Commander does a \bchdir(2)\v to the selected directory and
+reloads the information on the panel; if the selection is
+an executable file then it is executed. Finally, if the
+extension of the selected file name matches one of the
+extensions in the \ 1extensions file\ 2Extension File Edit\ 3 then the corresponding
+command is executed.
+
+\bC-l.\v Repaint all the information in the Midnight
+Commander.
+
+\bC-x c.\v Run the \ 1Chmod\ 2Chmod\ 3 command on a file or on the tagged
+files.
+
+\bC-x o.\v Run the \ 1Chown\ 2Chown\ 3 command on the current file or on the
+tagged files.
+
+\bC-x l.\v Run the link command.
+
+\bC-x s.\v Run the symbolic link command.
+
+\bC-x i.\v Set the other panel display mode to information.
+
+\bC-x q.\v Set the other panel display mode to quick view.
+
+\bC-x !.\v Execute the \ 1External panelize\ 2External panelize\ 3 command.
+
+\bC-x h\v Run the \ 1add directory to hotlist\ 2Hotlist\ 3 command.
+
+\bM-!,\v Executes the Filtered view command, described in the
+\ 1view command.\ 2Internal File Viewer\ 3
+
+\bM-?,\v Executes the \ 1Find file\ 2Find File\ 3 command.
+
+\bM-c,\v Pops up the \ 1quick cd\ 2Quick cd\ 3 dialog.
+
+\bC-o,\v When the program is being run in the Linux or SCO
+console or under an xterm, it will show you the output of
+the previous command. When ran on the Linux console, the
+Midnight Commander uses an external program (cons.saver)
+to handle saving and restoring of information on the
+screen.
+
+When the subshell support is compiled in, you can type C-o
+at any time and you will be taken back to the Midnight
+Commander main screen, to return to your application just
+type C-o. If you have an application suspended by using
+this trick, you won't be able to execute other programs
+from the Midnight Commander until you terminate the
+suspended application.
+
+\ 4[Directory Panels]
+Directory Panels
+
+This section lists the keys which operate on the directory
+panels. If you want to know how to change the appearance
+of the panels take a look at the section on \ 1Left and Right
+Menus.\ 2Left and Right Menus\ 3
+
+\bTab, C-i.\v Change the current panel. The old other panel
+becomes the new current panel and the old current panel
+becomes the new other panel. The selection bar moves from
+the old current panel to the new current panel.
+
+\bInsert, C-t.\v To tag files you may use the Insert key (the
+kich1 terminfo sequence) or the C-t (Control-t) sequence.
+To untag files, just retag a tagged file.
+
+\bM-g, M-h (or M-r), M-j.\v Used to select the top file in a
+panel, the middle file and the bottom one, respectively.
+
+\bC-s, M-s.\v Start a filename search in the directory
+listing. When the search is active the keypresses will be
+added to the search string instead of the command line. If
+the \14"Show mini-status"\v option is enabled the search string
+is shown on the mini-status line. When typing, the
+selection bar will move to the next file starting with the
+typed letters. The \14"backspace" or DEL \v keys can be used to
+correct typing mistakes. If C-s is pressed again, the next
+match is searched for.
+
+\bM-t\v Toggle the current display listing to show the next
+display listing mode. With this it is possible to quickly
+switch from long listing to regular listing and the user
+defined listing mode.
+
+\bC-\\ (control-backslash).\v Show the \ 1directory hotlist\ 2Hotlist\ 3 and
+change to the selected directory.
+
+\b+ (plus).\v This is used to select (tag) a group of files.
+The Midnight Commander will prompt for a regular
+expression describing the group. When \14Shell Patterns \v are
+enabled, the regular expression is much like the regular
+expressions in the shell (* standing for zero or more
+characters and ? standing for one character). If \14Shell
+Patterns\v is off, then the tagging of files is done with
+normal regular expressions (see ed (1)).
+
+If the expression starts or ends with a slash (/), then it
+will select directories instead of files.
+
+\b\\ (backslash).\v Use the "\" key to unselect a group of
+files. This is the opposite of the Plus key.
+
+\bup-key, C-p.\v Move the selection bar to the previous entry
+in the panel.
+
+\bdown-key, C-n.\v Move the selection bar to the next entry in
+the panel.
+
+\bhome, a1, M-<.\v Move the selection bar to the first entry
+in the panel.
+
+\bend, c1, M->.\v Move the selection bar to the last entry in
+the panel.
+
+\bnext-page, C-v.\v Move the selection bar one page down.
+
+\bprev-page, M-v.\v Move the selection bar one page up.
+
+\bM-o,\v If the other panel is a listing panel and you are
+standing on a directory in the current panel, then the
+other panel contents are set to the contents of the
+currently selected directory (like Emacs' dired C-o key)
+otherwise the other panel contents are set to the parent
+dir of the current dir.
+
+\bC-PageUp, C-PageDown\v Only when ran on the Linux console:
+does a chdir to ".." and to the currently selected
+directory respectively.
+
+\ 4[Shell Command Line]
+Shell Command Line
+
+This section lists keys which are useful to avoid
+excessive typing when entering shell commands.
+
+\bM-Enter.\v Copy the currently selected file name to the
+command line.
+
+\bC-Enter.\v Same a M-Enter, this one only works on the Linux
+console.
+
+\bM-Tab.\v Does the filename, command, variable, username and
+hostname \ 1completion\ 2Completion\ 3 for you.
+
+\bC-x t, C-x C-t.\v Copy the tagged files (or if there are no
+tagged files, the selected file) of the current panel (C-x
+t) or of the other panel (C-x C-t) to the command line.
+
+\bC-x p, C-x C-p. \v The first key sequence copies the current
+path name to the command line, and the second one copies
+the unselected panel's path name to the command line.
+
+\bC-q.\v The quote command can be used to insert characters
+that are otherwise interpreted by the Midnight Commander
+(like the '+' symbol)
+
+\bM-p, M-n.\v Use these keys to browse through the command
+history. M-p takes you to the last entry, M-n takes you to
+the next one.
+
+\bM-h.\v Displays the history for the current input line.
+
+\ 4[General Movement Keys]
+General Movement Keys
+
+The help viewer, the file viewer and the directory tree
+use common code to handle moving. Therefore they accept
+exactly the same keys. Each of them also accepts some keys
+of its own.
+
+Other parts of the Midnight Commander use some of the same
+movement keys, so this section may be of use for those
+parts too.
+
+\bUp, C-p.\v Moves one line backward.
+
+\bDown, C-n.\v Moves one line forward.
+
+\bPrev Page, Page Up, M-v.\v Moves one pageful backward.
+
+\bNext Page, Page Down, C-v.\v Moves one pageful forward.
+
+\bHome, A1.\v Moves to the beginning.
+
+\bEnd, C1.\v Move to the end.
+
+The help viewer and the file viewer accept the following
+keys in addition the to ones mentioned above:
+
+\bb, C-b, C-h, Backspace, Delete.\v Moves one pageful
+backward.
+
+\bSpace bar.\v Moves one pageful forward.
+
+\bu, d.\v Moves one half of a page backward or forward.
+
+\bg, G.\v Moves to the beginning or to the end.
+
+\ 4[Input Line Keys]
+Input Line Keys
+
+The input lines (they are used for the \ 1command line\ 2Shell Command Line\ 3 and
+for the query dialogs in the program) accept these keys:
+
+\bC-a\v puts the cursor at the beginning of line.
+
+\bC-e\v puts the cursor at the end of the line.
+
+\bC-b, move-left\v move the cursor one position left.
+
+\bC-f, move-right\v move the cursor one position right.
+
+\bM-f\v moves one word forward.
+
+\bM-b\v moves one word backward.
+
+\bC-h, backspace\v delete the previous character.
+
+\bC-d, Delete\v delete the character in the point (over the
+cursor).
+
+\bC-@\v sets the mark for cutting.
+
+\bC-w\v copies the text between the cursor and the mark to a
+kill buffer and removes the text from the input line.
+
+\bM-w\v copies the text between the cursor and the mark to a
+kill buffer.
+
+\bC-y\v yanks back the contents of the kill buffer.
+
+\bC-k\v kills the text from the cursor to the end of the line.
+
+\bM-p, M-n\v Use these keys to browse through the command
+history. M-p takes you to the last entry, M-n takes you to
+the next one.
+
+\bM-C-h, M-Backspace\v delete one word backward.
+
+\bM-Tab\v does the filename, command, variable, username and
+hostname \ 1completion\ 2Completion\ 3 for you.
+
+\ 4[]
+
+
+\ 4[Menu Bar]
+Menu Bar
+
+The menu bar pops up when you press F9 or click the mouse
+on the top row of the screen. The menu bar has five menus:
+"Left", "File", "Command", "Options" and "Right".
+
+The \ 1Left and Right Menus\ 2Left and Right Menus\ 3 allow you to modify the
+appearance of the left and right directory panels.
+
+The \ 1File Menu\ 2File Menu\ 3 lists the actions you can perform on the
+currently selected file or the tagged files.
+
+The \ 1Command Menu\ 2Command Menu\ 3 lists the actions which are more general
+and bear no relation to the currently selected file or the
+tagged files.
+
+\ 4[Left and Right Menus]
+Left and Right Menus
+
+The outlook of the directory panels can be changed from
+the \b"Left"\v and \b"Right"\v menus.
+
+\ 4[Listing Mode...]
+Listing Mode...
+
+The listing mode view is used to display a listing of
+files, there are four different listing modes available:
+\bFull,\v \bBrief,\v \bLong,\v and \bUser.\v The full directory view shows
+the file name, the size of the file and the modification
+time.
+
+The brief view shows only the file name and it has two
+columns (therefore showing twice as many files as other
+views). The long view is similar to the output of \b"ls -l"\v
+command. The long view takes the whole screen width.
+
+If you choose the "User" display format, then you have to
+specify the display format.
+
+The user display format must start with a panel size
+specifier. This may be "half" or "full", and they specify
+a half screen panel and a full screen panel respectively.
+
+After the panel size, you may specify the two columns mode
+on the panel, this is done by adding the number "2" to the
+user format string.
+
+After this you add the name of the fields with an optional
+size specifier. This are the available fields you may
+display:
+
+\bname,\v displays the file name.
+
+\bsize,\v displays the file size.
+
+\bbsize,\v is an alternative form of the <bf/size/ format. It
+displays the size of the files and for directories it just
+shows SUB-DIR or UP--DIR.
+
+\btype,\v displays a one character field type. This character
+is a superset of what is displayed by ls with the -F flag.
+An asterisk for executable files, a slash for directories,
+an at-sign for links, an equal sign for sockets, a hyphen
+for character devices, a plus sign for block devices, a
+pipe for fifos, a tilde for symbolic links to directories
+and an exclamation mark for stalled symlinks (links that
+point nowhere).
+
+\bmtime,\v file's last modification time.
+
+\batime,\v file's last access time.
+
+\bctime,\v file's creation time.
+
+\bperm,\v a string representing the current permission bits of
+the file.
+
+\bmode,\v an octal value with the current permission bits of
+the file.
+
+\bnlink,\v the number of links to the file. \bngid,\v the GID
+(numeric).
+
+\bnuid,\v the UID (numeric).
+
+\bowner,\v the owner of the file.
+
+\bgroup,\v the group of the file.
+
+\binode,\v the inode of the file.
+
+Also you may use these field names for arranging the
+display:
+
+\bspace,\v a space in the display format.
+
+\bmark,\v An asterisk if the file is tagged, a space if it's
+not.
+
+\b|,\v This character is used to add a vertical line to the
+display format.
+
+To force one field to a fixed size (a size specifier), you
+just add a ':' and then the number of characters you want
+the field to have, if the number is followed by the symbol
+'+', then the size specifies the minimum field size, if
+the program finds out that there is more space on the
+screen, it will then expand this field.
+
+For example, the \bFull\v display corresponds to this format:
+
+half type,name,|,size,|,mtime
+
+And the \bLong\v display corresponds to this format:
+
+full
+perm,space,nlink,space,owner,space,group,space,size,space,
+mtime,space,name
+
+This is a nice user display format:
+
+half name,|,size:7,|,type,mode:3
+
+Panels may also be set to the following modes:
+
+\b"Info"\v The info view display information related to the
+currently selected file and if possible information about
+the current file system.
+
+\b"Tree" \v The tree view is quite similar to the \ 1directory
+tree\ 2Directory Tree\ 3 feature. See the section about it for more
+information.
+
+\b"Quick View"\v In this mode, the panel will switch to a
+reduced \ 1viewer\ 2Internal File Viewer\ 3 that displays the contents of the
+currently selected file, if you select the panel (with the
+tab key or the mouse), you will have access to the usual
+viewer commands.
+
+\ 4[Sort Order...]
+Sort Order...
+
+The eight sort orders are by name, by extension, by
+modification time, by access time, and by inode
+information modification time, by size, by inode and
+unsorted. In the Sort order dialog box you can choose the
+sort order and you may also specify if you want to sort in
+reverse order by checking the reverse box.
+
+By default directories are sorted before files but this
+can be changed from the \ 1Options menu\ 2Options Menu\ 3 (option \b"Mix all
+files"\v ).
+
+\ 4[Filter...]
+Filter...
+
+The filter command allows you to specify a shell pattern
+(for example \b"*.tar.gz"\v ) which the files must match to be
+shown. Regardless of the filter pattern, the directories
+and the links to directories are always shown in the
+directory panel.
+
+\ 4[Reread]
+Reread
+
+The reread command reload the list of files in the
+directory. It is useful if other processes have created or
+removed files. If you have panelized file names in a panel
+this will reload the directory contents and remove the
+panelized information (See the section \ 1External panelize\ 2External panelize\ 3
+for more information).
+
+\ 4[File Menu]
+File Menu
+
+The Midnight Commander uses the F1 - F10 keys as keyboard
+shortcuts for commands appearing in the file menu. The
+escape sequences for the Fkeys are terminfo capabilities
+kf1 trough kf10. On terminals without function key
+support, you can achieve the same functionality by
+pressing the ESC key and then a number in the range 1
+through 9 and 0 (corresponding to F1 to F9 and F10
+respectively).
+
+The File menu has the following commands (keyboard
+shortcuts in parentheses):
+
+\bHelp (F1)\v
+
+Invokes the built-in hypertext help viewer. Inside the
+\ 1help viewer,\ 2Help\ 3 you can use the Tab key to select the next
+link and the Enter key to follow that link. The keys Space
+and Backspace are used to move forward and backward in a
+help page. Press F1 again to get the full list of accepted
+keys.
+
+\bMenu (F2)\v
+
+Invoke the \ 1user menu.\ 2Menu File Edit\ 3 The user menu provides an easy way
+to provide users with a menu and add extra features to the
+Midnight Commander.
+
+\bView (F3, Shift-F3)\v
+
+View the currently selected file. By default this invokes
+the \ 1Internal File Viewer\ 2Internal File Viewer\ 3 but if the option "Use internal
+view" is off, it invokes an external file viewer specified
+by the \bPAGER \v environment variable. If \bPAGER\v is undefined,
+the "view" command is invoked. If you use Shift-F3
+instead, the viewer will be invoked without doing any
+formatting or pre processing to the file.
+
+\bFiltered View (M-!)\v
+
+this command prompts for a command and it's arguments (the
+argument defaults to the currently selected file name),
+the output from such command is shown in the internal file
+viewer.
+
+\bEdit (F4)\v
+
+Currently it invokes the \bvi \v editor, or the editor
+specified in the \bEDITOR\v environment variable, or the
+\ 1Internal File Editor\ 2Internal File Editor\ 3 if the use_internal_edit option is
+on.
+
+\bCopy (F5)\v
+
+Pop up an input dialog with destination that defaults to
+the directory in the non-selected panel and copies the
+currently selected file (or the tagged files, if there is
+at least one file tagged) to the directory specified by
+the user in the input dialog. During this process, you can
+press C-c or ESC to abort the operation. For details about
+source mask (which will be usually either * or ^\(.*\)$
+depending on setting of Use shell patterns) and possible
+wildcards in the destination see \ 1Mask copy/rename.\ 2Mask Copy/Rename\ 3
+
+On some systems, it is possible to do the copy in the
+background by clicking on the background button (or
+pressing M-b in the dialog box). The \ 1Background Jobs\ 2Background Jobs\ 3 is
+used to control the background process.
+
+\bLink (C-x l)\v
+
+Create a hard link to the current file.
+
+\bSymLink (C-x s)\v
+
+Create a symbolic link to the current file. To those of
+you who don't know what links are: creating a link to a
+file is a bit like copying the file, but both the source
+filename and the destination filename represent the same
+file image. For example, if you edit one of these files,
+all changes you make will appear in both files. Some
+people call links aliases or shortcuts.
+
+A hard link appears as a real file. After making it, there
+is no way of telling which one is the original and which
+is the link. If you delete either one of them the other
+one is still intact. It is very difficult to notice that
+the files represent the same image. Use hard links when
+you don't even want to know.
+
+A symbolic link is a reference to the name of the original
+file. If the original file is deleted the symbolic link is
+useless. It is quite easy to notice that the files
+represent the same image. The Midnight Commander shows an
+"@"-sign in front of the file name if it is a symbolic
+link to somewhere (except to directory, where it shows a
+tilde (~)). The original file which the link points to is
+shown on mini-status line if the \14"Show mini-status"\v option
+is enabled. Use symbolic links when you want to avoid the
+confusion that can be caused by hard links.
+
+\bRename/Move (F6)\v
+
+Pop up an input dialog that defaults to the directory in
+the non-selected panel and moves the currently selected
+file (or the tagged files if there is at least one tagged
+file) to the directory specified by the user in the input
+dialog. During the process, you can press C-c or ESC to
+abort the operation. For more details look at Copy
+operation above, most of the things are quite similar.
+
+On some systems, it is possible to do the copy in the
+background by clicking on the background button (or
+pressing M-b in the dialog box). The \ 1Background Jobs\ 2Background Jobs\ 3 is
+used to control the background process.
+
+\bMkdir (F7)\v
+
+Pop up an input dialog and creates the directory
+specified.
+
+\bDelete (F8)\v
+
+Delete the currently selected file or the tagged files in
+the currently selected panel. During the process, you can
+press C-c or ESC to abort the operation.
+
+\bQuick cd (M-c)\v Use the \ 1quick cd\ 2Quick cd\ 3 command if you have full
+command line and want to cd somewhere.
+
+\bSelect group (+)\v
+
+This is used to select (tag) a group of files. The
+Midnight Commander will prompt for a regular expression
+describing the group. When \14Shell Patterns \v are enabled,
+the regular expression is much like the filename globbing
+in the shell (* standing for zero or more characters and ?
+standing for one character). If \14Shell Patterns\v is off,
+then the tagging of files is done with normal regular
+expressions (see ed (1)).
+
+To mark directories instead of files, the expression must
+start or end with a '/'.
+
+\bUnselect group (\\)\v
+
+Used for unselecting a group of files. This is the
+opposite of the \14"Select group"\v command.
+
+\bQuit (F10, Shift-F10)\v
+
+Terminate the Midnight Commander. Shift-F10 is used when
+you want to quit and you are using the shell wrapper.
+Shift-F10 will not take you to the last directory you
+visited with the Midnight Commander, instead it will stay
+at the directory where you started the Midnight Commander.
+
+\ 4[Quick cd]
+Quick cd
+
+This command is useful if you have a full command line and
+want to \ 1cd\ 2The cd internal command\ 3 somewhere without having to yank and paste
+the command line. This command pops up a small dialog,
+where you enter everything you would enter after \bcd \v on
+the command line and then you press enter. This features
+all the things that are already in the \ 1internal cd
+command.\ 2The cd internal command\ 3
+
+\ 4[Command Menu]
+Command Menu
+
+The \ 1Directory tree\ 2Directory Tree\ 3 command shows a tree figure of the
+directories.
+
+The \ 1Find file\ 2Find File\ 3 command allows you to search for a specific
+file. The "Swap panels" command swaps the contents of the
+two directory panels.
+
+The "Panels on/off" command shows the output of the last
+shell command. This works only on xterm and on Linux and
+SCO console.
+
+The Compare directories (C-x d) command compares the
+directory panels with each other. You can then use the
+Copy (F5) command to make the panels identical. There are
+three compare methods. The quick method compares only file
+size and file date. The thorough method makes a full
+byte-by-byte compare. The thorough method is not available
+if the machine does not support the mmap(2) system call.
+The size-only compare method just compares the file sizes
+and does not check the contents or the date times, it just
+checks the file size.
+
+The Command history command shows a list of typed
+commands. The selected command is copied to the command
+line. The command history can also be accessed by typing
+M-p or M-n.
+
+The \ 1Directory hotlist (C-\)\ 2Hotlist\ 3 command makes changing of the
+current directory to often used directories faster.
+
+The \ 1External panelize\ 2External panelize\ 3 allows you to execute an external
+program, and make the output of that program the contents
+of the current panel.
+
+\ 1Extension file edit\ 2Extension File Edit\ 3 command allows you to specify
+programs to executed when you try to execute, view, edit
+and do a bunch of other thing on files with certain
+extensions (filename endings). The \ 1Menu file edit\ 2Menu File Edit\ 3
+command may be used for editing the user menu (which
+appears by pressing F2).
+
+\ 4[Directory Tree]
+Directory Tree
+
+The Directory Tree command shows a tree figure of the
+directories. You can select a directory from the figure
+and the Midnight Commander will change to that directory.
+
+There are two ways to invoke the tree. The real directory
+tree command is available from Commands menu. The other
+way is to select tree view from the Left or Right menu.
+
+To get rid of long delays the Midnight Commander creates
+the tree figure by scanning only a small subset of all the
+directories. If the directory which you want to see is
+missing, move to its parent directory and press C-r (or
+F2).
+
+You can use the following keys:
+
+\ 1General movement keys\ 2General Movement Keys\ 3 are accepted.
+
+\bEnter.\v In the directory tree, exits the directory tree and
+changes to this directory in the current panel. In the
+tree view, changes to this directory in the other panel
+and stays in tree view mode in the current panel.
+
+\bC-r, F2 (Rescan).\v Rescan this directory. Use this when the
+tree figure is out of date: it is missing subdirectories
+or shows some subdirectories which don't exist any more.
+
+\bF3 (Forget).\v Delete this directory from the tree figure.
+Use this to remove clutter from the figure. If you want
+the directory back to the tree figure press F2 in its
+parent directory.
+
+\bF4 (Static/Dynamic).\v Toggle between the dynamic navigation
+mode (default) and the static navigation mode.
+
+In the static navigation mode you can use the Up and Down
+keys to select a directory. All known directories are
+shown.
+
+In the dynamic navigation mode you can use the Up and Down
+keys to select a sibling directory, the Left key to move
+to the parent directory, and the Right key to move to a
+child directory. Only the parent, sibling and children
+directories are shown, others are left out. The tree
+figure changes dynamically as you traverse.
+
+\bF5 (Copy).\v Copy the directory.
+
+\bF6 (RenMov).\v Move the directory.
+
+\bF7 (Mkdir).\v Make a new directory below this directory.
+
+\bF8 (Delete).\v Delete this directory from the file system.
+
+\bC-s, M-s.\v Search the next directory matching the search
+string. If there is no such directory these keys will move
+one line down.
+
+\bC-h, Backspace.\v Delete the last character of the search
+string.
+
+\bAny other character.\v Add the character to the search
+string and move to the next directory which starts with
+these characters. In the tree view you must first activate
+the search mode by pressing C-s. The search string is
+shown in the mini status line.
+
+The following actions are available only in the directory
+tree. They aren't supported in the tree view.
+
+\bF1 (Help).\v Invoke the help viewer and show this section.
+
+\bEsc, F10.\v Exit the directory tree. Do not change the
+directory.
+
+The mouse is supported. A double-click behaves like Enter.
+See also the section on \ 1mouse support.\ 2Mouse Support\ 3
+
+\ 4[Find File]
+Find File
+
+The Find File feature first asks for the start directory
+for the search and the filename to be searched for. By
+pressing the Tree button you can select the start
+directory from the \ 1directory tree\ 2Directory Tree\ 3 figure.
+
+The contents field accepts regular expressions similar to
+egrep(1). That means you have to escape characters with a
+special meaning to egrep with "\", e.g. if you search for
+"strcmp (" you will have to input "strcmp \(" (without the
+double quotes).
+
+You can start the search by pressing the Ok button. During
+the search you can stop from the Stop button and continue
+from the Start button.
+
+You can browse the filelist with the up and down arrow
+keys. The Chdir button will change to the directory of the
+currently selected file. The Again button will ask for the
+parameters for a new search. The Quit button quits the
+search operation. The Panelize button will place the found
+files to the current directory panel so that you can do
+additional operations on them (view, copy, move, delete
+and so on). After panelizing you can press C-r to return
+to the normal file listing.
+
+It is possible to have a list of directories that the Find
+File command should skip during the search (for example,
+you may want to avoid searches on a CDROM or on a NFS
+directory that is mounted across a slow link).
+
+Directories to be skipped should be set on the variable
+\bfind_ignore_dirs \v in the \bMisc \v section of your ~/.mc/ini
+file.
+
+Directory components should be separated with a colon,
+here is an example:
+
+[Misc]
+find_ignore_dirs=/cdrom:/nfs/wuarchive:/afs
+
+You may consider using the \ 1External panelize\ 2External panelize\ 3 command for
+some operations. Find file command is for simple queries
+only, while using External panelize you can do as
+mysterious searches as you would like.
+
+\ 4[External panelize]
+External panelize
+
+The External panelize allows you to execute an external
+program, and make the output of that program the contents
+of the current panel.
+
+For example, if you want to manipulate in one of the
+panels all the symbolic links in the current directory,
+you can use external panelization to run the following
+command:
+
+find . -type l -print
+Upon command completion, the directory contents of the
+panel will no longer be the directory listing of the
+current directory, but all the files that are symbolic
+links.
+
+If you want to panelize all of the files that have been
+downloaded from your ftp server, you can use this awk
+command to extract the file name from the transfer log
+files:
+
+awk '$9 ~! /incoming/ { print $9 }' < /usr/adm/xferlog
+
+You may want to save often used panelize commands under a
+descriptive name, so that you can recall them quickly. You
+do this by typing the command on the input line and
+pressing Add new button. Then you enter a name under which
+you want the command to be saved. Next time, you just
+choose that command from the list and do not have to type
+it again.
+
+\ 4[Hotlist]
+Hotlist
+
+The Directory hotlist command shows the labels of the
+directories in the directory hotlist. The Midnight
+Commander will change to the directory corresponding to
+the selected label. From the hotlist dialog, you can
+remove already created label/directory pairs and add new
+one. For adding you may want to use a standalone Add to
+hotlist command (C-x h), which adds the current directory
+into the directory hotlist, as well. The user is prompted
+for a label for the directory.
+
+This makes cd to often used directories faster. You may
+consider using the CDPATH variable as described in
+\ 1internal cd command\ 2The cd internal command\ 3 description.
+
+\ 4[Extension File Edit]
+Extension File Edit
+
+This will invoke your editor on the file ~/.mc/ext. The
+format of this file is as follows (the format has changed
+with version 3.0):
+
+All lines starting with # or empty lines are thrown away.
+
+Lines starting in the first column should have following
+format:
+
+\14keyword/descNL,\v i.e. everything after \14keyword/\v until new
+line is \14desc\v
+
+keyword can be:
+
+\14shell\v (desc is then any extension (no wildcards), i.e.
+matches all the files *desc . Example: .tar matches *.tar)
+
+\14regex\v (desc is a regular expression)
+
+\14type\v (file matches this if `file %f` matches regular
+expression desc (the filename: part from `file %f` is
+removed))
+
+\14default\v (matches any file no matter what desc is)
+
+Other lines should start with a space or tab and should be
+of the format:
+
+\14keyword=commandNL\v (with no spaces around =), where \14keyword\v
+should be:
+
+\14Open\v (if the user presses Enter or doubleclicks it), \14View\v
+(F3), \14Edit\v (F4), \14Drop\v (user drops some files on it) or any
+other user defined name (those will be listed in the
+extension dependent pop-up menu). \14Icon\v name is reserved
+for future use by mc.
+
+\14command\v is any one-line shell command, with the simple
+\ 1macro substitution.\ 2Macro Substitution\ 3
+
+Target are evaluated from top to bottom (order is thus
+important). If some actions are missing, search continues
+as if this target didn't match (i.e. if a file matches the
+first and second entry and View action is missing in the
+first one, then on pressing F3 the View action from the
+second entry will be used. default should catch all the
+actions.
+
+\ 4[Background jobs]
+Background jobs
+
+This lets you control the state of any background Midnight
+Commander process (only copy and move files operations can
+be done in the background). You can stop, restart and kill
+a background job from here.
+
+\ 4[Menu File Edit]
+Menu File Edit
+
+The user menu is a menu of useful actions that can be
+customized by the user. When you access the user menu, the
+file .mc.menu from the current directory is used if it
+exists, but only if it is owned by user or root and is not
+world-writable. If no such file found, ~/.mc/menu is tried
+in the same way, and otherwise mc uses the default
+system-wide menu @prefix@/lib/mc/mc.menu.
+
+The format of the menu file is very simple. Lines that
+start with anything but space or tab are considered
+entries for the menu (in order to be able to use it like a
+hot key, the first character should be a letter). All the
+lines that start with a space or a tab are the commands
+that will be executed when the entry is selected.
+
+When an option is selected all the command lines of the
+option are copied to a temporary file in the temporary
+directory (usually /usr/tmp) and then that file is
+executed. This allows the user to put normal shell
+constructs in the menus. Also simple macro substitution
+takes place before executing the menu code. For more
+information, see \ 1macro substitution.\ 2Macro Substitution\ 3
+
+Here is a sample mc.menu file:
+
+A Dump the currently selected file
+ od -c %f
+
+B Edit a bug report and send it to root
+ vi /tmp/mail.$$
+ mail -s "Midnight Commander bug" root < /tmp/mail.$$
+
+M Read mail
+ emacs -f rmail
+
+N Read Usenet news
+ emacs -f gnus
+
+H Call the info hypertext browser
+ info
+
+J Copy current directory to other panel recursively
+ tar cf - . | (cd %D && tar xvpf -)
+
+K Make a release of the current subdirectory
+ echo -n "Name of distribution file: "
+ read tar
+ ln -s %d `dirname %d`/$tar
+ cd ..
+ tar cvhf ${tar}.tar $tar
+
+= f *.tar.gz | f *.tgz & t n
+X Extract the contents of a compressed tar file
+ tar xzvf %f
+
+\bDefault Conditions\v
+
+Each menu entry may be preceded by a condition. The
+condition must start from the first column with a '='
+character. If the condition is true, the menu entry will
+be the default entry.
+
+Condition syntax: = <sub-cond>
+ or: = <sub-cond> | <sub-cond> ...
+ or: = <sub-cond> & <sub-cond> ...
+
+Sub-condition is one of following:
+
+ f <pattern> current file matching pattern?
+ F <pattern> other file matching pattern?
+ d <pattern> current directory matching pattern?
+ D <pattern> other directory matching pattern?
+ t <type> current file of type?
+ T <type> other file of type?
+ ! <sub-cond> negate the result of sub-condition
+
+Pattern is a normal shell pattern or a regular expression,
+according to the shell patterns option. You can override
+the global value of the shell patterns option by writing
+"shell_patterns=x" on the first line of the menu file
+(where "x" is either 0 or 1).
+
+Type is one or more of the following characters:
+
+ n not directory
+ r regular file
+ d directory
+ l link
+ c char special
+ b block special
+ f fifo
+ s socket
+ x executable
+ t tagged
+
+For example 'rlf' means either regular file, link or fifo.
+The 't' type is a little special because it acts on the
+panel instead of the file. The condition '=t t' is true if
+there are tagged files in the current panel and false if
+not.
+
+If the condition starts with '=?' instead of '=' a debug
+trace will be shown whenever the value of the condition is
+calculated.
+
+The conditions are calculated from left to right. This
+means
+ = f *.tar.gz | f *.tgz & t n
+is calculated as
+ ( (f *.tar.gz) | (f *.tgz) ) & (t n)
+
+Here is a sample of the use of conditions:
+
+= f *.tar.gz | f *.tgz & t n
+L List the contents of a compressed tar-archive
+ gzip -cd %f | tar xvf -
+
+\bAddition Conditions\v
+
+If the condition begins with '+' (or '+?') instead of '='
+(or '=?') it is an addition condition. If the condition is
+true the menu entry will be included in the menu. If the
+condition is false the menu entry will not be included in
+the menu.
+
+You can combine default and addition conditions by
+starting condition with '+=' or '=+' (or '+=?' or '=+?' if
+you want debug trace). If you want to use two different
+conditions, one for adding and another for defaulting, you
+can precede a menu entry with two condition lines, one
+starting with '+' and another starting with '='.
+
+Comments are started with '#'. The additional comment
+lines must start with '#', space or tab.
+
+\ 4[Options Menu]
+Options Menu
+
+The \ 1Configuration\ 2Configuration\ 3 command pops up a dialog from which you
+can change most of settings of the Midnight Commander.
+
+The \ 1Display bits\ 2Display bits\ 3 command pops up a dialog from which you
+may select which characters is your terminal able to
+display.
+
+The \ 1Confirmation\ 2Confirmation\ 3 command pops up a dialog from which you
+specify which actions you want to confirm.
+
+The \ 1Learn keys\ 2Learn keys\ 3 command pops up a dialog from which you
+test some keys which are not working on some terminals and
+you may fix them.
+
+The \ 1Virtual FS\ 2Virtual FS\ 3 command pops up a dialog from which you
+specify some VFS related options.
+
+The \ 1Layout\ 2Layout\ 3 command pops up a dialog from which you specify
+a bunch of options how mc looks like on the screen.
+
+The \ 1Save setup\ 2Save Setup\ 3 command saves the current settings of the
+Left, Right and Options menus. A small number of other
+settings is saved, too.
+
+\ 4[Configuration]
+Configuration
+
+The program has some options that may be toggled on and
+off from the Configuration dialog. Options are enabled if
+they have an asterisk or "x" in front of them. These
+options are divided into three groups: Screen Colors,
+Panel Options and Other Options.
+
+\bScreen Colors\v
+
+You can select whether your display supports color or not.
+Normally this information is in the terminfo database. If
+you want to know how to change individual colors see the
+section on \ 1Colors.\ 2Colors\ 3
+
+\bPanel Options\v
+
+\14Show Backup Files.\v By default the Midnight Commander
+doesn't show files ending in '~' (like GNU's ls option
+-B).
+
+\14Show Hidden Files.\v By default the Midnight Commander will
+show all files that start with a dot (like ls -a).
+
+\14Mark moves down.\v By default when you mark a file (with
+either C-t or the Insert key) the selection bar will move
+down.
+
+\14Show Mini-Status.\v If enabled, show one line of status
+information at the bottom of the panels about the
+currently selected item.
+
+\14Mix all files.\v When this option is enabled, all files and
+directories are shown mixed together. If the option is
+off, directories (and links to directories) are shown at
+the beginning of the listing, and other files afterwards.
+
+\14Fast directory reload.\v This option is off by default. If
+you activate the fast reload, the Midnight Commander will
+use a trick to determine if the directory contents have
+changed. The trick is to reload the directory only if the
+i-node of the directory has changed; this means that
+reloads only happen when files are created or deleted. If
+what changes is the i-node for a file in the directory
+(file size changes, mode or owner changes, etc) the
+display is not updated. In these cases, if you have the
+option on, you have to rescan the directory manually (with
+C-r).
+
+\bOther Options\v
+
+\14Verbose operation.\v This toggles whether the file Copy,
+Rename and Delete operations are verbose (i.e., display a
+dialog box for each operation). If you have a slow
+terminal, you may wish to disable the verbose operation.
+It is automatically turned off if the speed of your
+terminal is less than 9600 bps.
+
+\14Pause after run.\v After executing your commands, the
+Midnight Commander can pause, so that you can examine the
+output of the command. There are three possible settings
+for this variable: \14Never\v Means that you do not want to see
+the output of your command. If you are using the Linux or
+SCO console or an xterm, you will be able to see the
+output of the command by typing C-o. \14"On dumb terminals"\v
+You will get the pause message on terminals that are not
+capable of showing the output of the last command executed
+(any terminal that is not an xterm or the Linux console).
+\14Always\v The program will pause after executing all of your
+commands.
+
+\14Shell Patterns.\v By default the Select, Unselect and Filter
+commands will use shell-like regular expressions. The
+following conversions are performed to achieve this: the
+'*' is replaced by '.*' (zero or more characters); the '?'
+is replaced by '.' (exactly one character) and '.' by the
+literal dot. If the option is disabled, then the regular
+expressions are the ones described in ed(1).
+
+\14Auto Save Setup.\v If this option is enabled, when you exit
+the Midnight Commander the configurable options of the
+Midnight Commander are saved in the ~/.mc/ini file.
+
+\14Auto menus.\v If this option is enabled, the user menu will
+be invoked at startup. Useful for building menus for
+non-unixers.
+
+\14Use internal editor.\v If this option is enabled, the
+built-in file editor is used to edit files. If the option
+is disabled, the editor specified in the \bEDITOR\v
+environment variable is used. If no editor is specified,
+\bvi\v is used. See the section on the \ 1internal file editor.\ 2Internal File Editor\ 3
+
+\14Use internal viewer.\v If this option is enabled, the
+built-in file viewer is used to view files. If the option
+is disabled, the pager specified in the \bPAGER\v environment
+variable is used. If no pager is specified, the \bview\v
+command is used. See the section on the \ 1internal file
+viewer.\ 2Internal File Viewer\ 3
+
+\14Confirm Delete.\v This option is toggled on by default, and
+will cause the Midnight Commander to ask for confirmation
+when deleting a single file.
+
+\14Cd follows links.\v This option, if set, causes the Midnight
+Commander to follow the logical chain of directories when
+changing current directory either in the panels, or using
+the cd command. This is the default behavior of bash. When
+unset, the Midnight Commander follows the real directory
+structure, so cd .. if you've entered that directory
+through a link will move you to the current directory's
+real parent and not to the directory where the link was
+present.
+
+\ 4[Display bits]
+Display bits
+
+This is used to configure the range of visible characters
+on the screen. This setting may be 7-bits if your
+terminal/curses supports only seven output bits,
+ISO-8859-1 displays all the characters in the ISO-8859-1
+map and full 8 bits is for those terminals that can
+display full 8 bit characters.
+
+\ 4[Confirmation]
+Confirmation
+
+In this menu you configure the confirmation options for
+file deletion, overwriting, execution by pressing enter
+and quitting the program.
+
+\ 4[Learn keys]
+Learn keys
+
+This dialog lets you test if your keys F1-F20, Home, End,
+etc. work properly on your terminal. They often don't,
+since many terminal databases are broken.
+
+You can move around with the Tab key, with the vi moving
+keys ('h' left, 'j' down, 'k' up and 'l' right) and after
+you press any arrow key once (this will mark it OK), then
+you can use that key as well.
+
+You test them just by pressing each of them. As soon as
+you press a key and the key works properly, OK should
+appear next to the name of that key. Once a key is marked
+OK it starts to work as usually, e.g. F1 for the first
+time will just check that F1 works OK, but from that time
+on it will show help. The same applies to the arrow keys.
+Tab key should be working always.
+
+If some keys do not work properly, then you won't see OK
+after the key name after you have pressed that key. You
+may then want to fix it. You do it by pressing the button
+of that key (either by mouse or using Tab and Enter). Then
+a red message will appear and you will be asked to type
+that key. If you want to abort this, press just Esc and
+wait until the message disappears. Otherwise type the key
+you're asked to type and also wait until the dialog
+disappears.
+
+When you finish with all the keys, you may want either to
+Save your key fixes into your ~/.mc/ini file into the
+[terminal:TERM] section (where TERM is the name of your
+current terminal) or to discard them. If all your keys
+were working properly and you had not to fix any key, then
+(of course) no saving will occur.
+
+\ 4[Virtual FS]
+Virtual FS
+
+This option gives you control over the settings of the
+\ 1Virtual File System \ 2Virtual File System\ 3 information cache.
+
+The Midnight Commander keeps in memory the information
+related to some of the virtual file systems to speed up
+the access to the files in the file system. Since the
+information that must be kept may be large (for example,
+compressed tar files may be kept in RAM for faster
+access), you may want to tune the parameters of the cached
+information to decrease your memory usage or to maximize
+the speed of access to frequently used file systems.
+
+The Tar file system is quite clever about how it handles
+tar files: it just loads the directory entries and when it
+needs to use the information contained in the tar file, it
+goes and grab it.
+
+In the wild, tar files are usually kept compressed (plain
+tar files are species in extinction), and because of the
+nature of those files (the directory entries for the tar
+files is not there waiting for us to be loaded), the tar
+file system has two choices: load the complete,
+uncompressed tar file into memory or uncompress the file
+in the disk in a temporary location and then access the
+uncompressed file as a regular tar file.
+
+In this dialog box you tell the Midnight Commander which
+sizes for compressed tar files you will tolerate to load
+into your precious memory. The default setting is set to
+one megabyte, this means that compressed tar files whose
+size is at most one megabyte will be loaded into core,
+otherwise a temporary uncompressed tar file will be
+created to access the contents (all of this is transparent
+to the user).
+
+The program will let you add a suffix to specify the units
+of the number you typed in, use 'k' for kilobyte and 'm'
+for megabyte. Our routine does not accept floating point
+numbers, so you can't use ".5 m" to specify 512 kilobytes,
+you will have to use "512 k" instead.
+
+Now, since we all love to browse files and tar files all
+over the disk, it's common that you will leave a tar file
+and the re-enter it later. Since uncompression is slow,
+the Midnight Commander will cache the information in
+memory for a limited amount of time, after you hit the
+timeout, all of the memory resources associated with the
+file system will be freed. The default timeout is set to
+one minute.
+
+\ 4[Layout]
+Layout
+
+The layout dialog gives you a possibility to change the
+general layout of screen. You can specify whether the
+menubar, the command prompt, the hintbar and the function
+keybar are visible. On the Linux or SCO console you can
+specify how many lines are shown in the output window.
+
+The rest of the screen area is used for the two directory
+panels. You can specify whether the area is split to the
+panels in vertical or horizontal direction. The split can
+be equal or you can specify an unequal split.
+
+\ 4[Save Setup]
+Save Setup
+
+At startup the Midnight Commander will try to load
+initialization information from the ~/.mc/ini file. If
+this file doesn't exist, it will load the information from
+the system-wide configuration file, located in
+@prefix@/lib/mc/mc.ini. If the system-wide configuration
+file doesn't exist, MC uses the default settings.
+
+The \14Save Setup\v command creates the ~/.mc/ini file by
+saving the current settings of the \ 1Left, Right\ 2Left and Right Menus\ 3 and
+\ 1Options\ 2Options Menu\ 3 menus.
+
+If you activate the \14auto save setup\v option, MC will always
+save the current settings when exiting.
+
+There also exist settings which can't be changed from the
+menus. To change these settings you have to edit the setup
+file with your favorite editor. See the section on \ 1Special
+Settings\ 2Special Settings\ 3 for more information.
+
+\ 4[]
+
+
+\ 4[Executing operating system commands]
+Executing operating system commands
+
+You may execute commands by typing them directly in the
+Midnight Commander's input line, or by selecting the
+program you want to execute with the selection bar in one
+of the panels and hitting Enter.
+
+If you press Enter over a file that is not executable, the
+Midnight Commander checks the extension of the selected
+file against the extensions in the \ 1Extensions File.\ 2Extension File Edit\ 3 If a
+match is found then the code associated with that
+extension is executed. A very simple \ 1macro expansion\ 2Macro Substitution\ 3
+takes place before executing the command.
+
+\ 4[The cd internal command]
+The cd internal command
+
+The \14cd\v command is interpreted by the Midnight Commander,
+it is not passed to the command shell for execution. Thus
+it may not handle all of the nice macro expansion and
+substitution that your shell does, although it does some
+of them:
+
+\14Tilde substitution\v The (~) will be substituted with your
+home directory, if you append a username after the tilde,
+then it will be substituted with the login directory of
+the the specified user.
+
+For example, ~guest is the home directory for the user
+guest, while ~/guest is the directory guest in your home
+directory.
+
+\14Previous directory\v You can jump to the directory you were
+previously by using the special directory name '-' like
+this: \bcd -\v
+
+\14CDPATH directories\v If the directory specified to the \bcd \v
+command is not in the current directory, then The Midnight
+Commander uses the value in the environment variable
+\bCDPATH\v to search for the directory in any of the named
+directories.
+
+For example you could set your \bCDPATH\v variable to
+~/src:/usr/src, allowing you to change your directory to
+any of the directories inside the ~/src and /usr/src
+directories, from any place in the file system by using
+it's relative name (for example cd linux could take you to
+/usr/src/linux).
+
+\ 4[Macro Substitution]
+Macro Substitution
+
+
+When accessing a \ 1user menu, \ 2Menu File Edit\ 3 or executing an \ 1extension
+dependent command,\ 2Extension File Edit\ 3 or running a command from the command
+line input, a simple macro substitution takes place.
+
+The macros are:
+
+\14"%f"\v The current file name.
+
+\14"%d"\v The current directory name.
+
+\14"%F"\v The current file in the unselected panel.
+
+\14"%D"\v The directory name of the unselected panel.
+
+\14"%t"\v The currently tagged files.
+
+\14"%T"\v The tagged files in the unselected panel.
+
+\14"%u"\v and \14"%U"\v Similar to the %t and %T macros, but in
+addition the files are untagged. You can use this macro
+only once per menu file entry or extension file entry,
+because next time there will be no tagged files.
+
+\14"%s"\v and \14"%S"\v The selected files: The tagged files if
+there are any. Otherwise the current file.
+
+\14"%q"\v Dropped files. In all places except in the Drop
+action of the \ 1mc.ext file,\ 2Extension File Edit\ 3 this will become a null
+string, in the Drop action it will be replaced with a
+space separated list of files that were dropped on the
+file.
+
+\14"%cd"\v This is a special macro that is used to change the
+current directory to the directory specified in front of
+it. This is used primarily as an interface to the \ 1Virtual
+File System.\ 2Virtual File System\ 3
+
+\14"%view"\v This macro is used to invoke the internal viewer.
+This macro can be used alone, or with arguments. If you
+pass any arguments to this macro, they should be enclosed
+in brackets. The arguments are: \14ascii\v to force the viewer
+into ascii mode; \14hex\v to force the viewer into hex mode;
+\14nroff\v to tell the viewer that it should interpret the bold
+and underline sequences of nroff; \14unformated\v to tell the
+viewer to not interpret nroff commands for making the text
+bold or underlined.
+
+\14"%%"\v The % character
+
+\14"%{some text}"\v Prompt for the substitution. An input box
+is shown and the text inside the braces is used as a
+prompt. The macro is substituted by the text typed by the
+user. The user can press ESC or F10 to cancel. This macro
+doesn't work on the command line yet.
+
+\ 4[The subshell support]
+The subshell support
+
+The subshell support is a compile time option, that works
+with the shells: bash, tcsh and zsh.
+
+When the subshell code is activated the Midnight Commander
+will spawn a concurrent copy of your shell (the one
+defined in the \bSHELL\v variable and if it is not defined,
+then the one in the /etc/passwd file) and run it in a
+pseudo terminal, instead of invoking a new shell each time
+you execute a command, the command will be passed to the
+subshell as if you had typed it. This also allows you to
+change the environment variables, use shell functions and
+define aliases that are valid until you quit the Midnight
+Commander.
+
+If you are using \bbash\v you can specify startup commands for
+the subshell in your ~/.mc/bashrc file and special
+keyboard maps in the ~/.mc/inputrc file. \btcsh \v users may
+specify startup commands in the ~/.mc/tcshrc file.
+
+When the subshell code is used, you can suspend
+applications at any time with the sequence C-o and jump
+back to the Midnight Commander, if you interrupt an
+application, you will not be able to run other external
+commands until you quit the application you interrupted.
+
+An extra added feature of using the subshell is that the
+prompt displayed by the Midnight Commander is the same
+prompt that you are currently using in your shell.
+
+The OPTIONS section has more information on how you can
+control the subshell code.
+
+\ 4[Controlling Midnight Commander]
+Controlling Midnight Commander
+
+The Midnight Commander defines an environment variable
+MC_CONTROL_FILE. The commands executed by MC may give
+instructions to MC by writing to the file specified by
+this variable. This is only available if you compiled your
+copy of the Midnight Commander with the WANT_PARSE option.
+
+The following instructions are supported.
+
+clear_tags Clear all tags.
+tag <filename> Tag specified file.
+untag <filename> Untag specified file.
+select <filename> Move pointer to file.
+change_panel Switch between panels.
+cd <path> Change directory.
+
+If the first letter of the instruction is in lower case it
+operates on the current panel. If the letter is in upper
+case the instruction operates on the other panel. The
+additional letters must be in lower case. Instructions
+must be separated by exactly one space, tab or newline.
+The instructions don't work in the Info, Tree and Quick
+views. The first error causes the rest to be ignored.
+
+\ 4[Chmod]
+Chmod
+
+The Chmod window is used to change the attribute bits in a
+group of files and directories. It can be invoked with the
+C-x c key combination.
+
+The Chmod window has two parts - \14Permissions\v and \14File\v
+
+In the File section are displayed the name of the file or
+directory and its permissions in octal form, as well as
+its owner and group.
+
+In the Permissions section there is a set of check buttons
+which correspond to the file attribute bits. As you change
+the attribute bits, you can see the octal value change in
+the File section.
+
+To move between the widgets (buttons and check buttons)
+use the \14arrow keys\v or the \14Tab\v key. To change the state of
+the check buttons or to select a button use \14Space.\v You can
+also use the hotkeys on the buttons to quickly activate
+that selection (they are the highlit letters on the
+buttons).
+
+To set the attribute bits, use the Enter key.
+
+When working with a group of files or directories, you
+just click on the bits you want to set or clear. Once you
+have selected the bits you want to change, you select one
+of the action buttons (Set marked or Clear marked).
+
+Finally, to set the attributes exactly to those specified,
+you can use the \b[Set all]\v button, which will act on all
+the tagged files.
+
+\b[Marked all]\v set only marked attributes to all selected
+files
+
+\b[Set marked]\v set marked bits in attributes of all selected
+files
+
+\b[Clean marked]\v clear marked bits in attributes of all
+selected files
+
+\b[Set]\v set the attributes of one file
+
+\b[Cancel]\v cancel the Chmod command
+
+\ 4[Chown]
+Chown
+
+The Chown command is used to change the owner/group of a
+file. The hot key for this command is C-x o.
+
+\ 4[File Operations]
+File Operations
+
+When you copy, move or delete files the Midnight Commander
+shows the file operations dialog. It shows the files
+currently being operated on and there are at most three
+progress bars. The file bar tells how big part of the
+current file has been copied so far. The count bar tells
+how many of tagged files have been handled so far. The
+bytes bar tells how big part of total size of the tagged
+files has been handled so far. If the verbose option is
+off the file and bytes bars are not shown.
+
+There are two buttons at the bottom of the dialog.
+Pressing the Skip button will skip the rest of the current
+file. Pressing the Abort button will abort the whole
+operation, the rest of the files are skipped.
+
+There are three other dialogs which you can run into
+during the file operations.
+
+The error dialog informs about error conditions and has
+three choices. Normally you select either the Skip button
+to skip the file or the Abort button to abort the
+operation altogether. You can also select the Retry button
+if you fixed the problem from another terminal.
+
+The replace dialog is shown when you attempt to copy or
+move a file on the top of an existing file. The dialog
+shows the dates and sizes of the both files. Press the Yes
+button to overwrite the file, the No button to skip the
+file, the alL button to overwrite all the files, the nonE
+button to never overwrite and the Update button to
+overwrite if the source file is newer than the target
+file. You can abort the whole operation by pressing the
+Abort button.
+
+The recursive delete dialog is shown when you try to
+delete a directory which is not empty. Press the Yes
+button to delete the directory recursively, the No button
+to skip the directory, the alL button to delete all the
+directories and the nonE button to skip all the non-empty
+directories. You can abort the whole operation by pressing
+the Abort button. If you selected the Yes or alL button
+you will be asked for a confirmation. Type "yes" only if
+you are really sure you want to do the recursive delete.
+
+If you have tagged files and perform an operation on them
+only the files on which the operation succeeded are
+untagged. Failed and skipped files are left tagged.
+
+\ 4[Mask Copy/Rename]
+Mask Copy/Rename
+
+The copy/move operations lets you translate the names of
+files in an easy way. To do it, you have to specify the
+correct source mask and usually in the trailing part of
+the destination specify some wildcards. All the files
+matching the source mask are copied/renamed according to
+the target mask. If there are tagged files, only the
+tagged files matching the source mask are renamed.
+
+There are other option which you can set:
+
+Follow links tells whether make the symlinks and hardlinks
+in the source directory (recursively in subdirectories)
+new links in the target directory or whether would you
+like to copy their content.
+
+Dive into subdirs tells what to do if in the target
+directory exists a directory with the same name as the
+file/directory being copied. The default action is to copy
+it's content into that directory, by enabling this you can
+copy the source directory into that directory. Perhaps an
+example will help:
+
+You want to copy content of a directory foo to /bla/foo,
+which is an already existing directory. Normally (when
+Dive is not set), mc would copy it exactly into /bla/foo.
+By enabling this option you will copy the content into
+/bla/foo/foo, because the directory already exists.
+
+Preserve attributes tells whether to preserve the original
+files' permissions, timestamps and if you are root whether
+to preserve the original files' UID and GID. If this
+option is not set the current value of the umask will be
+respected.
+
+\b"Use shell patterns on"\v
+
+When the shell patterns option is on you can use the '*'
+and '?' wildcards in the source mask. They work like they
+do in the shell. In the target mask only the '*' and
+'\<digit>' wildcards are allowed. The first '*' wildcard
+in the target mask corresponds to the first wildcard group
+in the source mask, the second '*' corresponds to the
+second group and so on. The '\1' wildcard corresponds to
+the first wildcard group in the source mask, the '\2'
+wildcard corresponds to the second group and so on all the
+way up to '\9'. The '\0' wildcard is the whole filename of
+the source file.
+
+Two examples:
+
+If the source mask is "*.tar.gz", the destination is
+"/bla/*.tgz" and the file to be copied is "foo.tar.gz",
+the copy will be "foo.tgz" in "/bla".
+
+Let's suppose you want to swap basename and extension so
+that "file.c" will become "c.file" and so on. The source
+mask for this is "*.*" and the destination is "\2.\1".
+
+\b"Use shell patterns off"\v
+
+When the shell patterns option is off the MC doesn't do
+automatic grouping anymore. You must use '\(...\)'
+expressions in the source mask to specify meaning for the
+wildcards in the target mask. This is more flexible but
+also requires more typing. Otherwise target masks are
+similar to the situation when the shell patterns option is
+on.
+
+Two examples:
+
+If the source mask is "^\(.*\)\.tar\.gz$", the destination
+is "/bla/*.tgz" and the file to be copied is "foo.tar.gz",
+the copy will be "/bla/foo.tgz".
+
+Let's suppose you want to swap basename and extension so
+that "file.c" will become "c.file" and so on. The source
+mask for this is "^\(.*\)\.\(.*\)$" and the destination is
+"\2.\1".
+
+\b"Case Conversions"\v
+
+You can also change the case of the filenames. If you use
+'\u' or '\l' in the target mask the next character will be
+converted to uppercase or lowercase correspondingly.
+
+If you use '\U' or '\L' in the target mask the next
+characters will be converted to uppercase or lowercase
+correspondingly up to the next '\E' or next '\U', '\L' or
+the end of the file name.
+
+The '\u' and '\l' are stronger than '\U' and '\L'.
+
+For example, if the source mask is '*' (shell patterns on)
+or '^\(.*\)$' (shell patterns off) and the target mask is
+'\L\u*' the file names will be converted to have initial
+upper case and otherwise lower case.
+
+You can also use '\' as a quote character. For example,
+'\\' is a backslash and '\*' is an asterisk.
+
+\ 4[Internal File Viewer]
+Internal File Viewer
+
+The internal file viewer provides two display modes: ASCII
+and hex. To toggle between modes, use the F4 key. If you
+have the GNU gzip program installed, it will be used to
+automatically decompress the files on demand.
+
+The viewer will try to use the best method provided by
+your system or the file type to display the information.
+The internal file viewer will interpret some string
+sequences to set the bold and underline attributes, thus
+making a pretty display of your files.
+
+When in hex mode, the search function accepts text in
+quotes as well as hexadecimal constants.
+
+You can mix quoted text with constants like this: "String"
+0xFE 0xBB "more text". Text between constants and quoted
+text is just ignored.
+
+Some internal details about the viewer: On systems that
+provide the mmap(2) system call, the program maps the file
+instead of loading it; if the system does not provide the
+mmap(2) system call or the file matches an action that
+requires a filter, then the viewer will use it's growing
+buffers, thus loading only those parts of the file that
+you actually access (this includes compressed files).
+
+Here is a listing of the actions associated with each key
+that the Midnight Commander handles in the internal file
+viewer.
+
+\bF1\v Invoke the builtin hypertext help viewer.
+
+\bF2\v Toggle the wrap mode.
+
+\bF4\v Toggle the hex mode.
+
+\bF5\v Goto line. This will prompt you for a line number and
+will display that line.
+
+\bF6, /. \v Regular expression search.
+
+\b?,\v Reverse regular expression search.
+
+\bF7\v Normal search / hex mode search.
+
+\bC-s.\v Start normal search if there was no previous search
+expression else find next match.
+
+\bC-r.\v Start reverse search if there was no previous search
+expression else find next match.
+
+\bn.\v Find next match.
+
+\bF8\v Toggle Raw/Parsed mode: This will show the file as
+found on disk or if a processing filter has been specified
+in the mc.ext file, then the output from the filter.
+Current mode is always the other than written on the
+button label, since on the button is the mode which you
+enter by that key.
+
+\bF9\v Toggle the format/unformat mode: when format mode is on
+the viewer will interpret some string sequences to show
+bold and underline with different colors. Also, on button
+label is the other mode than current.
+
+\bF10, Esc.\v Exit the internal file viewer.
+
+\bnext-page, space, C-v.\v Scroll one page forward.
+
+\bprev-page, M-v, C-b, backspace.\v Scroll one page backward.
+
+\bdown-key\v Scroll one line forward.
+
+\bup-key\v Scroll one line backward.
+
+\bC-l\v Refresh the screen.
+
+\b!\v Spawn a shell in the currently working directory.
+
+\b"[n] m"\v Set the mark n.
+
+\b"[n] r"\v Jump to the mark n.
+
+\bC-f\v Jump to the next file.
+
+\bC-b \v Jump to the previous file.
+
+\bM-r \v Toggle the ruler.
+
+It's possible to instruct the file viewer how to display a
+file, look at the \ 1Extension File Edit section\ 2Extension File Edit\ 3\ 4[Internal File Editor]
+Internal File Editor
+
+The internal file editor provides most of the features of
+common full screen editors. It is invoked using \bF4\v
+provided the \14use_internal_edit\v option is set in the
+initialization file. It has an extensible file size limit
+of sixteen megabytes and edits binary files flawlessly.
+
+The features it presently supports are: Block copy, move,
+delete, cut, paste; \14"key for key undo"; \v pull-down menus;
+file insertion; macro definition; regular expression
+search and replace (and our own scanf-printf search and
+replace); shift-arrow MSW-MAC text highlighting (for the
+linux console only); insert-overwrite toggle; and an
+option to pipe text blocks through shell commands like
+indent.
+
+The editor is very easy to use and requires no tutoring.
+To see what keys do what, just consult the appropriate
+pull-down menu. Other keys are: Shift movement keys do
+text highlighting. \bCtrl-Ins\v copies to the file
+\bcooledit.clip and \v \bShift-Ins\v pastes from cooledit.clip.
+\bShift-Del \v cuts to \bcooledit.clip, \v and \bCtrl-Del\v deletes
+highlighted text. The completion key also does a Return
+with an automatic indent. Mouse highlighting also works,
+and you can override the mouse as usual by holding down
+the shift key while dragging the mouse to let normal
+terminal mouse highlighting work.
+
+To define a macro, press \bCtrl-R\v and then type out the key
+strokes you want to be executed. Press \bCtrl-R\v again when
+finished. You can then assign the macro to any key you
+like by pressing that key. The macro is executed when you
+press \bCtrl-A and then the assigned key. The macro is also
+executed if\v you press Meta, Ctrl, or Esc and the assigned
+key, provided that the key is not used for any other
+function. Once defined, the macro commands go into the
+file \bcedit/cooledit.macros\v in your home directory. You can
+delete a macro by deleting the appropriate line in this
+file.
+
+\bF19 will format C code when it is highlighted. For this\v to
+work, make an executable file called \bcedit/edit.indent.rc\v
+in your home directory containing the following:
+
+#!/bin/sh
+/usr/bin/indent -kr -pcs ~/cedit/cooledit.block >& /dev/null
+cat /dev/null > ~/cedit/cooledit.error
+
+You can use scanf search and replace to search and replace
+a C format string. First take a look at the \bsscanf\v and
+\bsprintf man pages to see what a format string\v is and how
+it works. An example is as follows: Suppose you want to
+replace all occurences of say, an open bracket, three
+comma seperated numbers, and a close bracket, with the
+word \14apples, \v the third number, the word \14oranges\v and then
+the second number, I would fill in the Replace dialog box
+as follows:
+
+ Enter search string
+(%d,%d,%d)
+ Enter replace string
+apples %d oranges %d
+ Enter replacement argument order
+3,2
+
+The last line specifies that the third and then the second
+number are to be used in place of the first and second.
+
+It is advisable to use this feature with Prompt on replace
+on, because a match is thought to be found whenever the
+number of arguments found matches the number given, which
+is not always a real match. Scanf also treats whitespace
+as being elastic. Note that the scanf format % is very
+useful for scanning strings, and whitespace.
+
+The editor also displays non-us characters (160+). When
+editing binary files, you should set \bdisplay bits\v to 7
+bits in the options menu to keep the spacing clean.
+
+See also the file \bREADME.edit\v in the source tree for some
+more info.
+
+\ 4[Completion]
+Completion
+
+
+Let the Midnight Commander type for you.
+
+Attempt to perform completion on the text before current
+position. MC attempts completion treating the text as
+variable (if the text begins with \b$\v ), username (if the
+text begins with \b~\v ), hostname (if the text begins with \b@\v
+) or command (if you are on the command line in the
+position where you might type a command, possible
+completions then include shell reserved words and shell
+builtin commands as well) in turn. If none of these
+produces a match, filename completion is attempted.
+
+Filename, username, variable and hostname completion works
+on all input lines, command completion is command line
+specific. If the completion is ambiguous (there are more
+different possibilities), MC beeps and the following
+action depends on the setting of the \ 1show_all_if_ambiguous\ 2Special
+Settings\ 3variable in the Initialization file. If it is nonzero, a
+list of all possibilities pops up next to the current
+position and you can select with the arrow keys and \bEnter\v
+the correct entry. You can also type the first letters in
+which the possibilities differ to move to a subset of all
+possibilities and complete as much as possible. If you
+press \bM-Tab\v again, only the subset will be shown in the
+listbox, otherwise the first item which matches all the
+previous characters will be highlighted. As soon as there
+is no ambiguity, dialog disappears, but you can hide it by
+canceling keys \bEsc,\v \bF10\v and left and right arrow keys. If
+\ 1show_all_if_ambiguous\ 2Special Settings\ 3 is set to zero, the dialog pops up
+only if you press \bM-Tab\v for the second time, for the first
+time MC just beeps.
+
+\ 4[Virtual File System]
+Virtual File System
+
+The Midnight Commander is provided with a code layer to
+access the file system; this code layer is known as the
+virtual file system switch. The virtual file system switch
+allows the Midnight Commander to manipulate files not
+located on the Unix file system.
+
+Currently the Midnight Commander is packaged with five
+Virtual File Systems (VFS): the local file system, used
+for accessing the regular Unix file system; the ftpfs,
+used to manipulate files on remote systems with the FTP
+protocol; the tarfs, used to manipulate tar and compressed
+tar files; the undelfs, used to recover deleted files on
+ext2 file systems (the default file system for Linux
+systems) and finally the mcfs (Midnight Commander file
+system), a network based file system.
+
+The VFS switch code will interpret all of the path names
+used and will forward them to the correct file system, the
+formats used for each one of the file systems is described
+later in their own section.
+
+\ 4[FTP File System]
+FTP File System
+
+The ftpfs allows you to manipulate files on remote
+machines, to actually use it, you may try to use the panel
+command FTP link (accessible from the menubar) or you may
+directly change your current directory to it using the cd
+command to a path name that looks like this:
+
+\14ftp://[!][user[:pass]@]machine[:port][remote-dir]\v
+
+The, \14user, port\v and \14remote-dir\v elements are optional. If
+you specify the \14user\v element, then the Midnight Commander
+will try to logon on the remote machine as that user,
+otherwise it will use your login name. The optional \14pass\v
+element, if present is the password used for the
+connection. This use is not recomented (nor keeping this
+in your hotlist, unless you set the appropiate permissions
+there, and then, it may not be entirely safe anyways).
+
+Examples:
+
+ ftp://ftp.nuclecu.unam.mx/linux/local
+ ftp://tsx-11.mit.edu/pub/linux/packages
+ ftp://!behind.firewall.edu/pub
+ ftp://guest@remote-host.com:40/pub
+ ftp://miguel:xxx@server/pub
+
+To connect to sites behind a firewall, you will need to
+use the prefix ftp://! (ie, with a bang character after
+the double slash) to make the Midnight Commander use a
+proxy host for doing the ftp transfer. You can define the
+proxy host in the \ 1Virtual File System\ 2Virtual FS\ 3 dialog box.
+
+Another option is to set the \14ftpfs_always_use_proxy\v
+parameter in the initialization file. This will configure
+the program to always use the proxy host. If this variable
+is set, the program will do two things: consult the
+@prefix@/lib/mc.no_proxy file for lines containing host
+names that are local (if the host name starts with a dot,
+it is assumed to be a domain) and to assume that any
+hostnames without dots in their names are directly
+accessible.
+
+If you are using the ftpfs code with a filtering packet
+router that does not allow you to use the regular mode of
+opening files, you may want to force the program to use
+the passive-open mode. To use this, set the
+ftpfs_use_passive_connections option.
+
+The Midnight Commander keeps the directory listing in a
+cache. The cache expire time is configurable in the
+\ 1Virtual File System \ 2Virtual FS\ 3 dialog box. This has the funny
+behavior that even if you make changes to a directory,
+they will not be reflected in the directory listing until
+you force a cache reload with the C-r key. This is a
+feature (when you think it's a bug, think about
+manipulating files on the other side of the Atlantic with
+ftpfs).
+
+\ 4[Tar File System]
+Tar File System
+
+The tar file system provides you with read-only access to
+your tar files and compressed tar files by using the chdir
+command. To change your directory to a tar file, you
+change your current directory to the tar file by using the
+following syntax:
+
+\14tar:filename.tar[dir-inside-tar]\v
+
+The mc.ext file already provides a shortcut for tar files,
+this means that usually you just point to a tar file and
+press return to enter into the tar file, see the \ 1Extension
+File Edit \ 2Extension File Edit\ 3 section for details on how this is done.
+
+Examples:
+
+ tar:mc-3.0.tar.gz/mc-3.0/vfs
+ tar:/ftp/GCC/gcc-2.7.0.tar
+
+The latter specifies the full path of the tar archive.
+
+\ 4[Network File System]
+Network File System
+
+The Midnight Commander file system is a network base file
+system that allows you to manipulate the files in a remote
+machine as if they were local. To use this, the remote
+machine must be running the mcserv(8) server program.
+
+To connect to a remote machine, you just need to chdir
+into a special directory which name is in the following
+format:
+
+\14mc:[user@]machine[:port][remote-dir]\v
+
+The, \14user, port\v and \14remote-dir\v elements are optional. If
+you specify the \14user\v element then the Midnight Commander
+will try to logon on the remote machine as that user,
+otherwise it will use your login name.
+
+The \14port\v element is used when the remote machine running
+on a special port (see the mcserv(8) manual page for more
+information about ports); finally, if the \14remote-dir\v
+element is present, your current directory on the remote
+machine will be set to this one.
+
+Examples:
+
+ mc:ftp.nuclecu.unam.mx/linux/local
+ mc:joe@foo.edu:11321/private
+
+\ 4[Undelete File System]
+Undelete File System
+
+On Linux systems, if you asked configure to use the ext2fs
+undelete facilities, you will have the undelete file
+system available. Recovery of deleted files is only
+available on ext2 file systems. The undelete file system
+is just an interface to the ext2fs library to: retrieve
+all of the deleted files names on an ext2fs and provides
+and to extract the selected files into a regular
+partition.
+
+To use this file system, you have to chdir into the
+special file name formed by the "undel:" prefix and the
+file name where the actual file system resides.
+
+For example, to recover deleted files on the second
+partition of the first scsi disk on Linux, you would use
+the following path name:
+
+ undel:/dev/sda2
+
+It may take a while for the undelfs to load the required
+information before you start browsing files there.
+
+\ 4[Colors]
+Colors
+
+The Midnight Commander will try to detect if your terminal
+supports color using the terminal database and your
+terminal name. Sometimes it gets confused, so you may
+force color mode or disable color mode using the -c and -b
+flag respectively.
+
+If the program is compiled with the Slang screen manager
+instead of ncurses, it will also check the variable
+\bCOLORTERM,\v if it is set, it has the same effect as the -c
+flag.
+
+You may specify terminals that always force color mode by
+adding the \14color_terminals\v variable to the Colors section
+of the initialization file. This will prevent the Midnight
+Commander from trying to detect if your terminal supports
+color. Example:
+[Colors]
+color_terminals=linux,xterm
+color_terminals=terminal-name1,terminal-name2...
+
+The program can be compiled with both ncurses and slang,
+ncurses does not provide a way to force color mode:
+ncurses uses just the information in the terminal
+database.
+
+The Midnight Commander provides a way to change the
+default colors. Currently the colors are configured using
+the environment variable \bMC_COLOR_TABLE \v or the Colors
+section in the initialization file.
+
+In the Colors section, the default color map is loaded
+from the \14base_color \v variable. You can specify an
+alternate color map for a terminal by using the terminal
+name as the key in this section. Example:
+
+[Colors]
+base_color=
+xterm=menu=magenta:marked=,magenta:markselect=,red
+
+The format for the color definition is:
+
+ <keyword>=<foregroundcolor>,<backgroundcolor>:<keyword>= ...
+
+The colors are optional, and the keywords are: normal,
+selected, marked, markselect, errors, input, reverse menu,
+menusel, menuhot, menuhotsel, gauge; the dialog colors
+are: dnormal, dfocus, dhotnormal, dhotfocus; Help colors
+are: helpnormal, helpitalic, helpbold, helplink,
+helpslink; Viewer color is: viewunderline; Special
+highlighting mode: executable, directory, link, device,
+special.
+
+The dialog boxes use the following colors: \14dnormal \v is
+used for the normal text, \14dfocus\v is the color used for the
+currently selected component, \14dhotnormal\v is the color used
+to differentiate the hotkey color in normal components,
+whereas the \14dhotfocus\v color is used for the highlighted
+color in the currently selected component.
+
+Menus use the same scheme but uses the menu, menusel,
+menuhot and menuhotsel tags instead.
+
+Help uses the following colors: \14helpnormal\v is used for
+normal text, \14helpitalic\v is used for text which is
+emphasized in italic in the manual page, \14helpbold\v is used
+for text which is emphasized in bold in the manual page,
+\14helplink\v is used for not selected hyperlinks and \14helpslink\v
+is used for selected hyperlink.
+
+\14gauge\v determines color of filled part of the progress bar
+(gauge), which shows how many percent of files were copied
+etc. in a graphical way.
+
+For file type highlighting mode \14directory\v specifies the
+color in which directories are shown; \14executable\v for
+executable files; \14link \v is used to represent links; \14device
+\vfor character and block devices; \14special\v is for special
+files, such as FIFO and IPC sockets; \14core\v is for core
+files (see also the option \bhighlight_mode\v at the section
+on \ 1Special Settings).\ 2Special Settings\ 3
+
+The possible colors are: black, gray, red, brightred,
+green, brightgreen, brown, yellow, blue, brightblue,
+magenta, brightmagenta, cyan, brightcyan, lightgray and
+white.
+
+\ 4[Special Settings]
+Special Settings
+
+Most of the settings of the Midnight Commander can be
+changed from the menus. However, there are a small number
+of settings which can only be changed by editing the setup
+file.
+
+These variables may be set in your ~/.mc/ini file:
+
+\14clear_before_exec.\v By default the Midnight Commander
+clears the screen before executing a command. If you would
+prefer to see the output of the command at the bottom of
+the screen, edit your ~/mc.ini file and change the value
+of the field clear_before_exec to 0.
+
+\14confirm_view_dir.\v If you press F3 on a directory, normally
+MC enters that directory. If this flag is set to 1, then
+MC will ask for confirmation before changing the directory
+if you have files tagged.
+
+\14drop_menus.\v If this variable is set, when you press the F9
+key, the pull down menus will be activated, else, you will
+only be presented with the menu title, and you will have
+to select the entry with the arrow keys or the first
+letter and from there select your option in the menu.
+
+\14ftpfs_retry_seconds.\v This value is the number of seconds
+the Midnight Commander will wait before attempting a
+reconnection to an ftp server that has denied the login.
+If the value is zero, the the program will not retry the
+login.
+
+\14ftpfs_use_passive_connections.\v This option is by off
+default. This makes the ftpfs code use the passive open
+mode for transfering files. This is used by people that
+are behind a filtering packet router. This option just
+works if you are not using an ftp proxy.
+
+\14max_dirt_limit.\v Specifies how many screen updates can be
+skipped at most in the internal file viewer. Normally this
+value is not significant, because the code automatically
+adjusts the number of updates to skip according to the
+rate of incoming keypresses. However, on very slow
+machines or terminals with a fast keyboard auto repeat, a
+big value can make screen updates too jumpy. It seems that
+setting max_dirt_limit to 10 causes the best behavior, and
+that is the default value.
+
+\14mouse_move_pages.\v Controls whenever scrolling with the
+mouse is done by pages or line by line on the panels.
+
+\14mouse_move_pages_viewer.\v Controls if scrolling with the
+mouse is done by pages or line by line on the internal
+file viewer.
+
+\14navigate_with_arrows.\v If this setting is turned on, then
+you may use the arrows keys to automatically chdir if the
+current selection is a subdirectory and the shell command
+line is empty. By default, this setting is off.
+
+\14nice_rotating_dash\v When on, this flag causes the commander
+to show a rotating dash as a work in progress indicator.
+
+\14old_esc_mode\v By default the Midnight Commander treats the
+ESC key as a key prefix (old_esc_mode=0), if you set this
+option (old_esc_mode=1), then the ESC key will act as a
+prefix key for one second, and if no extra keys have
+arrived, then the ESC key is interpreted as a cancel key
+(ESC ESC).
+
+
+\14only_leading_plus_minus\v set special treatment for '+',
+'-', '*' in command line (select, unselect, reverse
+selection) only if command line is empty. No need to quote
+this characters in the middle of the command line. But we
+can not change selection when command line is not empty.
+\14panel_scroll_pages\v If set (the default), panel will scroll
+by half the display when the cursor reaches the end or the
+beginning of the panel, otherwise it will just scroll a
+file at a time.
+
+\14preserve_uidgid\v If this option is set (the default), when
+logged in as root the default will be to preserve the UID
+and the GID of files. Some users prefer to disable this
+option, so that's why it's configurable.
+
+\14show_output_starts_shell\v This variable only works if you
+are not using the subshell support. When you use the C-o
+keystroke to go back to the user screen, if this one is
+set, you will get a fresh shell. Otherwise, pressing any
+key will bring you back to the Midnight Commander.
+
+\14show_all_if_ambiguous.\v By default the Midnight Commander
+pops up all possible \ 1completions\ 2Completion\ 3 if the completion is
+ambiguous if you press \bM-Tab\v for the second time, for the
+first time it just completes as much as possible and in
+the case of ambiguity beeps. If you want to see all the
+possible completions already after the first \bM-Tab\v
+pressing, set this option to 1.
+
+\14torben_fj_mode\v If this flag is set, then the home and end
+keys will work slightly different on the panels, instead
+of moving the selection to the first and last files in the
+panels, they will act as follows: The home key will: Go up
+to the middle line, if below it; else go to the top line
+unless it is already on the top line, in this case it will
+go to the first file in the panel. The end key has a
+similar behavior: Go down to the middle line, if over it;
+else go to the bottom line unless you already are at the
+bottom line, in such case it will move the selection to
+the last file name in the panel.
+
+\14highlight_mode \v By default all information on panels
+displayed with the same color. If this variable is set to
+1, then \14perm\v or \14mode\v tokens in display format get ability
+to show access rights of the user to the shown file.
+Appropriate triplet of reading, writing and execution
+rights highlighted with the yellow ( \14selected\v ) color. In
+addition, if the variable is equal to 2, then all lines
+are displaying by the color according to their type (see
+\ 1Colors).\ 2Colors\ 3 Permissions highlighting also works in this mode.
+
+\14use_file_to_guess_type\v If this variable is on (the
+default) it will spawn the file command to match the file
+types listed on the \ 1mc.ext file.\ 2Extension File Edit\ 3
+
+\14xterm_mode\v If this variable is on (default is off) when
+you browse the file system on a Tree panel, it will
+automatically reload the other panel with the contents of
+the selected directory.
+
+\ 4[Terminal databases]
+Terminal databases
+
+The Midnight Commander provides a way to fix your system
+terminal database without requiring root privileges. The
+Midnight Commander searches in the system initialization
+file (the mc.lib file located in the Midnight Commander
+library directory) or in the ~/.mc/ini file for the
+section "terminal:your-terminal-name" and then for the
+section "terminal:general", each line of the section
+contains a key symbol that you want to define, followed by
+an equal sign and the definition for the key. You can use
+the special \E form to represent the escape character and
+the ^x to represent the control-x character.
+
+The possible key symbols are:
+
+f0 to f20 Function keys f0-f20
+bs backspace
+home home key
+end end key
+up up arrow key
+down down arrow key
+left left arrow key
+right right arrow key
+pgdn page down key
+pgup page up key
+insert the insert character
+delete the delete character
+complete to do completion
+
+For example, to define the key insert to be the Escape + [
++ O + p, you set this in the ini file:
+
+insert=\\E[Op
+
+The \14complete\v key symbol represents the escape sequences
+used to invoke the completion process, this is invoked
+with M-tab, but you can define other keys to do the same
+work (on those keyboard with tons of nice and unused keys
+everywhere).
+
+\ 4[]
+
+
+\ 4[FILES]
+FILES
+
+@prefix@/lib/mc.hlp The help file for the program.
+
+@prefix@/lib/mc/mc.ext The default system-wide extensions
+file.
+
+~/.mc/ext User's own extension, view configuration and
+edit configuration file. They override the contents of the
+system wide files if present.
+
+@prefix@/lib/mc/mc.ini The default system-wide setup for
+the Midnight Commander, used only if the user lacks his
+own ~/.mc/ini file.
+
+@prefix@/lib/mc/mc.lib Global settings for the Midnight
+Commander. Settings in this file are global to any
+Midnight Commander, it is useful to define site-global
+terminal settings.
+
+~/.mc/ini User's own setup. If this file is present then
+the setup is loaded from here instead of the system-wide
+startup file.
+
+@prefix@/lib/mc/mc.hint This file contains the hints
+(cookies) displayed by the program.
+
+@prefix@/lib/mc/mc.menu This file contains the default
+system-wide applications menu.
+
+~/.mc/menu User's own application menu. If this file is
+present it is used instead of the system-wide applications
+menu.
+
+~/.mc/tree The directory list for the directory tree and
+tree view features. Each line is one entry. The lines
+starting with a slash are full directory names. The lines
+starting with a number have that many characters equal to
+the previous directory. If you want you may create this
+file by giving the command "find / -type d -print | sort >
+~/.mc.tree". Normally there is no sense in doing it
+because the Midnight Commander automatically updates this
+file for you.
+
+Local user-defined menu. If this file is present it is
+used instead of the home or system-wide applications menu.
+
+\ 4[AVAILABILITY]
+AVAILABILITY
+
+The latest version of this program can be found at
+ftp.nuclecu.unam.mx in the directory /linux/local and from
+Europe at sunsite.mff.cuni.cz in the directory /GNU/mc and
+at ftp.teuto.de in the directory /lmb/mc.\ 4[SEE ALSO]
+SEE ALSO
+
+ed(1), gpm(1), mcserv(8), terminfo(1), view(1), sh(1),
+bash(1), tcsh(1), zsh(1).
+
+The Midnight Commander page on the World Wide Web:
+ http://mc.blackdown.org/mc
+
+\ 4[AUTHORS]
+AUTHORS
+
+Miguel de Icaza (miguel@roxanne.nuclecu.unam.mx), Janne
+Kukonlehto (jtklehto@paju.oulu.fi), Radek Doulik
+(rodo@earn.cvut.cz), Fred Leeflang (fredl@nebula.ow.org),
+Dugan Porter (dugan@b011.eunet.es), Jakub Jelinek
+(jj@sunsite.mff.cuni.cz), Ching Hui
+(mr854307@cs.nthu.edu.tw), Andrej Borsenkow
+(borsenkow.msk@sni.de), Norbert Warmuth
+(nwarmuth@privat.circular.de), Mauricio Plaza
+(mok@roxanne.nuclecu.unam.mx) and Paul Sheer
+(psheer@icon.co.za) are the developers of this package;
+Alessandro Rubini (rubini@ipvvis.unipv.it) has been
+especially helpful debugging and enhancing the program's
+mouse support, John Davis (davis@space.mit.edu) also made
+his S-Lang library available to us under the GPL and
+answered my questions about it, and the following people
+have contributed code and many bug fixes (in alphabetical
+order):
+
+Adam Tla/lka (atlka@sunrise.pg.gda.pl), alex@bcs.zp.ua
+(Alex I. Tkachenko), Antonio Palama, DOS port
+(palama@posso.dm.unipi.it), Erwin van Eijk
+(wabbit@corner.iaf.nl), Gerd Knorr
+(kraxel@cs.tu-berlin.de), Jean-Daniel Luiset
+(luiset@cih.hcuge.ch), Jon Stevens
+(root@dolphin.csudh.edu), Juan Francisco Grigera, Win32
+port (j-grigera@usa.net), Juan Jose Ciarlante
+(jjciarla@raiz.uncu.edu.ar), Ilya Rybkin
+(rybkin@rouge.phys.lsu.edu), Marcelo Roccasalva
+(mfroccas@raiz.uncu.edu.ar), Massimo Fontanelli
+(MC8737@mclink.it), Pavel Roskin
+(pavel.roskin@ecsoft.co.uk), Sergey Ya. Korshunoff
+(root@seyko.msk.su), Thomas Pundt
+(pundtt@math.uni-muenster.de), Timur Bakeyev
+(timur@goff.comtat.kazan.su), Tomasz Cholewo
+(tjchol01@mecca.spd.louisville.edu), Torben Fjerdingstad
+(torben.fjerdingstad@uni-c.dk), Vadim Sinolitis
+(vvs@nsrd.npi.msu.su) and Wim Osterholt
+(wim@djo.wtm.tudelft.nl).
+
+\ 4[BUGS]
+BUGS
+
+See the file TODO in the distribution for information on
+what remains to be done.
+
+If you want to report a problem with the program, please
+send mail to this address:
+mc-bugs@roxanne.nuclecu.unam.mx.
+
+Provide a detailed description of the bug, the version of
+the program you are running (mc -V display this
+information), the operating system you are running the
+program on and if the program crashes, we would appreciate
+a stack trace.
+
+\ 4[main]
+\ e \ 5lqwqk k k \ 6
+ \ 5x x x . x . x \ 6
+ \ 5x x x k lqu wqk k lqw tqk n \ 6
+ \ 5x x x x x x x x x x x x x x \ 6
+ \ 5v v v mqv v v v mqu v v mj\ 6
+ \ 5qqqqqq\ 6\bCommander\v\ 5qj\ 6 \a
+\ f\10\f
+
+Version \a
+
+\11This is the main help screen for the \bGNU Midnight Commander\v.
+
+To learn more on how to use the interactive help facility
+just tap \ 1enter\ 2How to use help\ 3. You may like to go directly to the
+help \ 1contents\ 2Contents\ 3.
+
+The Midnight Commander is written by its \ 1authors\ 2AUTHORS\ 3.
+
+The Midnight Commander comes with ABSOLUTELY NO \ 1WARRANTY\ 2Warranty\ 3.
+This is free software, and you are welcome to redistribute
+it under certain \ 1conditions\ 2License\ 3.\ 4[License]
+
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation,
+Inc. 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ Everyone is permitted to copy and distribute verbatim
+copies of this license document, but changing it is not
+allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away
+your freedom to share and change it. By contrast, the GNU
+General Public License is intended to guarantee your
+freedom to share and change free software--to make sure
+the software is free for all its users. This General
+Public License applies to most of the Free Software
+Foundation's software and to any other program whose
+authors commit to using it. (Some other Free Software
+Foundation software is covered by the GNU Library General
+Public License instead.) You can apply it to your
+programs, too.
+
+ When we speak of free software, we are referring to
+freedom, not price. Our General Public Licenses are
+designed to make sure that you have the freedom to
+distribute copies of free software (and charge for this
+service if you wish), that you receive source code or can
+get it if you want it, that you can change the software or
+use pieces of it in new free programs; and that you know
+you can do these things.
+
+ To protect your rights, we need to make restrictions
+that forbid anyone to deny you these rights or to ask you
+to surrender the rights. These restrictions translate to
+certain responsibilities for you if you distribute copies
+of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program,
+whether gratis or for a fee, you must give the recipients
+all the rights that you have. You must make sure that
+they, too, receive or can get the source code. And you
+must show them these terms so they know their rights.
+
+ We protect your rights with two steps: (1) copyright the
+software, and (2) offer you this license which gives you
+legal permission to copy, distribute and/or modify the
+software.
+
+ Also, for each author's protection and ours, we want to
+make certain that everyone understands that there is no
+warranty for this free software. If the software is
+modified by someone else and passed on, we want its
+recipients to know that what they have is not the
+original, so that any problems introduced by others will
+not reflect on the original authors' reputations.
+
+ Finally, any free program is threatened constantly by
+software patents. We wish to avoid the danger that
+redistributors of a free program will individually obtain
+patent licenses, in effect making the program proprietary.
+To prevent this, we have made it clear that any patent
+must be licensed for everyone's free use or not licensed
+at all.
+
+ The precise terms and conditions for copying,
+distribution and modification follow.
+\f
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING,
+ DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work
+which contains a notice placed by the copyright holder
+saying it may be distributed under the terms of this
+General Public License. The "Program", below, refers to
+any such program or work, and a "work based on the
+Program" means either the Program or any derivative work
+under copyright law: that is to say, a work containing the
+Program or a portion of it, either verbatim or with
+modifications and/or translated into another language.
+(Hereinafter, translation is included without limitation
+in the term "modification".) Each licensee is addressed
+as "you".
+
+Activities other than copying, distribution and
+modification are not covered by this License; they are
+outside its scope. The act of running the Program is not
+restricted, and the output from the Program is covered
+only if its contents constitute a work based on the
+Program (independent of having been made by running the
+Program). Whether that is true depends on what the
+Program does.
+
+ 1. You may copy and distribute verbatim copies of the
+Program's source code as you receive it, in any medium,
+provided that you conspicuously and appropriately publish
+on each copy an appropriate copyright notice and
+disclaimer of warranty; keep intact all the notices that
+refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of
+this License along with the Program.
+
+You may charge a fee for the physical act of transferring
+a copy, and you may at your option offer warranty
+protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or
+any portion of it, thus forming a work based on the
+Program, and copy and distribute such modifications or
+work under the terms of Section 1 above, provided that you
+also meet all of these conditions:
+
+ a) You must cause the modified files to carry
+prominent notices stating that you changed the files and
+the date of any change.
+
+ b) You must cause any work that you distribute or
+publish, that in whole or in part contains or is derived
+from the Program or any part thereof, to be licensed as a
+whole at no charge to all third parties under the terms of
+this License.
+
+ c) If the modified program normally reads commands
+interactively when run, you must cause it, when started
+running for such interactive use in the most ordinary way,
+to print or display an announcement including an
+appropriate copyright notice and a notice that there is no
+warranty (or else, saying that you provide a warranty) and
+that users may redistribute the program under these
+conditions, and telling the user how to view a copy of
+this License. (Exception: if the Program itself is
+interactive but does not normally print such an
+announcement, your work based on the Program is not
+required to print an announcement.)
+
+These requirements apply to the modified work as a whole.
+If identifiable sections of that work are not derived from
+the Program, and can be reasonably considered independent
+and separate works in themselves, then this License, and
+its terms, do not apply to those sections when you
+distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a
+work based on the Program, the distribution of the whole
+must be on the terms of this License, whose permissions
+for other licensees extend to the entire whole, and thus
+to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights
+or contest your rights to work written entirely by you;
+rather, the intent is to exercise the right to control the
+distribution of derivative or collective works based on
+the Program.
+
+In addition, mere aggregation of another work not based on
+the Program with the Program (or with a work based on the
+Program) on a volume of a storage or distribution medium
+does not bring the other work under the scope of this
+License.
+
+ 3. You may copy and distribute the Program (or a work
+based on it, under Section 2) in object code or executable
+form under the terms of Sections 1 and 2 above provided
+that you also do one of the following:
+
+ a) Accompany it with the complete corresponding
+machine-readable source code, which must be distributed
+under the terms of Sections 1 and 2 above on a medium
+customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at
+least three years, to give any third party, for a charge
+no more than your cost of physically performing source
+distribution, a complete machine-readable copy of the
+corresponding source code, to be distributed under the
+terms of Sections 1 and 2 above on a medium customarily
+used for software interchange; or,
+
+ c) Accompany it with the information you received as
+to the offer to distribute corresponding source code.
+(This alternative is allowed only for noncommercial
+distribution and only if you received the program in
+object code or executable form with such an offer, in
+accord with Subsection b above.)
+
+The source code for a work means the preferred form of the
+work for making modifications to it. For an executable
+work, complete source code means all the source code for
+all modules it contains, plus any associated interface
+definition files, plus the scripts used to control
+compilation and installation of the executable. However,
+as a special exception, the source code distributed need
+not include anything that is normally distributed (in
+either source or binary form) with the major components
+(compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself
+accompanies the executable.
+
+If distribution of executable or object code is made by
+offering access to copy from a designated place, then
+offering equivalent access to copy the source code from
+the same place counts as distribution of the source code,
+even though third parties are not compelled to copy the
+source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute
+the Program except as expressly provided under this
+License. Any attempt otherwise to copy, modify,
+sublicense or distribute the Program is void, and will
+automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from
+you under this License will not have their licenses
+terminated so long as such parties remain in full
+compliance.
+
+ 5. You are not required to accept this License, since
+you have not signed it. However, nothing else grants you
+permission to modify or distribute the Program or its
+derivative works. These actions are prohibited by law if
+you do not accept this License. Therefore, by modifying
+or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to
+do so, and all its terms and conditions for copying,
+distributing or modifying the Program or works based on
+it.
+
+ 6. Each time you redistribute the Program (or any work
+based on the Program), the recipient automatically
+receives a license from the original licensor to copy,
+distribute or modify the Program subject to these terms
+and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights
+granted herein. You are not responsible for enforcing
+compliance by third parties to this License.
+
+ 7. If, as a consequence of a court judgment or
+allegation of patent infringement or for any other reason
+(not limited to patent issues), conditions are imposed on
+you (whether by court order, agreement or otherwise) that
+contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you
+cannot distribute so as to satisfy simultaneously your
+obligations under this License and any other pertinent
+obligations, then as a consequence you may not distribute
+the Program at all. For example, if a patent license
+would not permit royalty-free redistribution of the
+Program by all those who receive copies directly or
+indirectly through you, then the only way you could
+satisfy both it and this License would be to refrain
+entirely from distribution of the Program.
+
+If any portion of this section is held invalid or
+unenforceable under any particular circumstance, the
+balance of the section is intended to apply and the
+section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to
+infringe any patents or other property right claims or to
+contest validity of any such claims; this section has the
+sole purpose of protecting the integrity of the free
+software distribution system, which is implemented by
+public license practices. Many people have made generous
+contributions to the wide range of software distributed
+through that system in reliance on consistent application
+of that system; it is up to the author/donor to decide if
+he or she is willing to distribute software through any
+other system and a licensee cannot impose that choice.
+
+This section is intended to make thoroughly clear what is
+believed to be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is
+restricted in certain countries either by patents or by
+copyrighted interfaces, the original copyright holder who
+places the Program under this License may add an explicit
+geographical distribution limitation excluding those
+countries, so that distribution is permitted only in or
+among countries not thus excluded. In such case, this
+License incorporates the limitation as if written in the
+body of this License.
+
+ 9. The Free Software Foundation may publish revised
+and/or new versions of the General Public License from
+time to time. Such new versions will be similar in spirit
+to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If
+the Program specifies a version number of this License
+which applies to it and "any later version", you have the
+option of following the terms and conditions either of
+that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a
+version number of this License, you may choose any version
+ever published by the Free Software Foundation.
+
+ 10. If you wish to incorporate parts of the Program into
+other free programs whose distribution conditions are
+different, write to the author to ask for permission. For
+software which is copyrighted by the Free Software
+Foundation, write to the Free Software Foundation; we
+sometimes make exceptions for this. Our decision will be
+guided by the two goals of preserving the free status of
+all derivatives of our free software and of promoting the
+sharing and reuse of software generally.
+
+[Warranty]
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE,
+THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT
+PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED
+IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND,
+EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED
+TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE
+QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.
+SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR
+AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY
+OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM
+AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY
+TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED
+BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO
+OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR
+OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of
+the greatest possible use to the public, the best way to
+achieve this is to make it free software which everyone
+can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program.
+It is safest to attach them to the start of each source
+file to most effectively convey the exclusion of warranty;
+and each file should have at least the "copyright" line
+and a pointer to where the full notice is found.
+
+<one line to give the program's name and a brief idea of
+what it does.>
+Copyright (C) 19yy <name of author>
+
+ 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 2 of the License, or (at your option) any
+later version.
+
+ This program is distributed in the hope that it will
+be useful, but WITHOUT ANY WARRANTY; without even the
+implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+ You should have received a copy of the GNU General
+Public License along with this program; if not, write to
+the Free Software Foundation, Inc., 675 Mass Ave,
+Cambridge, MA 02139, USA.
+
+Also add information on how to contact you by electronic
+and paper mail.
+
+If the program is interactive, make it output a short
+notice like this when it starts in an interactive mode:
+
+Gnomovision version 69, Copyright (C) 19yy name of author
+Gnomovision comes with ABSOLUTELY NO WARRANTY; for details
+type `show w'. This is free software, and you are welcome
+to redistribute it under certain conditions; type `show c'
+for details.
+
+The hypothetical commands `show w' and `show c' should
+show the appropriate parts of the General Public License.
+Of course, the commands you use may be called something
+other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a
+programmer) or your school, if any, to sign a "copyright
+disclaimer" for the program, if necessary. Here is a
+sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest
+in the program `Gnomovision' (which makes passes at
+compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating
+your program into proprietary programs. If your program
+is a subroutine library, you may consider it more useful
+to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU
+Library General Public License instead of this License.
+
+\ 4[QueryBox]
+
+In the query dialog box you can use the arrow keys or the
+first letter to select an item or click with the mouse on
+the button.
+
+\ 4[How to use help]
+
+You can use the cursor keys or mouse to navigate in the
+help viewer.
+Press down arrow to move to the next item or scroll down.
+Press up arrow to move to the previous item or scroll up.
+Press right arrow to follow the current link.
+Press left arrow to go back in the history of nodes that
+you have visited.
+
+If you terminal doesn't support the cursor keys you can
+use the space bar to scroll forward and the 'b' key scroll
+back. Use the TAB key to move to the next item and press
+ENTER to follow the current link. The 'l' (last) key may
+be used to go back in the history of nodes that you have
+visited. Press ESC to exit the help viewer.
+
+The left mouse button will follow the link or scroll. The
+right mouse button can be used to go back in the history
+of nodes.
+
+The full key list of the help viewer:
+
+\ 1General movement keys\ 2General Movement Keys\ 3 are accepted.
+
+tab Move to the next item.
+M-tab Move to the previous item.
+down Move to the next item or scroll a line down.
+up Move to the previous item or scroll a line up.
+right, enter Follow the current link.
+left, l Go back in the history of visited nodes.
+F1 Show the help for the help viewer.
+n Go to the next node.
+p Go to the previous node.
+c Go to the Contents node.
+F10, esc Exit the help viewer.
+\ 4
+Local variables:
+fill-column: 58
+end:
--- /dev/null
+#ifndef __MEM_H
+#define __MEM_H
+
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+# include <string.h>
+ /* An ANSI string.h and pre-ANSI memory.h might conflict */
+# if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H)
+# include <memory.h>
+# endif /* not STDC_HEADERS and HAVE_MEMORY_H */
+
+# ifndef index
+#define index strchr
+# endif
+
+# ifndef rindex
+# define rindex strrchr
+# endif
+
+# define bcopy(s,d,n) memcpy ((d), (s), (n))
+# define bcmp(s1,s2,n) memcmp ((s1), (s2), (n))
+# define bzero(s,n) memset ((s), 0, (n))
+
+#else /* not STDC_HEADERS and not HAVE_STRING_H */
+# include <strings.h>
+ /* memory and strings.h conflict on other systems */
+#endif /* not STDC_HEADERS and not HAVE_STRING_H */
+#endif /* __MEM_H */
+
--- /dev/null
+/* Pulldown menu code.
+ Copyright (C) 1994 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <string.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <ctype.h>
+#include <malloc.h>
+#include "mad.h"
+#include "util.h"
+#include "menu.h"
+#include "dialog.h"
+#include "global.h"
+#include "color.h"
+#include "main.h"
+#include "mouse.h"
+#include "win.h"
+#include "key.h" /* For mi_getch() */
+
+/* "$Id: menu.c,v 1.1 2001/12/30 09:55:23 sedwards Exp $" */
+
+extern int is_right;
+int menubar_visible = 1; /* This is the new default */
+
+Menu create_menu (char *name, menu_entry *entries, int count)
+{
+ Menu menu;
+
+ menu = (Menu) xmalloc (sizeof (*menu), "create_menu");
+ menu->count = count;
+ menu->max_entry_len = 0;
+ menu->entries = entries;
+
+#ifdef ENABLE_NLS
+ if (entries != (menu_entry*) 0)
+ {
+ register menu_entry* mp;
+ for (mp = entries; count--; mp++)
+ {
+ if (mp->text[0] == '\0')
+ continue;
+
+ mp->text = _(mp->text);
+ }
+ }
+#endif /* ENABLE_NLS */
+
+ menu->name = _(name);
+ menu->start_x = 0;
+ return menu;
+}
+
+static void menubar_drop_compute (WMenu *menubar)
+{
+ const Menu menu = menubar->menu [menubar->selected];
+ int max_entry_len = 0;
+ int i;
+
+ for (i = 0; i < menu->count; i++)
+ max_entry_len = max (max_entry_len, strlen (menu->entries [i].text));
+ menubar->max_entry_len = max_entry_len = max (max_entry_len, 20);
+}
+
+static void menubar_paint_idx (WMenu *menubar, int idx, int color)
+{
+ const Menu menu = menubar->menu [menubar->selected];
+ const int y = 2 + idx;
+ int x = menubar-> menu[menubar->selected]->start_x;
+
+ if (x + menubar->max_entry_len + 3 > menubar->widget.cols)
+ x = menubar->widget.cols - menubar->max_entry_len - 3;
+
+ widget_move (&menubar->widget, y, x);
+ attrset (color);
+ hline (' ', menubar->max_entry_len+2);
+ if (!*menu->entries [idx].text){
+ attrset (SELECTED_COLOR);
+ widget_move (&menubar->widget, y, x + 1);
+ hline (slow_terminal ? ' ' : ACS_HLINE, menubar->max_entry_len);
+ } else {
+ unsigned char *text = menu->entries [idx].text;
+
+ addch((unsigned char)menu->entries [idx].first_letter);
+ for (text = menu->entries [idx].text; *text; text++)
+ {
+ if (*text == '&')
+ {
+ ++text;
+ menu->entries [idx].hot_key = tolower(*text);
+ attrset (color == MENU_SELECTED_COLOR ?
+ MENU_HOTSEL_COLOR : MENU_HOT_COLOR);
+ addch(*text);
+ attrset(color);
+ continue;
+ }
+ addch(*text);
+ }
+ }
+ widget_move (&menubar->widget, y, x + 1);
+}
+
+static INLINE void menubar_draw_drop (WMenu *menubar)
+{
+ const int count = (menubar->menu [menubar->selected])->count;
+ int i;
+ int sel = menubar->subsel;
+ int column = menubar-> menu[menubar->selected]->start_x - 1;
+
+ if (column + menubar->max_entry_len + 4 > menubar->widget.cols)
+ column = menubar->widget.cols - menubar->max_entry_len - 4;
+
+ attrset (SELECTED_COLOR);
+ draw_box (menubar->widget.parent,
+ menubar->widget.y+1, menubar->widget.x + column,
+ count+2, menubar->max_entry_len + 4);
+
+ column++;
+ for (i = 0; i < count; i++){
+ if (i == sel)
+ continue;
+ menubar_paint_idx (menubar, i, MENU_ENTRY_COLOR);
+ }
+ menubar_paint_idx (menubar, sel, MENU_SELECTED_COLOR);
+}
+
+static void menubar_draw (WMenu *menubar)
+{
+ const int items = menubar->items;
+ int i;
+
+ /* First draw the complete menubar */
+ attrset (SELECTED_COLOR);
+ widget_move (&menubar->widget, 0, 0);
+
+ /* ncurses bug: it should work with hline but it does not */
+ for (i = menubar->widget.cols; i; i--)
+ addch (' ');
+
+ attrset (SELECTED_COLOR);
+ /* Now each one of the entries */
+ for (i = 0; i < items; i++){
+ if (menubar->active)
+ attrset(i == menubar->selected?MENU_SELECTED_COLOR:SELECTED_COLOR);
+ widget_move (&menubar->widget, 0, menubar->menu [i]->start_x);
+ printw ("%s", menubar->menu [i]->name);
+ }
+
+ if (menubar->dropped)
+ menubar_draw_drop (menubar);
+ else
+ widget_move (&menubar->widget, 0,
+ menubar-> menu[menubar->selected]->start_x);
+}
+
+static INLINE void menubar_remove (WMenu *menubar)
+{
+ menubar->subsel = 0;
+ if (menubar->dropped){
+ menubar->dropped = 0;
+ do_refresh ();
+ menubar->dropped = 1;
+ }
+}
+
+static void menubar_left (WMenu *menu)
+{
+ menubar_remove (menu);
+ menu->selected = (menu->selected - 1) % menu->items;
+ if (menu->selected < 0)
+ menu->selected = menu->items -1;
+ menubar_drop_compute (menu);
+ menubar_draw (menu);
+}
+
+static void menubar_right (WMenu *menu)
+{
+ menubar_remove (menu);
+ menu->selected = (menu->selected + 1) % menu->items;
+ menubar_drop_compute (menu);
+ menubar_draw (menu);
+}
+
+static void menubar_finish (WMenu *menubar)
+{
+ menubar->dropped = 0;
+ menubar->active = 0;
+ menubar->widget.lines = 1;
+ widget_want_hotkey (menubar->widget, 0);
+ dlg_select_nth_widget (menubar->widget.parent,
+ menubar->previous_selection);
+ do_refresh ();
+}
+
+static void menubar_drop (WMenu *menubar, int selected)
+{
+ menubar->dropped = 1;
+ menubar->selected = selected;
+ menubar->subsel = 0;
+ menubar_drop_compute (menubar);
+ menubar_draw (menubar);
+}
+
+static void menubar_execute (WMenu *menubar, int entry)
+{
+ const Menu menu = menubar->menu [menubar->selected];
+
+ is_right = menubar->selected != 0;
+ (*menu->entries [entry].call_back)(0);
+ menubar_finish (menubar);
+}
+
+static void menubar_move (WMenu *menubar, int step)
+{
+ const Menu menu = menubar->menu [menubar->selected];
+
+ menubar_paint_idx (menubar, menubar->subsel, MENU_ENTRY_COLOR);
+ do {
+ menubar->subsel += step;
+ if (menubar->subsel < 0)
+ menubar->subsel = menu->count - 1;
+
+ menubar->subsel %= menu->count;
+ } while (!menu->entries [menubar->subsel].call_back);
+ menubar_paint_idx (menubar, menubar->subsel, MENU_SELECTED_COLOR);
+}
+
+static int menubar_handle_key (WMenu *menubar, int key)
+{
+ int i;
+
+ /* Lowercase */
+ if (key < 256 && isalpha (key)) /* Linux libc.so.5.x.x bug fix */
+ key = tolower (key);
+
+ if (is_abort_char (key)){
+ menubar_finish (menubar);
+ return 1;
+ }
+
+ if (key == KEY_LEFT || key == XCTRL('b')){
+ menubar_left (menubar);
+ return 1;
+ } else if (key == KEY_RIGHT || key == XCTRL ('f')){
+ menubar_right (menubar);
+ return 1;
+ }
+
+ /* .ado: NT Alpha can not allow CTRL in Menubar */
+#if defined(_OS_NT)
+ if (!key)
+ return 0;
+#endif
+
+ if (!menubar->dropped){
+ const int items = menubar->items;
+ for (i = 0; i < items; i++){
+ const Menu menu = menubar->menu [i];
+
+ /* Hack, we should check for the upper case letter */
+ if (tolower (menu->name [1]) == key){
+ menubar_drop (menubar, i);
+ return 1;
+ }
+ }
+ if (key == KEY_ENTER || key == XCTRL ('n') || key == KEY_DOWN
+ || key == '\n'){
+ menubar_drop (menubar, menubar->selected);
+ return 1;
+ }
+ return 1;
+ } else {
+ const int selected = menubar->selected;
+ const Menu menu = menubar->menu [selected];
+ const int items = menu->count;
+
+ for (i = 0; i < items; i++){
+ if (!menu->entries [i].call_back)
+ continue;
+
+ if (key != menu->entries [i].hot_key)
+ continue;
+
+ menubar_execute (menubar, i);
+ return 1;
+ }
+
+ if (key == KEY_ENTER || key == '\n'){
+ menubar_execute (menubar, menubar->subsel);
+ return 1;
+ }
+
+
+ if (key == KEY_DOWN || key == XCTRL ('n'))
+ menubar_move (menubar, 1);
+
+ if (key == KEY_UP || key == XCTRL ('p'))
+ menubar_move (menubar, -1);
+ }
+ return 0;
+}
+
+static int menubar_callback (Dlg_head *h, WMenu *menubar, int msg, int par)
+{
+ switch (msg){
+ /* We do not want the focus unless we have been activated */
+ case WIDGET_FOCUS:
+ if (menubar->active){
+ widget_want_cursor (menubar->widget, 1);
+
+ /* Trick to get all the mouse events */
+ menubar->widget.lines = LINES;
+
+ /* Trick to get all of the hotkeys */
+ widget_want_hotkey (menubar->widget, 1);
+ menubar->subsel = 0;
+ menubar_drop_compute (menubar);
+ menubar_draw (menubar);
+ return 1;
+ } else
+ return 0;
+
+ /* We don't want the buttonbar to activate while using the menubar */
+ case WIDGET_HOTKEY:
+ case WIDGET_KEY:
+ if (menubar->active){
+ menubar_handle_key (menubar, par);
+ return 1;
+ } else
+ return 0;
+
+ case WIDGET_CURSOR:
+ /* Put the cursor in a suitable place */
+ return 0;
+
+ case WIDGET_UNFOCUS:
+ if (menubar->active)
+ return 0;
+ else {
+ widget_want_cursor (menubar->widget, 0);
+ return 1;
+ }
+
+ case WIDGET_DRAW:
+ if (menubar_visible)
+ menubar_draw (menubar);
+ }
+ return default_proc (h, msg, par);
+}
+
+int
+menubar_event (Gpm_Event *event, WMenu *menubar)
+{
+ int was_active;
+ int new_selection;
+ int left_x, right_x, bottom_y;
+
+ if (!(event->type & (GPM_UP|GPM_DOWN|GPM_DRAG)))
+ return MOU_NORMAL;
+
+ if (!menubar->dropped){
+ menubar->previous_selection = dlg_item_number(menubar->widget.parent);
+ menubar->active = 1;
+ menubar->dropped = 1;
+ was_active = 0;
+ } else
+ was_active = 1;
+
+ /* Mouse operations on the menubar */
+ if (event->y == 1 || !was_active){
+ if (event->type & GPM_UP)
+ return MOU_NORMAL;
+
+ new_selection = 0;
+ while (new_selection < menubar->items
+ && event->x > menubar->menu[new_selection]->start_x
+ )
+ new_selection++;
+
+ if (new_selection) /* Don't set the invalid value -1 */
+ --new_selection;
+
+ if (!was_active){
+ menubar->selected = new_selection;
+ dlg_select_widget (menubar->widget.parent, menubar);
+ menubar_drop_compute (menubar);
+ menubar_draw (menubar);
+ return MOU_NORMAL;
+ }
+
+ menubar_remove (menubar);
+
+ menubar->selected = new_selection;
+
+ menubar_drop_compute (menubar);
+ menubar_draw (menubar);
+ return MOU_NORMAL;
+ }
+
+ if (!menubar->dropped)
+ return MOU_NORMAL;
+
+ /* Ignore the events on anything below the third line */
+ if (event->y <= 2)
+ return MOU_NORMAL;
+
+ /* Else, the mouse operation is on the menus or it is not */
+ left_x = menubar->menu[menubar->selected]->start_x;
+ right_x = left_x + menubar->max_entry_len + 4;
+ if (right_x > menubar->widget.cols)
+ {
+ left_x = menubar->widget.cols - menubar->max_entry_len - 3;
+ right_x = menubar->widget.cols - 1;
+ }
+
+ bottom_y = (menubar->menu [menubar->selected])->count + 3;
+
+ if ((event->x > left_x) && (event->x < right_x) && (event->y < bottom_y)){
+ int pos = event->y - 3;
+
+ if (!menubar->menu [menubar->selected]->entries [pos].call_back)
+ return MOU_NORMAL;
+
+ menubar_paint_idx (menubar, menubar->subsel, MENU_ENTRY_COLOR);
+ menubar->subsel = pos;
+ menubar_paint_idx (menubar, menubar->subsel, MENU_SELECTED_COLOR);
+
+ if (event->type & GPM_UP)
+ menubar_execute (menubar, pos);
+ } else
+ if (event->type & GPM_DOWN)
+ menubar_finish (menubar);
+
+ return MOU_NORMAL;
+}
+
+static void menubar_destroy (WMenu *menubar)
+{
+}
+
+/*
+ * Properly space menubar items. Should be called when menubar is created
+ * and also when widget width is changed (i.e. upon xterm resize).
+ */
+void
+menubar_arrange(WMenu* menubar)
+{
+ register int i, start_x = 1;
+ int items = menubar->items;
+
+#ifndef RESIZABLE_MENUBAR
+ int gap = 3;
+
+ for (i = 0; i < items; i++)
+ {
+ int len = strlen(menubar->menu[i]->name);
+ menubar->menu[i]->start_x = start_x;
+ start_x += len + gap;
+ }
+
+#else /* RESIZABLE_MENUBAR */
+
+ int gap = menubar->widget.cols - 2;
+
+ /* First, calculate gap between items... */
+ for (i = 0; i < items; i++)
+ {
+ /* preserve length here, to be used below */
+ gap -= (menubar->menu[i]->start_x = strlen(menubar->menu[i]->name));
+ }
+
+ gap /= (items - 1);
+
+ if (gap <= 0)
+ {
+ /* We are out of luck - window is too narrow... */
+ gap = 1;
+ }
+
+ /* ...and now fix start positions of menubar items */
+ for (i = 0; i < items; i++)
+ {
+ int len = menubar->menu[i]->start_x;
+ menubar->menu[i]->start_x = start_x;
+ start_x += len + gap;
+ }
+#endif /* RESIZABLE_MENUBAR */
+}
+
+void
+destroy_menu (Menu menu)
+{
+ free (menu);
+}
+
+WMenu *menubar_new (int y, int x, int cols, Menu menu [], int items)
+{
+ WMenu *menubar = (WMenu *) xmalloc (sizeof (WMenu), "menubar_new");
+
+ memset(menubar, 0, sizeof(*menubar)); /* FIXME: subsel used w/o being set */
+ init_widget (&menubar->widget, y, x, 1, cols,
+ (callback_fn) menubar_callback,
+ (destroy_fn) menubar_destroy,
+ (mouse_h) menubar_event, NULL);
+ menubar->menu = menu;
+ menubar->active = 0;
+ menubar->dropped = 0;
+ menubar->items = items;
+ menubar->selected = 0;
+ widget_want_cursor (menubar->widget, 0);
+ menubar_arrange(menubar);
+
+ return menubar;
+}
--- /dev/null
+#ifndef __MENU_H
+#define __MENU_H
+
+/* IMPORTANT NOTE: This header is dependent on HAVE_X / HAVE_XVIEW. If you
+ * include this header, you have to move it to the group of HAVE_X dependant
+ * modules in {xv|tk}/Makefile.in !!!
+ */
+
+#include "dlg.h"
+#include "widget.h"
+
+typedef void (*callfn) ();
+/* FIXME: We have to leave this type ambiguous, because `callfn' is
+ used both for functions that take an argument and ones that don't.
+ That ought to be cleared up. */
+
+typedef struct {
+ char first_letter;
+ char *text;
+ int hot_key;
+ callfn call_back;
+} menu_entry;
+
+#ifdef HAVE_XVIEW
+# ifndef xview_walkmenu_DEFINED
+ typedef unsigned long Menu;
+# endif
+#else
+typedef struct {
+ char *name;
+ int count;
+ int max_entry_len;
+ int selected;
+ menu_entry *entries;
+ int start_x; /* position relative to menubar start */
+} sMenu;
+typedef sMenu *Menu;
+#endif
+
+Menu create_menu (char *name, menu_entry *entries, int count);
+void destroy_menu (Menu menu);
+
+extern int menubar_visible;
+
+/* The button bar menu */
+typedef struct {
+ Widget widget;
+
+ int active; /* If the menubar is in use */
+ int dropped; /* If the menubar has dropped */
+ Menu *menu; /* The actual menus */
+ int items;
+ int selected; /* Selected menu on the top bar */
+ int subsel; /* Selected entry on the submenu */
+ int max_entry_len; /* Cache value for the columns in a box */
+ int previous_selection; /* Selected widget before activating menu */
+} WMenu;
+
+WMenu *menubar_new (int y, int x, int cols, Menu menu [], int items);
+
+#endif /* __MENU_H */
+
--- /dev/null
+/* mfmt: sets bold and underline for mail files */
+/* (c) 1995 miguel de icaza */
+
+#include <stdio.h>
+
+enum states {
+ header,
+ definition,
+ plain,
+ newline,
+ seen_f,
+ seen_r,
+ seen_o,
+ header_new,
+ seen_m
+};
+
+void
+omain (void)
+{
+ enum states state = header;
+ int prev = 0;
+ int c;
+
+ while ((c = getchar ()) != EOF){
+ if (c != '\n'){
+ switch (state){
+ case header:
+ putchar ('_');
+ putchar ('\b');
+ break;
+
+ case definition:
+ putchar (c);
+ putchar ('\b');
+ break;
+ default:
+ break; /* inhibit compiler warnings */
+ }
+ }
+ putchar (c);
+ if ((state != plain) && c == ':')
+ state = definition;
+
+ if (c == '\n' && prev == '\n')
+ state = plain;
+
+ if (state == definition && c == '\n')
+ state = header;
+
+ prev = c;
+ }
+}
+
+int
+main (void)
+{
+ int state = newline;
+ int space_seen;
+ int c;
+
+ while ((c = getchar ()) != EOF){
+ switch (state){
+ case plain:
+ if (c == '\n')
+ state = newline;
+ putchar (c);
+ break;
+
+ case newline:
+ if (c == 'F')
+ state = seen_f;
+ else {
+ state = plain;
+ putchar (c);
+ }
+ break;
+
+ case seen_f:
+ if (c == 'r')
+ state = seen_r;
+ else {
+ printf ("F%c", c);
+ state = plain;
+ }
+ break;
+
+ case seen_r:
+ if (c == 'o')
+ state = seen_o;
+ else {
+ state = plain;
+ printf ("Fr%c", c);
+ }
+ break;
+
+ case seen_o:
+ if (c == 'm'){
+ state = seen_m;
+ } else {
+ state = plain;
+ printf ("Fro%c", c);
+ }
+ break;
+
+ case seen_m:
+ if (c == ' '){
+ state = definition;
+ printf ("_\bF_\br_\bo_\bm ");
+ } else {
+ state = plain;
+ printf ("From%c", c);
+ }
+ break;
+
+ case header_new:
+ space_seen = 0;
+ if (c == ' ' || c == '\t') {
+ state = definition;
+ putchar (c);
+ break;
+ }
+ if (c == '\n'){
+ state = plain;
+ putchar (c);
+ break;
+ }
+
+ case header:
+ if (c == '\n'){
+ putchar (c);
+ state = header_new;
+ break;
+ }
+ printf ("_\b%c", c);
+ if (c == ' ')
+ space_seen = 1;
+ if (c == ':' && !space_seen)
+ state = definition;
+ break;
+
+ case definition:
+ if (c == '\n'){
+ putchar (c);
+ state = header_new;
+ break;
+ }
+ printf ("%c\b%c", c, c);
+ break;
+ }
+ }
+ return (0);
+}
--- /dev/null
+/* mountlist.c -- return a list of mounted filesystems
+ Copyright (C) 1991, 1992 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 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifndef NO_INFOMOUNT
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "mountlist.h"
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#else
+void free (void *ptr);
+#endif
+#if defined(STDC_HEADERS) || defined(HAVE_STRING_H)
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+#endif /* MOUNTED_GETFSSTAT */
+
+#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+#include <mntent.h>
+#if !defined(MOUNTED)
+#if defined(MNT_MNTTAB) /* HP-UX. */
+#define MOUNTED MNT_MNTTAB
+#endif
+#if defined(MNTTABNAME) /* Dynix. */
+#define MOUNTED MNTTABNAME
+#endif
+#endif
+#endif
+
+#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
+#include <sys/mount.h>
+#endif
+
+#ifdef MOUNTED_GETMNT /* Ultrix. */
+#include <sys/mount.h>
+#include <sys/fs_types.h>
+#endif
+
+#ifdef MOUNTED_FREAD /* SVR2. */
+#include <mnttab.h>
+#endif
+
+#ifdef MOUNTED_FREAD_FSTYP /* SVR3. */
+#include <mnttab.h>
+#include <sys/fstyp.h>
+#include <sys/statfs.h>
+#endif
+
+#ifdef MOUNTED_GETMNTENT2 /* SVR4. */
+#include <sys/mnttab.h>
+#endif
+
+#ifdef MOUNTED_VMOUNT /* AIX. */
+#include <fshelp.h>
+#include <sys/vfs.h>
+#endif
+
+#ifdef __bsdi__
+# ifndef MOUNT_UFS
+# define xBSD
+# endif
+#endif
+
+#ifdef __NetBSD__
+# define xBSD
+#endif
+
+#ifdef __OpenBSD__
+# define xBSD
+#endif
+
+#if defined(SCO_FLAVOR) && defined(__GNUC__)
+extern char* strdup(const char*);
+#endif
+
+char *strstr (const char *haystack, const char *needle);
+/* void error (void); FIXME -- needed? */
+
+#ifdef DOLPHIN
+/* So special that it's not worth putting this in autoconf. */
+#undef MOUNTED_FREAD_FSTYP
+#define MOUNTED_GETMNTTBL
+#endif
+
+#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+/* Return the value of the hexadecimal number represented by CP.
+ No prefix (like '0x') or suffix (like 'h') is expected to be
+ part of CP. */
+
+static int xatoi (char *cp)
+{
+ int val;
+
+ val = 0;
+ while (*cp) {
+ if (*cp >= 'a' && *cp <= 'f')
+ val = val * 16 + *cp - 'a' + 10;
+ else if (*cp >= 'A' && *cp <= 'F')
+ val = val * 16 + *cp - 'A' + 10;
+ else if (*cp >= '0' && *cp <= '9')
+ val = val * 16 + *cp - '0';
+ else
+ break;
+ cp++;
+ }
+ return val;
+}
+#endif /* MOUNTED_GETMNTENT1. */
+
+#if defined (MOUNTED_GETMNTINFO) && !defined (xBSD)
+static char *fstype_to_string (short t)
+{
+ switch (t) {
+ case MOUNT_UFS:
+ return "ufs";
+ case MOUNT_NFS:
+ return "nfs";
+#ifdef MOUNT_PC
+ case MOUNT_PC:
+ return "pc";
+#endif
+#ifdef MOUNT_MFS
+ case MOUNT_MFS:
+ return "mfs";
+#endif
+#ifdef MOUNT_LO
+ case MOUNT_LO:
+ return "lo";
+#endif
+#ifdef MOUNT_TFS
+ case MOUNT_TFS:
+ return "tfs";
+#endif
+#ifdef MOUNT_TMP
+ case MOUNT_TMP:
+ return "tmp";
+#endif
+ default:
+ return "?";
+ }
+}
+#endif /* MOUNTED_GETMNTINFO */
+
+#ifdef MOUNTED_VMOUNT /* AIX. */
+static char *fstype_to_string (int t)
+{
+ struct vfs_ent *e;
+
+ e = getvfsbytype (t);
+ if (!e || !e->vfsent_name)
+ return "none";
+ else
+ return e->vfsent_name;
+}
+#endif /* MOUNTED_VMOUNT */
+
+/* Return a list of the currently mounted filesystems, or NULL on error.
+ Add each entry to the tail of the list so that they stay in order.
+ If NEED_FS_TYPE is nonzero, ensure that the filesystem type fields in
+ the returned list are valid. Otherwise, they might not be.
+ If ALL_FS is zero, do not return entries for filesystems that
+ are automounter (dummy) entries. */
+
+struct mount_entry *read_filesystem_list (int need_fs_type, int all_fs)
+{
+ struct mount_entry *mount_list;
+ struct mount_entry *me;
+ struct mount_entry *mtail;
+
+ /* Start the list off with a dummy entry. */
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_next = NULL;
+ mount_list = mtail = me;
+
+#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+ {
+ struct mntent *mnt;
+ char *table = MOUNTED;
+ FILE *fp;
+ char *devopt;
+
+ fp = setmntent (table, "r");
+ if (fp == NULL)
+ return NULL;
+
+ while ((mnt = getmntent (fp))) {
+ if (!all_fs && (!strcmp (mnt->mnt_type, "ignore")
+ || !strcmp (mnt->mnt_type, "auto")))
+ continue;
+
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_devname = strdup (mnt->mnt_fsname);
+ me->me_mountdir = strdup (mnt->mnt_dir);
+ me->me_type = strdup (mnt->mnt_type);
+ devopt = strstr (mnt->mnt_opts, "dev=");
+ if (devopt) {
+ if (devopt[4] == '0' && (devopt[5] == 'x' || devopt[5] == 'X'))
+ me->me_dev = xatoi (devopt + 6);
+ else
+ me->me_dev = xatoi (devopt + 4);
+ } else
+ me->me_dev = -1; /* Magic; means not known yet. */
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+
+ if (endmntent (fp) == 0)
+ return NULL;
+ }
+#endif /* MOUNTED_GETMNTENT1. */
+
+#ifdef MOUNTED_GETMNTINFO /* 4.4BSD. */
+ {
+ struct statfs *fsp;
+ int entries;
+
+ entries = getmntinfo (&fsp, MNT_NOWAIT);
+ if (entries < 0)
+ return NULL;
+ while (entries-- > 0) {
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_devname = strdup (fsp->f_mntfromname);
+ me->me_mountdir = strdup (fsp->f_mntonname);
+#ifdef xBSD
+ me->me_type = strdup (fsp->f_fstypename);
+#else
+ me->me_type = fstype_to_string (fsp->f_type);
+#endif
+ me->me_dev = -1; /* Magic; means not known yet. */
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ fsp++;
+ }
+ }
+#endif /* MOUNTED_GETMNTINFO */
+
+#ifdef MOUNTED_GETMNT /* Ultrix. */
+ {
+ int offset = 0;
+ int val;
+ struct fs_data fsd;
+
+ while ((val = getmnt (&offset, &fsd, sizeof (fsd), NOSTAT_MANY,
+ (char *) 0)) > 0) {
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_devname = strdup (fsd.fd_req.devname);
+ me->me_mountdir = strdup (fsd.fd_req.path);
+ me->me_type = gt_names[fsd.fd_req.fstype];
+ me->me_dev = fsd.fd_req.dev;
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+ if (val < 0)
+ return NULL;
+ }
+#endif /* MOUNTED_GETMNT. */
+
+#if defined (MOUNTED_GETFSSTAT) /* __alpha running OSF_1 */
+ {
+ int numsys, counter, bufsize;
+ struct statfs *stats;
+
+ numsys = getfsstat ((struct statfs *) 0, 0L, MNT_WAIT);
+ if (numsys < 0)
+ return (NULL);
+
+ bufsize = (1 + numsys) * sizeof (struct statfs);
+ stats = (struct statfs *) malloc (bufsize);
+ numsys = getfsstat (stats, bufsize, MNT_WAIT);
+
+ if (numsys < 0) {
+ free (stats);
+ return (NULL);
+ }
+ for (counter = 0; counter < numsys; counter++) {
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_devname = strdup (stats[counter].f_mntfromname);
+ me->me_mountdir = strdup (stats[counter].f_mntonname);
+ me->me_type = mnt_names[stats[counter].f_type];
+ me->me_dev = -1; /* Magic; means not known yet. */
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+
+ free (stats);
+ }
+#endif /* MOUNTED_GETFSSTAT */
+
+#if defined (MOUNTED_FREAD) || defined (MOUNTED_FREAD_FSTYP) /* SVR[23]. */
+ {
+ struct mnttab mnt;
+ char *table = "/etc/mnttab";
+ FILE *fp;
+
+ fp = fopen (table, "r");
+ if (fp == NULL)
+ return NULL;
+
+ while (fread (&mnt, sizeof mnt, 1, fp) > 0) {
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+#ifdef GETFSTYP /* SVR3. */
+ me->me_devname = strdup (mnt.mt_dev);
+#else
+ me->me_devname = malloc (strlen (mnt.mt_dev) + 6);
+ strcpy (me->me_devname, "/dev/");
+ strcpy (me->me_devname + 5, mnt.mt_dev);
+#endif
+ me->me_mountdir = strdup (mnt.mt_filsys);
+ me->me_dev = -1; /* Magic; means not known yet. */
+ me->me_type = "";
+#ifdef GETFSTYP /* SVR3. */
+ if (need_fs_type) {
+ struct statfs fsd;
+ char typebuf[FSTYPSZ];
+
+ if (statfs (me->me_mountdir, &fsd, sizeof fsd, 0) != -1
+ && sysfs (GETFSTYP, fsd.f_fstyp, typebuf) != -1)
+ me->me_type = strdup (typebuf);
+ }
+#endif
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+
+ if (fclose (fp) == EOF)
+ return NULL;
+ }
+#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
+
+#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
+ {
+ struct mntent **mnttbl = getmnttbl (), **ent;
+ for (ent = mnttbl; *ent; ent++) {
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_devname = strdup ((*ent)->mt_resource);
+ me->me_mountdir = strdup ((*ent)->mt_directory);
+ me->me_type = strdup ((*ent)->mt_fstype);
+ me->me_dev = -1; /* Magic; means not known yet. */
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+ endmnttbl ();
+ }
+#endif
+
+#ifdef MOUNTED_GETMNTENT2 /* SVR4. */
+ {
+ struct mnttab mnt;
+ char *table = MNTTAB;
+ FILE *fp;
+ int ret;
+
+ fp = fopen (table, "r");
+ if (fp == NULL)
+ return NULL;
+
+ while ((ret = getmntent (fp, &mnt)) == 0) {
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ me->me_devname = strdup (mnt.mnt_special);
+ me->me_mountdir = strdup (mnt.mnt_mountp);
+ me->me_type = strdup (mnt.mnt_fstype);
+ me->me_dev = -1; /* Magic; means not known yet. */
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+
+ if (ret > 0)
+ return NULL;
+ if (fclose (fp) == EOF)
+ return NULL;
+ }
+#endif /* MOUNTED_GETMNTENT2. */
+
+#ifdef MOUNTED_VMOUNT /* AIX. */
+ {
+ int bufsize;
+ char *entries, *thisent;
+ struct vmount *vmp;
+
+ /* Ask how many bytes to allocate for the mounted filesystem info. */
+ mntctl (MCTL_QUERY, sizeof bufsize, (struct vmount *) &bufsize);
+ entries = malloc (bufsize);
+
+ /* Get the list of mounted filesystems. */
+ mntctl (MCTL_QUERY, bufsize, (struct vmount *) entries);
+
+ for (thisent = entries; thisent < entries + bufsize;
+ thisent += vmp->vmt_length) {
+ vmp = (struct vmount *) thisent;
+ me = (struct mount_entry *) malloc (sizeof (struct mount_entry));
+ if (vmp->vmt_flags & MNT_REMOTE) {
+ char *host, *path;
+
+ /* Prepend the remote pathname. */
+ host = thisent + vmp->vmt_data[VMT_HOSTNAME].vmt_off;
+ path = thisent + vmp->vmt_data[VMT_OBJECT].vmt_off;
+ me->me_devname = malloc (strlen (host) + strlen (path) + 2);
+ strcpy (me->me_devname, host);
+ strcat (me->me_devname, ":");
+ strcat (me->me_devname, path);
+ } else {
+ me->me_devname = strdup (thisent +
+ vmp->vmt_data[VMT_OBJECT].vmt_off);
+ }
+ me->me_mountdir = strdup (thisent + vmp->vmt_data[VMT_STUB].vmt_off);
+ me->me_type = strdup (fstype_to_string (vmp->vmt_gfstype));
+ me->me_dev = -1; /* vmt_fsid might be the info we want. */
+ me->me_next = NULL;
+
+ /* Add to the linked list. */
+ mtail->me_next = me;
+ mtail = me;
+ }
+ free (entries);
+ }
+#endif /* MOUNTED_VMOUNT. */
+
+ /* Free the dummy head. */
+ me = mount_list;
+ mount_list = mount_list->me_next;
+ free (me);
+ return mount_list;
+}
+#endif /* NO_INFOMOUNT */
+
+#if defined(NO_INFOMOUNT) && defined(__QNX__)
+/*
+** QNX has no [gs]etmnt*(), [gs]etfs*(), or /etc/mnttab, but can do
+** this via the following code.
+** Note that, as this is based on CWD, it only fills one mount_entry
+** structure. See my_statfs() in utilunix.c for the "other side" of
+** this hack.
+*/
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <sys/disk.h>
+#include <sys/fsys.h>
+#include <sys/statfs.h>
+
+#include "mountlist.h"
+
+struct mount_entry *read_filesystem_list(int need_fs_type, int all_fs)
+{
+ struct _disk_entry de;
+ struct statfs fs;
+ int i, fd;
+ char *tp, dev[_POSIX_NAME_MAX], dir[_POSIX_PATH_MAX];
+
+ static struct mount_entry *me = NULL;
+
+ if (me)
+ {
+ if (me->me_devname) free(me->me_devname);
+ if (me->me_mountdir) free(me->me_mountdir);
+ if (me->me_type) free(me->me_type);
+ }
+ else
+ me = (struct mount_entry *)malloc(sizeof(struct mount_entry));
+
+ if (!getcwd(dir, _POSIX_PATH_MAX)) return (NULL);
+
+ if ((fd = open(dir, O_RDONLY)) == -1) return (NULL);
+
+ i = disk_get_entry(fd, &de);
+
+ close(fd);
+
+ if (i == -1) return (NULL);
+
+ switch (de.disk_type)
+ {
+ case _UNMOUNTED: tp = "unmounted"; break;
+ case _FLOPPY: tp = "Floppy"; break;
+ case _HARD: tp = "Hard"; break;
+ case _RAMDISK: tp = "Ram"; break;
+ case _REMOVABLE: tp = "Removable"; break;
+ case _TAPE: tp = "Tape"; break;
+ case _CDROM: tp = "CDROM"; break;
+ default: tp = "unknown";
+ }
+
+ if (fsys_get_mount_dev(dir, &dev) == -1) return (NULL);
+
+ if (fsys_get_mount_pt(dev, &dir) == -1) return (NULL);
+
+ me->me_devname = strdup(dev);
+ me->me_mountdir = strdup(dir);
+ me->me_type = strdup(tp);
+ me->me_dev = de.disk_type;
+
+#ifdef DEBUG
+ fprintf(stderr, "disk_get_entry():\n\tdisk_type=%d (%s)\n\tdriver_name='%-*.*s'\n\tdisk_drv=%d\n",
+ de.disk_type, tp, _DRIVER_NAME_LEN, _DRIVER_NAME_LEN, de.driver_name, de.disk_drv);
+ fprintf(stderr, "fsys_get_mount_dev():\n\tdevice='%s'\n", dev);
+ fprintf(stderr, "fsys_get_mount_pt():\n\tmount point='%s'\n", dir);
+#endif
+
+ return (me);
+}
+#endif /* __QNX__ */
+
--- /dev/null
+/* mountlist.h -- declarations for list of mounted filesystems
+ Copyright (C) 1991, 1992 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 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __MOUNTLIST_H
+#define __MOUNTLIST_H
+
+/* A mount table entry. */
+struct mount_entry
+{
+ char *me_devname; /* Device node pathname, including "/dev/". */
+ char *me_mountdir; /* Mount point directory pathname. */
+ char *me_type; /* "nfs", "4.2", etc. */
+ dev_t me_dev; /* Device number of me_mountdir. */
+ struct mount_entry *me_next;
+};
+
+struct mount_entry *read_filesystem_list (int need_fs_type, int all_fs);
+#endif /* __MOUNTLIST_H */
--- /dev/null
+/* Mouse managing
+ Copyright (C) 1994 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Events received by clients of this library have their coordinates 0 */
+/* based */
+
+/* "$Id: mouse.c,v 1.1 2001/12/30 09:55:23 sedwards Exp $" */
+
+#include <config.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <signal.h> /* For kill() and SIGQUIT */
+#include <fcntl.h>
+#if (!defined(__IBMC__) && !defined(__IBMCPP__)) && !defined(OS2_NT)
+# include <termios.h>
+#endif
+#include <malloc.h>
+#include <stdio.h>
+
+#include "mad.h"
+#include "mouse.h"
+#include "global.h" /* ESC_STR */
+#include "util.h" /* xmalloc */
+#include "key.h" /* define sequence */
+#include "tty.h" /* get ncurses header */
+
+int xmouse_flag = 0;
+
+/*
+ * This chunk of NCURSES internals is used to support the keyok() function for
+ * NCURSES versions between 1.9.6 (when the mouse code was introduced in 1995),
+ * and 4.2 (when the keyok function will be release).
+ */
+#ifndef HAVE_KEYOK
+#ifdef NCURSES_MOUSE_VERSION /* first defined for ncurses 1.9.6 */
+#ifdef NCURSES_970530 /* defined by configure script */
+/*
+ * ncurses 1.9.8a ported to QNX doesn't provide the SP pointer as a global
+ * symbol in the library...
+ */
+#ifndef __QNX__
+struct tries {
+ struct tries *child;
+ struct tries *sibling;
+ unsigned char ch;
+ unsigned short value;
+};
+
+struct screen {
+ int _ifd;
+ FILE *_ofp;
+#if NCURSES_970530 >= 2
+ char *_setbuf; /*4.0*/
+#endif
+ int _checkfd;
+ struct term *_term;
+ short _lines;
+ short _columns;
+#if NCURSES_970530 >= 1
+ short _lines_avail; /*1.9.9g*/
+ short _topstolen; /*1.9.9g*/
+#endif
+ struct _win_st *_curscr;
+ struct _win_st *_newscr;
+ struct _win_st *_stdscr;
+ struct tries *_keytry; /* "Try" for use with keypad mode */
+ /* there's more, but this is just for alignment */
+};
+extern struct screen *SP;
+
+/*
+ * Remove a code from the specified tree, freeing the unused nodes. Returns
+ * true if the code was found/removed.
+ */
+static
+int _nc_remove_key(struct tries **tree, unsigned short code)
+{
+ struct tries *ptr = (*tree);
+
+ if (code > 0) {
+ while (ptr != 0) {
+ if (_nc_remove_key(&(ptr->child), code)) {
+ return TRUE;
+ }
+ if (ptr->value == code) {
+ *tree = 0;
+ free(ptr);
+ return TRUE;
+ }
+ ptr = ptr->sibling;
+ }
+ }
+ return FALSE;
+}
+
+int
+keyok(int code, bool flag)
+{
+ _nc_remove_key(&(SP->_keytry), code);
+ return OK;
+}
+#endif /* __QNX__ */
+#endif /* NCURSES_970530 */
+#endif /* NCURSES_MOUSE_VERSION */
+#endif /* HAVE_KEYOK */
+
+#ifdef HAVE_LIBGPM
+static int mouse_d; /* Handle to the mouse server */
+#endif
+
+#ifdef DEBUGMOUSE
+/* Only used for debugging */
+static int top_event = 0;
+FILE *log;
+#endif
+
+#ifdef HAVE_LIBGPM
+
+void show_mouse_pointer (int x, int y)
+{
+#ifdef HAVE_LIBGPM
+ if (use_mouse_p == GPM_MOUSE){
+ Gpm_DrawPointer (x, y, gpm_consolefd);
+ }
+#endif
+}
+
+#endif /* HAVE_LIBGPM */
+#if 0
+int mouse_handler (Gpm_Event *gpm_event)
+{
+ MouseEvent *event = mouse_events;
+ int x = last_x = gpm_event->x;
+ int y = last_y = gpm_event->y;
+ int redo = 0;
+
+/* DEBUGM ((log, "Mouse [%d, %d]\n", x, y)); */
+
+ /* Call any registered event handlers */
+ for (; event; event = (MouseEvent *) event->next){
+ if ((event->x1 <= x) && (x <= event->x2)
+ && (event->y1 <= y) && (y <= event->y2)){
+ gpm_event->x -= event->x1;
+ gpm_event->y -= event->y1;
+ last_mouse_event = event;
+ redo = (*(event->mouse_callback))(gpm_event, event->data);
+ gpm_event->x += event->x1;
+ gpm_event->y += event->y1;
+ break;
+ }
+ }
+ return redo;
+}
+
+int redo_mouse (Gpm_Event *event)
+{
+ if (last_mouse_event){
+ int result;
+ event->x -= last_mouse_event->x1;
+ event->y -= last_mouse_event->y1;
+ result = (*(last_mouse_event->mouse_callback))
+ (event,last_mouse_event->data);
+ event->x += last_mouse_event->x1;
+ event->y += last_mouse_event->y1;
+ return result;
+ }
+ return MOU_NORMAL;
+}
+#endif
+
+void init_mouse (void)
+{
+ /*
+ * MC's use of xterm mouse is incompatible with NCURSES's support. The
+ * simplest solution is to disable NCURSE's mouse.
+ */
+#ifdef NCURSES_MOUSE_VERSION
+/* See the comment above about QNX/ncurses 1.9.8a ... */
+#ifndef __QNX__
+ keyok(KEY_MOUSE, FALSE);
+#endif /* __QNX__ */
+#endif /* NCURSES_MOUSE_VERSION */
+
+#if defined(NCURSES_970530)
+#endif
+ switch (use_mouse_p)
+ {
+#ifdef HAVE_LIBGPM
+ case GPM_MOUSE:
+ {
+ Gpm_Connect conn;
+
+ conn.eventMask = ~GPM_MOVE;
+ conn.defaultMask = GPM_MOVE;
+ conn.minMod = 0;
+ conn.maxMod = 0;
+
+ if ((mouse_d = Gpm_Open (&conn, 0)) == -1)
+ return;
+
+#ifdef DEBUGMOUSE
+ log = fopen ("mouse.log", "w");
+#endif
+ }
+ break;
+#endif /* HAVE_LIBGPM */
+ case XTERM_MOUSE:
+ if (!xmouse_flag) {
+
+ /* save old highlight mouse tracking */
+ printf("%c[?1001s",27);
+
+ /* enable mouse tracking */
+ printf("%c[?1000h",27);
+
+ fflush (stdout);
+ /* turn on */
+ xmouse_flag = 1;
+ define_sequence (MCKEY_MOUSE, ESC_STR "[M", MCKEY_NOACTION);
+ }
+ break;
+ default:
+ /* nothing */
+ break;
+ } /* switch (use_mouse_p) */
+}
+
+void shut_mouse (void)
+{
+ switch (use_mouse_p){
+#ifdef HAVE_LIBGPM
+ case GPM_MOUSE:
+ Gpm_Close ();
+ break;
+#endif
+ case XTERM_MOUSE:
+ if (xmouse_flag) {
+
+ /* disable mouse tracking */
+ /* Changed the 1 for an 'l' below: */
+ printf("%c[?1000l",27);
+
+ /* restore old highlight mouse tracking */
+ printf("%c[?1001r",27);
+
+ fflush (stdout);
+ /* off */
+ xmouse_flag = 0;
+ }
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+}
+
+#ifdef DEBUGMOUSE
+void mouse_log (char *function, char *file, int line)
+{
+ fprintf (log, "%s called from %s:%d\n", function, file, line);
+}
+#endif
+
--- /dev/null
+#ifndef MC_MOUSE_H
+#define MC_MOUSE_H
+
+#ifdef HAVE_LIBGPM
+
+/* GPM mouse support include file */
+#include <gpm.h>
+
+#else
+
+/* Equivalent definitions for non-GPM mouse support */
+/* These lines are modified version from the lines appearing in the */
+/* gpm.h include file of the Linux General Purpose Mouse server */
+
+#define GPM_B_LEFT 4
+#define GPM_B_MIDDLE 2
+#define GPM_B_RIGHT 1
+
+/* Xterm mouse support supports only GPM_DOWN and GPM_UP */
+/* If you use others make sure your code also works without them */
+enum Gpm_Etype {
+ GPM_MOVE=1,
+ GPM_DRAG=2, /* exactly one in four is active at a time */
+ GPM_DOWN=4,
+ GPM_UP= 8,
+
+#define GPM_BARE_EVENTS(ev) ((ev)&0xF)
+
+ GPM_SINGLE=16, /* at most one in three is set */
+ GPM_DOUBLE=32,
+ GPM_TRIPLE=64,
+
+ GPM_MFLAG=128, /* motion during click? */
+ GPM_HARD=256 /* if set in the defaultMask, force an already
+ used event to pass over to another handler */
+};
+
+typedef struct Gpm_Event {
+ int buttons, x, y;
+ enum Gpm_Etype type;
+} Gpm_Event;
+
+extern int gpm_fd;
+
+#endif
+
+/* General mouse support definitions */
+
+typedef int (*mouse_h)(Gpm_Event *, void *);
+
+#define NO_MOUSE 0
+#define GPM_MOUSE 1
+#define XTERM_MOUSE 2
+
+void init_mouse (void);
+void shut_mouse (void);
+
+/* Type of mouse: NO_MOUSE, GPM_MOUSE or XTERM_MOUSE */
+extern int use_mouse_p;
+/* If use_mouse_p is XTERM_MOUSE: is mouse currently active? */
+extern int xmouse_flag;
+
+int mouse_handler (Gpm_Event *gpm_event);
+int redo_mouse (Gpm_Event *event);
+
+/* Constants returned from mouse handlers */
+
+#define MOU_NORMAL 0x00
+#define MOU_REPEAT 0x01
+#define MOU_ENDLOOP 0x02
+#define MOU_LOCK 0x04
+
+#ifdef DEBUGMOUSE
+#define DEBUGM(data) fprintf data
+#else
+#define DEBUGM(data)
+#endif
+
+#ifdef HAVE_LIBGPM
+
+/* GPM specific mouse support definitions */
+void show_mouse_pointer (int x, int y);
+
+#else
+
+/* Mouse support definitions for non-GPM mouse */
+#define show_mouse_pointer(a,b)
+
+#endif
+
+#endif /* MC_MOUSE_H */
--- /dev/null
+#ifndef __MYSLANG_H
+#define __MYSLANG_H
+
+#ifdef SLANG_H_INSIDE_SLANG_DIR
+# include <slang/slang.h>
+#else
+# include "slang.h"
+#endif
+
+enum {
+ KEY_BACKSPACE = 400,
+ KEY_END, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT,
+ KEY_HOME, KEY_A1, KEY_C1, KEY_NPAGE, KEY_PPAGE, KEY_IC,
+ KEY_ENTER, KEY_DC, KEY_SCANCEL, KEY_BTAB
+};
+
+#define KEY_F(x) 1000+x
+
+#define ACS_VLINE SLSMG_VLINE_CHAR
+#define ACS_HLINE SLSMG_HLINE_CHAR
+#define ACS_ULCORNER SLSMG_ULCORN_CHAR
+#define ACS_LLCORNER SLSMG_LLCORN_CHAR
+#define ACS_URCORNER SLSMG_URCORN_CHAR
+#define ACS_LRCORNER SLSMG_LRCORN_CHAR
+
+#ifdef OS2_NT
+# define ACS_LTEE 0xC3
+# define acs() ;
+# define noacs() ;
+# define baudrate() 19200
+#else
+# define ACS_LTEE 't'
+# define acs() SLsmg_set_char_set(1)
+# define noacs() SLsmg_set_char_set (0)
+# define baudrate() SLang_TT_Baud_Rate
+#endif
+
+enum {
+ COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW, COLOR_BLUE,
+ COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
+};
+
+/* When using Slang with color, we have all the indexes free but
+ * those defined here (A_BOLD, A_UNDERLINE, A_REVERSE, A_BOLD_REVERSE)
+ */
+#define A_BOLD 0x40
+#define A_UNDERLINE 0x40
+#define A_REVERSE 0x20
+#define A_BOLD_REVERSE 0x21
+
+#ifndef A_NORMAL
+# define A_NORMAL 0x00
+#endif
+
+#define COLOR_PAIR(x) x
+#define ERR -1
+#define TRUE 1
+#define FALSE 0
+
+void slang_set_raw_mode (void);
+
+#define doupdate()
+#define raw() slang_set_raw_mode()
+#define noraw()
+#define nodelay(x,val) set_slang_delay(val)
+#define noecho()
+#define beep() SLtt_beep ()
+#define keypad(scr,value) slang_keypad (value)
+
+#define ungetch(x) SLang_ungetkey(x)
+#define start_color()
+#define touchwin(x) SLsmg_touch_lines(0, LINES)
+#define reset_shell_mode slang_shell_mode
+#define reset_prog_mode slang_prog_mode
+#define flushinp()
+
+void slint_goto (int y, int x);
+void attrset (int color);
+void set_slang_delay (int);
+void slang_init (void);
+void slang_done_screen (void);
+void slang_prog_mode (void);
+void hline (int ch, int len);
+void vline (int ch, int len);
+int getch (void);
+void slang_keypad (int set);
+void slang_shell_mode (void);
+void slang_shutdown (void);
+int has_colors (void);
+/* Internal function prototypes */
+void load_terminfo_keys ();
+
+/* FIXME Clean up this; gnome has nothing to do here */
+#ifndef HAVE_GNOME
+void init_pair (int, char *, char *);
+#endif
+
+/* copied from slcurses.h (MC version 4.0.7) */
+#define move SLsmg_gotorc
+#define clreol SLsmg_erase_eol
+#define printw SLsmg_printf
+#define mvprintw(x, y, z) SLsmg_gotorc(x, y); SLsmg_printf(z)
+#define COLS SLtt_Screen_Cols
+#define LINES SLtt_Screen_Rows
+#define clrtobot SLsmg_erase_eos
+#define clrtoeol SLsmg_erase_eol
+#define standout SLsmg_reverse_video
+#define standend SLsmg_normal_video
+#define addch SLsmg_write_char
+#define addstr SLsmg_write_string
+#define initscr() do { extern int force_ugly_line_drawing; \
+ extern int SLtt_Has_Alt_Charset; \
+ SLtt_get_terminfo (); \
+ if (force_ugly_line_drawing) \
+ SLtt_Has_Alt_Charset = 0; \
+ SLsmg_init_smg (); \
+ } while(0)
+#define refresh SLsmg_refresh
+#define clear SLsmg_cls
+#define erase SLsmg_cls
+#define mvaddstr(y, x, s) SLsmg_gotorc(y, x); SLsmg_write_string(s)
+#define touchline SLsmg_touch_lines
+#define inch SLsmg_char_at
+#define endwin SLsmg_reset_smg
+
+#define SLsmg_draw_double_box(r,c,dr,dc) SLsmg_draw_box ((r), (c), (dr), (dc))
+
+#ifdef OS2_NT
+# define one_vline() addch(ACS_VLINE)
+# define one_hline() addch(ACS_HLINE)
+ /* This is fast, but unusefull if ! pc_system - doesn't use
+ Alt_Char_Pairs [] :( */
+#else
+ /* This is slow, but works well :| */
+# define one_vline() SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), slow_terminal ? ' ' : ACS_VLINE)
+# define one_hline() SLsmg_draw_object (SLsmg_get_row(), SLsmg_get_column(), slow_terminal ? ' ' : ACS_HLINE)
+#endif
+
+void enable_interrupt_key ();
+void disable_interrupt_key ();
+#endif
--- /dev/null
+This patch was written by Janne Kukonlehto (jtklehto@stekt.oulu.fi),
+it adds 8 bit clean support to ncurses 1.8.5
+
+--- ncurses-1.8.5/src/lib_addch.c.old Sun Oct 30 21:03:08 1994
++++ ncurses-1.8.5/src/lib_addch.c Sun Oct 30 21:04:59 1994
+@@ -32,6 +32,13 @@
+ if (y > win->_maxy || x > win->_maxx || y < 0 || x < 0)
+ return(ERR);
+
++ /* Attempt to solve problems caused by
++ sign-extension of eighth bit
++ (this should make ncurses 8-bit clean) */
++ if ((ch & A_ATTRIBUTES) == A_ATTRIBUTES){
++ ch &= A_CHARTEXT;
++ }
++
+ switch (ch&A_CHARTEXT) {
+ case '\t':
+ for (newx = x + (8 - (x & 07)); x < newx; x++)
--- /dev/null
+Fri Jan 16 00:11:20 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * popt.c (poptGetNextOpt, poptReadConfigFile): added missing free
+ and munmap
+
+ * vfs/ftpfs.c: Activated CD_THEN_LS_DOT as default; instead of
+ "LIST path" send the commands "CWD path" and "LIST ."
+
+ * vfs/ftpfs.c (command): First check errno because
+ disable_interrupt_key might change it.
+
+ * vfs/ftpfs.c (resolve_symlink): Finished the CD_THEN_LS_DOT hack.
+ If you activate it you will be able to browse directories containing
+ spaces in their name (that's a compile-time option; search
+ for the define in this file).
+
+ * vfs/ftpfs.c (__ftpfs_chdir): New function; this code is moved from
+ ftpfs_chdir, takes a remote path and for performance reasons it keeps
+ track of previous CWD's.
+
+ * vfs/ftpfs.c: To change directories use __ftp_chdir instead of
+ sending the CWD command.
+
+ * vfs/vfs.c (parse_ls_lga): Added support for symlinks containing
+ spaces (spaces either in the name of the symlink or in the target
+ of the symlink).
+Thu Jan 15 23:09:58 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * color.c (get_two_colors), (configure_colors_string): get two
+ colors now splits the color names instead of brute force text
+ matching. make a copy of the string to be able to patch the
+ string.
+
+ * screen.c (file_compute_color): renamed, old name was
+ normal_color. This is now used by the gnome port as well. The Tk
+ port should be using this too instead of having its own color
+ scheme.
+
+ * color.h: Use PORT_COLOR to choose the color.
+
+ * gscren.c: Compute the proper sizes for the panel columns; Add
+ sorting callbacks for the buttons on the top
+
+Wed Jan 14 22:29:01 1998 Peter Daum <gator@cs.tu-berlin.de>
+
+ * patchfs: added new file system for browsing patch files.
+
+Wed Jan 14 20:54:38 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (parse_display_format, use_display_format):
+ Functionality has been splited now. the former routine only
+ parses the user specified format, while the later parses and
+ activates the format for text mode editions.
+
+ * panel.h (format_e): we now have a couple of extra fields:
+ use_in_gui indicates that this field should be displayed on a GUI
+ (ie, only the text-mode decoration tags are ommited).
+
+ expand field indicates that the field should be expanded.
+
+Wed Jan 14 12:55:19 1998 Sung-Hyun Nam <namsh@lgic.co.kr>
+
+ * mc.tcl: find a user specific 'tkmc' file in the ~/.mc
+
+Tue Jan 13 17:15:21 1998 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * main.c (pre_exec): reset_prog_mode is not called if mc is
+ compiled with SLang. Otherwise, raw_mode in invoke_subshell()
+ may be improperly initialized. In this case Ctrl-O was ignored
+Tue Jan 13 09:08:32 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * widget.c (show_hist): cleaned up; historylist_callback (now removed)
+ replaced with listbox_finish to enable selection with mouse double click
+
+ * wtools.c (create_listbox_window): added comparison of passed width
+ with title and cancel button length. Max value of three is now taken;
+ fixed cancel button xpos calculation.
+
+Sun Jan 11 11:31:39 1998 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * view.[ch]: removed obsoleted macro HEX_EDIT and related code
+ cleaned up.
+
+ * wtools.c (query_dialog): added color to hotkeys in focus
+
+ by subshell on FreeBSD.
+
+ * mouse.h: obsolete code removed. gpm-xterm.h doesn't exist anymore
+
+ * nt/Makefile.NT: sldisply.c is not linked with mc.
+
+ * myslang.h: we don't try to draw double lines for panels anymore
+ because "official" SLang doesn't support them supported for OS/2
+ and NT.
+
+ * doc/mc.sgml: "<tscreen><verb>" should not appear in mc.1 and
+ mc.hlp anymore.
+
+ * layout.c, main.c: "mc -a" is not supported for OS/2 and NT.
+
+ * configure.in: libtermcap is linked only if it is available and
+ needed.
+
+ * vfs/undelfs.c: umode_t is undefined before entering the kernel
+ headers, because the Linux kernel defines its own umode_t
+
+ * key.c: First left mouse click on xterm was interpreted as
+ a right click. Now event->buttons doesn't need to be initialized
+ (exactly as in liblow.c in libgpm)
+
+ * screen.c, key.c: Some routines were surrounded with HAVE_XVIEW.
+ HAVE_X is used instead since that code is not used in Tk and gnome
+ versions either.
+
+Tue Jan 13 11:08:26 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * lib/mc.menu: Bugs fixed caused by quoting the expanded %-macros
+
+Fri Jan 9 20:33:14 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * layout.h (get_other_panel): Define get_current_panel/get_other_panel
+ as macros that use the index stuff we used before. I am getting
+ rid of this.
+
+ * gnome/glayout.c: Gnome code does not link with the layout.c
+ code, we use our own set of routines here.
+
+Fri Jan 9 13:24:22 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/extfs.c (extfs_get_path_from_entry): New function which maps
+ a struct extfs_entry to a local path inside the archive.
+
+ (extfs_open, extfs_close): Use the path to the resolved symlink
+ when making or storing a local copy of a file from the archive
+ (at least the zipfs doesn't follow symlinks).
+
+Thu Jan 8 20:10:23 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c: Moved some edition specific code into the edition
+ specific routines (Tk, XView, Gnome and text).
+
+ * text.c: new file, has some of the text mode edition code bits.
+
+Sat Dec 6 23:24:23 1997 Yuri Kuzmenko <yuri@microsoft.kiev.ua>
+
+ * main.c: added -r command-line option. It removes
+ "The shell is already running a command" message in
+
+Thu Jan 7 14:50:00 1998 Norbert Warmuth <k3190@fh-sw.de>
+ * screen.c (panel_callback): Don't set h->grided to zero. The fix
+ in dlg.c (create_dlg) is sufficient.
+
+
+Wed Jan 7 17:55:40 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+ * dlg.c (create_dlg): Initialize new_d->grided to zero. [ Note:
+ Strange, very very strange, as this is supposedly initialized by
+ x_create_dialog from the D_GRID flag. Mhm, wonder what is going
+ on there ].
+
+Wed Jan 7 17:30:53 1998 Norbert Warmuth <k3190@fh-sw.de>
+ * screen.c (panel_callback): Initialize h->grided to zero.
+
+ * extfs.c: fix crash by using properly quoted file names to the
+ scripts.
+
+ * configure.in: INSTALL_PROGRAM mustn't be set explicitly. configure
+ adapts the path in INSTALL but not in INSTALL_PROGRAM and INSTALL_DATA
+ (adaption of the path is necessary when the compilation tree is
+ different from the source tree and mc/install-sh is used for
+ installation).
+
+Tue Jan 6 18:10:55 1998 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * tkwidget.c (tk_new_command):
+
+ There are two types of dialog boxes in the Tk edition: those that
+ are manually layed out (which have a layout_XXXX routine in
+ mc.tcl) and those that are layed out according to the information
+ generated by the GUI designer (gd.tcl). The layout information
+ for the later are called gui.XXX.tcl, and they contain information
+ used for laying out widgets according to a table.
+
+ Now, dialogs that used the GUI designer, had their widgets labeled
+ (this label was recently used by the history code (and thus, some
+ widgets that did not have name, got names, which means that they
+ will be tried to be layed out with the wrong laying out routine).
+
+ The flag DLG_GRID is used when creating a dialog box that uses the
+ gui designer, so we store this variable now and use it when
+ creating the widgets.
+
+Tue Jan 6 18:07:24 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/edit.c (edit_load_file), editcmd.c (edit_save_as_cmd,
+ edit_save_cmd, edit_quit_cmd): Delete the edited file if we
+ created it in edit_load_file (e.g. mcedit <non-existing-file>)
+ and the file wasn't modified OR it wasn't saved.
+
+ * editcmd.c (my_open, pipe_mail): Deleted the external declaration
+ of errno (errno is delared in errno.h which is already included);
+ deleted the only reference to errno (I can't see it's purpose).
+
+Mon Jan 5 13:11:54 1998 Norbert Warmuth <k3190@fh-sw.de>
+
+ * acconfig.h: Define HAVE_CRYPT when libcrypt or libcrypt_i are
+ available. AC_CHECK_FUNCS(crypt) defines HAVE_CRYPT but
+ AC_CHECK_LIB(crypt, crypt) doesn't (the consequence were login
+ failures with mcserv).
+
+ * configure.in: Define HAVE_SOCKET also when the function socket
+ isn't found in libc but in a other library.
+
+ Don't define HAVE_GETHOSTBYNAME by using AC_CHECK_FUNC instead of
+ AC_CHECK_FUNCS (we don't use this define and to be consistent we
+ would have to do the same as for HAVE_SOCKET and HAVE_CRYPT).
+
+ * doc/mc.in.1, doc/mc.sgml, mc.hlp: Updated the find-file entry
+ (the contents field is interpreted as regular expression).
+
+ * lib/mc.hint: Updated the information for lynx-style navigation.
+
+ * layout.c (layout_cmd): Removed de-reference of NULL-pointer in the
+ XView edition
+
+ * main.c (reload_panelized): Update the panel's summary information
+
+ * popt.c: removed references to alloca
+
+ * widget.c: more changes to prevent mxc from issuing characters
+ on the console
+
+ * vfs/Makefile.in: Install extfs/arfs from the source directory
+ and not from the compilation directory which lacks arfs if both
+ are different directories.
+
+ *vfs/extfs.c: Quote special characters before passing it to pipe.
+
+ (read_extfs_archive): List a symlink as normal file if the extfs-
+ script lists symlinks without providing the destination of the symlink
+ (namely the zipfs caused coredumps)
+
+ * vfs/mcfs.c (mcfs_login_server): Close the socket after and not
+ before it's last use.
+
+ * xv/Makefile.in: Some sourcefiles which depend on HAVE_XVIEW and
+ HAVE_X were not recompiled.
+
+ * xv/xvwidget.c (x_create_gauge): set the PANEL_CLIENT_DATA (other
+ parts of the code depend on it)
+
+ * lib/mc.ext.in: Added entry for ftplist-extfs
+
+ * user.c (expand_format): Added parameter which decides whether
+ expanded %-macros are quoted or not.
+ Adapted every reference to "expand_format" for the additional
+ parameter
+
+ * ext.c (exec_extension): Don't quote the result of expanded %-macros
+ when we use it internally (e.g. the parameters of %cd).
+
+ * util.c (name_quote): Quote backticks.
+
+ (fake_name_quote): New function used by exec_extension (I need this
+ function only because I was too lazy to recode exec_extension
+ completely and wanted to avoid a lot of if-clauses).
+
+ * vfs/extfs/arfs, deb.in: Set LC_ALL to the C locale because we run
+ "date" and expect the output to be formated for this locale.
+
+ * vfs/extfs/*: Removed "eval" from the scripts because it made problems
+ with filenames which contain special characters, e.g. ', "
+
+ * vfs/extfs/ftplist.in: If mc is compiled with "-DWANT_PARSE" you
+ will be able to hit return in order to connect to ftp servers listed
+ in the ftplist-extfs.
+
+ * vfs/extfs/zip.in: Added support for symlinks in zip-files.
+
+Tue Dec 30 15:20:13 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * widget.c (button_new): We no longer require the hotkey and the
+ hotposition arguments, these are automatically computed from an
+ embedded "&" in the button text. This is required for
+ internationalizing the program.
+
+ * achown.c (init_chown_advanced): Adhere to new button_new
+ convention.
+
+ * achown.c, boxes.c, chmod.c, chown.c, file.c, find.c, wtools.c,
+ panelize.c, option.c, listmode.c, learn.c, layout.c, hotlist.c:
+ likewise.
+
+ * wtools.c (query_dialog): Do not use the first character as the
+ hotkey, clients now should use the widget "&" character.
+
+Tue Dec 30 15:06:52 1997 Tomasz K³oczko <kloczek@rudy.mif.pg.gda.pl>
+
+ * edit/: Many small changes preparing for internationalization.
+
+ * doc/: renamed the manual pages to include a .in, the manual
+ pages are now generated by configure.
+
+ * makimg definition INSTALL_PROGRAM depended on
+ --with[out]-debug. Default value INSTALL_PROGRAM is "${INSTALL}
+ -s" (striping binaries on installing), with --with-debug is
+ "${INSTALL}"
+
+ * tk/Makefile.in: Compiling the tk edition on first pass.
+
+ * mc.spec.in: Cosmetic changes.
+
+Tue Dec 30 14:30:09 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * vfs/extfs/arfs: UID and GID shell variables renamed because they
+ are read-only under Linux.
+
+ * configure.in: mxc can be compiled if even libXext is missing.
+
+ * main.c, layout.c: minor changes to prevent tkmc and mxc from
+ issuing some characters on the console. initscr is included into
+ init_curses.
+
+Tue Dec 30 14:28:54 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * view.c (view_hook): Allow viewing links in quick view mode.
+
+Tue Dec 23 13:19:36 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * find.c (find_parameters): Don't quote special characters like (,
+ [ and | in the search string (Note: for egrep name_quote quotes
+ to many characters).
+
+Mon Dec 22 15:28:25 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * screen.c (panel_key, keymap): Alt-H is now only used to center
+ the current selection if torben_fj_mode is on, this allows the
+ history to be used with Alt-h.
+
+Mon Dec 22 15:14:22 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * mc.sgml, mc.1, mcedit.1, mc.hlp, main.c: gray and brightred
+ colors was not mentioned.
+
+ * ext.c: isspace is used instead of comparision with space and
+ tab. MC for NT has working internal viewer again (there was a
+ problem with parsing of mc.ext).
+
+ * find.c: improved look of dialogs for console and XView
+ versions. Hotkeys for edit ('e') and view ('v') work now.
+
+ * tree.c: NULL is no more used in define_label and
+ define_label_data. XView version can show the tree buttonbar
+ (which is not yet useful).
+
+ * many files in edit/, src/, nt/: added config.h where
+ needed. Minor fixes to prevent grp.h and pwd.h from including in
+ OS2 and NT version. Makefile.NT is updated. HAVE_TRACE determines
+ whether tracing in util.debug.c is enabled.
+
+ * utilnt.c: canonicalize_pathname returns value. If MCHOME is not
+ defined, the directory is used, where mc.exe resides
+
+ * nt/drive.c: updated.
+
+ * nt/chmod.c: New button scheme is used.
+
+ * nt/Makefile.NT, nt/Makefile.VC4: updated
+
+ * edit/wordproc.h: include config.h
+
+ * src/widget.c: after changing the label of a button, the dialog
+ is redrawn.
+
+Mon Dec 22 15:12:50 1997 Alexander Romanyuk <alexr@krid.crimea.ua>
+
+ * edit/editcmd.c (edit_refresh_cmd): Use the same refresh code as
+ used in dlg.c
+
+Mon Dec 22 14:56:26 1997 Bakeyev I. Timur timur@goff.comtat.kazan.su
+
+ * editcmd.c, editoptions.c: adjusted the buttons locations to work
+ with the new button code.
+
+Mon Dec 22 14:43:16 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * layout.c (setup_panels): If the keybar is not visible, then
+ reduce the size of the command input line.
+
+ * ChangeLog: went back to old date format, I get confused with the
+ new date specification. To make your emacs 20 work like this set:
+
+ (setq add-log-time-format 'current-time-string)
+
+Mon Dec 22 14:43:16 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * ext.c (FILE_CMD): Removed -- when invoking file because the file
+ command shipped with sco doesn't support the -- option
+
+ * util.c (name_quote): Names beginning with a dash will be prepended
+ with ./
+
+Sun Dec 21 00:00:00 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * cons.saver.c (detect_console): Do not check for root privileges.
+ Newer versions of Linux have a /dev/vcs, which should have the
+ user id permissions set correctly by login.
+
+1997-12-20 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * docs: Updated Ching Hui's address to his new address:
+ mr854307@cs.nthu.edu.tw
+
+ * Added Norbert to some files, not complete though.
+
+1997-12-19 Norbert Warmuth <k3190@fh-sw.de>
+
+ * popt.h (poptStrerror): Added workaround for systems lacking
+ strerror
+
+1997-12-17 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * ext.c (FILE_CMD): Include a -- when invoking file to avoid it
+ interpreting dashes on the filenames.
+
+1997-12-19 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c (handle_args): Do not depend on optarg
+
+1997-12-17 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c (do_nc): Fixed wrong parameter count ('edit' takes two
+ parameters)
+
+1997-12-21 Paul Sheer <psheer@icon.co.za>
+
+ * editcmd.c: Some dialog boxes did not have tknames for the
+ input histories. I've now check all the input widgets and all
+ seem to have adequite (i.e. unique) tknames.
+
+ * widget.c: Added a button to all input widgets that have a
+ reasonable width. You have a choice of two styles determined by
+ LARGE_HISTORY_BUTTON at compile time. I have set this to larger
+ style: [^] as apposed to the smaller style: ^ i.e. a button
+ with an up arrow in it instead of just an arrow. I still am not
+ sure of the color scheme everyone would prefer. Should the
+ history button be the same as a regular button? This is
+ extremely cool, because even the commandline has a little button
+ to the right which you can click on for an input history.
+
+ * widget.c: input history listboxes that appear above the widget
+ now have the last line selected (most recent input) instead of
+ the first line (oldest input).
+
+ * whats with the new date style?
+
+1997-12-16 Norbert Warmuth <k3190@fh-sw.de>
+
+ * configure.in: check for ext2fs/ext2fs.h and linux/ext2_fs.h
+ before enabling the undelfs (libext2fs alone isn't sufficient
+ for a successful compile of the file recovery code).
+ $withval isn't processed yet, i.e. --with-ext2undel and
+ --with-ext2undel=/usr/src/ext2fs are the same.
+
+ * edit/edit.c (edit): Added parameter, now it's possible to invoke
+ the internal editor and jump to the passed linenumber
+
+ * lib/mc.ext.in: removed the quotes which surrounded the %-macros
+
+ * cmd.c (do_edit_at_line): invoke the editor and in case of the
+ internal editor jump to the passed linenumber.
+
+ * ext.c (exec_extension), find.c (find_par_start), main.c (copy_tagged,
+ copy_prog_name), view.c (load_view_file): Added calls to name_quote
+ where appropiate, i.e. everything which is passed to the commandline
+ of a shell is passed to name_quote first
+
+ * file.c (find_file): Added a button to invoke the editor from
+ the results dialog.
+
+ * subshell.c (quote_directory): deleted
+
+ (do_subshell_chdir): use name_quote instead of quote_directory
+
+ * user.c (expand_format): pass expanded parameters to name_quote
+
+ * util.c (name_quote): prefix characters with special meaning to
+ the shell with '\' (I fear the current implementation is highly bash
+ specific);
+ when requested by the caller double percent signs (that's needed
+ when copying filenames to MC's commandline)
+
+ * tk/gui.mfind.tcl: Added button to invoke the editor
+
+Mon Dec 22 11:21:17 1997 Bakeyev I. Timur timur@goff.comtat.kazan.su
+
+ * widget.c (button_new): Change number of parameters in function call.
+ Now, You need just specify button type and pure label name, without
+ ugly spaces and brackets. This allows to reuse same button name under X
+ versions of MC.
+
+ * button_callback: Add code, that draw proper button, dependently of
+ it's type.
+
+ * widget.h: Add constants for new types.
+
+ * query_dialog: Changes to handle new buttons, style overwritting.
+
+ * quick_dialog: Apropriate changes to show new buttons correctly, style
+ changing, ability to have default button.
+
+ * Mostly all dialog boxes was rewritten, to make their look similar
+ and a bit smoother :).
+
+1997-12-16 Paul Sheer (psheer@icon.co.za)
+
+ * widget.c (history_put): Check for a tkname in a couple of extra
+ places.
+
+1997-12-16 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * src/popt.c: Include config.h to get the HAVE_MMAP definition.
+
+1997-12-15 Miguel de Icaza <miguel@metropolis.nuclecu.unam.mx>
+
+ * file.c (file_mask_dialog):
+
+1997-12-15 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * edit/editcmd.c: Provide tknames for the quick input lines
+ on for search/replace and for the mail dialogs.
+
+ * src/widget.c (history_put): Do not manipulate the history for an
+ input line that lacks a tkname.
+
+ * panel.h, screen.c (parse_display_format): Keep track of the
+ number of columns on the format.
+
+ * gscreen.c: Use GtkClist widget for representing the file
+ listing.
+
+1997-12-13 Paul Sheer (psheer@icon.co.za)
+
+ * src/widget.c: Add support for input line history
+ saving/restoring.
+
+ * src/profile.c: add translate/untralste routines (required for
+ avoding the case where a newline is saved as part of the history
+ routines).
+
+ Paul sent this as '\0200', I changed it to '\\', even if he told
+ me that it could have problems with Windows :-). Blame me, not
+ him for this change.
+
+ * src/setup.c: Keep track of the number of history items stored.
+
+ * src/command.c: add a tkname to the input line.
+ * src/file.c: add tknames for all of the input lines
+ * src/wtools.c: likewise.
+
+Thu Dec 11 11:37:47 1997 Alex I. Tkachenko (alex@bcs.zp.ua)
+
+ * src/view.c (load_view_file): remove unused variable;
+ seek to the beginning of the file (since it gets advanced by the
+ zip-figure out routine).
+
+Wed Dec 10 10:28:44 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * widget.c (button_len): New function. Dependent of the type of
+ button (NORMAL_BUTTON, NARROW_BUTTON, DEFPUSH_BUTTON,
+ HIDDEN_BUTTON) calculate the amount of characters the button label
+ occupies.
+
+ (button_new, button_settext): use button_len instead of strlen.
+
+ * main.c (handle_args): There were still references to variables
+ specific to getopt - replaced with the corresponding popt function
+ calls.
+
+ * dlg.c (frontend_run_dlg): changed the call to get_event because now
+ it takes an additional parameter
+
+ * file.c (update_buttons): deleted
+
+ (check_buttons): Completly rewritten - check mouse and key events
+ nonblocking and process available events with the dialog manager.
+
+ (create_op_win): Added "Skip" and "Abort" buttons. Previously we
+ handled these buttons completely without the dialog manager, i.e.
+ these buttons looked like buttons but we displayed them with addstr
+ and processed events (only keypresses) ourself.
+ Now these buttons can be selected with the mouse.
+
+ (file_mask_dialog): Changed the order in which the checkbuttons are
+ added to the dialog. Now when pressing tab the selection goes round
+ and round (Timur did a terrific job in fixing all the other dialogs).
+
+ * key.c (get_event): Added parameter to make it possible to select
+ blocking or non-blocking behaviour (This change breaks the OS2 and NT
+ version, sorry).
+ I need the non-blocking behaviour in check_buttons. Previously it
+ was only possible to check non-blocking for keypresses.
+
+ * key.h: changed declaration of get_event
+
+ * tk/gui.quick_file_mask_copy.tcl: Changed the order of the
+ checkbuttons
+
+Wed Dec 10 10:19:52 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * gnome/Makefile.in: popt.c is compiled with the gnome version
+ gwidget.c: clean_button is not needed anymore
+
+ * user.c: filename of the global menu is calculated using
+ concat_dir_and_file instead of copy_strings
+
+ * configure.in: use lynx if no browser for X is found
+ lib/mc.ext.in: mc uses the best browser available
+
+
+Mon Dec 8 07:20:34 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * configure.in: allow to remove support for ext2-undel file system
+Sat Dec 13 17:15:32 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/edit.c, edit/*.c: updated editor code to match cooledit
+ sources.
+
+ * editoptions.c: Nice options dialog box.
+
+ * wordproc.c: wordprocessor like paragraph formatting for the
+ editor.
+
+Fri Dec 5 23:13:30 1997 Yuri Kuzmenko <yuri@cracksoft.kiev.ua>
+
+ * find.c: fix the bug with unsaved in_contents field
+
+Fri Dec 5 07:23:34 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c (do_execute): Don't advice the subshell to chdir into
+ non-local virtual filesystems.
+
+ (do_panel_cd): Stop filename search (C-s) when the directory is
+ changed.
+
+ (print_usage): this_dir and other_panel_dir were listed in
+ the wrong order.
+
+ (handle_args): The transition from getopt to popt wasn't complete (e.g
+ with "mc -u -s" this_dir and other_panel_dir were set to "-u"
+ and "-s").
+
+Mon Dec 1 05:35:00 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * cmd.c (menu_edit_cmd): use concat_dir_and_file instead of
+ copy_strings
+
+ * util.c (set_int): enlarged the temporary buffer because the
+ ascii representation of an integer value can be greater than
+ five chars.
+
+ * file.c (file_mask_defaults): New function which sets the global
+ variables used by the copy and move file routines to a reasonable
+ default. Use file_mask_defaults when you don't want to call the
+ interactive file_mask_dialog.
+ Note: I know that always setting preserve_uidgid is redundant
+ for non-root when we keep the change in setup.c but I like it
+ this way better (everything set in one function without making
+ assumptions).
+
+ * setup.c (load_setup): removed the check for preserve_uidgid
+ which isn't longer necessary
+
+ * cmd.c (check_for_default), tree.c (tree_copy, tree_move): call
+ the new file_mask_defaults
+
+Mon Dec 1 05:47:17 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * cmd.c (ext_cmd): use proper filenames for ~ and $MCLIB
+
+ * ext.c: likewise.
+
+Mon Dec 1 05:14:41 1997 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * popt.c: If mmap is not available, read the configuration file
+ into memory.
+
+Sun Nov 30 18:11:18 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c: Tell the user about the new location of his
+ configuration files.
+
+ * subshell.c (init_subshell): Use .bashrc if the .mc/bashrc file
+ does not exist.
+
+ * user.c (user_menu_cmd): Cleaned up the menu filenames.
+
+Fri Nov 28 12:38:39 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c (print_usage): Include the long options now on the
+ listing.
+
+ * mc.1, mc.sgml: Updated docs to new pathnames; Unformized usage
+ of the $HOME and ~ usage in the docs.
+
+ * user.h (MC_MENU), main.h (MC_BASE), ext.h, ext.c, main.c,
+ tree.h, cmd.c, main.c (do_compatibility_move): Move the midnight
+ commander specific files into ~/.mc.
+
+Thu Nov 27 22:07:34 1997 Erik Troan <ewt@redhat.com>
+
+ * src/popt.c, src/popt.h: New files, long options argument parsing
+ module.
+
+ * src/main.c: Implement long options.
+
+Thu Nov 27 19:14:33 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * main.c (prepend_cwd): Prepend the directory only if the pathname
+ is a local pathname.
+
+ * configure.in: autodetect the ext2lib.
+
+ * mc.tcl: catch tk_popup output, there is a bug in tk 8.0
+
+ * util.c (get_current_wd): Replace HAVE_VFS with USE_VFS, thanks
+ to Pavel for submiting the relevant information.
+
+Thu Nov 27 19:05:12 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * boxes.c: very small patch for src/boxes.c Some array was
+ incorrectly initialized, XV_WLAY_DONTCARE was at a wrong position.
+
+Thu Nov 27 11:48:06 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/tar.c (load_compressed_tar): Allocate the memory for the
+ uncompressed tar file after mc_doublepopen, i.e. when forking MC's
+ process size will be much lower (that's a win on systems without
+ memory over-commitment); Make a memory hole in size of 100k which
+ enlarges on some system the chance that free can give back memory
+ to the operating system when the memory for the tar file is freed.
+
+Wed Nov 26 11:16:01 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * src/background.c, cons.handler.c, utilunix.c, extfs.c, tar.c:
+ Include sys/wait.h only if HAVE_SYS_WAIT_H is defined.
+
+ * Makefile.NT, Makefile.VC4: Updated
+
+Mon Nov 24 16:48:16 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * file.c (copy_file_file): "preserve Attributes" didn't work when
+ fetching files with ftp.
+
+ * utilunix.c (init_groups): Check the return value of getpwuid(),
+ it can be NULL.
+
+Fri Nov 21 18:08:54 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * view.c: Double escape on save dialog was save old changes. Now
+ it cancels quit.
+
+ * key.c: get_key_code() returns ERR in tkmc version. This
+ preventsome SLang functions from linking with tkmc.
+
+ * subshell.c: mc warns about unsuccessful directory change in
+ messagebox, not via fprintf().
+
+ * help.h: help_follow_link() is declared here to prevent a warning
+ when compiling mxc.
+
+ * tkmain.c: spelling error corrected. Internal viewer is
+ incomplete, but does work.
+
+Fri Nov 21 16:46:44 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * mountlist.c: For BSDI: Assume BSDI 2.1 if MOUNT_UFS is defined.
+ xBSD mustn't be defined to compile MC on BSDI 2.1. Moved all
+ defines after the include files.
+
+Thu Nov 13 12:24:23 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * find.c: fix the bug introduces by Pavel's fix. Goto a directory
+ which contains more files than the number of files which fit into
+ the panel, select the last file, find one file, panelize the
+ search result and voila - coredump.
+
+ * lib/mc.ext.in: added support for word2x and catdoc (disabled);
+ I'm not sure about the icon.
+
+Wed Nov 19 12:51:51 1997 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * setup.c (load_setup) ignoring preserve_uidgid config option
+ if called by non-root option.
+
+ * doc/mc.1 doc/mc.sgml added notes for local menu files.
+
+Tue Nov 11 11:51:57 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * file.c (make_symlink): If the option Stable Symlinks is enabled
+ and either source or destination directory is on a non-local filesystem
+ an error message will be displayed and stable symlinks will be disabled.
+ Previously the error message was displayed for every symlink and
+ no link was created at the target directory.
+
+ * vfs/ftp.c (open_command_connection, resolve_symlink, retrieve_dir):
+ Added an unique inode number generator to avoid problems with the
+ cyclic link detection while copying files.
+
+Mon Nov 10 21:41:53 1997 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * dlg.c: Cleaned up the generic dlg code from backend specific
+ bits.
+
+ * gmain.c, gwidget.c: GNOME versions of the main and widget bits.
+
+Mon Nov 10 20:10:01 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * file.h: added missing declaration for erase_file
+
+ * find.c: try_to_select is not called if the find window is
+ canceled.
+
+ * configure.in: support for using --without-gpm-mouse;
+ --with-gpm-mouse forces support for gpm.
+
+ * learn.c: MC crashed sometimes in the learn dialog because some
+ memory block was freed twice. Now fixed.
+
+ * tree.h, tree.c: tree_rescan_cmd is now void, no cast is needed.
+
+ * xv/Makefile.in: Target libedit.a was included twice. make
+ install tried to run mxc after installing.
+
+ * xv/xvicon.c, xv/xvscreen.c: ext.h is included for
+ regex_command. Old-style calls of regex_command are corrected.
+
+ * tk/mc.tcl: Procedure center_win was buggy. Requested width was
+ used as heigth and vice versa. Notably, viewer was incorrectly
+ "centered".
+
+ * 10) view.c: Debug printing in tk version is removed.
+
+Mon Nov 10 11:34:57 1997 Alex I. Tkachenko alex@bcs.zp.ua
+
+ * user.c: (user_menu_cmd) added possibility to use user-defined
+ menu from current directory first. Local menus are used only if
+ owned by user or root and are not group and world-writable.
+
+ * cmd.c: (menu_edit_cmd) reorganized to allow local menu editing
+ via pull-down menus. After editing local menu file it is assigned mode
+ 0600.
+
+ * cmd.c: (compare_files) added code for thorough file comparison
+ by reading them by BUFSIZ blocks. compare_dirs_cmd - removed #ifdef's
+ for HAVE_MMAP, because everyone now can check file byte by byte.
+
+Fri Nov 7 17:52:55 1997 Bakeyev I. Timur timur@goff.comtat.kazan.su
+
+ * panel.h/screen.c: Changed highlight_mode variable to 2 separate
+ permission_mode and filetype_mode.
+
+ * setup.c: The same change for saving/restoring new variables.
+
+ * layout.c: Added 2 chechboxes to "Layout.." menu, to visualize
+ new variables changings.
+
+
+Fri Nov 7 13:37:54 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * tk/Makefile.in: gui.quick_file_mask_copy.tcl was listed twice
+ in the variable GUIS.
+
+Thu Nov 6 11:39:24 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * lib/mc.ext.in: When calling lynx use %f instead of %p. %p fails
+ for non-anonymous ftp and we have to make a local copy anyways
+ because %f is used.
+
+ * slang/slang.h: Removed the definition of REAL_UNIX_SYSTEM for
+ AIX. It's not necessary any longer because the previous #ifdef
+ defines already REAL_UNIX_SYSTEM (if "unix" isn't defined it will
+ be defined in config.h).
+ That's a patch I haven't tested but I'm really sure it will not
+ break compile for AIX ;-).
+
+ * slang/slutty.c: The translation of return-value-from-cfgetospeed
+ to baud-rate was made with assumptions about the value of symbolic
+ constants (B0 is defined to 0, B50 to 1, B75 to 2, ...). This assumption
+ is wrong for BSDI. There was already a fix for this problem but
+ I made a more generic and IMO better fix.
+
+ (speed_t2baud_rate): New function. Translate the symbolic constants
+ B0, B50, B75, ... to the actual baud rate.
+
+ * hotlist.c (hotlist_button_callback): After moving entries the
+ hostlist wasn't marked as modified, i.e. it wasn't saved.
+
+ * util.c (is_gunzipable): added recognition of BZIP headers
+
+ * file.c (copy_file_file): chmod and utime was called on the
+ destination file even if it couldn't be created or when it was
+ read-only
+
+ * file.c (move_dir_dir, copy_dir_dir): When moving files cross
+ filesystem boundaries don't erase subdirectories unconditional,
+ erase only files which were copied successful.
+ Added an parameter to copy_dir_dir to indicate wheather successful
+ copied files should be added to a linked list (to be deleted by
+ move_dir_dir when the subdirectory was copied completly) or whether
+ successful copied files should be deleted immediatly (that's
+ implemented but not tested and there's no checkbox to activate it;
+ I will delete this piece of code if I can't find a place and name for
+ this option)
+
+ (erase_dir_iff_empty): New function. Delete an empty directory, don't
+ report an error if the directory isn't empty.
+
+ * utilunix.c (errno_dir_not_empty): use of errno was wrong, use err
+ instead.
+
+Tue Nov 4 17:52:39 1997 Michael K. Johnson <johnsonm@redhat.com>
+
+ * vfs/mcserv.c: PAM code updated.
+
+Tue Nov 4 13:01:52 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * util.c (decompress_command_and_arg, decompress_command): new
+ commands that return the command that should be invoked to
+ decompress a file.
+
+ (is_gunzipable): return the compression type.
+
+ * tkkey.c (delete_select_channel): Moved the Tk key code.
+
+ * tkscreen.c: Make it work/compile with Tk 7 and Tk 8.
+
+ (show_dir): Do not invoke the widget commands if the widget has
+ not been realized yet.
+
+Wed Oct 29 14:06:48 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/extfs/rpm: We set LC_TIME back to C but the order in which
+ the environment variables are checked is this: LC_ALL, LC_CTYPE,
+ LANG. This means if you set LC_ALL the setting of LC_CTYPE has no
+ effect.
+
+Thu Oct 23 02:07:26 1997 mc@timur.kazan.su (Bakeyev I. Timur)
+
+ * boxes.c: Changes in "Listing mode" dialog box for handling 4
+ different user defined status lines, for each viewing type res-
+ pectively.
+
+ * panel.h (WPanel): Add an array of strings to handle different
+ status lines.
+
+ * setup.c (panel_save_setup/panel_load_setup): Some additions,
+ with the same purpose. Allows to save/load 4 user status lines.
+ (See above).
+
+ * screen.c (panel_update_format/set_panel_format): This functions
+ was changed to new one - set_panel_formats() due doubling the code.
+ Also improve error handling in seting new formats.
+
+ * main.c (listing_cmd), layout.c (panel_do_cols): Made apropriate
+ changes to use new set_panel_formats() instead of old ones. Clean error
+ handling in main.c - it was so buggy :) (My fault - allows to break
+ format strings and get fine blue panels after loading :).
+
+ * screen.c: Some changes to handle new feature - different status lines,
+ code cleanup.
+
+ * color.c, color.h: Delete sel_mark_color array - isn't necessary now.
+
+ * tree.c, rxvt.c: Supprese some compilation warnings.
+
+Thu Oct 1 03:22:02 1997 mc@timur.kazan.su (Bakeyev I. Timur)
+
+ * files.c: Improve look of copy/move dialog. Fix screen breaks on
+ long directory filenames. Some other beautify :)
+
+ * boxes.c: Slightly chaneged some buttons positions, order, names :)
+ Make dialogs look more standart. Little cleanups.
+
+Mon Oct 27 13:26:55 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * slint.c (slang_init): On BSD based systems ignore the C-y and
+ C-v special control characters.
+
+Mon Oct 27 13:24:28 1997 Steven N. Hirsch <shirsch@ibm.net>
+
+ * file.c: Restored the old defaults for attributes and follow
+ links: op_follow_links set to zero; op_preserve set to one.
+
+Fri Oct 24 12:50:56 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/editcmd.c (my_open): Deleted the extern declaration of errno.
+ It's bad habit to declare errno in the source file instead of
+ adding the correct include file. And it's wrong for multi threaded
+ applications [heh, got this patch twice ]
+
+ * chwon.c (chown_cmd): getpwnam and getgrnam may return NULL if
+ <Unknown> is selected. This was the last place in the code where
+ the return values of this two functions were used without check.
+
+ * tree.c (pathcmp): Added comments and a slightly improvement in
+ speed which was suggested by "D. Hugh Redelmeier" <hugh@mimosa.com>.
+
+ * wtools.c (query_dialog): Skip '[' when searching for a hotkey.
+ The rename of buttons e.g. from " Yes " to "[ Yes ]" made some
+ hotkeys disappear.
+
+Thu Oct 23 10:44:57 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * doc/mc.1, doc/mc.sgml, src/mc.hlp: updated in order to reflect MC's
+ new behaviour when copying files
+
+ * background.c (real_message_[123]s): Added the OperationMode
+ (foreground/background) to the list of passed parameters.
+ background_attention called these functions already with an
+ additional parameter. It was passed as *first* parameter but
+ the compiler couldn't find the wrong parameter passing because
+ the function call was made indirectly by a function pointer.
+ Prefix the title of dialog boxes for messages from the background
+ process with " Background process:"
+
+ * background.c (message_[123]s): Call real_message_[123]s with the
+ additional parameter.
+
+ * file.c: A lot of changes to make MC behave (as default) the same
+ way as cp -R does. The new defaults:
+ - respect the umask
+ - follow links: dereference symlinks and hardlinks, new: follow
+ links to directories;
+ follow links can be toggled for the source of copy with the option
+ "follow links", it is always activated for the destination
+ - don't preserve file date, file mode, UIDs, GIDs
+
+ Note: the old defaults were:
+ - don't respect the umask at all
+ - don't follow symlinks (links in subdirectories were never followed
+ even if the option "follow symlinks" was set)
+ - always try to duplicate hardlinks as hardlinks
+ - always preserve filemode and date of copied files
+
+ Renamed the option "preserve UIDs/GIDs" to "preserve Attibutes"
+ (anyone a better suggestion??). If set it means
+ - preserve filemode and filedate for non-root and
+ - preserve filemode, filedate and UIDs/GIDs for root.
+
+ New features:
+ - follow symlinks to directories
+ - detect cyclyc symbolic links
+ - detect when directories are copied into itself (it's better not
+ to copy infinitly)
+ - stable symlinks when moving files works
+ - don't try to make stable symlinks across non-local filesystems
+
+ * file.c (make_symlink): New function (cut out of copy_file_file)
+ used to make symlinks resp. stable symlinks.
+
+ * file.c (copy_file_file, copy_dir_dir): exchanged the calls to
+ chown and chmod because chown might alter the file permissions.
+
+ * file.c (file_mask_dialog): Removed options without effect from
+ the file-move dialog (the old "follow symlinks", "preserve UIDs/GIDs").
+ Now there are two different dialogs: file-move and file-copy (formerly
+ the dialogs differed for root and non-root)
+
+ * tk/gui.quick_file_mask.tcl, tk/gui.quick_file_mask_move.tcl: New
+ files
+
+ * tk/gui.quick_file_mask.tcl: deleted
+
+Mon Oct 20 18:11:39 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * slang/slutty.c (SLang_init_tty): Don't use fileno(stderr) for
+ terminal input. It may hang MC when viewing files (exact: when between
+ calls to open_error_pipe and close_error_pipe we try to get some
+ terminal input with SLang_getkey)
+
+ * slint.c (slang_init): An independent fix for the same problem
+ (needed when MC is linked against a slang library which was
+ not built with the sources we ship with MC).
+
+ * key.c (init_key_input_fd): New function. Due to constraints in
+ the flow of execution I had to split init_key. init_key has to be
+ called before slint_init but a short piece of keyboard initialization
+ has to be done after the call of slint_init).
+ Also fixed: Since 4.0.8 it was also possible that we called
+ select on different file descriptors to see whether there is
+ new terminal input available.
+
+Mon Oct 20 18:05:00 1997 Manuel Sugawara <masm@deprof.fciencias.unam.mx>
+
+ * edit/editcmd.c: add #include <errno.h>
+
+Mon Oct 20 14:45:50 1997 Cezary Sliwa <sliwa@blue.cft.edu.pl>
+
+ * vfs/vfs.c (vfs_setup_wd): The bug in vfs_setup_wd caused "Couldn't
+ change to ." messages, particularly when starting mc from '/'.
+ Notice that an empty string in current_dir is equivalent to "/"
+ (see vfs_canon), while after bare 'cd'p you're at home (see
+ do_subshell_chdir).
+
+ * src/subshell.c (quote_directory): Handle more cases.
+
+Sun Oct 19 10:26:43 1997 Paul Sheer
+
+ * editcmd.c: last_search for forward replace doesn't decrement
+ even when a replace with a smaller word shortens the file - fixed.
+
+
+Fri Oct 17 22:02:12 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * color.h: When not compiling with SLang use MARKED_SLECTED_COLORS
+ from version 4.1.4 because the change in 4.1.5 is only applicable
+ when compiling with SLang.
+
+ * vfs/extfs.c (read_extfs_archive): On failure there were two
+ missing calls to pclose
+
+ * xv/Makefile.in: The new xpm-files in 4.1.5 were not added to
+ Makefile.in. The result was that these files were missing in 4.1.5
+
+
+Thu Oct 9 13:22:43 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * editcmd.c (edit_load_macro_cmd): The macro-file was closed twice.
+ Made it more robust against defective macro files, e.g. delete one
+ non-space in the macro file and the rest of the file is skipped.
+ That's IMO still not very good error handling but better than the
+ endless loop we got before (to get the endless loop you had to delete
+ chars at the right side of the colon).
+ I hope this patch will also fix the bug reported by Paul Seelig
+ <pseelig@goofy.zdv.Uni-Mainz.de>. Thanks for the help with debugging,
+ Paul.
+
+
+Mon Oct 6 11:59:00 1997 bill@kayhay.com (Bill Davidson)
+
+ *xv/xvmain.c (get_panel_color): Instead of passing this function a
+ color map segment, we pass it a pointer to an Xv_Singlecolor,
+ which we fill in.
+
+ *xv/xvmain.c (xtoolkit_init): Set up an array of
+ Xv_Singlecolor before calling get_panel_color(). Use this in
+ creating a color map segment which is NOT a dynamic CMS. Use
+ pixmaps to create the icons at defaultDepth.
+
+ *xv/xvmain.c (x_create_panel_container): Use pixmaps to create
+ icons.
+
+ *xv/xvinfo.c (x_setup_info): Use pixmap for mc_icon at defaultDepth.
+
+ *xv/xvscreen.c (copymove_in_panel): Return type is void.
+
+ *xv/xvscreen.c (user_drop): Return type is void.
+
+ *xv/xvview.c (textsw_notify): Return type is void.
+
+ *xv/xvview.c (create_frame): Added Quit button.
+
+ *xv/xvview.c (x_quit_cmd): New function, callback for Quit button.
+
+ *xv/pictures.h : dropped trailing commas from arrays.
+
+ *xv/panel_icon.xpm: New file, defines panel_icon_xpm[].
+
+ *xv/mc_icon.xpm: New file, defines mc_icon_xpm[].
+
+ *xv/mc.icon: Cleaned up trailing commas, added null
+ termination to mc_colors.
+
+ *xv/Regular.xpm: New file, defines Regular_xpm[].
+
+ *xv/Directory.xpm: New file, defines Directory_xpm[].
+
+Tue Oct 7 21:53:57 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/edit.c, edit/editcmd.c, edit/editwidget.c,
+ edit/editmenu.c: updated the editor files to match the
+ X version. This gives the editor backwards search and
+ replace. Also, a mail command was added to mail the edit
+ buffer.
+
+Thu Oct 2 12:37:00 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * view.c: F17 works as "Next search". Improved look of the
+ save dialog. Suppressed some warning about "incompatible
+ pointer type"
+
+ * cmd.c: Improved look of some dialogs (Mkdir, Filter, Filtered
+ view)
+
+Wed Oct 1 11:25:49 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * learn.c (learn_button): The old code was wrong because `*seq <
+ 32 && *seq > 126' is always false. Now it is not possible to
+ redefine characters from space to ~ (I think that's the range we
+ should exclude from redefinition of single characters).
+
+Mon Sep 22 12:35:53 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * aclocal.m4 (fp_PROG_CC_STDC): Removed all the checks but the one
+ for HP-UX. I took over this macro from other gnu software without
+ further investigation but it broke compilation with the native
+ compiler on some systems (e.g. AIX). Now I take the opposite
+ approach and add flags only when I definitly know they are needed.
+ At the moment that's only for HP-UX the case. When we know that
+ some compiler need special flags we can add them later again.
+
+Tue Sep 16 16:39:39 1997 Pavel Roskin <pavel.roskin@ecsoft.co.uk>
+
+ * src/main.c: Pressing of "tab" correctly refreshes the command
+ prompt.
+
+ * configure.in: Syntax error is corrected (function AC_CHECK_LIB).
+ Work-around for autoconf-2.12 bug is proposed. Two lines are just
+ changed.
+
+Thu Sep 11 12:11:03 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs/ftpfs.c (login_server): Handle servers that do not ask for a
+ password.
+
+Thu Sep 11 12:09:26 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * tree.h: Deleted check_sublevel from WTree's definition because
+ it's not needed to recognice whether directory B is subdirectory
+ of directory A (e.g. "/usr/src" and "/usr").
+
+ * tree.c (pathcmp): New function ('strcmp for directories'). strcmp
+ gives the wrong result in a few cases
+ e.g. for strcmp ("mc/src", "mc.orig/src")
+
+ * tree.c (tree_append_entry): Commented out and replaced with
+ tree_add_entry to avoid strange results when an old (wrong sorted)
+ .mc.tree-file is loaded. The negative effect is that it takes now
+ a few us longer to display the tree the very first time.
+
+ * tree.c (tree_copy, tree_move): The input dialog was a little
+ bit to wide for 80-column-terminals.
+
+ * tree.c (tree_callback): Disabled function-key F7 because mkdir
+ is defunct in the directory tree.
+
+ * tk/Makefile.in: Moved mad.o from OOBJ to LOBJ in order to stop
+ bash (>= 2.0??) from complaining at the 'links' target.
+
+Fri Sep 5 10:03:41 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * file.c (check_buttons): Discard mouse events. Pressing the left
+ mouse button caused abort of file operations when MC was run in a
+ XTerm.
+
+Thu Sep 4 12:08:53 1997 Matthias Moeller <mattes@ice.robin.de>
+
+ * vfs/tar.c: From time to time MC isn't recognizing symlinks while
+ extracting an archive. This is especially the case for some
+ archives not built with GNU-Tar (e.g. the cdrecord archive).
+
+ These archives don't set the symlink-flag in the header->mode
+ field, but only the header->linkflag to LF_SYMLINK. The original
+ GNU-Tar has no problems extracting these archives.
+
+Thu Sep 4 12:06:44 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * aclocal.m4 (fp_PROG_CC_STDC): The SVR4 option -Xc is also a valid
+ option for Unixware 2.1. But it turnes some useful extensions off
+ which are on by default. I extented the macro to avoid this.
+
+ * main.c (handle_args): New option -k to enable reset of HP softkeys
+
+ * slint.c (slang_reset_softkeys): New function only useful with HP
+ terminals which program the function keys. It is activated with the -k
+ commandline option. Thanks to GianPiero Puccioni <gip@fox.ino.it>
+ for testing.
+
+ * slint.c (getch): Removed the DEC_8BIT_HACK completely because I
+ think we don't need it. The initial motivation behind this hack has
+ to do with VTxxx terminal which are in eight bit mode and use some
+ characters between 128 and 159 as control characters. We can control
+ with the display-bits dialog which characters are displayed and so
+ I think we don't need the DEC_8BIT_HACK (it can break the mouse in
+ XTerms when buttons are pressed and the position is in either direction
+ between 128 and 159).
+
+ * vfs/tar.c (read_header): Some tar-files contain symbolic links
+ without S_IFLNK set in the mode field. I don't know whether this is
+ a feature or a bug but I use the header's linkflag to add the missing
+ information to the mode field (same for S_IFCHR, S_IFBLK and S_IFIFO
+ but I'm not really sure if this is necessary).
+
+Wed Aug 27 22:33:42 1997 mc@timur.kazan.su (Bakeyev I. Timur)
+
+ * screen.c (panel_new): Use DEFAULT_USER_FORMAT:
+
+ * mc.sgml: fix typos.
+
+Thu Aug 28 10:38:40 1997 Liviu Daia <daia@stoilow.imar.ro>
+
+ * util.c (icase_search): searching in the internal viewer didn't
+ find patterns containing troff formating sequences - fixed.
+
+ * view.c (regexp_view_search): replaced re_search() and
+ re_match() with a single call to regexec().
+
+ * view.c (regexp_view_search): made regexp matching case
+ sensitive only when the search pattern contains upper case
+ characters - new.
+
+Thu Aug 28 19:22:54 1997 Liviu Daia <daia@stoilow.imar.ro>
+
+ * edit/editcmd.c: separated searching by regexp from the scanf
+ stuff.
+
+ * edit/editcmd.c: Regexp search recognized ^ only if it was the
+ first character in the pattern - fixed.
+
+ * edit/editcmd.c: Regexp search didn't handle empty patterns
+ correctly - fixed.
+
+Wed Aug 20 17:29:12 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c (setup_dummy_mc): Setup a more complete MC for mcedit
+ and mc -v to avoid coredumps on screen resize. I think that's
+ the best way to handle this bug.
+
+ * view.c (do_view_init): filtered_view_cmd invokes the internal
+ viewer with command != 0 and with file == "".
+ With the wrong Parse/Raw option (set with F8 when viewing the
+ former file) MC tried to open the file "" - fixed.
+
+ * util.c (strip_password, strip_home_and_password): handle pathes
+ like ftp://host/abc:defg@hij correct
+
+ * find.c (do_find): when searched for content the chdir button
+ didn't work - fixed.
+
+ * util.c (strip_password): New function used to remove the password
+ from a path (persons storing passwords in the hotlist just
+ don't want to see plain passwords on top of the panel). Currently
+ strip_password is only used by strip_home_and_password.
+ Note: Everything between : and @ is removed, i.e. strip_password
+ has to be called without ftp:// and mc:. I have not added checks
+ already done in strip_home_and_password. As soon as strip_password
+ is called from somewhere it should be reconsidered where to add
+ the checks.
+
+ * util.c, util.h, screen.c (show_dir): Renamed strip_home to
+ strip_home_and_password
+
+ * util.c (icase_search): Use toupper for the case-insensitive
+ compare to make icase_search aware of national characters.
+
+Thu Aug 14 00:17:40 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * slang/slgetkey.c: Commented SLang_input_pending and SLang_getkey out
+ because in order to enable input of characters from 128 to 159
+ I have to remove the DEC_8BIT_HACK from SLang_getkey. And because
+ I don't want any diffrence when compiling with a shared slang library
+ and our slang I moved as much as necessary to slint.c and then
+ made the change in slint.c. (SLang_input_pending only moved to be
+ sure it is using the correct SLang_getkey).
+ Perhaps I should give up the attempt to make MC compile with a
+ system installed slang library?!?
+
+ * slint.c: New functions SLang_input_pending2 and SLang_getkey2 with
+ the same functionality without the DEC_8BIT_HACK
+
+ * slint.c (getch): use SLang_getkey2/SLang_input_pending2
+
+ * file.c (copy_dir_dir): preserve access and modification time of
+ copied directories
+
+ * file.c (panel_operate, real_query_recursive): The logic of
+ know_what_am_i_doing was wrong i.e. the configuration option
+ "safeDelete" did the opposite as it pretented. I renamed the variable
+ and every reference to match the setting of "safeDelete".
+ When deleting files the yes/no query defaults to yes when "safe Delete"
+ isn't checked.
+ The query defaults to no when safeDelete is checked and recursive
+ recursive deleting of directories gets very difficult.
+
+ * myslang.h (initscr): In order to make the -a option work we have
+ to reset SLtt_Has_Alt_Charset after every call to SLtt_get_terminfo.
+
+
+Mon Aug 11 12:11:53 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * acconfig.h, config.h.in: Define 'unix' because some Compiler don't
+ define it and SLang requires it.
+
+ * configure.in, aclocal.m4 (fp_PROG_CC_STDC): new macro to check
+ whether an option is needed to put the C Compiler into ANSI C mode
+ (as suggested by GianPiero Puccioni <gip@fox.ino.it>)
+
+ * cmd.c (view_other_cmd): Disable/enable keypad when switching
+ panel's off/on with C-o (this fix is supposed to solve the problem
+ with cursor keys in an xterm reported by Paul Seelig
+ <pseelig@goofy.zdv.Uni-Mainz.de>
+
+ * main.c (handle_args): Replaced -m option with an error message
+ because first we can set in in the option's menu and second load_setup
+ will possibly override a given -m later.
+ Removed the obsolete -N option.
+ Added option -a in order to force +, |, - used as line drawing
+ characters when compiled with slang. Useful for persons not wanting
+ to modify their terminfo databases (Thanks to GianPiero Puccioni
+ <gip@fox.ino.it> for this suggestion).
+
+ * slint.c (slang_init): Force slang to use +, |, - when the option -a
+ is given.
+
+ * tk/tkscreen.c (x_fill_panel), xv/xvscreen.c (xv_insert_panel_item,
+ xv_panel_repaint_item): Necessary changes due to Timur's new screen
+ code i.e. make Tk and XView version compile.
+
+Mon Aug 4 01:20:42 1997 mc@timur.kazan.su (Bakeyev I. Timur)
+
+ * panel.h (format_e): add new fields: next - pointer to the next
+ element in the list; id - pointer to the token identificator.
+
+ (WPanel): Current display format placed in the linked
+ list with header pointed by *format. The similar list used to hold
+ status info display string in *status_format. fmt_count is now obsolete, deleted.
+
+ Added #define for current line display mode, deleted
+ set_attr() as unneccesary, add extra parametrs to repaint_file()
+ and format_file(), new function mini_status_format() and variable
+ highlight_mode added. (See screen.c)
+
+ * screen.c (set_attr): deleted, now uses attrset.
+
+ (mini_info_brief): absolutly fixed :), deleted. See below.
+
+ * Rewritten display format string handling. Array changed to
+ linked list. Mini status format string also keeps in list. Unified
+ parse_display_format() and parse_panel_size() to hold both
+ cases. Other functions (paint_dir(),paint_frame() and other) works
+ with list.
+
+ * (mini_status_format): new function. Currently, each
+ display format has apropriate default mini status display format.
+
+ * (add_permission_string): new function. New feature: if
+ highligh_mode > 0 permission string displays with highlighted user
+ access rights.
+
+ * (normal_color): new function. New feature: if highligh_mode=2,
+ then each file type highlights with it's own color.
+
+ * (delete_format): new function. Destruct format linked list.
+
+ * (string_file_size_brief), (string_dot): new functions. First
+ gives size for files and "SUB-DIR" for directories. Second simply
+ adds "dot" to the tokens in format string. (Try
+ ">owner,dot,<group"). Also add "bsize" and "dot" to formats.
+
+ * (repaint_file): add extra parameters, color choosen here.
+
+ * (format_file): here we actually do output to the screen and make
+ highlighting.
+
+ * (display_mini_info): delete currently unneccesary 3 calls to
+ parse_display_format per line.
+
+ * (parse_display_format()): fix some problems in parsing and
+ rewrite it to creat linked list.
+
+ * color.h, color.c: add 6 new color pairs: input - for input
+ fields, directory, execute, link, special, device - for type
+ highlighting.
+
+ * info.c, tree.c: change calls to set_attr to attrset.
+
+ * main.c (listing_cmd): slightly changed, to parse both user
+ defined display format and mini status format at the same time
+ (due other changes).
+
+ * main.c: add calls to init_groups and delete_groups for
+ initialization and destruction list of groups, to which user
+ belongs, for proper access highlighting.
+
+ * setup.c: add highligh_mode to mc.ini.
+
+ * util.h, utilunix.c: add functions init_groups, delete_groups,
+ get_user_rights to proper detection user access
+ rights. get_user_rights returns 0, if accessable on user level, 1
+ - on group, 2 - as other.
+
+Tue Aug 5 11:33:23 1997 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * configure.in, vfs/local.c: autodetection of statlstat() added
+
+ * slang/sldisply.c: TIOCGWINSIZ ifdef'ed to exclude window
+ resize on SCO (there is no struct winsize defined). Maybe someone
+ could explain, why they have it defined in termio.h, but only
+ for _IBCS2 define; and TIOCGWINSIZ defined unconditionally?
+
+ * src/cons.hanler.c, slang/sldisply.c: little cosmetic changes
+ to remove compiler warnings
+
+Tue Aug 5 08:48:21 1997 Fernando Alegre <alegre@debian.org>
+
+ * Debian viewer now handles both pre and post tar-1.12 formats
+
+Mon Aug 4 18:27:43 1997 T.E. Dickey <dickey@clark.net>
+
+ * change declaration of keyok() to 'int' rather than 'void'.
+
+ * configure.in: add test for 'resizeterm()' and 'keyok()' (I did
+ test builds against ncurses 4.1, 4.0, and 1.9.9e).
+
+ Btw, I tested resizing on SunOS 4.1, with both ncurses and slang.
+ Your application handles a few resizing events before getting hung
+ (this is not related to the libraries - perhaps you should
+ investigate it further).
+
+ * Makefile.in: remove a couple of items from the distclean rule
+ that don't correspond to generated files.
+
+ * resize (supported in NCURSES 4.0)
+
+ * mouse (supported in NCURSES since 1.9.6, but not compatible with MC
+ -- the simplest solution is to turn off the mouse code in NCURSES so
+ that MC can do what it wants. I've constructed a patch that will do
+ this - the function will be in the next release of NCURSES; it was a
+ minor item on my list, so I did it this week to get MC working).
+
+ * some configure nits (if ncurses is installed as curses, your script
+ does the wrong thing).
+
+ * vt100-style codes for F1-F4 (you'll need these for the XFree86 xterm)
+
+ * add some stuff to the "make distclean" rule, so it _is_ clean.
+ (Otherwise I waste time making the patch).
+
+ * initialized a variable in menu.c (your program dumped core while I
+ was testing the mouse events).
+
+Mon Aug 4 18:24:25 1997 Alexander Dong (ado@software-ag.de)
+
+ * edit/edit.c, editcmd.c: changes for handling ^M.
+
+ * nt/config.h: updates
+
+ * slang/myslang.h: some constants that are used by the Windows and
+ OS/2 ports are here.
+
+ * nt/utilnt.c: New way of executing programs. Use _P_NOWAIT in
+ the spawn invocation for win16 and win32 applications.
+
+ (unixlike_canonicalize_pathname): Do manual canonicalizing needed
+ for some VFS fucntions.
+
+Mon Aug 4 17:48:39 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * configure.in: My last patch wasn't complete. I forgot to delete a
+ few lines in order to make it work the way I want.
+
+ * slang/Makefile.in: Removed a few defines which are no longer needed.
+
+ * slang/sltermin.c: Renamed SLtt_try_termcap to SLtt_Try_Termcap within
+ Ching Hui fixes for AIX and OSF/1 (the new slang source had this
+ change).
+
+ * cmd.c: Don't include edit/edit.h because it defines open to mc_open
+ but mmap remains mmap. This broke the compare directories command
+ (thorough compare).
+
+ * cons.saver.h: When HAVE_X is defined replace all the console-stuff
+ with no-ops. I think the TK and XView version don't need to save and
+ restore consoles.
+
+ * main.c (init_menu): In the menues use Above/Below instead of Left/
+ Right when the panels are horizontally split (only non X version).
+ Made init_menu and done_menu non-static because they are used in
+ layout.c.
+
+ * layout.c (layout_change): Make a new menubar in case the vertical/
+ horizontal split changed.
+
+ * main.c (sigchld_handler_no_subshell): Body of function commented out
+ for XView and TK version.
+
+ * main.c (main): Moved OS_Setup before xtoolkit_init to avoid using of
+ mc_home == 0 (mc_home is set in OS_Setup).
+
+ * myslang.h: A few definitions were wrong causing keys not to work.
+
+ * screen.c (start_search), tree.c (start_search): The filename search
+ (C-s, M-s) didn't wrap around when hitting C-s again and the panel's
+ last filename and one more file matched the search string.
+
+ * screen.c (panel_callback): Always define the label for the F1 key
+ on WIDGET_INIT and WIDGET_FOCUS (with one panel in tree mode only the
+ help for the directory tree was displayed furthermore).
+
+ * view.c (view_callback): When v was renamed to i (because the
+ parameter v was hidden by a local variable) one location was forgotton
+ to change.
+
+ * tk/Makefile.in, xv/Makefile.in: Don't link with cons.saver.o.
+ Re-arranged a few object files in order to compile the TK and XView
+ version without the console save/restore stuff.
+
+
+Thu Jul 31 12:57:01 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * slang/sltermin.c: Put Ching Hui's AIX and OSF/1 workarounds into
+ the code again again.
+
+ * boxes.c (tree): Add a buttonbar to the tree-box in order to
+ make it possible to redefine the function keys in the tree-widget
+
+ * main.c (tree_box): Change to the selected directory as described
+ in the online help.
+
+ * tree.c (tree_keymap): Activated the C-r key for the tree box
+ (with a panel in tree mode C-r did already something, but with
+ the tree invoked with Command/Directory tree C-r and all function
+ keys did not work)
+
+ * configure.in: First check for a system installed SLang library,
+ then check for --with-terminfo and --with-termap, i.e. we compile
+ the SLang code ourself when --with-terminfo, --with-termcap or
+ --with-our-slang is given (regardles whether there is a system
+ installed SLang library or not)
+
+ * conv.handler.c: The recent rxvt patch removed the definition of
+ console_flag on some systems
+
+Thu Jul 31 12:29:44 1997 Jurij Ivliev <yury@win.kazan.su>
+
+ * setup.c (options): add entry for use_8th_bit_as_meta flag
+ to save it in .mc.ini
+
+ * boxes.c (display_widgets): add entry for changing
+ use_8th_bit_as_meta flag via "Display bits" dialog box.
+
+ * boxes.c (display_bits_box): add handling for that entry.
+ It's will possible 8-bits input on/off easy instead -m command
+ line option.
+
+Fri Jul 25 17:38:11 1997 timur@goff.comtat.kazan.su (Bakeyev I. Timur)
+
+ * screen.c (string_file_size): Use %ld instead of %d to sprintf
+ the file size.
+
+Thu Jul 24 20:01:42 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c (do_panel_cd): Make the code compile without USE_VFS defined.
+ Reversed a former change (setting panel->cwd before the call to
+ mc_chdir) because it broke the password dialog for ftpfs and mcfs.
+ Stamp the old filesystem (mc_chdir can't stamp it because it thinks
+ the old directory is still in use).
+
+ * main.c (do_nc): After destroying cpanel and opanel set cpanel zero
+ to avoid vfs_add_noncurrent_stamps from using them.
+
+ * screen.c (do_enter): Make the code compile without USE_VFS defined.
+
+ * vfs/extfs.c (extfs_get_path, extfs_close), vfs/tarfs.c
+ (tarfs_get_path, tarfs_close): Fixed memory leaks
+
+ * vfs/vfs.c (vfs_addstamp): Reversed the order in which stamps are
+ stored in the linked list so the last added stamp is first checked
+ for timeout. That's only needed for embedded virtual file systems
+ in order to try to free the vfs resources in a more reasonable
+ order.
+ When using the variable parent make a new copy of the list it points
+ to. That make's it easier for the caller function to decide whether
+ it should free parent or not.
+
+ * vfs/vfs.c (vfs_rm_parents): New function, free the list of parent
+ vfs's
+
+ * vfs/vfs.c (vfs_rmstamp): use vfs_rm_parents to free the list of
+ parents
+
+ * vfs/vfs.c (vfs_ncs_getid): made non-static because needed in main.c
+
+ * vfs/vfs.c (is_parent): Check a vfs whether it's in a given list of
+ parents
+
+ * vfs/vfs.c (vfs_add_noncurrent_stamps): Added current_dir to the
+ directories to check when deciding whether to add a given vfs to
+ the timeout structure or not
+
+ * vfs/vfs.c (vfs_stamp_path): Stamp the parent file systems, too.
+
+ * vfs/vfs.c (vfs_shut): Set stamps to zero before walking through
+ the list because freeing the filesystems can add new stamps and
+ the now reveresed ordered stamp list caused an endless loop.
+
+ * main.c (jump2dotdot): Addapted and reused the OS2_NT version for
+ use with unix. Now the directory tree command of the Command menu
+ switches to the parent directory of the selected directory.
+
+ * vfs/ftpfs.c (ftpfs_close): On error don't set ftpfs_errno because
+ it's already set by store_file.
+
+ * vfs/vfs.c (mc_close): Return error when mc_close is called the
+ second time with the same handle (happens e.g when storing a file
+ to an ftpfs without having the permissions and selecting Retry in
+ the error dialog)
+ Set errno when the lower layer reports an error.
+
+Tue Jul 22 12:14:21 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (copy_file_file): Nicer and fixed bps display.
+
+ * view.c (view_callback), edit.c (edit_callback): Warning fix, use
+ void * for the prototype, cast them to the right type inside the
+ function.
+
+Mon Jul 21 07:48:33 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * key.c (get_event): removed typo which caused busy waiting when
+ leaving a vfs and MC used with mouse
+
+Fri Jul 18 10:11:01 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * boxes.c (cd_dialog): Don't use the commandline widget to callculate
+ the y-Position of the quick-cd dialog because cmdline->y is 0 when
+ there is no commandline.
+
+ * vfs/names.c (finduid, findgid): For a cache-hit in the uid/gid-cache
+ a value of zero was returned because the cache-content was always
+ destroyed at top of finduid/findgid.
+
+
+Wed Jul 23 18:43:57 1997 Alex Tkachenko (alex@bcs.zp.ua)
+
+ * editcmd.c restored national chars support, broken with recent
+ editor patches
+
+Wed Jul 23 18:43:57 1997 Alex Tkachenko (alex@bcs.zp.ua)
+
+ * editcmd.c restored national chars support, broken with recent
+ editor patches
+
+Wed Jul 23 18:43:57 1997 Alex Tkachenko (alex@bcs.zp.ua)
+
+ * editcmd.c restored national chars support, broken with recent
+ editor patches
+
+Mon Jul 21 14:25:55 1997 Alexander Dong (ado@software-ag.de)
+
+ * editcmd.c (edit_help_cmd), cmd.c, dlg.c, ext.c, main.c, setup.c,
+ tree.c, user.c, view.c: Do not use LIBDIR for accessing the
+ information on the disk, instead use the the mc_home variable,
+ which is setup differently for Unix and Windows/OS/2 machines: On
+ UNIX, it still is LIBDIR, on Windows/OS/2 it uses the value of
+ MCHOME. [This should be changed to use argv [0] -- miguel]
+
+ * nt/utilnt.c (conv_nt_unx_rc, mc_unlink): New function
+ For Windows 95 and NT, files should be able to be deleted even
+ if they don't have write-protection. We should build a question box
+ like: Delete anyway? Yes <No> All
+
+ removed the beep messages from the vfs code.
+
+ * src/drive.h: add prototypes for drive commands.
+
+ * os2/util.os2.c: implement getinstalldir ();
+
+Mon Jul 21 14:25:55 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * util.c, utilunix.c, key.c: Make the code compile on both libc5
+ and gnu libc setups. Thanks to dvelp@dds.nl (Willem de Vries)
+ and ewt@redhat.com (Erik Troan) for pointing the solution.
+
+Sun Jul 20 21:15:55 1997 Bakeyev I. Timur <timur@goff.comtat.kazan.su>
+
+ * view.c (grow_string_buffer): This may be called with a null
+ pointer to grow. Fix this condition.
+
+Mon Jul 14 12:34:08 1997 Juan Grigera <j-grigera@usa.net>
+
+ * edit/editcmd.c: (Win32) added O_TEXT flag to file I/O -CR/LF translation
+
+Sun Jul 20 13:22:16 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/edit.c, editcmd.c, editwidget.c, editmenu.c, editdraw.c,
+ edit.h, editcmddef.h: This patch (on 4.0.4) updates the editor
+ code to match the X Window version. Features added:
+ - On saving, chown() file to the same as when it was loaded.
+ - Backups on save are now created if the option is set. A
+ "Save Mode" dialog was added bu Oleg (see next
+ entry), as well as the support routines.
+ - Various new movement and editing commands added:
+ o Delete to eol.
+ o Delete to bol.
+ o Paragraph move up/down.
+ o Move to top/bottom of screen.
+ (Key bindings for these new features are only available
+ for the X Windows version. But will soon be added.)
+ - Highlights the matching bracket under the cursor.
+ - OS2_NT check defines are moved to the edit.h file.
+ Please try keep any defines in the file under
+ the section
+ "/* put OS2/NT/WIN95 defines here */"
+ unless essential, so that this will also
+ compile for X.
+ - Fixed scanf search/replace. This now works properly,
+ where it never used to find the match length
+ before.
+ - Doc updates.
+ - The remainder of the changes are only applicable to the
+ X Window version.
+
+Sun Jul 20 13:26:53 1997 Oleg Yu. Repin <repin@ssd.sscc.ru>
+
+ edit/editcmd.c: Added save mode feature (see above entry).
+
+Thu Jul 10 11:33:05 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/edit.h: Added stdarg.h because I need it to compile MC
+ under SunOS without SLang.
+
+ * edit/editcmd.h (edit_refresh_cmd): When compiling without
+ SLang SLsmg_touch_lines() isn't defined. Fixed.
+
+ * main.c (main): Take the value of the LC_CTYPE locale from
+ the environment because at program startup each category is
+ initialized to the locale described by the environment "C"
+ (see setlocale(3C)).
+ Now control-left, control-right and control-backspace handle
+ words with national characters correct, i.e. they are only
+ handled correct on a system with non-broken locale support.
+
+Wed Jul 9 10:48:28 1997 Juan Grigera <j-grigera@usa.net>
+
+ * view.c (do_view_init): Init the save_start as well.
+
+ * complete.c (command_completion_function): Use new PATH_ENV_SEP,
+ on Windows/NT and OS/2 this is ';' on Unix this is ':'
+
+Thu Jul 3 23:07:56 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * achown.c (do_enter_key): Ugh, getpwnam/getgrnam may return NULL
+ if <Unknown> is selected. Reported by Federico Mena (quartic@nuclecu).
+
+Thu Jul 3 18:58:02 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c (subshell_chdir): vfs_add_non_current_stamps needs to
+ know the current directory in any panel. Formerly it used
+ current_dir and opanel->cwd to get this information but it
+ was possible that current_dir and opanel->cwd were the same.
+ I changed vfs_add_non_current_stamps to use cpanel->cwd and
+ opanel->cwd but now I have to set cpanel->cwd before the
+ call of mc_chdir.
+
+ * vfs/ftpfs.c (changetype): Always send the command "TYPE I"
+ when changing to binary transfer mode, even if MC thinks the
+ connection is already in binary mode (bucket->isbinary == 1).
+ There was a problem when transfering files in background. Hmm,
+ I think there's still a problem because my fix cures only a
+ symptom.
+
+ * vfs/vfs.c (vfs_add_non_current_stamps): patches to fix a bug
+ with releasing a vfs still in use. Thanks to Alex I. Tkachenko
+ who helped to fix this bug.
+ Do not time out the old vfs if it is current in any panel or if
+ it is a parent in any panel, e.g. while browsing a tar-file on
+ an ftp filesystem the tarfs is 'current' and the ftpfs is it's
+ 'parent'.
+ Use cpanel->cwd and opanel->cwd instead of current_dir and
+ opanel->cwd to get the information which vfs's are current in
+ any panel because it's possible that current_dir and opanel->cwd
+ are the same (then the vfs for cpanel->cwd was timed out).
+
+Thu Jul 3 18:56:46 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (handle_args): Add support for jumping into the editor if
+ the program is invoked as 'mcview'.
+
+Mon Jul 7 17:03:15 1997 Ingo Brueckl <ib@wupperonline.de>
+
+ * slang/sltermin.c: find compiled terminfo database under
+ /usr/{,local/}share/terminfo which is default for ncurses 4.1
+
+Thu Jul 3 20:00:10 1997 Ingo Brueckl <ib@wupperonline.de>
+
+ * src/setup.c, src/setup.h: load new profile string 'color_terminals'
+ from mc.ini which is a list of terminals that support color and force
+ mc to start in color mode
+
+ * src/slint.c: use new profile string 'color_terminals' (if found in
+ mc.ini) instead of hard-coded string 'color_terminals' but fall back
+ to hard-coded string if new profile string is empty
+
+Tue Jul 1 12:17:08 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (file_bps_show): report KBS, MBS and BPS.
+
+Mon Jun 30 11:44:13 1997 D. J. Hawkey Jr. <hawkeyd@visi.com>
+
+ * src/boxes.c, src/widget.c: add the proper return value.
+
+ * src/fsuage.c, src/mountlist.c, src/utilunix.c: Add support for QNX.
+
+Mon Jun 30 23:18:52 1997 Alex Tkachenko <alex@bcs.zp.ua>
+
+ * edit/editcmd.c (edit_find_string): fixed search of chars > 128
+
+ * acconfig.h configure.in src/find.c: an ability of grep to
+ accept dash to denote stdin is now handled by configure. Also
+ -lintl added to LIBS to avoid SCO (maybe not only :) problems
+ with nls chars
+
+Thu Jun 26 20:56:03 1997 Ralf Gutzeit <ralf.gutzeit@weisswasser.de>
+
+ * src/file.c (file_bps_show): added display for the current
+ line quality during ftp. It's just a modified version from the
+ function file_eta_show to display a BPS-rate during file transfer
+ in the line below the ETA-display. Now the stalled_msg appears in
+ the third line under the ETA-display.
+
+Thu Jun 26 20:39:54 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/tar.c (read_header): check len before using it as index
+ with len-1
+
+ * vfs/vfs.c (vfs_add_noncurrent_stamps): I did some copy and
+ paste and forgot to adapt the variable names :-(
+
+ * vfs/vfs.c (vfs_shut): There was a pointer used after it was
+ freed.
+
+Mon Jun 23 11:08:56 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * mountlist.c (read_filesystem_treat OpenBSD and NetBSD as the
+ same thing.
+
+Fri Jun 20 12:02:30 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/extfs.c (extfs_get_path, extfs_close), vfs/tar.c (tarfs_get_path,
+ tarfs_close): initialize parent->next with NULL, the vfs code
+ depends on it
+
+ * file.c (copy_dir_dir): preserve uid and gid of copied direcories
+ if Preserve UIDs/GIDs in the copy dialog is checked
+
+Mon Jun 16 12:36:41 1997 Alexander Dong (ado@software-ag.de)
+
+ * os2: Improvement in my_system () to start Windows, DOS and OS/2
+ programs.
+
+ * show_output_starts_shell in mc.ini enabled for OS/2-version.
+ * Enable CTRL-O
+ * Bug fix for Windows 95 (fprintf(\r\n) instead of \n)
+
+Wed Jun 11 17:25:21 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * ftpfs.h, ftpfs.c (changetype): store the transfer type (ASCII/Binary)
+ at a connection basis
+
+Tue Jun 10 11:37:11 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * screen.c, widget.c: changed some defines from HAVE_X to HAVE_TK
+ (e.g the XView code didn't want to provide a 'tk_evalf')
+
+ * xv/Makefile.in: added missing dirhist.o to the list of objects,
+ changed the order of the libs in the final makestep because I got
+ undefined references with SunOS
+
+ * xv/xvaction.c: added missing #define "mad.h"
+
+ * xv/xvmenu.c: changed menubar_event from static to nonstatic
+ because the internal editor wants to call it (note the internal
+ editor isn't working with XView)
+
+ * vfs/ext/a: New Perl version of this script.
+
+ * src/info.c: remove the call to my_statfs in info_new because
+ my_statfs is always called before the information is displayed
+ (in function info_show_info).
+
+Mon Jun 9 18:36:51 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (panel_operate): Put back the old behaviour.
+
+Wed Jun 4 17:11:23 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c: highlight the proper hotkeys.
+
+ * cons.saver: it is no longer compiled/linker with the -N flag, as
+ discussed on the mailing list.
+
+Wed Jun 4 17:08:13 1997 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * info.c (info_new): my_statfs() was called before mount list was
+ initialized It seems to also fix the problem with symbolic
+ links across filesystems in Info view. Strange ...
+
+ * file.c (panel_operate): Default in Delete dialog changed to "No"
+ (after I lost a file ;-) Note, that RecursiveDelete dialog
+ defaults to "No" as well - it seems to be reasonable.
+
+ * mcserv.c (signal_int_handler): Added dummy parameter to keep
+ ANSI compilers happy. All other signale handlers define it as well.
+
+ * miscellanious changes to add neccessary casts/remove unneeded
+ ones; trailing comma in enum declarations removed. Again to
+ overcome problems with ANSI compilers.
+
+Wed Jun 4 16:58:34 1997 Alexander Dong (ado@software-ag.de)
+
+ * main.c (tree_box): OS/2 and Windows NT use this routine.
+
+Thu May 29 15:25:19 1997 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * vfs/vfs.c (vfs_canon): Fixed the "local:" vfs handling
+
+Thu May 29 14:30:50 1997 Michele Marziani <marziani@axpfe1.fe.infn.it>
+
+ * cmd.c (do_edit): Reread also when invoking the internal editor.
+
+Tue May 27 21:10:53 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * configure.in: remove typo
+
+ * lib/xnc.hlp, src/mc.hlp: corrected the two ascii chars ^A, ^B
+ and ^C with the corresponding control chars
+
+Mon May 26 13:20:56 1997 Alex Tkachenko (alex@bcs.zaporizhzhe.ua)
+
+ * vfs/extfs.c, src/ext.c, vfs/tar.c, etc, etc: added waitpid() after
+ pclose() for SCO_FLAVOR, to avoid spawning of zombie process
+ (mostly while using external filesystem features)
+
+ * src/main.c: added fflush() to get shell display prompt before
+ saving console contents
+
+ * console handler for sco added
+
+ * src/view.c: hex editor feature enabled via loading entire file
+ into memory for those who don't have mmap() call.
+
+ * src/cmd.c DUSUM_USEB and DUSUM_FACTOR #undef'ed to get this
+ code working for SCO (3.2v4).
+
+ * src/cmd.c, src/panelize.c: a workaround provided for sco 3.2v4 bug
+ in pclose() implementation. Return value ignored.
+
+ * vfs/extfs.c: a workaround provided for sco bug in system() call
+ implementation - it reports an error while it seems to be allright.
+ Return value silently ignored.
+
+ * many small fixes to let more smooth compiling on sco 3.2v4.2.
+ These avoid annoying gcc warnings about scopes of struct declarations
+ and redefining of struct timeval.
+
+Fri May 23 18:33:23 1997 Alexander Dong (ado@software-ag.de)
+
+ * os2/drive.os2.c, nt/drive.nt.c: fixes.
+
+Fri May 23 13:56:15 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (copy_file_file): Oops. uidgid and the original modes
+ were not restored when the file was a character device, a block
+ device a fifo or a socket.
+
+ * cmd.c (do_edit): Reload the panel information after calling the
+ internal editor.
+
+ * tcputil.c (rpc_get): implement RPC_LIMITED_STRING. Same as
+ RPC_STRING, but if the string is bigger than 16k, it silently
+ aborts. This should prevent a denial of service attack.
+
+Wed May 21 21:32:41 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * complete.c (try_complete): Bug fix. Free the proper pointer.
+ Same problem that Bernhard found, in a different location. Grep
+ does wonders.
+
+Wed May 21 21:19:58 1997 Bernhard Sadlowski <sadlowsk@mathematik.uni-bielefeld.de>
+
+ * command.c (do_cd_command): Bug fix. Free the proper pointer.
+ This fixed the cd "xxxx" problem.
+
+Mon May 19 12:07:39 1997 Michele Marziani <marziani@axpfe1.fe.infn.it>
+
+ * mc.spec: small bug fixes.
+
+ * lib/mcserv.init: use the -d flag for starting the daemon.
+
+Mon May 19 10:38:39 1997 Oleg Yu. Repin <repin@ssd.sscc.ru>
+
+ * util.c (is_printable): Add explicit set of printable characters
+ for xterm. Viewing binaries should not crash mc for now.
+
+Fri May 16 17:35:59 1997 Alexander Dong (ado@software-ag.de)
+
+ * src/main.c: Added new -S flag on Windows and OS/2 platforms:
+ this will create a batch file that can change the parent's default
+ directory and disk (equivalente to the Unix mc function and the
+ -P flag).
+
+ * nt/slint.nt.c, os2/slint.os2.c: slang_set_raw_mode stubs,
+ according to the may/14 change.
+
+Fri May 16 16:46:06 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/editwidget.c: Fixes editor keybar redisplay.
+
+ * tk/tkslint.c: Provide new function.
+
+Fri May 16 16:42:18 1997 Tomasz K³oczko, <kloczek@rudy.mif.pg.gda.pl>
+
+ * mc.spec: New spec file, this packages mc, mcserv and tkmc.
+
+ * lib/mcserv.init, lib/mc.sh, lib/mcserv.pamd: added
+
+ * vfs/ext/rpm: instead using sed and rpm -qpi use rpm queries,
+ more info currently displayed (changeslogs, Os, URL, packager
+
+Tue May 13 18:14:49 1997 Wojtek Pilorz <wpilorz@bdk.lublin.pl>
+
+ * vfs/Makefile.in (INSTALL_PROGRAM): Use -m flag for install to
+ force vfs scripts to be executable on those systems that use
+ install.sh
+
+ * src/utilunix.c: Implement socketpair for SCO flavored systems.
+
+Wed May 14 18:07:09 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * myslang.h (raw): Make raw an alias for slang_set_raw_mode, which
+ will set the raw mode. This should fix Hugh's problem.
+
+Wed May 14 17:18:59 1997 Alexander Dong (ado@software-ag.de)
+
+ * nt/chmod.nt.c: Updated the code to use the new file book-keeping
+ routines from Norbert.
+
+ * os2/chmod.os2.c: same here
+
+Wed May 14 14:57:41 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * */Makefile.in: Made the target distclean work (the Makefile
+ was used with 'make realclean' after it has been deleted).
+
+ * vfs/Makefile.in: Fixes needed for --with-debug
+
+ * tk/Makefile.in: After a successful build create an empty file
+ which make can check against (this prevents make from linking tkmc
+ every time)
+
+ * src/dirhist.h: Moved '#include "mad.h"' a few lines down (when
+ compiled with --with-debug there was a conflict with stdlib.h on
+ SunOS 5.4)
+
+Mon May 12 10:37:37 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * setup.c (load_setup): We don't want to load the private version
+ of the .mc.ini file.
+
+Tue May 13 18:43:13 1997 Paul Sheer <psheer@icon.co.za>
+
+ * editcmd.c: edit_find_string(): now checks if regexp has '^'
+ proper.
+
+Fri May 9 14:53:07 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * src/*: Use do_file_mark to mark and unmark files in order to
+ update the summary information the right way i.e. I hope that
+ the repored negative numbers in the mini-status are something
+ of the past.
+ In particular replaced lots of occurances of file_mark with
+ do_file_mark and removed the local calculation of panel->total
+ etc. which was not always done the same way in every file.
+ * src/main.c (parse_control_file): Additionally use unmark_files
+ to unmark all files
+
+ * src/screen.c (do_file_mark, do_mark_file): Moved the code to
+ repaint the changed file from do_file_mark to do_mark_file.
+ The first one was only called from the second one and from the
+ XView code and the latter does not use the moved code.
+ I had to do it in order to avoid a check if the file is 'within
+ the display' at the moment.
+
+ * src/screen.c (panel_reload): clear panel->dirs_marked
+
+ * src/find.c (find_files), src/panelize.c (do_external_panelize):
+ Set cpanel->has_dir_sizes to 0 when clearing the counters
+
+ * doc/mc.1: Fixed wrong URL
+
+ * src/mfmt: Changed the return value of main from void to
+ int and return 0. I made this stupid change a while ago when
+ I wanted to get rid of a compiler warning (if you have two
+ possibilities the probability to do it the wrong way is at
+ least 60%).
+
+ * vfs/ftpfs.c (ftpfs_done): Close the logfile
+
+Fri May 9 14:41:33 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.c (display): Two lines were on the wrong place. This cause
+ the growing buffers to stop displaying before of time.
+
+Thu May 8 11:35:24 1997 Sung-Hyun Nam <namsh@amuna.rms.lgic.co.kr>
+
+ * file.c (file_eta_show): Correct ETA computation.
+
+Sat May 10 13:32:55 1997 Ingo Brueckl <ib@wupperonline.de>
+
+ * main.c, main.h, boxes.c, setup.c, screen.c (do_enter): Added an
+ extra confirmation 'confirm_execute' to be used when pressing enter
+ on a file to execute it.
+
+Tue May 6 12:51:35 1997 roryt@hol.gr (I.Ioannou)
+
+ * view.c (display, view_handle_key): Added an option to display a
+ ruler in the built-in viewer.
+
+Tue May 6 12:26:31 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * hotlist.c (hotlist_callback): Added the possibility to copy the
+ directory path to the command line (C-Enter, M-Enter).
+
+ One could jump from the active VFS list to the hotlist (with the
+ left curser key) - fixed.
+
+ * hotlist.c (init_hotlist): The active VFS list showed the help
+ for the hotlist. Now it shows 'Can't find node [vfshot] in help file'
+ (not much better but maybe someone will write a few lines for
+ the man page?).
+
+ * hotlist.c (hotlist_cmd, load_hotlist, save_hotlist, hotlist_done):
+ Check the modification time of ~/.mc.hot and reload the hotlist when
+ ~/.mc.hot is newer than the hotlist in memory.
+ Save the hotlist after every change.
+
+ * hotlist.c (hotlist_done): Reset all necessary variables to make
+ a hotlist reload possible.
+
+ * screen.c (panel_callback): When changing the panel the current
+ directory on top of each panel remained highlighted unil C-r was
+ pressed. There was a change for the tk version (in 3.5.17 I think)
+ which caused this.
+
+ * mcserv.c (do_readlink): the returnvalue of readlink was used
+ without check as an index. On failure the line 'buffer[-1] = 0'
+ was executed.
+
+ * vfs/undelfs.c: The undelfs could not handle the '..' entry. That
+ became a problem when I ensured that every directory listing contains
+ a '..' (e.g. hitting F3 on that entry caused a segfault).
+
+ Another problem only showed up when the 'Fast dir reload' option was
+ activated (an unnecessary warning message was displayed).
+
+ Once more I used the opportunity to cleanup the code a little bit.
+ I changed the type for inodes to ino_t (some were already of type
+ ino_t, some not), made it possible to free all malloced memory, fixed
+ memory leaks and inserted the undelfs in the vfs timeout scheme, i.e.
+ the malloced memory is freed automaticly when the undelfs isn't used
+ within the vfs timeout.
+
+ * vfs/undelfs.c (undelfs_shutdown): Filled the formerly empty body
+ with something useful i.e. free memory and shut down the ext2 utility.
+
+ * vfs/undelfs.c (undelfs_loaddel): Added ext2fs_close_inode_scan
+
+ * vfs/undelfs.c (com_err, undelfs_readdir): Fixed an incorrect sprintf
+ format specifier (to be honest it was not incorrect at least for the
+ intel x86 architecture due to sizeof (int) == sizeof (long) ).
+
+ * vfs/undelfs.c (undelfs_opendir): Now it's possible that the pointer
+ ext2_fname becomes 0 so I had to consider this case.
+ Fixed an incorrect sprintf format specifier
+
+ * vfs/undelfs.c (undelfs_open, undelfs_close): Keep in mind for the
+ timeout thing if there are open files in the undelfs (I don't think
+ that this is really necessary but I made the changes in correpondence
+ to the the solution in other vfs filesystems).
+
+ * vfs/undelfs.c (undelfs_lstat): Do a simple check if the filename
+ to stat is valid (this removes a harmless warning message when
+ undlefs_stat is called from save_cwd_stats).
+
+ * vfs/undelfs.c (undelfs_getid, undelfs_nothingisopen, undelfs_free):
+ Adapted for the vfs timeout
+
+ * vfs/vfs.c (vfs_canon): Recognice 'undel:/dev/sda1/..' as '/' (needed
+ to go out of the undelfs with 'cd ..' or to stat 'undel:/dev/sda1/..'
+
+ * vfs/vfs.c (vfs_shut): fixed a memory leak
+
+Mon May 5 18:40:28 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs/utilvfs.c (get_host_and_username): Rewrote it completely.
+ Now it is clearer and should handle some problematic cases it did
+ not handle very well before. It comes with a small test suite as
+ well.
+
+Fri May 9 11:13:59 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c, main.c, setup.c: editor_word_wrap_line_length option
+ added, and a function to do word wrap.
+
+ * mcedit.1 updated.
+
+Fri May 2 13:14:13 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * util.c (diff_two_paths): Fixed two typos and a too small size
+ calculation for one malloc-call.
+ 'Stable Symlinks' in the filecopy-dialog works now. In the
+ filemove-dialog both 'follow Symlinks' and 'Stable Symlinks'
+ don't work.
+
+ * file.c (move_file_file): name_trunc returns a pointer to
+ a static array. That makes problems when something is done
+ like 'foo (name_trunc (a,10), name_trunc (b,10));`.
+ Juan corrcted one occurance of this error and I checked the
+ other sources and found another one.
+
+ * find.c (find_file): Panelizing in the find dialog didn't work
+ if the selection in the listbox wasn't on a found file but on
+ one of the entries which shows the found files' directories.
+
+ * view.c (do_view_init): Initialize view->last (there was a
+ problem when viewing files with a starting line number e.g
+ from the find file dialog)
+
+ * view.c (view_ok_to_quit): Added missing return value
+
+ * tk/tkscreen.h: The whole file was duplicated.
+
+ * FAQ, INSTALL, README, doc/mcedit.1, doc/mcserv.8, lib/mc.hint:
+ Corrected wrong URLs
+
+ * doc/mc.1, doc/mc.sgml: Corrected wrong URLs, removed the outdated
+ entry '8-bit clean' (this option disappeared somewhen in 3.5.X).
+
+ * src/TODO: removed outdated information about '8-bit clean'
+
+Fri May 2 13:11:31 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/: Updated to latest cooledit sources.
+
+Fri May 2 13:09:58 1997 Migue l de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * find.c (locate_egrep): Search the egrep program instead of using
+ a hardcoded value.
+
+Fri May 2 12:21:31 1997 roryt@hol.gr (I.Ioannou)
+
+ * configure.in: SCO needs to use _SVID3 to compile. Otherwise the
+ fsusage routine complains.
+
+Tue Apr 29 18:10:42 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+
+Tue Apr 29 18:03:09 1997 Christofer Edvardsen <jce@kuai.se>
+
+ * vfs/utilvfs.c (get_host_and_username): Allow the login name to
+ have a password as well.
+
+Tue Apr 29 17:42:53 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * replaced all the occurences of:
+ copy_strings (d, PATH_SEP_STR, f, NULL)
+ with a call to the concat_dir_and_file which do a copy_strings
+ of d, f if d has a trailing "/" or a copy_strings of
+ d, PATH_SEP_STR, f if not. This cleans up some code and make s
+ the code work just fine on OS/2 and Windows/NT.
+
+ * boxes.c: Adjusted the listbox size, some test code went out.
+
+ * hotlist.c (save_hotlist): Set the file permission of the file to
+ the one from the backup file. This is for added security for
+ those guys keeping passwords on their .mc.hot file.
+
+Tue Apr 29 17:41:13 1997 Alexander Dong <ado@software-ag.de>
+
+ * src/dlg.c: On Windows NT RISC editions (for Alpha, PPC and
+ MIPS), the functions have a heading-code which calculates the real
+ address of the function. So, instead of testing pointer
+ addresses for checking if we are dealing with an input line, we
+ use the W_IS_INPUT flag in the widget options menu.
+
+ * nt: I have changed the function drive_cmd for Windows NT so that
+ it can display a more beautiful drive-select-window. This change
+ also fixes a problem with more than 5 drives.
+
+ * os2: misc updates to all of the files. (Alexander, could you
+ send me ChangeLogs for your changes/).
+
+Fri May 2 12:38:07 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/*: Lotsa changes. Basically:
+ - Whole lot of tabbing options added.
+ - Sort command added.
+ - Spell command added.
+
+Mon Apr 28 14:52:03 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * boxes.c (JOBS_X): Added dialog box for controlling the
+ background jobs.
+
+ * main.c: C-x j is bound to the job control dialog box.
+
+Sun Apr 20 11:04:09 1997 Alexander Dong <ado@software-ag.de>
+
+ * profile.c (load): Add fclose(f).
+
+ * util.c (strcasecmp): change char to int.
+
+ * cmd.c (do_edit): Default editor changed for NT and OS/2
+
+ * dir.c (case_sensitive): Case insensitive for OS/2 and NT.
+
+ * file.c (copy_file_file): Check for st_ino and st_dev for NT and
+ OS/2 diabled.
+
+ * info.c (info_show_info): check the wrong value for st_dev on
+ NT and OS/2.
+
+ * main.c (do_execute): disable control_file for OS/2.
+
+ * screen.c (do_search): Case insensitive search for OS/2 and NT.
+
+ * tree.c (load_tree): Changes to enable the tree file to be read
+ correctly.
+
+ * Add many changes for OS/2. (Change drive left and right ...)
+
+ * Seperate set of files (*.os2.*) for OS/2.
+
+Fri Apr 18 16:44:12 1997 Wojtek Pilorz <wpilorz@bdk.lublin.pl>
+
+ * mc.ext.in: Replace %f with quoted '%f'.
+
+Wed Apr 16 13:56:38 1997 Alexander Dong <ado@software-ag.de>
+
+ * Contributed OS2 port of Midnight Commander.
+
+ * config.h: new macro OS2_NT: defined if compiling under OS2 or
+ Windows 95/NT.
+
+Wed Apr 16 11:47:14 1997 Pawel T. Jochym <ptj@pkpf.if.uj.edu.pl>
+
+ * util.h: fixed prototypes for SGI compilation.
+
+Mon Apr 14 21:38:04 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c (view_ok_to_quit): New function. Allows cancelation of
+ the quit command when there changes have been made to the file.
+
+ (view_handle_key): catch quit events as well and allow the user to
+ save the file.
+
+ * vfs/ftpfs.c (select_on_two): Timeout after 1 second.
+
+ * file.c: Added estimated time of arrival for ftp file systems and
+ stalled condition detection messages.
+
+Mon Apr 14 11:59:13 1997 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * vfs/vfs.h: Use bug fix version on NT of rename and mkdir.
+
+ * file.c (files_error): we were clobbering the return value of one
+ of the names displayed.
+
+ * slang.h: Updated to new version.
+
+ * main.c (handle_args): fix: background_wait is only available
+ if the program is compiled with WITH_BACKGROUND
+
+Thu Apr 10 00:39:38 1997 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * mouse.c (init_mouse): Use MCKEY_MOUSE as the magic key code
+ returned by the xterm mouse sequence instead of zero.
+
+ key.c (get_event): Check for MCKEY_MOUSE as a return value from
+ getch_with_delay instead of assuming return value == 0 => mouse
+ event.
+
+ Paul: Control-space now passes a zero properly to your editor
+ widget.
+
+Wed Apr 9 23:01:44 1997 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * nt/config.h: NT has HAVE_FCNTL_H
+
+ * nt/util.Win32.h: Definition to make a distinction between
+ Windows NT and 95.
+
+ * nt/utilnt.c: call set console title on Windows 95.
+ Choose the proper shell depending on the Windows version.
+
+ mc_rmdir: implement a Windows 95 version.
+ mc_rename: same.
+
+Tue Apr 8 19:05:37 1997 Jim Smelansky <jim@axis.donetsk.ua>
+
+ * mc.ext.in: rexx, wavww, rar and dbf additions.
+
+ * extfs/rar: new updated version
+
+Mon Mar 31 21:06:56 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/ftpfs.c: Removed the no-op macro 'wipe_password'. There is
+ a function wipe_password in src/util.c which overrides a string
+ with zero and frees the previously malloced pointer.
+
+ Fixed memory leaks, prevent freeing of NULL pointers
+
+ * view.c (regexp_view_search): Avoid freeing a pointer more than
+ once when entering wrong regular expressions on the search dialog.
+
+ * view.c (regexp_search, normal_search): Fixed memory leaks, removed
+ some statements which had no effect
+
+Mon Mar 17 12:03:50 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * configure.in (--with-hsc): fix.
+
+ * vfs/ftpfs.c (ftpfs_get_proxy_host_and_port): Fixed wrong parameter
+ passing (HSC_DEFAULT_PORT was passed as pointer to char instead of
+ passing it as integer)
+
+Sun Mar 16 15:13:08 1997 Michele Marziani <marziani@axpfe1.fe.infn.it>
+
+ * mc.ext.in (html): When invoking lynx use -force_html;
+ When calling netscape or lynx, use %f instead of %p.
+ (type/compress): detect compressed files as well.
+
+Tue Mar 11 11:32:59 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * widget.c (key_left): Add support for control-left, control-right
+ in WInputs.
+
+ * main.c (do_execute): Decouple the dependency of the vfs on the
+ subshell.
+
+ * file.c (copy_dir_dir): Do not create the directory if it already
+ exists.
+
+Fri Feb 28 11:49:56 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * src/*, vfs/*: Removed compiler warnings about missing prototypes,
+ unused variables, etc.
+
+ * tk/*: Removed compiler warnings about missing prototypes and
+ wrong/missing return values
+
+ * tk/tkinfo.h, tk/tkscreen.h, tk/tkwidget.h: New files with
+ prototypes needed by src/* (tk edition)
+
+ * mfmt.c (main), tk/tkinfo.c (x_show_info): Corrected wrong
+ parameter count in one function call
+
+ * tk/tkwidget.c (x_create_gauge): Changed the returntype from
+ void to int because the return value is used by gauge_callback.
+
+Thu Feb 27 17:50:22 1997 Paul Sheer <psheer@icon.co.za>
+
+ * tk/tkscreen.c: new compute_font_size function created to
+ work with tcl/tk8.0.
+
+ * edit/edit*: emacs key binding option added. Can be envoked
+ with edit_key_emulation=1 in the ini file. 0 is normal keys.
+
+ * mcedit.1: updated
+
+Wed Feb 26 11:41:18 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * key.c (get_event): Now it returns either a key sequence code or
+ EV_NONE or EV_MOUSE. These were already implemented but were
+ hardcoded to the constants -1 and 0 respectively. This allows the
+ C-@ key to be processed.
+
+Tue Feb 25 20:21:00 1997 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * extfs/lha: Updated the lha filesystem and included a command
+ for running an executable from within an lha archive suggested
+ by Zdenek Kabelac <kabi@informatics.muni.cz>
+
+ * extfs/: Renamed cpio, deb, rar, rpm as *.in files and altered
+ config.in to create these VFS's for cleaner compilation
+
+Sun Feb 23 14:52:12 1997 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * mcedit.1, mc.sgml, mc.1: Spelling fixes to the internal editor
+ documentation.
+
+Sun Feb 23 20:00:00 1997 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * src/Makefile.in (uninstall:) make uninstall removed /bin/rm; Added
+ a semicolon after "cons.saver" so the line is not interpreted as
+ "rm ... cons.saver /bin/rm ..."
+
+ * src/view.c (hex_search) Added code to set the hex editing cursor to
+ the start of the found text after a hex search. Left ASCII search
+ undisturbed; in the case of searching for ASCII then switching to
+ hex mode, the hex edit cursor is at the beginning of the line
+ containing the found text, an artifact of setting the hex edit
+ cursor to a byte position ending in 0 to make hex navigation a
+ little easier.
+
+ * src/view.c HexEdit seems stable enough for release as a View
+ suboperation available from function key F4 Hex under F3 View.
+
+
+Sun Feb 23 14:08:00 1997 Yuri Elkin <yury@intruder.mktg.stratus.com>
+
+ * tar.c (tarfs_get_path): Flush tarfs cache if the tar file we are
+ openning has been modified since the time we loaded it into the
+ cache.
+
+Sun Feb 23 14:00:45 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * dir.c (handle_path): New function used by find.c and panelize.c
+ instead of handle_dirent. handle_path is a simplified handle_dirent.
+ The difference is that handle_path doesn't pay attention to the
+ settings of 'Config/Configuration/show Backup files' and 'Config/
+ Configuration/show Hidden files'. Moreover handle_path can't be
+ used with a filemask.
+
+ The main reason for introducing handle_path was to make it
+ possible to panelize hidden and backup files regardles of the config
+ settings.
+
+ I used the opportunity to get rid of struct spaced_dirent in
+ find.c and panelize.c. It was only used to pass parameters to
+ handle_dirent. In theory this could be a problem because the
+ d_name member has only space for a filename (at least on linux)
+ but it was used to pass a complete path (directory + filename).
+
+ * dir.h: Added prototype for handle_path
+
+ * find.c (find_file), panelize.c (do_external_panelize): Moved
+ from struct spaced_dirent and handle_dirent to handle_path
+
+ * view.c (view_handle_key): Enabled input of hex digits B-F for
+ left side data entry (hex editing).
+ Use of is_printable for right side data entry.
+
+ * widget.c (button_callback): Remember if button is focused (WButton's
+ selected memeber wasn't used up to now).
+ Formerly changing the text of a focused button the button wasn't
+ redisplayed with the correct color (e.g. the Start/Stop button of
+ the find dialog).
+
+ * cmd.c (dirsizes_cmd): Fixed memory leak
+
+ * vfs/mcserv.c (get_port_number): There was a return statement
+ without value hidden in the macro DO_QUIT(). I added a macro
+ which returns a value. Now there are two macros: DO_QUIT_VOID()
+ and DO_QUIT_NONVOID().
+
+ * vfs/mcserv.c (main): Added an additional error check.
+
+ * vfs/*: Removed compiler warnings about missing prototypes,
+ unused variables, etc.
+
+Sun Feb 23 13:46:04 1997 Dan Nicolaescu <DONE@DONE>
+
+ * Wrote makefiles :-)
+
+ * chmod.nt.c, drive.nt.c: minor bugs fixed (incorrect number of
+ params)
+
+ * util.WinNT.c (geteuid): added #ifdef WINNT
+
+ * slint.nt.c (mc_refresh): added this (copied from src/slint.c)
+
+ * utilnt.c (vfs_get_current_dir): dummy function, the vfs
+ currently does not work for win32, but this function is called
+ (vfs_current_is_extfs): see vfs_get_current_dir
+ (vfs_file_is_ftp): see vfs_get_current_dir
+ (mc_utime): see vfs_get_current_dir
+ (extfs_run): see vfs_get_current_dir
+
+Thu Feb 20 11:32:04 1997 Yuri Elkin <yury@intruder.mktg.stratus.com>
+
+ * main.c: Add '-e' flag to the help output.
+
+ * configure.in: Install mcedit if it was compiled in.
+
+Tue Feb 18 22:02:50 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * ext.c (regex_command): Added support for including a global
+ entry with the "Include=" tag.
+
+Sun Feb 23 20:00:00 1997 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * src/Makefile.in (uninstall:) make uninstall removed /bin/rm; Added
+ a semicolon after "cons.saver" so the line is not interpreted as
+ "rm ... cons.saver /bin/rm ..."
+
+ * view.c (hex_search) Added code to set the hex editing cursor to
+ the start of the found text after a hex search. Left ASCII search
+ undisturbed; in the case of searching for ASCII then switching to
+ hex mode, the hex edit cursor is at the beginning of the line
+ containing the found text, an artifact of setting the hex edit
+ cursor to a byte position ending in 0 to make hex navigation a
+ little easier.
+
+ * view.c HexEdit seems stable enough for release as a View
+ suboperation available from function key F4 Hex under F3 View.
+
+ * lib/mc.ext.in (lha) Amended the lha entry to include upper case
+ file extensions LHA|LZH and implemented the lha Virtual Filesystem
+ instead of outputting just the file list.
+
+Mon Feb 17 12:41:32 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * widget.c (button_callback): Special FOCUS case for Tk edition:
+ the default button is actually a frame+button. The default dlg.c
+ code will focus the frame (and thus, the focus will not be
+ shown). By adding a focus response to WIDGET_FOCUS, the code can
+ focus the correct widget.
+
+ * mc.tcl: Keyboard bindings now affect all TkMC instead of being
+ done in a per-window basis. This fixes several problems.
+
+ * screen.c (do_search): Make sure we unselect the item before
+ changing the selection. Tk version needs this.
+
+ * cmd.c (set_panel_filter): Make a version that allows setting the
+ filter for any panel.
+
+ * ext.c (regex_command): Separate returned tags with the '='
+ symbol (since this one can't be part of the tag name). This
+ extends the usefulness of the popup menus in the Tk edition.
+
+ * dialog.c: Do refreshes on X. This fixes the problem with the
+ masks and the rereads not working.
+
+ * slint.c: Provide X version for the refresh screen. This is a
+ nop.
+
+ * find.c (view_currently_selected_file): Check if there is a
+ selected file before attempting to view it.
+
+Fri Feb 14 00:02:40 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkscreen.c (x_fill_panel): Added some support for coloring
+ directory entries.
+
+ * mc.tcl: cleaned up code for the tags in the panels. This is
+ used by the new coloring code.
+
+Fri Feb 14 12:49:22 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * find.c (find_file): Added the correct useage of struct dirent
+ for some operating systems (e.g Solaris 2).
+ A comment regarding this is contained in ftpfs.c (search for
+ NEED_EXTRA_DIRENT_BUFFER)
+
+ * find.c (do_find): The status of the start/stop toggle button
+ wasn't set right sometimes.
+
+Thu Feb 13 22:42:34 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * mc.tcl, tkscreen.c: Made the sort bar useful.
+
+ The code is small-icon-ready.
+
+ Resizing works properly now.
+
+Thu Feb 13 13:05:45 1997 Yuri Elkin <yury@intruder.mktg.stratus.com>
+
+ * hotlist.c: quote backslashes on pathnames when saving.
+
+Thu Feb 13 10:29:36 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * extfs.c (extfs_fill_names): Fix crash when expanding a zip on a
+ floppy drive.
+
+ * panelize.c (remove_from_panelize): Don't allow to remove
+ the entry "Other command" from the list of commands.
+ This entry is always added on startup so there's no need to
+ remove it and most important I remove one posibility to
+ segfault (when removing from an empty list).
+
+ * panelize.c (external_panelize): Don't run the external
+ panelize command on non local file systems.
+
+ * panelize.c (do_external_panelize): Fixed possible memory leaks.
+
+Wed Feb 12 13:05:01 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/editcmd.c (string_regexp_search): Avoid freeing a
+ pointer more than once.
+
+ * edit/editcmd.c (edit_find_string): Fixed possible memory
+ leaks
+
+ * dir.c (do_reload_dir): fixed possible memory leaks
+
+ * find.c (search_content): fixed memory leak
+
+ * find.c (do_search): do_search opens a directory stream and
+ stores the pointer to it in a static local variable. I added
+ the posibility to close the directory stream from outside
+ without making the variable in question global. Call it a
+ ugly hack if you want.
+ (Formerly the stream remained open e.g. if ESC was hit while
+ the search was runing)
+
+ * find.c (find_file): Every found file is added only once into
+ the current panel when button 'Panelize' is pressed.
+ I also removed two bugs which I could reproduce and which
+ caused coredumps.
+
+ * find.c (do_find): fixed memory leaks
+
+ * screen.c (panel_reload): fixed possible memory leak
+
+Tue Feb 11 13:14:52 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c: some keys are better ignored.
+
+ * screen.c (get_sort_fn): Use the sort_types array instead of
+ using screen's.c table.
+
+ * dir.c: Added more sorting types, this is basically just used for
+ the GUI versions that may want this accessible.
+
+Thu Feb 6 15:01:44 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/edit*: Added goto line function. Added delete line
+ function.
+
+Wed Feb 5 18:08:47 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit/editdraw.c, edit/editwidget.c: Changed some of the
+ draw code to properly check for waiting key presses. This
+ should speed things up a bit. Redraws all when you let
+ up key repeating. I think I should add a 'dirty' variable
+ like in view.c.
+
+Wed Feb 5 12:29:24 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * background.c (background_attention): Added missing break to
+ switch-statement
+
+ * cmd.c (dirsizes_cmd), panelize.c (do_external_panelize): Changed
+ message-type from INSERT to NORMAL
+
+ * file.c (copy_dir_dir): Replaced one chmod with mc_chmod
+
+ * tk/Makefile.in: Added missing dirhist.o to OOBJS to make the
+ tk-version compile
+
+ * achown.c, chmod.c, chown.c: Made the Advanced chown command,
+ the Chmod command and the Chown command vfs-aware; added missing
+ destroy_dlg; added some simple error-handling
+
+ * vfs/vfs.c, vfs/vfs.h: Added new function vfs_current_is_tarfs
+ now needed by achown.c, chmod.c and chown.c
+
+
+Mon Feb 3 09:33:55 1997 D. Hugh Redelmeier <hugh@mimosa.com>
+
+ * layout.c (set_display_type): Cast to correct type.
+
+ * screen.c (panel_event): remove static.
+
+ * hotlist.c (l_call): remove warning.
+
+Sun Feb 2 14:04:57 1997 Yuriy V. Elkin <yury@intruder.mktg.stratus.com>
+
+ * hotlist.c (CHECK_BUF): Use realloc only if the pointer has a value.
+
+Wed Jan 29 14:01:30 1997 Tomasz J. Cholewo <tjchol01@mecca.spd.louisville.edu>
+
+ * dir.c: Fix sorting. We assumed that the first directory entry
+ returned by readdir would be the "." and ".." entries. This is
+ not the case under some operating systems, and ftp fs was already
+ bitten by this. This fix, finds the ".." dir and puts it at the
+ beginning.
+
+Thu Jan 30 19:52:01 1997 Paul Sheer <psheer@icon.co.za>
+
+ * main.c: fixed view file from command line. Added edit file
+ from command line with the extra option -e <file>. Added
+ function prepend_cwd() which adds cwd to a fname if its not
+ an absolute path (does a function like this exist already?).
+ Does -v <file> now do what was intended?
+
+ * main.c: added check if viewing or editing from command line
+ to always output "." even if -P is set. Otherwise we get a
+ segfault.
+
+ * main.c: added check if mcedit is in argv[0]. if so we are an
+ editor, so edit file on command line.
+
+ * edit/edit.c: made some changes to push_action to reduce stack
+ usage.
+
+ * edit/editcmd.c: made changes to handle getting a null file.
+ goes to new file for mcedit without args.
+
+ *doc/mcedit.1: man page created.
+
+Mon Jan 27 11:17:37 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * vfs/tar.c (uncompress_tar_file): Check for error while
+ uncompressing to temporary file (the main error is probably
+ writing to a full tmp-volume)
+
+ * vfs/tar.c (tar_chdir): fixed memory leak
+
+ * util.c (load_file), widget.c (assign_text): fixed memory leaks
+
+ * vfs/extfs.c (free_archive): Added check before freeing
+ archive->name because it's NULL for a mtools-fs e.g. 'cd a:'
+
+ * vfs/extfs.c (read_extfs_archive, extfs_close): fixed
+ memory leaks
+
+ * vfs/extfs.c (extfs_done): New function in order to free memory
+ at program termination; it made it easier to me to find the
+ memory leaks
+
+ * vfs/extfs.h: Added prototype for extfs_done
+
+ * vfs/mcfs.c (mcfs_get_path, mcfs_rpc_two_paths, mcfs_rpc_path,
+ mcfs_rpc_path_int, mcfs_rpc_path_int_int, mcfs_open,
+ mcfs_opendir, mcfs_stat_cmd, mcfs_readlink, mcfs_chdir,
+ mcfs_forget): fixed memory leaks
+
+ * vfs/utilvfs.c (get_host_and_username): Now at return there's
+ always the same state (*host and *user malloced, *pass malloced
+ or NULL)
+
+ * vfs/vfs.c (mc_get_current_wd, mc_utime, mc_chdir): fixed
+ memory leaks
+
+ * vfs/vfs.c (vfs_canon): Added check before freeing because
+ 'arc_name' may be NULL (extfs for mtools e.g. 'cd a:')
+
+ * vfs/vfs.c (vfs_shut): Added call to new function extfs_done
+
+ * vfs/vfs.c (vfs_force_expire): fixed memory leak
+
+Mon Jan 27 10:51:30 1997 Tomasz J. Cholewo <tjchol01@mecca.spd.louisville.edu>
+
+ * view.c (view_percent): File percentage values in the built-in
+ viewer are wrong for files bigger than approx. 20MB because of
+ arithmetic overflow in the view_percent function in view.c.
+
+Mon Jan 27 10:42:13 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * main.c (do_panel_cd): My third patch changes the behaviour of mc
+ when leaving the tarfs. In that case the working directory of the
+ subshell isn't changed to ".." but to the directory of the current
+ panel.
+
+Fri Jan 17 17:21:48 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * edit/Makefile.in: clean up, one could see that it was an
+ adapted vfs/Makefile.in
+
+ * background.c: added missing #include "mad.h"
+
+ * cmd.c (compare_dir): count and bytes of marked files were
+ calculated sometimes wrong
+
+ * help.c (interactive_display): fixed possible memory leak
+ in size of mc.hlp
+
+ * hotlist.c (add2hotlist_cmd): hotlist was not marked as
+ modified if only button 'Add current' was used i.e. that
+ there was no chance of saving the hotlist unless there
+ hadn't been other modifications
+
+ * hotlist.c (load_hotlist): removing [Hotlist] in ~/mc.ini
+ didn't work when 'auto save setup' wasn't activated.
+
+ * hotlist.c (save_hotlist): a saved hotlist is marked as
+ unmodified
+
+ * learn.c (learn_button): don't allow definition of enter
+
+ * learn.c (learn_save): without 'Auto save setup' the new
+ key-definitions were not saved
+
+ * main.c (done_mc): without 'Auto save setup' activated a
+ modified hotlist wasn't saved at program termination
+
+ * mad.c (mad_realloc): MAD complained about 'realloc (NULL, size)'
+ but that's legal C and the same as 'malloc (size)'
+
+ * screen.c (panel_key): hitting C-s more than once the next
+ file matching the search string is searched for instead of
+ starting a new search, any abort key stops filename search
+
+ * enable abort of filename search with the usual abort keys
+
+ * tree.c (tree_destroy): fixed memory leak
+
+ * tree.c (do_tree_check): F2 on very last directory in
+ an tree view didn't work
+
+ * tree.c (maybe_chdir): removed compiler warning about
+ missing return value
+
+ * tree.c (start_search, tree_key): Added same search method
+ like with a panel in listing mode, i.e. C-s starts search,
+ further C-s move to the next matching directory, any abort key
+ stops search
+
+ * tree.c (global variable tree_keymap[]): made an invisible
+ { 0, 0 } visible before one has the idea of removing an needless
+ comma
+
+Sat Jan 18 18:18:40 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c: Fixed segfault on when C-n ing.
+
+Thu Jan 16 11:11:50 1997 Norbert Warmuth <k3190@fh-sw.de>
+
+ * layout.c (set_display_type): Fix a bug where the current_panel
+ variabel would not point to a WPanel * but to something else. We
+ are looking for a better fix.
+
+Tue Jan 14 16:53:26 1997 namsh <namsh@amuna.rms.lgic.co.kr
+
+ * find.c (search_content):
+
+Tue Jan 14 15:11:15 1997 Leos Bitto <bitto@kolej.mff.cuni.cz>
+
+ * cons.saver.c: make it work with virtual consoles bigger than tty9.
+
+Mon Jan 13 20:58:28 1997 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * dirhist.c: Added routines for keeping track of recently used
+ directories.
+
+Tue Jan 28 12:56:39 1997 Paul Sheer <psheer@icon.co.za>
+
+ * option.c: Added 'use internal edit' check box to options list.
+
+ * mc.sgml: Added help for config for this.
+
+ * edit/*: Now displays full 8 full bit. (This screws up completely
+ when editing binaries files because terminal display chars
+ as ^X which is two chars wide.)
+
+Sat Jan 18 18:18:40 1997 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c: Fixed segfault on when C-n ing.
+
+Mon Jan 13 18:24:41 1997 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * ftpfs.c (ftpfs_get_proxy_host_and_port): Handle properly proxyes
+ that have a port number specified as well.
+
+Fri Jan 10 02:10:45 1997 Norbert <k3190@fh-sw.de>
+
+ * cmd.c (quick_chdir_cmd): fixed memory leak
+
+ * cmd.c (view_other_cmd): changing to subshell with C-o and
+ typing 'exit' doesn't cause an segfault any more.
+ Now MC exits quietly, to achieve this minor changes in cmd.c
+ (view_other_cmd), command.c (enter), main.c (do_execute,
+ quit_cmd_internal, done_screen, main), subshell.c (sigchld_handler),
+ subshell.h were necessary
+
+ * command.c (command_new): fixed memory leak
+
+ * main.c (do_execute): fixed memory leak
+
+ * main.c (main): call of flush_extension_file in order to free
+ malloced memory on program termination. It just makes it easier
+ to find memory leaks with MAD or something similar.
+
+Mon Dec 23 10:13:04 1996 Norbert <k3190@fh-sw.de>
+
+ * profile.c (profile_forget_profile): Bug fixed which caused
+ complete loss of settings for all .ini files instead of loss for
+ only one .ini file as wanted.
+
+ * vfs/mcfs.c (mcfs_forget): fixed incorrect parameter passing to
+ mcfs_open_tcp_link (port itself instead of pointer to port was
+ passed)
+
+ * vfs/tar.c (tar_open): fixed disregarded operator precedence
+
+ * hotlist.c (CHECK_BUFFER): fixed disregarded operator precedence
+
+ * hotlist.c (add2hotlist_cmd): inserted check of malloc's return value
+ by using of xmalloc (only a 'cosmetic' change)
+
+ * hotlist.c (remove_group, remove_from_hotlist, done_hotlist):
+ now freeing should work: for HL_TYPE_GROUP hotlist->directory is
+ NULL and Janne's Memory Allocation Debugger complained e.g. when
+ removing a group from the hotlist
+
+
+Thu Dec 26 19:03:47 1996 Paul Sheer
+
+ * edit.c: Fixed a bug that caused undo to sometimes stop
+ working when the undo stack wrapped. (This can be BAD news for
+ someone if they suddenly found they couldn't undo -- sorry guys.
+ I've now tested it quite thoroughly with a visual on whats going
+ on in the stack and it works perfectly.)
+
+ * editcmd.c: memmove() command added if HAVE_MEMMOVE not defined;
+ return value of sprintf() now ignored.
+
+ * configure.in: check for memmove func added.
+
+ * edit/*: Lotsa minor odds and ends.
+
+Wed Dec 18 15:13:04 1996 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * mc.ext: Use lha file system.
+
+ * Makefile.in: Create proper mc.tcl file.
+
+Wed Dec 18 15:13:04 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * widget.c (listbox_key): Do not process any key command if the
+ listbox list is emtpy.
+
+Tue Dec 17 12:59:13 1996 Christophe MEYNARD <Christophe.Meynard@ign.fr>
+
+ hotlist.c (update_path_name): Fixed crash in hotlist.
+
+ (add_new_group_input): Initialize the text field in
+ the quick widget.
+
+Tue Dec 17 12:59:13 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * configure.in: By default compile the builtin editor now.
+
+ * mc.ext: Do not provide an action for editting, this is needed
+ for using the internal editor.
+
+Mon Dec 16 14:26:55 1996 Norbert Warmuth <k3190@fh-sw.de>
+
+ * widget.c (insert_char): Fixed a buffer overrun: in the original
+ code there is always one location too much copied in the function
+ "insert_char()" in file "src/widget.c".
+
+Mon Dec 16 14:26:55 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c (view_handle_key): Took the Hex Edit changes out. Hex
+ Edit will be shipped separetedly until the code is ready for
+ public release.
+
+Fri Dec 13 19:15:39 1996 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * view.c: Added support for using the viewer as an hex editor. Woo
+ Woo!
+
+Wed Dec 11 20:54:53 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkscreen.c (tk_panel_callback): Added drag/drog for the Tk
+ version.
+
+ * mc.tcl: Lots of enhancements.
+
+Sat Dec 7 13:54:43 1996 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * extfs/lha.in (LHA): New external file system handler for the LHA
+ file format.
+
+Fri Dec 6 14:57:43 1996 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * vfs/extfs/README: Updated the information on creating an
+ external file system handler.
+
+Wed Dec 11 14:07:50 1996 Paul Sheer <psheer@icon.co.za>
+
+ * mc.sgml: created proper editor help. sgml page is not tested
+ though.
+
+Wed Dec 11 10:57:28 1996 Paul Sheer <psheer@icon.co.za>
+
+ * key.c, key.h: New command: get_modifier() which gets the state
+ of the alt/shift/control keys.
+
+ * edit/*: Added in key translations for shift arrow text
+ highlighting using get_modifier(). Added insert/overwrite
+ support.
+
+Thu Dec 5 00:06:31 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkscreen.c (x_filter_changed): Added a tick border to default
+ buttons.
+
+Wed Dec 4 18:41:37 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * mc.tcl: Put some nicer colors for Tk input lines.
+
+ Changed the cwd display to show the file mask as well. It now is
+ also a menu, so this will show a menu that can run some commands
+ on the current directory (should I remove some of the stuff from
+ the left/right menus then? Probably everything should be moved
+ here for the Tk edition).
+
+ * tkscreen.c (tk_invoke), mc.tcl: Now the Tk version has context
+ popup menus just like Jakub's XView version and TkDesk
+ (tk_load_popup):
+
+ * mfmt.c: Added this program that I had here for a long time and
+ had not been included in the distribution.
+
+Tue Dec 3 20:09:35 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkmain.c (tkmc_callback), mc.tcl: Generate a escape char when
+ a window is closed by the window manager. This keeps the
+ information consistent (ie, windows don't get killed behind our
+ backs).
+
+Mon Dec 2 23:51:59 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkscreen.c (x_unselect_item): Cleaned up the panel managing
+ routines. Added focus/unfocus calls.
+
+Wed Dec 4 15:16:59 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit*.c: Support for Winsnows/Macinosh shift-arrow text
+ highlighting, although no keys have been defined as yet to
+ actually do highlighting. Fix of potential bug overwriting
+ line[1024] in editdraw.c.
+
+Sat Nov 30 09:04:24 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * background.c (parent_call_string): Our parent/child protocol now
+ can handle strings.
+
+Fri Nov 29 21:05:52 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * features.inc: Moved th configuration report information to this
+ file. Now the -V option will show information on which options
+ were compiled into the program.
+
+ * background.c: Moved the general purpose background code to this
+ file.
+
+Fri Nov 29 18:57:37 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * hotlist.c: Added Lynx style navigation.
+
+ * hotlist.c: this version will finally get rid of [Hotlist] and Co
+ in ~/.mc.ini If no ~/.mc.hot exists, it will copy old enrties and
+ warn user about new file; if ~/.mc.hot already exists, you have
+ the choice to keep old entries, to remove them or to add them in
+ separate group for later review. I tried to make it foolproof, but
+ no warranty ;) anyway, the betatesters can just tell "Remove".
+
+ * changed "hotlist_params" to "hotlist_state" (seems to me more
+ logical).
+
+ * added "modified" flag so MC won't rewrite ~/.mc.hot every time.
+
+ * preliminary added "unfolded" parameter - the intent is to show
+ all groups at once in tree like structure; I tried to make simple
+ implementation, but the result was less than satisfactory and I
+ backed out changes. Sometimes ...
+
+ * when copying from ~/.mc.ini to ~/.mc.hot I try to make shure it
+ works; so I check if ~/.mc.hot was written (actually I *intended*
+ to check - it probably doesn't work 100%) Changed definition of
+ load_hotlist() from void to int.
+
+ * setup.c, main.c: because we now need to tell user what's going
+ on, moved hotlist loading after screen initialization.
+
+Thu Nov 28 11:50:32 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * hotlist.c: add2hotlist_cmd (): length of current directory name
+ was not checked; in case of very long name "Add current" display
+ was distorted. The patch tries to truncate name to reasonable
+ length (I thought it appropriate to keep dialog inside of hotlist
+ main dlg window - it could be made something more wide if enough
+ demand ;)
+
+ * update_path_name (): directory path was truncated but with
+ incorrect lenth - long paths were getting out of bounding box.
+
+Tue Nov 26 12:29:27 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * ftpfs: ftpfs open mode (passive or active) is now controlled by
+ the variable ftpfs_use_passive_connections variable.
+
+Tue Nov 26 12:28:53 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * ftpfs.c: Moved all of the proxy checking to ftpfs_check_proxy;
+ Never use passive mode if we are using a proxy host.
+
+Thu Nov 28 20:14:34 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit*.c: macro now creates ~/cooledit.macros automatically
+ Execute macro now does nothing if key not found, instead of error.
+ Save file sets permissions on creating a new file.
+
+Mon Nov 25 20:19:40 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * file.c (panel_operate): remove code for background operation if
+ this is not compiled in (thanks to done@nexus.sorostm.ro (Dan
+ Nicolaescu) for pointing this).
+
+ * ftpfs.c (ftpfs_close): Avoid flushing the directory on every
+ store operation if it is not absolutely necessary. This is an
+ optimization that I missed.
+
+ * vfs/*.c: Make all of the virtual file systems use the message
+ stubs. We still need a stub for the input_dialog. I will do this
+ one next (as well as moving the stub functions out from file.c).
+
+Mon Nov 25 13:41:19 1996 Luca Berra <bluca@comedia.it>
+
+ * ftpfs.c (initconn): Made passive connections the default.
+ Fallback to active connections if this fails (per connection).
+
+Mon Nov 25 09:31:57 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * src/hotlist.c: Use input lines with a non-null default value.
+ Better redrawing.
+
+ * src/boxes.c: New proxy options: Can make the usage of the proxy
+ a global option (no need to use the ftp://! syntax if the
+ ftpfs_always_use_proxy variable is set, check the man page for
+ details on this).
+
+ * src/widget.c: Mouse support;
+
+Mon Nov 18 20:31:47 1996 Elliot Lee <sopwith@cuc.edu>
+
+ * xv: Patches to make it compile.
+
+Mon Nov 18 20:15:14 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * ftpfs.c: Put the CD/LS optimization back. We know do an ls on
+ $PATH/. and we magically get the symlink information we were
+ missing with this optimization in the previous attempt.
+
+Tue Nov 12 16:47:52 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * hotlist.c: Bug fixes. Made the hotlist window resizable again.
+
+Tue Nov 12 18:54:10 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit/*: changes to low level insert, delete etc to allow inserting
+ of chars before the display window without the window going out
+ of sync -- fixes replace bug that I hope only I knew about + some
+ optimisation of push/pop_action routines (hope it doesn't break
+ undo).
+
+ # layout.c: added call to edit_adjust_size for window resizing.
+
+Mon Nov 11 09:24:02 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c: Re-enabled the CD remote-path; LS "." code instead of
+ the optimzied (and broken) code that did LS remote-path directly.
+
+Mon Nov 11 09:16:01 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * edit/*: changes to structure initializer
+
+ edit_move_forward3() returns *float* but is called in argument
+ conetxt which expects *int*. And without function prototypes
+
+ * util.c: more changes were neccessary to use mc://host syntax
+
+ * vfs/ftpfs.c: new -password code failed for non-anonymous logins
+
+ * hotlist.c: add2hotllist() - corrected stupid error which resulted
+ in empty hotlist. If you had it, remove empty ~/.mc.hot before
+ running new MC!!!
+
+ * widget.c (listboxes): Can now specify the position where the
+ item is inserted.
+
+ * mcfs.c: more changes to adapt mc:// syntax.
+
+ * vfs.c: more changes to adapt mc:// syntax. (I hope it to be the
+ last)
+
+Thu Nov 7 12:34:03 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * mcfs.c (mcfs_forget), ftpfs.c (ftpfs_forget): Actually, instead
+ of forgeting about the connection, we now update it. We close the
+ socket that is being used by the child and reopen the connection.
+
+Thu Nov 7 21:16:59 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit*.c: Change c-o to load file. c-l now refreshes
+ screen. Menu command added to refresh screen. Menu command
+ added to insert a literal. C-z and c-x now move word left
+ and right respectively.
+
+ * editmenu.c: About box added.
+
+ * mc.hlp: Editor help added.
+
+Wed Nov 6 12:23:14 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * editcmd.c: Not every compiler takes non-statical initializer of
+ structures. Also, dlg_init (or is it init_dlg?) crashes, if passed
+ *empty* (as opposed to *no* - NULL) tk name.
+
+ * main.c (handle_args): If the program ends while handling args
+ and the -P option was used report the current working directory.
+
+ * ftpfs.c (login_server): Removed the - option altogether.
+
+Sat Nov 2 17:31:21 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c: Rewrote edit_move_forward/backward functions to
+ handle eof properly.
+
+Fri Nov 1 13:08:22 1996 Paul Sheer <psheer@icon.co.za>
+
+ * editdraw.c: Status line drawing improved for screens with
+ small widths.
+
+Thu Oct 31 13:08:22 1996 Paul Sheer <psheer@icon.co.za>
+
+ * editcmd.c: Added regular expression search and replace. Checks
+ for overwriting an existing file if you change the filename.
+
+Sun Oct 27 21:17:11 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit*.c: Slight changes to allow compilation with gcc's
+ options -ansi -pedantic. Checks for macro NO_EDITOR added so
+ that '#define NO_EDITOR' in config.h will leave out the editor.
+ Editor now adds 30kb (9%) to the mc binary size (compiled without
+ -g and with -O2).
+
+Sun Oct 27 11:24:07 1996 Paul Sheer <psheer@icon.co.za>
+
+ # editwidget.c, editmenu.c: alt-f, alt-e... now drops menus
+ File, Edit etc.
+
+Sun Oct 27 10:45:40 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c: Date/time command added.
+
+Sun Oct 26 00:00:00 1996 Paul Sheer <psheer@icon.co.za>
+
+ * editwidget.c, editmenu.c (new): Pull-down menus added.
+ function menubar_event required to be non-static so that
+ it can be called from editwidget.c.
+ Macros made to work with any key. Quote feature added.
+ Both use new edit_raw_key_query dialog sub. editcmddef.h
+ added which now contains all the command defs.
+
+Fri Oct 25 12:00:00 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit*.c: Macro record and execution added.
+
+??? Oct ?? 12:00:00 1996 Paul Sheer <psheer@icon.co.za>
+
+ * editcmd.c: Scanf search and replace added. Function edit_adjust_size
+ added for resizing of the widget analogous to view_adjust_size.
+ Must be called from layout.c just like view_adjust_size.
+
+??? Sep ?? 12:00:00 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c, editwidget.c, editdraw.c, edit.h, editcmd.c,
+ edit_key_translate.c: Created from single source file, code
+ completely overhauled. Undo now also undoes marking. Some
+ drawing and behavioural problems solved. All key actions
+ now work through commands, and the command to key mappings are
+ done by a seperate file edit_key_translate.c.
+
+??? ??? ?? 12:00:00 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit.c, edit.h: Created from view.c as a simple editor, with
+ same look, with block commands and undo. Command to call is
+ int edit(char *filename);
+
+
+Tue Nov 5 00:21:22 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * ftpfs.c (login_server): Do not send the dash if the user is
+ debugging the connection.
+
+Mon Nov 4 14:21:48 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * edit/: updated to latest version from Paul Sheer.
+
+ * ftpfs.c: Fixed a couple of memory leaks in the code.
+
+ * mcfs.c (mcfs_forget): when searching for a connection
+ description, check also the port number.
+
+ * vfs.c, vfs.h: Added a way to forget about a connections. This
+ is required by the background code. The idea is that the
+ background copy of the program keeps the information for what it
+ will copy/move (ie, the open sockets for mcfs and ftpfs) and the
+ parent code has to open a new connection.
+
+ * ftpfs.c (ftpfs_forget), mcfs.c (mcfs_forget): Implementation of
+ the ftp forget-about-a-connection code. This routine just makes
+ the hostname an empty string, so that no further matches will
+ occur when referencing the file system, thus forcing a connection
+ to be opened again.
+
+Fri Nov 1 15:40:31 1996 Paul Sheer <psheer@icon.co.za>
+
+ * edit/: Built in editor.
+
+Fri Nov 1 15:40:31 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * find.c (find_file): Add a button for the View option so that
+ people actually know it is possible to view those.
+
+ * file.c (real_query_recursive): Add background operations.
+
+ * replaced refresh for mc_refresh in all of our code. This serves
+ two purposes: X11 code will never refresh the console ever again
+ (we provide a wrapper in tkslint) and the background tasks will
+ not output text to a console.
+
+ * slint.c (mc_refresh): refresh only if we are not a background
+ task.
+
+ * tkslint.c (mc_refresh): Empty routine, may call update idletasks
+ in the future.
+
+ * file.c (background_attention): More background code goes in.
+
+Fri Nov 1 00:07:59 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (parent_call): I defined wrappers around the functions to
+ let both the foreground and background processes call these
+ routines in a less hacky way (ie, we won't be giving the
+ background process control of the terminal ever). Now, I plan on
+ using an rpc method for the background process to call the parent
+ process. The idea of this is that the X11 editions of the program
+ will benefit from this.
+
+ * cmd.c (compare_dir): Add compare only based in size.
+
+ * wtools.c (common_dialog_repaint): Not all dialogs have titles. Fix.
+
+ * hotlist.c (init_hotlist): Make the size of the dialog
+ proportional for the screen size.
+
+ * find.c (find_file): ditto. This one was easier.
+
+Sat Oct 19 16:32:35 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * extfs.c (extfs_init): Use a better structure for extfs_extensions.
+
+Mon Oct 14 19:29:38 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * ftpfs.c (login_server): Use a dash in front of the username,
+ some ftp servers use this to avoid sending the .messages file.
+ Log the directory ouput when debugging the ftp output.
+
+Sun Oct 13 13:10:34 1996 Alexander V. Lukyanov <lav@video.yars.free.net>
+
+ * mouse.c: Do not open /dev/console. Use the file handle that gpm
+ opens for any operation on the console.
+
+Mon Oct 7 11:32:26 1996 Kikutani Makoto <kikutani@jdc.ericsson.se>
+
+ * cmd.c (view_file): fixed: return a value from this function,
+ prevents the crash.
+
+Tue Oct 1 16:20:03 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c (load_view_file): When we close the file descritor, set
+ the file field on the WView to -1 so that we don't close the file
+ two times by a mistake. This bug was found by esteban@nuclecu.unam.mx
+
+Sat Sep 21 12:12:45 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * main.c (listing_cmd): Make sure the user_format is set at all
+ times (in the past, we changed the display format on any error,
+ but the wrong format was still there, and because of our broken
+ way of handling mini status it would broke.
+
+Fri Sep 20 06:13:08 1996 Gregor Hoffleit <flight@mathi.uni-heidelberg.DE>
+
+ * find.c (search_content): Use ISASCII from util.h, not isascii.
+
+Thu Sep 19 10:05:52 1996 Liviu Daia <daia@stoilow.imar.ro>
+
+ * Added the rar external fs.
+
+Wed Sep 18 13:54:37 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * wtools.c (query_dialog): Another mistaken widget creation item
+ fixed.
+
+Fri Sep 13 12:54:45 1996 Alexander V. Lukyanov <lav@video.yars.free.net
+
+ * zipfs: prevents doubling of file names for unix-created zip
+ files. It also replaces forgotten awk to @AWK@.
+
+Thu Sep 12 22:27:25 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkslint.c: Provided an routine with empty routines to substitute
+ slint.c. We don't need any terminal handling when running as the
+ Tk version.
+
+ * slint.c: Removed the NT support for slint.c, NT has it's own
+ slint file now.
+
+ * gd.tcl: Added support for editing previously created layouts.
+ To edit a previously creted layout, it is necesary to set the
+ environment variable MCGD_EDIT to the name of the dialog that you
+ want to edit. Removing rows is still done by editing the
+ generated file as well as removing the extra texts and frames.
+
+ * guil.*.tcl: Redesigned most of the layouts, should be nicer.
+
+ * hotlist.c (add_new_entry_cmd): Small fixes to hotlist to make it
+ tk-guiable.
+
+Wed Sep 11 16:30:04 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * panelize.c (init_panelize): Made panelize tk-aware
+
+Tue Sep 10 20:53:41 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * wtools.c: Made tk-aware. Now all quick dialogs should be tk-enabled.
+
+Mon Sep 9 14:09:21 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * boxes.c: Made tk-aware
+
+ * gd.tcl: Saving/restoring of the GUI. I still have not coded the
+ part that would load the saved code and allow the programmer to
+ modify the layout. It is still missing a delete-row feature.
+
+Fri Sep 6 21:05:44 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * tkmain.c (tk_init_dlg): Call the GUI editor, support for
+ different layout styles in the program (the previous mode is to
+ call a routine called layout_NAME, where NAME is the name of the
+ dialog box; the new mode is the one that uses the information
+ generated by the GUI designer).
+
+ * gd.tcl: Minimal interactive GUI designed to layout widgets on
+ the Tk edition of the program. To add GUI designer support to a
+ dialog box it is required that:
+
+ a) All of the widgets have a non-NULL value for the tkname
+ parameter (this is specified when widgets are created).
+
+ b) You add the DLG_GRID flag in the the create_dlg call.
+
+ Once those are met, the GUI designer will pop up automatically the
+ next time the dialog is invoked.
+
+ * tkwidget.c (tk_new_command): Added support for the grided
+ objects. All of the widgets now take an extra parameter: the
+ tkname, a name used to identify the widget from the Tk code that
+ is not renumbered (as did happen with the previous attempts at
+ supporting Tk).
+
+ * dlg.c: Support for the new dialog layout routines.
+
+Tue Sep 3 00:17:11 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * find.c: Fixed panelization when searching inside files.
+ (find_par_start): Use mc_stat instead of stat.
+
+Mon Sep 2 23:48:34 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * subshell.c: before pushing a streams module on svr4, we use
+ I_FIND. Fixes also the calling convention for zsh 3.0. FIXME: We
+ don't need if this will work with older versions of zsh.
+
+ * hotlist.c: Added multi-level hot list to the program.
+
+Mon Sep 2 18:31:24 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c (view), cmd.c: view functions now can take a starting
+ line number.
+
+ * ext.c (regex_command): when asking for the View tag, you can
+ append :number to the tag (View:45) to make the viewer jump to
+ that line at startup.
+
+ * utilunix.c (mc_doublepopen): Bumped the blcok size that the
+ mc_doublepopen uses to be 8192, this provides faster grepping.
+
+ * find.c (find_parameters, find): Added a capability to search
+ information inside files. I believe this will be quite handy for
+ searching files in vfs files.
+
+ Replaced instances of hardcoded path separators for our portable
+ PATH_SEP variables.
+
+ * local.c (local_read): Return proper failure value when errno is
+ not EAGAIN or EINTR.
+
+ * wtools.c: Added routines for common dialog callbacks:
+ dialog_repaint: repaints the background of a dialog.
+ common_dialog_repaint: calls dialog_repaint with defaults colors.
+ common_dialog_callback: Callback intended for sample dialog, it
+ just redraws, nothing fancy.
+
+Mon Sep 2 18:31:24 1996 Aldy Hernandez <aldy@andrews.edu>
+
+ * configure.in, utilunix.c: check for Sequent having
+ get_process_stats for implementing gettimeofday.
+
+ * Use HAVE_SYS_SELECT_H instead of an ifdef for AIX. Sequent and
+ QNX also have fd_set on sys/select.h
+
+Thu Aug 29 12:05:15 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * vfs/mcfs.c: added mc_utime() vfs callback; added local_utime() function;
+ * added mcfs_utime() function;
+
+ implemented RPC utime call; program version is now 2;
+
+ * Version 2 tries to transmit true file timestamps if speaking
+ with anybody with version >= 2 (is it portable?)
+
+ * slightly changed the way mcserv works. Now it becomes "true"
+ daemon if given -d flag (thus it is possible to say just `mcserv
+ -d -f' instead of `mcserv -f -d &') One drawback is, that -v
+ doesn't work for daemon mode; it could be made, but I consider it
+ more as debugging aid. What is neede is syslog() interface for
+ daemon. But I have the ffeling, that mcserv() is not being used
+ by anybody except me ;) and I don't need syslog().
+
+Wed Aug 28 19:14:38 1996 Fernando Magariños <mancha@breogan.iimas.unam.mx>
+
+ * extfs/arc: Added support for .arc and .pak files
+
+Tue Aug 27 00:20:41 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c (block_search): enable interrupts at the beginning of the
+ search and at the end, this should speed up searching.
+
+Mon Aug 26 16:30:13 1996 Miguel de Icaza <miguel@tirania.nuclecu.unam.mx>
+
+ * view.c (hex_search): Added missing toupper. Now hex searches
+ should work again.
+
+ * cmd.c (nice_cd): If the user types in the prefix for the ftp://
+ directory, do not insert one at the beginning.
+
+Sat Aug 17 15:37:13 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c: Removed the CWD optimization. If the connection is
+ dropped, then we should resend the CWD again. Thinking about a
+ proper fix for this.
+
+Fri Aug 16 13:31:33 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (command): Invalidate the current path name when the
+ connection is dropped.
+
+Thu Aug 15 22:42:13 1996 Wojtek Pilorz <wpilorz@celebris.bdk.lublin.pl>
+
+ * ftpfs.c (get_line_interruptible): Make sure we don't write past
+ the buffer. Make sure the buffer is zero terminated.
+
+Thu Aug 15 15:00:45 1996 I. Ioannou <roryt@compulink.gr>
+
+ * sldisply.c: SCO doesn't have TIOCGWINSZ.
+
+Thu Aug 15 21:20:09 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * mcserv.c (mc_pam_auth): Added support for Linux-PAM for
+ authenticating users.
+
+Thu Aug 15 15:00:45 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * mcserv.c: most commands look like send_status (unlink (f),
+ errno); It is the text-book example of undefined behaviour. At
+ least by me it returns errno from *previous* syscall, and not from
+ e.g. unlink(f). It results in absolutely wild things sometime
+ (errors with errno 0; MC making wrong decision based on wrong
+ errno and so on). In particular, recursive delete didn't work
+ (probably, due to second bug also). I set errno to 0 in
+ send_status() for the same reason.
+
+ The do_readdir() sometimes worked incorrectly. The following code
+ fails:
+
+ while ((dirent = readdir (mcfs_DIR.dirs [handle]))){
+ .....
+ lstat (dirent->d_name, &st);
+
+ It cannot be assumed, that current directory is that of dirent. It
+ is *not* in case of recursive delete (when I am reading
+ subdirectory first). So I save directory name from opendir() call
+ and use it in readdir(). My patch assumes, that MC always sends
+ absolute pathname in opendir(); so far I have always seen that.
+
+ I tried to add clean up code to remove RPC mapping after exit. I
+ cannot verify it; it always fails by me probably due to bug in
+ portmapper interface functions. It is possible when using rpcbind.
+
+ As a side note, I removed close_handle() call from do_readdir(). I
+ don't understand, what it does there; MC normally makes
+ opendir()/readdir()/closedir() cycle.
+
+ I done minor cleanups in do_opendir(); in particular, it should
+ probably always read RPC request first before doing anything else.
+ Otherwise it will be read on next loop. Currently it is possible,
+ that do_opendir() exits without fetching RPC request.
+
+Wed Aug 14 19:38:13 1996 Andrej Borsenkow <borsenkow.msk@sni.de>
+
+ * mcfs.c: Cache the home directory for the mc file system. This
+ one was causing an rpc message to be sent constantly for home
+ directory operations.
+
+Wed Aug 14 20:30:09 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (open_command_connection): Important ftpfs retry code
+ bug fix: break from the retry loop. This caused a bug that made
+ the program to keep retrying a connection even if it had
+ successfully logged in.
+
+Mon Aug 12 17:30:09 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (do_cd): Now takes an extra argument: it can be either
+ cd_exact or cd_parse_command. If cd_exact is passed, then no
+ further processing is done in do_cd for checking special directory
+ names (- for lwd, and spaces removed at the beginning of the
+ filename). If the parameter is cd_parse_command, then special
+ interpreatation is performed.
+
+ The rule is easy: if we are changing the working directory to a
+ directory specified by the user, then we should use
+ cd_parse_command. If we are changing to a directory whose name we
+ got from a system call (readdir for example), we use cd_exact.
+
+Thu Aug 8 13:10:47 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (ftpfs_chdir, retrieve_dir): Do not send CWD commands if
+ the directory we are changing to is the same we are on.
+
+ * profile.c (load): Fixed a long standing bug (since I guess 0.3 or
+ 0.5). The bug had not shown until now: when a file controled by
+ profile.c did not have a newline after the last definition on the
+ file the value parameter would have been zero and this would make
+ the program at some point free () a zero pointer if this case
+ happened. This was not the case until I edited the extfs.ini file
+ and removed all of the extra spaces there.
+
+Wed Aug 7 22:46:36 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * extfs.c (extfs_init): Fixed idioticc bug I introduced in the
+ last version: I removed the strdup in one place, thus the code was
+ freeing two times a pointer. Janne's Memory Allocation Debugger
+ pin pointed the bug in a second.
+
+ * ftpfs.c: Fixed a file descriptor leak on ftpfs redial code
+ reported by tony@trishul.sci.gu.edu.au
+
+ (ftpfs_open_socket): Fixed an idiotic bug I introduced while
+ merging the HSC patches. Little endian machines would not be able
+ to use ftpfs.
+
+Tue Aug 6 13:09:26 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * tcputil.c (tcp_init): Use sigaction instead of signal.
+
+Mon Aug 5 20:36:55 1996 Erik Troan <ewt@redhat.com>
+
+ * extfs/rpm, cpio: Fixes to the rpm file system and a new cpio
+ external file system
+
+ * main.c (toggle_listing_cmd): When you press Alt-t it will toggle
+ the display mode of the midnight commander.
+
+Tue Jul 23 13:36:33 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * This is here just to comment that Juan has done a terrific job
+ with the Windows NT port.
+
+Tue Jul 23 13:23:42 1996 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * myslang.h (baudrate): Provide port specific acs, noacs and
+ baudrate.
+
+ * util.c (file_date): Copy the non existant permissions to timebuf
+ on NT.
+
+ * file.c (mc_ctl): NT does not have vfs yet.
+
+ * main.c (main): Some commands do not exit on NT. Handle properly
+ home_dir if the user has no HOMEDRIVE/HOMEPATH defined.
+
+ * utilunix.c (save_stop_handler, my_statfs): These are per port
+ functions and do not belong into util.c
+
+Wed Jul 17 18:15:07 1996 Benjamin Ryzman <Benjamin.Ryzman@hsc.fr>
+
+ * ftpfs.c: Added support for the HSC firewall.
+
+Fri Jul 12 19:31:32 1996 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * subshell.c: Hack to avoid the couldn't change to %s messages.
+
+Mon Jul 8 10:50:04 1996 Alexander V. Lukyanov <lav@video.yars.free.net>
+
+ * main.c (setup_sigwinch): Bug fix: initialize sa_flags on systems
+ that do not have SA_RESTART defined.
+
+Thu Jul 4 14:25:41 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * key.c (is_idle): Changed struct fd_set to fd_set in the two
+ places where this did happen.
+
+Thu Jul 4 13:50:47 1996 Gregor Hoffleit <flight@mathi.uni-heidelberg.DE>
+
+ * configure.in: create the malloc.h stub in the distribution
+ directory instead of the src directory.
+
+ * util.c (is_printable), utilunix.c (putenv): Provide putenv from
+ GNU libc in case the OS does not have putenv (nextstep).
+
+ * util.h: Add replacement for ISASCII
+
+ * menu.c (menubar_handle_key): Use ISASCII instead of isascii,
+ NeXTStep lacks it.
+
+Tue Jul 2 14:29:36 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (reload_panelized): Fix this routine. This is the
+ culrpit of all of the panelize problems. The code was freeing
+ pointers that were in use. Now I free the pointer when I notice
+ it is not going to be used. Fixes the problem reported by Steven
+ and Michael Sterret.
+
+Mon Jun 24 17:47:36 1996 D. Hugh Redelmeier <hugh@mimosa.com>
+
+ * subshell.c (feed_subshell): Looking at this some more, I notice
+ that &read_set is being modified by the select, but not
+ re-initialized by the code! The initialization code precedes the
+ loop, but should be inside it! Here is my version, with the
+ initialization moved into the loop (remember to delete it from in
+ front of the loop).
+
+Thu Jun 20 15:53:47 1996 Alexander V. Lukyanov <lav@video.yars.free.net>
+
+ * subshell.c (feed_subshell): Retry if we get EINTR (even if we
+ have SA_RESTART solaris will deliver EINTR on SIGCHLD).
+
+Thu Jun 13 21:12:14 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (copy_file_file): During non-local file systems that
+ support mc_ctl, rotate the dash every 5 seconds or so, to keep the
+ user awake.
+
+ * cmd.c (do_link): Check that the other panel is actually a
+ listing before attempting to use ->cwd.
+
+Tue Jun 11 18:36:09 1996 Miguel de Icaza <miguel@mirage.nuclecu.unam.mx>
+
+ * ext.c (regex_command): Editing of non local files should work now.
+
+Tue Jun 11 16:07:38 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ext.c, cmd.c: if the user edits the mc.ext file, flush the
+ cached copy.
+
+Mon May 20 12:27:58 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * configure.in: check for putenv and isascii. Next does not have
+ those. If malloc.h does not exist, create an empty file as a
+ substitute (next too).
+
+Wed Jun 5 11:18:19 1996 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * cons.saver.c, cons.handler.c, key.c: Misc changes to make
+ mc work on SparcLinux (code written only for linux - like cons.saver
+ handling - didn't care about endians...)
+
+Thu May 16 12:30:23 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.c (view): Use the global Wview variable instead
+
+Wed May 15 20:24:55 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * panelize.c: Provide extra space for temporary dirent structure.
+
+ * win.c (check_movement_keys): Do not handle the C-b combination,
+ it is used by the viewer for next/previous file.
+
+Mon May 13 09:11:27 1996 Joseph M. Hinkle <jhinkle@rockisland.com>
+
+ * boxes.c (display_bits): Call proper help information.
+
+Mon May 6 21:20:39 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (copy_file_file): Should abort now ongoing transfers
+ faster.
+
+ * ftpfs.c (initconn): Attempt to use passive ftp transfer mode if
+ source routing is in effect. If this does not work, dump source
+ routing and use regular method for ftp transfer.
+
+
+Thu May 2 19:29:07 1996 ?????
+
+ * extfs/zip (DOZIPINFO): Fixed zipfs support for files with
+ comments, lost mail address.
+
+Thu May 2 19:29:07 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs/vfs.c: minor parse fix.
+
+Thu May 2 19:25:09 1996 "Sergey Ya. Korshunoff" <root@seyko.msk.su>
+
+ * configure.in: Check for libtermcap (new Linux libcs do not have
+ libtermcap in libc).
+
+Tue Apr 30 20:58:34 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (store_file): Remove temporary files after an outgoing
+ tansfer.
+
+Mon May 6 01:10:50 1996 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * extfs.c: Hack to get the a: and b: fs running (fixed couple of
+ problems with external fs when no archive file was used
+
+ * extfs.c (extfs_run): Allows you to "execute" some files inside
+ of extfs - your script will be called with $1=run $2=archive $3=path,
+ e.g.
+ /usr/lib/mc/extfs/rpm run /home/jj/rpm-2.0-2.src.rpm INSTALL
+
+ * vfs/Makefile.in: rpm script gets installed
+
+ * vfs/extfs/rpm: Couple of changes to make rpmfs more powerful
+
+ * vfs/extfs/a: Fixes - the ls -l parse in mc is quite strict
+ about date, so that it wasn't happy by 2-24-96 (correct is 02-24-96)
+
+ * layout.c: New checkbox in the Layout dialog. When running on xterm
+ and Xterm hintbar is checked, hintbar will be put into the xterm's
+ title bar, so that you'll save space - will have more lines for file
+ display
+
+ * main.c: Fix, so that it is possible to do quick searches for
+ characters like +, -. In order to select/unselect, you have to press
+ escape twice before +, -.
+
+Mon Apr 29 21:34:53 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * subshell.c (init_subshell): Documented startup shell scripts.
+
+ * find.c (do_search): Added directory exclusion.
+
+Mon Apr 29 08:42:52 1996 Adam Tla/lka <atlka@pg.gda.pl>
+
+ * cmd.c (view_file): Return value, fixes Soalris crash.
+
+Fri Apr 26 18:10:10 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (initconn): Added source routing to ftpfs, he he, this
+ lets you specify a specific route for your ftp traffic :-). It is
+ still missing the passive open code, so it currenly is only able
+ to send commands trough the source route. This code is disabled
+ by default, it requires human intervention (ie, editting config.h
+ and specifying HAVE_SETSOCKOPT).
+
+Thu Apr 25 11:11:08 1996 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * cmd.c (source_routing): Added source routing option to sockets,
+ he he he.
+
+Wed Apr 24 22:12:50 1996 Alexander V. Lukyanov <lav@video.yars.free.net>
+
+ * key.c: touch window for ncurses.
+
+ * color.c: use proper colors for ncurses.
+
+Fri Apr 19 09:02:51 1996 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * vfs.h (vfs_canon): On the non-vfs definition return a strdupped
+ version of the string, just like vfs_canon does.
+
+ * profile.h: Do not include profile prototypes routines present on
+ NT.
+
+ * key.nt.c, slint.nt.c, utilnt.c: updated, look at README.NT
+
+Thu Apr 18 20:35:03 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * subshell.c (exit_subshell): Do not ask for confirmation for
+ killing subshell when it is already dead.
+
+ * Do not return after invoking subshell, let the code reinit slang
+ and let it shutdown properly.
+
+Wed Apr 17 10:03:57 1996 Erik Troan <ewt@redhat.com>
+
+ * extfs/rpm: Added new rpm file system. This one lets you browse
+ RPM files.
+
+Wed Apr 10 17:05:57 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * utilunix.c (tilde_expand): Now returns 0 if the home directory
+ for the tilde expansion does not work.
+
+ * vfs.c (vfs_canon): Check for tilde_expand results.
+
+ * complete.c (command_completion_function): Check for return
+ values from tilde expand.
+
+ * wtools.c (input_expand_dialog): Check for tilde_expand result.
+
+Tue Apr 9 20:06:03 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (create_panels): both startup directories are now handled
+ properly (for those cases where the second directory was relative
+ to the startup working directory)
+
+ * subshell.c (do_subshell_chdir): Added proper quoting of
+ directories, should get rid of the problems with directories with
+ spaces (common now for those using windows)
+
+Thu Apr 4 11:03:07 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * chown.c (chown_cmd): Check for return values of getpwnam and
+ getgrnam, bug report by Mikhail Savitski <mms@eiscathq.irf.se>
+
+Fri Mar 29 18:00:11 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * From: Liviu Daia <daia@stoilow.imar.ro>: Fix the documentation
+ on the keywords for setting colors
+
+Wed Mar 27 19:58:32 1996 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * tree.c: If configuration variable xtree_mode is true then when
+ browsin with the tree panel the other panel will reload the
+ contents of the panel.
+
+ * tkmain.c, key.c: Should compile and link with latest release of
+ Tk
+
+Mon Mar 11 09:53:10 1996 John Ioannou <roryt@compulink.gr>
+
+ * cmd.c (do_link): Suggest symlink names. (get_random_hint): make
+ it work on SCO.
+
+ * utilunix.c (gettimeofday): Contrinuted this routine for SCO machines.
+
+Mon Mar 11 09:47:15 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * Makefile.in: Split the util.c file in three pieces: utilunix.c:
+ util routines pertinent to Unix; utilnt.c: util routines for
+ Windows NT (from Juan Grigera) and util.c that has the OS
+ independent (well, mostly)
+
+Tue Mar 5 19:28:35 1996 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * boxes.c (sort_box): Add case sensitivity to the menu.
+
+ * user.c (execute_menu_command): windows nt requires a .cmd
+ extension to execute commands. Fix a return path that did not
+ close nor unlink the file.
+
+ * chmod.c: now we have working chmod.
+
+ * hotlist.c: use the proper path separator, do not pass a non used
+ parameter to update_path_name
+
+ * dir.c, panelize.c, boxes.h, setup.c: added support for case
+ sensitive sorting (for windows nt).
+
+Mon Mar 4 17:08:22 1996 Mark Olessen <olesen@weber.me.queensu.ca>
+
+ * container.c, sldisply.c: Include config.h before anything else.
+
+ * tcputil.c (sig_pipe): AIX requires an int parameter
+
+ * sltermin.c: changes to compile slang on AIX.
+
+Mon Mar 4 09:29:32 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * profile.c (GetSetProfileChar): Fixed bug when the AppName was
+ zero. This could be the case if one of the keys in the profile
+ has no value.
+
+ * info.c (info_show_info): Fixed crash when info was displayed on
+ a non local vfs.
+
+Mon Mar 4 08:17:27 1996 Anatoly A. Kulakov (kulakov@JamesBond.inp.nsk.su)
+
+ * mc.lib: for xterms and xterm-colors define the page up and page
+ down keys.
+
+ * nt/Makefile: remove spurious backslash
+
+ * src/dlg.h: Do not give a name to the Widget_messages enum (some
+ compilers can't handlte this).
+
+Sat Mar 2 10:27:24 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * cmd.c (view_other_cmd): Call my_system (1, shell, NULL) instead
+ of my_system (1, shell, ""). This allows one have a shell spawned
+ when pressing C-o and the subshell code is not activated.
+
+Tue Feb 27 21:52:21 1996 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * More Windows NT code.
+
+Tue Feb 27 21:52:21 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs: Now the program will retry logins if the server is too
+ busy.
+
+ * view.c, cmd.c: C-f and C-b will take you to the previous and
+ next files on the panels.
+
+Fri Feb 23 08:51:44 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * tree.c (my_mkdir_rec): Do not create recursive directories if
+ the file system is not the local one. I should actually fix this
+ to use a routine that checks if the pathname is already at the top
+ directory for that filesystem.
+
+Wed Feb 21 09:58:22 1996 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c: fix symlink file handling for ftpfs file systems. If we are a
+ symlinks and follow symlinks is set, we should operate on the
+ pointed to file stat information, not the symlink information.
+
+ * ftpfs.c (open_command_connection): Setup the proxy field, added
+ retry code for ftp.
+
+Fri Jan 19 12:00:00 1996 Mark Olesen (olesen@weber.me.queensu.ca)
+
+ * Include config.h allways before any other include file, this
+ fixes compilation on AIX.
+
+Fri Jan 19 12:00:00 1996 Miguel de Icaza
+
+ * subshell.c (init_subshell): Enable the interrupt key when doing
+ the feed subshell, if the subshell code hangs, we will turn of the
+ subshell support and allow the user to press C-c.
+
+Tue Jan 16 11:28:58 1996 SGI portability fixes.
+
+ * I lost the mail with the author name, could you tell me who are
+ you?
+
+ * widget.h: removed enum names. Broken sgi compiled complains
+ about this.
+
+ * tar.h: Removed trailing ,.
+
+ * dir.h: Define sort_orders as external.
+
+Tue Jan 9 11:47:47 1996 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * configure.in: Define USE_SETUPTERM only if the sample program
+ included in configure is compiled successfully. This is required
+ because some systems have setupterm but are lacking the macros we
+ need.
+
+Tue Jan 2 17:01:23 1996 Carl Thompson <miguel@athena.nuclecu.unam.mx>
+
+ * subshell.c (init_subshell): Use the builtin $cwd variable and
+ echo instead of invoking an external pwd command. This fixes
+ follow links.
+
+Sun Dec 31 17:46:39 1995 Ching Hui <u811563@Oz.nthu.edu.tw>
+
+ * layout.c (print_vfs_message): Check midnight_shutdown first.
+
+Fri Dec 29 19:10:25 1995 Juan Grigera <grigera@isis.unlp.edu.ar>
+
+ * various portability changes to the Midnight Commander so that it
+ runs under Windows NT.
+
+Fri Dec 29 19:09:23 1995 Antonio Palama <palama@posso.dm.unipi.it>
+
+ * main.c: For Windows NT, Juan Grigera hacked the drive_cmd.
+
+Tue Jan 2 00:51:12 1996 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * complete.c (filename_completion_function): Fixed one completion
+ related bug.
+
+ * ftpfs.c (store_file, ftpfs_open): Fixed uploading of files using
+ ftp.
+
+ * ftpfs.c (ftpfs_chown): Don't always cry that you cannot chown
+ using ftp - everyone should know it and who cares - but for root
+ this was shouting for each file :(
+
+ * vfs.c, undelfs.c: Changed the vfs prefix to `undel:' from
+ `undelfs:'. So you specify cd undel:/dev/hda1. This is similar
+ to how we do ftp (not ftpfs://) etc.
+
+ * vfs.c (parse_ls_lga): Made more robust, so that it handles again
+ listings from extfs (with all date formats), doesn't mind if someone
+ is not supplying gid and handles even if major,minor are printed
+ without an intervening space (like 14,5).
+
+ * vfs.c (vfs_canon): Fixed a bug, which made an endless loop when
+ trying to enter an extfs archive (like zip:), where the archive name
+ was not absolute. Together with the previous bug fix, zip files
+ should work again well :)
+
+Sat Dec 23 16:55:54 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs/undelfs.c, vfs/vfs.c: Add support for the Undelete file
+ system.
+
+Sat Dec 23 16:55:25 1995 Ching Hui <u811563@Oz.nthu.edu.tw>b
+
+ * configure.in: Fixed bug in curses detection for OSF/1.
+ sltermin.h: include config.h.
+
+Thu Dec 21 19:25:48 1995 Carl Thompson <clip@clip.clark.net>
+
+ * file.c: This is just a one line patch to fix a bug in the
+ Midnight Commander. When a delete operation is attempted while
+ delete confirmation is turned off, it pops up a destination
+ directory dialog box instead of just deleting the file. This
+ dialog box is unused and defeats the purpose of having delete
+ confirmation off.
+
+Mon Dec 18 18:44:16 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (midnight_callback): Do not handle the +, - and / keys
+ specially if the panel is in search mode.
+
+Fri Dec 15 12:38:18 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (copy_dir_dir): When copying directories recursively,
+ make sure the directory have write permission. Before returning,
+ use chmod to set the correct directory attribute.
+
+Sat Dec 16 16:40:14 1995 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * util.c (resolve_symlinks, diff_two_paths): New utility functions:
+ the first one traces a symlink as much as possible, so that the
+ final returned (mallocated) path contains no symlink steps at all.
+ The latter one takes two paths and creates a relative path from the
+ first one to the second one, as short as possible.
+
+ * file.c: Stable symlinks should now keep relative symlinks
+ relative, using the above mentioned functions.
+
+ * panel.h: Switches some boolean flags into a bit-field.
+
+ * cmd.c, screen.c: Directory total should be now displayed
+ correctly, i.e. if not Show Dir Sizes is active, it shouldn't count
+ them at all, if it is active, it should sum these sizes as well and
+ when changing from not active to active (via F9 C I) or back (C-R),
+ adapt the total correctly :)
+
+ * vfs.c (parse_ls_lga): Should now handle No{v,tw}ell listings
+ as well.
+
+ * cmd.c (other_symlink_cmd): New command - C-x C-l. Makes a relative
+ symlink to the selection of the current panel, defaults to a file
+ in the other panel. The symlink value is shortest possible, so that
+ it may optionally fit into inode itself, if the fs supports this.
+
+Thu Dec 7 13:15:30 1995 Sergey Ya. Korshunoff <root@seyko.msk.su>
+
+ * layout.c (layout_callback): Fixed the constants for the menubar.
+
+ * If we try turn off command prompt from Option->Layout,
+ then we will see command propt again (no Hint if it
+ turned on).
+
+ * widget.c: Removing first element from User listing mode list
+ causes crash.
+
+Thu Dec 7 13:00:20 1995 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * file.c: Stable symlinks works for copying (i.e. the symlink
+ points to the location it should), but it is not like I would
+ like it to be - there has to be an algorithm, which will try
+ to reduce the size of the symlink as much as possible and
+ not just making absolute symlinks from relative :( This is only
+ a short time solution.
+
+Thu Dec 7 00:00:00 1995 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * cmd.c (edit_symlink_cmd): New function, binded to C-x C-s.
+ Allows to edit the content of the symlink.
+
+ * file.c: Move should now work when dive_into_subdirs is not
+ set, i.e. you can finally move two similar subtrees into one.
+ It tries to use move as much as possible and where it is not
+ possible, it does a copy and delete strategy. Also, prepared things
+ for next patch, which will allow copying/moving of relative symlinks,
+ so that they'll point to the same location as before.
+
+ * setup.c: Users can save their defaults of dive_into_subdirs
+ into mc.ini.
+
+ * help.c, xv/xvhelp.c, xv/xvscreen.c: xv edition should now compile :)
+
+ * screen.c: New keystroke M-l, which chdirs in the other panel to
+ directory where current symlink points to (even if it doesn't point
+ to a directory - then other panel will become the directory where a
+ file the symlink points to is located).
+
+ * main.c (copy_current_readlink, copy_other_readlink): New keystrokes
+ C-x r, C-x C-r. If current/other panel's selection is a symlink,
+ readlink value will be inserted into the command line.
+
+Wed Dec 6 13:21:21 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (ftpfs_chdir): Better reconnect code on chdir.
+
+ * vfs.c (parse_ls_lga): ftpfs will work with directories that have
+ spaces in their name (".. " and ". ." will both work for example).
+
+ (parse_ls_lga): Support for servers that do not provide the
+ groupname even when asked to.
+
+Wed Dec 6 11:01:17 1995 Sergey Ya. Korshunoff <root@seyko.msk.su>
+
+ * mc.lib, win.c: Handle some more key pad keys on the
+ use_alternate_keypad_mode.
+
+ * main.c (midnight_callback): New option only_leading_plus_minus=1
+ in ~/.mc.ini set special treatment for '+', '-', '*' in command
+ line (select, unselect, inverse selection) only if command line is
+ empty. No need to qoute this characters in middle of command
+ line. But we cant change selection when command line is not empty.
+
+
+ * main.c (midnight_callback): Added missing terminator for the
+ default_map keyboard map.
+
+ * main.c (done_mc_profile): Do not sync_profiles if
+ auto_save_setup is not set. This plus the fix below should avoid
+ most cases of .mc.ini overriding (the exceptions are when the
+ hotlist or the panelize options commands are used).
+
+Wed Dec 6 11:00:00 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * panelize.c (save_panelize), hotlist.c (save_hotlist): call
+ sync_profiles since now at program shutdown if auto-save setup is
+ not set we won't do the updating.
+
+Mon Dec 4 11:32:02 1995 Ching Hui <u811563@Oz.nthu.edu.tw>
+
+ * sltermin.c: Provide an alternate way if setupterm is defined on
+ curses to retrieve terminal capabilities. This fixes the line
+ drawing problems on OSF/1 (and hopefully on AIX as well).
+
+Mon Nov 27 21:08:41 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * tree.c (load_tree): Finally fixed the tree-loading crash when
+ the .mc.tree file was corrupt.
+ (tree_key): Do not eat characters not meant for the trereree below
+ ' '.
+
+Fri Nov 24 19:54:01 1995 Ilya Rybkin (rybkin@rouge.phys.lsu.edu)
+
+ * user.c (strip_ext): Basename macor (%b, %B)
+ * user.c: Do not add space to temporary files, so that the #!
+ works for the script files.
+
+ * key.c: Allow the M-? sequence to be generated (find file).
+
+ * wtools.c: Do not make the cancel button the default action.
+
+Thu Nov 23 13:51:11 1995 Ching Hui <u811563@Oz.nthu.edu.tw>
+
+ * slint.c (slang_init), sldisply.c: Fix the USE_TERMCAP usage. It
+ should now allow FreeBSD and Nextstep users to use the arrow keys.
+
+Mon Nov 20 14:25:59 1995 Ching Hui <u811563@Oz.nthu.edu.tw>
+
+ * main.c (main): Call vfs shut before shutting down the window system.
+
+Thu Nov 16 23:08:17 1995 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * lib/Makefile.in: Fixed install goal for the mc.ext file.
+
+ * file.c (copy_file_file): If appending, do not change mtime &
+ owner & permissions - leave them all untouched as they were at
+ the original target file you were appending to.
+
+ * widget.c, cmd.c: Changed input line history behaviour.
+ Now the history shouldn't remember same lines when they follow
+ each other, then shouldn't remember empty lines at all, but
+ also, once a line is added into history, it should stay there
+ forever, so that you can repeat it again (previously, if you've
+ moved using M-p and M-n onto any line in the history and changed
+ it, you lost the original line from the history).
+
+Wed Nov 15 12:22:47 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (command, is_connection_closed, ftpfs_chdir): Check for
+ dropped connections. In the past the is_connection_closed routine
+ actually attempted to read from the connection but this caused a
+ problem (remember the hang connections for small files?).
+
+ (ftpfs_setctl): vfs_canon the filename.
+
+Mon Nov 13 10:28:42 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * ftpfs.c (ftpfs_ctl): Now it will be able to flush the directory
+ cache (used by C-r in the main program); increased the ftpfs
+ directory timeout; C-r now works for ftp file systems.
+
+ * profile.c: increased the line size to 4k, should fix this and do
+ something better.
+
+Wed Nov 8 10:04:55 1995 Sergey Ya. Korshunoff <root@seyko.msk.su>
+
+ * widget.c (listbox_remove_current): listbox_remove_current:
+ free() at subroutine end make free not old current position but
+ new one. Removing all entries in the listbox causes problems when
+ routine return. This patch don't allow listbox with no
+ elements. IMHO it's not bad (we always show something insteed of
+ nothing)
+
+ * wtools.c (remove_callback): On listbox with user display formats
+ <r> hot key removes entry and show new listbox state. When we
+ select [Remove] button with mouse or <TAB>, then we dont see new
+ listbox state. Ugly hack, but works OK.
+
+ * layout.c (swap_panels): Fixed crash: Now we change the
+ definitions of left_panel and right_panel.
+
+ * chmod.c (chmod_refresh): use REVERSE_COLOR instead of
+ normal_color.
+
+ * color.h: COLOR_FOCUS now uses A_BOLD instead of A_REVERSE,
+ COLOR_HOT_FOCUS is now 0 inseat of REVERSE|BOLD.
+
+ * tree.c: Different colors
+
+ * boxes.c (display_callback): After selecting user listing format
+ from listbox we see old format string. When we press LEFT, RIGHT
+ or other key we see a new one.
+
+Thu Nov 2 17:03:37 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * ftpfs.c (ftpfs_ctl): Clear the localname
+ (ftpfs_ungetlocalcopy): Keep in sync: if we free
+ local_filename in an ftpfsentry, clear it.
+
+Tue Oct 31 16:57:57 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * help.c (interactive_display): I wonder why I code so badly?
+
+Mon Oct 30 16:16:22 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.c (view_handle_key): Some additions so that in the future I
+ will be able to make the viewer work as tail -f [Not yet ready].
+
+ * dlg.h: New WIDGET_IDLE message. W_WANT_IDLE flag defined.
+
+ * dlg.c: The default routine for dialogs now handles the DLG_IDLE
+ message and broadcasts it to all the widgets in the current Dialog
+ head.
+
+ * ftpfs.c (ftpfs_ctl): Get the reply before closing the data
+ connection. (command, get_line, get_line): Keep a log of the ftp
+ dialog (also new flag on main.c)
+
+Mon Oct 30 11:26:09 1995 Sergey Ya. Korshunoff <root@seyko.msk.su>
+
+ * slgetkey.c: move the DEC 8bit hack to the slint.c file.
+
+ * boxes.c (display_callback): Button 'u' did not work as the other
+ buttons.
+
+ * boxes.c (display_callback): User listing format selection by C-c
+ don't work with SLANG. SLANG convert C-c to C-g. This patch
+ correct this. But emove patch from list dont wotk (general
+ protection error)
+
+ * screen.c (paint_frame): Moving files in brief panel format
+ corrected. (move_up, move_down): Allows to configure if scrolling
+ is going to be line by line or page by page with the
+ panel_scroll_pages setting.
+
+
+ * view.c (view_labels): Don't setup wrap mode on in view module
+ every time when view called. Show UnWrap label when wrap_mode on.
+
+Mon Oct 30 11:17:25 1995 Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+ * configure.in, mc.ext.in: Use autoconf for the MANDOC and -Tascii
+ detection instead of doing our own seding at make time.
+
+Thu Oct 26 18:03:50 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (check_hardlinks): Avoid hardlink checks only if
+ vfs_file_is_ftp.
+
+ * vfs.c (vfs_file_is_ftp): guess.
+
+Tue Oct 24 17:36:15 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * help.c (interactive_display): Help should not crash at help
+ startup when prev_node_cmd is invoked.
+
+Thu Oct 26 15:15:04 1995 Jakub Jelinek <jj@sunsite.mff.cuni.cz>
+
+ * file.c (check_hardlinks): Hack, so that no more cyclic hardlinks
+ appear on Slowaris - stupid kernel, which makes it possible to
+ link directories :(. Disabled hardlink cache for all non-local
+ vfs's. Where do we need it? Ftp cannot handle it, tar is still read
+ only, mcfs perhaps?
+
+ * cmd.c ((un)select_cmd): Fixed a problem when .. directory is a
+ symlink (i.e. grand parent of current directory is a symlink).
+
+Tue Oct 24 11:09:05 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (create_panels): Loading of the proper other directory at
+ startup.
+
+Fri Oct 20 19:55:48 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * subshell.c (init_subshell): ZSH: use pwd>&%d instead of
+ pwd>>&%d, I hope to get this one right this time.
+
+Wed Oct 18 17:58:11 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * panelize.c (do_external_panelize): fixed the ghost marked files
+ when panelizing.
+
+Tue Oct 17 19:15:10 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs.h: ftp copies should work on the alpha again.
+
+Thu Oct 12 16:44:02 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * file.c (copy_file_file: for the ftpfs case): Instead of
+ incrementing the file size by 8192 bytes, we should increment by
+ the actual bytes trasfered
+
+Wed Oct 11 20:19:28 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (ftpfs_ctl): Now the FINISHREMOTE message actually
+ aborts the ftp transfer.0
+
+ * slang.h: Fixed color problem on some linuces with the Unicode
+ support. Now we only define linux_unicode here if we are on linux
+ and there is support for it. This caused the strange non-color
+ problem on some versions of Linux.
+
+Wed Oct 11 13:09:27 1995 Adam Tla/lka <atlka@sunrise.pg.gda.pl>
+
+ * help.c (show): Puts the cursor over the currently selected link.
+
+ * xnc.hlp: Fixed the help corrupt problem.
+
+Sat Oct 7 16:40:21 1995 Jakub Jelinek <jj@jfch.vc.cvut.cz>
+
+ * file.c, ftpfs.c: First trial to make copying from FTPFS work as
+ it should work, i.e. if we have no local copy yet, copy it directly
+ and not through temp and also copy it from within the main
+ copy_file_file loop and not fetch it before and then copy the local,
+ so that e.g. the progress bar will be displayed correctly.
+
+Thu Oct 5 15:35:36 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * cmd.c (view_other_cmd): It's obvious that one of this days I
+ will have to learn programming and to write bug free code for
+ programs that are > 10 lines.
+
+ Now, the good news: Finally I got rid of the ugly constant in
+ terms.c for changing the font on xterms (the esc + "(" + 0 thing),
+ this means that the kanji char set should work on the viewer and
+ also means that slang will redraw correcly the screen.
+
+ * main.c (setup_mc_viewer): Create a fake panel for the viewer
+ when the mc is invoked in viewer mode. Needed, since
+ expand_format will want to use cpanel to extract the file name.
+
+ * cmd.c (view_other_cmd): C-o should give a shell even for users
+ without the subshell support. I'm not sure if this is a good
+ idea.
+
+Wed Oct 4 13:45:21 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (retrieve_file): Moved the disable_interrupt_key to the
+ error_3 section.
+
+ * find.c (find_callback): Now you can use F3 and F13 to view at
+ the files found on the find panel without leaving the find box.
+
+ * view.c (do_view_init): Implemented view markers, use nm and nr
+ (where n is a number between 0 and 9) to set the nth mark and to
+ jump to the nth part respectively
+
+ * main.c (create_panels): Current panel set to a panel that is in
+ the view_listing mode (before it was set always to the left_panel).
+
+Thu Sep 28 12:06:46 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * help.c (interactive_display): Really, this time the help is fixed.
+
+ * vfs.c (vfs_stamp_path): Provide a way to stamp the file systems
+ that are on the panels. This is called from main.c just before
+ disposing the panels, so that the vfs's have a chance to shutdown
+ (and cleanup /tmp as torben reported :-)
+
+ * option.c: Replaced 8-bit display with navigate-with-arrows,
+ since Display Bits already handles the 8 bit setting.
+
+ * learn.c (learn_save): Loop only from 0 to learn_total. The
+ learnkeys array is smaller than the key_name_conv_tab (fixes a
+ crash on hp-ux).
+
+ * screen.c: Now the F13 should clear also the search status.
+
+ * view.c (change_viewer): Fixed program crash when the viewer was
+ invoked as a filtered view.
+
+ * dir.c (do_load_dir): Ok, we can open a directory, but I have
+ found the first empty directory in my life (no . nor ..: the
+ remote systems nfs directory does not exist any longer).
+
+Wed Sep 27 11:07:43 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (do_nc): Starting the Midnight Commander as a file viewer
+ should be faster now
+
+ * view.c (view_handle_key): Started implementation of reverse
+ search, use the C-r and '?' keys to activate normal and regex
+ reverse search respectively. May still have bugs.
+
+ * ftpfs.c (open_command_connection): Initialize the complete
+ bucket structure, this fixes the crash when the password is not
+ answered (when tryingo to reconnect to an ftp server).
+
+ * util.c (strip_home): Check return values from ftpfs_gethome and
+ mcfs_gethome.
+
+ * boxes.c (display_bits_box): Stupid bug fixed: now it should
+ reflect the internal setting of the display variables.
+
+ * help.c (interactive_display): Now history_ptr always is between
+ 0 and HISTORY_SIZE - 1, this should fix the crash reported by
+ Thanh.
+
+ * view.c (block_search, search): small changes (should be somewhat
+ faster).
+
+ * main.c (setup_mc): Add the select channel for load_prompt after
+ panels have been created (so, calling get_event before this
+ (mc_chdir on an ftpfs may do this) won't try to invoke the load
+ prompt routine).
+
+Wed Sep 27 11:03:21 1995 Gerd Knorr <kraxel@cs.tu-berlin.de>
+
+ * main.c (handle_args, create_panels, setup_mc): Allowed the
+ program to be passed a vfs path name by making the mc_chdir call
+ to be done after slang has been setup (the ftpfs and mcfs both may
+ need to use slang to ask for a password).
+
+Tue Sep 26 20:38:57 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * view.c (view_callback): Removed call to view_status before
+ view_update on WIDGET_KEY message, this should work, if not, I
+ should put it back or put the view_updated on the proper places.
+ (search): On non-hex view the viewer now shows the search status.
+ (block_search): Coded but untested: also the hex view should
+ report the search status. I wonder if it will work.
+
+ * boxes.c: 8 bits should work now with slang correctly.
+
+Tue Sep 26 11:36:12 1995 Jakub Jelinek (jj@jj)
+
+ * screen.c: If a column for size is more narrow than actual size
+ can fit in, show number of Kilobytes or Megabytes or Gigabytes
+ instead and do not strip the most important digits (like e.g.
+ a 4e6B file was shown equally to a 104e6 file).
+
+Sat Sep 23 00:27:05 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * mc.sgml, linuxdoc-sgml.diff: I hope I have managed to fix the
+ problems I has been aware of with backslashes, tildes etc. I do not
+ know about any further conversion problem.
+
+Thu Sep 21 20:21:59 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * widget.c (button_callback): Global kill ring.
+
+Thu Sep 21 23:09:12 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * converted the documentation to mc.sgml (linux-doc DTD), so that
+ from one source (mc.sgml) you can generate mc.1, mc.hlp, mc.texi,
+ mc.info, mc.html, mc.tex, mc.dvi, mc.ps, mc.txt (and some other
+ formats). To convert this, you have to install Matt Welsh's
+ linuxdoc-sgml-utils and apply patch from the our doc directory.
+ (linuxdoc-sgml is only name of the dtd, it is not useful for Linux
+ only, but the name is like this only because linuxdoc sgml utilities
+ were developed primarily for Linux HOWTO documentation and LDP).
+ src/mc.hlp file is generated from mc.sgml, so you can get some
+ feeling.
+
+ * configure.in: Fixed an awful bug with the gpm library.
+
+Thu Sep 21 11:56:08 1995 John E. Davis (davis@space.mit.edu)
+
+ * sldisply.c: Should now use the acsc definition from the terminal
+ database instead of the hardcoded values.
+
+Thu Sep 21 11:13:41 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (handle_args): Now you have to use the -v [file] flag to make
+ the Midnight Commander start up in the viewer mode on the file file.
+
+Wed Sep 20 16:38:44 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * achown.c (next_file): Chown and advanced chown should work now
+ when setting all of the tagged files.
+
+ * wtools.c (input_dialog_help): Input dialogs now have nice
+ buttons so that mouse users will not complain
+ (create_listbox_window): Added cancel button.
+
+ * tcputil.c (lookup_netrc): Avoid a program crash.
+
+ * help.c (help_event): Fixed crash when the user pressed the left
+ too long.
+
+Wed Sep 20 10:16:27 1995 Ching Hui <Nicholas@u811571.JEN.AB.nthu.edu.tw>
+
+ * panelize.c: Fix the hang problem on OSF/1.
+
+ * subshell.c: Open the slave side of the pty on the parent code
+ just after opening the master side, then close it on the parent
+ code. No need to use the sigusr1 sync code anymore and it's
+ working on Solaris, Linux and OSF/1.
+
+Tue Sep 19 21:04:25 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.c (view_new): Initialize last_read, should fix the bug
+ with reformatting pages.
+
+ * user.c (check_format_var): Added the %var macro. Now tcsh users
+ will be able to use the stock mc.ext file.
+
+ * ftpfs.c (send_ftp_command, ftpfs_hint_reread): Now you can
+ specify blocks of operation that will disable ftp's code to reread
+ the directory on each operation.
+
+Sat Sep 16 18:56:51 1995 Alessandro Rubini <rubini@ipvvis.unipv.it>
+
+ * Makefile.in: Abort make process if one of the submakes fails.
+
+Sat Sep 16 18:56:51 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * tcputil.c (open_tcp_link), ftpfs.c (ftpfs_open_socket): Check for
+ empty hostnames.
+
+Sat Sep 16 18:33:38 1995 Perry Francis Nguyen <pfnguyen@netcom.com>
+
+ * subshell.c: Fixed the subshell hanging when the noclobber option
+ is set.
+
+Sat Sep 16 15:37:41 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c: Tidied up a bit and re-created the fold structure.
+ (P.S. Try the emacs package folding.el to view/edit subshell.c)
+
+ * Makefile.in, */Makefile.in: Made `make distclean' leave the
+ directory tree truly pristine.
+
+ * key.c, view.c, ext.c, layout.c, complete.c, cmd.c, tcputil.c,
+ vfs.c and extfs.c: Fixed some nasty compilation warnings, some of
+ which were definite bugs.
+
+ * extfs.c: extfs_getlocalcopy wasn't returning any value.
+
+ * tcputil.c (ruserpass): Can't use copy_strings() here, because
+ mcserv won't link. Replaced with strcpy() and strcat().
+
+Sat Sep 16 01:54:41 1995 Ching Hui <Nicholas@u811571.JEN.AB.nthu.edu.tw>
+
+ * ftpfs.c (resolve_symlink): resolve symbolic links by send the
+ command "LIST -Lla" to server.
+
+ * vfs/Makefile.in: delete mcserv.c entry variable NETFILES.
+
+Fri Sep 13 23:41:17 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * main.c, key.c: New mc.ini option - alternate_plus_minus.
+ If set, plus and backslash keys will work normally (i.e. insert
+ + and \), plus/minus/asterix on keypad will select/deselect/reverse
+ and M-+, M-- (M-\), M-* will do the same.
+
+ * tcputil.c: .netrc support. Currently is angry on users which have
+ .netrc readable by anybody else than owner, if it contains any
+ non-anonymous password. Perhaps, if it has good permissions, but
+ contains secret passwords, we should remember it and instead of
+ about 25% hints display a hint to remove them...
+
+Wed Sep 13 09:31:12 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * slang/*, main.c, screen.c: Some basic Linux Unicode support.
+ I cannot force the kernel to tell current Unicode UTF state, so
+ this has to be forced on the command line by running mc -N.
+
+Thu Sep 14 23:54:25 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * util.c (strip_home), vfs.c (vfs_canon), ftpfs.c, mcfs.c:
+ Handling of home directory (cd ftp://jfch.vc.cvut.cz/~/private)
+ and .. directory in the ftp root (will bring you to the directory
+ you have entered ftp from). nice_cd (cd via Network/Ftp link) will
+ append the home /~/ for you.
+
+ * widget.c (buttonbar_callback): In SLang, paint also buttonbar
+ numbers correctly fg on bg.
+
+Tue Sep 12 20:21:35 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ftpfs.c (store_file): Small change to allow compilation on
+ primitive systems that use a flag for SO_LINGER instead of a
+ struct linger.
+
+Tue Sep 12 10:25:01 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * Make.common.in, */Makefile.in, configure.in: Fixed and cleaned
+ all the Make.common and dependency stuff. Now we do not patch
+ Makefiles for non-GNU make ourselves, but leave that job on
+ autoconf. If non-GNU make, we put dependencies into the Makefiles
+ and if your make supports stem rules (e.g. %.o : %.c), then
+ we use them to avoid unnecessary relinking. Now the dependency
+ stuff should always work like you expect.
+
+Mon Sep 11 15:05:04 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * menu.c (menubar_paint_idx): Paint first letter when no matching
+ hotkey has been found.
+
+ * find.c (do_find): Allow chdir to selected directories
+
+ * screen.c (do_file_mark): Do not count the directory size when
+ tagging directories.
+
+ * slang/: Upgraded Slang to 0.99.20
+
+ * menu.c (menubar_event): Fixed the dropping menubar problem with GPM.
+
+ * subshell.c: Use the SIGUSR1 syncronization always (before it
+ only was used with SysV).
+
+ * init_sigchld is now always called from main.c instead of
+ allowing the subshell to setup the sigchld handler. Ching's fixes
+ to the waitpid routine (made on Jun 27) make this possible.
+ Should finally fix all the problems with SunOS.
+
+Sun Sep 10 02:06:05 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * mcserv.c (get_port_number): there must not be any references to
+ IPPORT_RESERVED outside the "#ifdef HAVE_RRESVPORT" block, because
+ it probably won't be defined. Also simplified the code a little.
+
+Sun Sep 10 14:57:04 1995 Jakub Jelinek (jj@jj)
+
+ * configure.in, Make*: Make.common handling is now done much cleaner
+ using the autoconf features. Also, dependencies now work for all
+ make programs, not only GNU. And last, but not least, fixed a thing
+ which didn't allow cross-compiling...
+
+Sat Sep 9 10:03:13 1995 Jakub Jelinek (jj@jj)
+
+ * */Makefile.in: Moved goals for libvfs.a and libmcslang.a back
+ from Make.common.in, since there is a collision in slang and vfs
+ directory...
+
+ * depend.awk: Fixed so that it never generates duplicate goals.
+ A pain are symlinks, but at least my GNU make doesn't find anything
+ suspicious (like there may be goals for src/util.h and xv/util.h,
+ which is a link to ../src/util.h). This is not possible to be done
+ in awk. The perl script will do it correctly...
+
+Fri Sep 8 17:53:14 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * layout.c (set_display_type), screen: Misc fixes. Containers are
+ not always WPanel *. I should rewrite the code to use containers
+ for the information that must be shared between panels.
+
+Sat Sep 9 01:16:11 1995 Ching Hui <br811563@csa2.cs.nthu.edu.tw>
+
+ * ftpfs.c (ftpfs_get_current_directory): New function.
+
+ * ftpfs.c (ftpfs_chdir): remember current remote directory.
+
+ * ftpfs: The active vfs list now should also report the working
+ directory on an ftpfs.
+
+Thu Sep 7 16:59:13 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * menu.c: Misc menubar fixes.
+
+ * tree.c (event_callback): God it was easy to fix one part of the
+ tree bug.
+
+ * key.c (get_key_code): Simplified the Meta-hanlding.
+
+Thu Sep 7 12:58:26 1995 Thanh Ma (tma@encore.com)
+
+ * mcfs.c: Small bug fix: do not return a value from a void routine.
+
+Thu Sep 7 12:06:27 1995 Juan Jose Ciarlante <jjciarla@raiz.uncu.edu.ar>
+
+ * subshell.c: On SCO do not compile the TIOCGWINSZ code even if
+ SCO has it. Wrote SCO versions of pty_open_slave and
+ pty_open_master.
+
+Fri Sep 8 02:07:07 1995 Jakub Jelinek (jj@jj)
+
+ * depend.awk, */Makefile.in: Alternate make dep mechanism if you
+ have awk. It is much faster (three up to four times) and
+ finds dependencies even for libraries from other directories
+ (libmcslang and libvfs).
+
+Thu Sep 7 10:45:01 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * Make.common.in, Makefile.in, */Makefile.in: Reorganized, so that
+ commonly used things are all in one file (Make.common), so that
+ e.g. if you want to define other CFLAGS by hand, you go to
+ Make.common. Also, reduces the possibility of errors, since all
+ variables (like the installation paths) have to be typed once.
+ If your make doesn't support include directive, we deal with it
+ in config.status and include it for you instead of make.
+
+ * view.c (get_line_at): Fixed awful bug which caused view not to
+ find anything on lines longer than 158 bytes.
+
+ * extfs.c (extfs_init): We now free the extfs.ini profile, so that
+ it won't be overwritten and is thus save to be edited by hand.
+
+Fri Sep 8 02:48:23 1995 Ching Hui <Nicholas@u811571.JEN.AB.nthu.edu.tw>
+
+ * panelize.c (add2panelize_cmd): get the correct input from pname.
+
+ * ftpfs.c: set errno to 0 before call the fgets.
+
+Wed Sep 6 10:08:59 1995 Marcelo and Juan Jose jjciarla@raiz.uncu.edu.ar
+
+ * src/tty.h: define correctly the macros to enable/disable the
+ keys.
+
+Wed Sep 6 10:07:17 1995 Steven N. Hirsch <hirsch@emba.uvm.edu>
+
+ * main.c (make_panels_dirty), user.c: Call the get_other_type
+ function, do not compare the address.
+
+Wed Sep 6 21:11:21 1995 Jakub Jelinek (jj@jj)
+
+ * screen.c, dir.c: Show @, ~, ! as file type instead of always @
+ for normal symlinks, symlinks to directories and stalled links
+ (those who point nowhere) at no time costs.
+
+ * file.c: If you are root, preserve_uidgid is now default.
+
+ * key.c: Handling of 8th bit for meta even when it has not matched
+ a stored sequence.
+
+ * learn.c: Now it is not possible to redefine characters from
+ space to ~.
+
+ * vfs.c: Per filesystem (un)getlocalcopy. This has an advantage
+ of not copying one local file to the other in case of ftpfs and
+ extfs and saves multiple extracts in tarfs.
+
+ * vfs.c (parse_ls_lga): Fixes the date problem.
+
+ * tar.c: Now it should handle even gzipped tar archives inside of
+ tar archives correctly.
+
+ * vfs/extfs.[ch], vfs/extfs/* (NEW): External filesystem.
+ Not working by default (and won't until we release 3.0), but if
+ you want to try, you can by typing make install.extfs in the
+ vfs directory. Doesn't still handle symlinks to different
+ vfs's (like linux -> ftp://sunsite.unc.edu/pub/Linux) correctly
+ and still read only. If you want to try it, you should also install
+ lib/mc.ext.extfs instead of lib/mc.ext to $(libdir)/mc/mc.ext.
+
+Tue Sep 5 19:37:35 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * find.c (do_find): Find again should work again.
+
+ * view.c (get_byte): Copy just those bytes on the original page.
+ Electric Fence and Ching found this one.
+
+ * subshell.c (init_subshell): Removed the check to TIOCSCTTY, from
+ the Emacs sources, it seems like we should ignore the return value.
+
+ * learn.c (learn_button): Do not define common keys as learned
+ function keys.
+
+Tue Sep 5 22:59:35 1995 Ching Hui <br811563@csa2.cs.nthu.edu.tw>
+
+ * vfs.c (mc_getlocalcopy): call mc_open function before tmpnam
+ function.
+
+ * ext.c (exec_extension): check the return value of mc_getlocalcopy.
+
+Tue Sep 5 23:39:12 1995 Jakub Jelinek <jj@gnu.ai.mit.edu>
+
+ * configure.in: fix to the XView and Tk check code - no they really
+ should not be compiled in by default in any case. If I'm wrong,
+ shoot.
+
+ * key.c: new flag - use_8th_bit_as_meta - is set (by default), input
+ characters greater than 127 are handled as Esc + (c - 128). This is
+ not true if inside of an control sequence. You can suppress this
+ meta handling (if you use your national characters greater than 127)
+ by running mc -m.
+
+ * screen.c (string_file_size): Show major,minor instead of size
+ for block and character devices.
+
+ * tar.c, vfs.c: Now I hope tar inside tar should work. At least
+ what I tested (and it was working) tar:tar:1.tgz/2.tar/VERSION
+
+Mon Sep 4 12:02:37 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * setup.c (save_setup), boxes.c (configure_vfs), ftpfs.c
+ (ftpfs_init): Should save/restore all of the VFS settings.
+
+ * tree.c (tree_event): on double click call chdir.
+
+ * slint.c (do_define_key): Use SLtt_tgetstr instead of tgetstr.
+ Lately Slang provides the SLtt_tgetstr as an interface to tgetstr
+ and the SLtt_tigetstr. This should fix the problem Torben had
+ with FreeBSD.
+
+ * mcserv.c (do_auth): Cancel login if the setuid system call failed.
+
+Sat Sep 2 20:58:18 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * key.c (get_key_code): generate an ALT-key if ESC+key is found
+ when outputing pending_keys. This should fix the problem with the
+ viewer quiting when some non-recognized key was pressed.
+
+Fri Sep 1 14:26:49 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c: C-x q switches the other panel to Quick View.
+
+ * dlg.c (dialog_handle_key): Added a call to clr_scr to force
+ ncurses to repaint on C-l
+
+ * slint.c (slang_init): Do not set the signal handlers that reset
+ the slkang attributes. They are only useful for the developer.
+ On SunOS they make the program get into a recursive loop (xterm -e
+ program).
+
+ * subshell.c (TIOCSCTTY): Pass the 0 argument to this ioctl,
+ SunOS makes a difference between 0 and 1 (this should fix the bug
+ reported).
+
+Sat Aug 2 00:38:01 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * vfs/mcserv.c: Now by default ftp validation is not done, to turn
+ it on, you need to use the -f flag.
+
+ * lib/xterm.ad: X resources to make xterm (not rxvt :( ) work well
+ with most (I hope all) the keys mc works with.
+
+ * lib/xterm.tcap: Termcap entry for xterm and xterm-color,
+ compatible with sequences send by xterm.ad and compatible with
+ xterm.ti. Those three should be used together.
+
+ * lib/xterm.ti: Minor changes.
+
+ * lib/README.xterm: HOWTO on installing these three files.
+
+Fri Aug 1 13:43:12 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * file.c: name_trunc in the file progress dialog.
+
+ * cmd.c (do_link): Cosmetic changes. Symlink now shows only one
+ dialog instead of two. Link shows name of the file you want link
+ to.
+
+ * help.c, man2hlp.c: Use HELP_*_COLOR colors in help. Added
+ italic color (no more same as bold).
+
+ * color.c: User can now define also helpnormal, helpitalic,
+ helpbold, helplink, helpslink and gauge colors.
+
+Sat Sep 2 02:02:18 1995 Ching Hui <br811563@csa2.cs.nthu.edu.tw>
+
+ * ftpfs.c: make all data transfer interruptable.
+
+ * boxes.c: add anonymous passwd and ftpfs directory cache timeout
+ entry to Virtual FS dialog box.
+
+ * vfs.c (vfs_path): New function.
+
+ * dir.c (set_zero_dir): fix possible loop when directory is
+ unreadable.
+
+Thu Aug 31 13:31:34 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * tree.c (event_callback): Focus panel when receiveing a key
+ click; set the correct event y for panelized trees.
+
+Thu Aug 31 14:06:11 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * key.c: Rewritten get_key_code. Now has a parameter nodelay,
+ if 0, it behaves like before, if 1, it doesn't ever wait but
+ emulates the behaviour of get_key_code (0), so it returns correct
+ KEY_* and other keycodes instead of sequences. You just have
+ to call it more times (in case all seqence characters are not
+ waiting on stdin). get_key_code (1) handles even old_esc_mode
+ (it uses GET_TIME instead of select).
+
+ * file.c: Uses get_key_code (1) instead of non-delayed xgetch
+ (otherwise you couldn't use arrow keys etc...)
+
+ * ext.c (regex_command): fixed behaviour of use_file_to_check_type
+ and initialized a local variable (which could cause in one of
+ 4G (perhaps less, 0 are often on the stack) an incorrect behaviour).
+
+ * configure.in, Makefile.in: create_vcs is installed only on Linux
+ machines.
+
+Mon Aug 28 13:27:38 1995 Ching Hui <u811571@JEN.AB.nthu.edu.tw>
+
+ * ftpfs.c: Check for connection close; beginning of the transfer
+ abortion code.
+
+Wed Aug 30 14:15:07 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * ext.c (regex_command): Now it will just execute file once
+ instead of one time per type/ in the mc.ext file.
+
+ * slint.c (slang_shutdown): Output the op capability at program
+ shutdown, this should fix the problem for Thanh.
+
+Tue Aug 29 18:47:35 1995 Torben Fjerdingstad <tfj@olivia.ping.dk>
+
+ * mc.menu: Added missing tar definitions.
+
+Wed Aug 30 11:05:44 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * file.c: Removed most of the #ifdef X - text code now uses
+ widgets (label & gauge) as well. Should produce normal dialog colors
+ instead of some strange ones and should be consistent with all the
+ others. Also, Skipping and Aborting should now work well and you
+ won't have to press keys to many times. Also, Enter and Escape
+ should work as well.
+
+ * widget.c: Finally text mode gauge widget is written.
+
+ * color.[ch]: Oops, 32 was used by A_REVERSE. I assigned to the
+ default color number 31.
+
+ * view.c: Added some vi-like, less-like and lynx-like keys for
+ moving in the viewer. We still do not support numbers before moving
+ commands. Should we? At least Ng and NG would be useful (as a short
+ variant of F5 N Enter).
+
+Tue Aug 29 18:53:26 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * boxes.c (tree): Set decent colors for the tree box.
+
+ * tree.c (tree_new): The tree problem was just that the searching
+ variable was not initialized.
+
+ * screen.c (repaint_file): Fixed the half panel bug.
+
+ * subshell.c (pty_open_master): Stupid mistake, will not hang
+ anymore.
+
+ * view.c (view_handle_key): Return now moves only one line.
+
+Tue Aug 29 18:47:35 1995 Torben Fjerdingstad <tfj@olivia.ping.dk>
+
+ * mc.ext: Non destructive mc.ext fixes. Jakub, please test them.
+
+Mon Aug 28 16:36:29 1995 Janne Kukonlehto <jtkl@jysky.oulu.fi>
+
+ * file.c: Added missing #include <ctype.h>.
+
+ * listmode.c: Some parts already working: OK, Cancel and General
+ options. Add and Remove almost work. Items listbox and Item
+ options don't work yet.
+
+Tue Aug 29 14:33:16 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * layout.c (swap_panels): Fixed. Now it should work fine and if
+ there are both view_listings, then it just swappes their content
+ (and not formats etc.), so that you may have one format in the left
+ and a different one in the right panel and if you want to see some
+ things that are in the left for a file on the right, you just C-u.
+
+ * cmd.c, color.c, sldisply.c: In SLang when default attributes
+ are different than white on black, mc shows command line and
+ hintbar correctly. You can easily run mc -c on a black on white
+ color xterm and the output is not awful.
+
+Mon Aug 28 21:12:37 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * icons/: I hope better and nicer icon collection than the previous
+ one. Most of them now have entries in mc.ext.
+
+ * main.c: Fixed the mc -P problem when the tty is not owned by
+ the user.
+
+ * dir.c (handle_dirent): Added one test that causes panelize
+ not to add files that are not on the disk (so it is possible
+ to e.g. cat any list of files and panelize will add to the
+ panel only the existing ones).
+
+ * main.c: Sets xterm window title to GNU Midnight Commander.
+
+Wed Aug 30 00:51:28 1995 br811563 <br811563@csa2.cs.nthu.edu.tw>
+
+ * ftpfs.c (get_line): fix mc block when socket is closed.
+
+ * tar.c (uncompress_tar_file): fix core dump when popen failed.
+
+ * tar.c (tarfs_get_path): return error when tar archive open
+ failed.
+
+Mon Aug 28 13:27:38 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * layout.c (change_screen_size), view.c (view_adjust_size): Add
+ screen resizing to the viewer.
+
+ * terms.c: (do_enter_ca_mode): Hard code the font switch "ESC)0".
+
+ * key.c (get_event): Will now delay calls to refresh if there is
+ input pending.
+
+ * cmd.c (nice_cd): Really, this time I fixed the problem with the
+ menus opening a ftp connection or net connection in the right panel.
+
+Mon Aug 28 13:27:38 1995 Ching Hui <u811571@JEN.AB.nthu.edu.tw>
+
+ * ftpfs.c: Switched to file descriptors again.
+
+Sun Aug 27 16:43:20 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * layout.c: Include termios.h, otherwise we don't get a resizing
+ Midnight Commander on Solaris.
+
+ * view.c (search): Allow search aborting.
+
+ * key.c (get_key_code): Handle the ESC+number inside get_key_code;
+ handle esc+space; use push_char/goto pend_send instead of returing
+ the key code to keep the internal sequence tracker on sync.
+
+ * subshell.c (pty_open_master): Will retry pty opening
+
+ * panelize.c (do_external_panelize): Do not free() the command,
+ let the parent handle this.
+
+Sun Aug 27 12:52:36 1995 Torben Fjerdingstad <tfj@olivia.ping.dk>
+
+ * FAQ, doc/mc.1: Spelling fixes.
+
+Sat Aug 26 20:45:00 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * learn.c: Now the left and right keys move among columns and the
+ vi's h, j, k, l work as well.
+
+ * wtools.c: It is now possible to specify a particular position
+ of quick dialog - this is used for M-c.
+
+ * Fixed the problem with xterm mouse.
+
+Sun Aug 27 11:05:43 1995 Ching Hui <u811571@JEN.AB.nthu.edu.tw>
+
+ * ftpfs.c: fix connection refused and connection close from
+ server bugs.
+
+ * ftpfs.c (ftpentry_destructor): fix memory corruption bug.
+
+ * ftpfs.c (ftpfs_chmod): use non-standard "SITE CHMOD" command.
+
+ * ftpfs.c (_get_file_entry): upload zero length to check the write
+ permission.
+
+Sun Aug 27 11:05:43 1995 Ching Hui <Nicholas@u811571.JEN.AB.nthu.edu.tw>
+
+ * ftpfs.c: fix connection refused and connection close from
+ server bugs.
+
+ * ftpfs.c (ftpentry_destructor): fix memory corruption bug.
+
+ * ftpfs.c (ftpfs_chmod): use non-standard "SITE CHMOD" command.
+
+ * ftpfs.c (_get_file_entry): upload zero length to check the write
+ permission.
+
+Fri Aug 25 13:11:55 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.h: Yes, very funny, we need unsigned chars, otherwise we
+ get those funny (char) 0377 -> (int) -1 conversions. Now, the
+ search should work on Piped files.
+
+ * view.c (get_line_at): Fixed the search routine. Now, the
+ get_line_at routine will skip over nulls.
+
+ * main.c (repaint_screen): Command line and panels should be
+ repainted correctly after executing a command.
+
+ * configure.in: SCO library detection
+
+ * fs.h: MC_MAXPATHLEN is the MAXPATHLEN or 1024 on systems that do
+ not define it (SCO), we should actually use pathconf.
+
+ * tar.c (tarfs_fill_names): Report the tar file names.
+
+ * container.c (linklist_delete): bug fixed: need to increment the
+ h pointer.
+
+ * widget.c (listbox_drawscroll): Presentation bug fix.
+
+ * util.c (my_system): do not block SIGCHLD anymore.
+
+Fri Aug 25 13:11:55 1995 Juan Jose Ciarlante <jjciarla@raiz.uncu.edu.ar>
+
+ * util.c (truncate, my_ftruncate): Provide truncate for systems
+ that lack it (SCO).
+
+Fri Aug 25 13:18:18 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * Makefile.in: Added listmode.c, listmode.h and listmode.o
+
+ * boxes.c (display_callback): Renamed Display mode dialog to
+ Listing mode. I think the dialog names should correspond to the
+ names of the menu entries where they are invoked.
+
+ * layout.c (rotate_dash): Verboseness check is no longer
+ necessary because we have an own nice_rotating_dash option.
+
+ * listmode.c, listmode.h: New files to implement user listing mode
+ editor. Still incomplete: it's got the looks but no functionality.
+
+ * main.c (listmode_cmd): New function to invoke user listing mode
+ editor. (CmdMenu): User listing mode editor is temporarily placed
+ in to Command menu. To be moved to Listing mode dialog when
+ complete. (OptMenu): I think Save setup should be separated from
+ the other choices. (version): In case of Slang reports which
+ terminal database is used. (handle_args): The -f option should
+ output to stderr, not stdout.
+
+Fri Aug 25 23:37:18 1995 Jakub Jelinek (jj@jj)
+
+ * key.c: A bunch of changes. old_esc_mode works again (should we
+ set a shorter timeout than 1 sec or should we let the user specify
+ this?). I was trying to unify all the different key routines
+ into the new define_sequence structure. Tell me if it works.
+
+ * mcserv.c (do_auth), configure.in: Support for Linux shadow
+ passwords.
+
+ (do_auth): Assign correct supplemental groups for process, if they
+ exist in the system and enhanced security of mcserv a bit.
+
+ * util.c (convert_controls): Fixed a bug, which caused that control
+ (< 32) characters could not be defined as sequences.
+
+ * learn.c (learn_keys): Added somehow more descriptive messages.
+
+ * xvmain.c (xv_center_layout): Fixed a problem with widgets
+ XV_WLAY_EXTENDWIDTH and narrow dialogs (such as one with empty
+ listbox) correct their width.
+
+ * cmd.c (view_other_cmd): Quick hack to repaint cmdline and hintbar
+ on Linux console after C-o correctly.
+
+Thu Aug 24 15:25:24 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * cmd.c (reselect_vfs): New command, uses the hotlist code to
+ display all the non local active virtual file systems.
+
+ * vfs.c (mcfs_fill_names, ftpfs_fill_names): Fill Used to report
+ the number of file systems active.
+
+Thu Aug 24 15:40:34 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * ext.c (regex_command): Now works correctly with files like
+ '#draft'.
+
+ * file.c (convert_case): New function. (transform_source): Now
+ supports six new codes in the target mask: \u and \l convert the
+ next character to uppercase or lowercase, \U and \L convert
+ characters up to \E or the end of the file name. Backslash also
+ works as a quote character. See the manual page for details.
+
+Wed Aug 23 13:50:13 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * subshell.c (init_subshell): If subshell does not initialize,
+ kill the subshell.
+
+ * help.c (interactive_display): Move the help bar to the proper
+ position.
+
+ * screen.c (WIDGET_UNFOCUS): clear the searching when loosing
+ focus.
+
+ * file.c (create_op_dlg, destroy_op_dlg): modify the hint bar
+ position during the operations to avoid the screen override that
+ could be caused by the ftpfs.
+
+ * cmd.c: Call repaint_screen again after update_panels.
+
+ * main.c (update_panels): do not repaint the panels, just mark
+ them as dirty and let the midnight_callback check for dirtiness
+ before a get_event is called (the new message DLG_PRE_EVENT is
+ used for this).
+
+Wed Aug 23 21:31:24 1995 Steven N. Hirsch <hirsch@emba.uvm.edu>
+
+ * layout.c (setup_panels): Compute properly the hint position.
+
+Wed Aug 23 20:42:45 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * mc.1: Documentation fixes.
+
+ * learn.[ch] (NEW): Learn keys command.
+
+ * slint.c: SLang now resets attributes after SIGTERM and bunch of
+ other signals.
+
+ * wtools.c (message): Fixed D_INSERTed messages (like Searching
+ wasn't ever shown).
+
+ * ext.c: Version check for 3.0's mc.ext and .mc.ext. In case it
+ finds and old formatted, tells what to do.
+
+Tue Aug 22 20:15:01 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * configure.in: --with-slang is now the default together with
+ --without-xview and --without-tk. If you want to compile with
+ ncurses, use --with-ncurses and likewise --with-xview and --with-tk
+
+ * tcputil.h, configure.in: Check for rpc/pmap_clnt.h header and
+ including it if exists.
+
+ * xv/Makefile.in: Fixed the -lXpm problem.
+
+ * mc.1, INSTALL, INSTALL.FAST, NEWS: A bunch of documentation
+ fixes and additions, but there is still lot of work for EVERYONE.
+
+ * man2hlp.c: Now indents the help's index again...
+
+ * {tk|xv}/Makefile.in: Fixed a link goal problem on old SunOs.
+
+ * */*: Many fixes all around the code to make at least my GCC happy
+ with the -Wall. Now it shows on the slang mc no warnings except in
+ regex.c.
+
+Mon Aug 21 19:08:05 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs.c (vfs_add_noncurrent_stamps): Do nothing if the panels have
+ not been setup (this let's you: mc ftp://roxanne)
+
+ * setup.c (load_setup): Will not open by default non local vfs
+ when loading the configuration.
+
+ * profile.c (free_profile_name): Fixed seg fault problem on Linux;
+ (load): Keep spaces on keys unless they are at the beginning of
+ the line (for nice external panelize displays).
+
+Mon Aug 21 22:10:06 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * configure.in: Removed duplicate -L options for XView, misc fixes.
+
+ * xterm.ti: Modified smcup so that it works well even on broken
+ xterms. Hope this will not break anything.
+
+ * mcfn_install.in: Added check and installation to ~/.bashrc,
+ if running from bash. If mc () is in ~/.profile, then it applies
+ only to the login shell :(
+
+ * boxes.c, cmd.c: New feature - M-c (Quick cd) - pops up a dialog
+ where you enter exactly what you type after "cd " on the command
+ line. The difference is that you don't have to yank and paste
+ your full command line because you want shortly change directory.
+
+ * complete.c: Added special handling for "cd " and quick cd -
+ now only directories are completed (CDPATH should remain untouched).
+
+ * file.c (move_dir_dir): Removed test for EXDEV error, now we
+ are trying to copy and then delete whenever any error during
+ renaming occurs. This is because e.g. NFS returns sometimes
+ EIO, if I'm moving on one nfs filesystem, which contains more
+ filesystems on the nfs server. Hope this won't even hurt.
+
+ * panelize.[ch]: New modules which show nice database of stored
+ panelizing commands, you can add new, assign to them names etc.
+ (Like C-\ for cd).
+
+ * widget.c (label_set_text): Fixed this routine so that it paints
+ everything correctly if the new string is shorter than the previous
+ one and added a parameter/flag which tells it whether we want to
+ adapt the label length (useful for the message bar).
+
+Sun Aug 20 11:00:51 1995 Ching Hui <Nicholas@u811563.JEN.AB.nthu.edu.tw>
+
+ * container.c (linklist_destroy): fix memory corruption bug.
+
+ *ftpfs.c: add time out code to directory cache.
+
+Sat Aug 19 15:25:56 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c: fix symlink.
+
+Sat Aug 19 13:27:09 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * help.c (move_backward2, move_forward2): If we can't move the
+ number of lines requested, set current to the startup value.
+
+ * view.c (search): Now will rotate the dash when searching.
+
+ (normal_search): Will not load all the file into core before
+ starting a search.
+
+ * slint.c (vline): uses spaces when -s flag is used.
+
+ * main.c (suspend_cmd): Call do_refresh for a complete screen
+ redraw, slang seems to not like the touchwin, refresh after coming
+ back from suspend.
+
+ * dlg.c: use suspend_cmd instead of do_suspend_cmd that should be
+ an internal function of suspend_cmd.
+
+Fri Aug 18 10:09:07 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * screen.c: Implemented torben_fj_mode for home/end key behavior.
+
+ * wtools.c (input_dialog_help): Fixed the password problem on the
+ input dialogs.
+
+Wed Aug 16 05:16:50 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c: flush directory cache after store file, rmdir, and
+ mkdir.
+
+ * ftpfs.c (ftpfs_rmdir): fill the missing code.
+
+ * ftpfs.c (retrieve_dir): change "LIST -lba" to "LIST -la", since
+ ftp.funet.fi doesn't happy with -b argument.
+
+Tue Aug 15 23:34:01 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * mc.1: Manual page fixes.
+
+ * win.c: You can now define even f11-f20 keystrokes in your
+ mc.lib/.mc.ini file. f13 is used for unparsed view, f20 for quiet
+ quit (no confirmation, if invoked with -P, it returns ., i.e.
+ no current directory change).
+
+ * file.c: Fixed a bug when the target existed as a symlink. Now, if
+ you say you want to overwrite it, mc deletes the symlink and either
+ links new symlink or copies the new file there. Previously, in the
+ first case, a message saying cannot create target symlink was shown
+ and in the later case the new file overwrote the file target symlink
+ was pointing to.
+
+ * main.c: Command line in XView now looks a bit better.
+
+ * xvwidget.c: WCheck and WRadio now correctly set their initial
+ values (previously all of them were on/with first one checked).
+
+ * xvwidget.c: WLabel now moves all the widgets to the right of it,
+ if we change its length by assigning a new text to it.
+
+Wed Aug 16 05:16:50 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c: flush directory cache after store file, rmdir, and
+ mkdir.
+
+ * ftpfs.c (ftpfs_rmdir): fill the missing code.
+
+ * ftpfs.c (retrieve_dir): change "LIST -lba" to "LIST -la", since
+ ftp.funet.fi doesn't happy with -b argument.
+
+Tue Aug 15 00:42:18 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * cmd.c (view_simple_cmd): This is for displaying unformatted
+ view of a file (will be sticked to F13 or Shift+F3).
+
+ * ext.c: Fixed a view Format/Unform error.
+
+ Fixed two other bugs in regex_command, causing e.g. a file to be
+ viewed only once in its formatted version.
+
+ * main.c (quiet_quit_cmd): This is for quitting without changing
+ the directory where you were before if using -P (more precisely,
+ this prints "." instead of the last directory). Will be sticked
+ to F20 / Shift+F10.
+
+ * screen.c (do_file_mark): Fixed selection handling in XView.
+ Now sets panel->marked etc. correctly.
+
+ * xvmain.c: Fixes to make drop work. It is still an ugly hack, but
+ it seems to me that I've found an awful bug in XView :(
+
+ * xvscreen.c: Drop should really work. Try it...
+
+Fri Aug 11 16:57:35 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * file.c (check_buttons): Now it handles space and tabs.
+
+ * cons.handler.c (show_console_contents): Slang/terminfo does not
+ wrap characters at the end of a line, so we manually move to the
+ next line.
+
+ * widget.c (label_destroy): Expanded the Label widget: if the text
+ member does have a zero value it will not be displayed (I will
+ use this for the hintbar). Removed the hintbar support from the
+ buttonbar code.
+
+Mon Aug 14 14:18:19 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c: fix redundant copy of directory cache and support open
+ for write.
+
+Sun Aug 13 22:46:12 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * Misc fixes in configure and installation procedures.
+
+ * xvicon.c: Now it is possible to move these icons, drop files onto
+ them, show the icon dependent menu etc.
+
+ * ext.c: Fixed some horrible bugs causing segfaults noticed by
+ someone here on the list, which I had troubles for a longer time
+ with.
+
+Thu Aug 10 19:45:30 1995 Ching Hui <u811563@thccy12>
+
+ * ext.c (exec_extension): Tcsh did not like our lines without a
+ trailing newline.
+
+Thu Aug 11 00:43:17 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * Makefile.in: libdir is now in $prefix/lib/mc instead of
+ $prefix/lib, so that all our mc.{hlp|ext|menu|hint|keys} files
+ and the FAQ are nicely grouped together into one directory.
+ In there is a subdirectory icons with all the icons.
+
+ * aclocal.m4: Test for header files in standard paths and in user
+ defined additional directories (AC_CHECK_HEADER_IN_PATH). Those
+ directories can be specified in the beginning of configure.in.
+ Let me know which directories would you like to be there.
+
+ Also added checks for the Xpm library and headers and for the X11
+ shape extension (also header and -lXext).
+
+ * configure.in: I was trying to fix the file & sed bug. Could
+ anybody test it and in case of error send me again sh -x configure?
+
+ * doc/mc.1: Now are even mc.1 and mc.hlp parsed with sed for
+ @prefix@.
+
+ * ext.c (regex_command): Speeded up by i) caching mc.ext in memory
+ (FIXME - should reload it on any change in mc.ext) and ii)
+ when looking for Icon, we are automagically looking for Title
+ as well.
+
+ * xvicon.c (CreateXpmIcon): Now paints titles under icons as well.
+
+Wed Aug 9 18:54:33 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * widget.c (buttonbar_callback): Added the hint-bar support (or
+ should it be called message bar?), now we need to add the hints
+ and the code that will display them.
+
+Wed Aug 9 23:56:12 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * ext.c (do_regex_command): Changed meaning of shell/ in mc.ext -
+ it is extension only if the first character is ., i.e.
+ shell/.tar
+ will match *.tar, but if it doesn't start with a dot, then it
+ matches only the same filenames (i.e. shell/gzip matches only gzip).
+
+ Added Icon and Title actions in mc.ext. Icon is a pathname of an
+ XPM file (possibly with the None color somewhere, so that it may
+ be transparent somewhere). If it is not absolute pathname, then
+ it defaults to $(icondir) ($(prefix)/lib/mc/icons/). Title specifies
+ the title under icon, with %p for filename and %d for pathname.
+ %d/%f is complete path. Default title is %p.
+
+ Fixed an awful bug in comparison of actions.
+
+ * cmd.c (dirsizes_cmd): Fixed a bug that caused wrong information,
+ if you had directories where name of one of them was concatenation
+ of the other plus something (like mc and mc-2.4.93).
+
+ * setup.c: Now we clean the correct temporal sections ('cause panel
+ names have changed).
+
+ * wtools.c (input_dialog_help): Fixed displaying of input boxes in
+ XView.
+
+ * xvscreen.c (xv_mouse_event): Double-click works! Drop should work
+ as well, but it is still a bit buggy.
+
+ File type dependent menu, if you press the right mouse button on a
+ file. This one lets you easily Open/View/Edit/Copy/Move/Delete plus
+ any user defined actions from mc.ext (like Compile, Link, Flush
+ etc.).
+
+ * xvaction.c, xvicon.c: Completely changed basics of Action icons.
+ Now these icons are just files which were moved (dropped in the
+ future) from the panels. Icon and Title are looked up in mc.ext, the
+ only thing we have to specify in mc.ini for those icons, which are
+ loaded by default at startup, is position of icon center, in format
+ +x+y, where x and y are positive numbers.
+ Entries in .mc.ini's Action Icons section look like
+ /bin/rm=+20+120
+
+ * icons/: New directory full of nice icons in XPM format. Hope
+ you'll like them. We'll have to look for some even nicer ones,
+ but some of them are really good (I think).
+
+Tue Aug 8 17:22:15 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * key.c (get_event): Now we return to the caller program if select
+ sets errno = EINTR (thanks to Hugh Redelmeier (hugh@mimosa.com)
+ for the hint). This actually makes the program resize it's screen
+ as soon as it is resized.
+
+ (get_event): If we are not waiting for a mouse repeat event and
+ there are pending
+
+ sldisply.c: Clear the current acs status at slang startup.
+
+Tue Aug 8 16:23:39 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c: Will not hang if the address is bogus.
+
+ * vfs.c: Removed the dialog stuff (we did not use it).
+
+Mon Aug 7 13:13:12 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * screen.c (panel_update_cols): Now all of the column computing is
+ done in this function (instead of doing half the job here and the
+ other half in layout.c: setup_panels).
+
+ * auto.c: Removed automount feature.
+
+ * option.c: optimize the case for a toggle-only variable and
+ remove all of the unused toggle_* functions.
+
+Sun Aug 6 21:33:08 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c (retrieve_file): New function.
+
+ * ftpfs.c (parse_ls_lga): fix typo.
+
+ * vfs.h: change vfsid type definition from int to void *.
+
+Mon Aug 7 23:43:12 1995 Jakub Jelinek <jj@gnu.ai.mit.edu>
+
+ * */Makefile.in: Added make variable DESTDIR, which makes it
+ possible to move the install root somewhere in the directory tree.
+ (Was necessary because not all files are installed in $(prefix)).
+ Use it like: make install DESTDIR=/package/mc
+ and the files (in case $(prefix) is /usr/local) will be installed
+ into /package/mc/usr/local/bin, /package/mc/usr/local/lib and
+ /package/mc/usr/openwin/bin etc...
+
+ * boxes.c (display_box): Now correctly restores default format
+ after returning from a Info/Quick View/Tree widget.
+
+ * configure.in: Default prefix (if you do not specify) will now
+ depend on whether you have mc already installed in your system
+ to /usr/bin/mc or /usr/local/bin/mc.
+
+ * mc.ext, ext.c: For Torben - the lynx action for \.html?$ files
+ added and should work even on ftpfs :)
+
+ * cmd.c (dirsizes_cmd): Do not call du if on non-local vfs.
+
+ * vfs/Makefile.in: If you undef USE_NETCODE, you should compile
+ it without the net objects.
+
+Fri Aug 4 18:45:39 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * slint.c (slang_init): Disable flow control, thanks to John Davis.
+
+Sat Aug 5 01:03:08 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c (ftpentry_destructor, ftpfs_dir_destructor, ftpfs_chdir,
+ ftpfs_mkdir, ftpfs_getid): fix typo and memory leak.
+
+ * ftpfs.c (ftp_connection_destructor, ftpfs_init, ftpfs_done):
+ New function.
+
+ * ftpfs.h: New file.
+
+ * vfs.c (vfs_init): call ftpfs_init.
+
+ * vfs.c (vfs_shut): always free the vfs resource, call ftpfs_done.
+
+Thu Aug 3 20:07:58 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * main.c (reload_panelized): Fixes the problems with the panelized
+ files. We first chdir to the panelized directory cwd and then
+ restore it if it is not the current_panel.
+
+ * tkmain.c (tkmc_callback): Tk: Selection on input lines work now.
+
+ * wtools.c (message), view.c (search): Search should work with Tk now.
+
+Thu Aug 3 16:01:00 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * configure.in, */Makefile.in: A lot of small changes - tkmc is now
+ included by default, --without-tk can turn it of, new options
+ --with-tk-includes=dir --with-tk-libs=dir --with-xv-bindir=dir.
+ Also should check if file accepts - as an option (Miguel, could you
+ test it on a machine which doesn't support it)?
+
+Thu Aug 3 23:24:34 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c: use link list instead of array to store connection
+ information.
+ * ftpfs.c (ftpfs_free): free the connection resource when timeout.
+
+Wed Aug 2 19:30:03 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * help.c (move_forward2, move_backward2): The next/prev page works
+ again on the help.
+
+ * widget.c (listbox_drawscroll): Now we draw a sort of scrollbar
+ that includes the '|' character.
+
+ * subshell.c (init_subshell): More robust: If the child had
+ problems before the parent had a chance to setup the sigchld
+ handler it would hang, now the code calls waitpid after the
+ init_sigchld has been called. (There is no use in installing
+ sigchld_handler before since the child could execute and abort
+ before the parent had returned from fork ()).
+
+Wed Aug 2 16:01:00 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * ext.c: Rewritten, now uses only one file (mc.ext) instead of three
+ (mc.{edit|view|ext}) with a completely new structure. For the
+ description see comments in the sample lib/mc.ext file.
+ BTW: You have to update your .mc.ext file, otherwise nothing will
+ work.
+
+ * configure.in: du checks, now should handle all the du's.
+
+Wed Aug 2 21:24:45 1995 Ching Hui <u811563@thccy12>
+
+ * ftpfs.c (get_file_entry, _get_file_entry): New function.
+
+ * ftpfs.c (ftpfs_lstat, ftpfs_stat, ftpfs_fstat): call get_file_entry
+ to get ftpentry.
+
+ * ftpfs.c (retrieve_dir): change into directory before getting the
+ directory list.
+
+Tue Aug 1 12:47:59 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * tkwidget.c (tk_update_input): Use the window name.
+
+ * vfs.c: Removed the alarm code.
+
+ * slint.c: Now we keep track of the original and program-mode
+ terminal settings, no more problems with the raw mode on
+ terminals.
+
+Tue Aug 1 12:12:45 1995 John E. Davis (davis@space.mit.edu)
+
+ * sldisply.c (write_attributes): Some broken terminal databases
+ when restoring normal video turn of ALL attributes. This should
+ fix the problem on HP-UX and maybe AIX.
+
+Tue Aug 1 23:26:12 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * xvscreen.c, xvmain.c: XView repaint fixes, coded mouse handling -
+ everything except drop (drag should work).
+
+Mon Jul 31 12:41:52 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * ftpfs.c: Recoded missing parts of the ftpfs, now it allows you
+ to do copying/viewing of the remote files.
+
+Sat Jul 29 20:01:00 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * main.c (main, do_nc): Fixed a bug causing mc to list a part of
+ .mc.ini on my system. It occurred when ran with -P, because we were
+ trying to print already freed string which has been accidentally
+ overwritten.
+
+ * mcfn_install: New shell program (called from main Makefile's
+ mcfninstall goal) which tries to install the mc() function into your
+ profile.
+
+ * cmd.c (dirsizes_cmd): New command in the command menu. Until you
+ press C-r or change directory in the current panel, directory sizes
+ will be replaced by the space used by them and their subdirectories
+ as shown by du -s -b. You can then easily select these files and
+ see the totals.
+
+ * file.c (copy_file_file, move_file_file): If you're moving a file
+ onto already existing one, you won't be asked twice any more...
+
+Fri Jul 28 18:29:11 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * slang/ Upgraded to slang 0.99-19.
+
+ * Tk/ File copy/move/delete progress window works.
+
+Fri Jul 28 19:32:15 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * menu.c (menubar_handle_key): Fix so that menu hot keys work
+ properly...
+
+ * xv/: I've broken everything, do not even try it, but it compiles
+ without SlingShot already :)
+
+ * find.c (external_panelize): stderr goes to /dev/null where it
+ ought to be :)
+
+Thu Jul 27 17:51:43 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * tkmain.c (tk_dispatch_all): New function to flush all the
+ pending Tk events.
+
+ * mc.tcl, file.c: Now query_dialogs work with any number of
+ options, replace dialog is working with Tk.
+
+ * tkmenu.c: left/right commands now work.
+
+ * tkmain.c: tk_getch implemented, quote works on tkmc.
+
+Thu Jul 27 10:43:25 1995 Janne Kukonlehto (jtklehto@indy4)
+
+ * find.c (external_panelize): new function, now you can panelize
+ the output of any external command.
+
+Wed Jul 26 19:54:40 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * tkinfo.c, mc.tcl: WInfo now works with Tk.
+
+Wed Jul 26 10:48:58 1995 Thanh Ma <tma@encore.com>
+
+ * tar.c (tar_fstat): fixed missing ifdefs, now it should compile
+ on SVR3.x
+
+Thu Jul 27 00:14:05 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * screen.c (to_buffer, parse_display_format): Fixed painting of
+ files when the column is narrow and also titles should be painted
+ correctly in such case.
+
+ * Makefile.in: Should make non-existent directories on install now
+
+ * file.c (move_file_file): Fix so that append works even when
+ moving.
+
+Tue Jul 25 14:32:56 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * main.c (load_prompt): Cut prompt if it is too long.
+
+Tue Jul 26 00:40:12 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * help.c (show): Midnight in the first help page should be painted
+ in ACS even in slang (if terminal has it).
+
+ * myslang.h, main.c (main): beep should work even in slang.
+
+ * */Makefile.in*: Ugly hack which removes the stupid relinking of
+ mc/mxc/tkmc always, since libvfs.a and libmc.a were in another
+ directory...
+
+ * complete.c (try_complete): Now completes fine even if you have
+ CDPATH set to something and try to complete a non-existant path
+ which exists if prefixed with one of the directories in CDPATH.
+ Example: I have CDPATH=.:~:~/src:/usr
+ and I'm somewhere where no directory begins with mc. The only
+ directories starting with mc- are in ~/src. If I type
+ cd mc-
+ and press M-Tab twice ('cause there are more than one possible
+ completions), I get list of ~/src/mc-2.4.76 and ~/src/mc-patches.
+ FIXME: Should write some documentation on CDPATH and its usage.
+
+Mon Jul 24 17:49:38 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * tkscreen.c, tkmain.c: Finally I'm using a proper method that
+ does not rely on the container name to create the panels. This is
+ required to implement to WView, WTree and WInfo widgets in Tk to
+ be used as panels.
+
+ * Quick view working under Tk.
+
+ * vfs.c (vfs_setup_wd): At setup time, set current_dir to empty if
+ we happend to hit a non-existant directory.
+
+Mon Jul 24 15:55:28 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * util.c (mc_doublepopen), tar.c: Bug fixing of corrupt tar files.
+
+Mon Jul 24 11:42:35 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * main.c (sigchld_handler_no_subshell): Wait only the
+ cons_saver_pid when compile without subshell.
+
+ * tar.c (tafs_get_path): put the archive on stamp list, tar_open must
+ remove the archive from stamp list.
+
+ (read_tar_archive): will close archive->fd after reading the
+ entry, but it is wrong, when mc didn't read the whole archie in
+ memory, it will get a core dump. (i.e open a non-gzip tar file,
+ and try to view the file.)
+
+ Delete the mc_close(archive->fd) from tar_close, it is handle by
+ free_archive.
+
+Fri Jul 21 20:52:24 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * mc.tcl: Copy dialog works with the new dialog that Jakub wrote.
+
+ * view.c: Tk/Viewer is now working.
+
+ * util.c: No more <defunct> processes after looking at a tar.gz file.
+
+Fri Jul 21 11:00:05 1995 Jakub Jelinek (jj@gnu.ai.mit.edu)
+
+ * tree.c (my_mkdir, my_mkdir_rec): F7 (Mkdir) now creates as many
+ directories as you want in one command (just type there e.g.
+ bla/foo/foo2/).
+
+ * main.c (copy_*): C-x (C-)p now adds a slash at the end, so you do
+ not have to type it yourself.
+
+Wed Jul 19 18:41:29 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * view.c (flush_line): Tk: Colors work on the internal file
+ viewer.
+
+ * tar.c: possible bug fix to the growing tar files tar_open, I'm
+ not sure I did it right. (load_compressed): Added a couple of
+ rotate_dash()s.
+
+ * layout.c (use_dash): New routine, controls updating of the dash
+ with rotate_dash.
+
+Tue Jul 18 13:08:54 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * main.c (main), slint (slang_shutdown): Now it leaves the program
+ in the non-application screen.
+
+Tue Jul 18 10:50:25 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * cons.saver.c (detect_console): Make the code compile.
+
+ * command.c: The Ctrl+Enter never reaches this part of the code,
+ moved to midnight_callback.
+
+Mon Jul 17 12:53:32 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * slint.c, myslang.h: Better compatibility with curses.
+
+Mon Jul 17 11:18:42 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * configure.in, tty.h: Forgot to define USE_NCURSES, forgot some
+ constants.
+
+ * util.c: Handle too many arguments on mc_doubleopen.
+
+Tue Jul 18 16:55:20 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * xvmain.c, xvinfo.c: XView version should compile cleanly and
+ even run (at least on my system) now... :)
+
+ * help.c: No more deadlocks in XView's help
+
+ * xvmain.c (xvdlg_show): Should now handle initial focus for
+ dialogs.
+
+Fri Jul 14 16:10:47 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * util.c (my_statfs): Should report the correct file system. I
+ have nfs mounted /home/miguel/s and it was reporting
+ /home/miguel/slang to be on the nfs partition.
+
+ * key.c (init_key): Fixed the escape sequences for irix-ansi and
+ xterm.
+
+ * sldisply.c: Added terminal size detection to Slang.
+
+ * help.c (help_event): Fixed mouse coordinate handling and repainting.
+
+Fri Jul 14 15:47:07 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * aclocal.m4: OSF/1 cc compiler fixes.
+
+ * tty.h: handles all of the curses differences now instead of
+ our tricky lib/ncurses.h
+
+ * util.c: exevp portability fixes.
+
+ * menu.c: hline fixed.
+
+ * xcurses.c: Hacked to work with OSF/1 curses.
+
+Thu Jul 13 16:06:06 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * mouse.c (init_mouse): When running with slang is important to
+ flush stdout so that the mouse actually its activated.
+
+ * boxes.c (display_bits_box): Now the setting is computed
+ correctly (ie, it works)
+
+ * sltermin.c (Tgetstr_Map): Added keypad transmit mode on/off, now
+ cursor keys should work with terminfo.
+
+ * subshell.c (read_subshell_prompt): The prompt should be there no
+ matter what happens.
+
+Thu Jul 13 16:51:34 1995 John Davis <davis@space.mit.edu>
+
+ * slang/sldisply.c: Provided semantic compatible routines for
+ tgetstr, tgetnum and tgetflag.
+
+Wed Jul 12 18:40:06 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs.c (vfs_add_noncurrent_stamps): Check for other panel type
+ before using opanel.
+
+Wed Jul 12 16:59:23 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * slint.c (slang_init): Fixed the slang/terminfo problem, reported
+ by Ching and Thanh.
+
+ * help.c: Make the buttonbar functions redraw the screen.
+
+ * slint.c: Slang support should work with terminfo again.
+
+Wed Jul 12 14:09:30 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * vfs: cpp options indentation to compile under OSF/1.
+
+ * configure.in: Support for --with-vcurses flag for those strange
+ setups.
+
+ * OSF/1: Changed some inline functions for macros in order to get
+ OSF/1 compiler to work.
+
+ * screen.c: move is sometimes a macro (slang support).
+
+ * util.c: portability fix for exec parameters.
+
+Tue Jul 11 11:01:45 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * dir.c, tree.c: Updating of the tree widget when loading new
+ directories should be working again.
+
+ * dlg.c (find_widget_type): New function to find the first widget
+ in a dialog head. FIXME: find_buttonbar should be rewritten to use
+ this routine.
+
+ * cons.saver.c (detect_console): Should detect a console on
+ /dev/tty[0-9][0-9]
+
+ * help.c: Works again.
+
+ * slint.c (has_colors): Now it activates color based on the
+ terminal name
+
+ * OSF/1 C Compiler portability fixes (change the format of the cpp
+ directives), thanks to Ching Hui,.
+
+Mon Jul 10 13:04:19 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * view.c (flush_line): Now we use call directly the widget command
+ to insert the line text thus avoiding escaping the string.
+
+ * dlg.c (dlg_run_done): Tk: focus the previous running dialog.
+
+ * ftpfs.c (ftpfs_readdir), mcfs.c (mcfs_readdir), tar.c: On
+ Slowaris 2 and maybe the new Linux C library (with the latest
+ kernels) the d_name field is only 1 byte long, a clever trick that
+ breaks our code. We now have an extra buffer after the dirent
+ struct. In short: the VFS works under Solaris.
+
+ * main.c, screen.c (panel_new): Use the vfs' mc_get_current_dir
+
+ * slint.c (slang_keypad): Now it should set the keypad mode before
+ starting up, this should fix the problem with the keyboard.
+
+
+ * screen.c (panel_new): mc core dumped when I tried to change the
+ Listing mode, because it did not initialize the panel->fmt_count
+ variable.
+
+ * wtools.c: the net based file systems showed the typed in password.
+
+Fri Jul 7 14:37:44 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * view.c (flush_line, view_gotoxy): Added initial support for
+ caching viewer lines in the Tk version, need to escape the special
+ character sequences before it will work properly.
+
+Thu Jul 6 17:25:00 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * subshell.c (init_subshell): We no longer complain if the
+ subshell can not be used, we just toggle it off
+
+Thu Jul 6 16:24:34 1995 Mark Olesen <tma@encore.com>
+
+ * slint.c: Check for the COLORTERM environment variable, this
+ will activate the color support for slang.
+
+Thu Jul 6 16:24:34 1995 Thanh Ma <tma@encore.com>
+
+ * tcputil.c, mcserv.c: The correct include file to use is not
+ rpc/types.h but rpc/rpc.h
+
+Wed Jul 5 12:55:31 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * file.c (file_mask_dialog): Should compile with Unixware compiler.
+
+ * Makefile.in (CPPFLAGS): Thanks to Thanh Ma <tma@encore.com> for
+ pointing me that the regex code from GNU can be used without alloca.
+
+
+Wed Jul 5 19:34:52 1995 Mark Olesen <olesen@weber.me.queensu.ca>
+
+ * Portability to non GNU C compiler under AIX: replaced #ifdef 0
+ for #if 0, included time.h in vfs files, mem.h: rindex is only
+ defined if no definition existed previously.
+
+Tue Jul 4 18:27:10 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * screen.c (chdir_other_panel): Now Alt-o besides showing the
+ contents of the current directory in the other panel, moves the
+ cursor down one line. Please tell me if you like this option.
+
+ * find.c (insert_file): Removed the code that advanced the dir
+ name pointer over the "./", this caused the find/panelize problem
+ to be triggered, since the panelized paths were all wrong.
+
+ * mc.tcl (center_win): Tk: Dialogs are now centered inside the
+ main window and have local grabs (at least!)
+
+Mon Jul 3 18:15:12 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * mc.tcl: Now child windows are centered after being displayed.
+ This is still not working properly, since we flush all the events
+ (and thus make the window visible) before we compute the correct
+ geometry. If someone knows how to center a toplevel window or how
+ to compute the geometry of a toplevel before it's mapped onto the
+ screen it would be great.
+
+ * tkscreen.c (compute_font_size): Now we finally are able to
+ compute the font size and thus the panel size, so resizing a panel
+ should work now. Anyways, most of the job is based on Janne's
+ changes for the Midnight Commander 2.1 that were not released
+ officially.
+
+Mon Jul 3 10:30:38 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * dlg.c: Fixed event dispatching, now we don't send wrong events.
+
+ * tree.c: Define the correct event handler.
+
+ * wtools.c (listbox_refresh, listbox_callback): The listbox did
+ not have a listbox_callback routine and no refresh code, now it does.
+
+Sun Jul 2 20:51:19 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * file.c: Fixes to the new copy/move commands, on deletion user
+ can turn off/on typing yes to make himself sure he wants to do it
+ (the other possibility is that the No button will be default instead
+ of Yes). Also, added support to preserve UID/GIDs when copying (only
+ root can do it). Can anyone test all of this :)...
+
+ Also, removed the mask rename command, which should be completely
+ redundant by the new rename operation (you just do specify both
+ masks as before, the only difference is that you can now specify
+ a target path as well, i.e. mask rename equals to rename in the
+ current directory).
+
+ * main.c (cd_try_to_select): is done for tar archives as well :)
+
+ * mc.1: Eventhough real programmers do not write any documentation,
+ I wrote something, which is quite unreadable and unclear and looking
+ for someone who has a gift of explaining what I wanted to write and
+ actually wrote (this mightn't be the same).
+
+ * xv/Makefile.in: Another change in the Makefile. Hopefully XView
+ will compile out of box now, not for the second time...
+
+ * wtools.c (query_dialog_*): Added new procedure (query_dialog_sel),
+ which has one of its parameters id of the button you want to have
+ initially focused.
+
+ * dlg.c: Support for initial focus, currently used in query_dialog_*
+ only, but should become at least a bit more used.
+
+Thu Jun 29 13:01:31 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * wtools.c (query_dialog): Fixed the bug that showed only empty
+ dialog boxes.
+
+Wed Jun 28 09:14:00 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * subshell.c (sigchld_handler): Fixed another miguel-mistake. We
+ should not return blindly after dispatching one signaled child,
+ maybe the console saver also had something to say and only one
+ signal was sent.
+
+Tue Jun 27 12:14:10 1995 Ching Hui (u811563@Oz.nthu.edu.tw)
+
+ * subshell.c (sigchld_handler): Now we only catch the subshell_pid
+ and the cons_saver_pid, this should fix the long standing bug with
+ popen and other wait() calls.
+
+Mon Jun 26 14:23:22 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * tkwidget.c (tk_radio_callback, tk_check_callback): They now call
+ the actions on the standard widget.
+
+Sat Jun 24 16:29:52 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * chown.c: Now it uses labels for the interesting information, the
+ rest will be handled on Tk.
+
+Fri Jun 23 15:01:55 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * hotlist.c (init_hotlist): We now use labels instead of manually
+ drawing the labels on the widget. This is what must be done for
+ the rest of the widgets in order to run the dialogs with both
+ ncurses and X.
+
+ * (tk/): find file command, listing mode, sort order and option
+ configuration panels work on tk.
+
+Thu Jun 16 00:09:09 1995 Jakub Jelinek (jj@jfch.vc.cvut.cz)
+
+ * xvkey.c: Got rid of mouse and key stuff of the text version, so
+ now good bye lgpm and a chunk of ncurses. I will have to take some
+ time and remove all the ncurses/slang dependent stuff :)
+
+ * configure: Fixed bugs
+
+ * xvmain.c: Modal dialog boxes. Should be done for file.c's dialog
+ (it is not run by xvrundlg_event) one day :)
+
+Fri Jun 9 22:24:23 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * screen.c (format_file): Split repaint_file, now format_file
+ fills a buffer and then this buffer is passed by repaint_file to
+ the display engine. This should be usefull for the X version of
+ the code, since we don't need to duplicated the repainting code.
+
+Fri Jun 9 20:51:22 1995 Sinolitis Vadim <vvs@nsrd.npi.msu.su>
+
+ * widget.c (radio_callback): Now the focus color tracks the
+ cursor.
+
+Thu Jun 8 22:02:38 1995 Miguel de Icaza <miguel@luthien.nuclecu.unam.mx>
+
+ * wtools.c (query_dialog): this one also uses now the label
+ instead of the draw callback.
+
+Thu Jun 8 13:54:19 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * setup.c (save_panel_types): Save setup bug fix, now it only
+ saves the listing status if it is a listing, this should get rid
+ of the random user formats appearing.
+
+ * key.c (get_event): M-enter works on slang.
+
+Mon Jun 5 13:22:52 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * layout.c (change_screen_size): Resizing is working again.
+
+Sat Jun 3 15:51:15 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * dlg.c (init_widget): Data is cleared on init_widget.
+
+ * mcfs.c (mcfs_readdir): Now it allocates the cached directory
+ list in the proper order, also frees the catched directory
+ contents.
+
+ * key.c: Disposal of the sequences and the channel lists.
+
+ * Changed printw calls for addstr where possible.
+
+Sat Jun 3 11:44:30 1995 "Sinolits Vadim V." <vvs@nsrd.npi.msu.su>
+
+ * tkmain.c (xtoolkit_init): Call the proper Tcl/Tk setup routines
+
+Fri Jun 2 18:04:31 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * subshell.c (read_subshell_prompt): prompt_pos is reset upon
+ seeing a newline or after calling feed_subshell instead of being
+ reset each time here. This fixes the bug of truncated prompts.
+
+Fri Jun 2 16:20:00 1995 John Davis <davis@space.mit.edu
+
+ * sldisply.c (COLOR_EQS): Compare b&w attributes when running
+ without color.
+
+Fri Jun 2 10:38:11 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (copy_prog_name): Added support to copy the current
+ pathname from the trees.
+
+Tue May 30 20:29:40 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * slint.c, color.c: Added Slang support for Black and white
+ terminals, thanks to John Davis for helping me with the code.
+
+ * subshell.c (read_subshell_prompt): return whenever we actually
+ read something from the inferior subshell, if that's the case, we
+ set the update_prompt flag.
+ (invoke_subshell): if we send commands to the subshell, do not
+ repaint the loaded prompt, since the subshell will repaint it.
+
+Sun May 28 11:54:02 1995 Jakub Jelinek <root@jj>
+
+ * aclocal.m4, configure.in, xview/Makefile.in: Autodetection of
+ XView, you can use configure switches --with-xview,
+ --with-xview-includes=path and --with-xview-libraries=path to
+ override if configure cannot find yours xview libs/headers.
+ There is a make goal mxc in xview/Makefile which now compiles quite
+ the same Midnight Commander, but will contain XView support later
+ on.
+
+Thu May 25 20:34:17 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * key.c: Please note that on IRIX terminals you should set the
+ .mc.ini variable irix_fn_keys to 1.
+
+ * Use new version of Slang, now is covered under the GPL.
+
+ * key.c (get_key_code): Now we have a nice routine that does the
+ conversion for us of constants, this is needed at least for the
+ slang version.
+
+Fri May 26 09:58:12 1995 Jakub Jelinek <jj@jfch.vc.cvut.cz>
+
+ * Restructuralized the system of Makefiles to be one per dir,
+ also moved to the config.h autoconf model, so that our command
+ lines do not get unbearable chunks of -D defines. Note:
+ The source for the root Makefile and autoconf sources are
+ in the config directory in order to keep the root directory
+ moreless clean :)
+
+Thu May 25 17:32:52 1995 Jakub Jelinek <jj@jfch.vc.cvut.cz>
+
+ * command.c (examine_cd, do_cd_command): Changed the behaviour
+ of our internal cd command (the one typed on the command line).
+ Now we support simple variable expansion, but without quoting,
+ i.e. all the $VAR and ${VAR} will be expanded if the variables
+ exist, otherwise it will remain $VAR or ${VAR}. Any comments??
+ The second thing is that we now in case of failure use
+ the CDPATH variable used by bash etc., which has a $PATH form
+ and specifies paths which will be added at the beginning of the
+ requested path in case it is not absolute.
+ Other possibility for the user is to run
+ eval cd 'path'
+ and he'll get all his shell behaviour he wants to.
+ NOTE: This should be documented :)
+
+Tue May 23 13:12:53 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (init_sigchld): Bug fix: install the sigchild signal
+ handler.
+
+ * vfs.c (mc_mmap): Small bug fix: store the actual place where the
+ mmap took place. Thanks again to Wim for providing a test case
+ for this bug.
+
+ * screen.c (panel_event): Marking with the mouse works again.
+
+ * mcserv.c, mcfs.c: Use the portmapper to register a system port,
+ this gets rid of the security weakness of the server.
+
+ * mcfs.c, ftpfs.c: Use the common routine get_host_and_username to
+ parse remote addresses instead of two separate routines.
+
+ * tar.c (open_tar_archive): Reset the read pointer on the
+ compressed tar file, split in three functions (tar_open): set a
+ proper value for file->fd (tar_close): do not close files that
+ have not been opened.
+
+Mon May 22 17:39:00 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * profile.c: Now we handle integers instead of shorts.
+
+ * vfs.c (mc_mmap): Added checking for invalid file handles
+
+ * widget.c (radio_event): Mouse support works again on radio
+ buttons (thanks to Jakub for pointing this bug to me).
+
+ * menu.c (menubar_event): Now dragging from a non-dropped menu bar
+ drops the menubar as it should (thanks again to Jakub).
+
+ * find.c: Now uses the vfs.
+
+ * info.c (info_hook): Do not display the info view if there is an
+ overlapping window in top of us.
+
+Sun May 21 22:36:13 1995 Jakub Jelinek (jelinek1@jfch.vc.cvut.cz)
+
+ * vfs.c, tar.c, ..., boxes.c: Added a rubbish collector for
+ non local virtual file systems. If an archive / connection
+ is not as current dir in any panel and if it has no open
+ files and it is not an envelope of an unfreed tar archive,
+ we give it a user selectable timeout (in seconds) from the
+ last operation on the archive/connection and after the
+ timeout we free it.
+
+ * tar.c, boxes.c: Added a user selectable limit for gzipped
+ tar archives. If the uncompressed size is less than this limit,
+ archive will be gunzipped into memory, if it is not, than we
+ gunzip it somewhere into /tmp. The user can also set that
+ he wants all the archives to be extracted into memory or to
+ disk (the latter one by setting the limit to 0 B).
+ Both vfs options are in the Virtual FS dialog from the Option menu.
+
+Thu May 18 11:16:45 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.c (get_byte): Now the viewer will show you the contents of
+ the zero length files by setting it's mode to growing buffers, so
+ now it's possible to see all those nice files on /proc with the
+ viewer.
+
+ * widget.c: Moved the buttonbar code from win.c
+ (input_callback): Now we actually quote everything
+
+ * ftpfs.c (parse_ls_lga): Should work with more ftp servers
+ (ftp.dec.com, ftp.nuclecu.unam.mx, prep.ai.mit.edu are working).
+
+Wed May 17 13:11:49 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * Makefile.in (mcserv): Fixed the Makefiles for old and broke make
+ programs that do not handle the $< on regular dependencies (just
+ .c.o for example).
+
+Wed May 17 23:19:03 1995 Jakub Jelinek (root@jj)
+
+ * ext.c (regex_command): Call the file command even on non-local
+ files, but if it is non-local, pipe the first 8192 bytes of the
+ file on standard input of a `file -` command.
+
+ * util.c (mc_doublepopen, mc_doublepclose): The routines for
+ piping input and output of an command from tar.c moved here and
+ made for more general use (currently this is called also from
+ regex_command).
+
+Tue May 16 12:32:00 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * view.c (view): Now we return a truth value telling if we were
+ able to show or not the file.
+
+ * ext.c (regex_command): Do not call the file command on non-local
+ files.
+
+ Now we only make a localcopy if the command is not a chdir
+ command. This allows us to still use filters for viewing files
+ while using the chdir command properly (ie: we do not chdir to
+ mc:dir//tmp/something).
+
+ * configure.in: Now autodetects the proper value for formatting
+ man pages (-mandoc or -man macros) and also detect the arguments
+ to the file command required by view.c
+
+ * tree.c (tree_do_search): Trees now have searches again.
+
+ * boxes.c (tree): We have the tree routine again working.
+
+ * layout.c (get_current_index, get_current_type, get_other_type):
+ We do not use midnight_dlg->current->widget anymore as an alias
+ for current_panel, since for instance commands executed from the
+ menu make midnight_dlg->current be the menubar and not a panel.
+ We use cpanel that is currently being set by
+ panel_event/WIDGET_FOCUS.
+
+ This fixes the compare directories command, thanks to Wim for
+ pointing out this bug.
+
+Sun May 14 14:48:07 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (tree_box): Started to code the tree box using the tree
+ widget. It's almost there.
+
+ * view.c (toggle_hex_mode): Calling get_bottom_first is a very
+ expensive operation (on a 386@16 Mhz it takes several seconds (half
+ a minute reported on another machine) to switch from hex mode to
+ ascii mode.
+
+ * tree.c (show_tree): Now the tree code uses the colors defined
+ for the dialog.
+
+ * configure.in (witf-vfs): Small bug fix, thanks to
+ fbingha@ultrix5.cs.csubak.edu
+
+Mon May 15 21:29:05 1995 Jakub Jelinek (root@jj)
+
+ * ftpfs.c, mcfs.c, tcputil.c: First trial on a ftp file system:
+ the syntax is as follows:
+ ftp://[[user]@]host[:port]/remotepath
+ e.g.:
+ ftp://sunsite.unc.edu/pub/linux (anonymous ftp)
+ ftp://miguel@roxanne.nuclecu.unam.mx/c/nc (ftp login as miguel)
+ ftp://myhost.foo.edu:4311/public (anonymous on specified port)
+ ftp://@jj.vc.cvut.cz/src (ftp login as your current
+ login name)
+ Take care, it is only ---------------pre-ALPHA version. Really not
+ ready for any use, except bug fixing.
+
+Sat May 13 19:29:03 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * tar.c (__tarfs_find_entry): On the strcmp (pent->name, p),
+ changed the break for a return pent. This should fix the bug on
+ my Linux box.
+
+Sat May 13 22:45:00 1995 Jakub Jelinek (root@jj)
+
+ * mc.edit: New configuration file (can be overridden by a
+ ~/.mc.edit) of the same format as mc.ext and mc.view. Defines
+ which editors are for which extensions or types of files.
+
+ * ext.c (exec_extension): Made possible viewing and editing
+ of files in non-local vfs's. Currently the %f parameter, if it
+ should be expanded to a non-local vfs name (like tar:...tar/name),
+ is substituted by a temporary name in /tmp, into which is the
+ non-local file copied. Then, as soon as you finish with
+ viewing/editing/extension dependent command, we look if the file
+ /tmp/something was changed. If it is so, we update it by copying
+ back - note: tarfs is read only at the moment.
+ Also note that only %f parameter is handled in this way.
+
+ * Fixed a readlink problem on the artificial .. directory in the
+ root of the tar archive.
+
+Fri May 12 19:17:02 1995 Jakub Jelinek (root@jj)
+
+ * util.c (string_perm): Fixed text mode appearance when there is no
+ x and we put there an s or t over (suid, sgid or sticky). Then the
+ letter should be uppercase.
+
+ * tar.c (make_dot_doubledot): Created an fictive .. entry in the
+ root of the tar archive so you can easily escape by pressing enter
+ on it. (Previously you had to do a cd ..).
+
+ (read_header): Fixed a problem on non-ANSI tar archives.
+
+ * tar.c (tarfs_analysis): Now correctly enters tar archives
+ by the cd tar:/path/archive.tar/ and cd tar:archive.tar/ method.
+
+ * vfs.c (mc_opendir, mc_chdir): Fixed a problem when there was
+ an tar archive (or gzipped/compressed tar) inside of the tar archive
+
+Thu May 11 18:13:20 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * configure.in: the subshell support and the vfs code are now the
+ default build options, the user should specify --without-subshell
+ and --without-vfs in case it wants to.
+
+ * boxes.c (display_bits_box), wtools.c (quick_dialog): Now we use
+ radio buttons to display the display bits. Implemented the
+ quick_radio routine to achieve this.
+
+ * screen.c (next_page_key), cmd.c (view_cmd): They both check for
+ links to directories now to perform a chdir.
+
+ * slint.c: Removed dependency on the local slang patch
+
+ * main.c, user.c: Misc checks, we do not use opanel without
+ checking for it's type first.
+
+ * user.c (test_condition): Fixed another bug reported by Wim
+ Osterholt: We check for the validity of the other panel type.
+
+ * layout.c (set_display_type): Fix: if the panel has been resized
+ artificially and we are switching to a panel type that does not
+ make use of the long panel size, reduce the panel size, thanks to
+ Wim Osterholt for pointing this bug.
+
+Thu May 11 22:31:10 1995 Jakub Jelinek (root@jj)
+
+ * changed 0 to UP_KEEPSEL in most update_panels calls in order
+ to keep current selection in the other panel as stable as possible.
+
+ * view.c (get_byte): fixed viewing on non-local vfs's (there was a
+ read instead of an mc_read call)
+
+ * view.c (init_growing_buffer): Fixed viewing of non-piped
+ not mmaped files
+
+ * view.c (display): Assured that we have always to show something if
+ it is in the pipe
+
+Wed May 10 21:02:30 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * tcputil.c (tcp_init, rpc_send, rpc_get), mcfs.c: We now check
+ the status of the connection, the program should not block anymore
+ if the server crashes or disconnects.
+
+ mcfs.c (mcfs_get_host_and_username): Now parses correctly the user
+ name (mc:remotehost:remoteuser/utils is a correct path for example).
+
+Tue May 9 11:45:10 1995 Miguel de Icaza <miguel@nuclecu.unam.mx>
+
+ * mcserv.c (do_auth): If root, change the UID and the GID to those
+ of the user logged in. If the user logged in as anonymous or ftp,
+ do a chroot to the directory of the ftp/anonymous account.
+
+Wed May 10 22:09:12 1995 Jakub Jelinek (root@jj)
+
+ * dir.c (set_zero_dir), main.c (do_cd): Currently we can cd
+ into directories --x (we will see only ..), but we should be
+ able to get there. Also, fixed a problem when the one of the parent
+ is not readable (then Permission denied is displayed instead of the
+ directory path). Only works in vfs. But - does somebody need not to
+ use vfs? I think we should make it as default or the only
+ possibility.
+
+ * util.c (name_trunc): I know I'm not going along with the crowd
+ when using non-printable characters in directory names, but this
+ makes me happy. It doesn't scramble the screen any more :-)
+
+ * view.c, vfs.c, local.c, tar.c, mcfs.c: Added mc_mmap and mc_munmap
+ calls and converted viewing out of FILE f* calls, so that it works
+ in vfs as well. mc_mmap call is defined only in localfs, but I'll
+ extend it to tarfs soon.
+
+ * widget.c: Fixed a problem in File Find - all input lines were
+ passworded (*), the is_password was uninitialized.
+
+Mon May 8 13:29:59 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * widget.c (update_input), wtools (quick_widget, input_dialog):
+ Added support for password prompts.
+
+ * mcserv.c (do_auth): Now we try to authenticate with pwdauth if
+ available on the system, then we try the conventional validation
+ method (this only works on systems without the shadow suite) and
+ finally we try to login to a local ftp server.
+
+ * view.c (view_labels): F3 is also a quit key, very usefull for
+ browsing large amounts of information (F3 chdirs, F3, enters
+ viewer, F3 quits viewer).
+
+Sun May 7 13:31:59 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * mcserv.c (do_auth), mcfs.c (login_server): Added authentication,
+ currently it only supports authentication by connecting to a local
+ FTP server and trying to login.
+
+ * main.c (quit_cmd): Fixed the quit bug when confirm_exit was 0.
+
+Sat May 6 14:31:26 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * util.c (delete_hook): Fixed the delete_hook routine, now it
+ may delete hooks on hook variables with more than one hook.
+
+ (hook_present): Returns true if a function is on the hook list
+
+ * layout.c (set_display_type): Load the currently selected file in
+ the quick view panel, not /etc/motd
+
+ * view.c: Fixed view initialization (quick view mode had
+ problems).
+ quick view now is updated on the idle time.
+
+Thu May 4 13:37:27 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (do_execute): Console is now refreshed here, we do not
+ rely on the client function calling do_refresh.
+
+ * mcfs.c: Now functions check the return value of mcfs_get_path.
+
+ * vfs.c: mcfs and local file system do not use the trailing slash
+ any more.
+
+Tue May 2 17:48:28 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * boxes.c (display_box): Now the current_mode is set before
+ initializing the display box.
+
+Wed May 3 17:20:13 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * tar.c, vfs.c, main.c: Changes to the current directory handling,
+ paths across virtual filesystems, extensive use of vfs_canon.
+
+ * tar.c: Now uses real growing buffers - still locks on some
+ large gzipped tar.gz's :-(
+
+Tue May 2 18:05:34 1995 Radek Doulik <root@RoDo-station>
+
+ * main.c (quit_cmd): fixed bug when confirm_exit is 0
+
+ * achown.c (advanced_chown_callback): repaired cursor move
+
+ * key.c (mi_getch): bug fix in while () - enables ^X key
+ combinations for libc.5.*
+
+ * chmod.c, chown.c: new variables - shared by ch* commands,
+ needed for correct redraw (try ^L)
+
+Tue May 2 00:01:05 1995 Jakub Jelinek (jj@jj)
+
+ * tar.c, tar.h, vfs.c, vfs.h, ...: Added tar and compressed tar
+ support. Still buggy, read only, view doesn't work there...
+
+ * ext.c: Added the %cd command, which can be called to change current
+ mc's directory, like in
+ \.tar$ %cd tar:%d/%f/
+
+Fri Apr 28 18:32:15 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * dlg.c (slow_box), screen.c: Use the slow_terminal variable to
+ avoid drawing the acs chars.
+
+Thu Apr 27 17:06:56 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * screen.c, panel.h: searching and was_searching are now state
+ variables of each panel.
+
+ * view.c (get_line_at): Search optimization: gets the string only
+ one time, not two times as it used to do.
+
+ * setup.c (load_setup), screen.c (panel_destroy, panel_new): Ugly
+ hacks to let us use the profile mechanism to keep values of the
+ panels between mode switches while not being an auto-save feature.
+
+Mon Apr 24 16:17:53 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * widget.c (handle_char): Clear the quote variable after we have
+ used it.
+
+Tue Apr 25 20:31:12 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * ext.c (regex_command): We now take from the `file -L' command
+ only output after the initial filename: and whitespace, 'cause
+ I had problems with viewing files that contained gzip in its name.
+
+ * file.c: made a hardlink cache, so that we retain hardlinks
+ (if you have a hardlink to a file and that file was already copied,
+ then the new file is just a hardlink to that file it was copied).
+ Copying of special files (block, character, fifos and sockets) is
+ now possible. Copy and move now handles always with absolute
+ filenames (I think the vfs will need it absolutely) and the
+ added cwd is stripped when displaying the source. When copying
+ a symlink to a directory, it will be a symlink and not a directory.
+
+ * find.c: Fixed the problem when no files were found in the search
+ (you had to kill mc).
+
+ * menu.c: Fixed a problem with movement keys in menus when compiled
+ with the libc.so.5.x.x (ELF) on Linux.
+
+ * local.c: Fixed some obvious bugs (local_write, local_open).
+
+Wed Apr 19 10:43:37 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * vfs.c, local.c: started the vfs layer code, currently only the
+ local case is handled.
+
+ * dlg.c (dlg_try_hotkey): User Interface Change: Hotkeys are not
+ sent anymore when the focus is on an input line, this fixes a long
+ standing bug.
+
+ Support has been added to use hotkeys bounded to alt-<char> they
+ are converted to char events on the try hotkey routine.
+
+Tue Apr 18 18:26:20 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * screen.c: Panels use a private search_buffer instead of a global
+ one.
+
+ * slint.c, myslang.h: Added the slang support, currently it runs
+ only in color.
+
+ * color.c: reorganized code, now the boldness of the attributes is
+ not hard coded, there is a new set of bright colors.
+
+Wed Apr 19 00:39:10 1995 Jakub Jelinek (jelinek1@jfch.vc.cvut.cz)
+
+ * complete.c (complete_engine): Fixed a bug that caused
+ completions not to be shown at all on some places where it should
+ be applied (namely when you had a space just on the current point).
+
+ * cmd.c (view_cmd): Changed so that it uses ~/.mc.view and mc.view
+ files to determine which program should be piped for which file.
+
+ Format of the mc.view file is the same as of the mc.ext file. Both
+ were extended now: They can include white lines, comments (#......),
+ files can be matched using an exact match (when beginning with .
+ like in .tar.gz), using an regexp match or shell pattern match
+ (depends on setting shell_patterns=0/1 as the first line of the mc.*
+ file) and using an regexp match on output of the `file -L %f'
+ command (using the ?"pattern" syntax). In this case you can
+ use embedded spaces (when quoted by \). Take care with the ^
+ character in the pattern - a usual output of the file -L command
+ starts with the full pathname, followed by :, space and then
+ description of the content.
+ Included one more preprocessed command - %view, optionally followed
+ by {} with a list of view options separated by commas. Currently
+ only ascii, hex, nroff and unformatted are supported. This command
+ causes all the rest of the command (this command is replaced by
+ nothing) is run and its standard output is piped into the internal
+ viewer. If only %view command is given and nothing else, like in
+
+ ?"executable" %view{hex}
+
+ then the internal viewer is forced to load just the file %f and
+ set the viewer attributes.
+
+ * ext.c: Rewritten in order to handle changes described above.
+
+ * view.c (view, view_init, do_view_init, init_growing_buffer):
+ Changed arguments to these routines, there is no is_program any
+ more, but two strings: command and filename. If command is NULL, it
+ is like is_program=0 before. If command is not NULL, then depending
+ on the Parsed/Raw option (the F8 option was renamed so) will pipe
+ in command or display filename. In the status line on top filename
+ is always shown and not command (no more nroff -... titles on
+ the status field, just manpage.1).
+
+Fri Apr 14 14:32:25 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * main.c (setup_mc): We should not push a refresh handler anymore,
+ it's handled by the dialog manager.
+
+ * util.c (close_error_pipe): Fixed a long standing bug. Need to
+ check len for indexes that are > 0, otherwise we override the
+ stack contents. In this special case the variable that got
+ overwritten is part of the $edi register variable, this had
+ unexpected consequences. The first documented symptom was
+ detected by Erwin when quitting the view command on a runnable
+ region.
+
+Mon Apr 10 13:05:55 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * screen.c (panel_key): Fixed the problem with Alt-s adding an 's'
+ to the search.
+
+ KEY_LEFT and KEY_RIGHT events are only used if we have a need to
+ do it same done on tree.c tree_key.
+
+Sun Apr 9 20:42:12 1995 Jakub Jelinek <jj@jj.vc.cvut.cz>
+
+ * cmd.c (view_other_cmd): Subshell support should compile now.
+
+ * menu.c (menubar_paint_idx): Menu separators.
+
+ * view.c (display, move_forward2, change_nroff): Added possibility
+ to switch the nroff style formatting off (using the F9 key).
+
+ * view.c (search, regexp_view_search, do_regexp_search): Searching
+ should now work on growing buffers, regexp searches should be OK
+ as well (and search for real regexps and not for shell patterns -
+ formerly was a F6 search for a.e a search for ^a\.e (and nobody has
+ expected it)).
+
+ * command.c (do_cd_command): Fixed a problem with the cd command
+ when no space was after cd characters (just enter).
+
+Tue Apr 4 17:38:24 1995 Miguel de Icaza <miguel@athena.nuclecu.unam.mx>
+
+ * key.c (get_event): The mouse is displayed after the refresh.
+
+ * main.c (menu_cmd): F9/Shift-F9 works again.
+
+Tue Apr 4 16:50:46 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * file.c (panel_operate): Fix by Ron Sommeling <sommel@sci.kun.nl>
+ Actually use the setting of the confirm_delete variable.
+
+Sat Apr 1 19:18:52 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * menu.c: Has been converted to a widget. I have tried to
+ keep the cursor in the selection place. This should help people
+ without colors.
+
+ * main.c, cmd.c: Subshell support works again.
+
+ * layout.c: The program should work now with the
+ nice_rotating_dash option set.
+
+Mon Mar 27 13:14:25 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * dlg.c (run_dlg): Hotkey is allways sent to the current widget if
+ they have set the W_WANT_HOTKEY value. It is not sent only if
+ WIDGET_HOTKEY returns 1.
+
+Sat Mar 25 18:40:15 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * tree.c: Converted to a widget.
+
+Fri Mar 24 20:16:52 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * setup.c (load_setup): We do not expect any longer to have the
+ variables sort_* and display type.
+
+Thu Mar 23 12:37:02 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * layout.c (set_display_type): This function takes care of the
+ views displayed in the screen. It is responsible for creating and
+ destroying the left and right panels. This routine is the one to
+ be changed for the multiple panels support.
+
+ * screen.c (panel_destroy): Save the setup just before shutting down.
+ (panel_new): Load the setup at panel startup.
+
+ * setup.c (panel_save_setup, panel_load_setup): Functions to load
+ and save the setup.
+
+ * boxes.c (display_init): Do not call the input_set_point routines
+ before adding the widget to the proper place.
+
+ * configure.in (LIBS): We do not use the writable-strings anymore.
+
+Mon Mar 27 14:48:12 1995 Jakub Jelinek <jjel3210@beta.ms.mff.cuni.cz>
+
+ * util.c (icase_search): Fixed a bug in searching algorithm.
+
+ * util.c (canonicalize_pathname): This routine handled incorrectly
+ ../../* and such things (this particular was squeezed to /).
+
+ * view.c (get_byte): get_byte always returns -1 if we try to look
+ past the buffer.
+
+ * (display): Added _\b? sequence (underlined in ntroff) as red on
+ blue, added highlighting of search results - FIXME: it has to work
+ with regexps as well.
+
+ * (search): Now we can search through binary files (containing some
+ \0 stuff) as easy as in text files and we support result
+ highlighting.
+
+ * (block_search, hex_search): Fixed a bug in searching algorithm.
+
+Wed Mar 22 13:45:58 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (repaint_screen): Now we call do_refresh ().
+
+ * widget.c (input_new): Do not call update_input at program
+ startup, wait for the kind WIDGET_DRAW message to arrive.
+
+ * hotlist.c, chmod.c, chown.c, boxes.c, achown.c, wtools.c,
+ option.c, layout.c: Converted them to use the new widget methods.
+
+Tue Mar 21 13:35:11 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * dlg.c (add_widget): Modify widget position relative to the
+ dialog origin.
+
+ * win.c: Implemented the WButtonBar widget. Changed the code to
+ use this widget.
+
+ * main.c (midnight_callback): DLG_UNHANDLED_KEY now takes care of
+ the hotkeys.
+
+Mon Mar 20 10:28:00 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * widget.c (input_callback): Return whenever the input char is
+ processed.
+
+ * input.c (handle_char): Now returns if the character was handled.
+
+ * widget.c (button_callback, radio_callback, check_callback,
+ input_callback, listbox_callback): Respond to the WIDGET_CURSOR
+ message.
+
+ * dlg.c (dlg_redraw): After redrawing, send a message to let the
+ widget put the cursor in a suitable place. This is needed since
+ the panel implementation forces the cursor to stay on the panel.
+
+ * cmd.c: moved most *_cmd functions from main to this file.
+
+ * panel.h (selection): Now we should specify an argument (the panel).
+
+Sun Mar 19 14:48:47 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * dlg.h: Removed unnecessary WIDGET_CHECK_HOTKEY.
+ Widget: added options to the widget structure.
+
+ * command.c: New file, implements the WCommand widget. This is a
+ widget based on WInput. This widget does not accept the focus but
+ accepts the unused keys messages.
+
+ * main.c: left_panel and right_panel are now Panel *.
+ (view_cmd): We really meant do-cd, not action.
+
+ (init_panels): Use the new syntax for panel creation.
+
+Sat Mar 18 19:21:24 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (do_cd): Now it calls cd_try_to_select when the chdir was
+ successfull.
+
+ * screen.c (ITEMS, select_item, unmark_files, panel_event,
+ select_cmd, unselect_cmd, move_down, move_up, move_left,
+ move_right, mark_file, move_home, move_end, next_page_key,
+ prev_page_key, goto_top_file, goto_middle_file, goto_bottom_file,
+ next_page, prev_page, start_search): Moved from main.c
+
+
+ (panel_event): Cleaned up.
+
+ renamed do_init_panel to panel_init
+ renamed init_panel to panel_set_size
+
+ * panel.h (Panel structure):
+ replaced:
+ view_type with list_type
+
+ added:
+ Widget structure to make it a widget.
+
+ removed:
+ x, y, cols, lines, xpos, ypos: these are redundant with the
+ widget element.
+ half_cols, full_cols: now we compute the values directly
+ is_status: Panel is only used as a FileListing Widget.
+
+ (prototypes): Renamed panel functions to make them more uniform.
+
+ * panel.c: Panel routines do not use a special window anymore,
+ just stdscr (this is needed for the slang port).
+
+ * dlg.c (dlg_broadcast_msg): Changed redraw order: this forces the
+ current item to be the last one drawn.
+
+Fri Mar 17 13:38:41 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * mc.1: Updated man page for completion.
+
+ * complete.c: Last big completion changes.
+ (command_completion_function): Command completion algorithms,
+ currently supports bash reserved words and builtins only (and of
+ course examining of $PATH).
+ (completion_matches): We remove duplicate possibilities.
+ (try_complete): Changed algorithm where to do which completion.
+ (complete): Now we use the show_all_if_ambiguous variable to find
+ out if we should popup possibilities for the first or for the
+ second time M-Tab is pressed.
+
+ * main.c (change_panel, do_cd): On these events we dismiss all the
+ collected possibilities like we do if the user types any character
+ on the input line.
+ (do_nc): We allow command completion on the command line (of course
+ ;-)).
+
+Wed Mar 15 20:48:13 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * panel.h: the selection variable now is a macro that returns the
+ current value of the selection instead of relying in a possibly
+ inaccurate value (I already have seen this).
+
+ * option.c: Fixed hotkeys.
+ (init_configure): Fixed indexes.
+
+ * mem.h (bcopy): Fixed horrible bug, should not use macros that
+ much.
+
+ * main.c (view_cmd): Added quick hack to load man pages through
+ the nroff program using the new growing buffers routines.
+
+ * view.c (get_byte): Rewrote routine to use growing buffers.
+ (init_growing_view): New function to open the view stream.
+ (load_view_file): cleaned up error handling return values.
+ (free_file): free the growing buffer memory blocks.
+
+ * main.c (prev_page, next_page, prev_page_key, next_page_key): The
+ PgUp, PgDn key + Control works by doing a chdir up or down, while
+ the C-v and Alt-v keys moves by pages.
+
+Tue Mar 14 14:22:48 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * view.c (view_status): Should not break even if s.st_size is 0.
+ (view_init, do_view_init): now we can specify that the input comes
+ from a program.
+
+Mon Mar 20 11:36:10 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * main.c (select_item), screen.c: Some more orphans in the panels
+ removed.
+
+ * widget.c (label_callback): Mc displays correctly multi-lines
+ labels (it didn't before).
+
+ * wtools.c (input_dialog): Fixed the width problem in dialogs wider
+ than 64...
+
+Mon Mar 13 13:15:59 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * complete.c: Next step (probably one more is needed to get it
+ somehow working with all the expected features, but not bug free).
+ Now it does hostname completion, if the current word beginns with
+ a @, username if ~, variable if $ and filename as before. It doesn't
+ do command completion, checking of where to apply which completion
+ is not in the state it should be and also you cannot choose whether
+ the auto_query_if_ambiguous (in this version is the default bash's
+ behaviour, so we first beep and for the second time show the
+ possibilities. completion now shows a / after completing a directory
+ or username.
+
+Thu Mar 9 21:25:43 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * colors.c (init_colors): provide dialog_colors with proper
+ values.
+
+ * dlg.c (create_dlg): New dialog creation function. It allocates
+ the window instead of letting the caller do the window allocation.
+
+ * file.c wtools.c, boxes.c, chown.c, achown.c, option.c:
+
+ Switch to create_dlg instead of dlg_new.
+
+ Do not use the window directly, use the window member of the
+ Dlg_head structure.
+
+ Use the coloring scheme dialog_colors instead of it's own copy per
+ module.
+
+Fri Mar 10 08:21:16 1995 Jakub Jelinek (jelinek1@jfch)
+
+ * view.c (display, move_forward2, move_backward2): Changed so it
+ now correctly handles such things as the bold sequence split accross
+ the lines in wrap_mode and so on. Cause even move_forward2 became
+ very complex, I've changed in wrap_mode calls to move_backward2 to
+ move_forward2 (after finding the previous \n), so there is only
+ one place we have to change in the future when we want to change
+ something in the scrolling :-)
+
+Wed Mar 8 18:26:25 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * widget.c (listbox_add_item): Added duplicates handling.
+
+ * wtools.c (new_chooser, run_chooser, destroy_chooser): Functions
+ to write quick routines for selecting entries (possibly letting the
+ user remove them).
+
+ * widget.c (listbox_select_last): New function to remove the
+ currently selected item.
+
+Wed Mar 8 11:12:19 1995 Janne Kukonlehto (jtklehto@indy4)
+
+ * ../doc/FILES: Rewritten to conform new directory structure.
+
+ * global.h: Replaced `#if defined(ultrix)...' with `#ifndef
+ HAVE_STRDUP'.
+
+ * help.c (show), help.h: Supports bold characters now.
+
+ * layout.c (make_box): A new function which outputs a box of
+ requested size at requested location. (move_resize_panel): A new
+ function to move and resize the current directory panel.
+
+ * layout.h: Added move_resize_panel.
+
+ * main.c (only_refresh_screen, only_touchwin, untouch_bar,
+ repaint_screen): Replaced wrefresh with wnoutrefresh/doupdate pair
+ in order to reduce blinking. Reordered update sequence to be more
+ compatible with moved and resized panels. Other small changes.
+ (outrefresh_screen): A new function which marks all the standard
+ windows for update but doesn't update them yet. Used by
+ move_resize_panel. Useful to reduce blinking. (OptMenu): Added
+ `Move/resize panel'. (handle_args): Fixed a small bug which
+ prevented `-U' option from working.
+
+ * main.h: Added outrefresh_screen.
+
+ * man2hlp.c (handle_command): Checks that heading levels are even.
+ Outputs bold_on/bold_off commands in the HLP mode, too.
+
+ * panel.h: Added the coordinates of the top left corner. Required
+ by move_resize_panel.
+
+ * screen.c (init_panel): Sets the coordinates of the top left
+ corner.
+
+ * util.c (is_printable): I think DEL character is never printable.
+
+ * view.c (display): Now show sequences like
+ character-backspace-character as boldface (like less does).
+ (move_forward2): Handles correctly character-backspace-character
+ sequences. FIXME: I could not figure out how to change
+ move_backward2 to handle char-bspace-char sequences correctly.
+
+Tue Mar 7 22:12:13 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * widget.c (listbox_key): No more orphans in listboxes when
+ pressing End.
+
+ * widget.c (listbox_get_current): It didn't work with the
+ second parameter NULL (if we didn't want to get extra data).
+
+ * setup.c, option.c, main.c (*cd_symlinks): Added flag to enable
+ /disable following of logical directory structure made of symlinks
+ (which I have added 3 days ago). Rearranged key assignment in the
+ Configuration dialog, so that all keys work for the check boxes
+ where they are capitalized.
+
+ * input.c (is_in_input_map): Test function for the complete engine.
+
+ * complete.c: Now it shows a listbox of all possible completions
+ if there are more then one, you can type characters when this
+ listbox is displayed and mc will try to complete as much as it can.
+ You may select an entry and press Enter to insert it into the
+ input line or you can press M-Tab again if you've typed some
+ characters and want to see fewer possibilities. Still lacks
+ other completions than filename.
+
+ * boxes.c: Cosmetic changes to the Display mode dialog.
+
+Fri Mar 3 19:25:12 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * boxes.c (select_format, display_callback): Added a list for the
+ user formats while pressing C-c.
+
+ * man2hlp.c (handle_command): Small change to remove the spaces
+ before the section name.
+
+Mon Mar 6 08:38:12 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * new files: complete.c, complete.h - First steps for the
+ filename/command/username/variable/hostname completion in
+ the input lines. At the moment only filename completion is
+ supported.
+
+ * input.[ch]: Incorporation of complete.[ch] into the project,
+ complete function is assigned to the M-Tab keystroke.
+
+Sat Mar 4 21:19:32 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * main.c (do_cd): cd should follow symlinks up to the location
+ where you've entered them and not to the .. directory of the
+ real directory symlinks are pointing to.
+
+ * util.c (canonicalize_pathname): This routine makes previous
+ change possible and despite of that can be usefull elsewhere
+ as well.
+
+Tue Feb 28 09:39:20 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * boxes.c (display_bits_box): Added the nice dialog box for
+ choosing the number of display bits.
+
+ * util.c (is_printable): Added the full 8 bit support as well as
+ iso-8859-1.
+
+ * main.c (next_page): Now also handles C-PgDn, this chdirs into
+ the current directory.
+
+ * boxes.c (quick_dialog): New routine to write simple dialog boxes
+ with confirmation boxes, no more, no less.
+
+ * util.c (ctrl_pressed): Thanks to Alessandro Rubini for providing
+ this code.
+
+ * main.c (do_cd_command): We can't write past the buffer (cmd [3]
+ if cmd [2] is 0).
+
+ (quit_cmd): Added check for confirmation before exiting.
+
+ * configure.in, util.c: The proper thing to do is to check
+ for strdup here and not for ultrix.
+
+ * main.c (view_other_cmd): Changed call to mi_getch for xgetch,
+ since now we have a do_update call in mi_getch.
+
+Wed Mar 1 20:03:17 1995 root <root@RoDo-station>
+
+ * achown.c: space now does nothing (in future maybe toggle),
+ after '+', '-', '=' cursor moves to the next flag (owner)
+
+Thu Feb 23 07:37:56 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * chmod.c, dir.c (stat_file, handle_dirent): Changed
+ all file type tests to the S_IS* macros, because usage of the
+ (x & S_IF*) == S_IF* caused misbehaviour, e.g. the block
+ devices and sockets on linux were handled as directories and
+ therefore sorting in the /dev directory looked a little bit
+ strange.
+
+ * input.c (input_set_prompt): Added a call to update_input,
+ because otherwise when we changed from a longer to a shorter
+ prompt, the rest of the old prompt remained on the screen.
+
+ * input.c: Added KEY_HOME, KEY_A1, KEY_END and KEY_C1 as
+ moving to the beginning / end of the input line. It doesn't
+ do anything on the cmdline, because then we handle these
+ special keys before, but of other input lines.
+
+ * layout.c (init_layout, update_split, layout_callback):
+ We have to initialize our internal _* variables and not
+ to wait until someone presses a key / clicks mouse bottom,
+ because then the first press / click has sometimes no
+ result. Also I've changed Miguel's recent addition of
+ redrawing numbers only if they changed, so that it works
+ fine when you press C-l or check/uncheck Equal checkbox.
+
+ * main.c (untouch_bar): Fixed so menu repaints fine even
+ when having menubar_visible set.
+
+ * main.c (init_labels): Having keybar_visible == 0 doesn't
+ cause an segfault any more.
+
+ * view.c (view_init, view): Setting dirty to max_dirt_limit + 1
+ moved to the view_init function and should work fine (mc
+ really always displays the view_win on start).
+
+ * view.c (move_backward2, move_forward2): Rewritten so it
+ should work well even when wrapping (e.g. before, when you were
+ moving up in wrap mode, it moved sometimes several lines up,
+ moving to the end didn't sometimes reach 100% etc.).
+
+ * view.c (get_bottom_first): Added a new check so that the
+ view's shown page always shows as many lines as possible
+ (no more last one line on the screen if there are many in the
+
+Thu Feb 23 12:17:39 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * file.c: Oops, I forgot to include <utime.h>.
+
+ * find.c (find_parameters): The previous parameters are now
+ remembered. (insert_file, do_search, find_callback, start_stop,
+ find_file): Cosmetic changes. (do_search): Shows the name of
+ directory being scanned.
+
+ * main.c (compare_files): A new function to compare two files,
+ used by thorough compare. (compare_dir, compare_dirs): Now there
+ two compare methods: quick compare (the old method) and thorough
+ compare (byte-by-byte compare).
+
+ * mc.1 (Command Menu): Documented the two compare methods.
+
+ * util.c (get_full_name): Now able to handle directory names which
+ end to '/' (required by find file feature).
+
+Thu Feb 5 13:12:20 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * main.c (move_down,prev_page,next_page): Code changed so that
+ PageDn,Up work well and do not show only some entries if there is
+ a lot of them.
+
+Wed Feb 22 16:18:08 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * FILES: A new file to list the purpose of files included in the
+ distribution. I hope wanna-be MC hackers will find it useful.
+
+ * Makefile.in (DISTFILES): Added the FILES file.
+
+ * file.c (copy_file_file): Code clean-up. Now preserves time
+ stamps.
+
+ * find.c (do_search): Optimized, now about ten times faster than
+ before and only two times slower than GNU find.
+
+ * panel.h, find.c, main.c, screen.c: In the Panel structure the
+ dont_reload field is renamed to is_panelized.
+
+ * main.c (reload_panelized): A new function to update contents of
+ panelized view. (update_panels): Now calls the new
+ reload_panelized function for panelized panels instead of skipping
+ update. (enter): Now removes any initial and trailing whitespace
+ in directory names of the cd command.
+
+ * menu.c (run_menu): because F10 is a abort key nowadays there is
+ no need to check for it again.
+
+Tue Feb 21 17:18:09 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (handle_args), configure.in: Now you can specify if you
+ want the subshell by default.
+
+Tue Feb 21 12:51:24 1995 Sinolits Vadim V. <vvs@nsrd.npi.msu.su>
+
+ * file.c (copy_file_file): Avoid copying a file to itself.
+
+Tue Feb 21 12:39:06 1995 Janne Kukonlehto (jtklehto@indy6)
+
+ * find.c (find_file): Draw the nice dash when panelizing
+
+Sat Feb 18 14:09:12 1995 Janne Kukonlehto (jtklehto@indy6)
+
+ * subshell.c (read_subshell_prompt): You can't use a label without
+ a statement. (pty_open_slave): Irix doesn't support ioctl
+ (pty_slave, I_PUSH, "ttcompat").
+
+ * user.c (expand_format): Removed an extra ';'.
+
+Fri Feb 17 13:56:45 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (change_view): Call view_done if we are switching away
+ from a quick view mode.
+
+Thu Feb 16 10:07:12 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * dialog.c (input_event, input_dialog): Added mouse support
+ for the input dialogs' edit lines, so the cursor will move
+ to the place you press mouse on. Also added F10 key as the
+ abort key.
+
+ * dlg.c (dialog_handle_key): Added C-c and C-g as abort
+ keys for the dialog (so it behaves exactly same as the input
+ dialog).
+
+ * main.c (edit_cmd): Fixed a bug that caused improper screen
+ redrawing if you when searching in the panel pressed F4.
+
+ * widget.c (input_event, listbox_select_pos, listbox_event):
+ Added full mouse functionality for the input line and listbox
+ widgets.
+
+ * wtools.c (create_listbox_window): Changed colors of user menu
+ and history command dialogs, so they're compatible with other
+ dialogs in their look and feel (I found the previous colors
+ extremely ugly).
+
+Fri Feb 17 13:04:44 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * layout.c (update_split): We don't update the split information
+ if it has not changed.
+
+Thu Feb 16 11:07:04 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c: We don't support advanced chmod/chown for 2.0.
+ (view_other_cmd): Added a repaint screen.
+
+Thu Feb 16 16:12:04 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * gindex.pl: A small typographical change in the index output.
+
+ * user.c (expand_format): Removed a compilation warning.
+
+Thu Feb 16 19:56:12 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * widget.c (button_event, radio_callback, radio_event, check_event,
+ listbox_event): Last trial to make layout dialog box work with
+ mouse. Whenever we send in these events any key to the widgets,
+ we have to send then a DLG_POST_KEY message to the dialog, what
+ is normally done when a real key is pressed.
+
+ * layout.c (b2_left_cback, b2_right_cback): Removed ugly hack
+ to update something what is not needed now cause we do it
+ already in the *_event - see the above change.
+
+Wed Feb 15 22:13:21 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * layout.c (setup_event): Do not modify the events. Just push
+ them. Since we have fixed the layout problem, this code is not
+ needed anymore.
+
+ * main.c (do_nc): Do not accept character -1.
+
+ * input.c (insert_char): Do not accept character -1.
+
+ * cons.saver.c (restore_console, save_console, detect_console):
+ Changes to work with Linux >= 1.1.91. Now they use /dev/vcsaN for
+ accessing the memory associated with the virtual console N.
+
+Wed Feb 15 00:46:33 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (do_execute): Fixed the pause_after_run so the console
+ contents still get saved even if pause_after_run == pause_never.
+
+ * main.h: Removed the after_run_actions enum; it is not used in
+ any .c files other than main.c, and besides it is inconsistent
+ with the enum given in main.c itself...
+
+ * main.c, main.h (toggle_pause_after_run): Removed as obsolete.
+
+ * terms.c (do_exit_ca_mode): New function; the counterpart of
+ do_enter_ca_mode(). Called in main.c.
+
+ * main.c (view_other_cmd): Now calls do_exit_ca_mode(), and it
+ isn't disabled any more just because OTHER_CURSES is defined.
+
+ [Begin Not included]
+ * subshell.c (pty_open_master, SVR4 version): Temporarily ignore
+ SIGCHLD while calling grantpt() (which forks a pt_chmod process.)
+
+ * main.c (main): Now we always install the SIGCHLD handler here,
+ regardless of whether use_subshell is set or not.
+
+ * subshell.c (init_subshell): No need to mess around with SIGUSR1
+ any more; we never install the SIGCHLD handler here now.
+ [End Not included]
+
+ * util.c (my_system): Don't die horribly if the sigaction() calls
+ to ignore SIGINT and SIGQUIT fail; run the command anyway.
+
+ * cons.handler.c (handle_console): Close old pipe ends during
+ CONSOLE_INIT, in case it is the second time we run cons.saver.
+
+ * cons.saver.c (send_contents): Removed the `lastline' variable
+ and all references to it.
+
+Tue Feb 14 18:16:20 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * chown.c, achown.c (init_chown, init_chown_advanced): Fixed
+ a bug that caused mouse events to be shifted down, so you
+ had to click 2 resp. 5 lines above the widget. winpos and the value
+ of the newwin must be kept in sync.
+
+Wed Feb 15 18:39:01 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * file.c (panel_operate): Also a single tagged file should be left
+ tagged if the operation failed.
+
+ * gindex.pl: Now can handle hierarchical headings.
+
+ * man2hlp.c: Better backslash quoting handling. Now can handle
+ hierarchial headings. Fixed a problem with HTML links. Now can
+ handle \& command in the beginning of line.
+
+ * mc.1: Switched to hierarchial headings. Some reorganization.
+ Documented the find file feature, the layout dialog and the file
+ operations dialog.
+
+ * menu.c (run_menu): The F10 key works again.
+
+ * xnc.hlp (QueryBox): Small change in the wording.
+
+Tue Feb 14 19:13:41 1995 Miguel de Icaza <miguel@sphinx>
+
+ * Interesting: is_idle returns 0 if we used the mouse on an xterm.
+ Because the mouse up has not been handled yet. We should take
+ this into account for the future.
+
+ * view.c (view): Force refresh by setting an initial value to
+ dirty of max_dirt_limit + 1.
+
+ * mouse.c (click): Now click returns a MOU_ENDLOOP: this gives the
+ view command a chance to refresh the screen.
+
+ * main.c (menu_bar_event): When executing code from the menus, end
+ the mouse loop.
+ (do_nc): Added a wrefresh before the mi_getch call. This puts the
+ cursor in the correct position.
+ (restore_console): Restore the console properly: if using the
+ subshell support, add the prompt we have loaded, since it may not
+ have been printed before we got the snapshot of the screen.
+
+ * layout.c (layout_cmd): Instead of changing the layout on the
+ fly, let the main loop take this decision: this solves the problem
+ of the unpaired frames.
+
+ * main.c (init_labels): Misc changes to make the layout changing
+ code to work (add test to check if fkeys is set before
+ refreshing).
+
+Mon Feb 13 00:59:04 1995 Miguel de Icaza <miguel@sphinx>
+
+ * file.c (panel_operate): Now we return 0 if the panel_operate
+ did not modify the fs, and 1 otherwise.
+
+ * main.c (delete_cmd, copy_cmd, ren_cmd): update and repaint the
+ screen only if panel_operate did something interesting on the disk.
+
+Mon Feb 13 22:54:12 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * dir.c (sort_*): Changed reverse sorting so if the mix_all_files
+ options is not set, directories come always before other files.
+
+Tue Feb 14 02:47:59 1995 Janne Kukonlehto <jtkl@jysky.oulu.fi>
+
+ * dialog.h, wtools.c (query_dialog): Added a new flag
+ WITH_HOTKEYS. Now it is possible to use hotkeys other than the
+ first letters of the possible choices.
+
+ * file.c: Added a new function query_recursive which asks
+ confirmations for the recursive deletes. A part of its code
+ originates from recursive_erase. (mask_rename): Got rid of a
+ warning. (panel_operate): Code clean-up. Skipped files are no
+ longer untagged. (show_bar): Should not overflow anymore.
+
+ * layout.c (b2left_cback, b2right_cback, init_layout): An attempt
+ to adjust panel widths now toggles the equal split off
+ automatically. (remove_dash): Operates correctly even if menubar
+ is visible.
+
+ * man2hlp.c (handle_command): Typographic fix in the html index
+ output.
+
+ * screen.c (repaint_file): If the panel is split to two columns no
+ longer colours the division bar when tagging files or drawing the
+ selection bar. (display_mini_info): Handles singular and plural
+ form of the `file' word correctly when outputting number of tagged
+ files.
+
+ * util.c (regexp_match): Optimized: compiles the pattern only if
+ it has changed since the last time.
+
+ * wtools.h: There exists no query_dialog_new function nowadays.
+
+Sun Feb 12 20:31:09 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_nc, main): Reordered the push_frames and panel
+ creation so that the layout stuff can remove properly all the
+ mouse events when switching modes (for disabling the key bar).
+
+ * win.c: misc changes to add an option to specify whenever we want
+ or not a fkey.
+
+ * option.c (init_configure), main.c (do_execute): Implemented the
+ 3-type of pause_after_run.
+
+ * key.c (mouse_getch): Removed pending variable; now ESC is a
+ prefix key, not a prefix and a abort key. There is a workaround:
+ you can set the old_esc_mode in the ini file.
+
+ * dialog.c, file.c, menu.c, tree.c, widget.c: C-c and C-g also
+ abort actions.
+
+ * screen.c (parse_display_format): Fixed bug that truncated the
+ user format if it had an error.
+
+Sun Feb 12 12:31:15 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * Makefile.in: Added regex.c to SRCS, regex.h to HDRS, regex.o to
+ OBJS.
+
+ * configure, configure.in: Added AC_ALLOCA check. Removed the
+ search for the correct regular expression commands. The GNU regex
+ library is used instead.
+
+ * file.c (mask_rename): Dumped the old shell pattern parser. The
+ GNU regex library is used instead.
+
+ * mc.1 (File Menu, Mask Rename): Moved the description of the mask
+ rename feature from the File Menu section to a new Mask Rename
+ section. Documented the new support for regular expressions (shell
+ patterns off).
+
+ * regex.c, regex.h: New files. Copied from the GNU regex library
+ version 0.12.
+
+ * util.c: Removed the #ifdef jungle to get the correct regular
+ expressions code. Now uses the GNU regex library instead. Moved a
+ part of the regexp function to a new convert_pattern function.
+
+ * util.h: Added convert_pattern.
+
+ * key.c (check_selects): Void function can't return value.
+ (mouse_getch): The gpm_fd variable is not defined if the libgpm is
+ not used.
+
+ * user.c (expand_format): Why ';' was removed after "/* Fall
+ through */"?
+
+ * view.c: Renamed the quit variable to view_quit to avoid problems
+ with the quit variable in the main.h.
+
+Sat Feb 11 13:31:33 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (main): Set an initial value for the prompt, since we are
+ not loading it at subshell initialization.
+
+ * key.c (check_selects, add_selects, channels_up, channels_down):
+ Add a way to activate and deactivate the select channel checking.
+
+ * configure.in (LIBS): Removed the -ltermcap
+
+Sat Feb 11 00:46:52 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * user.c (expand_format): Removed ';' after "/* Fall through */"
+
+ * auto.c (do_exec_mount): Blocked SIGCHLD during the fork/wait,
+ to avoid interference with our sigchld_handler() in main.c.
+
+Fri Feb 10 12:17:37 1995 Miguel de Icaza <miguel@sphinx>
+
+ * key.c (mouse_getch): Do not use max_fd anymore, use FD_SETSIZE.
+ (try_channels): New function to check the wait channels on the
+ work around version of getch.
+
+ * widget.c (listbox_get_current): Don't return information if the
+ listbox is empty.
+
+ * main.c (reread_cmd): Many changes to remove a bunch of warnings.
+
+ * widget.c: Added hotkey support to radio buttons.
+
+Sat Feb 11 21:56:03 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * main.c (panel_event): fixed a bug on mouse dragging in a two
+ column full sized panel, fixed proper changing of panels when
+ dragging the mouse, fixed dragging when having panels split
+ horizontally.
+
+ * main.c (panel_event): Double clicking at the border (so not
+ on any file) doesn't run the active file any more. This caused
+ some unwanted actions when moving in the panel up and down.
+
+ * main.c (paint_quick_view_panel): Blank Quick view panel cannot
+ be active and current panel is changed automatically.
+
+ * screen.c (repaint_file): When the user defined format is
+ shorter than the actual panel width, there are no black gaps
+ at the end any more.
+
+ * screen.c, panel.h (parse_display_format): When you select
+ different panel size in used defined format and in user defined
+ mini-status format, the panel size of mini-status line is adapted
+ to the panel size of the panel, so there are no black gaps any
+ more...
+
+ * screen.c (paint_frame): Removed black gaps when titles are
+ shorter and added trimming of titles if they're longer than
+ the field length.
+
+ * view.c (view_status): Modified for the cases when quick view
+ panel width is extremely short.
+
+ * view.c (view_event): Added unnecessary wrapping, 'cause panel
+ event was changed.
+
+ * mouse.c (mouse_handler, redo_mouse): Changed a hideous bug
+ that mouse was generating unexpected event coordinates when
+ auto repeating last event.
+
+Thu Feb 9 13:43:42 1995 Miguel de Icaza <miguel@sphinx>
+
+ * find.c (find_file): Remove the old directory contents before
+ panelizing the entries.
+
+ * chown.c (chown_cmd): Fixed stupid bug.
+
+ * chmod.c (chmod_cmd): Fixed stupid bug.
+
+ * file.c (panel_operate), main.c (do_mark_file, select_cmd,
+ unselect_cmd): Use strcmp
+ (,".."), not strncmp (,"..",2)
+
+Thu Feb 9 11:06:46 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * chmod.c (chmod_mcd), chown.c (chown_cmd): The
+ is_view_file_listing macro should take cpanel->view_type as
+ parameter, not plain cpanel.
+
+ * configure.in (--with-debug): Added definition of MCDEBUG (used
+ by view.c).
+
+ * file.c (copy_dir_dir, recursive_erase, erase_dir), main.c
+ (mkdir_cmd): Replaced mkdir and rmdir with my_mkdir and my_rmdir.
+
+ * find.c (find_file, do_find): Added a 'Panelize' button to put
+ found files to the current directory panel (to make possible
+ viewing, copying, deleting and so on). Press Ctrl-r to return to
+ normal file listing after panelizing.
+
+ * layout.c (destroy_panels): Oops, a pop_fkey call missing. Now
+ ncurses doesn't seg-fault anymore if the MC catches WINCH signal.
+ (change_screen_size): Added a noraw call.
+
+ * main.c (cd_try_to_select): A new function which tries to select
+ the old directory if we chdired to the parent directory.
+ (parse_control_file, action, enter, maybe_cd, tree_cmd,
+ quick_chdir, tree_leave): Now uses the cd_try_to_select function
+ instead of try_to_select.
+
+ * main.c (update_panels): Tries to avoid reloading after a
+ panelize operation. (do_nc): The pop_fkey call isn't needed here
+ anymore after I added it to destroy_panels.
+
+ * mc.1 (Directory Tree): Cleared up the explanation of the F3
+ (Forget) key. (FILES): Fixed the command to generate the .mc.tree
+ file manually. The .mc.hotlist file isn't used anymore.
+
+ * panel.h (Panel): Added a dont_reload flag to be used by panelize
+ operation.
+
+ * screen.c (do_init_panel): Now initializes the dont_reload flag.
+ (panel_reload): If the current directory of the panel doesn't
+ exist anymore, moves to the parent directory until a existing
+ directory is found. Loads zero dir only if the root directory
+ doesn't exist.
+
+ * tree.c (tree_add_entry), tree.h: The tree_add_entry function is
+ now global instead of static (used by the my_mkdir function).
+
+ * util.c (get_full_name): Now handles root directory correctly.
+ (get_absolute_name, my_mkdir, my_rmdir): New functions to replace
+ mkdir and rmdir. These versions update the tree figure when
+ directories are created or destroyed.
+
+ * util.h: Added my_mkdir and my_rmdir.
+
+ * view.c (load_byte): Tries recover from errors. Now aborts only
+ if the MCDEBUG macro is defined. (view): The keybar of the
+ internal viewer is now shown regardless of the value of the
+ keybar_visible variable.
+
+Wed Feb 8 16:41:40 1995 Miguel de Icaza <miguel@sphinx>
+
+ * dialog.c: Made refresh_list public.
+
+ * subshell.c (feed_subshell): Initialize the subshell_prompt
+ variable; don't read the prompt anymore, let this work to main.
+
+ * util.c (strip_ctrl_codes): Don't strip codes of a null pointer.
+
+ * file.c (recursive_erase): Removed extra free.
+
+ * main.c (copy_tagged): Work on the panel, *not* the current
+ panel.
+ (load_prompt): Refresh the window.
+ (main): Added the select channel function (load_prompt).
+
+ * screen.c (display_mini_info): Corrected bug just introduced
+ yesterday. The format should have a minus.
+
+ * file.c (erase_dir): In order to let the hot key work on
+ query_dialogs, the second character must be the hotkey.
+
+ * input.c (assign_text): The current_max_len is the size of the
+ string *including* the terminating 0.
+
+Thu Feb 9 15:44:20 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * main.c (panel_event): If mouse is pressed inside the quick
+ view panel, it doesn't show garbage any more - instead mouse
+ is there fully functional.
+
+ * view.c (view_event, real_view_event): Full mouse support
+ in both real view and quick view causes movement in all
+ directions.
+
+Wed Feb 8 16:40:04 1995 Jakub Jelinek <jelinek1@jfch.vc.cvut.cz>
+
+ * menu.c (quit_all_event): Releasing mouse button outside of
+ the menu causes the menu to hide - acts like expected from the
+ pull down menu.
+
+
+Wed Feb 8 10:27:14 1995 Thomas Pundt <pundtt@math.uni-muenster.de>
+
+ * view.c (half_up): Added view_update: this fixes a problem with
+ some versions of ncurses.
+
+Tue Feb 7 16:20:33 1995 Miguel de Icaza <miguel@sphinx>
+
+ * subshell.c (read_subshell_prompt): Moved the code from
+ feed_subshell here: code cleanup and reuse.
+
+ made public the subshell_pty variable to let the main program use
+ hooks.
+
+ * main.c: Disable advanced chown for release 2.0.
+ (change_view): Call switch_to_info instead of info_cmd.
+
+ * find.c (find_parameters): Starting directory is current dir, as
+ Dugan suggested in the list.
+
+ * chmod.c (chmod_cmd): Shouldn't operate in modes different than a
+ file listing.
+
+ * chown.c (chown_cmd): Shouldn't operate in modes different than a
+ file listing.
+
+ * key.c (delete_select_channel, add_select_channel, check_selects,
+ add_selects): New function to add select channels to the program.
+
+ * file.c (panel_operate): Fixed bug: the confirmation prompt
+ should be computed for marked files > 1.
+
+Wed Feb 8 02:23:52 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * dir.c (do_reload_dir): New variable `tmp_len' used for an
+ optimization of the directory-rescanning code, which is now
+ about 30% faster :-)
+
+ * subshell.c: Made zsh work properly as a subshell of MC, and
+ fixed up the subshell-type handling generally.
+
+Mon Feb 6 17:49:36 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * boxes.c (displays): The button names are now easier to
+ understand.
+
+ * dir.c (do_load_dir, do_reload_dir), file.c (create_op_win,
+ destroy_op_win), util.h, win.c: The create_dash and destroy_dash
+ functions have been deleted.
+
+ * layout.c (_check_split, layout_callback): Fixed two silly bugs
+ in panel size limit checking. (create_panels, destroy_panels): The
+ window for the rotating dash is created and destroyed here now.
+
+ * win.c, layout.c, util.h: The rotate_dash function has been moved
+ from the win.c file to the layout.c file. A new remove_dash
+ function to remove dash when not needed anymore.
+
+ * main.c (update_panels): Ctrl-r works in the tree view again.
+
+ * main.c (change_panel): Can't change to quick view panel if the
+ current file is a directory. (enter): Doesn't execute the command
+ on the command line if there isn't a command line. Fixed the macro
+ expansion bug (I hope). (view_cmd): Repaint the quick view panel
+ after exiting from the real view. (copy_current_pathname,
+ copy_other_pathname, copy_prog_name, copy_other_prog_name,
+ copy_tagged): Don't put stuff on the command line if there is no
+ command line. (do_nc): Remove the rotating dash on the each
+ iteration of the main input loop.
+
+ * mc.1 (Macro Substitution), user.c (expand_format): Implemented
+ the %s macro.
+
+Sun Feb 5 15:12:45 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (menu_mouse_cmd, menu_cmd, menu_last_selected_cmd,
+ menu_display_cmd): Changes to allow the user to open the menu
+ place where he clicked the mouse.
+
+ * util.c (my_statfs): Changes to let the code compile even if we
+ don't have mount information.
+
+ * main.c (do_link): Changed the order for symlinking
+
+Fri Feb 3 16:26:39 1995 Miguel de Icaza <miguel@sphinx>
+
+ * view.c (do_view_init): Removed hex_mode initialization.
+
+ * win.c (create_dash): We don't want to keep the cursor in the
+ corner.
+
+ * view.c (toggle_wrap_mode): If we toggle the wrap mode, we have
+ to set the starting column to 0.
+
+ * dir.c (do_reload_dir, do_load_dir): Do not rotate that often.
+
+ * file.c (check_buttons): Use again xgetch instead of mouse_getch.
+
+ * configure.in (LIBS): Fixed the problem of the configure
+ program.
+
+
+Fri Feb 3 17:09:04 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * configure: A temporary fix to get it work. Someone should take a
+ closer look at this and fix it from the configure.in, too.
+
+ * cons.saver.c: Replaced an ugly hack with a less ugly hack.
+
+ * dir.c (do_load_dir, do_reload_dir), file.c (check_buttons,
+ create_op_win, destroy_op_win): Uses new rotating dash feature.
+
+ * file.c (do_file_error, query_replace): The file operation main
+ window is no longer refreshed if the user selected abort.
+ (copy_dir_dir, recursive_erase): The abort feature should work
+ better now.
+
+ * key.c (mouse_getch): Now works without libgpm again.
+
+ * main.h: The quit variable is volatile nowadays.
+
+ * win.c, util.h (create_dash, destroy_dash, rotate_dash): New
+ functions to show rotating dash during long operations.
+
+Thu Feb 2 15:18:10 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c: const-ified the status_using_* variables, to help with
+ compile-time optimisation. Not that these variables are exactly
+ "heavily used" or anything... ;-)
+
+ (main): Moved the "handle_console (CONSOLE_INIT)" call before
+ the init_sigchld(), so the waitpid()s in cons.handler.c don't
+ interfere with our SIGCHLD handler.
+
+ (view_other_cmd): Made it switch to the subshell (if enabled)
+ regardless of whether screen dumps are possible or not.
+
+Fri Feb 3 17:09:04 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * configure: A temporary fix to get it work. Someone should take a
+ closer look at this and fix it from the configure.in, too.
+
+ * cons.saver.c: Replaced an ugly hack with a less ugly hack.
+
+ * dir.c (do_load_dir, do_reload_dir), file.c (check_buttons,
+ create_op_win, destroy_op_win): Uses new rotating dash feature.
+
+ * file.c (do_file_error, query_replace): The file operation main
+ window is no longer refreshed if the user selected abort.
+ (copy_dir_dir, recursive_erase): The abort feature should work
+ better now.
+
+ * key.c (mouse_getch): Now works without libgpm again.
+
+ * main.h: The quit variable is volatile nowadays.
+
+ * win.c, util.h (create_dash, destroy_dash, rotate_dash): New
+ functions to show rotating dash during long operations.
+
+Thu Feb 2 13:33:40 1995 Miguel de Icaza <miguel@sphinx>
+
+ * key.c (mi_getch): Cleanup. If we don't HAVE_LIBGPM, set
+ gpm_flag to 0 in a define.
+
+ * help.c (show): Since now we are not using a derived window, we
+ have to check when we go out of place.
+
+Tue Jan 31 16:30:23 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * file.c (erase_dir): Check for FILE_ABORT.
+
+ * main.c (enter): Fixed the command line problem.
+
+Fri Feb 3 19:01:48 1995 Midnight commander developing <rodo@earn>
+
+ * achown.c: reworked, not working yet
+
+Fri Feb 3 10:48:43 1995 Midnight commander developing <rodo@earn>
+
+ * chown.c: cosmetic changes - now it doesn't waste so much
+ space :-)
+
+Wed Feb 1 17:33:16 1995 Miguel de Icaza <miguel@sphinx>
+
+ * dlg.c (dlg_new): Changed: relative to frame set to 0, maybe this
+ should be a parameter to dlg_new, we want a child window or not.
+ This actually fixes the mouse disabled problem on the new file
+ command windows.
+
+ * subshell.c: Added use_subshell = 0 when no subshell support is
+ present and removed it from subshell.h. This is needed. We
+ can't use a const in a header file.
+
+ * main.c (reread_cmd, update_panels): Update only the current
+ panel (new flag: UP_ONLY_CURRENT).
+
+ * layout.c (layout_callback): Fixed the bug I introduced
+ previously on displaying the _output_lines variable.
+
+ * main.c (done_panels): Free user_mini_status in both panels.
+
+ * dir.c (alloc_dir_copy): Set initial values to dir_copy.list so
+ that we only free those values that were actually allocated.
+ Also, now we free those values that were allocated.
+
+Wed Feb 1 22:03:41 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c: Implemented the QUIETLY/VISIBLY argument to
+ invoke_subshell. Made yet another fix for System V (synchronizing
+ with the child process once the latter has opened the slave pty
+ successfully). Removed all old references to mc_ctty. Changed
+ pty_open_slave to be more specific about problems encountered.
+ Plus a few minor fixes and cleanups.
+
+ * screen.c (string_file_type): Added (provisional) type codes for
+ named pipes and block and character special files.
+
+ * cons.saver.h, cons.saver.c, cons.handler.c: Changes so that
+ show_console_contents can return a range of lines anywhere on the
+ screen, not just at the bottom. This is used by the subshell
+ support, and will hopefully be useful later in other ways.
+
+ * main.c: Made `quit' volatile because it can be changed by the
+ SIGCHLD handler in subshell.c. Call show_console_contents and
+ invoke_subshell with the new arguments. Trivial fixes.
+
+ * layout.c (create_panels): Call show_console_contents with the
+ new arguments.
+
+Sun Jan 29 03:01:31 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (init_subshell): Removed the MCBASH variable feature
+ as pointless; we always want to run with the usual bash now.
+
+Wed Feb 1 16:30:17 1995 Miguel de Icaza <miguel@sphinx>
+
+ * file.c (panel_operate): Free `temp' variable if it has been
+ used.
+ (mask_rename): Added missing return types (return FILE_ABORT on
+ the first two returns).
+
+Wed Feb 1 02:01:45 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c: Use the screen size calculated by ncurses rather
+ than trying to calculate it again. Also, removed a duplicated
+ "#include <sys/ioctl.h>".
+
+ * main.c (main): Moved the call to init_curses after the one to
+ init_subshell. (init_subshell needs the terminal to be in its
+ original mode, and init_curses puts it in raw mode.) But we still
+ need `initscr' to be called before init_subshell, so I removed
+ initscr from init_curses and call it just before init_subshell.
+ Extremely ugly, I know; sorry. Do it better if you like...
+
+ * layout.c (init_curses): Removed the initscr() call (see above).
+
+ (change_screen_size): Call initscr() just before init_curses().
+ Call resize_subshell() (see below).
+
+ * subshell.c (resize_subshell): New function which resizes the
+ subshell's pseudo-tty according to the values of the ncurses
+ variables LINES and COLS.
+
+Tue Jan 31 16:30:23 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * Makefile.in, file.c, newfile.c: The old `file.c' file removed and
+ the new `newfile.c' file renamed to `file.c'.
+
+ * TODO, mc.1: Fixed my email address.
+
+ * file.c (previously known as newfile.c): A lot of changes and
+ fixes in all the functions.
+
+ * file.h: Added two enumerations, create_op_win, destroy_op_win,
+ refresh_op_win, mask_rename and panel_operate. Removed
+ copy_file_dir, erase_file, recursive_erase, move_file,
+ move_file_dir and new_file_ops.
+
+ * main.c (enter): The command line supports the user menu macros
+ now. This makes possible to execute the same command line to
+ multiple sets of files (by tagging the files and getting the line
+ from the history with M-p and M-n).
+
+ * main.c (unmark_file): Now works in the tree view mode.
+ (ok_to_copy, ok_to_copy_all): Not needed anymore. (copy_cmd,
+ ren_cmd, delete_cmd): Now use the new file operations
+ code. (do_mask_ren_cmd): Moved to file.c and renamed to
+ mask_rename. (mask_ren_cmd): Now calls the mask_rename function.
+ (new_file_ops_cmd, CmdMenu): The new_file_ops_cmd function is not
+ need anymore.
+
+ * tree.c (tree_copy, tree_move, rmdir_cmd): Now use the new file
+ operations code.
+
+ * util.c (get_full_name): Now strips the old path out of the
+ filename.
+
+Mon Jan 30 16:53:26 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (main): sigchld_hanlder was only defined with subshell
+ support.
+
+ * configure.in (AC_NCURSES): This replaces the try_ncurses
+ function, since some shells (Ultrix /bin/sh for example) don't
+ understand function definitions.
+
+ * main.c (do_nc): Setup must be saved before the destruction of
+ the panels takes place.
+
+ * profile.c (profile_clean_section): Fixed a bug that prevented
+ the the last item in the section list to be saved.
+
+ * setup.c: Added inode sort option
+
+ * dir.c: Added inode sort option.
+
+ * screen.c (string_inode): Added inode display.
+
+Mon Jan 30 14:37:30 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * Makefile.in: Added newfile.c, fsusage.c and mountlist.c to SRCS.
+ Added fsusage.h and mountlist.h to HDRS. Added newfile.o,
+ fsusage.o and mountlist.o to OBJS. (mc.hlp, ync.hlp, mc.html):
+ Added some missing $(srcdir)s.
+
+ * configure.in, configure: Added a lot of tests from the GNU
+ fileutils (needed by fsusage.c and mountlist.c).
+
+ * file.h: Added the prototype for the new_file_ops function.
+
+ * fsusage.c, fsusage.h: New files to get the filesystem space
+ usage. Copied from the GNU fileutils. Needed by the my_statfs
+ function.
+
+ * mountlist.c, mountlist.h: New files to get the list of mounted
+ filesystems. Copied from the GNU fileutils. Needed by the
+ my_statfs function.
+
+ * main.c (parse_control_file): Now handles directories correctly
+ when tagging or untagging. (unmark_file): Now global instead of
+ static (needed by the new_file_ops function). (new_file_ops_cmd):
+ New function to wrap calls to the new_file_ops function.
+ (CmdMenu): Add the "New file operations" entry to the bottom of
+ this menu.
+
+ * main.c (paint_info_panel): Got rid of "#ifdef HAVE_STATFS". The
+ my_statfs function uses GNU code now and it should work on all
+ machines. The Linux and Ultrix filesystem type switch clauses
+ aren't needed anymore (GNU code does a better job). (main): Added a
+ call to the init_my_statfs function to initialize the list of the
+ mounted filesystems.
+
+ * menu.c (menu_handler, run_menu): The menu is now removed after
+ the user has made his/her choice.
+
+ * newfile.c: New file which will replace the file.c file in the
+ future. Implements the new file operations.
+
+ * util.c, util.h: Removed the stuff to define the WE_HAVE_STATFS
+ macro. Removed the find_mountpoint and find_device functions.
+ (init_my_statfs): A new function to read the list of mounted
+ filesystems for the my_statfs function. (my_statfs): Dumped the
+ old code. Now uses the mountlist read by the init_my_statfs
+ function and the get_fs_usage function from the fsusage.c.
+ Therefore it should work correctly on all machines now.
+
+Sun Jan 29 15:35:34 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (init_sigchld): Use the main program sigchld handler when
+ no subshell support is requested.
+
+ * ncurses.h, configure.in: Changes to detect ncurses 1.8.6 and
+ newers.
+
+ * main.c (main): Moved the initialization code so that Dugan can
+ do the rest.
+
+Sat Jan 28 13:30:40 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (history_cmd): Free the listbox.
+
+ * chmod.c (chmod_toggle_select): Use the normal color.
+
+ * input.c (assign_text): The current max lenght of the string is
+ exactly the string lenght, not +1.
+
+ * main.c (history_cmd): Removed the hot key on the listbox window.
+
+ * configure.in (XCURSES): Added --with-sunos-curses
+
+ * ncurses.h: Updated the file to run with SunOS 4.x curses
+
+ * layout.c (init_layout): Changes to include the mini status field.
+
+ * option.c: Removed the show mini status option from the config
+ dialog and added the drop down menus instead.
+
+ * util.c (my_system): Removed the prepare_environement routines
+ since it didn't work with the subshell.
+
+ * main.c (do_nc): Removed the LINES checking, this must be done by
+ ncurses.
+
+Fri Jan 27 13:49:57 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (tree_view_cmd): Added missing call to clean_dir.
+
+ * dir.c (clean_dir): Sanity check.
+
+ * main.c (change_panel): Added extra check to avoid showing a non
+ existant entry if the view type is view_tree.
+
+ * subshell.c (init_subshell): Get and set the window size only if
+ the operating system has support for it.
+
+ The Solaris Fix for subshell:
+
+ (sigchld_handler):
+ Remove the loop around the pid = waitpid.
+ Add the WNOHANG option to the waitpid.
+ Remove the abortion code if pid <= 0.
+
+ (init_subshell): On Solaris, if you close the master pty on the
+ child, it also closes the slave side, so I removed the close
+ (subshell_pty). I leaved nice comments in case we want to undo
+ this behavior.
+
+ End of The Solaris Fix.
+
+ (get_window_size): Grabbed some code from GNU's shellutils. We
+ try first with stdout, then stdin, and finally with a user
+ provided file descriptor (in this case, ctermid (0)).
+
+ (init_subshell): Set the window size only if we could get the
+ window size.
+
+ * view.c (move_left, move_right): Even if wrap mode is set, we
+ have to tell the upper layers that the key was handled.
+
+ * main.c (paint_quick_view_panel): Replaced long condition for
+ is_view_file_listing.
+
+Fri Jan 27 13:40:07 1995 Thomas Pundt (pundtt@math.uni-muenster.de)
+
+ * main.c (paint_quick_view_panel): "fkeys" and "view_win" are not
+ initialized, if QuickView is activated and other_panel has not
+ selected a regular file. This causes mc to segfault, if you press
+ F4, before a file is selected. Added calls to view_init_windows
+ (panel->win_file, fkeys).
+
+ * view.c (load_view_file): Added missing strdups of string
+ constants.
+
+ * view.c (do_view_init): If we are displaying an error message in
+ the quick view panel, we also need to initialize the bytes_read
+ variable, not only the s.st_size field.
+
+ * view.c (view_init_windows): New function to setup the view_win
+ and fkeys variables, called from main for the quick view stuff.
+
+ * view.c (view_status): If filename is not set, then avoid the
+ crash by printw "".
+
+Fri Jan 27 16:43:38 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (sigchld_handler): Several corrections. Fixed stupid
+ mental typo of writing "handle_console" instead of "console_flag".
+
+ * screen.c (parse_display_format): There was a division by the
+ variable `field' which looped from 0 to (fields-1), provoking
+ an FPE on the first iteration. Replaced `field' by `fields',
+ which I think is what was intended.
+
+Fri Jan 27 15:21:09 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * cons.handler.c (show_console_contents): Oops, I forgot to clear
+ the window.
+
+ * layout.c (layout_callback, create_panels): Now there are minimum
+ and maximum limit for the number of output lines.
+
+ * main.c (sigchld_handler): Fixed a silly bug.
+
+Thu Jan 26 12:37:40 1995 Miguel de Icaza <miguel@sphinx>
+
+ * subshell.c: include sys/ioctl.h on 4.3 BSD systems for the
+ TIOCGWINSZ constant.
+
+ * main.c (ok_to_copy_all): Set the abort flag before returning. I
+ wonder how I could put the return before the assignment?
+
+ * menu.c (query_dialog): We don't use menu's query_dialog anymore,
+ now the query_dialog routine is the one written by Radek found in
+ the wtools.c file.
+
+ (run_bar): We don't use derwin any longer, we now require the
+ parent to provide a suitable window to draw on. Since this
+ routine is only used by the main program menu, I wonder if we
+ should just simple create this window here.
+
+ * wtools.c (query_dialog): Compute correctly the number of columns
+ needed for the query box.
+
+ * main.c (menu_display_cmd): Create the window to be used in run
+ bar.
+
+ * dialog.c, dialog.h (create_dialog): Now dialogs only use one
+ window, we don't use anymore the derwin call. Getting rid of the
+ derwin call will let us run with BSD curses (I hope).
+
+ (input_dialog): Adjust the area of display to conform to the new
+ changes.
+
+ (create_dialog): Adjust my_wputs.
+
+ * tree.c (show_tree): Adjust the display routines.
+
+ * help.c (show): Adjust the display routines.
+
+ * configure.in: Renamed --with-aixcc option to --with-mmap.
+
+ * main.c (untouch_bar): Call only_refresh_screen.
+
+ (only_refresh_screen): Now takes a boolean to determine if the
+ panels are being refreshed.
+
+ * help.c (interactive_display): Added missing call to
+ clear_link_areas.
+
+ * layout.c (destroy_panels): Changed pop events for pop_frame.
+
+Thu Jan 26 12:56:04 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * cons.handler.h: New file, to allow cons.handler.c to export
+ the `cons_saver_pid' variable (which used to be called `child')
+
+ * cons.handler.c, cons.saver.c, cons.saver.h: Changed type of
+ console_flag from 'int' to 'signed char', so that the various
+ write (cmd_output, &console_flag, 1) calls will work even on the
+ big-endian machines to which Linux will one day be ported ;-)
+
+ * vfs.h: Added 'const' to prototypes where appropriate.
+
+ * main.c (version): Polished the version message slightly.
+ Corrected the new sigchld_handler function a little.
+
+ * subshell.c: Improved the sigchld_handler function.
+
+Thu Jan 26 14:36:54 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * Makefile.in: cons.saver depends on cons.saver.o.
+
+ * boxes.c (display_callback): The 'm' key no longer jumps to user
+ mini status input field.
+
+ * cons.handler.c (show_console_contents): New function to show
+ output with the help of cons.saver.
+
+ * cons.saver.c (send_contents): New function to send the contents
+ of the console screen to the parent process.
+
+ * cons.saver.h: A new message CONSOLE_CONTENTS to request the
+ contents of console screen. Added prototype for show_console_contents.
+
+ * dlg.c (destroy_dlg): I finally fixed the mystic bug. The
+ destroy_dlg function was starting the loop from the second item
+ instead of the first item.
+
+ * layout.c (bplus_cback *new*, bminus_cback *new*,
+ layout_callback, init_layout, layout_cmd, create_panels,
+ destroy_panels), layout.h, main.c (do_execute, repaint_screen,
+ only_refresh_screen, refresh_screen), setup.c (layout): Now
+ supports defining a output window. You need the new cons.saver for
+ this (remember to type "make install.saver").
+
+ * layout.c (init_curses *new*, create_panels, destroy_panels,
+ change_screen_size), layout.h, main.c (main): Workarounds for
+ ncurses bugs. The initscr function is called only when really needed.
+
+ * main.c (select_item), screen.c (init_panel): Small bug fix
+ related to the long view.
+
+ * main.c (switch_to_info): No longer rejects second switch to the
+ info mode (needed by layout stuff).
+
+ * option.c (check_options): Removed the hotkey of the advanced
+ chown toggle.
+
+ * util.c (my_putenv): Removed the free command and added some
+ warnings to prevent others from adding it back (sorry Miguel).
+
+Wed Jan 25 13:05:59 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (goto_bottom_file, goto_top_file, goto_middle_file,
+ mark_file, copy_other_pathname, copy_prog_name,
+ copy_other_prog_name): Added checks so that they don't work when
+ quick or info modes are selected.
+
+ (try_to_select): Changed call to SELECT_ITEM for a call to
+ select_item, this should keep the info and quick view modes in
+ sync. If the users experiment a terrible slow down, then this
+ must be the reason.
+
+ * view.c (check_left_right_keys): Only allow horizontal scrolling
+ if the wrap mode is not toggled on.
+
+ (do_view_init): Now, the error message from loading a file is
+ displayed here. It is only displayed in a message box if we are
+ the real view and not the quick one.
+
+ (load_view_file): Now we guarantee that data has always data.
+ Thus on quick view, the keys will actually be checked correctly,
+ and the only information displayed on the quick view panel will be
+ the error message.
+
+ (load_view_file): Added missing close.
+
+ (view_update, move_forward2, move_backward2, move_to_top,
+ move_to_bottom, move_right, move_left, goto_line, regexp_search,
+ normal_search): if there is no data loaded, don't do anything
+
+Wed Jan 25 18:22:09 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * boxes.c: display_callback, display_init, display_box), panel.h,
+ screen.c (repaint_file, display_mini_info, do_init_panel), setup.c
+ (panel_save, panel_load): Now it is possible to define user format
+ for the mini status line, too.
+
+ * dlg.c (destroy_dlg): Another workaround for the mystic bug to
+ get the Electric Fence working. I hope someone fixes this bug soon.
+
+ * file.c (move_file, move_dir_dir): Now show a message box so that
+ the user knows we are moving files. The move_dir_dir is now more
+ bullet proof.
+
+ * layout.c: Replaced hardcoded values 20 and 5 with MINWIDTH and
+ MINHEIGHT. MINWIDTH is now 10 instead of 20.
+
+ * setup.c (save_setup): Swapped save_configure with save_layout.
+ Let's see if this it has any effect.
+
+ * view.c (free_file): Uses different method for checking errors.
+ No broken pipes anymore. (load_view_file): Oops, the s.st_size was
+ not initialized in case of compressed files.
+
+ * view.c (load_view_file, view_labels, change_viewer *new*,
+ create_windows): New Raw/Gunzip button: now the compressed files
+ can be viewed both as raw data and as uncompressed data.
+
+ * zip.c (get_small_endian_long): Now handles eof correctly.
+ (is_gunzipable): Now reports only deflated or stored zip files as
+ gunzipable.
+
+Tue Jan 24 16:34:13 1995 Miguel de Icaza <miguel@sphinx>
+
+ * layout.c (create_panels): Push a missing frame.
+
+ * main.c (main): Remove unused events at program end.
+
+ * util.c (my_putenv): Release the unused memory.
+
+ * main.c (do_possible_cd): Now it paints the panel as all the
+ other cd routines and selects the item.
+
+ (maybe_cd): if it's the left key, then go up one directory.
+
+Tue Jan 24 12:32:14 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * file.c (erase_dir): Slight changes to the confirmation box for
+ recursively deleting directories.
+
+ * main.c (main): Removed a repeated initialization of home_dir.
+
+Mon Jan 23 14:45:34 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (init_subshell): Removed the `shell_name' variable
+ and all references to it, and used `shell' from main.c instead.
+
+ (init_subshell): Now we install the SIGCHLD handler here and
+ leave it active all the time until MC exits, instead of enabling
+ it only during execution of the subshell functions. This seems
+ to make MC hang less frequently, but unfortunately it will still
+ hang if you try hard enough (by holding down C-o a lot).
+
+Sun Jan 22 20:48:57 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (main): Warn user if we can't start up the subshell.
+ Also, tentatively added putchar ('\r') at the end of main(),
+ to make the user's shell write its prompt starting in column 0
+ after MC has terminated.
+
+ * subshell.c (sigchld_handler): Moved the message about using
+ the old command execution method from here to main().
+
+Tue Jan 24 12:25:44 1995 Thomas Pundt <pundtt@math.uni-muenster.de>
+
+ * view.c (create_windows): Moved the push_frame from: before the
+ push_events to just after the wattron. The problem is, that not
+ all mouse events are popped off the stack, because the new frame
+ is set up too late.
+
+Tue Jan 24 11:35:01 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * file.c (copy_file_file): Now copies symbolic links correctly (as
+ defined by Dugan). (move_file): Dumped the code based on a system
+ call and copied the code from mv.c in GNU fileutils-3.12.
+ (move_file_dir): Dumped the old version and copied the code from
+ copy_file_dir.
+
+ * main.c: The init_entry function removed. (parse_control_file,
+ action, enter, tree_leave): Small changes in the handling of cd
+ command. (ok_to_copy): Now pressing ESC or F10 works
+ correctly. (swap_cmd): Windows are moved instead of swapping. Now
+ compatible with layout feature. (paint_info_panel): The code has
+ been turned upside-down to support leaving out the lines which
+ don't fit.
+
+ * panel.h: The win_mini field wasn't used for anything.
+
+ * view.c (do_view_init, view): The initialization of the start_col
+ variable belongs to the do_view_init function. (display,
+ move_right, move_left): Small fixes to the left/right movement.
+ (view): Added a workaround for a NCurses bug.
+
+Mon Jan 23 19:00:15 1995 Miguel de Icaza <miguel@sphinx>
+
+ * mouse.c (mouse_push_event): Now, we return the event pointer,
+ needed for changing the event parameters of the panels on a
+ resize.
+
+Mon Jan 23 15:43:49 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * dialog.c (input_dialog): The in variable was used after it was
+ destroyed.
+
+ * dlg.c (destroy_dlg): Added a workaround for the widget list bug.
+ This is just a temporary fix. Let's hope the bug gets really fixed
+ someday.
+
+ * layout.c (create_panels, destroy_panels): Now create and destroy
+ all the curses windows of the main screen. (flag_winch,
+ change_screen_size): Now they work correctly.
+
+ * main.c: The current_panel, other_panel, menubar_win,
+ cmdline_win, fkeys and clean_screen variables are initialized to
+ NULL in order to help catching the bugs. The cmdline, prompt and
+ clean_screen variables are now global. The contents of init_entry
+ function are moved to the create_panels function (maybe the whole
+ function can now be removed). Part of the init_menu function moved
+ to create_panels function. The init_labels function calls now the
+ change_labels function. (do_nc, main): Some reorganization to get
+ along with the more thorough behaviour of the create_panels and
+ destroy_panels functions.
+
+ * main.c (paint_quick_view_panel), view.c (display): Quick view no
+ longer flashes when holding an arrow key down.
+
+ * setup.c (load_setup): The call to the meta function moved to the
+ main function.
+
+ * util.c (close_error_pipe): Now it is possible to tell
+ close_error_pipe to ignore the message in the pipe (needed by
+ quick view).
+
+ * view.c: Reorganized to use the same kind of folding as Dugan
+ uses in the subshell.c. (free_file, get_byte, load_view_file,
+ search, regexp_search, normal_search): Changes to support loading
+ file in parts when mmap can't be used. (load_byte): New function
+ to implement loading in parts. (do_view_init): Small bug fixes.
+
+Sun Jan 22 12:10:03 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (init_subshell): Introduced a new symbolic constant
+ FORK_FAILURE, used as an exit code to indicate failure to start up
+ the subshell, to that the sigchld handler can distinguish that
+ case from when the user exits the subshell voluntarily.
+
+ (feed_subshell): Never call `select' without checking that the
+ subshell is alive is TRUE; this prevents MC from locking up so
+ often. Also, capture the subshell's prompt regardless of
+ whether the `how' parameter is QUIETLY or VISIBLY.
+
+ (sigchld_handler): Check the subshell's exit code to find out
+ whether the user exited or we simply failed to fork the subshell.
+
+ (pty_open_slave): Temporarily commented out the calls to chown()
+ and chmod(), to fix the /dev/tty?? permissions problem.
+
+Sat Jan 21 14:15:29 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (init_subshell): Replaced the multi-branched if
+ statements with switches, to accommodate future subshell types.
+
+Thu Jan 19 11:27:02 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * Makefile.in: Added cons.saver to the `all' target, and
+ install.saver to the `install' target. Plus minor cleanups.
+
+Sat Jan 14 08:41:07 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (quit_cmd): Added a call to exit_subshell.
+
+ * subshell.c (feed_subshell): Fixed a prompt-capturing bug, by
+ moving the declaration of prompt_pos closer to its point of use.
+
+ (feed_subshell): Added a nasty temporary hack to make MC wait for
+ the subshell's prompt for an extra second the first time through,
+ to allow time for the shell's init file to run.
+
+Fri Jan 13 12:17:43 1995 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (suspend_cmd): The screen contents weren't being saved
+ properly after returning to MC, because ncurses was re-drawing
+ the screen instantly, before the call to handle_console. Fixed
+ by swapping out ncurses' SIGTSTP handler briefly.
+
+ (view_other_cmd): Made MC update its prompt from the subshell's.
+
+ * util.c: Made startup_handler global so it can be accessed from
+ main.c. It would perhaps be better to put everything to do with
+ signals in a file "signals.c", and also re-organize MC's entire
+ source file structure while we're at it. Some other time...
+
+ * main.c (pre_exec, post_exec): Removed the calls to
+ handle_console, so that suspend_cmd can call pre_exec and
+ post_exec without saving the screen contents, if it wants to.
+
+Sun Jan 22 18:11:58 1995 "Sinolits Vadim vvs@nsrd.npi.msu.su
+
+ * view.c (move_left, move_right, check_left_right_keys): Added
+ vertical scrolling.
+
+Thu Jan 19 11:06:59 1995 Miguel de Icaza (miguel@roxanne)
+
+ * layout.c (change_screen_size), main.c (do_nc): compile the
+ window size change functions only if the system provides them.
+
+Thu Jan 19 14:57:14 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * input.c (update_input): Now supports 8bit clean mode.
+
+ * key.c (getch_with_delay): New function to work around System V
+ Curses vt100 bug. (mi_getch): Now uses getch_with_delay.
+
+Wed Jan 18 13:40:14 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * layout.c: The check_split function divided to two versions:
+ _check_split and check_split. Now cancel button really cancels all
+ the changes, not just some of them. Added support for horizontal
+ splitting.
+
+ * layout.c (flag_winch, change_screen_size), layout.h: New
+ functions for handling of the WINCH signal. Now, how can we get
+ curses to realize the change in the screen size?
+
+ * main.c (do_nc): Now handles the WINCH signal.
+
+ * main.c (select_item): Changes for horizontal splitting.
+
+ * main.c (init_entry, repaint_screen, only_refresh_screen,
+ refresh_screen, quick_view_key, init_menu): Changes to support
+ menubar_visible, command_prompt and keybar_visible toggles.
+
+ * main.c (enter, change_view): Small fixes.
+
+ * screen.c (do_init_panel): Fixed the missing titles bug.
+
+Tue Jan 17 11:04:24 1995 Miguel de Icaza (miguel@roxanne)
+
+ * util.c (strcasecmp): Fix strcasecmp.
+
+ * option.c (init_configure): The correct index is 10, not 9 after
+ adding the new advanced chown option to the dialog box.
+
+Tue Jan 17 18:12:03 1995 Janne Kukonlehto (jtklehto@paju)
+
+ * Makefile.in: Added layout.c to SRCS, layout.h to HDRS and
+ layout.o to OBJS.
+
+ * hotlist.c: The sf_stat variable isn't needed.
+
+ * hotlist.c (add2hotlist_cmd), hotlist.h, main.c (ctl_x_map): The
+ hotkey for adding a directory to the hotlist is back!
+
+ * layout.c: A new file for changing the panel widths and other
+ things like that on the fly.
+
+ * main.c (panel_event, menu_bar_event, change_view), panel.h: Now
+ global instead of static (needed by layout.c).
+
+ * main.c (init_panels, done_panels, do_nc): Window and mouse
+ handling code moved to layout.c in the create_panels and
+ destroy_panels functions. The do_init_panel function is now used
+ instead of init_panel.
+
+ * main.c (change_labels, repaint_screen, only_refresh_screen,
+ refresh_screen, default_key, init_labels), view.c (view_refresh,
+ create_windows, view), win.c (set_label_text): Command prompt and
+ function key bar might not exist.
+
+ * main.c (change_panel, paint_quick_view_panel, quick_view_cmd,
+ change_view): Miscellaneous changes to make sure we are always in
+ the right directory.
+
+ * main.c (do_mark_file), screen.c (display_mini_info): No
+ hardwired panel widths like "COLS/2-2" anymore.
+
+ * main.c (paint_quick_view_panel), view.c (view_init, view_status,
+ display, create_windows), view.h: Quick view has now a frame
+ (sorry about this, Torben).
+
+ * main.c (quick_view_key, tree_view_cmd), view.c (view):
+ Miscellenous fixes.
+
+ * option.c (check_options): Now static. Fixed the hotkey of
+ advanced chown. (configure_box): Now the save button saves only
+ the settings of this dialog. Use the save setup command to save
+ the whole setup.
+
+ * screen.c (do_init_panel, init_panel): The init_panel function
+ now initializes only the things related to the size and positions
+ of the panel. Other stuff moved to the new do_init_panel function.
+
+ * setup.c, setup.h: New functions: save_layout, load_layout and
+ save_configure. The configure and layout dialogs save now only
+ their own settings. Use save setup command to save the whole
+ setup. (save_setup, load_setup): Changes related to the addition of
+ save_layout, load_layout and save_configure.
+
+ * view.c (load_view_file, view_update, view_check_key): A lot of
+ error messages and problems are skipped or ignored when in quick
+ view mode. (do_view_init): hex_mode and wrap_mode are no longer
+ reinitialized in the quick view mode.
+
+ * win.c (wprint_bytesize): Outputs now always seven characters to
+ make justifying easier.
+
+Mon Jan 16 19:22:27 1995 Miguel de Icaza (miguel@roxanne)
+
+ * util.c (tilde_expand): Small bug fix: strdup the home_dir.
+
+Sat Jan 14 13:46:10 1995 Janne Kukonlehto <jtklehto@stekt10>
+
+ * main.c (parse_control_file): Small changes in handling of the cd
+ command.
+
+ * main.c (change_labels, change_panel, key_f2_cmd, key_f3_cmd,
+ key_f4_cmd, paint_quick_view_panel, quick_view_key, init_labels),
+ screen.c (init_panel): Changes for the quick view mode.
+
+ * main.c (key_f5_cmd, key_f6_cmd, key_f7_cmd, key_f8_cmd): New
+ functions for the quick view mode.
+
+ * view.c: Reorganized. A lot of changes to support quick view
+ feature.
+
+ * view.h: Added view_init, view_update, view_labels,
+ toggle_wrap_mode, toggle_hex_mode, goto_line, regexp_search,
+ normal_search and view_check_key to support quick view feature.
+
+ * main.c (dummy): Deleted as unnecessary.
+
+ * main.c (tree_leave), tree.c (tree_done, tree), tree.h: The
+ tree_done function deleted as unnecessary.
+
+ * subshell.c (init_subshell): Opening fifo as O_RDONLY or O_WRONLY
+ causes deadlock. Now uses O_RDWR instead. Replaced getenv ("HOME")
+ with the home_dir variable.
+
+Fri Jan 13 12:55:42 1995 Miguel de Icaza <miguel@sphinx>
+
+ * find.c (do_search): strcpy the string only if the returned value
+ is not null.
+
+Fri Jan 13 15:33:09 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * find.c (find_parameters): Now you can use tree for specifying
+ the start dir.
+
+ * main.c (change_labels, key_f4_cmd), tree.c (toggle_nav_mode,
+ win_init), tree.h: In tree mode the label of the F4 key is changed
+ between "static" and "dynamic".
+
+ * tree.c (set_navig_label): New function for changing the label of
+ the F4 key in the tree mode.
+
+ * mc.1 (Directory tree): Updated.
+
+Thu Jan 12 17:15:21 1995 Miguel de Icaza <miguel@sphinx>
+
+ * widget.c (input_callback): Ugly hack to avoid update_input clear
+ the first field of the Input* structure when used for displaying
+ the input line.
+
+ * find.c (start_stop): Changed the moving dot for a nice rotating
+ dash. Should change this for a rotating fish.
+
+ * widget.c (listbox_draw): When painting listboxes, display at
+ most the size that would fit in the listbox (obvious problem with
+ the find code).
+
+ * find.c (do_find): Free the dirname and filename only if they
+ were strduped.
+
+ * widget.c (listbox_get_current): Set decent values even if the
+ listbox is empty.
+
+ * option.c (configure_box): Sync the profiles after saving the
+ setup if the Save button was selected.
+
+ * tree.c: renamed search_buffer to search_buffer_tree, in order to
+ let the program link/compile under AIX with c6000. BTW, Janne,
+ could we share the search_buffer with main?
+
+ * subshell.c, view.c, key.c, gpm-xterm.c, util.c: check for AIX,
+ _AIX and __aix__ macros.
+
+ * main.c (do_nc): Now, we sync the profiles, but save the setup
+ only if requested. The net result is that now we save the hotlist
+ automagically even if the setup is not saved/changed. This from a
+ couple of comments from Janne and Dugan on the list.
+
+ * setup.c (save_setup): Save setup doesn't sync the profiles.
+
+ * subshell.c (init_subshell): Adapted Janne's patch of shell =
+ getenv ("SHELL") to new Dugan's code. Let's hope Dugan will send
+ me the ChangeLog entries for his last subshell code.
+
+Thu Jan 12 14:00:29 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * main.c (index_by_name, select_by_index, parse_control_file),
+ util.c (my_putenv, my_putenv_expand, prepare_environment): New
+ functions for the control file support.
+
+ * main.c (do_execute), main.h, util.c (my_system), util.h: Changes
+ for the control file support.
+
+ * main.c (execute, handle_args), main.h, subshell.c
+ (init_subshell), util.c (my_system): The value of shell variable
+ is now calculated only once in one place instead of dozens of
+ times and places.
+
+ * main.c (ITEMS, panel_event, move_left, move_right,
+ copy_current_pathname, copy_other_pathname, copy_prog_name,
+ copy_other_prog_name, copy_tagged, copy_other_tagged), user.c
+ (expand_format): Fixed bugs and problems caused by addition the
+ quick view mode.
+
+ * main.c (handle_args): Reports if the TERM variable is
+ unset. (main): The error messages are no longer wiped out from the
+ screen by cons.saver.
+
+ * mc.1 (Executing operating system commands): Documented the
+ control file feature.
+
+ * tree.c (tree_rescan_cmd): Someone had changed it to use the
+ get_current_wd function and forgot to test whether it works
+ after such change. Now fixed.
+
+ * util.c (load_file): Now more robust.
+
+Wed Jan 11 18:36:59 1995 Miguel de Icaza <miguel@sphinx>
+
+ * widget.c (listbox_get_current): New function for retrieving the
+ data from the listbox.
+
+ (button_set_text): New function to change the label of a button.
+
+ (listbox_add_item): Now we return the value of the strduped string.
+
+ * find.c: Many changes and fixes, the find feature is not yet ready.
+
+ * widget.c (input_callback): Enter gives the focus to the next
+ widget.
+
+ (listbox_select_last): Selects the last entry in the listbox.
+
+Wed Jan 11 15:08:12 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * Makefile.in (mc.html): New target which produces html version of
+ the manual page.
+
+ * boxes.c (display_callback, display_init), main.c (select_item,
+ change_panel, action, panel_event, move_left, move_right,
+ paint_info_panel, switch_to_info, change_view,
+ copy_other_pathname, copy_other_prog_name, copy_other_tagged,
+ do_nc), panel.h, screen.c (display_mini_info, paint_dir,
+ paint_panel, init_panel), setup.c (load_setup), user.c
+ (expand_format, test_condition): Preliminary changes to support
+ quick view mode.
+
+ * main.c (paint_quick_view_panel, dummy, quick_view_key,
+ quick_view_cmd): New functions for preliminary support for quick
+ view mode.
+
+ * ext.c (regex_command), mc.ext, mc.menu, user.c (user_menu_cmd),
+ user.h: Now supports local shell_patterns settings.
+
+ * user.c (check_patterns): New function to support local
+ shell_patterns settings.
+
+ * main.c (ITEMS, panel_event): Now works correctly with user
+ formats like "half 2 ..." and "full 2 ...".
+
+ * main.c (panel_event): Now works correctly user formats like
+ "full ...".
+
+ * main.c (paint_info_panel): Unsignificant bug fixes.
+
+ * man2hlp.c: Now can produce HTML format output in addition to HLP
+ format.
+
+ * mc.1: Fixes so that man2hlp can produce correct HTML
+ output. (Extension File Edit, Menu File Edit): Updated to mention
+ local shell_patterns setting. (Menu File Edit): Mentions now
+ combined default and addition conditions. Cleared out the
+ explanation of the calculation order of conditions. (SEE ALSO):
+ Corrected the URL.
+
+ * menu.c (get_motion): Now you can drop menu with the down key
+ like in the Norton Commander.
+
+ * user.c (user_menu_cmd): Now supports combined addition and
+ default conditions.
+
+Wed Jan 11 15:08:12 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * Makefile.in (mc.html): New target which produces html version of
+ the manual page.
+
+ * boxes.c (display_callback, display_init), main.c (select_item,
+ change_panel, action, panel_event, move_left, move_right,
+ paint_info_panel, switch_to_info, change_view,
+ copy_other_pathname, copy_other_prog_name, copy_other_tagged,
+ do_nc), panel.h, screen.c (display_mini_info, paint_dir,
+ paint_panel, init_panel), setup.c (load_setup), user.c
+ (expand_format, test_condition): Preliminary changes to support
+ quick view mode.
+
+ * main.c (paint_quick_view_panel, dummy, quick_view_key,
+ quick_view_cmd): New functions for preliminary support for quick
+ view mode.
+
+ * ext.c (regex_command), mc.ext, mc.menu, user.c (user_menu_cmd),
+ user.h: Now supports local shell_patterns settings.
+
+ * user.c (check_patterns): New function to support local
+ shell_patterns settings.
+
+ * main.c (ITEMS, panel_event): Now works correctly with user
+ formats like "half 2 ..." and "full 2 ...".
+
+ * main.c (panel_event): Now works correctly user formats like
+ "full ...".
+
+ * main.c (paint_info_panel): Unsignicant bug fixes.
+
+ * man2hlp.c: Now can produce HTML format output in addition to HLP
+ format.
+
+ * mc.1: Fixes so that man2hlp can produce correct HTML
+ output. (Extension File Edit, Menu File Edit): Updated to mention
+ local shell_patterns setting. (Menu File Edit): Mentions now
+ combined default and addition conditions. Cleared out the
+ explanation of the calculation order of conditions. (SEE ALSO):
+ Corrected the URL.
+
+ * menu.c (get_motion): Now you can drop menu with the down key
+ like in the Norton Commander.
+
+ * user.c (user_menu_cmd): Now supports combined addition and
+ default conditions.
+
+Wed Jan 11 15:08:12 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * Makefile.in (mc.html): New target which produces html version of
+ the manual page.
+
+ * boxes.c (display_callback, display_init), main.c (select_item,
+ change_panel, action, panel_event, move_left, move_right,
+ paint_info_panel, switch_to_info, change_view,
+ copy_other_pathname, copy_other_prog_name, copy_other_tagged,
+ do_nc), panel.h, screen.c (display_mini_info, paint_dir,
+ paint_panel, init_panel), setup.c (load_setup), user.c
+ (expand_format, test_condition): Preliminary changes to support
+ quick view mode.
+
+ * main.c (paint_quick_view_panel, dummy, quick_view_key,
+ quick_view_cmd): New functions for preliminary support for quick
+ view mode.
+
+ * ext.c (regex_command), mc.ext, mc.menu, user.c (user_menu_cmd),
+ user.h: Now supports local shell_patterns settings.
+
+ * user.c (check_patterns): New function to support local
+ shell_patterns settings.
+
+ * main.c (ITEMS, panel_event): Now works correctly with user
+ formats like "half 2 ..." and "full 2 ...".
+
+ * main.c (panel_event): Now works correctly user formats like
+ "full ...".
+
+ * main.c (paint_info_panel): Unsignicant bug fixes.
+
+ * man2hlp.c: Now can produce HTML format output in addition to HLP
+ format.
+
+ * mc.1: Fixes so that man2hlp can produce correct HTML
+ output. (Extension File Edit, Menu File Edit): Updated to mention
+ local shell_patterns setting. (Menu File Edit): Mentions now
+ combined default and addition conditions. Cleared out the
+ explanation of the calculation order of conditions. (SEE ALSO):
+ Corrected the URL.
+
+ * menu.c (get_motion): Now you can drop menu with the down key
+ like in the Norton Commander.
+
+ * user.c (user_menu_cmd): Now supports combined addition and
+ default conditions.
+
+Tue Jan 10 15:58:24 1995 Miguel de Icaza <miguel@sphinx>
+
+ * configure.in: Now detection of the regular expression functions
+ is more efficient. We now detect properly the HP-UX stuff.
+
+Mon Jan 9 15:39:58 1995 Miguel de Icaza <miguel@sphinx>
+
+ * widget.c (listbox_draw): If the listbox is empty, draw empty
+ fields.
+
+ * find.c: Continued work on the find command.
+
+ * dlg.c (set_idle_proc, dlg_new): Support for calling the callback
+ procedure on the idle time.
+
+ * configure.in: Under HP-UX link with -lc and -lPW.
+
+Mon Jan 9 15:39:58 1995 Thomas Pundt <pundtt@math.uni-muenster.de>
+
+ * util.c (basename): compile it only if it's not available in the
+ system.
+
+Mon Jan 9 16:50:51 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * *.c, *.h: Checked spelling of all comments with ispell.
+
+ * ChangeLog, NEWS: Minor corrections.
+
+ * tree.c (show_tree, tree_event): Rewrote the mouse support. Now
+ it is based on the new static tree_shown variable.
+
+Sun Jan 8 16:35:33 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * key.c, subshell.c: If being compiled under AIX, then include
+ sys/select.h
+
+Sat Jan 7 18:56:55 1995 Miguel de Icaza <miguel@sphinx.nuclecu.unam.mx>
+
+ * main.c (maybe_cd, move_left, move_right): Used to navigate
+ with the arrow keys, like the Lynx program. Need to turn the
+ navigate_with_arrows setting in the .mc.ini file.
+
+ * find.c (do_find): Complete rewrote of the find command.
+
+ * ext.c (exec_extension): If the users aborts an input_dialog,
+ then return value is 0. It's ok for the user to accept an empty
+ string.
+
+ Give an initial value to the prompt variable.
+
+Sun Jan 8 16:27:48 1995 Radek Doulik <rodo@RoDo-Station>
+
+ * main.c: toggle_adv_ch function to toggle advanced chmod/chown
+ command, int adv_ch - bool variable
+
+ * setup.c: added new option in .mc.ini file for advanced
+ chmod/chown command
+
+ * option.c: added new check button to switch between normal and
+ advanced chmod/chown commands.
+
+ * chown-advanced.c: new file for advanced chmod/chown command -
+ note that this is only preview and now does nothing.
+
+Sat Jan 7 18:51:10 1995 Radek Doulik <rodo@RoDo-Station>
+
+ * chown.h, chown.c (init_chown): One more bug fixed. Use
+ single_set variable to decide, why use only two buttons.
+
+Fri Jan 6 13:55:03 1995 Miguel de Icaza <miguel@sphinx>
+
+ * chmod.c (chmod_cmd): We have to destroy the complete dialog
+ completely each time, since we keep running the dialog and it
+ keeps pushing relevant data. We may need to split the run_dlg
+ stuff.
+
+ * chown.c (chown_cmd): Same as chmod.c
+
+ * dialog.c (push_refresh): Now the program should refresh the
+ complete screen if the fast_refresh setting is set to 0, else it
+ stands for the default behavior.
+
+Thu Jan 5 11:36:34 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (sort_cmd): When changing sort orders, and you ask for
+ unsorted, it has to reload the directory in order for the list to
+ be unsorted. A shame all the complexity needed.
+
+ (copy_cmd): If there is an error during the copy process, the copy
+ is aborted.
+
+ * screen.c (repaint_file): Now it's able to trunc the field name
+ taking care of justification.
+
+ * main.c (ok_to_copy): Free the file name if it was allocated from
+ get_full_name.
+
+ * file.c (erase_dir): Don't allow removal of "." or ".." directories.
+
+ * main.c (do_nc): Returns status of initialization, so we call
+ endwin only if the program ran successfully.
+
+Thu Jan 5 14:34:36 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * ChangeLog: Run through ispell and other small fixes.
+
+ * file.c (move_file), view.c (load_view_file): Now file moving and
+ compressed file viewing works also with filenames like "*(#&$%@}?>".
+ The only disallowed characters are "\000", "/" and "'".
+
+ * hotlist.c: No need to include chmod.h.
+
+ * main.c (do_mask_ren_cmd): Query for confirmation has now two new
+ choices: All and Cancel. Esc and F10 work now as expected.
+
+ * tree.c (tree_move_to_child): Directory is rescanned only if it
+ has no known children (as requested by Dugan).
+
+ * win.c (set_label_text): If screen has too few columns leaves out
+ those labels which don't fit. Avoids printing in bottomright
+ corner to get rid of strange side-effects. (define_label,
+ define_label_quit): Code clean-up.
+
+Wed Jan 4 11:17:53 1995 Miguel de Icaza <miguel@sphinx>
+
+ * profile.c (profile_clean_section): Removes a section from the
+ profile manager.
+
+ * hotlist.c (save_hotlist, load_hotlist): Now the hotlist save and
+ load functions load their information from the .mc.ini file
+ instead of their own file.
+
+ (done_hotlist): new shutdown function. Clears all the memory used
+ by the hotlist.
+
+ * setup.c (load_setup): Moved the load_hotlist function here.
+
+ (save_setup): Moved the save_hotlist function here.
+
+ * profile.c (profile_init_iterator, profile_iterator_next):
+ Iterator functions for the profile manager.
+
+ * widget.c (listbox_draw): Use a different set of colors if the
+ listbox is focused or not.
+
+ (button_callback, button_new): Allow the user to specify a
+ callback function for a button, in which case, we don't abort the
+ execution of the dialog.
+
+ (listbox_key): Report event as handled on both key up and key down.
+
+ * hotlist.c (hotlist_callback): Moved the redraw code to the
+ switch DLG_DRAW case.
+
+ (init_hotlist): Changed to use the new color scheme.
+
+Wed Jan 4 16:24:14 1995 Janne Kukonlehto <jtklehto@stekt8>
+
+ * Makefile.in: Added hotlist.c to SRCS, hotlist.h to HDRS and
+ hotlist.o to OBJS.
+
+ * chmod.c: SGI also needs the umode_t define.
+
+ * hotlist.c: New file which implements directory hotlist
+ feature. Most of its code is copied from chown.c or moved from
+ main.c.
+
+ * hotlist.h: New file.
+
+ * main.c: Now includes hotlist.h. (add2hotlist, load_hotlist,
+ save_hotlist and add2hotlist_cmd): Moved to
+ hotlist.c. (quick_chdir): Calls the new hotlist_cmd function
+ instead of creating a listbox of its own. (CmdMenu): "Add to
+ hotlist" removed from the Command menu. (ctl_x_map): Keyboard
+ shortcut of add2hotlist_cmd removed.
+
+ * ncurses.h: SGI is system-V, too.
+
+Tue Jan 3 16:26:04 1995 Miguel de Icaza <miguel@sphinx>
+
+ * screen.c (paint_frame): Trunc the header size to the computed size.
+
+ * wtools.c (run_listbox): Fixed memory leak. Free the Listbox
+ structure. The MAD system is a great tool. Don't develop without
+ it.
+
+ * color.c: New color entries for dnormal, dfocus, dhotfocus and
+ dhotnormal.
+
+ * boxes.c (init_box_colors), chown.c, chmod.c: Use new color
+ scheme for dialog boxes.
+
+ * util.c (regexp_match): Uses regcomp if available in that system
+ (HP-UX and Linux).
+
+Mon Jan 2 14:07:42 1995 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (ren_cmd): If we detect an '*' or an '?' in the rename
+ command, we invoke the mask rename command written by Janne.
+
+ (ok_to_copy_all): Now also let's the user abort with escape.
+
+ (copy_cmd): Added support for aborting a copy.
+
+ * file.c (copy_file_file): Changed exit address to ret3 when the
+ dialog has been inserted. This fixes another problem with pop
+ events.
+
+Sun Jan 1 19:27:05 1995 Miguel de Icaza <miguel@sphinx>
+
+ * subshell.c (invoke_subshell): Now takes two extra setable
+ parameters: new_dir and msg. new_dir is used to return the new
+ working dir if it changed and msg is used to return an informative
+ message back to the calling routine.
+
+ * screen.c (parse_display_format): Added handling for left and
+ right justification.
+
+ (repaint_file): Added support for justification modes.
+
+Sat Dec 31 13:41:54 1994 Miguel de Icaza <miguel@sphinx>
+
+ * input.c (create_input): current_max_len must be set to the
+ maximum of the field_length and the user provided initial text.
+
+ * menu.c (run_bar): Initialize abort variable.
+
+ * screen.c (init_panel): Assign user_format only if it doesn't
+ have a value set, this should not happen.
+
+ * dialog.c (input_dialog): Frees the buffer if the input box was
+ canceled.
+
+ * screen.c (repaint_file): On fields that are not the file name
+ field "cut" the leftmost characters when limiting the string
+ length.
+
+ (string_file_perm_octal): New mode: returns permissions mode in octal.
+
+Fri Dec 30 14:07:56 1994 Miguel de Icaza <miguel@sphinx>
+
+ * subshell.c (pty_open_master, pty_open_slave): New functions to
+ open the slave and master sides of a pty. They work on both BSD
+ and SystemV machines.
+
+ * main.c (filter_cmd): Fix: use the correct regexp on the filter
+ function.
+
+ * screen.c (string_marked): new display function "mark", returns
+ an asterisk if the file is marked or a space if it's not.
+
+ * terminfo/linux.ti: When compiling also generate the console
+ terminfo.
+
+ * util.c (string_perm): Changed position and character string for
+ sticky directories (was [0] -> i now is [9] -> t).
+
+ * profile.c (is_loaded): Bug fixing: return load status and the
+ section separately.
+
+ (GetSetProfileChar): Added a missing return this caused the long
+ initialization files problem.
+
+ * key.c (is_abort_char, is_quit_char): New functions, not yet
+ used. Should be used to test for abort/escape conditions.
+
+ * setup.c (load_setup): Do the setup even if there is no init file.
+
+ * screen.c (parse_display_format): Don't let the display format
+ use more space than the available. Not very nice fix.
+
+ (init_panel): Set a default user format.
+
+ * boxes.c (display_callback): If the user uses the 'u' key, now we
+ set the focus to the user format input field.
+
+ * file.c (copy_dir_dir): Added missing closedir.
+
+ (recursive_erase): Added missing destroy_dialog this should fix
+ the mouse missing mouse pop event.
+
+Fri Dec 30 01:36:24 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * util.c (strip_ctrl_codes): New function: removes the control
+ sequences from its argument string.
+
+ * main.c: Made some local variables and functions `static'.
+
+ (do_nc, set_new_prompt): Call the new function `strip_ctrl_codes'
+ to remove the control sequences from bash's prompt.
+
+Fri Dec 30 14:08:33 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * cons.handler.c (handle_console): Checks that the cons.saver
+ process is still running by sending cont signal everytime before
+ communicating with it (as requested by Dugan). Added comments.
+
+ * cons.saver.c: Code clean-up and comment adding. (tty_getsize):
+ Simplified the code based on the fact that tty is console.
+
+ * help.c (interactive_display), tree.c (tree): Doesn't seg-fault
+ anymore if screen has less than 22 rows. Now the minimum limit for
+ the screen size is the number of lines in File menu.
+
+ * main.c (handle_args): Gives an error message instead of
+ seg-faulting if the TERM variable is unset.
+
+ * subshell.c (init_subshell): Now supports also tcsh and zsh
+ shells in addition to bash. FIXME: The tcsh support leaves an
+ extra fifo in the /tmp directory.
+
+ * tree.c (show_tree): I hope it finally does the name truncation
+ correctly. It should now work up to 32 levels of subdirectories.
+
+Thu Dec 29 15:38:00 1994 Miguel de Icaza <miguel@sphinx>
+
+ * boxes.c (sort_box): Added nice Cancel button to the sort order
+ box.
+
+ * widget.c (input_event): Added precary mouse support for input
+ lines.
+
+ * input.c (update_input): Better cursor movement
+ (input_set_point): New function that allows the user to set the
+ point.
+
+ * panel.h (PANEL_ISVIEW): Added missing call new view to
+ PANEL_ISVIEW, this caused the problem of not reloading the user
+ display.
+
+ * screen.c (panel_reload): Added a missing return after
+ tree_rescan_cmd and paint_panel. Tree views don't need all the
+ extra code
+
+ * util.c (get_current_wd): system independent get wd function.
+
+ * find.c, main.c, screen.c, tree.c: replace ifdef code for calling
+ getwd/getcwd for a call to a new function in util.c
+
+ * screen.c (paint_dir): Paint directory only if the panel is not a
+ tree or info view.
+
+ * util.c (name_trunc): Truncate correctly when the field is odd.
+
+ * view.c (do_view): Scroll by half pages with mouse clicks instead
+ of one line at a time.
+
+ * xterm.ti: added a base xterm-base class for both xterm and xterm
+ color. xterm now adds support for the sgr and sgr0 capabilities.
+ This fixes the display problems with ncurses when changing
+ attributes.
+
+ We still need to make this work with the Linux console.
+
+ * setup.c, main.c (panel_event): mouse_move_pages, new setting
+ that let's the user specify which kind of movement should be done
+ when clicking on the top or the bottom of the panels.
+
+Thu Dec 29 03:08:01 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * util.c (my_system): Restore the signal mask after finishing.
+
+ * main.c (main): Simplified the print_last_wd handling slightly.
+
+Wed Dec 28 14:00:05 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_nc): Set the correct prompt even when we have
+ subshell support and have it disabled.
+
+ * screen.c (repaint_file): Small bug fix: use name trunc :-).
+
+ * input.c (update_input): Display control chars as a dot.
+
+Wed Dec 28 13:47:13 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (menu_edit_cmd): Fixed incorrect `count' argument to
+ `query_dialog' (was 3, now 2). This was corrupting the screen.
+
+ * util.c (msglen): Fixed a bug which was causing all the message
+ boxes to be one column too wide, by adding an `else' to the loop.
+
+Tue Dec 27 20:48:13 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (invoke_subshell): restart the subshell if it is
+ killed by a signal while performing the user's command.
+
+ (feed_subshell): don't exit if we get an I/O error reading from
+ the pseudoterminal; this error sometimes occurs just after the
+ shell has died, before we get a chance to restart it.
+
+ * main.c (do_execute, view_other_cmd): don't restart the subshell
+ with `init_subshell' if `invoke_subshell' fails; this is now done
+ in subshell.c instead.
+
+Mon Dec 26 12:47:40 1994 Miguel de Icaza <miguel@sphinx>
+
+ * setup.c (panel_save, panel_load): Load and save the user defined
+ format.
+
+ * main.c: got rid of the long_cmd and brief_cmd.
+
+ Changed the menus to use the new display_cmd for configuring the
+ display instead of the old menuing code.
+
+ * screen.c (set_panel_format): New function: used to change the
+ format display of a panel.
+
+ * user.c, main.c, setup.c, screen.c, panel.h: Got rid of the
+ obsolete VIEW_DISABLED constant and all its uses.
+
+ * screen.c: Added new display type: space.
+
+ * boxes.c: New file. Contains misc dialog boxes to be used by the
+ main program.
+
+ * widget.c (input_callback): Handles the ESC and F10 keys, as well
+ as the FOCUS and UNFOCUS commands.
+
+ * chown.c (init_chown), option.c (init_configure), chmod.c
+ (init_chmod): Use the centerwin routine.
+
+ * win.h (centerwin): New wonderful macro to get centered windows.
+
+Sun Dec 25 15:26:05 1994 Miguel de Icaza <miguel@sphinx>
+
+ * auto.c, chmod.c, chown.c, dir.c, main.c, mouse.c, gpm-xterm.c,
+ option.c, subshell.c, util.c, view.c: Fix to the header files to
+ include unistd.h only if available.
+
+ It seems that sys/types.h is present even if unistd.h is not.
+ Check this in all the ported architectures.
+
+Sat Dec 24 18:07:24 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c: Numerous changes to implement capturing of bash's
+ prompt for use on the MC command line.
+
+Fri Dec 23 01:34:48 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c: Added hotkey entries on the File menu for Link, Symlink
+ and Mask Rename, and on the Command menu for "Add to hotlist".
+
+Fri Dec 23 19:55:09 1994 Miguel de Icaza <miguel@sphinx>
+
+ * screen.c (parse_display_format, parse_panel_size): New functions
+ to parse the user provided screen format.
+
+Thu Dec 22 16:25:24 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (init_subshell): Removed the MC_PROMPT_COMMAND stuff,
+ to be replaced by a cleaner, faster and better method of switching
+ between MC and bash.
+
+ * main.c (view_other_cmd): Made some changes to add support for
+ the new way of switching to the shell and back.
+
+ (execute): Changed similarly. Now it refuses to run a command if
+ the shell is already running something else.
+
+Thu Dec 22 12:31:56 1994 Miguel de Icaza <miguel@sphinx>
+
+ * cons.saver.c (main): Changed the call to setpgrp to setsid, this
+ fixes the bug that killed both the child program and the
+ cons.saver program.
+
+ * util.c (my_system): Add handling for SIGCHLD signal.
+
+Wed Dec 21 13:21:37 1994 Miguel de Icaza <miguel@sphinx>
+
+ * option.c (configure_box): Small bug fix: now all the options are
+ checked.
+
+ * main.c (do_nc): Small change to fix the program seg faulting on
+ screens that are too small.
+
+ * util.c (name_trunc): Expanded the buffer size.
+
+ * main.c (do_search): Now we keep track of the search string in
+ the tree view.
+
+ * tree.c (search_tree): Now the function returns the status of the
+ search so that the do_search routine tracks the current search
+ string.
+
+Thu Dec 22 00:21:46 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * mc.bashrc: New file: a suggested "~/.mc.bashrc" for users.
+ It is worth thinking about whether a global version of this
+ file ($libdir/mc.bashrc) should be read also, or instead.
+
+ * subshell.c (init_subshell): Set up an environment variable
+ `MC_PROMPT_COMMAND', to store the value of `PROMPT_COMMAND' while
+ the latter is not being used.
+
+ * main.c (view_other_cmd): Modified so that, if the subshell is
+ enabled, C-o will not only let us view the shell output but switch
+ control to the shell altogether (using "unset PROMPT_COMMAND").
+
+Wed Dec 21 11:36:10 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c: Three small changes to help it compile under SunOS:
+ included errno.h, removed the sig_atomic_t type, and changed the
+ initialisation of the SIGCHLD signal action.
+
+ (init_subshell): MC now uses an alternative ".mc.inputrc" if it
+ exists, so that it is possible to have special `readline' options
+ for MC's bash subshell.
+
+ (invoke_subshell): Finally fixed the emacs corruption bug! It was
+ embarrassingly trivial: the tty needed to have OPOST mode disabled.
+
+Mon Dec 19 15:02:07 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (menu_edit_cmd): There are no longer local menus.
+ (init_panels): Free the other_dir variable only if it has been
+ allocated.
+
+ * util.c (my_statfs): Better statfs support. We will only do the
+ statfs call on systems we know how to handle.
+
+Mon Dec 19 16:52:06 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c: Sundry small changes.
+
+ (feed_subshell): Changed return type to void.
+
+ (invoke_subshell): Fixed CWD handling: now bash changes to MC's
+ working directory, if necessary, before running the user command.
+
+Sun Dec 18 11:10:01 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (view_cmd): Removed superfluous variable `command'.
+
+ * util.c: Removed all the (now unnecessary) references to the
+ subshell stuff.
+
+ * subshell.h: Added a declaration for the new global variable
+ `bash_prompt', which always contains bash's latest prompt when
+ the functions `init_subshell' and `invoke_subshell' return.
+
+ * main.c (do_execute): Fixed up the call to `invoke_subshell'.
+ (action): Removed superfluous variable `newdir'.
+
+ * main.h: Removed extern declaration of use_subshell because it is
+ already declared in subshell.h.
+
+Sat Dec 17 16:06:51 1994 Miguel de Icaza <miguel@sphinx>
+
+ * setup.c (done_setup): New function that shutdowns the setup module.
+
+ * terms.c: do_enter_ca_mode now enters putp's the enter_ca_mode to
+ the screen. Moved from main to avoid name space pollution, this
+ should make the A/UX port work.
+
+ * util.c: statfs structure definition moved from main.
+
+ * main.c: Load correctly the directory structure. Moved the stat
+ definition structures to util.c
+
+ * mouse.c (mouse_log): New function used to debug the mouse event
+ handling.
+
+ * mouse.h: New macros to debug the event/frame pushing popping
+ mechanism.
+
+ * screen.c (init_panel): Sets the information panel correctly and
+ load the stat information before displaying them.
+
+ (display_mini_info): Clean properly the display area when there
+ are tagged files.
+
+ * configure.in: Added check for statfs function.
+
+ * main.c (do_nc): Shutdown properly the setup managing code.
+
+Fri Dec 16 16:53:05 1994 Miguel de Icaza <miguel@sphinx>
+
+ * dlg.c (destroy_dlg): Fixed memory leak in the dialog manager.
+
+Fri Dec 16 15:36:58 1994 Jon Stevens <root@dolphin.csudh.edu>
+
+ * Ported to A/UX. Added ifdefs for A/UX in some of the files.
+ Detect A/UX when configuring.
+
+Fri Dec 16 15:36:58 1994 Miguel de Icaza <miguel@sphinx>
+
+ * dir.c, find.c: Use the proper defines to get the dirent file
+ (change DIRENT -> HAVE_DIRENT_H and the like.
+
+ * main.c (mask_ren_cmd): Fixed the rename mask command finally.
+
+Fri Dec 16 13:46:24 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * main.c (main): Moved the `print_last_wd'-handling code to just
+ before the call to init_subshell, to make "mc -P" work again.
+
+ * subshell.c (sigchld_handler): Sets `quit' to the special value
+ BASH_EXIT if the user has typed "exit" or "logout" in bash.
+
+ * main.c (main, do_nc, enter): Made certain parts of the shutdown
+ code conditional on having quit the program from bash, rather than
+ by using F10, to make MC exit cleanly in this case. (Done using
+ the BASH_EXIT constant described above.)
+
+ * subshell.c (feed_subshell): If you typed a command, pressed
+ Enter and hit some keys instantly afterwards, they would corrupt
+ the command. Fixed this by making `feed_subshell' not read from
+ the keyboard if called with the QUIETLY option.
+
+Thu Dec 15 15:42:29 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_execute): Was execute. Now, allow for 2 classes of
+ program execution: normal programs and commander programs.
+
+ (load_hotlist): Freed hotlist loaded data.
+
+ (do_search): Fixed bug: if we didn't find the file name, continue;
+
+ (mask_ren_cmd): Compute the correct size for the destination
+ string (sprintf).
+
+ * util.c (my_system): Allow execution of programs without the
+ shell (for the editor and view commands).
+
+Thu Dec 15 13:44:58 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * subshell.c (sigchld_handler): New function and changes to allow
+ us to react appropriately if the subshell is suspended or dies.
+
+ (feed_subshell): This now takes an argument `how', which can be
+ either QUIETLY or VISIBLY, to control whether the subshell's
+ output goes to the screen.
+
+Wed Dec 14 15:20:01 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_search): Don't add to the search string if we can't
+ find the current string.
+
+ * screen.c (display_mini_info): Clean the win_file window before
+ painting the %s bytes in %d files message.
+
+ * main.c (view_other_cmd): Put the cursor at the right place after
+ viewing the alternate screen.
+
+ * chown.h, chown.c (chown_cmd): Changed return type from int to void.
+
+ * chmod.h, chmod.c (chmod_cmd): Changed return type from int to
+ void.
+
+Wed Dec 14 13:18:19 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * Most source files: Trivial fixes to remove compiler warnings.
+
+Tue Dec 13 18:48:20 1994 Dugan O. Porter (dugan@b011.eunet.es)
+
+ * util.c (my_system): This function was temporarily blocking
+ SIGCHLD. I think this cannot have any effect (someone please
+ correct me if I'm wrong), since MC defines no handler for SIGCHLD,
+ and this signal is ignored by default. So I removed the block,
+ because subshell.c needs to do its own SIGCHLD handling.
+
+Mon Dec 12 22:28:23 1994 Dugan Porter <dugan@b011.eunet.es>
+
+ * main.c: Some spelling corrections.
+
+ (execute): Only load the user shell once. Changes for working
+ with the subshell stuff.
+
+ * subshell.c, subshell.h: New files: used to implement the
+ concurrent shell running with the Commander.
+
+Mon Dec 12 22:10:54 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * key.c, mem.h, tree.c: changes to allow compilation under AIX.
+
+Fri Dec 9 11:53:48 1994 Miguel de Icaza <miguel@sphinx>
+
+ * wtools.c (query_dialog_new): Moved function from dlg.c
+
+ * wtools.c, wtools.h: renamed from listbox.c and listbox.h. They
+ now will contain utility functions based on the dialog manager.
+
+ * help.c (interactive_display): Added support for going back on
+ the help history with the mouse.
+
+ * dlg.c (dlg_new): Correct the order in which the events are
+ pushed. This fixes a bug with out of dialog events being sent to
+ previous mouse handlers.
+ (destroy_dlg): Added extra pop_event.
+
+Thu Dec 8 20:08:55 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_nc): Redisplays the mini info when we have aborted a
+ search.
+
+Fri Dec 9 16:29:33 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * chmod.c: bug fix - bad call of chmod_init
+
+ * mc.1: chmod command documentation wrote.
+
+Wed Dec 7 21:40:04 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * chown.c: continue working on this stuff, now we have first
+ working version - I have found a bug in chmod, try to catch this bug
+
+Wed Dec 7 20:43:17 1994 Miguel de Icaza <miguel@sphinx>
+
+ * widget.c (check_event, check_callback): Added mouse support to
+ checkboxes.
+ (radio_event, radio_callback): Added mouse support to radio buttons.
+
+Wed Dec 7 20:23:52 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * find.c: Some changes to use static arrays instead of dynamically
+ allocated arrays. We will use this code while we fix the find
+ command.
+
+ * mem.h: On AIX, use rindex.
+
+ * gpm-xterm.c, key.c: On AIX, include sys/select.h
+
+Wed Dec 7 20:20:27 1994 Dugan Porter <dugan@b011.eunet.es>
+
+ * tree.c: Made internal functions static.
+
+ (tree_append_entry): New function, which is just like
+ tree_add_entry except that the entry always goes onto the end of
+ the list.
+
+ I left out the initial consistency check for tree_last->next
+ being NULL; there seem to be no bugs left in tree.c so I hope
+ it's not necessary (touch wood)!
+
+ I left out the final check that the parent dir is in the list,
+ because I assume that a directory is never saved in .mc.tree
+ without its parent being saved also.
+
+ Removed all references to the "dotdir" variable, which doesn't
+ seem to be used for anything.
+
+ I changed abort() so it doesn't take an argument
+
+ I made a few functions static that aren't called by any other
+ source files, and don't seem likely to be in the future (e.g.
+ back_ptr), to reduce namespace pollution. (In fact, the decls
+ for these functions could be left out of tree.h as well...)
+
+Mon Dec 5 11:24:31 1994 Miguel de Icaza <miguel@sphinx>
+
+ * user.c (user_menu_cmd): Don't use the local directory menu file.
+
+ * util.c (my_statfs): Moved the blocks2kilos and my_statfs from main.
+
+Sun Dec 4 17:11:24 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (execute): Cosmetic change: don't use a space between
+ prompt and command.
+
+ * widget.c (listbox_draw): Now the cursor tracks the selection on
+ listbox widgets.
+
+ * main.c (execute): Output the prompt and the command to be executed.
+
+ * input.c (forward_word): Allow skipping over punctuation chars.
+
+ * mc.1: updated documentation on key bindings.
+
+ * user.c (user_menu_cmd): Get rid of the old menuing code.
+
+ * chmod.c (chmod_cmd): Fixed a couple of function spelling errors
+ :-).
+
+Sun Dec 4 10:28:46 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * chmod.h: next_file, stat_file make available for chown.c
+
+ * chmod.c: not alloc memory for sf_stat - use local variable staying
+ on the stack make some functions static.
+
+Sat Dec 3 16:29:57 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * new files: chown.h, chown.c - New ChOwn command for changing
+ owner and group of file. This use new Listbox widget.
+
+ * chmod.c: rewritten, implement new features supposed by Miguel,
+ these are [ Set marked ] [ Clear marked ],
+ when only one file to proceed - only [ Set ] and [ Cancel ] displayed
+
+Sun Dec 4 16:29:22 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_nc): The prompt is set according to the EUID.
+ (ext_cmd, menu_edit_cmd): Use the EUID instead of the UID.
+
+Sun Dec 4 16:20:21 1994 Thomas Pundt <pundtt@math.uni-muenster.de>
+
+ * win.c (push_fkeys, pop_fkeys): push null mouse events so that we
+ don't get the previous behavior from the mouse events when
+ entering/leaving a new mode (This fixes this bug: View file, click
+ on F9, you get the pull down menu from the inside of the viewer).
+
+Fri Dec 2 13:39:34 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * Makefile.in: Added cons.handler.c to SRCS and cons.handler.o to
+ OBJS.
+
+ * TODO: Removed obsolete entries: regular expressions in extension
+ file are now implemented and the cons.saver now supports Linux
+ 1.1.67. Fixed a typo.
+
+ * cons.handler.c: A new file which includes the handle_console
+ function from main.c. This should make it easier to include
+ cons.saver functionality to other programs.
+
+ * cons.saver.c: A title line change: Not MC specific anymore.
+
+ * cons.saver.h: Added prototypes for the handle_console function
+ and the console_flag variable in the cons.handler.c.
+
+ * ext.c (regex_command): Now supports regular expressions in the
+ extension file.
+
+ * input.c (assign_text): Now global function instead of static
+ (required by the history_cmd function in main.c).
+
+ * main.c: Includes dlg.h, widget.h and listbox.h. New struct
+ hotlist. The handle_console function moved to the new
+ cons.handler.c file.
+
+ (move_left, move_right): If the tree view is active the left and
+ right move to parent and child directory even in the old
+ navigation mode.
+
+ (history_cmd): A new function which implements command history popup.
+
+ (add2hotlist, load_hotlist, save_hotlist): New functions for the
+ directory hotlist feature.
+
+ (add2hotlist_cmd): A new function which adds current directory to
+ the directory hotlist.
+
+ (quick_chdir): Now shows a directory hotlist popup instead of
+ builtin choices.
+
+ (CmdMenu): Added "command History", "Add to hotlist" and
+ "Directory hotlist".
+
+ (copy_prog_name, copy_other_prog_name, copy_other_pathname):
+ Better support for tree view mode.
+
+ (do_nc): Now loads and saves the directory hotlist.
+
+ * mc.1 (Directory Panels): Updated meaning of
+ control-backslash. (Command Menu): Documented "Command history",
+ "Add to hotlist" and "Directory hotlist". (Extension File Edit):
+ Documented support for regular expressions. (Menu File Edit):
+ Cleared up the explanation for <pattern> in the Default conditions
+ part. (FILES): Added $HOME/.mc.tree and $HOME/.mc.hotlist.
+
+ * setup.c: Now includes tree.h. (options): Added option
+ tree_navigation_flag.
+
+ * tree.c (move_to_child): Now rescans directory before moving to
+ its child.
+
+Thu Dec 1 15:49:39 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (ext_cmd): If running as root, let the user edit the
+ system wide extension file or the user file.
+
+ * input.c: Support for M-C-Backspace
+
+ * key.c (mi_getch): Support for M-C-h and M-Backspace
+
+ * listbox.c (create_listbox_window): New argument: help context.
+
+ * user.c (user_menu_cmd): Set the correct help context.
+
+Thu Dec 1 15:49:39 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * chmod.c: _AIX also needs the umode_t define.
+
+Thu Dec 1 15:30:09 1994 Dugan O. Porter <dugan@b011.eunet.es>
+
+ * dialog.c (create_dialog): Center correctly the dialog titles.
+
+ * main.c (copy_cmd): Removed extra spaces from strings.
+
+Wed Nov 30 11:21:34 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * cons.saver.c: The actual console saving and restoring code put
+ to their own functions save_console and restore_console. Now uses
+ ioctl TIOCLINUX subfunctions 8 and 9 if Linux version is >=
+ 1.1.67. Added some comments and more debugging output.
+
+ * main.c (paint_info_panel): Uses the new is_idle function to skip
+ painting if there is no time.
+
+ * util.c, util.h: Added a new is_idle function. Most of its code
+ is originates from view.c (do_view).
+
+ * view.c: No need to include <sys/time.h> anymore. (goto_line):
+ Now shows the current line number when asking the new line
+ number. (do_view): Now uses the new is_idle function instead of
+ the old select trickery. The automatic adjusting of the dirt_limit
+ variable in pace of incoming keypresses is more precise now.
+
+ * chmod.c: The umode_t type is not defined on Solaris.
+
+Tue Nov 29 15:54:13 1994 Miguel de Icaza <miguel@sphinx>
+
+ * color.c (init_colors): Start colors only if the user requested
+ so (if use_colors instead of if hascolors).
+
+ * user.c (user_menu_cmd): Removed test that didn't let us use more
+ that LINES-6 menu entries.
+
+ * terminfo/xterm.ti: The reset option on xterm_color uses the
+ cancel escape sequence instead of setting an arbitrary color.
+
+ * dlg.c (run_dlg): Many changes so that all dialog callback
+ functions get the extra Dlg_head * parameter.
+
+ * dialog.c (push_refresh, do_refresh): Refresh functions now can
+ take an extra parameter that is passed when a refresh is required.
+ Changed in all the refresh functions in the program.
+
+ * dlg.c (dialog_handle_key): Added support for repainting the
+ screen.
+
+ (dlg_broadcast_msg): New function to send a message to all the widgets.
+
+ * option.c (configure_callback): New: painting the widget is done
+ in the dialog callback (Message DLG_DRAW).
+
+ * dlg.c (dialog_handle_key), dlg.h: Added support for context
+ sensitive help.
+
+Tue Nov 29 14:37:49 1994 Radek Doulik <rodo@earn.cvut.cz>
+
+ * chmod.c: updated, attribute setting/clearing has changed. No
+ ChangeLog entries yet.
+
+Tue Nov 29 14:17:40 1994 Miguel de Icaza <miguel@sphinx>
+
+ * user.c (user_menu_cmd): Fix: select the default entry
+
+ * main.c (main): Fix: other dir argument is now used instead of the
+ value from the init file.
+
+Tue Nov 29 13:47:52 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * mc.1: Updated: Save Setup is now under the Options menu, not the
+ Commands menu. The old text of Options section moved to new
+ Configuration section. The Undocumented Features section renamed
+ to Special Settings section. All settings which can't be changed
+ from the menus moved to the Special Settings section.
+
+ * ChangeLog, INSTALL, INSTALL.FAST, NEWS, README, TODO, mc.1: Ran
+ through ispell and corrected spelling errors (there was no errors
+ in the INSTALL.FAST file).
+
+ * cons.saver.c (main): Now correctly loses the control terminal
+ (by calling setpgrp). Added some comments.
+
+ * screen.c (display_mini_info): No longer reports <readlink
+ failed> if current directory is different than panel->cwd.
+
+Mon Nov 28 13:45:48 1994 Miguel de Icaza <miguel@sphinx>
+
+ * listbox.c (run_listbox): Do proper shutdown of window.
+
+ * gc.c: deleted.
+
+ * view.c (load_view_file): Use free instead of gc_free.
+
+ * user.c (user_menu_cmd): Use free instead of gc_free.
+
+ * tree.c (do_tree_check, load_tree, save_tree): Use free instead of gc_free.
+
+ * setup.c (load_setup): don't uses free anymore.
+
+ * main.c (action, enter, view_cmd, do_edit, ext_cmd,
+ menu_edit_cmd): don't use gc_free, gc_free_now.
+
+ * util.c (copy_strings): Don't use the gc_* functions any more,
+ uses standard malloc.
+
+ * file.c (recursive_erase, copy_dir_dir, move_file, move_dir_dir,
+ erase_dir): don't use gc_free, gc_free_now.
+
+ * configure.in (LDFLAGS): Fix: Do not set DEFS manually, use
+ AC_DEFINE, this fixes the problem with selecting group of files in
+ Solaris.
+
+ * widget.c (listbox_callback): Return the handled/unhandled return
+ code on WIDGET_KEY so we can finish the dialog.
+
+ (listbox_select_entry): Return after finding the entry; advance
+ the top selection only if the selected item is outside the visual
+ area.
+
+Sun Nov 27 16:55:13 1994 Miguel de Icaza <miguel@sphinx>
+
+ * widget.c (listbox_callback, listbox_key, listbox_cdiff,
+ listbox_append_item, listbox_add_item): Implemented the listbox
+ widget.
+
+ * listbox.c (create_listbox_window, run_listbox): Creates a
+ listbox window, this function uses the dialog manager and the
+ listbox widget. run_listbox is used to run the simple listbox
+ objects.
+
+ * user.c (user_menu_cmd): Now the menu uses copy_strings instead
+ of the static buffer.
+
+ (user_menu_cmd): Use the new listbox manager instead of the old
+ menuing code.
+
+ * option.c: Made local variables static.
+
+Fri Nov 25 12:16:05 1994 Miguel de Icaza <miguel@sphinx>
+
+ * util.c (find_mountpoint, find_device): Moved from main.
+
+ * ncurses.h (USE_BSD_CURSES): Changes to let the program compile
+ without ncurses, this is not working yet.
+
+ * configure.in (XCURSES): Allow for configuration of the program
+ with bsd curses instead of ncurses, not very nice.
+
+ * xcurses.c (x_getch): New function: used to implement the missing
+ ungetch in the bsd curses.
+
+ * key.c, main.c: use xgetch instead of getch. with ncurses xgetch
+ is defined as getch, with bsd curses xgetch is defined as x_getch.
+
+ * main.c (my_statfs): Don't set the volname attribute, it no
+ longer exists.
+
+Fri Nov 25 16:14:50 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * dlg.c (dlg_one_up): remove send msg WIDGET_DRAW, I don't know
+ why it was here, but it causes check buttons doesn't work properly
+
+ * chmod.c: [Mark all] now works with no file selected
+
+Thu Nov 24 13:18:42 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (view_cmd): If you have tagged files, and press F3 and
+ have the new confirm_view_dir variable set, then you are asked for
+ confirmation.
+
+Thu Nov 24 13:39:34 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * main.c (change_labels): F4 is now "Navig" in the tree mode. F5
+ and F6 are no longer cleared.
+
+ (move_left, move_right): Now support the new tree navigation mode.
+
+ (key_f4_cmd): A new function. Toggles the navigation mode in the
+ tree view mode and invokes the edit command otherwise.
+
+ (copy_cmd, ren_cmd): Now work also in the tree view mode.
+
+ (init_labels): F4 corresponds to key_f4_cmd, not to edit_cmd.
+
+ * main.h: Added declaration of the cmd_buf variable.
+
+ * mc.1 (Directory Tree): Documented the new features: Navig, Copy
+ and RenMov.
+
+ * tree.c: A new global variable: tree_navigation_flag, which is
+ used for toggling between the new navigation mode and the old
+ navigation mode.
+
+ (whereis): Now returns NULL if not found, not the closest
+ match. Added some speed enhancements which are currently commented
+ out because they don't work yet.
+
+ (tree_add_entry): Added some speed enhancements which are
+ currently commented out because they don't work yet. After adding
+ an entry now tries to add the parent directory of the entry, too.
+
+ (tree_remove_entry, start_tree_check, tree_chdir): Changes related
+ to the new behaviour of the whereis function.
+
+ (show_tree, tree_move_backward, tree_move_forward): Now support
+ the new navigation mode.
+
+ (tree_move_to_child, tree_move_to_parent): New functions.
+
+ (tree_event): Mouse doesn't work in the new navigation mode yet.
+
+ (toggle_nav_mode, tree_copy, copy_cmd, tree_move, move_cmd): New
+ functions.
+
+ (win_init): The F4, F5 and F6 keys work now.
+
+ (tree): The left arrow moves to the parent directory and the right
+ arrow moves to the child directory.
+
+ * tree.h: Added tree_copy, tree_move, tree_move_to_parent,
+ tree_move_to_child and tree_navigation_flag.
+
+Wed Nov 23 12:24:11 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (suspend_cmd): After coming back from suspend, redraw the
+ screen.
+ (do_nc): Understands the LINES variable.
+
+Wed Nov 23 14:51:16 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * dlg.c: "#include <stdarg.h>" was still missing.
+
+ * main.c (find_mountpoint, find_device): New
+ functions. (my_statfs): Now uses the find_mountpoint and
+ find_device functions. Now works to some degree also on machines
+ which don't have statfs.
+
+ (do_cd): Changed the condition under which the my_statfs function
+ is called.
+
+ (switch_to_info): The my_statfs function is now called always.
+
+ (paint_info_panel): Some reorganization and changes.
+
+ (do_search): The search can wrap now.
+
+ (view_cmd): If trying to view a directory, now changes to the
+ directory. Very handy if there is something on the command line and
+ the enter key can't therefore be used.
+
+ (delete_cmd): The confirm_delete option works now also in the tree
+ view mode.
+
+ (quick_chdir): Should now work in tree view mode. Not tested!
+
+ * tree.c: Now includes the main.h file. (show_tree): Long
+ directory names are now truncated. (search_tree): The search can
+ wrap now.
+
+ (rmdir_cmd): The confirm_delete option works now. Added some
+ chdir-tricks.
+
+Tue Nov 22 15:21:59 1994 Miguel de Icaza <miguel@sphinx>
+
+ * auto.c (do_exec_mount): Little bug fix.
+
+ * dlg.c (query_dialog_new): Changed: use stdarg.h instead of
+ varargs.h, va_start takes two parameters.
+
+ * widget.c (button_callback, button_event (new)): Mouse support
+ for button widgets.
+
+ * dlg.c (dlg_one_up): New function: use by the widgets to select
+ themselves before sending a message to themselves, since they use
+ the h->current value to determine exactly who they are. Must
+ change this so that Dlg_Head is never sent to a Widget, now we
+ have the parent field that can be used to refer to the owner of
+ the dialogs.
+ (add_widget): Now, each widget knows the pointer to his parent.
+
+ * main.c (do_nc): Ok, now slow terminals are those that run under
+ 9600 bauds.
+
+Tue Nov 22 15:40:41 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * dlg.c: Added missing "#include <varargs.h>". (query_dialog_new):
+ The va_start macro only takes one parameter.
+
+ * main.c (blocks2kilos): A new function. (my_statfs): The fs_stats
+ variable is now static. The avail and total fields are now in
+ kilobytes instead of bytes to avoid overflow. (paint_info_panel):
+ The file name and the file system name are now passed through
+ the name_trunc function. Sizes are passed through the
+ wprint_bytesize function.
+
+ * tree.c (tree_remove_entry, start_tree_check, do_tree_check,
+ end_tree_check): The subdirectory check is correct now. For
+ example, no longer thinks that /devices is a subdirectory of /dev.
+
+ (show_tree): No longer segfaults when calculating the topsublevel
+ variable if the tree is empty.
+
+ (tree_forget_cmd): The old code replaced by a call to the
+ tree_remove_entry function.
+
+ * win.c (wprint_bytesize): A new function for printing file sizes
+ etc.
+
+ * win.h: Added wprint_bytesize.
+
+Mon Nov 21 17:01:40 1994 Miguel de Icaza <miguel@sphinx>
+
+ * option.c: Added new options 8bit clean and automount to the
+ option configuration dialog
+
+ * chmod.c (chmod_file): Small bug fix, init the c_file variable.
+
+ * main.c (do_cd): Added missing initialization of dirs_marked.
+ (unmark_file): Added missing cleaning of dirs_marked.
+
+ * dialog.c (input_dialog): Fixed problem with lines bigger than
+ the initial string.
+
+ * util.c (my_system): If user doesn't have a default shell, run
+ the shell specified in the SHELL environment variable.
+
+ * main.c (execute): Added missing endpwend.
+
+Mon Nov 21 10:59:55 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * file.c (recursive_erase): fixed bug, didn't call closedir.
+
+ * main.c (reverse_selection): New function.
+
+Fri Nov 18 11:43:01 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (update_panels, repaint_screen, swap_cmd): Correct order
+ of redraw: First update the other_panel and then the current_panel.
+
+Sat Nov 19 13:12:39 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * INSTALL: Removed documentation for the --with-screen-restore
+ option. Documented the 'make install.saver' command.
+
+ * Makefile.in: Removed the prog_mode variable.
+
+ * Configure.in: Removed the --with-screen-restore option as
+ obsolete.
+
+ * cons.saver.c (detect_console): Oops, I was checking the st_dev
+ field instead of the st_rdev field. No wonder it didn't work on
+ others' machines. (main): Some changes to help debugging.
+
+ * input.c (destroy_input): Now also destroys the history.
+
+ * mad.c (mad_alloc, mad_realloc): Now corrects the
+ alignment. (mad_finalize): Outputs the memory leaks.
+
+ * main.c (my_statfs, select_item, do_cd, paint_info_panel,
+ switch_to_info): Now there is some information in the info panel.
+
+ (handle_console): The standard error of the child is redirected to
+ /dev/null.
+
+ (done_panels, done_menu, do_nc): Clean up memory leaks.
+
+ (action): Don't free NULL pointer.
+
+ * mouse.c (init_mouse): Removed an extra push_frame.
+
+ * profile.c (free_keys, free_sections, free_profile,
+ free_profiles): Clean up memory leaks.
+
+ * profile.h: Added free_profiles.
+
+ * tree.c: Removed the base_dir variable as
+ unnecessary. (destroy_tree): Cleans up memory leaks.
+
+ * tree.h: Added destroy_tree.
+
+ * ext.c (exec_extension), user.c (execute_menu_command): Oh no, I
+ was using the dreadful goto command. Am I doomed now?
+
+ * view.c (goto_line): Small fixes.
+
+Sat Nov 19 20:10:08 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * chmod.c (chmod_callback): fix the problem with 'M' key -
+ replaced with 'T' key
+
+ * widget.c: fix in hotkey code for unify 'LwrCase'='UpCase'
+
+ * dlg.h: added DIR_FORWARD, DIR_BACKWARD - for dialog directions,
+
+ * dlg.c: allow change direction of circling the widget buffer
+ in order as they was inserted or reversed order (default)
+
+ (std_callback) use it as default callback does nothing,
+
+ (query_dlg_new) prepared to replace query_dlg function with this new
+ one using new dialog manager (after adding mouse support)
+
+Thu Nov 17 15:23:24 1994 Miguel de Icaza <miguel@sphinx>
+
+ * color.c (configure_colors), setup.c (load_setup): New colors per
+ terminal
+
+Thu Nov 17 15:01:40 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * tree.c (do_tree_check): Fixed bug.
+
+Thu Nov 17 17:27:00 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * widget.c widget.h: add hot key support to button
+ and check button, change in call button_new, check_new
+
+ * dlg.c dlg.h: add dialog custom colors, support hot keys
+ new WIDGET_HOTKEY message, change in call dlg_new
+
+ * option.c chmod.c: updated to use custom colors and hot keys
+
+Thu Nov 17 13:18:28 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * Makefile.in: Added mad.c to SRCS. Added mad.h to HDRS. Added
+ mad.o to OBJS.
+
+ * auto.c: Changed the title.
+
+ * All the *.c files but the cons.saver.c and man2hlp.c file: Now
+ include the mad.h file.
+
+ * mad.c, mad.h: New files which implement the Memory Allocation
+ Debugging system.
+
+ * main.c (main): Now calls the mad_finalize function as the last
+ thing before exit.
+
+ * mc.1 (Menu File Edit): Now documents the 't' type. (Macro
+ Substitution): Now documents the %u and %U macros. (AUTHORS):
+ Fixed a small typing mistake.
+
+ * mc.menu: Documented the 't' type and the %t, %T, %u and %U
+ macros.
+
+ * tree.c: (back_ptr, forw_ptr, show_tree): Now work better if the
+ selected_ptr variable happens to be NULL (it is NULL only if
+ the whole tree deleted with the 'forget' or 'delete' command).
+
+ * user.c (expand_format): Now supports the %u and %U
+ macros. (test_type): Now supports the 't' type.
+
+ * util.c (xmalloc), util.h (xmalloc): The xmalloc function is
+ compiled only if the MAD system is not used.
+
+ * view.c (goto_line): A new function to go to the specified
+ line. (init_view): Binds the goto_line function to the f5 key.
+
+Wed Nov 16 14:47:59 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * dir.c (set_zero_dir): When assigning to the fname field, use
+ strdup instead of a static constant.
+
+Wed Nov 16 09:52:36 1994 Miguel de Icaza <miguel@sphinx>
+
+ * util.c (tilde_expand): Doesn't use gc_alloc anymore.
+
+ * dialog.c (input_expand_dialog): Adapted to use the new
+ tilde_expand without using the gc.
+
+ * find.c (find_dialog): Remember the last searched expression.
+
+Tue Nov 15 15:52:28 1994 Fred Leeflang <fredl@nebula.ow.org>
+
+ * main.c: copying multiple files to an unexisting dest will now treat
+ dest as a directory, create it for you and copy the files/dirs
+ there. copying dirs/files to an unexisting dir now actually works.
+
+Tue Nov 15 11:40:42 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * ext.c (exec_extension), user.c (execute_menu_command): Now
+ support the %{...} macro.
+
+ * input.h: Changed the definition of the XCTRL macro.
+
+ * main.c (do_search, start_search, do_nc): Searches start from the
+ current point, not from the beginning. Pressing C-s again searches
+ the next match.
+
+ (mask_ren_cmd): A new function which implements the mask rename.
+
+ (compare_dir, compare_dirs): New functions which implement the
+ Compare Directories command.
+
+ (quick_chdir): A new function which implements the changing of
+ the directory to the home or the root on the C-\ press.
+
+ * mc.1 (Directory Panels): Documented the C-\ key. Mentioned that
+ C-s can be used to search again. (File Menu): Documented the Mask
+ Rename command. (Command Menu): Documented the Compare Directories
+ command. Replaced "View other screen" with "Panels
+ on/off". (Directory Tree): Removed some out of date
+ remarks. (Macro Substitution): Documented the %{...} macro.
+
+ * mc.menu: Changed the K-entry to use the %{...} macro.
+
+ * tree.c (search_tree): The focus is now checked at the correct
+ moment.
+
+Mon Nov 14 09:28:20 1994 Miguel de Icaza <miguel@sphinx>
+
+ * gpm-xterm.c: passed the source trough indent -pcs -kr
+
+ * screen.c (string_file_type, string_file_permission,
+ string_file_nlinks, string_file_owner, string_file_group,
+ string_file_size, string_file_mtime, string_file_atime,
+ string_file_ctime, string_file_name): New functions, to be used by
+ the new user configurable screen display.
+
+ * main.c (long_cmd): New behavior: allow user to have long panels
+ mixed with normal panels, there is a little flicker produced by
+ the new behavior but is not that bad.
+
+ (init_panels): Update the panels in this order: opanel, cpanel, to
+ remove some flicker.
+
+ (only_refresh_screen): Refresh screen in this order: opanel,
+ cpanel to avoid some flicker
+
+ (untouch_bar): Changed the order of refresh.
+
+ (execute): If running on the console (and cons.saver is running),
+ then don't ask for a keystroke after executing a command.
+
+ * user.c (menu_input_loop): Upper case letters and lower case
+ letters are different
+
+ * file.c (recursive_erase): Leave directory ".." alone.
+
+Mon Nov 14 14:36:12 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * dialog.c (input_dialog), find.c (input_find, do_load_find_menu,
+ find_dialog), main.c (copy_cmd), menu.c (get_motion), user.c
+ (menu_input_loop): Now you can cancel with both ESC and F10. Use
+ of F10 gets rid of the slight delay after an ESC press.
+
+ * file.c (erase_file, erase_dir): Now the error messages tell what
+ the MC was trying to erase. The recursive delete now works also on
+ Solaris which uses error number EEXIST instead of ENOTEMPTY.
+
+ * help.c: The quit variable is now file wide static instead of
+ function wide auto. New functions: help_cmd, index_cmd,
+ quit_cmd. (interactive_display): The function key labels now work
+ with mouse.
+
+ * main.c (change_labels): A new function to change the function
+ key labels when changing to the tree view mode and
+ back. (change_panel, tree_leave, tree_view_cmd): Now call the
+ change_labels function.
+
+ (panel_event): Now works more often when in the tree view mode.
+
+ (key_f2_cmd, key_f3_cmd): New functions which select the correct
+ action depending on whether the tree view mode is active.
+
+ (delete_cmd): Now behaves better when deleting the directories in
+ the tree view mode.
+
+ (tree_cmd): Now behaves better when the tree view mode is active.
+
+ (init_labels): The user_menu_cmd and view_cmd functions replaced
+ with the key_f2_cmd and key_f3_cmd functions.
+
+ * mc.1 (Directory Tree): Small changes in the wording. Now up to
+ date with new features. (Menu File Edit): Now up to date with the
+ new behaviour and features.
+
+ * mc.menu: Now up to date with the new behaviour and features of
+ the user menu condition feature.
+
+ * screen.c (display_mini_info): Simplified the way how the search
+ string is output.
+
+ * tree.c: The tree_entry structure is now defined in the tree.h
+ file. The top and selected variables deleted as unnecessary. New
+ variables: topdiff and check_sublevel. The variables check_name
+ and check_start are now static. New functions: back_ptr, forw_ptr,
+ win_init, win_done.
+
+ (tree_add_entry): Now return a pointer to the added entry. The
+ mark field is cleared.
+
+ (remove_entry): If removing the selected entry selects the next or
+ previous entry so that there will always be an existing selected
+ entry.
+
+ (tree_remove_entry): Removes the whole subtree instead of just one
+ directory.
+
+ (start_tree_check, do_tree_check, end_tree_check): Now using the
+ mark field. A lot of other miscellaneous changes. Should be working
+ correctly now (no orphan directories anymore).
+
+ (show_tree, tree_move_backward, tree_move_forward,
+ tree_move_to_top, tree_move_to_bottom, tree_init, tree_event,
+ search_tree): Now using the selected_ptr and topdiff variables
+ instead of the old selected and top variables.
+
+ (check_focus): Simplified.
+
+ (tree_chdir): Now uses the whereis function.
+
+ (help_cmd, tree_rescan_cmd, tree_mkdir_cmd, rmdir_cmd): Now using
+ the win_init and win_done functions.
+
+ (tree_forget_cmd): Now forgets the whole subtree instead of just
+ one directory.
+
+ (tree.c): Now using the win_init and win_done functions.
+
+ tree.h: The tree_entry structure is now defined here. Added the
+ mark field to the tree_entry structure. Added the tree_forget_cmd
+ function.
+
+ user.c: Divided the conditions to two subtypes: the default
+ conditions and the addition conditions. The addition conditions
+ behave like the old conditions. The default conditions can be used
+ for specifying the default menu entry. See the manual page.
+
+ * ChangeLog: Replaced the occurrences of the Finnish word 'Ups'
+ with the corresponding English word 'Oops'.
+
+Sun Nov 13 09:53:30 1994 Radek Doulik <rodo@RoDo-Station>
+
+ * chmod.c (chmod_file): change getting owner and group name using
+ functions in util.c, change length of printed strings
+
+Sat Nov 12 15:34:50 1994 Miguel de Icaza <miguel@sphinx>
+
+ * file.c (erase_dir): Fixed bug that was deleting directories even
+ if the user selected the no option.
+
+ * main.c (delete_cmd): Added recursive delete on tagged directories
+
+ * file.c (recursive_erase): Use lstat instead of stat for checking
+ the file information.
+
+Thu Nov 10 23:37:04 1994 Miguel de Icaza <miguel@sphinx>
+
+ * mouse.c (push_event): new parameter: options, currently accepts
+ event_absolute and event_use_frame.
+
+ * dialog.c, help.c, main.c, menu.c, tree.c, view.c: when calling
+ push_event specify event_use_frame.
+
+ * win.c (define_label, define_label_quit): use event_absolute to
+ define the mouse bindings.
+
+Thu Nov 10 13:21:50 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * dir.c (handle_dirent, do_load_dir, do_reload_dir): Added calls
+ to the start_tree_check, do_tree_check and end_tree_check
+ functions to achieve transparent tree update.
+
+ * help.c (interactive_display): Now shows a function key bar of
+ its own.
+
+ * main.c (action): Now uses cpanel->cwd instead of a tree_selected
+ call.
+
+ (enter): Typing 'cd' commands on the command line now works also
+ if the current panel is in the tree view mode.
+
+ (delete_cmd): Now works in the tree view mode.
+
+ (tree_cmd): Now works even if the tree view is already active,
+ just doesn't change directory in such case.
+
+ (tree_leave): A new function which is called when leaving the tree
+ view mode. Tries to chdir to the last selected directory.
+
+ (full_cmd, brief_cmd, info_cmd, long_cmd): Now using tree_leave
+ instead of tree_done.
+
+ (tree_view_cmd): Now uses tree_leave instead of tree_done. The
+ tree_init call takes one parameter more. No need to initialize
+ wtree variable yet. Clears the file entry list (calls
+ set_zero_dir).
+
+ (do_nc): Now uses the load_tree and save_tree functions to load
+ the .mc.tree file on startup and save it on exit. Removed the old
+ tree_init method of loading the tree.
+
+ mc.1: The directory tree section is now up to date with the new
+ features and behaviour.
+
+ screen.c (display_mini_info): Added a missing wattrset. Now uses
+ panel->cwd instead of the tree_selected call.
+
+ (panel_reload): Works again in the tree view mode.
+
+ tree.c: Uses now double linked list instead of single linked
+ list. The tree_list variable renamed to tree_first. New static
+ variables: tree_last, fkeys, check_name and check_start. The wtree
+ variable is now static instead of global. Function removed as
+ unnecessary: free_tree, read_tree, tree_selected. New functions:
+ str_common, whereis, tree_add_entry, remove_entry,
+ tree_remove_entry, start_tree_check, do_tree_check,
+ end_tree_check, load_tree, save_tree, tree_chdir, help_cmd,
+ tree_rescan_cmd, forget_cmd, tree_mkdir_cmd, rmdir_cmd, quit_cmd.
+
+ (show_tree): Small meaningless code cleaning. If in the tree view
+ mode copies the name of selected directory to the panel->cwd
+ variable. If the panel is active chdirs there.
+
+ (check_focus): Now behaves correctly even if there is less entries
+ in the tree than there are lines in tree window.
+
+ (tree_init): Takes one parameter more which tells amount of lines
+ in the window. No longer uses the base directory system. Tries to
+ select the current directory from the tree.
+
+ (tree_done): Now does nothing.
+
+ (tree): Now shows and uses a function key bar of its own. Changed
+ behaviour of the control-r key.
+
+ tree.h: Changed the definition tree_init. Removed read_tree and
+ tree_selected. Added load_tree, save_tree, tree_chdir,
+ tree_rescan_cmd, tree_add_entry, tree_remove_entry,
+ start_tree_check, do_tree_check, end_tree_check. Removed
+ tree_count and tree_lines.
+
+ view.c (help_cmd): Oops, the name of the 'Internal file viewer'
+ section has changed.
+
+Thu Nov 10 22:40:31 1994 Fred Leeflang <fredl@nebula.ow.org>
+
+ * file.c (copy_dir_dir, move_dir_dir): new functions.
+
+ * main.c (do_mark_file): allow directory marking.
+ (copy_cmd): Implement directory copying.
+ (ren_cmd): Implement directory moving.
+ (select_cmd, unselect_cmd): Allow selection of directories, when
+ there is a leading or trailing '/'.
+ (screen.c, screen.h): Added dirs_marked variable to panel
+ structure.
+
+ * util.c (basename): new function: returns the base name of it's
+ argument.
+
+Thu Nov 10 21:21:26 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (copy_tagged): Disable cmdline updating when inserting
+ all those file names.
+ (do_edit): Use copy_strings.
+
+ * input.c (input_disable_update, input_disable_update): New
+ routines: they let the client code disable the screen updating
+ when inserting characters. Used to speed up long insertions like
+ the copy all tagged files command.
+ (stuff): Disable updating when stuffing characters.
+
+Wed Nov 9 14:50:24 1994 Janne Kukonlehto <jtklehto@stekt8>
+
+ * cons.saver.c: Oops, forgot to initialize the action
+ variable. Made it fail randomly.
+
+ * cons.saver.h: Let's start commands from '1' instead of '\000' to
+ make debugging easier.
+
+ * main.c (do_nc): Now works also if the tree view has been
+ specified in the setup file.
+
+ * mc.1: Fixed a typing error in the .\"LINK" command in the
+ Options section. Wrote the Directory Tree
+ section.
+
+ * tree.c (show_tree): Oops, forgot to initialize the x and y
+ variables. Caused a deadlock when there was no entries in the tree
+ and the tree view was active.
+
+ (tree_selected): Now works correctly if the selected_ptr is
+ NULL. No more segmentation faults.
+
+Tue Nov 8 21:26:18 1994 Miguel de Icaza <miguel@sphinx>
+
+ * user.c (execute_menu_command): Now it frees the returned pointer
+ from expand_format
+ (expand_format): Added support for the '%t' flag. This represents
+ all the tagged files.
+
+ * ext.c (exec_extension): Now must free the returned pointer from
+ expand_format.
+
+Tue Nov 8 02:07:47 1994 Janne Kukonlehto (jtklehto@stekt.oulu.fi)
+
+ * Makefile.in: BINDIR now defined in the CPPFLAGS. Added
+ cons.saver.h to the HDRS. Added cons.saver.c to the DISTFILES. No
+ need for the prog_mode variable anymore. A new target:
+ install.saver which installs the Linux console screen save/restore
+ handler. The uninstall and clean targets now remove cons.saver.
+
+ * cons.saver.c: A new file: Linux console screen save/restore
+ handler. Most of the code was previously the child code in the
+ main.c file, the handle_console function. See below what was
+ removed from the main.c file.
+
+ * cons.saver.h: A new file. Included by cons.saver.c and main.c.
+ Defines the commands for cons.saver.
+
+ * gindex.pl: If the length of a node name is zero output a newline
+ on its place in the contents. This is used for dividing the help
+ file into five parts.
+
+ * help.c: A new static variable end_of_node which tells when the
+ end of node is reached and shown. (move_forward): Refuses to move
+ forward if the end_of_node variable is true. (show): Little
+ meaningless code clean-up. Now sets the end_of_node variable.
+
+ * main.c: Now includes the cons.saver.h file. The tty_getsize
+ function removed. The tty_cursormove function removed.
+ (handle_console): Console detection code removed. The child code
+ removed. Now uses the cons.saver program for saving and restoring
+ of the console screen. Security hole checks removed because the mc
+ does not need to be setuid anymore. (main.c): Backward
+ compatibility: gives up privileges in case someone installed the
+ mc as setuid.
+
+ * man2hlp.c (handle_command, handle_link, main): Now supports the
+ new LINK2 link format.
+
+ * mc.1: Reorganized and partially rewritten. Too many changes to
+ list them all.
+
+ * screen.c (reload_panel): No longer tries to reread tree. This
+ will get rid of those long delays when tree view is active. Real
+ fix will be introduced later.
+
+ * xnc.hlp: The [Main] and [About] nodes combined into one [Main]
+ node. The authors are now mentioned only in the mc.1 file which
+ should help in keeping them up to date.
+
+Tue Nov 8 14:09:23 1994 Leon Raadshooven<L.A.RoosvRaadshooven@research.ptt.nl>
+
+ * color.c: Code cleanup
+
+Tue Nov 8 13:12:12 1994 Mauricio Plaza <mok@roxanne.nuclecu.unam.mx>
+
+ * find.c (find_dialog): Choose the appropriate regexp depending on
+ the easy_patterns setting.
+
+Tue Nov 8 12:50:10 1994 Torben Fjerdingstad <tfj@olivia.ping.dk>
+
+ * mc.ext: It defaults to view the file with $PAGER. I have set
+ LESSCHARSET=latin1 to tell my $PAGER, NOT to display binary files
+ without a warning.
+
+Mon Nov 7 12:56:26 1994 Janne Kukonlehto (jtklehto@stekt.oulu.fi)
+
+ * Makefile.in (make install): Removed the 'if $(do_setuid) then'
+ line which caused 'make install' to fail.
+
+ * README: The sample menu file is mc.menu, not nc.ext.
+
+ * help.c (move_forward2, move_backward2, move_forward,
+ move_backward): The beginning of a line is just after newline, not
+ just before it.
+
+ (move_to_top, move_to_bottom): New functions which support moving
+ to the top and bottom of a node. (null_fn): Deleted, no longer
+ necessary.
+
+ (follow_link): Added one space to the beginning of the error
+ message.
+
+ (select_next_link): No longer tries to be too clever for its own
+ good.
+
+ (show): Now uses 'switch - case' instead of 'if - else if - else
+ if...'. Now supports alternate character set, output of the
+ version number of the Midnight Commander and tab characters.
+
+ (help_event): Now a click of the right mouse button moves to the
+ previous node. A left click on the top or bottom frame line moves
+ one pageful backward or forward.
+
+ (interactive_display): The beginning of a line is just after
+ newline, not just before it. Enlarged the mouse event area. Up and
+ down arrows behave now like a mixture of old behaviour and the
+ behaviour of the tab key (a bit like in Lynx). Old behaviour of up
+ and down arrow is available by pressing C-p and C-n. Comment
+ reorganization. Added 'n', 'p' and 'c' keys for moving to next,
+ previous and contents node.
+
+ * help.h: Defined codes for switching to the alternate character
+ set, returning to the normal set and outputting of the version
+ number.
+
+ * main.c (action.c): In the tree view: now it is able handle
+ failure of the do_cd call correctly.
+
+ (panel_event): When clicking above or below the directory listing
+ now moves one pageful instead of one lineful.
+
+ * mc.menu: Reorganized the comment lines to conform to the new
+ comment feature. Documented the new comment feature and the new
+ condition debug feature. Fixed a small bug in the condition
+ preceding the 'X' entry.
+
+ * tree.c: Added a lot of comments.
+
+ (show_tree): In the directory tree the mini-status line shows now
+ the full name of directory if there is no search string. This is
+ similar to the behaviour of the tree view feature.
+
+ (check_focus): A new function which tries to keep the selected
+ directory near the middle of the window.
+
+ (tree_move_backward, tree_move_forward): Now using the check_focus
+ function.
+
+ (event_callback): Now moves one pageful backward or forward if the
+ top or bottom frame line is clicked.
+
+ (tree): Enlarged the mouse event area.
+
+ * user.c: Two static variables debug_flag and debug_error for the
+ implementation of debug output feature.
+
+ (debug_out): A new function which takes care of all debug output
+ handling.
+
+ (test_type, test_condition, test_line): Now support the debug_out
+ function.
+
+ (test_condition): Fixed a small bug in the handling of the '!'
+ operator.
+
+ (user_menu_cmd): Now there can be real comments in the user menu.
+
+ * xnc.hlp: Added a nice logo to the [Main] node. Full rewrite of
+ the [Help] node. The 'General movement keys' link points to the
+ new manual page which is not ready yet and therefore it is not
+ working.
+
+Sun Nov 6 20:28:28 1994 Miguel de Icaza <miguel@sphinx>
+
+ * Makefile.in (install): Thanks to Janne who pointed out this
+ buglet, now we can install the software again.
+
+Sun Nov 6 20:07:12 1994 Radek Doulik <rodo@earn.cvut.cz>
+
+ * chmod.c, chmod.h: new files, implement the chmod command on a
+ nice dialog box. Binded to the C-x c key. We need to document
+ this. BTW, GNU indent -kr -pcs gives the approximate coding style
+ of the commander.
+
+Sun Nov 6 17:45:59 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (menu_display_cmd, menu_cmd, menu_last_selected_cmd):
+ Added support for recalling last used menu entry, Torben will be
+ happy.
+ (prev_page, next_page): Changed to have the 1.1 behavior again
+ (when moving, if possible, keep the selection at the same relative
+ distance from the top_file).
+
+Sat Nov 5 12:59:34 1994 Raadshooven <L.A.RoosvRaadshooven@research.ptt.nl>
+
+ * main.c (main): Added support for loading colors from the Command
+ line.
+
+Fri Nov 4 14:20:13 1994 Miguel de Icaza <miguel@sphinx>
+
+ * key.c (mi_getch): New default: on ncurses-1.8.6 we need to
+ untouch the window (stdscr), made the default.
+
+ * util.c:
+
+Fri Nov 4 14:16:08 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * main.c (move_down, move_up, move_home, move_end, prev_page,
+ next_page): Replaced the show_tree calls with paint_panel calls.
+
+ (do_search): Now supports the tree view feature (meaning that the
+ trees can now be searched).
+
+ (start_search): Added a call to the display_mini_info function because
+ it now behaves differently when searching.
+
+ (panel_event): Now supports the tree view feature (meaning that the
+ tree view feature has now mouse support).
+
+ (tree_cmd): Now reports an error if one of the panels is in the tree
+ view mode.
+
+ (view_other_cmd): Changed error message to reflect the new name for
+ the function.
+
+ (tree_view_cmd): Only one of the panels can be in the tree view mode.
+ Initialization of the tree_lines and tree_cols variables is no
+ longer necessary.
+
+ * main.h: Added the declarations of the searching and
+ search_buffer variables so that the display_mini_info function in
+ the screen.c file can use them.
+
+ * panel.h: Added view_tree to the list of possible views.
+
+ * screen.c: Now includes main.h.
+
+ (display_mini_info): If the search mode is active the current search
+ string is shown.
+
+ (panel_reload): Now supports the tree view feature (meaning that
+ ctrl-r works in the tree view mode).
+
+ * tree.c: Added the submask field to the tree_entry
+ structure. Deleted the tree_cols variable as unnecessary. Renamed
+ the count variable to tree_count and made it global. Added the
+ search_buffer variable. Made the done variable static instead of
+ auto.
+
+ (free_tree): The initialization of the top, selected, selected_ptr and
+ tree_count variables is moved here.
+
+ (read_tree): Now a global function. Added a call to the free_tree
+ function to remove a possible old tree data and initialize some
+ variables. The count/tree_count variable is no longer initialized
+ here. Added the code for the submask field calculation.
+
+ (show_tree): Now uses the submask field to decide whether a sub-branch
+ is the last sub-branch of its parent-branch and what levels of
+ parent-branches there are. This method creates the correct tree
+ figure as long as there are no more than 32 levels of
+ subdirectories (because of the submask field has only 32
+ bits). Better support for working as a panel. Small cosmetic
+ fixes. If working as a dialog now shows the current search string.
+
+ (tree_init): The initialization of the top and selected variables
+ moved away from here.
+
+ (tree_event, event_callback): New functions which implement the mouse
+ support.
+
+ (search_tree): A new function which implements the tree search feature.
+
+ (tree): The done variable moved away from here. Decreased the value of
+ tree_lines from 18 to 16 so that there is room for the search box.
+ The create_dialog call still allocates 18 lines. Added support for
+ tree search feature. Added mouse support. The additional movement
+ keys are longer allowed (because they are needed for the search
+ feature). Changed the handling of the result variable. The 'r' key
+ no longer rereads the tree (use ctrl-r instead).
+
+ * tree.h: Added the declarations of the read_tree, tree_event and
+ tree_count identifiers. Removed the tree_cols variable.
+
+Fri Nov 4 10:55:43 1994 Miguel de Icaza <miguel@sphinx>
+
+ * widget.c (check_new): Split the dialog manager in dialog manager
+ and widget implementation functions.
+
+ * color.c (init_colors): Major reworking. Now, we allow to switch
+ back and forth from color and bw mode.
+
+Fri Nov 4 10:04:19 1994 Raadshooven <L.A.RoosvRaadshooven@research.ptt.nl>
+
+ * color.c: Added support to reconfigure colors via the
+ MC_COLOR_TABLE environment variable.
+
+Fri Nov 4 08:55:37 1994 Miguel de Icaza (miguel@roxanne)
+
+ * file.c (erase_dir): Forced use of 'yes' to recursively delete a
+ subdirectory.
+
+Thu Nov 3 18:21:53 1994 Miguel de Icaza <miguel@sphinx>
+
+ * screen.c (display_mini_info): Prints the currently selected
+ directory.
+
+ * main.c (tree_view_cmd): Little patch to allow 'Cancel' on the
+ tree.
+ (select_item): Extra checking when using select_item
+
+Thu Nov 3 18:03:09 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * Makefile.in: Added tree.c to the SRCS, tree.h to the HDRS and
+ tree.o to the OBJS.
+
+ * main.c (change_panel, move_down, move_up, move_home, move_end,
+ prev_page, next_page, action, full_cmd, brief_cmd, info_cmd,
+ long_cmd, check_menu_panel, copy_other_prog_name,
+ copy_other_pathname, copy_other_tagged): Changes to support the
+ tree view feature.
+
+ * (tree_cmd, tree_view_cmd): New functions for the directory tree
+ and tree view features.
+
+ * panel.h: Added view_tree to the enumeration of view types.
+
+ * screen.c (display_mini_info, show_dir, paint_panel): Changes to
+ support the tree view feature
+
+ * setup.c (view_types, load_setup): Changes to support the tree
+ view feature.
+
+ * tree.c, tree.h: New files which implement the directory tree and
+ tree view features.
+
+ * user.c (expand_format, test_condition): Changes to support the
+ tree view feature.
+
+Wed Nov 2 18:32:12 1994 Miguel de Icaza <miguel@sphinx>
+
+ * dlg.c (input_new, input_callback, input_destroy): New widget,
+ handles input lines when ran under the dialog manager.
+
+ * find.c (add_list): Changed gc_free for gc_free_now.
+
+ * main.c (move_selection): Initialized adjust.
+ (do_re_sort): After setting selection, set the top_file field.
+ Need to make sure I didn't forget any of this in the source code.
+
+Wed Nov 2 16:14:18 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * INSTALL: Changed the wording to reflect current version of
+ console screen save/restore support.
+
+ * README: Changed the wording to reflect the new name and the
+ xterm mouse support. Small spelling fixes. Fixed the location of
+ the latest alpha version.
+
+ * configure.in: A bug fix in the --with-screen-restore
+ option. This bug caused 'make install' to fail.
+
+ dlg.c, option.c: A name change from MouseLess Commander to
+ Midnight Commander.
+
+ * file.c (copy_file_file): A small bug fix (replaced a
+ bracket-pair with a parentheses-pair). This bug was detected by
+ Irix compiler.
+
+ * main.c (handle_console): Corrected race-condition bug by making
+ the parent to wait until the child gets its job done. Also two
+ other small bug fixes.
+
+ * main.c (do_search): Now compatible with eight bit mode (again).
+
+ * mc.menu: Documented the syntax of the new user menu condition
+ feature. Added some examples how to use it.
+
+ * user.c (extract_arg, test_type, test_condition, test_line): New
+ functions which implement user menu condition feature.
+ (user_menu_cmd): Some changes to support the user menu
+ condition feature.
+
+ * util.c (is_printable): A small bug fix (replaced '>' with '>=').
+
+ * util.h: Added '#include <sys/types.h>'. Doesn't compile on
+ Ultrix without this.
+
+Wed Nov 2 15:57:07 1994 Radek Doulik <rodo@earn.cvut.cz>
+
+ * option.c: Fixed problem with data type of check_options and
+ XTRACT macro.
+ (init_configure): Code cleanup, also destroys properly the new window.
+
+ * view.c (do_view): Bug fix: delete the windows when leaving the
+ module.
+
+Wed Nov 2 15:20:26 1994 Fred Leeflang <fredl@nebula.ow.org>
+
+ * file.c (recursive_erase): Implemented recursive directory delete.
+
+Mon Oct 31 21:42:15 1994 Miguel de Icaza <miguel@sphinx>
+
+ * dlg.h, dlg.c, option.c: Many structural changes to the dialog
+ manager to allow easy integration of future widgets.
+
+Mon Oct 31 21:32:37 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * view.c (display): Now supports eight bit clean mode.
+
+ * input.c (handle_char): Now supports eight bit clean mode.
+
+ * main.c (tty_getsize): The tty_defaults function deleted as
+ unnecessary.
+ (handle_console): Small bug fixes and code clean-up.
+ new variable: eight_bit_clean, to be used in future patches.
+ (toggle_eight_bit): new function to support the eight bit clean
+ mode.
+
+ * setup (load_setup): Set the eight bit handling in ncurses.
+
+ * screen.c (display_mini_info): If the file is a symbolic link then
+ destination of the link is shown.
+
+ * key.c (mi_getch): Use the new macro ALT() for converting an ALT
+ value.
+
+ * util.c (is_printable): A new function to detect whether a
+ character is legal in current mode. In 7-bit mode characters 32 -
+ 126 are legal and in 8-bit mode characters 32 - 126 and 160 - 255
+ are legal (conforming to the ISO-8859-1 / latin-1 standard).
+
+Sun Oct 30 20:39:58 1994 Alessandro Rubini <rubini@ipvvis.unipv.it>
+
+ * gpm-xterm.c: New file, needed to cleanup the code in key.c,
+ key.c has not been changed yet to take advantage of this yet.
+
+Sun Oct 30 20:38:44 1994 Radek Doulik <rodo@earn.cvut.cz>
+
+ * option.c, dlg.c: New files: The new option configuration
+ routines and the new dialog box manager. Very nice.
+
+Sun Oct 30 18:21:00 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * main.c (tty_defaults, tty_cursormove, handle_console): New
+ functions for handling Linux console screen saving and
+ restoring. Original idea and part of code from Unix Interactive
+ Tools version 3.2b, file tty.c. NOTE: this code requires that the
+ user is root or the mc is setuid root (because it is reading the
+ console screen).
+
+ * main.c (pre_exec, post_exec, view_other_cmd, main):
+ Modifications to use handle_console for screen saving and
+ restoring.
+
+ * view.c (display): No longer tries to output DEL characters.
+
+ * win.c (check_movement_keys): Added the 'g' and 'G' keys to the
+ additional keys. They work like they do in 'less'. (This change
+ requires my previous patch applied).
+
+Sat Oct 29 16:38:20 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (post_exec, execute, view_other_cmd): Change cbreak ()
+ calls by raw () calls.
+
+Sat Oct 29 15:48:09 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * win.c (check_movement_keys): Added handling of 'g' and 'G' keys
+ (go top and go bottom keys).
+
+Sat Oct 29 15:31:08 1994 Alessandro Rubini <rubini@ipvvis.UNIPV.IT>
+
+ * configure.in: Misc patches.
+
+Fri Oct 28 12:07:01 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (copy_cmd, ren_cmd, link_cmd, mkdir_cmd, delete_cmd): Use
+ input_expand_dialog.
+
+ * dialog.c (input_expand_dialog): New function: this calls
+ tilde_expand on the information typed by the user.
+
+Fri Oct 28 11:36:15 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * dir.c (handle_dirent): No longer filters links pointing to
+ directories. This bug was accidentally introduced in alpha-27.
+
+ * win.c, win.h (define_label, define_label_quit): Saves the
+ callback function pointer in the fkey_table_list.
+ (push_fkey): The new_fkey function renamed to push_fkey. Now
+ allocates a new fkey_table_list.
+ (pop_fkey): A new function. Deletes the fkey window and
+ the old fkey_table_list.
+ (check_fkeys): A new function. Checks whether a key is a fkey and
+ has a action defined in the fkey_table_list.
+ (check_movement_keys): A new function. Checks whether a
+ key is up, down, pgup, pgdn, home or end and calls the correct
+ function. If the 'additional' flag is true checks also 'less' like
+ keys 'b', space, 'u' and 'd'.
+
+ * help.c (move_forward2, move_backward2, move_forward,
+ move_backward, null_fn, interactive_display): Now uses the
+ check_movement_keys function.
+
+ * help.c (move_backward2): A small bug fix (replaced '>' with
+ '>=').
+ (follow_link): Now mouse can be used for scrolling backward and
+ forward.
+
+ * main.c (init_labels, do_nc): Now uses the push_fkey, pop_fkey
+ and check_fkeys functions.
+
+ * setup.c (load_setup): Fixed a little memory allocation problem
+ (the other_dir variable).
+
+ * view.c (move_forward2, move_backward2, move_forward,
+ move_backward, move_to_top, move_to_bottom, init_view, do_view):
+ Now uses the push_fkey, pop_fkey, check_fkeys and
+ check_movement_keys functions.
+
+ * view.c (init_view): A small bug fix in the definition of the AIX
+ meaning of F8 and F9.
+ (one_line_up, one_line_down, do_view): Little fixes in the
+ support for scrolling text with mouse.
+ (load_view_file): Does not attempt to view a directory, a socket or
+ a fifo.
+
+Thu Oct 27 14:39:48 1994 Miguel de Icaza <miguel@sphinx>
+
+ * user.c (menu_input_loop): Allow more than 'a' through 'z'
+ entries in the user menu.
+
+ * auto.c (do_exec_mount): Added calls to open_error_pipe and
+ close_error_pipe, don't close descriptor (2).
+
+ * ext.c, file.c, help.c, main.c, user.c, view.c: Changed a lot of
+ uses to sys_errlist[errno] to unix_error_string (errno).
+
+Thu Oct 27 14:21:30 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * TODO: Now mentions the TERMINFO environment variable. Changed
+ the location of the line "Use the mv code from GNU's mv". Deleted
+ the entry about left and right moving the selection in brief mode
+ (already implemented).
+
+ * dir.c (handle_dirent): New function. (do_load_dir,
+ do_reload_dir): The common part of the code moved to the
+ handle_dirent function to avoid code duplication.
+
+ * dir.c (handle_dirent, sort_name, sort_ext, sort_time,
+ sort_size), dir.h: Links to directories are now sorted as
+ directories. Links to files continue to be sorted as files.
+
+ * ext.c, file.c, help.c, main.c, user.c, view.c: Changed a lot of
+ calls to the "message" function to include system error message
+ sys_errlist[errno].
+
+ * file.c (move_file): Now uses open_error_pipe/close_error_pipe to
+ catch the error messages from /bin/mv command.
+
+ * main (init_panels): If chdirs to the other_dir, now chdirs also
+ back. This thing seemed to be accidentally deleted by someone from
+ the alpha-26.
+
+ * util.c, util.h, view.c: The open_error_pipe, check_error_pipe
+ and close_error_pipe functions moved from view.c to util.c. The
+ prototypes now appear in the util.h. Modifications in
+ close_error_pipe to make it possible to define whether a possible
+ message in the error pipe should be printed as a warning message
+ or a error message.
+
+
+Wed Oct 26 17:21:19 1994 Miguel de Icaza <miguel@sphinx>
+
+ * configure.in: Now the gpm library is detected by the autoconf
+ program. If the lib is installed in a weird directory, then you
+ use the --with-gpm-mouse=base-directory.
+
+ * Changed the use_gpm constant for HAVE_LIBGPM.
+
+ * util.c (copy_strings): new function. This one uses gc_alloc and
+ returns the concatenation of all it's arguments. The list must
+ end with a 0.
+
+ * ext.c (regex_command), file.c (move_file), find.c, main.c
+ (action, view_cmd, ext_cmd, menu_edit_cmd), setup.c
+ (save_setup, load_setup), view.c (load_view_file): Removed hard
+ coded limits, use the new function copy_strings.
+
+ * gc.c (gc_free_now): New function, frees the pointer at that
+ point, also increased the number of handles.
+
+ * main.c: Typo fix.
+
+ * menu.c: allow F-10 to act like ESC.
+
+Wed Oct 26 17:13:15 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * main.c (filter_cmd): Filter was acting on the current panel
+ instead of the panel selected in the menus.
+ (action): When executing commands in a panel, prepend a ./ to the
+ command.
+
+Wed Oct 26 17:09:59 1994 Alessandro Rubini <rubini@ipvvis.UNIPV.IT>
+
+ * key.c (mi_getch): switch cleanup.
+
+Tue Oct 25 12:19:39 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ dir.c (do_load_dir, do_reload_dir): Directory "." is no longer
+ shown in the directory panel. Added support for directory panel
+ filter.
+
+ dir.h: Added a filter parameter to the prototypes of do_load_dir
+ and do_reload_dir.
+
+ panel.h: Added the filter field to the struct Panel.
+
+ find.c (select_and_change_panel): Added filter argument to the
+ call of do_load_dir.
+
+ screen.c (brief_frame): The titles of the directory panel in the
+ brief mode are located correctly even if the width of the screen
+ is not 80 columns.
+ (init_panel): The default filter is "*".
+ (panel_reload): Added filter argument to the call of
+ do_reload_dir.
+
+ main.c (init_panels, do_cd): Added filter argument to the call of
+ do_load_dir.
+ (filter_cmd): New function to change the directory panel
+ filter.
+ (swap_cmd): New function to swap the contents of the directory
+ panels, keyboard shortcut is C-u. Changes in PanelMenu, RightMenu
+ and CmdMenu to support the filter and swap commands. A name change
+ of a menu entry: "View other screen(xterm)" -> "Panels
+ on/off(xterm)". The width of the menu bar now matches the width of
+ the screen.
+
+ help.c (start_link_area, end_link_area, clear_link_area,
+ help_event): New functions which implement a mouse support.
+
+ (show, interactive_display): Now using the mouse support.
+
+ help.c (select_prev_link): No longer tries to recover if there is
+ no previous link. Returns NULL in such cases. (show): If the
+ selected link would not be visible the first or the last visible
+ link is selected.
+ (interactive_display): Reworked the way the "tab" and "b" keys
+ work. Now they step through the links on the screen, not the links
+ on the node.
+ (interactive_display): Added support for the "left" and "right"
+ keys. They work like they do in the Lynx.
+
+Sun Oct 23 17:21:14 1994 Miguel de Icaza <miguel@sphinx>
+
+ * util.c (tilde_expand): Now, this time, it should work.
+
+ * main.c (init_panels): Don't select the information window.
+
+ * setup.c (load_setup): Only one of the panels may be in the
+ information mode.
+
+ * main.c: Now you can use C-x i to toggle the information window.
+
+Thu Oct 20 11:47:24 1994 Miguel de Icaza <miguel@sphinx>
+
+ * profile.c (sync_profiles): Made some function static. Added
+ prototypes to profile.h file.
+
+ * profile.h: new file, prototypes to profile.c. Added #include to
+ the files that used the functions.
+
+ * main.c (switch_to_info): New function: switches to information
+ mode, and added the info option to the menus.
+
+ * screen.c (paint_panel): Can paint normal panels and information
+ panels.
+
+ * util.c (tilde_expand): Hopefully, now the tilde expansion is fixed.
+
+ * ncurses.h: Added detection for buggy ncurses when running on SGI
+ machines with GNU CC.
+
+Tue Oct 18 12:23:06 1994 Miguel de Icaza <miguel@sphinx>
+
+ * configure.in: Actually do something when GCC is detected. Copy
+ the GNUmakefile from the source directory to the compilation
+ directory.
+
+ * GNUmakefile: New file. Used to include the dependencies.
+ Developers should use GNU make, the rest of the people is ok with
+ a standard make.
+
+ * main.c (move_selection, move_left, move_right): When in Brief
+ mode, the program now is able to move the selection to the left
+ and right. Only the keybindings KEY_LEFT and KEY_RIGHT use this
+ option, the C-b and C-f still call the default_key handling
+ mechanism.
+
+Tue Oct 18 10:32:22 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * key.c (mi_getch): Solaris fix: if key received is kf0, convert
+ that to kf10.
+
+ * xterm.ti: fixed the op capability to the correct value and
+ changed the definition from kf0 to kf10.
+
+Mon Oct 17 18:41:33 1994 Miguel de Icaza <miguel@sphinx>
+
+ * util.c (tilde_expand): Finally, I fixed the tilde expansion, it
+ was not that hard to fix.
+
+ * user.c (execute_menu_command): Use strchr instead of
+ search_string, this fixes a little bug introduced by the need of
+ fmt before.
+
+ * xterm.ti, vt100.ti: new terminfo databases for vt100 and xterm.
+
+Mon Oct 17 17:44:11 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * xterm-color: new file. NCurses terminfo database for color
+ xterms.
+
+ * man2hlp.c: new file. replaces man2hlp.pl (and the use of fmt).
+
+ * main.c (view_other_cmd): Now displays an error box if curses
+ does not support the alternate screen.
+
+ * help.c: Now uses help.h. The constant definitions moved to
+ help.h. Now uses the constants (why to define constants if they
+ are not used?).
+
+ * help.h: New file. Defines constants for help.c and man2hlp.c.
+
+ * gindex.pl: Removed the ctrl-d workaround. Not needed because fmt
+ is no longer used. Removed the main node from contents (it was
+ added to contents by removal of ctrl-d workaround). Other new
+ nodes in the contents (About, License and Help) left visible.
+
+ * color.h, dialog.c (create_dialog), screen.c (show_dir): Color
+ selection bug fixes. The code was assuming that the default color
+ is white on black. On color xterm it is black on white.
+
+ * Makefile.in (ync.hlp): Uses man2hlp (compiled version of the
+ man2hlp.c) instead of man2hlp.pl and fmt. Rebuilding the mc.hlp
+ file works now on all machines, not just on Linux.
+
+ * Makefile.in (DISTFILES): Replaced the man2hlp.pl file with
+ man2hlp.c. Removed the second occurrence of xnc.hlp.
+
+Fri Oct 14 17:52:46 1994 Miguel de Icaza <miguel@sphinx>
+
+ * screen.c (panel_reload): If you can't chdir to a directory, load
+ a dummy.
+
+Fri Oct 14 16:23:41 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * find.c (find_dialog): You can't stop if lines is equal to
+ zero. This fixes one of the problems in the find file program.
+
+ Fri Oct 14 13:53:16 1994 Miguel de Icaza <miguel@sphinx>
+
+ * util.c (regexp_match): Fixed small typo when HAVE_LIBGEN_H is
+ defined.
+
+ * configure.in: Misc cleanup in the configuration process.
+ Solaris should use the -lgen library to have regular expression
+ support.
+
+Fri Oct 14 13:32:02 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * main.c (execute): The execute function didn't change the line
+ after prompting which caused the output of next external command
+ to start from the middle of line. The view_other_cmd function
+ didn't flush the output after putp(enter_ca_mode) which made it
+ look like two keypresses are needed to return to the mc screen.
+
+ * key.c (mi_getch): I finally managed to nail down that gpm bug I
+ have been complaining about. The mi_getch function was reading
+ gpm mouse even when shut_mouse had been called. It was a real hard
+ one. The existence of the mouse is now told by three
+ variables. The use_mouse_p variable tells the type of mouse and
+ the gpm_flag and xmouse_flag variables tell whether the mouse is
+ currently active (init_mouse called) or not (shut_mouse
+ called). Previously I was attempting to get along with only
+ use_mouse_p.
+
+Fri Oct 14 10:58:34 1994 Miguel de Icaza <miguel@sphinx>
+
+ * help.c (select_prev_link, select_next_link): Bug fixes.
+ (search_string_node): Don't return main if can't find a node.
+
+ * view.c (regexp_searc, normal_search): Now, it should not do
+ empty searches.
+ (do_view): Now, you can continue a search with the 'n' or C-s
+ command.
+
+Thu Oct 13 16:25:39 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * view.c (do_view): When running under AIX, keys F8 and F9 take
+ you to the beginning and bottom.
+
+Thu Oct 13 12:26:23 1994 Miguel de Icaza <miguel@sphinx>
+
+ * help.c (interactive_display): If there are no next or previous
+ links when that command is issued, don't go to the main node.
+
+Thu Oct 13 11:34:06 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * dialog.h: removes the warning which comes during compilation.
+
+ * help.c (search_string, move_backward, show,
+ interactive_display): Two fixes for the bugs uncovered by the
+ addition of '.\"LINK"' command: a newline in the link name bug fix
+ and a multi-line spanning link background colour flash bug
+ fix. Other changes: a backward scroll bug fix, a dialog name
+ change from "Main" to "Help", a next-page bug fix and F1 now shows
+ the help for the help viewer.
+
+ * view.c (do_view): Backspace and delete now scroll a screenful
+ backwards like they do in the internal help.
+
+ * Makefile.in: Added INSTALL.FAST to the DISTFILES.
+
+ * xnc.hlp: Improved the documentation for the help viewer.
+
+ * gindex.pl: The index is no longer sorted. Looks a bit better
+ now. I think that the name "Contents" would be better than the
+ current "Index".
+
+ * mc.1, mc.hlp: A name change in header: nc -> mc. Description and
+ Options moved out of the index to their own section. A lot of
+ links added. Bug fixes and spelling corrections. The awfully long
+ Keys section divided to five sections (Keys, Action Keys,
+ Selection Keys, Command Line Keys and Input Line Keys). The
+ existence of the menus documented (section Menu Bar).
+ Miscellaneous additions.
+
+ * man2hlp.pl: Added support for '.\"LINK"' command. Better support
+ for roff commands ".nf" and ".fi".
+
+ * NEWS: Spelling corrections.
+
+ * INSTALL.FAST: The INSTALL file seems to be a bit long. I wrote a
+ shorter version which only mentions the essential. It is still
+ longer than one screenful but I think it is a step to the right
+ direction.
+
+ * ChangeLog: Spelling corrections.
+
+Wed Oct 12 18:43:19 1994 Miguel de Icaza <miguel@sphinx>
+
+ * view.c (search), find.c (add_list), main.c (unselect_cmd,
+ select_cmd): Use the new regexp_match argument
+
+ * util.c (regexp_match): If matching files, and easy patterns are
+ enabled, then add '^' at the beginning of the regular expression
+ and a '$' at the end.
+
+ * Added some missing includes to many files (malloc.h, unistd.h)
+
+ * view.c (move_forward): Fixed bug in the internal viewer.
+ Changed line == lines for line >= lines, since line could have
+ been incremented twice: one caused by the wrapping and one because
+ of the newline.
+ (do_view): Added back scrolling with the DEL key.
+
+Tue Oct 11 11:12:53 1994 Miguel de Icaza <miguel@sphinx>
+
+ * find.c (find_dialog): Now, before returning, it properly
+ destroys the dialog.
+
+ * view.c (view): Call push_refresh only after the WINDOW * have
+ been setup, and pop the refresh function only if the viewer did
+ successfully run.
+
+ * find.c (do_find), user.c: Use do_refresh instead of
+ refresh_screen
+
+ * dialog.c (push_refresh, pop_refresh, do_refresh): new screen
+ refresh handler.
+
+ * view.c (view): Use the new display refresh handler.
+
+ * help.c (interactive_display): Now you can specify the node to be
+ looked up.
+
+ * main.c (version): Shows information about how was the program
+ compiled.
+
+Tue Oct 11 11:12:33 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * key.c (mi_getch): This patch makes function keys work under
+ Irix. It may also help on other machines which have incorrect
+ termcap. However, it doesn't make F10 work under Solaris.
+
+ * view.c: Some reorganization in view.c to support my forth-coming
+ version of the buffering. It now uses longs instead of char
+ pointers. "*from" has been replaced with "get_byte(from)". I
+ submit these changes now so that others won't make incompatible
+ changes before I get the buffering ready.
+
+ Changed some stupid abbreviations to the long form: errpipe ->
+ error_pipe, open_errpipe -> open_error_pipe, close_errpipe ->
+ close_error_pipe, olderr -> old_error.
+
+ Modifications in open_error_pipe and close_error_pipe and addition
+ of check_error_pipe to support my forth-coming version of the
+ buffering.
+
+ Moved the wrap toggle from F5 to the correct place F2. Disabled
+ the AIX meanings of F1 and F2.
+
+ regexp_search() disabled in the hex mode (previously only the fkey
+ label was removed). Replaced the RxSearch hotkey F8 with F6 (the
+ fkey labels already mentioned F6 as the hotkey).
+
+ (help_cmd): Added a help command to the internal viewer. BUGS:
+ doesn't open the help file from the correct place (is not context
+ sensitive), flashes the main screen when exiting from the help.
+
+ (move_forward): A bug fix in move_forward(). Now it correctly
+ scrolls forward when in wrap mode.
+
+ * mc.1: (Internal file viewer): Documented the active keys inside
+ the internal file viewer.
+
+ * main.c (view_other_cmd): Because view_other_cmd() now works only
+ in xterm I removed libgpm bug workaround (perhaps I should get a
+ bugless version of libgpm, I am having too many segmentation
+ faults when using mc on the console).
+
+ (check_for_default): When editing the extension file or the menu
+ file if the file doesn't exist the default file is copied for editing.
+
+ (ext_cmd, menu_edit_cmd): Uses check_for_default.
+
+ (version): A little change in version string informing about xterm
+ mouse support.
+
+Mon Oct 10 21:10:46 1994 Miguel de Icaza <miguel@sphinx>
+
+ * key.c (mi_getch): Buggy SystemV curses now should be able to
+ detect ESC+anything extra key sequences.
+
+ * help.c: When going back in the history, it sets the selected
+ link to the one that was followed.
+ (select_prev_link): Now it's possible to go back in the hypertext
+ viewer with the 'b' key.
+
+ * configure.in: Added --with-old-tools configuration option.
+
+Sat Oct 8 12:45:22 1994 Miguel de Icaza <miguel@sphinx>
+
+ * view.c (display): The viewer now can wrap text. It's still
+ missing movement by lines that correctly deals with wrapped text.
+ (move_forward): Moves ok when wrap mode is on.
+ (move_backward): Moves ok when wrap mode is on.
+
+Fri Oct 7 19:58:42 1994 Miguel de Icaza <miguel@sphinx>
+
+ * menu.c (run_bar): Always repaint menu bar.
+
+Thu Oct 6 09:48:18 1994 Miguel de Icaza <miguel@sphinx>
+
+ * profile.c (load): Changed char c for int c. That caused AIX and
+ SGI machines to freeze when loading the profile.
+
+ * setup.c: Added accidentally deleted entry for default_list_perm
+ option.
+
+Thu Oct 6 09:47:42 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * menu.c (run_bar): Fixed wrong type cast for IRIX.
+
+ * auto.c: fixed typo.
+
+Wed Oct 5 11:37:38 1994 Miguel de Icaza <miguel@sphinx>
+
+ * key.c (mi_getch): Fixed small typo: use_mouse_p == XTERM_MOUSE
+
+ * menu.c (top_menu_handle): Fixed the problems with the mouse. No
+ more flashing menus, and correctly select entries in the
+ query_boxes.
+ (run_bar): Added a missing line.
+
+ * main.c (main): Removed the \ec hack before entering do_nc, it
+ was a hack to a badly written termcap entry for the Linux console
+ in my machine.
+
+Wed Oct 5 10:44:30 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * zip.c (is_gunzipable): Clean up the code.
+
+ * view.c (open_err_pipe, close_err_pipe): These functions are used
+ for creating a pipe for capturing gzip error messages. If gzip
+ encounters a error, the error message is now shown in a nice
+ message box. Lot cleaner than the previous solution.
+ (view): More fixes to gzip viewer.
+
+ * main.c (view_other_cmd): The 'View other screen (xterm)' feature
+ now shows an error box if current terminal is not xterm. It still
+ doesn't work on Solaris xterm without real ncurses (well,
+ documentation encourages people to use real ncurses, so it is not
+ a bug, it is a feature).
+
+Tue Oct 4 11:37:06 1994 Miguel de Icaza <miguel@sphinx>
+
+ * configure.in (LIBS): Little fix: if ncurses is in /usr/include
+ then add -lncurses.
+
+ * menu.c (top_menu_handle): Fixed bug that prevented current
+ selection on dialog boxes to be selected in bars.
+
+ * key.c (xmouse_get_event): Added double click support under
+ xterms (double_click_speed loaded in setup.c).
+
+Tue Oct 4 10:25:55 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * zip.c (is_gunzipable): The code can now figure out the size of
+ pkzipped file.
+
+ If the file to viewed has PACK_MAGIC, LZH_MAGIC or compress magic
+ the code guesses that the uncompressed size is four times the
+ compressed size. If the uncompressed size is later found to be
+ smaller extra memory is freed with realloc.
+
+ * configure.in: When specifying --with-ncurses flag, add the
+ -lncurses library option. Added a missing fi to the script.
+
+ * view.c (search): If search string is not found, inform the user.
+ (load_view_file): Gzip support was showing uncompressed data only
+ worth the compressed size of the file. I fixed it and did two
+ other minor adjustments to the gzip support. I hope it will work
+ correctly now.
+
+Mon Oct 3 17:21:46 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (do_cd): trim directory to cd.
+ (do_cd): Use the new wonderful micro-garbage collector. This
+ should help to clean up the code in the future. I promise to
+ change the actual code with the time to use the garbage collector.
+ (do_cd): New: tilde expansion on cd.
+
+Mon Oct 3 09:30:59 1994 Miguel de Icaza (miguel@roxanne)
+
+ * main.c (main): Friendly hack.
+
+ * To configure the gpm mouse server, you need to specify
+ --with-console-mouse. Since now it always come with mouse support
+ (since you may be running in an xterm, again, all that was made by
+ Janne).
+
+ * mouse.c,main.c: changed use_mouse for use_gpm
+
+Mon Oct 3 09:23:04 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * win.c (define_label, define_label_quit): Now works on xterms.
+
+ * menu.c: Removed ifdefs around use_mouse, now on xterms it works.
+
+ * mouse.h: Modifications to use mouse on xterms without having the
+ gpm package installed.
+
+ * main.c: use_mouse_p now holds the type of mouse handling that is
+ done.
+ (main): Detect xterm and cleanup the constants.
+
+ * key.c (init_key): Changes for using mouse in xterms.
+ (xmouse_get_event): New function to handle xterminals mouse
+ events.
+ (mi_getch): Parse xterm escape sequences.
+
+ * view.c (load_view_file): Now it doesn't discard the first byte
+ of the uncompressed file.
+ * view.c: clean up.
+
+ * mouse.c: Include fcntl.h instead of sys/fcntl.h
+ (init_mouse): new code for xterm mouse handling.
+ (shut_mouse): new code for xterm mouse handling.
+
+Sun Oct 2 18:52:05 1994 Miguel de Icaza <miguel@sphinx>
+
+ * setup.c (save_setup,load_setup): Cleaned up setup loading/saving.
+
+ * zip.c (is_gunzipable): new function: determines if a file is
+ prone to be gunziped.
+
+ * view.c (hex_search): Added hex-search.
+ (load_view_file): Now it's possible to display gziped files in the
+ internal viewer.
+
+ * dialog.c (run_dialog): Fixed bug: call (*refresh_fn)() instead
+ of refresh_screen. Should do it a stack of refresh functions. To
+ be fixed
+
+Sun Oct 2 13:46:45 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * main.c (view_other_cmd): Added code to view command output on
+ xterms. C-o is binded to this command.
+
+Fri Sep 30 18:52:53 1994 Miguel de Icaza <miguel@sphinx>
+
+ * view.c (toggle_hex_mode): Disable regular expression searching
+ when given an hex pattern.
+
+Fri Sep 30 16:32:18 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * configure.in: when compiling in AIX, use -D_BSD
+
+ * main.c (mkdir_cmd): Spelling correction.
+
+ * view.c (view): Corrected: use variable version of max_dirt_limit
+ instead of constant.
+
+Fri Sep 30 11:33:36 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * view.c (view): On systems with no mmap or with buggy mmap
+ support, load the entire file into RAM and display it.
+
+Wed Sep 28 20:07:30 1994 Miguel de Icaza <miguel@sphinx>
+
+ * win.c (set_label_text): used for changing the values of the
+ labels.
+
+Wed Sep 28 20:06:41 1994 Massimo Fontanelli <MC8737@mclink.it>
+
+ * view.c (toggle_hex_mode): switch between Hex and Ascii labels
+
+Tue Sep 27 10:47:10 1994 Janne Kukonlehto <jtklehto@stekt.oulu.fi>
+
+ * view.c (view, one_line_up, one_line_down): scrolling speed
+ enhancements.
+
+ * view.c (display, toggle_hex_mode, move_forward, move_backward,
+ view): Added hex mode display of files.
+
+Fri Sep 23 13:29:54 1994 Miguel de Icaza <miguel@sphinx>
+
+ * main.c (mkdir_cmd): Fixed a little bug that didn't repaint
+ correctly the screen in some conditions, the fix is to pass the
+ name of the file to select to update_panels.
+
+Mon Sep 19 12:12:03 1994 Miguel de Icaza (miguel@sphinx)
+
+ * To show dates instead of permission, you need to manually add to
+ the .mc.ini file the default_list_perm = 0 setting.
+
+ * screen.c (repaint_file): More temporary support to show dates
+ instead of permission.
+
+ * setup.c (load_setup): Save the name of the profile in the global
+ pointer profile_name.
+
+ * main.c (umount_this_dir): Added C-x m and C-x u to manually
+ mount and umount directories. C-x a Toggles auto_mount flag.
+
+Sat Sep 17 15:50:42 1994 Miguel de Icaza (miguel@sphinx)
+
+ * auto.c (try_auto_mount): New routines for
+ auto-mounting/umounting directories.
+
+ * main.c (do_cd): Changes to allow auto_mounting.
+
+ * setup.c (load_setup): Changes to allow auto-mounting
+
+ * configure.in: We don't use the config.h.in file anymore, only
+ use the in the command line parameters.
+
+Fri Sep 16 17:38:18 1994 Miguel de Icaza (miguel@sphinx)
+
+ * ALPHA-2-0.15
+
+ * configure.in: AC_AIX added
+
+ * Replaced '\e' for ESC_CHAR, to allow compilation under AIX.
+
+Wed Sep 14 16:21:51 1994 Miguel de Icaza (miguel@roxanne)
+
+ * ALPHA-0.15
+
+ * Changes in many files to support GNU autoconf
+
+Thu Sep 8 12:50:34 1994 Herman Horsten (horsten@wins.uia.ac.be)
+
+ * Version 0.14
+
+ * view.c (view): Don't display empty files.
+
+Wed Sep 7 19:08:31 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c: Added Some extra C-x hot keys. The Alt-A Alt-a solution
+ to copying paths was very complex to remember.
+ (copy_tagged): C-x s, copies the tagged files or the selected
+ file to the command line.
+
+Tue Sep 6 15:58:49 1994 Miguel de Icaza (miguel@sphinx)
+
+ * util.c (unix_error_string): New unix_error_string function,
+ stolen from a posting of Roland McGrath in the mach4 mailing list
+ :-)
+
+Mon Sep 5 19:03:13 1994 Miguel de Icaza (miguel@sphinx)
+
+ * dir.h,dir.c,main.c,screen.c: Changes to allow unlimited
+ directory size handling.
+
+Tue Aug 30 14:22:04 1994 Miguel de Icaza (miguel@sphinx)
+
+ * Release 0.13
+
+ * main.c (ren_cmd): Changed the update_panels call, before it was
+ called with (UP_OPTIMIZE, 0, 0), now it's with UP_KEEPSEL to let
+ the bar stay near the original file was standing.
+ (menu_edit_cmd): Added menu file edit to the program.
+
+ * dir.c (do_load_dir): If there is no way to load a directory,
+ load a dummy directory.
+
+ * main.c: Added keybinding C-r to reread_cmd.
+ (do_re_sort): Now when resorting a panel, the selected file is
+ kept selected.
+
+Mon Aug 29 18:13:42 1994 Miguel de Icaza (miguel@sphinx)
+
+ * input.c (forward_word): Changed use of isalpha for isalnum in
+ order to skip over numbers.
+
+ * main.c (delete_cmd): Check that the result from query_dialog is
+ not escape (-1), since this deleted files when users pressed
+ esc. Oops.
+
+Mon Aug 29 16:36:27 1994 Jean-Daniel Luiset (luiset@cih.hcuge.ch)
+
+ * view.c (one_line_up,move_backward): Fix the backward scrolling.
+
+ * view.c (view_status): Change the way the computation of the
+ percentage to follow the Norton commander's (% from the beginning,
+ start = 0).
+
+ * view.c (view): Add KEY_HOME and KEY_END.
+
+Thu Aug 18 15:34:18 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (main): At setup, don't use the opanel and cpanel macros,
+ they don't point to valid data yet (until init_panels is called).
+
+Thu Aug 18 12:55:12 1994 Miguel de Icaza (miguel@roxanne)
+
+ * Release 0.12
+
+Wed Aug 17 19:39:12 1994 Miguel de Icaza (miguel@sphinx)
+
+ * dir.c(do_reload_dir): Added missing call to closedir, in the
+ Sparc it ran out of file handles.
+
+Mon Aug 15 13:54:34 1994 Miguel de Icaza (miguel@sphinx)
+
+ * key.c (mi_getch): When compiling under SVR4, untouchwin stdscr.
+
+ * main.c (ren_cmd): Bug fix: when file were selected, it only
+ searched from files [0..cpanel->marked] instead of
+ [0..cpanel->count].
+
+Thu Aug 11 18:19:08 1994 Miguel de Icaza (miguel@sphinx)
+
+ * dir.c (d_namelen): Define to allow compilation under IRIX and
+ Solaris 2. Thanks to Matthias Hammer
+ hammer@kirk.fmr.maschinenbau.th-darmstadt.de for his comments.
+
+Wed Aug 10 12:42:57 1994 Miguel de Icaza (miguel@sphinx)
+
+ * Release 0.11
+
+ * main.c: Changed hot-key for history.
+ (do_cd): support cd -.
+
+ * Makefile (dist): Moved mc.hlp dependency from install to dist.
+
+ * main.c (goto_bottom_file, goto_top_file, goto_middle_file),
+ functions to quickly select a file.
+ (main): Now correctly chdirs to the first directory specified in
+ the command line.
+
+ * util.c (trim): Now, it correctly trims the directory names.
+
+ * main.c (ok_to_copy): Fixed a very ugly bug in ok_to_copy. I was
+ freeing the wrong pointer.
+
+Tue Aug 9 14:23:51 1994 Miguel de Icaza (miguel@sphinx)
+
+ * menu.c (get_motion): Allow the first character in a query to
+ select the option.
+
+ * setup.c (save_setup): Now, instead of setting the defaults in
+ setup.c, use the values provided by the definition of the
+ variables.
+
+ * key.c (mi_getch): Fixed the mouse event auto repeat timeout
+ problem.
+
+ * menu.c (run_menu): Corrected bug that prevented option letters
+ from being used for selection in the menus.
+
+Tue Aug 9 13:39:35 1994 Torben Fjerdingstad <tfj@olivia.ping.dk>
+
+ * main.c (copy_cmd): use copy_file_file when copying to a file and
+ not copy_file_dir.
+ * main.c (main): Added missing "c" to getopt option.
+ * main.c (execute): Added call to cbreak () to allow "any key to
+ continue, and not just break".
+
+Mon Aug 1 14:13:07 1994 Miguel de Icaza (miguel@sphinx)
+
+ * Release 0.9
+
+ * menu.c (send_yes_event): Send an enter when the right mouse
+ button is pressed on menu_bars.
+
+ * main.c (panel_event): Added inline mark_if_marking to allow
+ marking when dragging the mouse.
+ (mkdir_cmd): changed update_panels (..., UP_KEEPSEL...) for not
+ trying to keep the selection. This fixed a bug when creating a
+ subdirectory.
+
+ * screen.c (repaint_file): Added call to wrefresh to fix the bug
+ in b&w mode.
+
+Fri Jul 29 12:03:23 1994 Miguel de Icaza (miguel@sphinx)
+
+ * mouse.c: (mouse_handler): Redraw correctly the mouse pointer.
+
+ * mc.1: Updates to the documentation.
+
+ * main.c (action): If trying to execute a symlink, check that the
+ file it points to is an executable.
+ (main): Added option to negate Force Black and White.
+
+ * dir.c (if_link_is_exe): New function, used to check if a symlink
+ points to an executable.
+
+ * screen.c (repaint_file): Instead of showing ctime, display
+ mtime. Fix by Torben Fjerdingstad <tfj@olivia.ping.dk>.
+
+Thu Jul 28 17:13:07 1994 Miguel de Icaza (miguel@sphinx)
+
+ * file.c (copy_file_file): Added verbose operation for file
+ copying.
+
+ * main.c (do_nc): If connection baud rate is too slow, verbose
+ mode is turned off.
+
+ * file.c (copy_file_file): Add verbose messages when copying a
+ file.
+
+ * main.c (main): Bug fix when specifying directories in the command
+ line.
+ (delete_cmd): Fixed a bug in the newly introduced confirm delete.
+
+ * file.c: New builtin copy command, taken from GNU's cp.
+
+ * main.c (do_cd): If we cant open the specified directory
+ (copy_cmd): Added confirmation when overwriting files.
+
+ * dir.c (do_load_dir): Avoid segmentation fault if we can cd into
+ a directory, but don't have read access.
+
+Wed Jul 27 17:07:58 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (pre_exec): Call shut_mouse before running a child
+ process. This is to avoid getting unhandled events. Thanks to
+ Alessandro Rubini.
+ (post_exec): Call init_mouse after return.
+
+ * Various changes to rename the MouseLess Commander from 'nc' to 'mc'.
+
+ * mouse.c (mouse_handler): Removed the mouse cursor display, let
+ the server do the work.
+ (init_mouse): Let the server handle GPM_MOVE|GPM_HARD.
+ use that in defaultMask. Enhancement by Alessandro Rubini
+ (rubini@ipvvis.UNIPV.IT).
+
+Tue Jul 26 14:37:35 1994 Miguel de Icaza (miguel@sphinx)
+
+ * dialog.c (create_dialog): When creating a dialog, a new frame is
+ pushed with the coordinates of the dialog.
+ (destroy_dialog): Call pop_frame.
+
+ * mouse.c (push_frame): Remember active mouse_events pointer.
+ (pop_frame): Pop mouse_events until previous state is restored.
+
+ * menu.c (run_bar): Now uses the frames to enter/leave subroutines.
+
+ * view.c (view): Now uses the frames to enter/leave subroutines.
+
+ * input.c (handle_char): Don't allow characters > 127 to be
+ inserted in input lines.
+
+ * help.c (interactive_display): When selecting a target outside
+ the view windows, start the display at the point where the link
+ was found.
+
+ * menu.c (run_menu): Menu entry lengths are not limited to 20
+ characters any more.
+ (run_menu): Code cleanup and added mouse support.
+
+ * user.c (menu_input_loop): Now uses my_getch.
+
+Mon Jul 25 16:14:49 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (delete_cmd): Added delete confirmation.
+
+ * view.c (init_view): Added null_event handling.
+ (search): Source code reorganization for mouse handling.
+
+ * user.c, help.c: Display error message if unable to open file.
+
+ * util.c (load_file): If there is a problem stat()ing or open()ing
+ the file, return 0 and don't show any message.
+
+ * main.c (action): Split enter () in enter () and action (). The
+ later is to be called by the mouse handler.
+ (panel_event): Added double click managing.
+ (main): Added nice usage message
+
+ * dialog.c (destroy_dialog): Changed name (was: done_dialog),
+ null_event handling.
+
+Fri Jul 22 18:58:21 1994 Miguel de Icaza (miguel@sphinx)
+
+ * screen.c (display_mini_info): The mini info now shows the number
+ in pretty format.
+
+ * util.c (size_trunc_sep): Nice formating of numbers.
+
+ * main.c (init_panels): Added events for the panels.
+ (panel_event): Added function that handles mouse events.
+
+ * key.c (mi_getch): Various changes to support the mouse.
+
+Thu Jul 21 13:20:41 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (move_up, move_down): Call select_item always, as
+ cpanel->selected must be properly set.
+ (reverse_cmd): Now, it's possible to sort the file in inverse order.
+
+Tue Jul 19 15:03:29 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (long_cmd): Bug fixes to disable activating a panel that
+ is disabled.
+
+ * setup.c (options_load): Now per panel options are saved.
+
+ * util.c (name_trunc): Added new truncate option. Now we use a ~
+ in the middle of the name instead of a > at the end of the
+ truncated name.
+
+ * input.c (create_input): More Input line changes.
+
+ * find.c (input_find): Adjustments to create_input.
+
+Mon Jul 18 17:02:46 1994 Miguel de Icaza (miguel@sphinx)
+
+ * dialog.c (my_wputs): Workaround ncurses wclreol when printing
+ \n. Better visual effect.
+
+ * screen.c (display_mini_info): When displaying the brief format,
+ show in the mini info the details of the directory.
+
+Fri Jul 15 12:23:46 1994 Miguel de Icaza (miguel@sphinx)
+
+ * win.c (define_label): Added callback support.
+
+ * main.c (init_labels): Added callbacks for mouse operations.
+
+ * input.c: More code reorganization; new Alt-D and Alt-Backspace
+ key handling.
+
+Thu Jul 14 19:37:18 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (toggle_fast_reload): Show the warning message when
+ activating for the first time the Fast directory reload.
+
+Wed Jul 13 11:51:51 1994 Miguel de Icaza (miguel@sphinx)
+
+ * util.c (init_uid_gid_cache): New cache for get_group and
+ get_name. This should speed up the Long directory listing.
+
+ * input.c (delete_char): New function. Patch from Ralf G. R. Bergs
+ <rabe@advw2.GM.FH-Koeln.DE>.
+ (backward_word): Skip correctly over punctuation characters.
+
+Mon Jul 11 14:36:15 1994 Miguel de Icaza (miguel@sphinx)
+
+ * input.c: New command history in all input lines.
+
+ * view.c (view_status): Display 100 percent with files with 0
+ bytes size.
+
+ * screen.c (repaint_file): Small cosmetic change that paints
+ >UP--DIR< when the directory is "..".
+
+ * input.c (handle_char): Use a keymap instead of the old switch in
+ the input mechanism.
+ (kill_save): Updated kill/yank mechanism.
+
+ * main.c (start_search): Now it's again possible to search
+ incrementally for a file name.
+ (do_search): Now can go back in the search string.
+
+Wed Jul 6 14:43:12 1994 Miguel de Icaza (miguel@sphinx)
+
+ * help.c (interactive_display): Added entries for page-up,
+ page-down.
+
+ * main.c (mkdir_cmd): Added missing call to select_item to
+ reselect the just created directory.
+
+Mon Jul 4 12:52:34 1994 Miguel de Icaza (miguel@sphinx)
+
+ * Release 0.8
+
+ * help.c: Changed node separator from '%' to ^D (octal 004).
+ (interactive_display): When pressing enter on a node without
+ links, go back to the previous link.
+
+ * util.c (regexp_match): Removed buggy optimization for detecting
+ same if the same pattern was being applied.
+
+ * main.c (try_to_select): Added call to display_mini_info.
+ try_to_select may be called when the file does not exist anymore.
+
+ * find.c (select_and_change_panel): When changing directories,
+ reset the total byte count (cpanel->total).
+
+ * main.c (do_cd): When changing directories, reset the total byte
+ count (cpanel->total).
+
+ * help.c (search_string_node): If start is 0, return the main node.
+
+ * man2hlp.pl, gindex.pl: New programs to convert the man page to
+ the help file format.
+
+Thu Jun 30 14:25:34 1994 Miguel de Icaza (miguel@roxanne)
+
+ * Changes all over the place to remove warnings from -Wall
+ -Wno-implicit.
+
+Wed Jun 29 15:32:06 1994 Miguel de Icaza (miguel@sphinx)
+
+ * input.c (handle_char): Input lines now support M-b, M-f for word
+ by word movement.
+
+ * main.c (default_key, do_nc): Now file name searches are started with
+ the Alt-S keysequence. Code cleanup.
+
+ * input.h (ALT): New Macro for alt-keys
+
+ * input.c (create_input, insert_char, update_input): All input
+ lines are malloced. They realloc as needed, they scroll as needed.
+
+ * find.c (input_find): Keep in sync with new Input line management.
+
+ * main.c (ren_cmd, copy_cmd, mkdir_cmd, select_cmd, unselect_cmd):
+ Fixed small bug. Keep in sync with the new Input line management.
+
+ * dialog.c (input_dialog): Keep in sync with new Input line
+ management.
+
+ * main.c (do_nc): Use COLS-strlen(prompt) instead of COLS-2-...
+
+ * input.c (create_input): Code cleanup.
+
+ * main.c (main): The unknown option is already handled by getopt,
+ just exit(1).
+
+ * key.c (mi_getch): Bug fix: Added option to recognize ESC-Tab.
+
+Mon Jun 27 13:01:03 1994 Miguel de Icaza (miguel@sphinx)
+
+ * Release 0.7
+
+ * screen.c (Xtry_to_select): New: now tries to select a file near
+ the deleted file. The old behavior was really painful.
+
+ * main.c (toggle_fast_reload): Added configuration option to use
+ fast directory reload.
+ (main): Abort execution if unknown option passed to the program.
+ (execute): Replaced repaint_screen for refresh_screen.
+ (select_item): New macro to select a file without repainting the
+ screen.
+ (try_to_select): Select without repainting the selection.
+
+ * screen.c (panel_reload), main.c (save_cwds_stat): Now,
+ optionally use the stat trick to do a fast reload of a directory.
+
+ * profile.c: Added include sys/types.h
+ (GetPrivateProfileInt): Extended the integer array size from 5 to
+ 6.
+
+Fri Jun 24 12:25:25 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (main): Call save_stop_handler ().
+ (pre_exec): Call endwin ().
+ (execute): call my_system, this should get rid of most of the
+ problems related to complex commands spawned.
+ (execute): removed call to repaint_screen.
+
+ * util.c (my_system): Misc changes to replace the actual execute
+ command sequence. This must fix also the annoying bug that
+ repaints the screen.
+
+ * ext.c (regex_command): Now it correctly recognizes all the
+ extensions in the extension file.
+
+ * main.c (mark_file): Fixed bug that didn't repaint the mini info
+ in some conditions.
+
+Wed Jun 22 18:49:07 1994 Miguel de Icaza (miguel@sphinx)
+
+ * screen.c (panel_reload): Now it correctly clears the number of
+ bytes in tagged files.
+
+ * main.c (main): Added option -P that prints the ending working
+ directory at program exit. It's still buggy.
+
+ * dir.c: Now it's possible when sorting files to show files and
+ directories together or separated (like the original nc).
+
+ * main.c (mark_file): Fixed cosmetic bug that didn't clear the
+ mini_info area correctly.
+
+ * screen.c (repaint_file): Added support for showing dates instead
+ of permissions in the panels. Still no way to activate it.
+
+ * main.c (copy_other_prog_name): Added Meta-Tab key. It inserts
+ the selected file name in the other panel into the input line.
+
+Tue Jun 21 19:25:26 1994 Miguel de Icaza (miguel@sphinx)
+
+ * help.c (interactive_display): Added history to the hypertext
+ browser.
+
+Tue Jun 14 17:47:30 1994 Miguel de Icaza (miguel@sphinx)
+
+ * find.c: new version from Mauricio.
+
+ * main.c (save_cwds_stat): removed the stat () trick optimization.
+
+ * screen.c (panel_reload): removed the stat () trick optimization,
+ it's not working in some cases, and I don't know how to fix it.
+
+Mon Jun 13 20:32:07 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (ext_cmd): Fixed bug that didn't pass home_dir to sprintf.
+ (mkdir_cmd): Now it will select the directory just created.
+
+ (do_edit,xmalloc): Thomas Roettgers fixes to a couple of bugs.
+
+Mon Jun 13 17:40:36 1994 Mauricio Plaza (mok@lya.fciencias.unam.mx)
+
+ * find.c: Many bug fixes.
+
+Wed Jun 1 17:19:13 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c: corrected entry for User Menu.
+
+ * view.c (move_forward, move_backward): Corrected bug, fix by
+ Torben Fjerdingstad <tfj@olivia.ping.dk>.
+
+ * main.c: replaced condition marked > 1 by marked > 0. The code
+ didn't check correctly when only one file was tagged and operated
+ on the selection instead.
+
+Tue May 31 19:59:30 1994 Miguel de Icaza (miguel@sphinx)
+
+ * user.c (execute_menu_command): Fixed temporary file unlink bug.
+
+ * ext.c (exec_extension): Fixed temporary file unlink bug.
+
+ * main.c (ext_cmd): New extension file edit command.
+
+ * user.c (expand_format): expansion of %f, %d, %F and %D in the
+ user menu commands and in the extension dependent exec.
+
+ * ext.c (regex_command): Execution of programs based on the
+ filename extension implemented.
+
+ * menu.c (run_menu): Fixed bug to select entries in the menus by
+ letter.
+
+Mon May 30 13:03:07 1994 Miguel de Icaza (miguel@sphinx)
+
+ * screen.c, main.c: various changes to optimize directory loading
+ (suggested by Torben Fjerdingstad <tfj@olivia.ping.dk>). Now it's
+ a pleasure to use the program even on /usr/local/bin.
+ (long_frame): corrected cosmetic bug (COLS/2 -> COLS-2)
+
+ * color.c: Added option to disable colors.
+
+ * main.c (main): Now it's possible to specify an initial directory
+ for both panels.
+
+ (main): Added option to disable colors.
+
+ (main): -V option added to report version number.
+
+Mon May 23 21:12:14 1994 Miguel de Icaza (miguel@sphinx)
+
+ * help.c, menu.c: added copyright
+
+ * view.c (display): Don't display characters above 127.
+ (init_view): Added clearok to view_win to clean the screen before
+ updating view_win.
+
+Sun May 15 14:11:47 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c: fixed bug that didn't set correctly select variable
+ after calling try_to_select.
+
+Sat May 14 13:43:58 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c: Added help and user menu to the File Menu.
+
+ * dialog.c (refresh_fn): points to a variable to refresh the
+ current screen.
+
+ * util.c (icase_search): new routine based on search_string.
+
+ * help.c (search_string): corrected typo (e now is *e).
+
+Thu May 12 16:40:45 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c: Misc patches to interface the new internal viewer.
+
+ * view.c: New internal viewer.
+
+ * key.c (mi_getch): Added support for ESC->, ESC-<,
+ ESC-Upper(letter).
+
+ * screen.c: many changes to support long display
+
+ * main.c: misc changes for support for long display
+
+ * main.c: Use panel_refresh instead of wrefresh (panel->win_file).
+
+ * main.c: Fixed bug that didn't correctly set the selection
+ variable when using page/up/down/home/end keys.
+
+Wed May 11 15:52:49 1994 Miguel de Icaza (miguel@sphinx)
+
+ * help.c: corrected bug that crashed the program (trying to select
+ a link on a node without links).
+
+Tue May 10 11:40:21 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (move_home): now it goes home no matter if top_file is 0.
+
+Mon May 9 11:01:09 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (suspend_cmd): Added suspend option.
+ (enter): Allow "cd" and "cd " to chdir to $HOME
+ (do_cd): Allow "cd" and "cd " to chdir to $HOME
+
+Sun May 8 13:42:41 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (execute): system now executes commands by calling the
+ user's shell with -c command argument.
+
+ * screen.c (try_to_select): Corrected bug introduced when fixing
+ selection of root directory subdirectories.
+
+ * user.c: New: user menus.
+
+ * main.c: Corrected unselect key.
+
+Fri May 6 13:10:52 1994 Miguel de Icaza (miguel@sphinx)
+
+ * screen.c (try_to_select): Correctly try_to_select when going up
+ to the root directory.
+
+Tue May 3 11:07:45 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (init_panels): Now it correctly changes the other_dir
+ (update_panels): does a chdir to cpanel->cwd after updating
+ the information.
+
+ * screen.c (display_mini_info): Changed selection for
+ panel->dir [panel->selected].fname since it showed wrong
+ information in opanel.
+
+ * main.c: (check_menu_panel): Corrected indexes to reflex the
+ released features
+
+ * main.c (copy_cmd): Now it unselects the copied files.
+
+ * main.c, util.c: Added setup loading/saving.
+
+ * util.c (regexp_match): modified code to handle the '?' meta
+ command as a '.' in the regular expression.
+
+ * input.c (handle_char): When pasting characters with c-y the
+ buffer would overflow.
+
+ * main.c (ren_cmd): fixed minor bug.
+
+Mon May 2 10:25:11 1994 Miguel de Icaza (miguel@sphinx)
+
+ * many changes to support variable screen widths/lengths.
+
+ * color.h, menu.c: Fixed problem with menu colors on monochrome
+ terminals.
+
+ * dir.c (do_reload_dir): Fixed bug that didn't retag correctly the
+ files (next_free instead of count).
+
+Sun May 1 16:29:05 1994 Miguel de Icaza (miguel@sphinx)
+
+ * main.c (cmd_quit): Asks before quitting, clear screen when
+ finishing the program.
+
+ * menu.c (get_motion): Fixed bug for query box.
+
+ * find.c (select_and_change_panel): Call select_item to update the
+ content of the selection variable.
+
+ (do_find): After running the find, restore nodelay to false.
+
--- /dev/null
+/* Configure box module for the Midnight Commander
+ Copyright (C) 1994 Radek Doulik
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+/* Needed for the extern declarations of integer parameters */
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include "tty.h"
+#include "mad.h"
+#include "util.h"
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "setup.h" /* For save_setup() */
+#include "dialog.h" /* For do_refresh() */
+#include "main.h"
+#include "profile.h" /* For sync_profiles */
+
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "layout.h" /* For nice_rotating_dash */
+#define PX 4
+#define PY 2
+
+#define RX 4
+#define RY 11
+
+#define BY 16
+#define OY 2
+
+static Dlg_head *conf_dlg;
+
+static int r_but;
+
+#define TOGGLE_VARIABLE 0
+
+extern int use_internal_edit;
+
+int dummy;
+
+static int OX = 33, first_width = 27, second_width = 27;
+static char *configure_title, *title1, *title2, *title3;
+
+static struct {
+ char *text;
+ int *variable;
+ void (*toggle_function)(void);
+ WCheck *widget;
+ char *tk;
+} check_options [] = {
+ {N_("safe de&Lete"), &know_not_what_am_i_doing, TOGGLE_VARIABLE,0, "safe-del" },
+ {N_("cd follows lin&Ks"), &cd_symlinks, TOGGLE_VARIABLE, 0, "cd-follow" },
+ {N_("advanced cho&Wn"), &advanced_chfns, TOGGLE_VARIABLE, 0, "achown" },
+ {N_("l&Ynx-like motion"), &navigate_with_arrows,TOGGLE_VARIABLE, 0, "lynx" },
+#ifdef HAVE_GNOME
+ {N_("Animation"), &dummy, TOGGLE_VARIABLE, 0, "dummy" },
+#else
+ {N_("ro&Tating dash"), &nice_rotating_dash,TOGGLE_VARIABLE, 0, "rotating" },
+#endif
+ {N_("co&Mplete: show all"),&show_all_if_ambiguous,TOGGLE_VARIABLE, 0, "completion" },
+ {N_("&Use internal view"), &use_internal_view, TOGGLE_VARIABLE, 0, "view-int" },
+ {N_("use internal ed&It"), &use_internal_edit, TOGGLE_VARIABLE, 0, "edit-int" },
+ {N_("auto m&Enus"), &auto_menu, TOGGLE_VARIABLE, 0, "auto-menus" },
+ {N_("&Auto save setup"), &auto_save_setup, TOGGLE_VARIABLE, 0, "auto-save" },
+ {N_("shell &Patterns"), &easy_patterns, TOGGLE_VARIABLE, 0, "shell-patt" },
+ {N_("&Verbose operation"), &verbose, TOGGLE_VARIABLE, 0, "verbose" },
+ {N_("&Fast dir reload"), &fast_reload, toggle_fast_reload, 0, "fast-reload" },
+ {N_("mi&X all files"), &mix_all_files, toggle_mix_all_files, 0, "mix-files" },
+ {N_("&Drop down menus"), &drop_menus, TOGGLE_VARIABLE, 0, "drop-menus" },
+ {N_("ma&Rk moves down"), &mark_moves_down, TOGGLE_VARIABLE, 0, "mark-moves" },
+ {N_("show &Hidden files"), &show_dot_files, toggle_show_hidden, 0, "show-hidden" },
+ {N_("show &Backup files"), &show_backups, toggle_show_backup, 0, "show-backup" },
+ { 0, 0, 0, 0 }
+};
+
+static WRadio *pause_radio;
+
+static char *pause_options [3] = {
+ N_("&Never"),
+ N_("on dumb &Terminals"),
+ N_("alwa&Ys") };
+
+static int configure_callback (struct Dlg_head *h, int Id, int Msg)
+{
+ switch (Msg) {
+ case DLG_DRAW:
+#ifndef HAVE_X
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 1, 2, h->lines - 2, h->cols - 4);
+ draw_box (h, PY, PX, 8, first_width);
+ draw_box (h, RY, RX, 5, first_width);
+ draw_box (h, OY, OX, 14, second_width);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 1, (h->cols - strlen(configure_title))/2);
+ addstr (configure_title);
+ dlg_move (h, OY, OX+1);
+ addstr (title3);
+ dlg_move (h, RY, RX+1);
+ addstr (title2);
+ dlg_move (h, PY, PX+1);
+ addstr (title1);
+#endif
+ break;
+
+ case DLG_END:
+ r_but = Id;
+ break;
+ }
+ return 0;
+}
+
+static void init_configure (void)
+{
+ int i;
+ static int i18n_config_flag = 0;
+ static int b1, b2, b3;
+ char* ok_button = _("&Ok");
+ char* cancel_button = _("&Cancel");
+ char* save_button = _("&Save");
+
+ if (!i18n_config_flag)
+ {
+ register int l1;
+
+ /* Similar code is in layout.c (init_layout()) */
+
+ configure_title = _(" Configure options ");
+ title1 = _(" Panel options ");
+ title2 = _(" Pause after run... ");
+ title3 = _(" Other options ");
+
+ first_width = strlen (title1) + 1;
+ for (i = 12; i < 18; i++)
+ {
+ check_options[i].text = _(check_options[i].text);
+ l1 = strlen (check_options[i].text) + 7;
+ if (l1 > first_width)
+ first_width = l1;
+ }
+
+ i = sizeof(pause_options)/sizeof(char*);
+ while (i--)
+ {
+ pause_options [i] = _(pause_options [i]);
+ l1 = strlen (pause_options [i]) + 7;
+ if (l1 > first_width)
+ first_width = l1;
+ }
+
+ l1 = strlen (title2) + 1;
+ if (l1 > first_width)
+ first_width = l1;
+
+ OX = first_width + 5;
+
+ second_width = strlen (title3) + 1;
+ for (i = 0; i < 12; i++)
+ {
+ check_options[i].text = _(check_options[i].text);
+ l1 = strlen (check_options[i].text) + 7;
+ if (l1 > second_width)
+ second_width = l1;
+ }
+
+ l1 = 11 + strlen (ok_button)
+ + strlen (save_button)
+ + strlen (cancel_button);
+
+ i = (first_width + second_width - l1) / 4;
+ b1 = 5 + i;
+ b2 = b1 + strlen(ok_button) + i + 6;
+ b3 = b2 + strlen(save_button) + i + 4;
+
+ i18n_config_flag = 1;
+ }
+
+ conf_dlg = create_dlg (0, 0, 19, first_width + second_width + 9,
+ dialog_colors, configure_callback, "[Options Menu]",
+ "option", DLG_CENTER | DLG_GRID);
+
+ x_set_dialog_title (conf_dlg, _("Configure options"));
+
+ add_widgetl (conf_dlg,
+ button_new (BY, b3, B_CANCEL, NORMAL_BUTTON, cancel_button, 0, 0, "button-cancel"),
+ XV_WLAY_RIGHTOF);
+
+ add_widgetl (conf_dlg,
+ button_new (BY, b2, B_EXIT, NORMAL_BUTTON, save_button, 0, 0, "button-save"),
+ XV_WLAY_RIGHTOF);
+
+ add_widgetl (conf_dlg,
+ button_new (BY, b1, B_ENTER, DEFPUSH_BUTTON, ok_button, 0, 0, "button-ok"),
+ XV_WLAY_CENTERROW);
+
+#define XTRACT(i) *check_options[i].variable, check_options[i].text, check_options [i].tk
+
+ /* Add all the checkboxes */
+ for (i = 0; i < 12; i++){
+ check_options [i].widget = check_new (OY + (12-i), OX+2, XTRACT(i));
+ add_widgetl (conf_dlg, check_options [i].widget,
+ XV_WLAY_BELOWCLOSE);
+ }
+
+ pause_radio = radio_new (RY+1, RX+2, 3, pause_options, 1, "pause-radio");
+ pause_radio->sel = pause_after_run;
+#ifndef HAVE_GNOME
+ add_widgetl (conf_dlg, pause_radio, XV_WLAY_BELOWCLOSE);
+#endif
+ for (i = 0; i < 6; i++){
+ check_options [i+12].widget = check_new (PY + (6-i), PX+2,
+ XTRACT(i+12));
+ add_widgetl (conf_dlg, check_options [i+12].widget,
+ XV_WLAY_BELOWCLOSE);
+ }
+#ifdef HAVE_XVIEW
+ add_widgetl (conf_dlg, label_new (OY, OX + 1, _("Other options"), "label-other"),
+ XV_WLAY_NEXTCOLUMN);
+ add_widgetl (conf_dlg, label_new (RY, RX + 1, _("Pause after run..."), "label-pause"),
+ XV_WLAY_BELOWOF);
+ add_widgetl (conf_dlg, label_new (PY, PX + 1, _("Panel options"), "label-panel"),
+ XV_WLAY_NEXTCOLUMN);
+#endif
+}
+
+
+void configure_box (void)
+{
+ int result, i;
+
+ init_configure ();
+ run_dlg (conf_dlg);
+
+ result = conf_dlg->ret_value;
+ if (result == B_ENTER || result == B_EXIT){
+ for (i = 0; check_options [i].text; i++)
+ if (check_options [i].widget->state & C_CHANGE){
+ if (check_options [i].toggle_function)
+ (*check_options [i].toggle_function)();
+ else
+ *check_options [i].variable =
+ !(*check_options [i].variable);
+ }
+ pause_after_run = pause_radio->sel;
+ }
+
+ /* If they pressed the save button */
+ if (result == B_EXIT){
+ save_configure ();
+ sync_profiles ();
+ }
+
+ destroy_dlg (conf_dlg);
+}
--- /dev/null
+#ifndef __OPTION_H
+#define __OPTION_H
+void configure_box (void);
+#endif
--- /dev/null
+#ifndef __PANEL_H
+#define __PANEL_H
+
+#include "dir.h" /* file_entry */
+#include "dlg.h"
+#include "widget.h" /* for history loading and saving */
+
+#define LIST_TYPES 5
+
+enum list_types {
+ list_full, /* Name, size, perm/date */
+ list_brief, /* Name */
+ list_long, /* Like ls -l */
+ list_user, /* User defined */
+ list_icons /* iconic display */
+};
+
+enum view_modes {
+ view_listing, /* Directory listing */
+ view_info, /* Information panel */
+ view_tree, /* Tree view */
+ view_quick, /* Quick view */
+ view_nothing /* Undefined */
+};
+
+enum panel_display_enum {
+ frame_full, /* full screen frame */
+ frame_half /* half screen frame */
+};
+
+#define is_view_special(x) ((x == view_info) || (x == view_quick))
+
+#define J_LEFT 0
+#define J_RIGHT 1
+
+#define NORMAL 0
+#define SELECTED 1
+#define MARKED 2
+#define MARKED_SELECTED 3
+#define STATUS 5
+
+/*
+ * This describes a format item. The parse_display_format routine parses
+ * the user specified format and creates a linked list of format_e structures.
+ *
+ * parse_display_format computes the actual field allocations if
+ * the COMPUTE_FORMAT_ALLOCATIONs define is set. MC frontends that are
+ * just interested in the parsed display format should not set this define.
+ */
+typedef struct format_e {
+ struct format_e *next;
+ int requested_field_len;
+ int field_len;
+ int just_mode;
+ int expand;
+ char *(*string_fn)(file_entry *, int len);
+ char *title;
+ char *id;
+
+ /* first format_e has the number of items */
+ int items;
+ int use_in_gui;
+} format_e;
+
+typedef struct {
+ Widget widget;
+ dir_list dir; /* Directory contents */
+
+ int list_type; /* listing type (was view_type) */
+ int active; /* If panel is currently selected */
+ char cwd [MC_MAXPATHLEN];/* Current Working Directory */
+ char lwd [MC_MAXPATHLEN];/* Last Working Directory */
+ Hist *dir_history; /* directory history */
+ char *hist_name; /* directory history name for history file */
+ int count; /* Number of files in dir structure */
+ int marked; /* Count of marked files */
+ int dirs_marked; /* Count of marked directories */
+ long int total; /* Bytes in marked files */
+ int top_file; /* The file showed on the top of the panel */
+ int selected; /* Index to the selected file */
+ int reverse; /* Show listing in reverse? */
+ int case_sensitive; /* Listing is case sensitive? */
+ int split; /* Split panel to allow two columns */
+ int is_panelized; /* Flag: special filelisting, can't reload */
+ int frame_size; /* half or full frame */
+ int icons_per_row; /* Icon view; how many icons displayed per row */
+ sortfn *sort_type; /* Sort type */
+ char *filter; /* File name filter */
+
+ int dirty; /* Should we redisplay the panel? */
+
+ int user_mini_status; /* Is user_status_format used */
+ char *user_format; /* User format */
+ char *user_status_format[LIST_TYPES];/* User format for status line */
+
+ format_e *format; /* Display format */
+ format_e *status_format; /* Mini status format */
+
+ int format_modified; /* If the format was changed this is set */
+
+ char *panel_name; /* The panel name */
+ struct stat dir_stat; /* Stat of current dir: used by execute () */
+
+ char *gc;
+ void *font;
+ int item_height;
+ int total_width;
+ int ascent;
+ int descent;
+
+ int searching;
+ char search_buffer [256];
+
+ int has_dir_sizes; /* Set if directories have sizes = to du -s */
+
+#ifdef HAVE_GNOME
+ /* These are standard GtkWidgets */
+
+ void *xwindow; /* The toplevel window */
+
+ void *table;
+ void *list;
+ void *icons;
+ void *status;
+ void *ministatus;
+
+ void *filter_w; /* A WInput* */
+ void *current_dir; /* A WInput* */
+ int estimated_total;
+
+ /* navigation buttons */
+ void *back_b;
+ void *fwd_b;
+ void *up_b;
+#endif
+} WPanel;
+
+WPanel *panel_new (char *panel_name);
+void panel_set_size (WPanel *panel, int x1, int y1, int x2, int y2);
+void paint_paint (WPanel *panel);
+void panel_refresh (WPanel *panel);
+void Xtry_to_select (WPanel *panel, char *name);
+
+int is_a_panel (Widget *);
+
+extern int torben_fj_mode;
+extern int permission_mode;
+extern int filetype_mode;
+extern int show_mini_info;
+extern int panel_scroll_pages;
+
+#define selection(p) (&(p->dir.list [p->selected]))
+
+extern int fast_reload;
+
+extern int extra_info;
+
+/*#define ITEMS(p) ((p)->view_type == view_brief ? (p)->lines *2 : (p)->lines)
+*/
+/* The return value of panel_reload */
+#define CHANGED 1
+
+#define PANEL_ISVIEW(p) (p->view_type == view_brief || \
+ p->view_type == view_full || \
+ p->view_type == view_long || \
+ p->view_type == view_user || \
+ p->view_type == view_tree)
+
+#define RP_ONLY_PAINT 0
+#define RP_SETPOS 1
+
+void set_colors (WPanel *panel);
+void paint_panel (WPanel *panel);
+void format_file (char *dest, WPanel *panel, int file_index, int panel_width, int attr, int isstatus);
+void repaint_file (WPanel *panel, int file_index, int move, int attr, int isstatus);
+void display_mini_info (WPanel *panel);
+void panel_reload (WPanel *panel);
+void paint_dir (WPanel *panel);
+void show_dir (WPanel *panel);
+
+/* NOTE: Have to be ifdefed for HAVE_X */
+void x_panel_set_size (int index);
+void x_create_panel (Dlg_head *h, widget_data parent, WPanel *panel);
+void x_fill_panel (WPanel *panel);
+void x_adjust_top_file (WPanel *panel);
+void x_filter_changed (WPanel *panel);
+void x_add_sort_label (WPanel *panel, int index, char *text, char *tag, void *sr);
+void x_sort_label_start (WPanel *panel);
+void x_reset_sort_labels (WPanel *panel);
+void x_panel_destroy (WPanel *panel);
+void change_view (WPanel *panel, int view_type);
+void x_panel_update_marks (WPanel *panel);
+
+extern void paint_info_panel (WPanel *);
+extern void paint_quick_view_panel (WPanel *);
+void info_frame (WPanel *panel);
+extern WPanel *the_info_panel;
+void paint_frame (WPanel *panel);
+void panel_update_contents (WPanel *panel);
+void panel_update_cols (Widget *widget, int frame_size);
+format_e *use_display_format (WPanel *panel, char *format, char **error, int isstatus);
+char *panel_format (WPanel *panel);
+char *mini_status_format (WPanel *panel);
+int set_panel_formats (WPanel *p);
+
+WPanel *get_current_panel (void);
+WPanel *get_other_panel (void);
+
+#define other_panel get_other_panel()
+
+extern WPanel *left_panel;
+extern WPanel *right_panel;
+extern WPanel *current_panel;
+
+void try_to_select (WPanel *panel, char *name);
+
+#define DEFAULT_USER_FORMAT "half type,name,|,size,|,perm"
+
+/* This were in main: */
+void unmark_files (WPanel *panel);
+void select_item (WPanel *panel);
+int ITEMS (WPanel *p);
+void unselect_item (WPanel *panel);
+
+extern Hook *select_file_hook;
+
+char *string_file_type (file_entry *fe, int len);
+char *string_file_size_brief (file_entry *fe, int len);
+char *string_file_permission (file_entry *fe, int len);
+char *string_file_nlinks (file_entry *fe, int len);
+char *string_file_owner (file_entry *fe, int len);
+char *string_file_group (file_entry *fe, int len);
+char *string_file_size (file_entry *fe, int len);
+char *string_file_mtime (file_entry *fe, int len);
+char *string_file_atime (file_entry *fe, int len);
+char *string_file_ctime (file_entry *fe, int len);
+char *string_file_name (file_entry *fe, int len);
+char *string_space (file_entry *fe, int len);
+char *string_dot (file_entry *fe, int len);
+char *string_marked (file_entry *fe, int len);
+char *string_file_perm_octal (file_entry *fe, int len);
+char *string_inode (file_entry *fe, int len);
+char *string_file_ngid (file_entry *fe, int len);
+char *string_file_nuid (file_entry *fe, int len);
+
+void file_mark (WPanel *panel, int index, int val);
+void do_file_mark (WPanel *panel, int index, int val);
+int file_compute_color (int attr, file_entry *fe);
+int file_entry_color (file_entry *fe);
+void do_file_mark_range (WPanel *panel, int r1, int r2);
+int do_enter (WPanel *panel);
+
+/* NOTE: Have to be ifdefed for HAVE_X */
+void x_panel_select_item (WPanel *panel, int index, int val);
+void x_select_item (WPanel *panel);
+void x_unselect_item (WPanel *panel);
+sortfn *get_sort_fn (char *name);
+void update_one_panel_widget (WPanel *panel, int force_update, char *current_file);
+void panel_update_marks (WPanel *panel);
+
+void directory_history_next (WPanel * panel);
+void directory_history_prev (WPanel * panel);
+void directory_history_list (WPanel * panel);
+
+#endif /* __PANEL_H */
--- /dev/null
+/* External panelize
+ Copyright (C) 1995 The Free Software Foundation
+
+ Written by: 1995 Janne Kukonlehto
+ 1995 Jakub Jelinek
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h> /* For malloc() */
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifndef OS2_NT
+# include <grp.h>
+# include <pwd.h>
+#endif
+#include "tty.h"
+#include "mad.h"
+#include "util.h" /* Needed for the externs */
+#include "win.h"
+#include "color.h"
+#include "dlg.h"
+#include "widget.h"
+#include "dialog.h" /* For do_refresh() */
+#include "setup.h" /* For profile_bname */
+#include "profile.h" /* Load/save directories panelize */
+#include "fs.h"
+
+/* Needed for the extern declarations of integer parameters */
+#define DIR_H_INCLUDE_HANDLE_DIRENT
+#include "dir.h"
+#include "panel.h" /* Needed for the externs */
+#include "file.h"
+#include "main.h"
+#include "global.h"
+#include "../vfs/vfs.h"
+
+void do_external_panelize (char *command);
+
+#define UX 5
+#define UY 2
+
+#define BX 5
+#define BY 18
+
+#define BUTTONS 4
+#define LABELS 3
+#define B_ADD B_USER
+#define B_REMOVE B_USER + 1
+
+static WListbox *l_panelize;
+
+static Dlg_head *panelize_dlg;
+
+static WInput *pname;
+
+static char *panelize_section = "Panelize";
+
+static int last_listitem;
+
+struct {
+ int ret_cmd, flags, y, x;
+ char *text;
+ char *tkname;
+} panelize_but[BUTTONS] = {
+ { B_CANCEL, NORMAL_BUTTON, 0, 53, N_("&Cancel"), "c"},
+ { B_ADD, NORMAL_BUTTON, 0, 28, N_("&Add new"), "a"},
+ { B_REMOVE, NORMAL_BUTTON, 0, 16, N_("&Remove"), "r"},
+ { B_ENTER, DEFPUSH_BUTTON, 0, 0, N_("Pane&lize"),"l"},
+};
+
+/* Directory panelize */
+static struct panelize{
+ char *command;
+ char *label;
+ struct panelize *next;
+} *panelize = NULL;
+
+static char* panelize_title = N_(" External panelize ");
+
+#ifndef HAVE_X
+static void
+panelize_refresh (void)
+{
+ attrset (COLOR_NORMAL);
+ dlg_erase (panelize_dlg);
+
+ draw_box (panelize_dlg, 1, 2, panelize_dlg->lines-2, panelize_dlg->cols-4);
+ draw_box (panelize_dlg, UY, UX, panelize_dlg->lines-10, panelize_dlg->cols-10);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (panelize_dlg, 1, (panelize_dlg->cols - strlen(panelize_title)) / 2);
+ addstr (panelize_title);
+}
+#endif
+
+static void
+update_command ()
+{
+ if (l_panelize->pos != last_listitem) {
+ last_listitem = l_panelize->pos;
+ assign_text (pname,
+ ((struct panelize *) l_panelize->current->data)->command);
+ pname->point = 0;
+ update_input (pname, 1);
+ }
+}
+
+static int
+panelize_callback (Dlg_head * h, int Par, int Msg)
+{
+ switch (Msg) {
+#ifndef HAVE_X
+ case DLG_DRAW:
+ panelize_refresh ();
+ break;
+#endif
+
+ case DLG_POST_KEY:
+ /* fall */
+ case DLG_INIT:
+ attrset (MENU_ENTRY_COLOR);
+ update_command ();
+ break;
+ }
+ return 0;
+}
+
+static int l_call (void *data)
+{
+ return listbox_nothing;
+}
+
+static void init_panelize (void)
+{
+ int i, panelize_cols = COLS - 6;
+ struct panelize *current = panelize;
+
+#ifdef ENABLE_NLS
+ static int i18n_flag = 0;
+ static int maxlen = 0;
+
+ if (!i18n_flag)
+ {
+ i = sizeof(panelize_but) / sizeof(panelize_but[0]);
+ while (i--)
+ {
+ panelize_but [i].text = _(panelize_but [i].text);
+ maxlen += strlen (panelize_but [i].text) + 5;
+ }
+ maxlen += 10;
+ panelize_title = _(panelize_title);
+
+ i18n_flag = 1;
+ }
+ panelize_cols = max(panelize_cols, maxlen);
+
+ panelize_but [2].x = panelize_but [3].x
+ + strlen (panelize_but [3].text) + 7;
+ panelize_but [1].x = panelize_but [2].x
+ + strlen (panelize_but [2].text) + 5;
+ panelize_but [0].x = panelize_cols
+ - strlen (panelize_but[0].text) - 8 - BX;
+
+#endif /* ENABLE_NLS */
+
+ last_listitem = 0;
+
+ do_refresh ();
+
+ panelize_dlg = create_dlg (0, 0, 22, panelize_cols, dialog_colors,
+ panelize_callback, "[External panelize]", "panelize",
+ DLG_CENTER|DLG_GRID);
+ x_set_dialog_title (panelize_dlg, _("External panelize"));
+
+#define XTRACT(i) BY+panelize_but[i].y, BX+panelize_but[i].x, panelize_but[i].ret_cmd, panelize_but[i].flags, panelize_but[i].text, 0, 0, panelize_but[i].tkname
+
+ for (i = 0; i < BUTTONS; i++)
+ add_widgetl (panelize_dlg, button_new (XTRACT (i)), (i == BUTTONS - 1) ?
+ XV_WLAY_CENTERROW : XV_WLAY_RIGHTOF);
+
+ pname = input_new (UY+14, UX, INPUT_COLOR, panelize_dlg->cols-10, "", "in");
+ add_widgetl (panelize_dlg, pname, XV_WLAY_RIGHTOF);
+
+ add_widgetl (panelize_dlg, label_new (UY+13, UX, _("Command"), "label-command"), XV_WLAY_NEXTROW);
+
+ /* get new listbox */
+ l_panelize = listbox_new (UY + 1, UX + 1, panelize_dlg->cols-12, 10, 0, l_call, "li");
+
+ while (current){
+ listbox_add_item (l_panelize, 0, 0, current->label, current);
+ current = current->next;
+ }
+
+ /* add listbox to the dialogs */
+ add_widgetl (panelize_dlg, l_panelize, XV_WLAY_EXTENDWIDTH);
+
+ listbox_select_entry (l_panelize,
+ listbox_search_text (l_panelize, _("Other command")));
+}
+
+static void panelize_done (void)
+{
+ destroy_dlg (panelize_dlg);
+ repaint_screen ();
+}
+
+static void add2panelize (char *label, char *command)
+{
+ struct panelize *current, *old;
+
+ old = NULL;
+ current = panelize;
+ while (current && strcmp (current->label, label) <= 0){
+ old = current;
+ current = current->next;
+ }
+
+ if (old == NULL){
+ panelize = malloc (sizeof (struct panelize));
+ panelize->label = label;
+ panelize->command = command;
+ panelize->next = current;
+ } else {
+ struct panelize *new;
+ new = malloc (sizeof (struct panelize));
+ new->label = label;
+ new->command = command;
+ old->next = new;
+ new->next = current;
+ }
+}
+
+void add2panelize_cmd (void)
+{
+ char *label;
+
+ if (pname->buffer && (*pname->buffer)) {
+ label = input_dialog (_(" Add to external panelize "),
+ _(" Enter command label: "),
+ "");
+ if (!label)
+ return;
+ if (!*label) {
+ free (label);
+ return;
+ }
+
+ add2panelize (label, strdup(pname->buffer));
+ }
+}
+
+static void remove_from_panelize (struct panelize *entry)
+{
+ if (strcmp (entry->label, _("Other command")) != 0) {
+ if (entry == panelize) {
+ panelize = panelize->next;
+ } else {
+ struct panelize *current = panelize;
+ while (current && current->next != entry)
+ current = current->next;
+ if (current) {
+ current->next = entry->next;
+ }
+ }
+
+ free (entry->label);
+ free (entry->command);
+ free (entry);
+ }
+}
+
+void external_panelize (void)
+{
+ char *target = NULL;
+
+ if (!vfs_current_is_local ()){
+ message (1, _(" Oops... "),
+ _(" I can't run external panelize while logged on a non local directory "));
+ return;
+ }
+
+ init_panelize ();
+
+ /* display file info */
+ attrset (SELECTED_COLOR);
+
+ run_dlg (panelize_dlg);
+
+ switch (panelize_dlg->ret_value) {
+ case B_CANCEL:
+ break;
+
+ case B_ADD:
+ add2panelize_cmd ();
+ break;
+
+ case B_REMOVE:
+ remove_from_panelize (l_panelize->current->data);
+ break;
+
+ case B_ENTER:
+ target = pname->buffer;
+ if (target != NULL && *target) {
+ char *cmd = strdup (target);
+ destroy_dlg (panelize_dlg);
+ do_external_panelize (cmd);
+ free (cmd);
+ repaint_screen ();
+ return;
+ }
+ break;
+ }
+
+ panelize_done ();
+}
+
+void load_panelize (void)
+{
+ void *profile_keys;
+ char *key, *value;
+
+ profile_keys = profile_init_iterator (panelize_section, profile_name);
+
+ add2panelize (strdup (_("Other command")), strdup (""));
+
+ if (!profile_keys){
+ add2panelize (strdup (_("Find rejects after patching")), strdup ("find . -name \\*.rej -print"));
+ add2panelize (strdup (_("Find *.orig after patching")), strdup ("find . -name \\*.orig -print"));
+ add2panelize (strdup (_("Find SUID and SGID programs")), strdup ("find . \\( \\( -perm -04000 -a -perm +011 \\) -o \\( -perm -02000 -a -perm +01 \\) \\) -print"));
+ return;
+ }
+
+ while (profile_keys){
+ profile_keys = profile_iterator_next (profile_keys, &key, &value);
+ add2panelize (strdup (key), strdup (value));
+ }
+}
+
+void save_panelize (void)
+{
+ struct panelize *current = panelize;
+
+ profile_clean_section (panelize_section, profile_name);
+ for (;current; current = current->next){
+ if (strcmp (current->label, _("Other command")))
+ WritePrivateProfileString (panelize_section,
+ current->label,
+ current->command,
+ profile_name);
+ }
+ sync_profiles ();
+}
+
+void done_panelize (void)
+{
+ struct panelize *current = panelize;
+ struct panelize *next;
+
+ for (; current; current = next){
+ next = current->next;
+ free (current->label);
+ free (current->command);
+ free (current);
+ }
+}
+
+void do_external_panelize (char *command)
+{
+ int status, link_to_dir, stalled_link;
+ int next_free = 0;
+ struct stat buf;
+ dir_list *list = &cpanel->dir;
+ char line [MC_MAXPATHLEN];
+ char *name;
+ FILE *external;
+
+ open_error_pipe ();
+ external = popen (command, "r");
+ if (!external){
+ close_error_pipe (1, _("Cannot invoke command."));
+ return;
+ }
+ clean_dir (list, cpanel->count);
+
+ /* Clear the counters */
+ cpanel->total = cpanel->dirs_marked = cpanel->marked = 0;
+ cpanel->has_dir_sizes = 0;
+ while (1) {
+ clearerr(external);
+ if (fgets (line, MC_MAXPATHLEN, external) == NULL)
+ if (ferror(external) && errno == EINTR)
+ continue;
+ else
+ break;
+ if (line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = 0;
+ if (strlen(line) < 1)
+ continue;
+ if (line [0] == '.' && line[1] == PATH_SEP)
+ name = line + 2;
+ else
+ name = line;
+ status = handle_path (list, name, &buf, next_free, &link_to_dir,
+ &stalled_link);
+ if (status == 0)
+ continue;
+ if (status == -1)
+ break;
+ list->list [next_free].fnamelen = strlen (name);
+ list->list [next_free].fname = strdup (name);
+ list->list [next_free].cache = NULL;
+ file_mark (cpanel, next_free, 0);
+ list->list [next_free].f.link_to_dir = link_to_dir;
+ list->list [next_free].f.stalled_link = stalled_link;
+ list->list [next_free].buf = buf;
+ next_free++;
+ if (!(next_free & 32))
+ rotate_dash ();
+ }
+ if (next_free){
+ cpanel->count = next_free;
+ cpanel->is_panelized = 1;
+ if (list->list [0].fname [0] == PATH_SEP){
+ strcpy (cpanel->cwd, PATH_SEP_STR);
+ chdir (PATH_SEP_STR);
+ }
+ } else {
+ cpanel->count = set_zero_dir (list);
+ }
+#ifndef SCO_FLAVOR
+ if (pclose (external) < 0)
+#else /* SCO_FLAVOR */
+ if (WEXITSTATUS(pclose (external)) < 0)
+#endif /* SCO_FLAVOR */
+ message (0, _("External panelize"), _("Pipe close failed"));
+ close_error_pipe (0, 0);
+ try_to_select (cpanel, NULL);
+ paint_panel (cpanel);
+}
--- /dev/null
+#ifndef __PANELIZE_H
+#define __PANELIZE_H
+
+void add2panelize_cmd (void);
+void external_panelize (void);
+void load_panelize (void);
+void save_panelize (void);
+void done_panelize (void);
+
+#endif
--- /dev/null
+/*
+ *
+ * Written by Erik Troan (ewt@redhat.com).
+ *
+ */
+#include <config.h>
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+#else
+# include "util.h"
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#ifdef OS2_NT
+# include <io.h>
+#endif
+
+#include "popt.h"
+
+struct optionStackEntry {
+ int argc;
+ char ** argv;
+ int next;
+ char * nextArg;
+ char * nextCharArg;
+ struct poptAlias * currAlias;
+};
+
+struct poptContext_s {
+ struct optionStackEntry optionStack[POPT_OPTION_DEPTH], * os;
+ char ** leftovers;
+ int numLeftovers;
+ int nextLeftover;
+ struct poptOption * options;
+ int restLeftover;
+ char * appName;
+ struct poptAlias * aliases;
+ int numAliases;
+ int flags;
+};
+
+poptContext poptGetContext(char * name ,int argc, char ** argv,
+ struct poptOption * options, int flags) {
+ poptContext con = malloc(sizeof(*con));
+
+ con->os = con->optionStack;
+ con->os->argc = argc;
+ con->os->argv = argv;
+ con->os->currAlias = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->nextArg = NULL;
+
+ if (flags & POPT_KEEP_FIRST)
+ con->os->next = 0; /* include argv[0] */
+ else
+ con->os->next = 1; /* skip argv[0] */
+
+ con->leftovers = malloc(sizeof(char *) * (argc + 1));
+ con->numLeftovers = 0;
+ con->nextLeftover = 0;
+ con->restLeftover = 0;
+ con->options = options;
+ con->aliases = NULL;
+ con->numAliases = 0;
+ con->flags = 0;
+
+ if (!name)
+ con->appName = NULL;
+ else
+ con->appName = strcpy(malloc(strlen(name) + 1), name);
+
+ return con;
+}
+
+void poptResetContext(poptContext con) {
+ con->os = con->optionStack;
+ con->os->currAlias = NULL;
+ con->os->nextCharArg = NULL;
+ con->os->nextArg = NULL;
+ con->os->next = 1; /* skip argv[0] */
+
+ con->numLeftovers = 0;
+ con->nextLeftover = 0;
+ con->restLeftover = 0;
+}
+
+/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
+int poptGetNextOpt(poptContext con) {
+ char * optString, * chptr, * localOptString;
+ char * longArg = NULL;
+ char * origOptString;
+ long aLong;
+ char * end;
+ struct poptOption * opt = NULL;
+ int done = 0;
+ int i;
+
+ while (!done) {
+ while (!con->os->nextCharArg && con->os->next == con->os->argc
+ && con->os > con->optionStack)
+ con->os--;
+ if (!con->os->nextCharArg && con->os->next == con->os->argc)
+ return -1;
+
+ if (!con->os->nextCharArg) {
+
+ origOptString = con->os->argv[con->os->next++];
+
+ if (con->restLeftover || *origOptString != '-') {
+ con->leftovers[con->numLeftovers++] = origOptString;
+ continue;
+ }
+
+ if (!origOptString[0])
+ return POPT_ERROR_BADOPT;
+
+ /* Make a copy we can hack at */
+ localOptString = optString =
+ strcpy(malloc(strlen(origOptString) + 1),
+ origOptString);
+
+ if (optString[1] == '-' && !optString[2]) {
+ con->restLeftover = 1;
+ free(localOptString);
+ continue;
+ } else if (optString[1] == '-') {
+ optString += 2;
+
+ if (!con->os->currAlias || !con->os->currAlias->longName ||
+ strcmp(con->os->currAlias->longName, optString)) {
+
+ i = con->numAliases - 1;
+ while (i >= 0 && (!con->aliases[i].longName ||
+ strcmp(con->aliases[i].longName, optString))) i--;
+
+ if (i >= 0) {
+ free(localOptString);
+ if ((con->os - con->optionStack + 1)
+ == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+ con->os++;
+ con->os->next = 0;
+ con->os->nextArg = con->os->nextCharArg = NULL;
+ con->os->currAlias = con->aliases + i;
+ con->os->argc = con->os->currAlias->argc;
+ con->os->argv = con->os->currAlias->argv;
+ continue;
+ }
+ }
+
+ chptr = optString;
+ while (*chptr && *chptr != '=') chptr++;
+ if (*chptr == '=') {
+ longArg = origOptString + (chptr - localOptString) + 1;
+ *chptr = '\0';
+ }
+
+ opt = con->options;
+ while (opt->longName || opt->shortName) {
+ if (opt->longName && !strcmp(optString, opt->longName))
+ break;
+ opt++;
+ }
+
+ if (!opt->longName && !opt->shortName) {
+ free(localOptString);
+ return POPT_ERROR_BADOPT;
+ }
+ } else
+ con->os->nextCharArg = origOptString + 1;
+ free(localOptString);
+ }
+
+ if (con->os->nextCharArg) {
+ origOptString = con->os->nextCharArg;
+
+ con->os->nextCharArg = NULL;
+
+ if (!con->os->currAlias || *origOptString !=
+ con->os->currAlias->shortName) {
+
+ i = con->numAliases - 1;
+ while (i >= 0 &&
+ con->aliases[i].shortName != *origOptString) i--;
+
+ if (i >= 0) {
+ if ((con->os - con->optionStack + 1) == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+ /* We'll need this on the way out */
+ origOptString++;
+ if (*origOptString)
+ con->os->nextCharArg = origOptString;
+
+ con->os++;
+ con->os->next = 0;
+ con->os->nextArg = con->os->nextCharArg = NULL;
+ con->os->currAlias = con->aliases + i;
+ con->os->argc = con->os->currAlias->argc;
+ con->os->argv = con->os->currAlias->argv;
+ continue;
+ }
+ }
+
+ opt = con->options;
+ while ((opt->longName || opt->shortName) &&
+ *origOptString != opt->shortName) opt++;
+ if (!opt->longName && !opt->shortName) return POPT_ERROR_BADOPT;
+
+ origOptString++;
+ if (*origOptString)
+ con->os->nextCharArg = origOptString;
+ }
+
+ if (opt->arg && opt->argInfo == POPT_ARG_NONE)
+ *((int *)opt->arg) = 1;
+ else if (opt->argInfo != POPT_ARG_NONE) {
+ if (longArg) {
+ con->os->nextArg = longArg;
+ } else if (con->os->nextCharArg) {
+ con->os->nextArg = con->os->nextCharArg;
+ con->os->nextCharArg = NULL;
+ } else {
+ while (con->os->next == con->os->argc &&
+ con->os > con->optionStack)
+ con->os--;
+ if (con->os->next == con->os->argc)
+ return POPT_ERROR_NOARG;
+
+ con->os->nextArg = con->os->argv[con->os->next++];
+ }
+
+ if (opt->arg) {
+ switch (opt->argInfo) {
+ case POPT_ARG_STRING:
+ *((char **) opt->arg) = con->os->nextArg;
+ break;
+
+ case POPT_ARG_INT:
+ case POPT_ARG_LONG:
+ aLong = strtol(con->os->nextArg, &end, 0);
+ if (*end)
+ return POPT_ERROR_BADNUMBER;
+
+ if (aLong == LONG_MIN || aLong == LONG_MAX)
+ return POPT_ERROR_OVERFLOW;
+ if (opt->argInfo == POPT_ARG_LONG) {
+ *((long *) opt->arg) = aLong;
+ } else {
+ if (aLong > INT_MAX || aLong < INT_MIN)
+ return POPT_ERROR_OVERFLOW;
+ *((int *) opt->arg) =aLong;
+ }
+ break;
+
+ default:
+ printf("option type not implemented in popt\n");
+ exit(1);
+ }
+ }
+ }
+
+ if (opt->val) done = 1;
+ }
+
+ return opt->val;
+}
+
+char * poptGetOptArg(poptContext con) {
+ char * ret = con->os->nextArg;
+ con->os->nextArg = NULL;
+ return ret;
+}
+
+char * poptGetArg(poptContext con) {
+ if (con->numLeftovers == con->nextLeftover) return NULL;
+ return (con->leftovers[con->nextLeftover++]);
+}
+
+char * poptPeekArg(poptContext con) {
+ if (con->numLeftovers == con->nextLeftover) return NULL;
+ return (con->leftovers[con->nextLeftover]);
+}
+
+char ** poptGetArgs(poptContext con) {
+ if (con->numLeftovers == con->nextLeftover) return NULL;
+
+ /* some apps like [like RPM ;-) ] need this NULL terminated */
+ con->leftovers[con->numLeftovers] = NULL;
+
+ return (con->leftovers + con->nextLeftover);
+}
+
+void poptFreeContext(poptContext con) {
+ int i;
+
+ for (i = 0; i < con->numAliases; i++) {
+ free(con->aliases[i].longName);
+ free(con->aliases[i].argv);
+ }
+
+ free(con->leftovers);
+ if (con->appName) free(con->appName);
+ if (con->aliases) free(con->aliases);
+ free(con);
+}
+
+int poptAddAlias(poptContext con, struct poptAlias newAlias, int flags) {
+ int aliasNum = con->numAliases++;
+ struct poptAlias * alias;
+
+ /* SunOS won't realloc(NULL, ...) */
+ if (!con->aliases)
+ con->aliases = malloc(sizeof(newAlias) * con->numAliases);
+ else
+ con->aliases = realloc(con->aliases,
+ sizeof(newAlias) * con->numAliases);
+ alias = con->aliases + aliasNum;
+
+ *alias = newAlias;
+ if (alias->longName)
+ alias->longName = strcpy(malloc(strlen(alias->longName) + 1),
+ alias->longName);
+ else
+ alias->longName = NULL;
+
+ return 0;
+}
+
+int poptParseArgvString(char * s, int * argcPtr, char *** argvPtr) {
+ char * buf = strcpy(malloc(strlen(s) + 1), s);
+ char * bufStart = buf;
+ char * src, * dst;
+ char quote = '\0';
+ int argvAlloced = 5;
+ char ** argv = malloc(sizeof(*argv) * argvAlloced);
+ char ** argv2;
+ int argc = 0;
+ int i;
+
+ src = s;
+ dst = buf;
+ argv[argc] = buf;
+
+ memset(buf, '\0', strlen(s) + 1);
+
+ while (*src) {
+ if (quote == *src) {
+ quote = '\0';
+ } else if (quote) {
+ if (*src == '\\') {
+ src++;
+ if (!*src) {
+ free(argv);
+ free(bufStart);
+ return POPT_ERROR_BADQUOTE;
+ }
+ if (*src != quote) *buf++ = '\\';
+ }
+ *buf++ = *src;
+ } else if (isspace(*src)) {
+ if (*argv[argc]) {
+ buf++, argc++;
+ if (argc == argvAlloced) {
+ argvAlloced += 5;
+ argv = realloc(argv, sizeof(*argv) * argvAlloced);
+ }
+ argv[argc] = buf;
+ }
+ } else switch (*src) {
+ case '"':
+ case '\'':
+ quote = *src;
+ break;
+ case '\\':
+ src++;
+ if (!*src) {
+ free(argv);
+ free(bufStart);
+ return POPT_ERROR_BADQUOTE;
+ }
+ /* fallthrough */
+ default:
+ *buf++ = *src;
+ }
+
+ src++;
+ }
+
+ if (strlen(argv[argc])) {
+ argc++;
+ buf++;
+ }
+
+ argv2 = malloc(argc * sizeof(*argv) + (buf - bufStart));
+ dst = (char *)argv2;
+ dst += argc * sizeof(*argv);
+ memcpy(argv2, argv, argc * sizeof(*argv));
+ memcpy(dst, bufStart, buf - bufStart);
+
+ for (i = 0; i < argc; i++) {
+ argv2[i] = dst + (argv[i] - bufStart);
+ }
+
+ free(argv);
+ free(bufStart);
+ *argvPtr = argv2;
+ *argcPtr = argc;
+
+ return 0;
+}
+
+static void configLine(poptContext con, char * line) {
+ int nameLength = strlen(con->appName);
+ char * opt;
+ struct poptAlias alias;
+
+ if (strncmp(line, con->appName, nameLength)) return;
+ line += nameLength;
+ if (!*line || !isspace(*line)) return;
+ while (*line && isspace(*line)) line++;
+
+ if (!strncmp(line, "alias", 5)) {
+ line += 5;
+ if (!*line || !isspace(*line)) return;
+ while (*line && isspace(*line)) line++;
+ if (!*line) return;
+
+ opt = line;
+ while (*line && !isspace(*line)) line++;
+ if (!*line) return;
+ *line++ = '\0';
+ while (*line && isspace(*line)) line++;
+ if (!*line) return;
+
+ if (!strlen(opt)) return;
+
+ if (poptParseArgvString(line, &alias.argc, &alias.argv)) return;
+
+ if (opt[0] == '-' && opt[1] == '-') {
+ alias.longName = opt + 2;
+ alias.shortName = '\0';
+ poptAddAlias(con, alias, 0);
+ } else if (opt[0] == '-' && !opt[2]) {
+ alias.longName = NULL;
+ alias.shortName = opt[1];
+ poptAddAlias(con, alias, 0);
+ }
+ }
+}
+
+int poptReadConfigFile(poptContext con, char * fn) {
+ char * file, * chptr, * end;
+ char * buf, * dst;
+ int fd, rc;
+ int fileLength;
+
+ fd = open(fn, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ return POPT_ERROR_ERRNO;
+ }
+
+ fileLength = lseek(fd, 0, SEEK_END);
+ lseek(fd, 0, 0);
+
+#ifndef HAVE_MMAP
+ file = (char*) xmalloc (fileLength, "poptReadConfigFile");
+ if (file == NULL)
+#else /* HAVE_MMAP */
+ file = mmap(NULL, fileLength, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (file == (void *) -1)
+#endif /* HAVE_MMAP */
+ {
+ rc = errno;
+ close(fd);
+ errno = rc;
+ return POPT_ERROR_ERRNO;
+ }
+#ifndef HAVE_MMAP
+ do
+ {
+ lseek(fd, 0, 0);
+ rc = read(fd, file, fileLength);
+ if (rc == -1 && errno != EINTR)
+ {
+ free(file);
+ return POPT_ERROR_ERRNO;
+ }
+ } while (rc != fileLength || (rc == -1 && errno == EINTR));
+#endif /* HAVE_MMAP */
+ close(fd);
+
+ dst = buf = malloc(fileLength + 1);
+
+ chptr = file;
+ end = (file + fileLength);
+ while (chptr < end) {
+ switch (*chptr) {
+ case '\n':
+ *dst = '\0';
+ dst = buf;
+ while (*dst && isspace(*dst)) dst++;
+ if (*dst && *dst != '#') {
+ configLine(con, dst);
+ }
+ chptr++;
+ break;
+ case '\\':
+ *dst++ = *chptr++;
+ if (chptr < end) {
+ if (*chptr == '\n')
+ dst--, chptr++;
+ /* \ at the end of a line does not insert a \n */
+ else
+ *dst++ = *chptr++;
+ }
+ break;
+ default:
+ *dst++ = *chptr++;
+ }
+ }
+ free (buf);
+#ifndef HAVE_MMAP
+ free (file);
+#else
+ munmap (file, fileLength);
+#endif
+ return 0;
+}
+
+int poptReadDefaultConfig(poptContext con, int useEnv) {
+ char * envName, * envValue, * envValueStart;
+ char * fn, * home, * chptr;
+ int rc, skip;
+ struct poptAlias alias;
+
+ if (!con->appName) return 0;
+
+ rc = poptReadConfigFile(con, "/etc/popt");
+ if (rc) return rc;
+ if ((home = getenv("HOME"))) {
+ fn = (char *) malloc (strlen(home) + 20);
+ sprintf(fn, "%s/.popt", home);
+ rc = poptReadConfigFile(con, fn);
+ free (fn);
+ if (rc) return rc;
+ }
+
+ envName = malloc(strlen(con->appName) + 20);
+ strcpy(envName, con->appName);
+ chptr = envName;
+ while (*chptr) {
+ *chptr = toupper(*chptr);
+ chptr++;
+ }
+ strcat(envName, "_POPT_ALIASES");
+
+ if (useEnv && (envValue = getenv(envName))) {
+ envValue = envValueStart = strcpy(malloc(strlen(envValue) + 1), envValue);
+
+ while (envValue && *envValue) {
+ chptr = strchr(envValue, '=');
+ if (!chptr) {
+ envValue = strchr(envValue, '\n');
+ if (envValue) envValue++;
+ continue;
+ }
+
+ *chptr = '\0';
+
+ skip = 0;
+ if (!strncmp(envValue, "--", 2)) {
+ alias.longName = envValue + 2;
+ alias.shortName = '\0';
+ } else if (*envValue == '-' && strlen(envValue) == 2) {
+ alias.longName = NULL;
+ alias.shortName = envValue[1];
+ } else {
+ skip = 1;
+ }
+
+ envValue = chptr + 1;
+ chptr = strchr(envValue, '\n');
+ if (chptr) *chptr = '\0';
+
+ if (!skip) {
+ poptParseArgvString(envValue, &alias.argc, &alias.argv);
+ poptAddAlias(con, alias, 0);
+ }
+
+ if (chptr)
+ envValue = chptr + 1;
+ else
+ envValue = NULL;
+ }
+ free(envValueStart);
+ }
+
+ free (envName);
+ return 0;
+}
+
+char * poptBadOption(poptContext con, int flags) {
+ struct optionStackEntry * os;
+
+ if (flags & POPT_BADOPTION_NOALIAS)
+ os = con->optionStack;
+ else
+ os = con->os;
+
+ return os->argv[os->next - 1];
+}
+
+#define POPT_ERROR_NOARG -10
+#define POPT_ERROR_BADOPT -11
+#define POPT_ERROR_OPTSTOODEEP -13
+#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
+#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
+
+const char * poptStrerror(const int error) {
+ switch (error) {
+ case POPT_ERROR_NOARG:
+ return "missing argument";
+ case POPT_ERROR_BADOPT:
+ return "unknown option";
+ case POPT_ERROR_OPTSTOODEEP:
+ return "aliases nested too deeply";
+ case POPT_ERROR_BADQUOTE:
+ return "error in paramter quoting";
+ case POPT_ERROR_BADNUMBER:
+ return "invalid numeric value";
+ case POPT_ERROR_OVERFLOW:
+ return "number too large or too small";
+ case POPT_ERROR_ERRNO:
+#ifdef HAVE_STRERROR
+ return strerror (errno);
+#else
+ {
+ extern int sys_nerr;
+ extern char *sys_errlist [];
+ if ((0 <= errno) && (errno < sys_nerr))
+ return sys_errlist[errno];
+ else
+ return "strange errno";
+ }
+#endif
+ default:
+ return "unknown error";
+ }
+}
+
+int poptStuffArgs(poptContext con, char ** argv) {
+ int i;
+
+ if ((con->os - con->optionStack) == POPT_OPTION_DEPTH)
+ return POPT_ERROR_OPTSTOODEEP;
+
+ for (i = 0; argv[i]; i++);
+
+ con->os++;
+ con->os->next = 0;
+ con->os->nextArg = con->os->nextCharArg = NULL;
+ con->os->currAlias = NULL;
+ con->os->argc = i;
+ con->os->argv = argv;
+
+ return 0;
+}
--- /dev/null
+#ifndef H_POPT
+#define H_POPT
+
+#define POPT_OPTION_DEPTH 10
+
+#define POPT_ARG_NONE 0
+#define POPT_ARG_STRING 1
+#define POPT_ARG_INT 2
+#define POPT_ARG_LONG 3
+
+#define POPT_ERROR_NOARG -10
+#define POPT_ERROR_BADOPT -11
+#define POPT_ERROR_OPTSTOODEEP -13
+#define POPT_ERROR_BADQUOTE -15 /* only from poptParseArgString() */
+#define POPT_ERROR_ERRNO -16 /* only from poptParseArgString() */
+#define POPT_ERROR_BADNUMBER -17
+#define POPT_ERROR_OVERFLOW -18
+
+/* context creation flags */
+#define POPT_BADOPTION_NOALIAS (1 << 0) /* don't go into an alias */
+#define POPT_KEEP_FIRST (1 << 1) /* pay attention to argv[0] */
+
+struct poptOption {
+ const char * longName; /* may be NULL */
+ char shortName; /* may be '\0' */
+ int argInfo;
+ void * arg; /* depends on argInfo */
+ int val; /* 0 means don't return, just update flag */
+};
+
+struct poptAlias {
+ char * longName; /* may be NULL */
+ char shortName; /* may be '\0' */
+ int argc;
+ char ** argv; /* must be free()able */
+};
+
+typedef struct poptContext_s * poptContext;
+
+poptContext poptGetContext(char * name, int argc, char ** argv,
+ struct poptOption * options, int flags);
+void poptResetContext(poptContext con);
+
+/* returns 'val' element, -1 on last item, POPT_ERROR_* on error */
+int poptGetNextOpt(poptContext con);
+/* returns NULL if no argument is available */
+char * poptGetOptArg(poptContext con);
+/* returns NULL if no more options are available */
+char * poptGetArg(poptContext con);
+char * poptPeekArg(poptContext con);
+char ** poptGetArgs(poptContext con);
+/* returns the option which caused the most recent error */
+char * poptBadOption(poptContext con, int flags);
+void poptFreeContext(poptContext con);
+int poptStuffArgs(poptContext con, char ** argv);
+int poptAddAlias(poptContext con, struct poptAlias alias, int flags);
+int poptReadConfigFile(poptContext con, char * fn);
+/* like above, but reads /etc/popt and $HOME/.popt along with environment
+ vars */
+int poptReadDefaultConfig(poptContext con, int useEnv);
+/* argv should be freed -- this allows ', ", and \ quoting, but ' is treated
+ the same as " and both may include \ quotes */
+int poptParseArgvString(char * s, int * argcPtr, char *** argvPtr);
+const char * poptStrerror(const int error);
+
+#endif
--- /dev/null
+/*
+ * Initialization-File Functions.
+ *
+ * From the Wine project
+
+ Copyright (C) 1993, 1994 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* "$Id: profile.c,v 1.1 2001/12/30 09:55:22 sedwards Exp $" */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h> /* For free() and atoi() */
+#include <sys/types.h>
+#include "mad.h"
+#include "util.h"
+#include "global.h"
+#include "profile.h"
+
+#define INIFILE "xxx.ini"
+#define STRSIZE 4096
+#define overflow (next == &CharBuffer [STRSIZE-1])
+
+enum { FirstBrace, OnSecHeader, IgnoreToEOL, KeyDef, KeyDefOnKey, KeyValue };
+
+typedef struct TKeys {
+ char *KeyName;
+ char *Value;
+ struct TKeys *link;
+} TKeys;
+
+typedef struct TSecHeader {
+ char *AppName;
+ TKeys *Keys;
+ struct TSecHeader *link;
+} TSecHeader;
+
+typedef struct TProfile {
+ char *FileName;
+ TSecHeader *Section;
+ struct TProfile *link;
+} TProfile;
+
+TProfile *Current = 0;
+TProfile *Base = 0;
+
+static int is_loaded (char *FileName, TSecHeader **section)
+{
+ TProfile *p = Base;
+
+ while (p){
+ if (!strcasecmp (FileName, p->FileName)){
+ Current = p;
+ *section = p->Section;
+ return 1;
+ }
+ p = p->link;
+ }
+ return 0;
+}
+
+#define TRANSLATION_CHAR '\200'
+
+char *str_untranslate_newline_dup (char *s)
+{
+ int l = 0;
+ char *p = s, *q;
+ while (*p) {
+ l++;
+ l += (*p == '\n' || *p == TRANSLATION_CHAR);
+ p++;
+ }
+ q = p = malloc (l + 1);
+ if (!q)
+ return 0;
+ for (;;) {
+ switch (*s) {
+ case '\n':
+ *p++ = TRANSLATION_CHAR;
+ *p++ = 'n';
+ break;
+ case TRANSLATION_CHAR:
+ if (s[1] == 'n' || s[1] == TRANSLATION_CHAR)
+ *p++ = TRANSLATION_CHAR;
+ *p++ = TRANSLATION_CHAR;
+ break;
+ case '\0':
+ *p = '\0';
+ return q;
+ break;
+ default:
+ *p++ = *s;
+ }
+ s++;
+ }
+ return 0; /* not reached */
+}
+
+char *str_translate_newline_dup (char *s)
+{
+ char *p, *q;
+ q = p = malloc (strlen (s) + 1);
+ if (!q)
+ return 0;
+ while (*s) {
+ if (*s == TRANSLATION_CHAR) {
+ switch (*(++s)) {
+ case 'n':
+ *p++ = '\n';
+ break;
+ case TRANSLATION_CHAR:
+ *p++ = TRANSLATION_CHAR;
+ break;
+ case '\0':
+ *p++ = TRANSLATION_CHAR;
+ *p++ = '\0';
+ return q;
+ default:
+ *p++ = TRANSLATION_CHAR;
+ *p++ = *s;
+ }
+ } else {
+ *p++ = *s;
+ }
+ s++;
+ }
+ *p = '\0';
+ return q; /* not reached */
+}
+
+static TSecHeader *load (char *file)
+{
+ FILE *f;
+ int state;
+ TSecHeader *SecHeader = 0;
+ char CharBuffer [STRSIZE];
+ char *next = ""; /* Not needed */
+ int c;
+
+ if ((f = fopen (file, "r"))==NULL)
+ return NULL;
+
+ state = FirstBrace;
+ while ((c = getc (f)) != EOF){
+ if (c == '\r') /* Ignore Carriage Return */
+ continue;
+
+ switch (state){
+
+ case OnSecHeader:
+ if (c == ']' || overflow){
+ *next = '\0';
+ next = CharBuffer;
+ SecHeader->AppName = strdup (CharBuffer);
+ state = IgnoreToEOL;
+ } else
+ *next++ = c;
+ break;
+
+ case IgnoreToEOL:
+ if (c == '\n'){
+ state = KeyDef;
+ next = CharBuffer;
+ }
+ break;
+
+ case FirstBrace:
+ case KeyDef:
+ case KeyDefOnKey:
+ if (c == '['){
+ TSecHeader *temp;
+
+ temp = SecHeader;
+ SecHeader = (TSecHeader *) xmalloc (sizeof (TSecHeader),
+ "KeyDef");
+ SecHeader->link = temp;
+ SecHeader->Keys = 0;
+ state = OnSecHeader;
+ next = CharBuffer;
+ break;
+ }
+ if (state == FirstBrace) /* On first pass, don't allow dangling keys */
+ break;
+
+ if ((c == ' ' && state != KeyDefOnKey) || c == '\t')
+ break;
+
+ if (c == '\n' || overflow) /* Abort Definition */
+ next = CharBuffer;
+
+ if (c == '=' || overflow){
+ TKeys *temp;
+
+ temp = SecHeader->Keys;
+ *next = '\0';
+ SecHeader->Keys = (TKeys *) xmalloc (sizeof (TKeys), "KD2");
+ SecHeader->Keys->link = temp;
+ SecHeader->Keys->KeyName = strdup (CharBuffer);
+ state = KeyValue;
+ next = CharBuffer;
+ } else {
+ *next++ = c;
+ state = KeyDefOnKey;
+ }
+ break;
+
+ case KeyValue:
+ if (overflow || c == '\n'){
+ *next = '\0';
+ SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
+ state = c == '\n' ? KeyDef : IgnoreToEOL;
+ next = CharBuffer;
+#ifdef DEBUG
+ printf ("[%s] (%s)=%s\n", SecHeader->AppName,
+ SecHeader->Keys->KeyName, SecHeader->Keys->Value);
+#endif
+ } else
+ *next++ = c;
+ break;
+
+ } /* switch */
+
+ } /* while ((c = getc (f)) != EOF) */
+ if (c == EOF && state == KeyValue){
+ *next = '\0';
+ SecHeader->Keys->Value = str_translate_newline_dup (CharBuffer);
+ }
+ fclose (f);
+ return SecHeader;
+}
+
+static void new_key (TSecHeader *section, char *KeyName, char *Value)
+{
+ TKeys *key;
+
+ key = (TKeys *) xmalloc (sizeof (TKeys), "new_key");
+ key->KeyName = strdup (KeyName);
+ key->Value = strdup (Value);
+ key->link = section->Keys;
+ section->Keys = key;
+}
+
+char *GetSetProfileChar (int set, char *AppName, char *KeyName,
+ char *Default, char *FileName)
+{
+
+ TProfile *New;
+ TSecHeader *section;
+ TKeys *key;
+
+ if (!is_loaded (FileName, §ion)){
+ New = (TProfile *) xmalloc (sizeof (TProfile), "GetSetProfile");
+ New->link = Base;
+ New->FileName = strdup (FileName);
+ New->Section = load (FileName);
+ Base = New;
+ section = New->Section;
+ Current = New;
+ }
+
+ /* Start search */
+ for (; section; section = section->link){
+ if (section->AppName == 0 || strcasecmp (section->AppName, AppName))
+ continue;
+ for (key = section->Keys; key; key = key->link){
+ if (strcasecmp (key->KeyName, KeyName))
+ continue;
+ if (set){
+ free (key->Value);
+ key->Value = strdup (Default);
+ }
+ return key->Value;
+ }
+ /* If getting the information, then don't write the information
+ to the INI file, need to run a couple of tests with windog */
+ /* No key found */
+ if (set){
+ new_key (section, KeyName, Default);
+ return 0;
+ }
+ }
+
+ /* Non existent section */
+ if (set && Default){
+ section = (TSecHeader *) xmalloc (sizeof (TSecHeader), "GSP3");
+ section->AppName = strdup (AppName);
+ section->Keys = 0;
+ new_key (section, KeyName, Default);
+ section->link = Current->Section;
+ Current->Section = section;
+ }
+ return Default;
+}
+
+short GetSetProfile (int set, char * AppName, char * KeyName, char * Default,
+ char * ReturnedString, short Size, char * FileName)
+
+{
+ char *s;
+
+ s = GetSetProfileChar (set, AppName, KeyName, Default, FileName);
+ if (!set){
+ ReturnedString [Size-1] = 0;
+ strncpy (ReturnedString, s, Size-1);
+ }
+ return 1;
+}
+
+short GetPrivateProfileString (char * AppName, char * KeyName,
+ char * Default, char * ReturnedString,
+ short Size, char * FileName)
+{
+ return (GetSetProfile (0, AppName, KeyName, Default, ReturnedString, Size, FileName));
+}
+
+char *get_profile_string (char *AppName, char *KeyName, char *Default,
+ char *FileName)
+{
+ return GetSetProfileChar (0, AppName, KeyName, Default, FileName);
+}
+
+#if 0
+int GetProfileString (char * AppName, char * KeyName, char * Default,
+ char * ReturnedString, int Size)
+{
+ return GetPrivateProfileString (AppName, KeyName, Default,
+ ReturnedString, Size, INIFILE);
+}
+#endif
+
+int GetPrivateProfileInt (char * AppName, char * KeyName, int Default,
+ char * File)
+{
+ static char IntBuf [15];
+ static char buf [15];
+
+ sprintf (buf, "%d", Default);
+
+ /* Check the exact semantic with the SDK */
+ GetPrivateProfileString (AppName, KeyName, buf, IntBuf, 15, File);
+ if (!strcasecmp (IntBuf, "true"))
+ return 1;
+ if (!strcasecmp (IntBuf, "yes"))
+ return 1;
+ return atoi (IntBuf);
+}
+
+#if 0
+int GetProfileInt (char * AppName, char * KeyName, int Default)
+{
+ return GetPrivateProfileInt (AppName, KeyName, Default, INIFILE);
+}
+#endif
+
+int WritePrivateProfileString (char * AppName, char * KeyName, char * String,
+ char * FileName)
+{
+ return GetSetProfile (1, AppName, KeyName, String, "", 0, FileName);
+}
+
+#if 0
+int WriteProfileString (char * AppName, char * KeyName, char * String)
+{
+ return (WritePrivateProfileString (AppName, KeyName, String, INIFILE));
+}
+#endif
+
+static void dump_keys (FILE * profile, TKeys * p)
+{
+ char *t;
+ if (!p)
+ return;
+ dump_keys (profile, p->link);
+ t = str_untranslate_newline_dup (p->Value);
+ fprintf (profile, "%s=%s\n", p->KeyName, t);
+ free (t);
+}
+
+static void dump_sections (FILE *profile, TSecHeader *p)
+{
+ if (!p)
+ return;
+ dump_sections (profile, p->link);
+ if (p->AppName [0]){
+ fprintf (profile, "\n[%s]\n", p->AppName);
+ dump_keys (profile, p->Keys);
+ }
+}
+
+static void dump_profile (TProfile *p)
+{
+ FILE *profile;
+
+ if (!p)
+ return;
+ dump_profile (p->link);
+ /* .ado: p->FileName can be empty, it's better to jump over */
+ if (p->FileName[0] != (char) 0)
+ if ((profile = fopen (p->FileName, "w")) != NULL){
+ dump_sections (profile, p->Section);
+ fclose (profile);
+ }
+}
+
+/*
+ * Must be called at the end of wine run
+*/
+
+void sync_profiles (void)
+{
+ dump_profile (Base);
+}
+
+static void free_keys (TKeys *p)
+{
+ if (!p)
+ return;
+ free_keys (p->link);
+ free (p->KeyName);
+ free (p->Value);
+ free (p);
+}
+
+static void free_sections (TSecHeader *p)
+{
+ if (!p)
+ return;
+ free_sections (p->link);
+ free_keys (p->Keys);
+ free (p->AppName);
+ p->link = 0;
+ p->Keys = 0;
+ free (p);
+}
+
+static void free_profile (TProfile *p)
+{
+ if (!p)
+ return;
+ free_profile (p->link);
+ free_sections (p->Section);
+ free (p->FileName);
+ free (p);
+}
+
+void free_profile_name (char *s)
+{
+ TProfile *p;
+
+ if (!s)
+ return;
+
+ for (p = Base; p; p = p->link){
+ if (strcmp (s, p->FileName) == 0){
+ free_sections (p->Section);
+ p->Section = 0;
+ p->FileName [0] = 0;
+ return;
+ }
+ }
+}
+
+void free_profiles (void)
+{
+ free_profile (Base);
+}
+
+void *profile_init_iterator (char *appname, char *file)
+{
+ TProfile *New;
+ TSecHeader *section;
+
+ if (!is_loaded (file, §ion)){
+ New = (TProfile *) xmalloc (sizeof (TProfile), "GetSetProfile");
+ New->link = Base;
+ New->FileName = strdup (file);
+ New->Section = load (file);
+ Base = New;
+ section = New->Section;
+ Current = New;
+ }
+ for (; section; section = section->link){
+ if (strcasecmp (section->AppName, appname))
+ continue;
+ return section->Keys;
+ }
+ return 0;
+}
+
+void *profile_iterator_next (void *s, char **key, char **value)
+{
+ TKeys *keys = (TKeys *) s;
+
+ if (keys){
+ *key = keys->KeyName;
+ *value = keys->Value;
+ keys = keys->link;
+ }
+ return keys;
+}
+
+void profile_clean_section (char *appname, char *file)
+{
+ TSecHeader *section;
+
+ /* We assume the user has called one of the other initialization funcs */
+ if (!is_loaded (file, §ion)){
+ fprintf (stderr,"Warning: profile_clean_section called before init\n");
+ return;
+ }
+ /* We only disable the section, so it will still be freed, but it */
+ /* won't be find by further walks of the structure */
+
+ for (; section; section = section->link){
+ if (strcasecmp (section->AppName, appname))
+ continue;
+ section->AppName [0] = 0;
+ }
+}
+
+int profile_has_section (char *section_name, char *profile)
+{
+ TSecHeader *section;
+
+ /* We assume the user has called one of the other initialization funcs */
+ if (!is_loaded (profile, §ion)){
+ return 0;
+ }
+ for (; section; section = section->link){
+ if (strcasecmp (section->AppName, section_name))
+ continue;
+ return 1;
+ }
+ return 0;
+}
+
+void profile_forget_profile (char *file)
+{
+ TProfile *p;
+
+ for (p = Base; p; p = p->link){
+ if (strcasecmp (file, p->FileName))
+ continue;
+ p->FileName [0] = 0;
+ }
+}
+
+
--- /dev/null
+#ifndef __PROFILE_H
+#define __PROFILE_H
+/* Prototypes for the profile management functions */
+
+#ifndef _OS_NT
+short GetPrivateProfileString (char * AppName, char * KeyName,
+ char * Default, char * ReturnedString,
+ short Size, char * FileName);
+
+int GetProfileString (char * AppName, char * KeyName, char * Default,
+ char * ReturnedString, int Size);
+
+int GetPrivateProfileInt (char * AppName, char * KeyName, int Default,
+ char * File);
+
+int GetProfileInt (char * AppName, char * KeyName, int Default);
+
+int WritePrivateProfileString (char * AppName, char * KeyName, char * String,
+ char * FileName);
+
+int WriteProfileString (char * AppName, char * KeyName, char * String);
+#endif /* not _OS_NT */
+
+void sync_profiles (void);
+
+void free_profiles (void);
+char *get_profile_string (char *AppName, char *KeyName, char *Default,
+ char *FileName);
+
+/* New profile functions */
+
+/* Returns a pointer for iterating on appname section, on profile file */
+void *profile_init_iterator (char *appname, char *file);
+
+/* Returns both the key and the value of the current section. */
+/* You pass the current iterating pointer and it returns the new pointer */
+void *profile_iterator_next (void *s, char **key, char **value);
+
+/* Removes all the definitions from section appname on file */
+void profile_clean_section (char *appname, char *file);
+int profile_has_section (char *section_name, char *profile);
+
+/* Forgets about a .ini file, to disable updating of it */
+void profile_forget_profile (char *file);
+
+/* Removes information from a profile */
+void free_profile_name (char *s);
+
+#endif /* __PROFILE_H */
--- /dev/null
+/* Extended regular expression matching and search library,
+ version 0.12.
+ (Implements POSIX draft P10003.2/D11.2, except for
+ internationalization features.)
+
+ Copyright (C) 1993, 1994, 1995 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 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* AIX requires this to be the first thing in the file. */
+#if defined (_AIX) && !defined (REGEX_MALLOC)
+ #pragma alloca
+#endif
+
+#define _GNU_SOURCE
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+/* We need this for `regex.h', and perhaps for the Emacs include files. */
+#include <sys/types.h>
+
+/* This is for other GNU distributions with internationalized messages. */
+#if HAVE_LIBINTL_H || defined (_LIBC)
+# include <libintl.h>
+#else
+# define gettext(msgid) (msgid)
+#endif
+
+/* The `emacs' switch turns on certain matching commands
+ that make sense only in Emacs. */
+#ifdef emacs
+
+#include "lisp.h"
+#include "buffer.h"
+#include "syntax.h"
+
+#else /* not emacs */
+
+/* If we are not linking with Emacs proper,
+ we can't use the relocating allocator
+ even if config.h says that we can. */
+#undef REL_ALLOC
+
+#if defined (STDC_HEADERS) || defined (_LIBC)
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+#endif
+
+/* When used in Emacs's lib-src, we need to get bzero and bcopy somehow.
+ If nothing else has been done, use the method below. */
+#ifdef INHIBIT_STRING_HEADER
+#if !(defined (HAVE_BZERO) && defined (HAVE_BCOPY))
+#if !defined (bzero) && !defined (bcopy)
+#undef INHIBIT_STRING_HEADER
+#endif
+#endif
+#endif
+
+/* This is the normal way of making sure we have a bcopy and a bzero.
+ This is used in most programs--a few other programs avoid this
+ by defining INHIBIT_STRING_HEADER. */
+#ifndef INHIBIT_STRING_HEADER
+#if defined (HAVE_STRING_H) || defined (STDC_HEADERS) || defined (_LIBC)
+#include <string.h>
+#ifndef bcmp
+#define bcmp(s1, s2, n) memcmp ((s1), (s2), (n))
+#endif
+#ifndef bcopy
+#define bcopy(s, d, n) memcpy ((d), (s), (n))
+#endif
+#ifndef bzero
+#define bzero(s, n) memset ((s), 0, (n))
+#endif
+#else
+#include <strings.h>
+#endif
+#endif
+
+/* Define the syntax stuff for \<, \>, etc. */
+
+/* This must be nonzero for the wordchar and notwordchar pattern
+ commands in re_match_2. */
+#ifndef Sword
+#define Sword 1
+#endif
+
+#ifdef SWITCH_ENUM_BUG
+#define SWITCH_ENUM_CAST(x) ((int)(x))
+#else
+#define SWITCH_ENUM_CAST(x) (x)
+#endif
+
+#ifdef SYNTAX_TABLE
+
+extern char *re_syntax_table;
+
+#else /* not SYNTAX_TABLE */
+
+/* How many characters in the character set. */
+#define CHAR_SET_SIZE 256
+
+static char re_syntax_table[CHAR_SET_SIZE];
+
+static void
+init_syntax_once ()
+{
+ register int c;
+ static int done = 0;
+
+ if (done)
+ return;
+
+ bzero (re_syntax_table, sizeof re_syntax_table);
+
+ for (c = 'a'; c <= 'z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = 'A'; c <= 'Z'; c++)
+ re_syntax_table[c] = Sword;
+
+ for (c = '0'; c <= '9'; c++)
+ re_syntax_table[c] = Sword;
+
+ re_syntax_table['_'] = Sword;
+
+ done = 1;
+}
+
+#endif /* not SYNTAX_TABLE */
+
+#define SYNTAX(c) re_syntax_table[c]
+
+#endif /* not emacs */
+\f
+/* Get the interface, including the syntax bits. */
+#include "regex.h"
+
+/* isalpha etc. are used for the character classes. */
+#include <ctype.h>
+
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#define ISASCII(c) 1
+#else
+#define ISASCII(c) isascii(c)
+#endif
+
+#ifdef isblank
+#define ISBLANK(c) (ISASCII (c) && isblank (c))
+#else
+#define ISBLANK(c) ((c) == ' ' || (c) == '\t')
+#endif
+#ifdef isgraph
+#define ISGRAPH(c) (ISASCII (c) && isgraph (c))
+#else
+#define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c))
+#endif
+
+#define ISPRINT(c) (ISASCII (c) && isprint (c))
+#define ISDIGIT(c) (ISASCII (c) && isdigit (c))
+#define ISALNUM(c) (ISASCII (c) && isalnum (c))
+#define ISALPHA(c) (ISASCII (c) && isalpha (c))
+#define ISCNTRL(c) (ISASCII (c) && iscntrl (c))
+#define ISLOWER(c) (ISASCII (c) && islower (c))
+#define ISPUNCT(c) (ISASCII (c) && ispunct (c))
+#define ISSPACE(c) (ISASCII (c) && isspace (c))
+#define ISUPPER(c) (ISASCII (c) && isupper (c))
+#define ISXDIGIT(c) (ISASCII (c) && isxdigit (c))
+
+#ifndef NULL
+#define NULL (void *)0
+#endif
+
+/* We remove any previous definition of `SIGN_EXTEND_CHAR',
+ since ours (we hope) works properly with all combinations of
+ machines, compilers, `char' and `unsigned char' argument types.
+ (Per Bothner suggested the basic approach.) */
+#undef SIGN_EXTEND_CHAR
+#if __STDC__
+#define SIGN_EXTEND_CHAR(c) ((signed char) (c))
+#else /* not __STDC__ */
+/* As in Harbison and Steele. */
+#define SIGN_EXTEND_CHAR(c) ((((unsigned char) (c)) ^ 128) - 128)
+#endif
+\f
+/* Should we use malloc or alloca? If REGEX_MALLOC is not defined, we
+ use `alloca' instead of `malloc'. This is because using malloc in
+ re_search* or re_match* could cause memory leaks when C-g is used in
+ Emacs; also, malloc is slower and causes storage fragmentation. On
+ the other hand, malloc is more portable, and easier to debug.
+
+ Because we sometimes use alloca, some routines have to be macros,
+ not functions -- `alloca'-allocated space disappears at the end of the
+ function it is called in. */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE malloc
+#define REGEX_REALLOCATE(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE free
+
+#else /* not REGEX_MALLOC */
+
+/* Emacs already defines alloca, sometimes. */
+#ifndef alloca
+
+/* Make alloca work the best possible way. */
+#ifdef __GNUC__
+#define alloca __builtin_alloca
+#else /* not __GNUC__ */
+#if HAVE_ALLOCA_H
+#include <alloca.h>
+#else /* not __GNUC__ or HAVE_ALLOCA_H */
+#ifndef _AIX /* Already did AIX, up at the top. */
+char *alloca ();
+#endif /* not _AIX */
+#endif /* not HAVE_ALLOCA_H */
+#endif /* not __GNUC__ */
+
+#endif /* not alloca */
+
+#define REGEX_ALLOCATE alloca
+
+/* Assumes a `char *destination' variable. */
+#define REGEX_REALLOCATE(source, osize, nsize) \
+ (destination = (char *) alloca (nsize), \
+ bcopy (source, destination, osize), \
+ destination)
+
+/* No need to do anything to free, after alloca. */
+#define REGEX_FREE(arg) ((void)0) /* Do nothing! But inhibit gcc warning. */
+
+#endif /* not REGEX_MALLOC */
+
+/* Define how to allocate the failure stack. */
+
+#ifdef REL_ALLOC
+#define REGEX_ALLOCATE_STACK(size) \
+ r_alloc (&failure_stack_ptr, (size))
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) \
+ r_re_alloc (&failure_stack_ptr, (nsize))
+#define REGEX_FREE_STACK(ptr) \
+ r_alloc_free (&failure_stack_ptr)
+
+#else /* not REL_ALLOC */
+
+#ifdef REGEX_MALLOC
+
+#define REGEX_ALLOCATE_STACK malloc
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) realloc (source, nsize)
+#define REGEX_FREE_STACK free
+
+#else /* not REGEX_MALLOC */
+
+#define REGEX_ALLOCATE_STACK alloca
+
+#define REGEX_REALLOCATE_STACK(source, osize, nsize) \
+ REGEX_REALLOCATE (source, osize, nsize)
+/* No need to explicitly free anything. */
+#define REGEX_FREE_STACK(arg)
+
+#endif /* not REGEX_MALLOC */
+#endif /* not REL_ALLOC */
+
+
+/* True if `size1' is non-NULL and PTR is pointing anywhere inside
+ `string1' or just past its end. This works if PTR is NULL, which is
+ a good thing. */
+#define FIRST_STRING_P(ptr) \
+ (size1 && string1 <= (ptr) && (ptr) <= string1 + size1)
+
+/* (Re)Allocate N items of type T using malloc, or fail. */
+#define TALLOC(n, t) ((t *) malloc ((n) * sizeof (t)))
+#define RETALLOC(addr, n, t) ((addr) = (t *) realloc (addr, (n) * sizeof (t)))
+#define RETALLOC_IF(addr, n, t) \
+ if (addr) RETALLOC((addr), (n), t); else (addr) = TALLOC ((n), t)
+#define REGEX_TALLOC(n, t) ((t *) REGEX_ALLOCATE ((n) * sizeof (t)))
+
+#define BYTEWIDTH 8 /* In bits. */
+
+#define STREQ(s1, s2) ((strcmp (s1, s2) == 0))
+
+#undef MAX
+#undef MIN
+#define MAX(a, b) ((a) > (b) ? (a) : (b))
+#define MIN(a, b) ((a) < (b) ? (a) : (b))
+
+typedef char boolean;
+#define false 0
+#define true 1
+
+static int re_match_2_internal ();
+\f
+/* These are the command codes that appear in compiled regular
+ expressions. Some opcodes are followed by argument bytes. A
+ command code can specify any interpretation whatsoever for its
+ arguments. Zero bytes may appear in the compiled regular expression. */
+
+typedef enum
+{
+ no_op = 0,
+
+ /* Succeed right away--no more backtracking. */
+ succeed,
+
+ /* Followed by one byte giving n, then by n literal bytes. */
+ exactn,
+
+ /* Matches any (more or less) character. */
+ anychar,
+
+ /* Matches any one char belonging to specified set. First
+ following byte is number of bitmap bytes. Then come bytes
+ for a bitmap saying which chars are in. Bits in each byte
+ are ordered low-bit-first. A character is in the set if its
+ bit is 1. A character too large to have a bit in the map is
+ automatically not in the set. */
+ charset,
+
+ /* Same parameters as charset, but match any character that is
+ not one of those specified. */
+ charset_not,
+
+ /* Start remembering the text that is matched, for storing in a
+ register. Followed by one byte with the register number, in
+ the range 0 to one less than the pattern buffer's re_nsub
+ field. Then followed by one byte with the number of groups
+ inner to this one. (This last has to be part of the
+ start_memory only because we need it in the on_failure_jump
+ of re_match_2.) */
+ start_memory,
+
+ /* Stop remembering the text that is matched and store it in a
+ memory register. Followed by one byte with the register
+ number, in the range 0 to one less than `re_nsub' in the
+ pattern buffer, and one byte with the number of inner groups,
+ just like `start_memory'. (We need the number of inner
+ groups here because we don't have any easy way of finding the
+ corresponding start_memory when we're at a stop_memory.) */
+ stop_memory,
+
+ /* Match a duplicate of something remembered. Followed by one
+ byte containing the register number. */
+ duplicate,
+
+ /* Fail unless at beginning of line. */
+ begline,
+
+ /* Fail unless at end of line. */
+ endline,
+
+ /* Succeeds if at beginning of buffer (if emacs) or at beginning
+ of string to be matched (if not). */
+ begbuf,
+
+ /* Analogously, for end of buffer/string. */
+ endbuf,
+
+ /* Followed by two byte relative address to which to jump. */
+ jump,
+
+ /* Same as jump, but marks the end of an alternative. */
+ jump_past_alt,
+
+ /* Followed by two-byte relative address of place to resume at
+ in case of failure. */
+ on_failure_jump,
+
+ /* Like on_failure_jump, but pushes a placeholder instead of the
+ current string position when executed. */
+ on_failure_keep_string_jump,
+
+ /* Throw away latest failure point and then jump to following
+ two-byte relative address. */
+ pop_failure_jump,
+
+ /* Change to pop_failure_jump if know won't have to backtrack to
+ match; otherwise change to jump. This is used to jump
+ back to the beginning of a repeat. If what follows this jump
+ clearly won't match what the repeat does, such that we can be
+ sure that there is no use backtracking out of repetitions
+ already matched, then we change it to a pop_failure_jump.
+ Followed by two-byte address. */
+ maybe_pop_jump,
+
+ /* Jump to following two-byte address, and push a dummy failure
+ point. This failure point will be thrown away if an attempt
+ is made to use it for a failure. A `+' construct makes this
+ before the first repeat. Also used as an intermediary kind
+ of jump when compiling an alternative. */
+ dummy_failure_jump,
+
+ /* Push a dummy failure point and continue. Used at the end of
+ alternatives. */
+ push_dummy_failure,
+
+ /* Followed by two-byte relative address and two-byte number n.
+ After matching N times, jump to the address upon failure. */
+ succeed_n,
+
+ /* Followed by two-byte relative address, and two-byte number n.
+ Jump to the address N times, then fail. */
+ jump_n,
+
+ /* Set the following two-byte relative address to the
+ subsequent two-byte number. The address *includes* the two
+ bytes of number. */
+ set_number_at,
+
+ wordchar, /* Matches any word-constituent character. */
+ notwordchar, /* Matches any char that is not a word-constituent. */
+
+ wordbeg, /* Succeeds if at word beginning. */
+ wordend, /* Succeeds if at word end. */
+
+ wordbound, /* Succeeds if at a word boundary. */
+ notwordbound /* Succeeds if not at a word boundary. */
+
+#ifdef emacs
+ ,before_dot, /* Succeeds if before point. */
+ at_dot, /* Succeeds if at point. */
+ after_dot, /* Succeeds if after point. */
+
+ /* Matches any character whose syntax is specified. Followed by
+ a byte which contains a syntax code, e.g., Sword. */
+ syntaxspec,
+
+ /* Matches any character whose syntax is not that specified. */
+ notsyntaxspec
+#endif /* emacs */
+} re_opcode_t;
+\f
+/* Common operations on the compiled pattern. */
+
+/* Store NUMBER in two contiguous bytes starting at DESTINATION. */
+
+#define STORE_NUMBER(destination, number) \
+ do { \
+ (destination)[0] = (number) & 0377; \
+ (destination)[1] = (number) >> 8; \
+ } while (0)
+
+/* Same as STORE_NUMBER, except increment DESTINATION to
+ the byte after where the number is stored. Therefore, DESTINATION
+ must be an lvalue. */
+
+#define STORE_NUMBER_AND_INCR(destination, number) \
+ do { \
+ STORE_NUMBER (destination, number); \
+ (destination) += 2; \
+ } while (0)
+
+/* Put into DESTINATION a number stored in two contiguous bytes starting
+ at SOURCE. */
+
+#define EXTRACT_NUMBER(destination, source) \
+ do { \
+ (destination) = *(source) & 0377; \
+ (destination) += SIGN_EXTEND_CHAR (*((source) + 1)) << 8; \
+ } while (0)
+
+#ifdef DEBUG
+static void
+extract_number (dest, source)
+ int *dest;
+ unsigned char *source;
+{
+ int temp = SIGN_EXTEND_CHAR (*(source + 1));
+ *dest = *source & 0377;
+ *dest += temp << 8;
+}
+
+#ifndef EXTRACT_MACROS /* To debug the macros. */
+#undef EXTRACT_NUMBER
+#define EXTRACT_NUMBER(dest, src) extract_number (&dest, src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+
+/* Same as EXTRACT_NUMBER, except increment SOURCE to after the number.
+ SOURCE must be an lvalue. */
+
+#define EXTRACT_NUMBER_AND_INCR(destination, source) \
+ do { \
+ EXTRACT_NUMBER (destination, source); \
+ (source) += 2; \
+ } while (0)
+
+#ifdef DEBUG
+static void
+extract_number_and_incr (destination, source)
+ int *destination;
+ unsigned char **source;
+{
+ extract_number (destination, *source);
+ *source += 2;
+}
+
+#ifndef EXTRACT_MACROS
+#undef EXTRACT_NUMBER_AND_INCR
+#define EXTRACT_NUMBER_AND_INCR(dest, src) \
+ extract_number_and_incr (&dest, &src)
+#endif /* not EXTRACT_MACROS */
+
+#endif /* DEBUG */
+\f
+/* If DEBUG is defined, Regex prints many voluminous messages about what
+ it is doing (if the variable `debug' is nonzero). If linked with the
+ main program in `iregex.c', you can enter patterns and strings
+ interactively. And if linked with the main program in `main.c' and
+ the other test files, you can run the already-written tests. */
+
+#ifdef DEBUG
+
+/* We use standard I/O for debugging. */
+#include <stdio.h>
+
+/* It is useful to test things that ``must'' be true when debugging. */
+#include <assert.h>
+
+static int debug = 0;
+
+#define DEBUG_STATEMENT(e) e
+#define DEBUG_PRINT1(x) if (debug) printf (x)
+#define DEBUG_PRINT2(x1, x2) if (debug) printf (x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3) if (debug) printf (x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4) if (debug) printf (x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e) \
+ if (debug) print_partial_compiled_pattern (s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2) \
+ if (debug) print_double_string (w, s1, sz1, s2, sz2)
+
+
+/* Print the fastmap in human-readable form. */
+
+void
+print_fastmap (fastmap)
+ char *fastmap;
+{
+ unsigned was_a_range = 0;
+ unsigned i = 0;
+
+ while (i < (1 << BYTEWIDTH))
+ {
+ if (fastmap[i++])
+ {
+ was_a_range = 0;
+ putchar (i - 1);
+ while (i < (1 << BYTEWIDTH) && fastmap[i])
+ {
+ was_a_range = 1;
+ i++;
+ }
+ if (was_a_range)
+ {
+ printf ("-");
+ putchar (i - 1);
+ }
+ }
+ }
+ putchar ('\n');
+}
+
+
+/* Print a compiled pattern string in human-readable form, starting at
+ the START pointer into it and ending just before the pointer END. */
+
+void
+print_partial_compiled_pattern (start, end)
+ unsigned char *start;
+ unsigned char *end;
+{
+ int mcnt, mcnt2;
+ unsigned char *p = start;
+ unsigned char *pend = end;
+
+ if (start == NULL)
+ {
+ printf ("(null)\n");
+ return;
+ }
+
+ /* Loop over pattern commands. */
+ while (p < pend)
+ {
+ printf ("%d:\t", p - start);
+
+ switch ((re_opcode_t) *p++)
+ {
+ case no_op:
+ printf ("/no_op");
+ break;
+
+ case exactn:
+ mcnt = *p++;
+ printf ("/exactn/%d", mcnt);
+ do
+ {
+ putchar ('/');
+ putchar (*p++);
+ }
+ while (--mcnt);
+ break;
+
+ case start_memory:
+ mcnt = *p++;
+ printf ("/start_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case stop_memory:
+ mcnt = *p++;
+ printf ("/stop_memory/%d/%d", mcnt, *p++);
+ break;
+
+ case duplicate:
+ printf ("/duplicate/%d", *p++);
+ break;
+
+ case anychar:
+ printf ("/anychar");
+ break;
+
+ case charset:
+ case charset_not:
+ {
+ register int c, last = -100;
+ register int in_range = 0;
+
+ printf ("/charset [%s",
+ (re_opcode_t) *(p - 1) == charset_not ? "^" : "");
+
+ assert (p + *p < pend);
+
+ for (c = 0; c < 256; c++)
+ if (c / 8 < *p
+ && (p[1 + (c/8)] & (1 << (c % 8))))
+ {
+ /* Are we starting a range? */
+ if (last + 1 == c && ! in_range)
+ {
+ putchar ('-');
+ in_range = 1;
+ }
+ /* Have we broken a range? */
+ else if (last + 1 != c && in_range)
+ {
+ putchar (last);
+ in_range = 0;
+ }
+
+ if (! in_range)
+ putchar (c);
+
+ last = c;
+ }
+
+ if (in_range)
+ putchar (last);
+
+ putchar (']');
+
+ p += 1 + *p;
+ }
+ break;
+
+ case begline:
+ printf ("/begline");
+ break;
+
+ case endline:
+ printf ("/endline");
+ break;
+
+ case on_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case on_failure_keep_string_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/on_failure_keep_string_jump to %d", p + mcnt - start);
+ break;
+
+ case dummy_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/dummy_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case push_dummy_failure:
+ printf ("/push_dummy_failure");
+ break;
+
+ case maybe_pop_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/maybe_pop_jump to %d", p + mcnt - start);
+ break;
+
+ case pop_failure_jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/pop_failure_jump to %d", p + mcnt - start);
+ break;
+
+ case jump_past_alt:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump_past_alt to %d", p + mcnt - start);
+ break;
+
+ case jump:
+ extract_number_and_incr (&mcnt, &p);
+ printf ("/jump to %d", p + mcnt - start);
+ break;
+
+ case succeed_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/succeed_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case jump_n:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/jump_n to %d, %d times", p + mcnt - start, mcnt2);
+ break;
+
+ case set_number_at:
+ extract_number_and_incr (&mcnt, &p);
+ extract_number_and_incr (&mcnt2, &p);
+ printf ("/set_number_at location %d to %d", p + mcnt - start, mcnt2);
+ break;
+
+ case wordbound:
+ printf ("/wordbound");
+ break;
+
+ case notwordbound:
+ printf ("/notwordbound");
+ break;
+
+ case wordbeg:
+ printf ("/wordbeg");
+ break;
+
+ case wordend:
+ printf ("/wordend");
+
+#ifdef emacs
+ case before_dot:
+ printf ("/before_dot");
+ break;
+
+ case at_dot:
+ printf ("/at_dot");
+ break;
+
+ case after_dot:
+ printf ("/after_dot");
+ break;
+
+ case syntaxspec:
+ printf ("/syntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+
+ case notsyntaxspec:
+ printf ("/notsyntaxspec");
+ mcnt = *p++;
+ printf ("/%d", mcnt);
+ break;
+#endif /* emacs */
+
+ case wordchar:
+ printf ("/wordchar");
+ break;
+
+ case notwordchar:
+ printf ("/notwordchar");
+ break;
+
+ case begbuf:
+ printf ("/begbuf");
+ break;
+
+ case endbuf:
+ printf ("/endbuf");
+ break;
+
+ default:
+ printf ("?%d", *(p-1));
+ }
+
+ putchar ('\n');
+ }
+
+ printf ("%d:\tend of pattern.\n", p - start);
+}
+
+
+void
+print_compiled_pattern (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ unsigned char *buffer = bufp->buffer;
+
+ print_partial_compiled_pattern (buffer, buffer + bufp->used);
+ printf ("%d bytes used/%d bytes allocated.\n", bufp->used, bufp->allocated);
+
+ if (bufp->fastmap_accurate && bufp->fastmap)
+ {
+ printf ("fastmap: ");
+ print_fastmap (bufp->fastmap);
+ }
+
+ printf ("re_nsub: %d\t", bufp->re_nsub);
+ printf ("regs_alloc: %d\t", bufp->regs_allocated);
+ printf ("can_be_null: %d\t", bufp->can_be_null);
+ printf ("newline_anchor: %d\n", bufp->newline_anchor);
+ printf ("no_sub: %d\t", bufp->no_sub);
+ printf ("not_bol: %d\t", bufp->not_bol);
+ printf ("not_eol: %d\t", bufp->not_eol);
+ printf ("syntax: %d\n", bufp->syntax);
+ /* Perhaps we should print the translate table? */
+}
+
+
+void
+print_double_string (where, string1, size1, string2, size2)
+ const char *where;
+ const char *string1;
+ const char *string2;
+ int size1;
+ int size2;
+{
+ unsigned this_char;
+
+ if (where == NULL)
+ printf ("(null)");
+ else
+ {
+ if (FIRST_STRING_P (where))
+ {
+ for (this_char = where - string1; this_char < size1; this_char++)
+ putchar (string1[this_char]);
+
+ where = string2;
+ }
+
+ for (this_char = where - string2; this_char < size2; this_char++)
+ putchar (string2[this_char]);
+ }
+}
+
+#else /* not DEBUG */
+
+#undef assert
+#define assert(e)
+
+#define DEBUG_STATEMENT(e)
+#define DEBUG_PRINT1(x)
+#define DEBUG_PRINT2(x1, x2)
+#define DEBUG_PRINT3(x1, x2, x3)
+#define DEBUG_PRINT4(x1, x2, x3, x4)
+#define DEBUG_PRINT_COMPILED_PATTERN(p, s, e)
+#define DEBUG_PRINT_DOUBLE_STRING(w, s1, sz1, s2, sz2)
+
+#endif /* not DEBUG */
+\f
+/* Set by `re_set_syntax' to the current regexp syntax to recognize. Can
+ also be assigned to arbitrarily: each pattern buffer stores its own
+ syntax, so it can be changed between regex compilations. */
+/* This has no initializer because initialized variables in Emacs
+ become read-only after dumping. */
+reg_syntax_t re_syntax_options;
+
+
+/* Specify the precise syntax of regexps for compilation. This provides
+ for compatibility for various utilities which historically have
+ different, incompatible syntaxes.
+
+ The argument SYNTAX is a bit mask comprised of the various bits
+ defined in regex.h. We return the old syntax. */
+
+reg_syntax_t
+re_set_syntax (syntax)
+ reg_syntax_t syntax;
+{
+ reg_syntax_t ret = re_syntax_options;
+
+ re_syntax_options = syntax;
+ return ret;
+}
+\f
+/* This table gives an error message for each of the error codes listed
+ in regex.h. Obviously the order here has to be same as there.
+ POSIX doesn't require that we do anything for REG_NOERROR,
+ but why not be nice? */
+
+static const char *re_error_msgid[] =
+ { "Success", /* REG_NOERROR */
+ "No match", /* REG_NOMATCH */
+ "Invalid regular expression", /* REG_BADPAT */
+ "Invalid collation character", /* REG_ECOLLATE */
+ "Invalid character class name", /* REG_ECTYPE */
+ "Trailing backslash", /* REG_EESCAPE */
+ "Invalid back reference", /* REG_ESUBREG */
+ "Unmatched [ or [^", /* REG_EBRACK */
+ "Unmatched ( or \\(", /* REG_EPAREN */
+ "Unmatched \\{", /* REG_EBRACE */
+ "Invalid content of \\{\\}", /* REG_BADBR */
+ "Invalid range end", /* REG_ERANGE */
+ "Memory exhausted", /* REG_ESPACE */
+ "Invalid preceding regular expression", /* REG_BADRPT */
+ "Premature end of regular expression", /* REG_EEND */
+ "Regular expression too big", /* REG_ESIZE */
+ "Unmatched ) or \\)", /* REG_ERPAREN */
+ };
+\f
+/* Avoiding alloca during matching, to placate r_alloc. */
+
+/* Define MATCH_MAY_ALLOCATE unless we need to make sure that the
+ searching and matching functions should not call alloca. On some
+ systems, alloca is implemented in terms of malloc, and if we're
+ using the relocating allocator routines, then malloc could cause a
+ relocation, which might (if the strings being searched are in the
+ ralloc heap) shift the data out from underneath the regexp
+ routines.
+
+ Here's another reason to avoid allocation: Emacs
+ processes input from X in a signal handler; processing X input may
+ call malloc; if input arrives while a matching routine is calling
+ malloc, then we're scrod. But Emacs can't just block input while
+ calling matching routines; then we don't notice interrupts when
+ they come in. So, Emacs blocks input around all regexp calls
+ except the matching calls, which it leaves unprotected, in the
+ faith that they will not malloc. */
+
+/* Normally, this is fine. */
+#define MATCH_MAY_ALLOCATE
+
+/* When using GNU C, we are not REALLY using the C alloca, no matter
+ what config.h may say. So don't take precautions for it. */
+#ifdef __GNUC__
+#undef C_ALLOCA
+#endif
+
+/* The match routines may not allocate if (1) they would do it with malloc
+ and (2) it's not safe for them to use malloc.
+ Note that if REL_ALLOC is defined, matching would not use malloc for the
+ failure stack, but we would still use it for the register vectors;
+ so REL_ALLOC should not affect this. */
+#if (defined (C_ALLOCA) || defined (REGEX_MALLOC)) && defined (emacs)
+#undef MATCH_MAY_ALLOCATE
+#endif
+
+\f
+/* Failure stack declarations and macros; both re_compile_fastmap and
+ re_match_2 use a failure stack. These have to be macros because of
+ REGEX_ALLOCATE_STACK. */
+
+
+/* Number of failure points for which to initially allocate space
+ when matching. If this number is exceeded, we allocate more
+ space, so it is not a hard limit. */
+#ifndef INIT_FAILURE_ALLOC
+#define INIT_FAILURE_ALLOC 5
+#endif
+
+/* Roughly the maximum number of failure points on the stack. Would be
+ exactly that if always used MAX_FAILURE_SPACE each time we failed.
+ This is a variable only so users of regex can assign to it; we never
+ change it ourselves. */
+#if defined (MATCH_MAY_ALLOCATE)
+int re_max_failures = 200000;
+#else
+int re_max_failures = 2000;
+#endif
+
+union fail_stack_elt
+{
+ unsigned char *pointer;
+ int integer;
+};
+
+typedef union fail_stack_elt fail_stack_elt_t;
+
+typedef struct
+{
+ fail_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} fail_stack_type;
+
+#define FAIL_STACK_EMPTY() (fail_stack.avail == 0)
+#define FAIL_STACK_PTR_EMPTY() (fail_stack_ptr->avail == 0)
+#define FAIL_STACK_FULL() (fail_stack.avail == fail_stack.size)
+
+
+/* Define macros to initialize and free the failure stack.
+ Do `return -2' if the alloc fails. */
+
+#ifdef MATCH_MAY_ALLOCATE
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.stack = (fail_stack_elt_t *) \
+ REGEX_ALLOCATE_STACK (INIT_FAILURE_ALLOC * sizeof (fail_stack_elt_t)); \
+ \
+ if (fail_stack.stack == NULL) \
+ return -2; \
+ \
+ fail_stack.size = INIT_FAILURE_ALLOC; \
+ fail_stack.avail = 0; \
+ } while (0)
+
+#define RESET_FAIL_STACK() REGEX_FREE_STACK (fail_stack.stack)
+#else
+#define INIT_FAIL_STACK() \
+ do { \
+ fail_stack.avail = 0; \
+ } while (0)
+
+#define RESET_FAIL_STACK()
+#endif
+
+
+/* Double the size of FAIL_STACK, up to approximately `re_max_failures' items.
+
+ Return 1 if succeeds, and 0 if either ran out of memory
+ allocating space for it or it was already too large.
+
+ REGEX_REALLOCATE_STACK requires `destination' be declared. */
+
+#define DOUBLE_FAIL_STACK(fail_stack) \
+ ((fail_stack).size > re_max_failures * MAX_FAILURE_ITEMS \
+ ? 0 \
+ : ((fail_stack).stack = (fail_stack_elt_t *) \
+ REGEX_REALLOCATE_STACK ((fail_stack).stack, \
+ (fail_stack).size * sizeof (fail_stack_elt_t), \
+ ((fail_stack).size << 1) * sizeof (fail_stack_elt_t)), \
+ \
+ (fail_stack).stack == NULL \
+ ? 0 \
+ : ((fail_stack).size <<= 1, \
+ 1)))
+
+
+/* Push pointer POINTER on FAIL_STACK.
+ Return 1 if was able to do so and 0 if ran out of memory allocating
+ space to do so. */
+#define PUSH_PATTERN_OP(POINTER, FAIL_STACK) \
+ ((FAIL_STACK_FULL () \
+ && !DOUBLE_FAIL_STACK (FAIL_STACK)) \
+ ? 0 \
+ : ((FAIL_STACK).stack[(FAIL_STACK).avail++].pointer = POINTER, \
+ 1))
+
+/* Push a pointer value onto the failure stack.
+ Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_POINTER(item) \
+ fail_stack.stack[fail_stack.avail++].pointer = (unsigned char *) (item)
+
+/* This pushes an integer-valued item onto the failure stack.
+ Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_INT(item) \
+ fail_stack.stack[fail_stack.avail++].integer = (item)
+
+/* Push a fail_stack_elt_t value onto the failure stack.
+ Assumes the variable `fail_stack'. Probably should only
+ be called from within `PUSH_FAILURE_POINT'. */
+#define PUSH_FAILURE_ELT(item) \
+ fail_stack.stack[fail_stack.avail++] = (item)
+
+/* These three POP... operations complement the three PUSH... operations.
+ All assume that `fail_stack' is nonempty. */
+#define POP_FAILURE_POINTER() fail_stack.stack[--fail_stack.avail].pointer
+#define POP_FAILURE_INT() fail_stack.stack[--fail_stack.avail].integer
+#define POP_FAILURE_ELT() fail_stack.stack[--fail_stack.avail]
+
+/* Used to omit pushing failure point id's when we're not debugging. */
+#ifdef DEBUG
+#define DEBUG_PUSH PUSH_FAILURE_INT
+#define DEBUG_POP(item_addr) *(item_addr) = POP_FAILURE_INT ()
+#else
+#define DEBUG_PUSH(item)
+#define DEBUG_POP(item_addr)
+#endif
+
+
+/* Push the information about the state we will need
+ if we ever fail back to it.
+
+ Requires variables fail_stack, regstart, regend, reg_info, and
+ num_regs be declared. DOUBLE_FAIL_STACK requires `destination' be
+ declared.
+
+ Does `return FAILURE_CODE' if runs out of memory. */
+
+#define PUSH_FAILURE_POINT(pattern_place, string_place, failure_code) \
+ do { \
+ char *destination; \
+ /* Must be int, so when we don't save any registers, the arithmetic \
+ of 0 + -1 isn't done as unsigned. */ \
+ int this_reg; \
+ \
+ destination = 0; /* inhibit possible compiler warning */ \
+ DEBUG_STATEMENT (failure_id++); \
+ DEBUG_STATEMENT (nfailure_points_pushed++); \
+ DEBUG_PRINT2 ("\nPUSH_FAILURE_POINT #%u:\n", failure_id); \
+ DEBUG_PRINT2 (" Before push, next avail: %d\n", (fail_stack).avail);\
+ DEBUG_PRINT2 (" size: %d\n", (fail_stack).size);\
+ \
+ DEBUG_PRINT2 (" slots needed: %d\n", NUM_FAILURE_ITEMS); \
+ DEBUG_PRINT2 (" available: %d\n", REMAINING_AVAIL_SLOTS); \
+ \
+ /* Ensure we have enough space allocated for what we will push. */ \
+ while (REMAINING_AVAIL_SLOTS < NUM_FAILURE_ITEMS) \
+ { \
+ if (!DOUBLE_FAIL_STACK (fail_stack)) \
+ return failure_code; \
+ \
+ DEBUG_PRINT2 ("\n Doubled stack; size now: %d\n", \
+ (fail_stack).size); \
+ DEBUG_PRINT2 (" slots available: %d\n", REMAINING_AVAIL_SLOTS);\
+ } \
+ \
+ /* Push the info, starting with the registers. */ \
+ DEBUG_PRINT1 ("\n"); \
+ \
+ for (this_reg = lowest_active_reg; this_reg <= highest_active_reg; \
+ this_reg++) \
+ { \
+ DEBUG_PRINT2 (" Pushing reg: %d\n", this_reg); \
+ DEBUG_STATEMENT (num_regs_pushed++); \
+ \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ PUSH_FAILURE_POINTER (regstart[this_reg]); \
+ \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ PUSH_FAILURE_POINTER (regend[this_reg]); \
+ \
+ DEBUG_PRINT2 (" info: 0x%x\n ", reg_info[this_reg]); \
+ DEBUG_PRINT2 (" match_null=%d", \
+ REG_MATCH_NULL_STRING_P (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" active=%d", IS_ACTIVE (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" matched_something=%d", \
+ MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT2 (" ever_matched=%d", \
+ EVER_MATCHED_SOMETHING (reg_info[this_reg])); \
+ DEBUG_PRINT1 ("\n"); \
+ PUSH_FAILURE_ELT (reg_info[this_reg].word); \
+ } \
+ \
+ DEBUG_PRINT2 (" Pushing low active reg: %d\n", lowest_active_reg);\
+ PUSH_FAILURE_INT (lowest_active_reg); \
+ \
+ DEBUG_PRINT2 (" Pushing high active reg: %d\n", highest_active_reg);\
+ PUSH_FAILURE_INT (highest_active_reg); \
+ \
+ DEBUG_PRINT2 (" Pushing pattern 0x%x: ", pattern_place); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pattern_place, pend); \
+ PUSH_FAILURE_POINTER (pattern_place); \
+ \
+ DEBUG_PRINT2 (" Pushing string 0x%x: `", string_place); \
+ DEBUG_PRINT_DOUBLE_STRING (string_place, string1, size1, string2, \
+ size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ PUSH_FAILURE_POINTER (string_place); \
+ \
+ DEBUG_PRINT2 (" Pushing failure id: %u\n", failure_id); \
+ DEBUG_PUSH (failure_id); \
+ } while (0)
+
+/* This is the number of items that are pushed and popped on the stack
+ for each register. */
+#define NUM_REG_ITEMS 3
+
+/* Individual items aside from the registers. */
+#ifdef DEBUG
+#define NUM_NONREG_ITEMS 5 /* Includes failure point id. */
+#else
+#define NUM_NONREG_ITEMS 4
+#endif
+
+/* We push at most this many items on the stack. */
+#define MAX_FAILURE_ITEMS ((num_regs - 1) * NUM_REG_ITEMS + NUM_NONREG_ITEMS)
+
+/* We actually push this many items. */
+#define NUM_FAILURE_ITEMS \
+ ((highest_active_reg - lowest_active_reg + 1) * NUM_REG_ITEMS \
+ + NUM_NONREG_ITEMS)
+
+/* How many items can still be added to the stack without overflowing it. */
+#define REMAINING_AVAIL_SLOTS ((fail_stack).size - (fail_stack).avail)
+
+
+/* Pops what PUSH_FAIL_STACK pushes.
+
+ We restore into the parameters, all of which should be lvalues:
+ STR -- the saved data position.
+ PAT -- the saved pattern position.
+ LOW_REG, HIGH_REG -- the highest and lowest active registers.
+ REGSTART, REGEND -- arrays of string positions.
+ REG_INFO -- array of information about each subexpression.
+
+ Also assumes the variables `fail_stack' and (if debugging), `bufp',
+ `pend', `string1', `size1', `string2', and `size2'. */
+
+#define POP_FAILURE_POINT(str, pat, low_reg, high_reg, regstart, regend, reg_info)\
+{ \
+ DEBUG_STATEMENT (fail_stack_elt_t failure_id;) \
+ int this_reg; \
+ const unsigned char *string_temp; \
+ \
+ assert (!FAIL_STACK_EMPTY ()); \
+ \
+ /* Remove failure points and point to how many regs pushed. */ \
+ DEBUG_PRINT1 ("POP_FAILURE_POINT:\n"); \
+ DEBUG_PRINT2 (" Before pop, next avail: %d\n", fail_stack.avail); \
+ DEBUG_PRINT2 (" size: %d\n", fail_stack.size); \
+ \
+ assert (fail_stack.avail >= NUM_NONREG_ITEMS); \
+ \
+ DEBUG_POP (&failure_id); \
+ DEBUG_PRINT2 (" Popping failure id: %u\n", failure_id); \
+ \
+ /* If the saved string location is NULL, it came from an \
+ on_failure_keep_string_jump opcode, and we want to throw away the \
+ saved NULL, thus retaining our current position in the string. */ \
+ string_temp = POP_FAILURE_POINTER (); \
+ if (string_temp != NULL) \
+ str = (const char *) string_temp; \
+ \
+ DEBUG_PRINT2 (" Popping string 0x%x: `", str); \
+ DEBUG_PRINT_DOUBLE_STRING (str, string1, size1, string2, size2); \
+ DEBUG_PRINT1 ("'\n"); \
+ \
+ pat = (unsigned char *) POP_FAILURE_POINTER (); \
+ DEBUG_PRINT2 (" Popping pattern 0x%x: ", pat); \
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, pat, pend); \
+ \
+ /* Restore register info. */ \
+ high_reg = (unsigned) POP_FAILURE_INT (); \
+ DEBUG_PRINT2 (" Popping high active reg: %d\n", high_reg); \
+ \
+ low_reg = (unsigned) POP_FAILURE_INT (); \
+ DEBUG_PRINT2 (" Popping low active reg: %d\n", low_reg); \
+ \
+ for (this_reg = high_reg; this_reg >= low_reg; this_reg--) \
+ { \
+ DEBUG_PRINT2 (" Popping reg: %d\n", this_reg); \
+ \
+ reg_info[this_reg].word = POP_FAILURE_ELT (); \
+ DEBUG_PRINT2 (" info: 0x%x\n", reg_info[this_reg]); \
+ \
+ regend[this_reg] = (const char *) POP_FAILURE_POINTER (); \
+ DEBUG_PRINT2 (" end: 0x%x\n", regend[this_reg]); \
+ \
+ regstart[this_reg] = (const char *) POP_FAILURE_POINTER (); \
+ DEBUG_PRINT2 (" start: 0x%x\n", regstart[this_reg]); \
+ } \
+ \
+ set_regs_matched_done = 0; \
+ DEBUG_STATEMENT (nfailure_points_popped++); \
+} /* POP_FAILURE_POINT */
+
+
+\f
+/* Structure for per-register (a.k.a. per-group) information.
+ Other register information, such as the
+ starting and ending positions (which are addresses), and the list of
+ inner groups (which is a bits list) are maintained in separate
+ variables.
+
+ We are making a (strictly speaking) nonportable assumption here: that
+ the compiler will pack our bit fields into something that fits into
+ the type of `word', i.e., is something that fits into one item on the
+ failure stack. */
+
+typedef union
+{
+ fail_stack_elt_t word;
+ struct
+ {
+ /* This field is one if this group can match the empty string,
+ zero if not. If not yet determined, `MATCH_NULL_UNSET_VALUE'. */
+#define MATCH_NULL_UNSET_VALUE 3
+ unsigned match_null_string_p : 2;
+ unsigned is_active : 1;
+ unsigned matched_something : 1;
+ unsigned ever_matched_something : 1;
+ } bits;
+} register_info_type;
+
+#define REG_MATCH_NULL_STRING_P(R) ((R).bits.match_null_string_p)
+#define IS_ACTIVE(R) ((R).bits.is_active)
+#define MATCHED_SOMETHING(R) ((R).bits.matched_something)
+#define EVER_MATCHED_SOMETHING(R) ((R).bits.ever_matched_something)
+
+
+/* Call this when have matched a real character; it sets `matched' flags
+ for the subexpressions which we are currently inside. Also records
+ that those subexprs have matched. */
+#define SET_REGS_MATCHED() \
+ do \
+ { \
+ if (!set_regs_matched_done) \
+ { \
+ unsigned r; \
+ set_regs_matched_done = 1; \
+ for (r = lowest_active_reg; r <= highest_active_reg; r++) \
+ { \
+ MATCHED_SOMETHING (reg_info[r]) \
+ = EVER_MATCHED_SOMETHING (reg_info[r]) \
+ = 1; \
+ } \
+ } \
+ } \
+ while (0)
+
+/* Registers are set to a sentinel when they haven't yet matched. */
+static char reg_unset_dummy;
+#define REG_UNSET_VALUE (®_unset_dummy)
+#define REG_UNSET(e) ((e) == REG_UNSET_VALUE)
+\f
+/* Subroutine declarations and macros for regex_compile. */
+
+static void store_op1 (), store_op2 ();
+static void insert_op1 (), insert_op2 ();
+static boolean at_begline_loc_p (), at_endline_loc_p ();
+static boolean group_in_compile_stack ();
+static reg_errcode_t compile_range ();
+
+/* Fetch the next character in the uncompiled pattern---translating it
+ if necessary. Also cast from a signed character in the constant
+ string passed to us by the user to an unsigned char that we can use
+ as an array index (in, e.g., `translate'). */
+#define PATFETCH(c) \
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ if (translate) c = translate[c]; \
+ } while (0)
+
+/* Fetch the next character in the uncompiled pattern, with no
+ translation. */
+#define PATFETCH_RAW(c) \
+ do {if (p == pend) return REG_EEND; \
+ c = (unsigned char) *p++; \
+ } while (0)
+
+/* Go backwards one character in the pattern. */
+#define PATUNFETCH p--
+
+
+/* If `translate' is non-null, return translate[D], else just D. We
+ cast the subscript to translate because some data is declared as
+ `char *', to avoid warnings when a string constant is passed. But
+ when we use a character as a subscript we must make it unsigned. */
+#define TRANSLATE(d) (translate ? translate[(unsigned char) (d)] : (d))
+
+
+/* Macros for outputting the compiled pattern into `buffer'. */
+
+/* If the buffer isn't allocated when it comes in, use this. */
+#define INIT_BUF_SIZE 32
+
+/* Make sure we have at least N more bytes of space in buffer. */
+#define GET_BUFFER_SPACE(n) \
+ while (b - bufp->buffer + (n) > bufp->allocated) \
+ EXTEND_BUFFER ()
+
+/* Make sure we have one more byte of buffer space and then add C to it. */
+#define BUF_PUSH(c) \
+ do { \
+ GET_BUFFER_SPACE (1); \
+ *b++ = (unsigned char) (c); \
+ } while (0)
+
+
+/* Ensure we have two more bytes of buffer space and then append C1 and C2. */
+#define BUF_PUSH_2(c1, c2) \
+ do { \
+ GET_BUFFER_SPACE (2); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ } while (0)
+
+
+/* As with BUF_PUSH_2, except for three bytes. */
+#define BUF_PUSH_3(c1, c2, c3) \
+ do { \
+ GET_BUFFER_SPACE (3); \
+ *b++ = (unsigned char) (c1); \
+ *b++ = (unsigned char) (c2); \
+ *b++ = (unsigned char) (c3); \
+ } while (0)
+
+
+/* Store a jump with opcode OP at LOC to location TO. We store a
+ relative address offset by the three bytes the jump itself occupies. */
+#define STORE_JUMP(op, loc, to) \
+ store_op1 (op, loc, (to) - (loc) - 3)
+
+/* Likewise, for a two-argument jump. */
+#define STORE_JUMP2(op, loc, to, arg) \
+ store_op2 (op, loc, (to) - (loc) - 3, arg)
+
+/* Like `STORE_JUMP', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP(op, loc, to) \
+ insert_op1 (op, loc, (to) - (loc) - 3, b)
+
+/* Like `STORE_JUMP2', but for inserting. Assume `b' is the buffer end. */
+#define INSERT_JUMP2(op, loc, to, arg) \
+ insert_op2 (op, loc, (to) - (loc) - 3, arg, b)
+
+
+/* This is not an arbitrary limit: the arguments which represent offsets
+ into the pattern are two bytes long. So if 2^16 bytes turns out to
+ be too small, many things would have to change. */
+#define MAX_BUF_SIZE (1L << 16)
+
+
+/* Extend the buffer by twice its current size via realloc and
+ reset the pointers that pointed into the old block to point to the
+ correct places in the new one. If extending the buffer results in it
+ being larger than MAX_BUF_SIZE, then flag memory exhausted. */
+#define EXTEND_BUFFER() \
+ do { \
+ unsigned char *old_buffer = bufp->buffer; \
+ if (bufp->allocated == MAX_BUF_SIZE) \
+ return REG_ESIZE; \
+ bufp->allocated <<= 1; \
+ if (bufp->allocated > MAX_BUF_SIZE) \
+ bufp->allocated = MAX_BUF_SIZE; \
+ bufp->buffer = (unsigned char *) realloc (bufp->buffer, bufp->allocated);\
+ if (bufp->buffer == NULL) \
+ return REG_ESPACE; \
+ /* If the buffer moved, move all the pointers into it. */ \
+ if (old_buffer != bufp->buffer) \
+ { \
+ b = (b - old_buffer) + bufp->buffer; \
+ begalt = (begalt - old_buffer) + bufp->buffer; \
+ if (fixup_alt_jump) \
+ fixup_alt_jump = (fixup_alt_jump - old_buffer) + bufp->buffer;\
+ if (laststart) \
+ laststart = (laststart - old_buffer) + bufp->buffer; \
+ if (pending_exact) \
+ pending_exact = (pending_exact - old_buffer) + bufp->buffer; \
+ } \
+ } while (0)
+
+
+/* Since we have one byte reserved for the register number argument to
+ {start,stop}_memory, the maximum number of groups we can report
+ things about is what fits in that byte. */
+#define MAX_REGNUM 255
+
+/* But patterns can have more than `MAX_REGNUM' registers. We just
+ ignore the excess. */
+typedef unsigned regnum_t;
+
+
+/* Macros for the compile stack. */
+
+/* Since offsets can go either forwards or backwards, this type needs to
+ be able to hold values from -(MAX_BUF_SIZE - 1) to MAX_BUF_SIZE - 1. */
+typedef int pattern_offset_t;
+
+typedef struct
+{
+ pattern_offset_t begalt_offset;
+ pattern_offset_t fixup_alt_jump;
+ pattern_offset_t inner_group_offset;
+ pattern_offset_t laststart_offset;
+ regnum_t regnum;
+} compile_stack_elt_t;
+
+
+typedef struct
+{
+ compile_stack_elt_t *stack;
+ unsigned size;
+ unsigned avail; /* Offset of next open position. */
+} compile_stack_type;
+
+
+#define INIT_COMPILE_STACK_SIZE 32
+
+#define COMPILE_STACK_EMPTY (compile_stack.avail == 0)
+#define COMPILE_STACK_FULL (compile_stack.avail == compile_stack.size)
+
+/* The next available element. */
+#define COMPILE_STACK_TOP (compile_stack.stack[compile_stack.avail])
+
+
+/* Set the bit for character C in a list. */
+#define SET_LIST_BIT(c) \
+ (b[((unsigned char) (c)) / BYTEWIDTH] \
+ |= 1 << (((unsigned char) c) % BYTEWIDTH))
+
+
+/* Get the next unsigned number in the uncompiled pattern. */
+#define GET_UNSIGNED_NUMBER(num) \
+ { if (p != pend) \
+ { \
+ PATFETCH (c); \
+ while (ISDIGIT (c)) \
+ { \
+ if (num < 0) \
+ num = 0; \
+ num = num * 10 + c - '0'; \
+ if (p == pend) \
+ break; \
+ PATFETCH (c); \
+ } \
+ } \
+ }
+
+#define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */
+
+#define IS_CHAR_CLASS(string) \
+ (STREQ (string, "alpha") || STREQ (string, "upper") \
+ || STREQ (string, "lower") || STREQ (string, "digit") \
+ || STREQ (string, "alnum") || STREQ (string, "xdigit") \
+ || STREQ (string, "space") || STREQ (string, "print") \
+ || STREQ (string, "punct") || STREQ (string, "graph") \
+ || STREQ (string, "cntrl") || STREQ (string, "blank"))
+\f
+#ifndef MATCH_MAY_ALLOCATE
+
+/* If we cannot allocate large objects within re_match_2_internal,
+ we make the fail stack and register vectors global.
+ The fail stack, we grow to the maximum size when a regexp
+ is compiled.
+ The register vectors, we adjust in size each time we
+ compile a regexp, according to the number of registers it needs. */
+
+static fail_stack_type fail_stack;
+
+/* Size with which the following vectors are currently allocated.
+ That is so we can make them bigger as needed,
+ but never make them smaller. */
+static int regs_allocated_size;
+
+static const char ** regstart, ** regend;
+static const char ** old_regstart, ** old_regend;
+static const char **best_regstart, **best_regend;
+static register_info_type *reg_info;
+static const char **reg_dummy;
+static register_info_type *reg_info_dummy;
+
+/* Make the register vectors big enough for NUM_REGS registers,
+ but don't make them smaller. */
+
+static
+regex_grow_registers (num_regs)
+ int num_regs;
+{
+ if (num_regs > regs_allocated_size)
+ {
+ RETALLOC_IF (regstart, num_regs, const char *);
+ RETALLOC_IF (regend, num_regs, const char *);
+ RETALLOC_IF (old_regstart, num_regs, const char *);
+ RETALLOC_IF (old_regend, num_regs, const char *);
+ RETALLOC_IF (best_regstart, num_regs, const char *);
+ RETALLOC_IF (best_regend, num_regs, const char *);
+ RETALLOC_IF (reg_info, num_regs, register_info_type);
+ RETALLOC_IF (reg_dummy, num_regs, const char *);
+ RETALLOC_IF (reg_info_dummy, num_regs, register_info_type);
+
+ regs_allocated_size = num_regs;
+ }
+}
+
+#endif /* not MATCH_MAY_ALLOCATE */
+\f
+/* `regex_compile' compiles PATTERN (of length SIZE) according to SYNTAX.
+ Returns one of error codes defined in `regex.h', or zero for success.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate'
+ fields are set in BUFP on entry.
+
+ If it succeeds, results are put in BUFP (if it returns an error, the
+ contents of BUFP are undefined):
+ `buffer' is the compiled pattern;
+ `syntax' is set to SYNTAX;
+ `used' is set to the length of the compiled pattern;
+ `fastmap_accurate' is zero;
+ `re_nsub' is the number of subexpressions in PATTERN;
+ `not_bol' and `not_eol' are zero;
+
+ The `fastmap' and `newline_anchor' fields are neither
+ examined nor set. */
+
+/* Return, freeing storage we allocated. */
+#define FREE_STACK_RETURN(value) \
+ return (free (compile_stack.stack), value)
+
+static reg_errcode_t
+regex_compile (pattern, size, syntax, bufp)
+ const char *pattern;
+ int size;
+ reg_syntax_t syntax;
+ struct re_pattern_buffer *bufp;
+{
+ /* We fetch characters from PATTERN here. Even though PATTERN is
+ `char *' (i.e., signed), we declare these variables as unsigned, so
+ they can be reliably used as array indices. */
+ register unsigned char c, c1;
+
+ /* A random temporary spot in PATTERN. */
+ const char *p1;
+
+ /* Points to the end of the buffer, where we should append. */
+ register unsigned char *b;
+
+ /* Keeps track of unclosed groups. */
+ compile_stack_type compile_stack;
+
+ /* Points to the current (ending) position in the pattern. */
+ const char *p = pattern;
+ const char *pend = pattern + size;
+
+ /* How to translate the characters in the pattern. */
+ char *translate = bufp->translate;
+
+ /* Address of the count-byte of the most recently inserted `exactn'
+ command. This makes it possible to tell if a new exact-match
+ character can be added to that command or if the character requires
+ a new `exactn' command. */
+ unsigned char *pending_exact = 0;
+
+ /* Address of start of the most recently finished expression.
+ This tells, e.g., postfix * where to find the start of its
+ operand. Reset at the beginning of groups and alternatives. */
+ unsigned char *laststart = 0;
+
+ /* Address of beginning of regexp, or inside of last group. */
+ unsigned char *begalt;
+
+ /* Place in the uncompiled pattern (i.e., the {) to
+ which to go back if the interval is invalid. */
+ const char *beg_interval;
+
+ /* Address of the place where a forward jump should go to the end of
+ the containing expression. Each alternative of an `or' -- except the
+ last -- ends with a forward jump of this sort. */
+ unsigned char *fixup_alt_jump = 0;
+
+ /* Counts open-groups as they are encountered. Remembered for the
+ matching close-group on the compile stack, so the same register
+ number is put in the stop_memory as the start_memory. */
+ regnum_t regnum = 0;
+
+#ifdef DEBUG
+ DEBUG_PRINT1 ("\nCompiling pattern: ");
+ if (debug)
+ {
+ unsigned debug_count;
+
+ for (debug_count = 0; debug_count < size; debug_count++)
+ putchar (pattern[debug_count]);
+ putchar ('\n');
+ }
+#endif /* DEBUG */
+
+ /* Initialize the compile stack. */
+ compile_stack.stack = TALLOC (INIT_COMPILE_STACK_SIZE, compile_stack_elt_t);
+ if (compile_stack.stack == NULL)
+ return REG_ESPACE;
+
+ compile_stack.size = INIT_COMPILE_STACK_SIZE;
+ compile_stack.avail = 0;
+
+ /* Initialize the pattern buffer. */
+ bufp->syntax = syntax;
+ bufp->fastmap_accurate = 0;
+ bufp->not_bol = bufp->not_eol = 0;
+
+ /* Set `used' to zero, so that if we return an error, the pattern
+ printer (for debugging) will think there's no pattern. We reset it
+ at the end. */
+ bufp->used = 0;
+
+ /* Always count groups, whether or not bufp->no_sub is set. */
+ bufp->re_nsub = 0;
+
+#if !defined (emacs) && !defined (SYNTAX_TABLE)
+ /* Initialize the syntax table. */
+ init_syntax_once ();
+#endif
+
+ if (bufp->allocated == 0)
+ {
+ if (bufp->buffer)
+ { /* If zero allocated, but buffer is non-null, try to realloc
+ enough space. This loses if buffer's address is bogus, but
+ that is the user's responsibility. */
+ RETALLOC (bufp->buffer, INIT_BUF_SIZE, unsigned char);
+ }
+ else
+ { /* Caller did not allocate a buffer. Do it for them. */
+ bufp->buffer = TALLOC (INIT_BUF_SIZE, unsigned char);
+ }
+ if (!bufp->buffer) FREE_STACK_RETURN (REG_ESPACE);
+
+ bufp->allocated = INIT_BUF_SIZE;
+ }
+
+ begalt = b = bufp->buffer;
+
+ /* Loop through the uncompiled pattern until we're at the end. */
+ while (p != pend)
+ {
+ PATFETCH (c);
+
+ switch (c)
+ {
+ case '^':
+ {
+ if ( /* If at start of pattern, it's an operator. */
+ p == pattern + 1
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's come before. */
+ || at_begline_loc_p (pattern, p, syntax))
+ BUF_PUSH (begline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ case '$':
+ {
+ if ( /* If at end of pattern, it's an operator. */
+ p == pend
+ /* If context independent, it's an operator. */
+ || syntax & RE_CONTEXT_INDEP_ANCHORS
+ /* Otherwise, depends on what's next. */
+ || at_endline_loc_p (p, pend, syntax))
+ BUF_PUSH (endline);
+ else
+ goto normal_char;
+ }
+ break;
+
+
+ case '+':
+ case '?':
+ if ((syntax & RE_BK_PLUS_QM)
+ || (syntax & RE_LIMITED_OPS))
+ goto normal_char;
+ handle_plus:
+ case '*':
+ /* If there is no previous pattern... */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ FREE_STACK_RETURN (REG_BADRPT);
+ else if (!(syntax & RE_CONTEXT_INDEP_OPS))
+ goto normal_char;
+ }
+
+ {
+ /* Are we optimizing this jump? */
+ boolean keep_string_p = false;
+
+ /* 1 means zero (many) matches is allowed. */
+ char zero_times_ok = 0, many_times_ok = 0;
+
+ /* If there is a sequence of repetition chars, collapse it
+ down to just one (the right one). We can't combine
+ interval operators with these because of, e.g., `a{2}*',
+ which should only match an even number of `a's. */
+
+ for (;;)
+ {
+ zero_times_ok |= c != '+';
+ many_times_ok |= c != '?';
+
+ if (p == pend)
+ break;
+
+ PATFETCH (c);
+
+ if (c == '*'
+ || (!(syntax & RE_BK_PLUS_QM) && (c == '+' || c == '?')))
+ ;
+
+ else if (syntax & RE_BK_PLUS_QM && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c1);
+ if (!(c1 == '+' || c1 == '?'))
+ {
+ PATUNFETCH;
+ PATUNFETCH;
+ break;
+ }
+
+ c = c1;
+ }
+ else
+ {
+ PATUNFETCH;
+ break;
+ }
+
+ /* If we get here, we found another repeat character. */
+ }
+
+ /* Star, etc. applied to an empty pattern is equivalent
+ to an empty pattern. */
+ if (!laststart)
+ break;
+
+ /* Now we know whether or not zero matches is allowed
+ and also whether or not two or more matches is allowed. */
+ if (many_times_ok)
+ { /* More than one repetition is allowed, so put in at the
+ end a backward relative jump from `b' to before the next
+ jump we're going to put in below (which jumps from
+ laststart to after this jump).
+
+ But if we are at the `*' in the exact sequence `.*\n',
+ insert an unconditional jump backwards to the .,
+ instead of the beginning of the loop. This way we only
+ push a failure point once, instead of every time
+ through the loop. */
+ assert (p - 1 > pattern);
+
+ /* Allocate the space for the jump. */
+ GET_BUFFER_SPACE (3);
+
+ /* We know we are not at the first character of the pattern,
+ because laststart was nonzero. And we've already
+ incremented `p', by the way, to be the character after
+ the `*'. Do we have to do something analogous here
+ for null bytes, because of RE_DOT_NOT_NULL? */
+ if (TRANSLATE (*(p - 2)) == TRANSLATE ('.')
+ && zero_times_ok
+ && p < pend && TRANSLATE (*p) == TRANSLATE ('\n')
+ && !(syntax & RE_DOT_NEWLINE))
+ { /* We have .*\n. */
+ STORE_JUMP (jump, b, laststart);
+ keep_string_p = true;
+ }
+ else
+ /* Anything else. */
+ STORE_JUMP (maybe_pop_jump, b, laststart - 3);
+
+ /* We've added more stuff to the buffer. */
+ b += 3;
+ }
+
+ /* On failure, jump from laststart to b + 3, which will be the
+ end of the buffer after this jump is inserted. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (keep_string_p ? on_failure_keep_string_jump
+ : on_failure_jump,
+ laststart, b + 3);
+ pending_exact = 0;
+ b += 3;
+
+ if (!zero_times_ok)
+ {
+ /* At least one repetition is required, so insert a
+ `dummy_failure_jump' before the initial
+ `on_failure_jump' instruction of the loop. This
+ effects a skip over that instruction the first time
+ we hit that loop. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (dummy_failure_jump, laststart, laststart + 6);
+ b += 3;
+ }
+ }
+ break;
+
+
+ case '.':
+ laststart = b;
+ BUF_PUSH (anychar);
+ break;
+
+
+ case '[':
+ {
+ boolean had_char_class = false;
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ /* Ensure that we have enough space to push a charset: the
+ opcode, the length count, and the bitset; 34 bytes in all. */
+ GET_BUFFER_SPACE (34);
+
+ laststart = b;
+
+ /* We test `*p == '^' twice, instead of using an if
+ statement, so we only need one BUF_PUSH. */
+ BUF_PUSH (*p == '^' ? charset_not : charset);
+ if (*p == '^')
+ p++;
+
+ /* Remember the first position in the bracket expression. */
+ p1 = p;
+
+ /* Push the number of bytes in the bitmap. */
+ BUF_PUSH ((1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* Clear the whole map. */
+ bzero (b, (1 << BYTEWIDTH) / BYTEWIDTH);
+
+ /* charset_not matches newline according to a syntax bit. */
+ if ((re_opcode_t) b[-2] == charset_not
+ && (syntax & RE_HAT_LISTS_NOT_NEWLINE))
+ SET_LIST_BIT ('\n');
+
+ /* Read in characters and ranges, setting map bits. */
+ for (;;)
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ PATFETCH (c);
+
+ /* \ might escape characters inside [...] and [^...]. */
+ if ((syntax & RE_BACKSLASH_ESCAPE_IN_LISTS) && c == '\\')
+ {
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ PATFETCH (c1);
+ SET_LIST_BIT (c1);
+ continue;
+ }
+
+ /* Could be the end of the bracket expression. If it's
+ not (i.e., when the bracket expression is `[]' so
+ far), the ']' character bit gets set way below. */
+ if (c == ']' && p != p1 + 1)
+ break;
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character class. */
+ if (had_char_class && c == '-' && *p != ']')
+ FREE_STACK_RETURN (REG_ERANGE);
+
+ /* Look ahead to see if it's a range when the last thing
+ was a character: if this is a hyphen not at the
+ beginning or the end of a list, then it's the range
+ operator. */
+ if (c == '-'
+ && !(p - 2 >= pattern && p[-2] == '[')
+ && !(p - 3 >= pattern && p[-3] == '[' && p[-2] == '^')
+ && *p != ']')
+ {
+ reg_errcode_t ret
+ = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+ }
+
+ else if (p[0] == '-' && p[1] != ']')
+ { /* This handles ranges made up of characters only. */
+ reg_errcode_t ret;
+
+ /* Move past the `-'. */
+ PATFETCH (c1);
+
+ ret = compile_range (&p, pend, translate, syntax, b);
+ if (ret != REG_NOERROR) FREE_STACK_RETURN (ret);
+ }
+
+ /* See if we're at the beginning of a possible character
+ class. */
+
+ else if (syntax & RE_CHAR_CLASSES && c == '[' && *p == ':')
+ { /* Leave room for the null. */
+ char str[CHAR_CLASS_MAX_LENGTH + 1];
+
+ PATFETCH (c);
+ c1 = 0;
+
+ /* If pattern is `[[:'. */
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (;;)
+ {
+ PATFETCH (c);
+ if (c == ':' || c == ']' || p == pend
+ || c1 == CHAR_CLASS_MAX_LENGTH)
+ break;
+ str[c1++] = c;
+ }
+ str[c1] = '\0';
+
+ /* If isn't a word bracketed by `[:' and:`]':
+ undo the ending character, the letters, and leave
+ the leading `:' and `[' (but set bits for them). */
+ if (c == ':' && *p == ']')
+ {
+ int ch;
+ boolean is_alnum = STREQ (str, "alnum");
+ boolean is_alpha = STREQ (str, "alpha");
+ boolean is_blank = STREQ (str, "blank");
+ boolean is_cntrl = STREQ (str, "cntrl");
+ boolean is_digit = STREQ (str, "digit");
+ boolean is_graph = STREQ (str, "graph");
+ boolean is_lower = STREQ (str, "lower");
+ boolean is_print = STREQ (str, "print");
+ boolean is_punct = STREQ (str, "punct");
+ boolean is_space = STREQ (str, "space");
+ boolean is_upper = STREQ (str, "upper");
+ boolean is_xdigit = STREQ (str, "xdigit");
+
+ if (!IS_CHAR_CLASS (str))
+ FREE_STACK_RETURN (REG_ECTYPE);
+
+ /* Throw away the ] at the end of the character
+ class. */
+ PATFETCH (c);
+
+ if (p == pend) FREE_STACK_RETURN (REG_EBRACK);
+
+ for (ch = 0; ch < 1 << BYTEWIDTH; ch++)
+ {
+ /* This was split into 3 if's to
+ avoid an arbitrary limit in some compiler. */
+ if ( (is_alnum && ISALNUM (ch))
+ || (is_alpha && ISALPHA (ch))
+ || (is_blank && ISBLANK (ch))
+ || (is_cntrl && ISCNTRL (ch)))
+ SET_LIST_BIT (ch);
+ if ( (is_digit && ISDIGIT (ch))
+ || (is_graph && ISGRAPH (ch))
+ || (is_lower && ISLOWER (ch))
+ || (is_print && ISPRINT (ch)))
+ SET_LIST_BIT (ch);
+ if ( (is_punct && ISPUNCT (ch))
+ || (is_space && ISSPACE (ch))
+ || (is_upper && ISUPPER (ch))
+ || (is_xdigit && ISXDIGIT (ch)))
+ SET_LIST_BIT (ch);
+ }
+ had_char_class = true;
+ }
+ else
+ {
+ c1++;
+ while (c1--)
+ PATUNFETCH;
+ SET_LIST_BIT ('[');
+ SET_LIST_BIT (':');
+ had_char_class = false;
+ }
+ }
+ else
+ {
+ had_char_class = false;
+ SET_LIST_BIT (c);
+ }
+ }
+
+ /* Discard any (non)matching list bytes that are all 0 at the
+ end of the map. Decrease the map-length byte too. */
+ while ((int) b[-1] > 0 && b[b[-1] - 1] == 0)
+ b[-1]--;
+ b += b[-1];
+ }
+ break;
+
+
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_open;
+ else
+ goto normal_char;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS)
+ goto handle_close;
+ else
+ goto normal_char;
+
+
+ case '\n':
+ if (syntax & RE_NEWLINE_ALT)
+ goto handle_alt;
+ else
+ goto normal_char;
+
+
+ case '|':
+ if (syntax & RE_NO_BK_VBAR)
+ goto handle_alt;
+ else
+ goto normal_char;
+
+
+ case '{':
+ if (syntax & RE_INTERVALS && syntax & RE_NO_BK_BRACES)
+ goto handle_interval;
+ else
+ goto normal_char;
+
+
+ case '\\':
+ if (p == pend) FREE_STACK_RETURN (REG_EESCAPE);
+
+ /* Do not translate the character after the \, so that we can
+ distinguish, e.g., \B from \b, even if we normally would
+ translate, e.g., B to b. */
+ PATFETCH_RAW (c);
+
+ switch (c)
+ {
+ case '(':
+ if (syntax & RE_NO_BK_PARENS)
+ goto normal_backslash;
+
+ handle_open:
+ bufp->re_nsub++;
+ regnum++;
+
+ if (COMPILE_STACK_FULL)
+ {
+ RETALLOC (compile_stack.stack, compile_stack.size << 1,
+ compile_stack_elt_t);
+ if (compile_stack.stack == NULL) return REG_ESPACE;
+
+ compile_stack.size <<= 1;
+ }
+
+ /* These are the values to restore when we hit end of this
+ group. They are all relative offsets, so that if the
+ whole pattern moves because of realloc, they will still
+ be valid. */
+ COMPILE_STACK_TOP.begalt_offset = begalt - bufp->buffer;
+ COMPILE_STACK_TOP.fixup_alt_jump
+ = fixup_alt_jump ? fixup_alt_jump - bufp->buffer + 1 : 0;
+ COMPILE_STACK_TOP.laststart_offset = b - bufp->buffer;
+ COMPILE_STACK_TOP.regnum = regnum;
+
+ /* We will eventually replace the 0 with the number of
+ groups inner to this one. But do not push a
+ start_memory for groups beyond the last one we can
+ represent in the compiled pattern. */
+ if (regnum <= MAX_REGNUM)
+ {
+ COMPILE_STACK_TOP.inner_group_offset = b - bufp->buffer + 2;
+ BUF_PUSH_3 (start_memory, regnum, 0);
+ }
+
+ compile_stack.avail++;
+
+ fixup_alt_jump = 0;
+ laststart = 0;
+ begalt = b;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+ break;
+
+
+ case ')':
+ if (syntax & RE_NO_BK_PARENS) goto normal_backslash;
+
+ if (COMPILE_STACK_EMPTY)
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_backslash;
+ else
+ FREE_STACK_RETURN (REG_ERPAREN);
+
+ handle_close:
+ if (fixup_alt_jump)
+ { /* Push a dummy failure point at the end of the
+ alternative for a possible future
+ `pop_failure_jump' to pop. See comments at
+ `push_dummy_failure' in `re_match_2'. */
+ BUF_PUSH (push_dummy_failure);
+
+ /* We allocated space for this jump when we assigned
+ to `fixup_alt_jump', in the `handle_alt' case below. */
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b - 1);
+ }
+
+ /* See similar code for backslashed left paren above. */
+ if (COMPILE_STACK_EMPTY)
+ if (syntax & RE_UNMATCHED_RIGHT_PAREN_ORD)
+ goto normal_char;
+ else
+ FREE_STACK_RETURN (REG_ERPAREN);
+
+ /* Since we just checked for an empty stack above, this
+ ``can't happen''. */
+ assert (compile_stack.avail != 0);
+ {
+ /* We don't just want to restore into `regnum', because
+ later groups should continue to be numbered higher,
+ as in `(ab)c(de)' -- the second group is #2. */
+ regnum_t this_group_regnum;
+
+ compile_stack.avail--;
+ begalt = bufp->buffer + COMPILE_STACK_TOP.begalt_offset;
+ fixup_alt_jump
+ = COMPILE_STACK_TOP.fixup_alt_jump
+ ? bufp->buffer + COMPILE_STACK_TOP.fixup_alt_jump - 1
+ : 0;
+ laststart = bufp->buffer + COMPILE_STACK_TOP.laststart_offset;
+ this_group_regnum = COMPILE_STACK_TOP.regnum;
+ /* If we've reached MAX_REGNUM groups, then this open
+ won't actually generate any code, so we'll have to
+ clear pending_exact explicitly. */
+ pending_exact = 0;
+
+ /* We're at the end of the group, so now we know how many
+ groups were inside this one. */
+ if (this_group_regnum <= MAX_REGNUM)
+ {
+ unsigned char *inner_group_loc
+ = bufp->buffer + COMPILE_STACK_TOP.inner_group_offset;
+
+ *inner_group_loc = regnum - this_group_regnum;
+ BUF_PUSH_3 (stop_memory, this_group_regnum,
+ regnum - this_group_regnum);
+ }
+ }
+ break;
+
+
+ case '|': /* `\|'. */
+ if (syntax & RE_LIMITED_OPS || syntax & RE_NO_BK_VBAR)
+ goto normal_backslash;
+ handle_alt:
+ if (syntax & RE_LIMITED_OPS)
+ goto normal_char;
+
+ /* Insert before the previous alternative a jump which
+ jumps to this alternative if the former fails. */
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (on_failure_jump, begalt, b + 6);
+ pending_exact = 0;
+ b += 3;
+
+ /* The alternative before this one has a jump after it
+ which gets executed if it gets matched. Adjust that
+ jump so it will jump to this alternative's analogous
+ jump (put in below, which in turn will jump to the next
+ (if any) alternative's such jump, etc.). The last such
+ jump jumps to the correct final destination. A picture:
+ _____ _____
+ | | | |
+ | v | v
+ a | b | c
+
+ If we are at `b', then fixup_alt_jump right now points to a
+ three-byte space after `a'. We'll put in the jump, set
+ fixup_alt_jump to right after `b', and leave behind three
+ bytes which we'll fill in when we get to after `c'. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ /* Mark and leave space for a jump after this alternative,
+ to be filled in later either by next alternative or
+ when know we're at the end of a series of alternatives. */
+ fixup_alt_jump = b;
+ GET_BUFFER_SPACE (3);
+ b += 3;
+
+ laststart = 0;
+ begalt = b;
+ break;
+
+
+ case '{':
+ /* If \{ is a literal. */
+ if (!(syntax & RE_INTERVALS)
+ /* If we're at `\{' and it's not the open-interval
+ operator. */
+ || ((syntax & RE_INTERVALS) && (syntax & RE_NO_BK_BRACES))
+ || (p - 2 == pattern && p == pend))
+ goto normal_backslash;
+
+ handle_interval:
+ {
+ /* If got here, then the syntax allows intervals. */
+
+ /* At least (most) this many matches must be made. */
+ int lower_bound = -1, upper_bound = -1;
+
+ beg_interval = p - 1;
+
+ if (p == pend)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_EBRACE);
+ }
+
+ GET_UNSIGNED_NUMBER (lower_bound);
+
+ if (c == ',')
+ {
+ GET_UNSIGNED_NUMBER (upper_bound);
+ if (upper_bound < 0) upper_bound = RE_DUP_MAX;
+ }
+ else
+ /* Interval such as `{1}' => match exactly once. */
+ upper_bound = lower_bound;
+
+ if (lower_bound < 0 || upper_bound > RE_DUP_MAX
+ || lower_bound > upper_bound)
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_BADBR);
+ }
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (c != '\\') FREE_STACK_RETURN (REG_EBRACE);
+
+ PATFETCH (c);
+ }
+
+ if (c != '}')
+ {
+ if (syntax & RE_NO_BK_BRACES)
+ goto unfetch_interval;
+ else
+ FREE_STACK_RETURN (REG_BADBR);
+ }
+
+ /* We just parsed a valid interval. */
+
+ /* If it's invalid to have no preceding re. */
+ if (!laststart)
+ {
+ if (syntax & RE_CONTEXT_INVALID_OPS)
+ FREE_STACK_RETURN (REG_BADRPT);
+ else if (syntax & RE_CONTEXT_INDEP_OPS)
+ laststart = b;
+ else
+ goto unfetch_interval;
+ }
+
+ /* If the upper bound is zero, don't want to succeed at
+ all; jump from `laststart' to `b + 3', which will be
+ the end of the buffer after we insert the jump. */
+ if (upper_bound == 0)
+ {
+ GET_BUFFER_SPACE (3);
+ INSERT_JUMP (jump, laststart, b + 3);
+ b += 3;
+ }
+
+ /* Otherwise, we have a nontrivial interval. When
+ we're all done, the pattern will look like:
+ set_number_at <jump count> <upper bound>
+ set_number_at <succeed_n count> <lower bound>
+ succeed_n <after jump addr> <succeed_n count>
+ <body of loop>
+ jump_n <succeed_n addr> <jump count>
+ (The upper bound and `jump_n' are omitted if
+ `upper_bound' is 1, though.) */
+ else
+ { /* If the upper bound is > 1, we need to insert
+ more at the end of the loop. */
+ unsigned nbytes = 10 + (upper_bound > 1) * 10;
+
+ GET_BUFFER_SPACE (nbytes);
+
+ /* Initialize lower bound of the `succeed_n', even
+ though it will be set during matching by its
+ attendant `set_number_at' (inserted next),
+ because `re_compile_fastmap' needs to know.
+ Jump to the `jump_n' we might insert below. */
+ INSERT_JUMP2 (succeed_n, laststart,
+ b + 5 + (upper_bound > 1) * 5,
+ lower_bound);
+ b += 5;
+
+ /* Code to initialize the lower bound. Insert
+ before the `succeed_n'. The `5' is the last two
+ bytes of this `set_number_at', plus 3 bytes of
+ the following `succeed_n'. */
+ insert_op2 (set_number_at, laststart, 5, lower_bound, b);
+ b += 5;
+
+ if (upper_bound > 1)
+ { /* More than one repetition is allowed, so
+ append a backward jump to the `succeed_n'
+ that starts this interval.
+
+ When we've reached this during matching,
+ we'll have matched the interval once, so
+ jump back only `upper_bound - 1' times. */
+ STORE_JUMP2 (jump_n, b, laststart + 5,
+ upper_bound - 1);
+ b += 5;
+
+ /* The location we want to set is the second
+ parameter of the `jump_n'; that is `b-2' as
+ an absolute address. `laststart' will be
+ the `set_number_at' we're about to insert;
+ `laststart+3' the number to set, the source
+ for the relative address. But we are
+ inserting into the middle of the pattern --
+ so everything is getting moved up by 5.
+ Conclusion: (b - 2) - (laststart + 3) + 5,
+ i.e., b - laststart.
+
+ We insert this at the beginning of the loop
+ so that if we fail during matching, we'll
+ reinitialize the bounds. */
+ insert_op2 (set_number_at, laststart, b - laststart,
+ upper_bound - 1, b);
+ b += 5;
+ }
+ }
+ pending_exact = 0;
+ beg_interval = NULL;
+ }
+ break;
+
+ unfetch_interval:
+ /* If an invalid interval, match the characters as literals. */
+ assert (beg_interval);
+ p = beg_interval;
+ beg_interval = NULL;
+
+ /* normal_char and normal_backslash need `c'. */
+ PATFETCH (c);
+
+ if (!(syntax & RE_NO_BK_BRACES))
+ {
+ if (p > pattern && p[-1] == '\\')
+ goto normal_backslash;
+ }
+ goto normal_char;
+
+#ifdef emacs
+ /* There is no way to specify the before_dot and after_dot
+ operators. rms says this is ok. --karl */
+ case '=':
+ BUF_PUSH (at_dot);
+ break;
+
+ case 's':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (syntaxspec, syntax_spec_code[c]);
+ break;
+
+ case 'S':
+ laststart = b;
+ PATFETCH (c);
+ BUF_PUSH_2 (notsyntaxspec, syntax_spec_code[c]);
+ break;
+#endif /* emacs */
+
+
+ case 'w':
+ laststart = b;
+ BUF_PUSH (wordchar);
+ break;
+
+
+ case 'W':
+ laststart = b;
+ BUF_PUSH (notwordchar);
+ break;
+
+
+ case '<':
+ BUF_PUSH (wordbeg);
+ break;
+
+ case '>':
+ BUF_PUSH (wordend);
+ break;
+
+ case 'b':
+ BUF_PUSH (wordbound);
+ break;
+
+ case 'B':
+ BUF_PUSH (notwordbound);
+ break;
+
+ case '`':
+ BUF_PUSH (begbuf);
+ break;
+
+ case '\'':
+ BUF_PUSH (endbuf);
+ break;
+
+ case '1': case '2': case '3': case '4': case '5':
+ case '6': case '7': case '8': case '9':
+ if (syntax & RE_NO_BK_REFS)
+ goto normal_char;
+
+ c1 = c - '0';
+
+ if (c1 > regnum)
+ FREE_STACK_RETURN (REG_ESUBREG);
+
+ /* Can't back reference to a subexpression if inside of it. */
+ if (group_in_compile_stack (compile_stack, c1))
+ goto normal_char;
+
+ laststart = b;
+ BUF_PUSH_2 (duplicate, c1);
+ break;
+
+
+ case '+':
+ case '?':
+ if (syntax & RE_BK_PLUS_QM)
+ goto handle_plus;
+ else
+ goto normal_backslash;
+
+ default:
+ normal_backslash:
+ /* You might think it would be useful for \ to mean
+ not to translate; but if we don't translate it
+ it will never match anything. */
+ c = TRANSLATE (c);
+ goto normal_char;
+ }
+ break;
+
+
+ default:
+ /* Expects the character in `c'. */
+ normal_char:
+ /* If no exactn currently being built. */
+ if (!pending_exact
+
+ /* If last exactn not at current position. */
+ || pending_exact + *pending_exact + 1 != b
+
+ /* We have only one byte following the exactn for the count. */
+ || *pending_exact == (1 << BYTEWIDTH) - 1
+
+ /* If followed by a repetition operator. */
+ || *p == '*' || *p == '^'
+ || ((syntax & RE_BK_PLUS_QM)
+ ? *p == '\\' && (p[1] == '+' || p[1] == '?')
+ : (*p == '+' || *p == '?'))
+ || ((syntax & RE_INTERVALS)
+ && ((syntax & RE_NO_BK_BRACES)
+ ? *p == '{'
+ : (p[0] == '\\' && p[1] == '{'))))
+ {
+ /* Start building a new exactn. */
+
+ laststart = b;
+
+ BUF_PUSH_2 (exactn, 0);
+ pending_exact = b - 1;
+ }
+
+ BUF_PUSH (c);
+ (*pending_exact)++;
+ break;
+ } /* switch (c) */
+ } /* while p != pend */
+
+
+ /* Through the pattern now. */
+
+ if (fixup_alt_jump)
+ STORE_JUMP (jump_past_alt, fixup_alt_jump, b);
+
+ if (!COMPILE_STACK_EMPTY)
+ FREE_STACK_RETURN (REG_EPAREN);
+
+ /* If we don't want backtracking, force success
+ the first time we reach the end of the compiled pattern. */
+ if (syntax & RE_NO_POSIX_BACKTRACKING)
+ BUF_PUSH (succeed);
+
+ free (compile_stack.stack);
+
+ /* We have succeeded; set the length of the buffer. */
+ bufp->used = b - bufp->buffer;
+
+#ifdef DEBUG
+ if (debug)
+ {
+ DEBUG_PRINT1 ("\nCompiled pattern: \n");
+ print_compiled_pattern (bufp);
+ }
+#endif /* DEBUG */
+
+#ifndef MATCH_MAY_ALLOCATE
+ /* Initialize the failure stack to the largest possible stack. This
+ isn't necessary unless we're trying to avoid calling alloca in
+ the search and match routines. */
+ {
+ int num_regs = bufp->re_nsub + 1;
+
+ /* Since DOUBLE_FAIL_STACK refuses to double only if the current size
+ is strictly greater than re_max_failures, the largest possible stack
+ is 2 * re_max_failures failure points. */
+ if (fail_stack.size < (2 * re_max_failures * MAX_FAILURE_ITEMS))
+ {
+ fail_stack.size = (2 * re_max_failures * MAX_FAILURE_ITEMS);
+
+#ifdef emacs
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) xmalloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) xrealloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+#else /* not emacs */
+ if (! fail_stack.stack)
+ fail_stack.stack
+ = (fail_stack_elt_t *) malloc (fail_stack.size
+ * sizeof (fail_stack_elt_t));
+ else
+ fail_stack.stack
+ = (fail_stack_elt_t *) realloc (fail_stack.stack,
+ (fail_stack.size
+ * sizeof (fail_stack_elt_t)));
+#endif /* not emacs */
+ }
+
+ regex_grow_registers (num_regs);
+ }
+#endif /* not MATCH_MAY_ALLOCATE */
+
+ return REG_NOERROR;
+} /* regex_compile */
+\f
+/* Subroutines for `regex_compile'. */
+
+/* Store OP at LOC followed by two-byte integer parameter ARG. */
+
+static void
+store_op1 (op, loc, arg)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg);
+}
+
+
+/* Like `store_op1', but for two two-byte parameters ARG1 and ARG2. */
+
+static void
+store_op2 (op, loc, arg1, arg2)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+{
+ *loc = (unsigned char) op;
+ STORE_NUMBER (loc + 1, arg1);
+ STORE_NUMBER (loc + 3, arg2);
+}
+
+
+/* Copy the bytes from LOC to END to open up three bytes of space at LOC
+ for OP followed by two-byte integer parameter ARG. */
+
+static void
+insert_op1 (op, loc, arg, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg;
+ unsigned char *end;
+{
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 3;
+
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op1 (op, loc, arg);
+}
+
+
+/* Like `insert_op1', but for two two-byte parameters ARG1 and ARG2. */
+
+static void
+insert_op2 (op, loc, arg1, arg2, end)
+ re_opcode_t op;
+ unsigned char *loc;
+ int arg1, arg2;
+ unsigned char *end;
+{
+ register unsigned char *pfrom = end;
+ register unsigned char *pto = end + 5;
+
+ while (pfrom != loc)
+ *--pto = *--pfrom;
+
+ store_op2 (op, loc, arg1, arg2);
+}
+
+
+/* P points to just after a ^ in PATTERN. Return true if that ^ comes
+ after an alternative or a begin-subexpression. We assume there is at
+ least one character before the ^. */
+
+static boolean
+at_begline_loc_p (pattern, p, syntax)
+ const char *pattern, *p;
+ reg_syntax_t syntax;
+{
+ const char *prev = p - 2;
+ boolean prev_prev_backslash = prev > pattern && prev[-1] == '\\';
+
+ return
+ /* After a subexpression? */
+ (*prev == '(' && (syntax & RE_NO_BK_PARENS || prev_prev_backslash))
+ /* After an alternative? */
+ || (*prev == '|' && (syntax & RE_NO_BK_VBAR || prev_prev_backslash));
+}
+
+
+/* The dual of at_begline_loc_p. This one is for $. We assume there is
+ at least one character after the $, i.e., `P < PEND'. */
+
+static boolean
+at_endline_loc_p (p, pend, syntax)
+ const char *p, *pend;
+ int syntax;
+{
+ const char *next = p;
+ boolean next_backslash = *next == '\\';
+ const char *next_next = p + 1 < pend ? p + 1 : 0;
+
+ return
+ /* Before a subexpression? */
+ (syntax & RE_NO_BK_PARENS ? *next == ')'
+ : next_backslash && next_next && *next_next == ')')
+ /* Before an alternative? */
+ || (syntax & RE_NO_BK_VBAR ? *next == '|'
+ : next_backslash && next_next && *next_next == '|');
+}
+
+
+/* Returns true if REGNUM is in one of COMPILE_STACK's elements and
+ false if it's not. */
+
+static boolean
+group_in_compile_stack (compile_stack, regnum)
+ compile_stack_type compile_stack;
+ regnum_t regnum;
+{
+ int this_element;
+
+ for (this_element = compile_stack.avail - 1;
+ this_element >= 0;
+ this_element--)
+ if (compile_stack.stack[this_element].regnum == regnum)
+ return true;
+
+ return false;
+}
+
+
+/* Read the ending character of a range (in a bracket expression) from the
+ uncompiled pattern *P_PTR (which ends at PEND). We assume the
+ starting character is in `P[-2]'. (`P[-1]' is the character `-'.)
+ Then we set the translation of all bits between the starting and
+ ending characters (inclusive) in the compiled pattern B.
+
+ Return an error code.
+
+ We use these short variable names so we can use the same macros as
+ `regex_compile' itself. */
+
+static reg_errcode_t
+compile_range (p_ptr, pend, translate, syntax, b)
+ const char **p_ptr, *pend;
+ char *translate;
+ reg_syntax_t syntax;
+ unsigned char *b;
+{
+ unsigned this_char;
+
+ const char *p = *p_ptr;
+ int range_start, range_end;
+
+ if (p == pend)
+ return REG_ERANGE;
+
+ /* Even though the pattern is a signed `char *', we need to fetch
+ with unsigned char *'s; if the high bit of the pattern character
+ is set, the range endpoints will be negative if we fetch using a
+ signed char *.
+
+ We also want to fetch the endpoints without translating them; the
+ appropriate translation is done in the bit-setting loop below. */
+ /* The SVR4 compiler on the 3B2 had trouble with unsigned const char *. */
+ range_start = ((const unsigned char *) p)[-2];
+ range_end = ((const unsigned char *) p)[0];
+
+ /* Have to increment the pointer into the pattern string, so the
+ caller isn't still at the ending character. */
+ (*p_ptr)++;
+
+ /* If the start is after the end, the range is empty. */
+ if (range_start > range_end)
+ return syntax & RE_NO_EMPTY_RANGES ? REG_ERANGE : REG_NOERROR;
+
+ /* Here we see why `this_char' has to be larger than an `unsigned
+ char' -- the range is inclusive, so if `range_end' == 0xff
+ (assuming 8-bit characters), we would otherwise go into an infinite
+ loop, since all characters <= 0xff. */
+ for (this_char = range_start; this_char <= range_end; this_char++)
+ {
+ SET_LIST_BIT (TRANSLATE (this_char));
+ }
+
+ return REG_NOERROR;
+}
+\f
+/* re_compile_fastmap computes a ``fastmap'' for the compiled pattern in
+ BUFP. A fastmap records which of the (1 << BYTEWIDTH) possible
+ characters can start a string that matches the pattern. This fastmap
+ is used by re_search to skip quickly over impossible starting points.
+
+ The caller must supply the address of a (1 << BYTEWIDTH)-byte data
+ area as BUFP->fastmap.
+
+ We set the `fastmap', `fastmap_accurate', and `can_be_null' fields in
+ the pattern buffer.
+
+ Returns 0 if we succeed, -2 if an internal error. */
+
+int
+re_compile_fastmap (bufp)
+ struct re_pattern_buffer *bufp;
+{
+ int j, k;
+#ifdef MATCH_MAY_ALLOCATE
+ fail_stack_type fail_stack;
+#endif
+#ifndef REGEX_MALLOC
+ char *destination;
+#endif
+ /* We don't push any register information onto the failure stack. */
+ unsigned num_regs = 0;
+
+ register char *fastmap = bufp->fastmap;
+ unsigned char *pattern = bufp->buffer;
+ unsigned long size = bufp->used;
+ unsigned char *p = pattern;
+ register unsigned char *pend = pattern + size;
+
+#ifdef REL_ALLOC
+ /* This holds the pointer to the failure stack, when
+ it is allocated relocatably. */
+ fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+ /* Assume that each path through the pattern can be null until
+ proven otherwise. We set this false at the bottom of switch
+ statement, to which we get only if a particular path doesn't
+ match the empty string. */
+ boolean path_can_be_null = true;
+
+ /* We aren't doing a `succeed_n' to begin with. */
+ boolean succeed_n_p = false;
+
+ assert (fastmap != NULL && p != NULL);
+
+ INIT_FAIL_STACK ();
+ bzero (fastmap, 1 << BYTEWIDTH); /* Assume nothing's valid. */
+ bufp->fastmap_accurate = 1; /* It will be when we're done. */
+ bufp->can_be_null = 0;
+
+ while (1)
+ {
+ if (p == pend || *p == succeed)
+ {
+ /* We have reached the (effective) end of pattern. */
+ if (!FAIL_STACK_EMPTY ())
+ {
+ bufp->can_be_null |= path_can_be_null;
+
+ /* Reset for next path. */
+ path_can_be_null = true;
+
+ p = fail_stack.stack[--fail_stack.avail].pointer;
+
+ continue;
+ }
+ else
+ break;
+ }
+
+ /* We should never be about to go beyond the end of the pattern. */
+ assert (p < pend);
+
+ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+ {
+
+ /* I guess the idea here is to simply not bother with a fastmap
+ if a backreference is used, since it's too hard to figure out
+ the fastmap for the corresponding group. Setting
+ `can_be_null' stops `re_search_2' from using the fastmap, so
+ that is all we do. */
+ case duplicate:
+ bufp->can_be_null = 1;
+ goto done;
+
+
+ /* Following are the cases which match a character. These end
+ with `break'. */
+
+ case exactn:
+ fastmap[p[1]] = 1;
+ break;
+
+
+ case charset:
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH)))
+ fastmap[j] = 1;
+ break;
+
+
+ case charset_not:
+ /* Chars beyond end of map must be allowed. */
+ for (j = *p * BYTEWIDTH; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ for (j = *p++ * BYTEWIDTH - 1; j >= 0; j--)
+ if (!(p[j / BYTEWIDTH] & (1 << (j % BYTEWIDTH))))
+ fastmap[j] = 1;
+ break;
+
+
+ case wordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case notwordchar:
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != Sword)
+ fastmap[j] = 1;
+ break;
+
+
+ case anychar:
+ {
+ int fastmap_newline = fastmap['\n'];
+
+ /* `.' matches anything ... */
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ fastmap[j] = 1;
+
+ /* ... except perhaps newline. */
+ if (!(bufp->syntax & RE_DOT_NEWLINE))
+ fastmap['\n'] = fastmap_newline;
+
+ /* Return if we have already set `can_be_null'; if we have,
+ then the fastmap is irrelevant. Something's wrong here. */
+ else if (bufp->can_be_null)
+ goto done;
+
+ /* Otherwise, have to check alternative paths. */
+ break;
+ }
+
+#ifdef emacs
+ case syntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) == (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ case notsyntaxspec:
+ k = *p++;
+ for (j = 0; j < (1 << BYTEWIDTH); j++)
+ if (SYNTAX (j) != (enum syntaxcode) k)
+ fastmap[j] = 1;
+ break;
+
+
+ /* All cases after this match the empty string. These end with
+ `continue'. */
+
+
+ case before_dot:
+ case at_dot:
+ case after_dot:
+ continue;
+#endif /* not emacs */
+
+
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbound:
+ case notwordbound:
+ case wordbeg:
+ case wordend:
+ case push_dummy_failure:
+ continue;
+
+
+ case jump_n:
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case jump:
+ case jump_past_alt:
+ case dummy_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (j, p);
+ p += j;
+ if (j > 0)
+ continue;
+
+ /* Jump backward implies we just went through the body of a
+ loop and matched nothing. Opcode jumped to should be
+ `on_failure_jump' or `succeed_n'. Just treat it like an
+ ordinary jump. For a * loop, it has pushed its failure
+ point already; if so, discard that as redundant. */
+ if ((re_opcode_t) *p != on_failure_jump
+ && (re_opcode_t) *p != succeed_n)
+ continue;
+
+ p++;
+ EXTRACT_NUMBER_AND_INCR (j, p);
+ p += j;
+
+ /* If what's on the stack is where we are now, pop it. */
+ if (!FAIL_STACK_EMPTY ()
+ && fail_stack.stack[fail_stack.avail - 1].pointer == p)
+ fail_stack.avail--;
+
+ continue;
+
+
+ case on_failure_jump:
+ case on_failure_keep_string_jump:
+ handle_on_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (j, p);
+
+ /* For some patterns, e.g., `(a?)?', `p+j' here points to the
+ end of the pattern. We don't want to push such a point,
+ since when we restore it above, entering the switch will
+ increment `p' past the end of the pattern. We don't need
+ to push such a point since we obviously won't find any more
+ fastmap entries beyond `pend'. Such a pattern can match
+ the null string, though. */
+ if (p + j < pend)
+ {
+ if (!PUSH_PATTERN_OP (p + j, fail_stack))
+ {
+ RESET_FAIL_STACK ();
+ return -2;
+ }
+ }
+ else
+ bufp->can_be_null = 1;
+
+ if (succeed_n_p)
+ {
+ EXTRACT_NUMBER_AND_INCR (k, p); /* Skip the n. */
+ succeed_n_p = false;
+ }
+
+ continue;
+
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p += 2;
+
+ /* Increment p past the n for when k != 0. */
+ EXTRACT_NUMBER_AND_INCR (k, p);
+ if (k == 0)
+ {
+ p -= 4;
+ succeed_n_p = true; /* Spaghetti code alert. */
+ goto handle_on_failure_jump;
+ }
+ continue;
+
+
+ case set_number_at:
+ p += 4;
+ continue;
+
+
+ case start_memory:
+ case stop_memory:
+ p += 2;
+ continue;
+
+
+ default:
+ abort (); /* We have listed all the cases. */
+ } /* switch *p++ */
+
+ /* Getting here means we have found the possible starting
+ characters for one path of the pattern -- and that the empty
+ string does not match. We need not follow this path further.
+ Instead, look at the next alternative (remembered on the
+ stack), or quit if no more. The test at the top of the loop
+ does these things. */
+ path_can_be_null = false;
+ p = pend;
+ } /* while p */
+
+ /* Set `can_be_null' for the last path (also the first path, if the
+ pattern is empty). */
+ bufp->can_be_null |= path_can_be_null;
+
+ done:
+ RESET_FAIL_STACK ();
+ return 0;
+} /* re_compile_fastmap */
+\f
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using PATTERN_BUFFER and REGS will use
+ this memory for recording register information. STARTS and ENDS
+ must be allocated using the malloc library routine, and must each
+ be at least NUM_REGS * sizeof (regoff_t) bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+
+void
+re_set_registers (bufp, regs, num_regs, starts, ends)
+ struct re_pattern_buffer *bufp;
+ struct re_registers *regs;
+ unsigned num_regs;
+ regoff_t *starts, *ends;
+{
+ if (num_regs)
+ {
+ bufp->regs_allocated = REGS_REALLOCATE;
+ regs->num_regs = num_regs;
+ regs->start = starts;
+ regs->end = ends;
+ }
+ else
+ {
+ bufp->regs_allocated = REGS_UNALLOCATED;
+ regs->num_regs = 0;
+ regs->start = regs->end = (regoff_t *) 0;
+ }
+}
+\f
+/* Searching routines. */
+
+/* Like re_search_2, below, but only one string is specified, and
+ doesn't let you say where to stop matching. */
+
+int
+re_search (bufp, string, size, startpos, range, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, startpos, range;
+ struct re_registers *regs;
+{
+ return re_search_2 (bufp, NULL, 0, string, size, startpos, range,
+ regs, size);
+}
+
+
+/* Using the compiled pattern in BUFP->buffer, first tries to match the
+ virtual concatenation of STRING1 and STRING2, starting first at index
+ STARTPOS, then at STARTPOS + 1, and so on.
+
+ STRING1 and STRING2 have length SIZE1 and SIZE2, respectively.
+
+ RANGE is how far to scan while trying to match. RANGE = 0 means try
+ only at STARTPOS; in general, the last start tried is STARTPOS +
+ RANGE.
+
+ In REGS, return the indices of the virtual concatenation of STRING1
+ and STRING2 that matched the entire BUFP->buffer and its contained
+ subexpressions.
+
+ Do not consider matching one past the index STOP in the virtual
+ concatenation of STRING1 and STRING2.
+
+ We return either the position in the strings at which the match was
+ found, -1 if no match, or -2 if error (such as failure
+ stack overflow). */
+
+int
+re_search_2 (bufp, string1, size1, string2, size2, startpos, range, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int startpos;
+ int range;
+ struct re_registers *regs;
+ int stop;
+{
+ int val;
+ register char *fastmap = bufp->fastmap;
+ register char *translate = bufp->translate;
+ int total_size = size1 + size2;
+ int endpos = startpos + range;
+
+ /* Check for out-of-range STARTPOS. */
+ if (startpos < 0 || startpos > total_size)
+ return -1;
+
+ /* Fix up RANGE if it might eventually take us outside
+ the virtual concatenation of STRING1 and STRING2. */
+ if (endpos < -1)
+ range = -1 - startpos;
+ else if (endpos > total_size)
+ range = total_size - startpos;
+
+ /* If the search isn't to be a backwards one, don't waste time in a
+ search for a pattern that must be anchored. */
+ if (bufp->used > 0 && (re_opcode_t) bufp->buffer[0] == begbuf && range > 0)
+ {
+ if (startpos > 0)
+ return -1;
+ else
+ range = 1;
+ }
+
+ /* Update the fastmap now if not correct already. */
+ if (fastmap && !bufp->fastmap_accurate)
+ if (re_compile_fastmap (bufp) == -2)
+ return -2;
+
+ /* Loop through the string, looking for a place to start matching. */
+ for (;;)
+ {
+ /* If a fastmap is supplied, skip quickly over characters that
+ cannot be the start of a match. If the pattern can match the
+ null string, however, we don't need to skip characters; we want
+ the first null string. */
+ if (fastmap && startpos < total_size && !bufp->can_be_null)
+ {
+ if (range > 0) /* Searching forwards. */
+ {
+ register const char *d;
+ register int lim = 0;
+ int irange = range;
+
+ if (startpos < size1 && startpos + range >= size1)
+ lim = range - (size1 - startpos);
+
+ d = (startpos >= size1 ? string2 - size1 : string1) + startpos;
+
+ /* Written out as an if-else to avoid testing `translate'
+ inside the loop. */
+ if (translate)
+ while (range > lim
+ && !fastmap[(unsigned char)
+ translate[(unsigned char) *d++]])
+ range--;
+ else
+ while (range > lim && !fastmap[(unsigned char) *d++])
+ range--;
+
+ startpos += irange - range;
+ }
+ else /* Searching backwards. */
+ {
+ register char c = (size1 == 0 || startpos >= size1
+ ? string2[startpos - size1]
+ : string1[startpos]);
+
+ if (!fastmap[(unsigned char) TRANSLATE (c)])
+ goto advance;
+ }
+ }
+
+ /* If can't match the null string, and that's all we have left, fail. */
+ if (range >= 0 && startpos == total_size && fastmap
+ && !bufp->can_be_null)
+ return -1;
+
+ val = re_match_2_internal (bufp, string1, size1, string2, size2,
+ startpos, regs, stop);
+#ifndef REGEX_MALLOC
+#ifdef C_ALLOCA
+ alloca (0);
+#endif
+#endif
+
+ if (val >= 0)
+ return startpos;
+
+ if (val == -2)
+ return -2;
+
+ advance:
+ if (!range)
+ break;
+ else if (range > 0)
+ {
+ range--;
+ startpos++;
+ }
+ else
+ {
+ range++;
+ startpos--;
+ }
+ }
+ return -1;
+} /* re_search_2 */
+\f
+/* Declarations and macros for re_match_2. */
+
+static int bcmp_translate ();
+static boolean alt_match_null_string_p (),
+ common_op_match_null_string_p (),
+ group_match_null_string_p ();
+
+/* This converts PTR, a pointer into one of the search strings `string1'
+ and `string2' into an offset from the beginning of that string. */
+#define POINTER_TO_OFFSET(ptr) \
+ (FIRST_STRING_P (ptr) \
+ ? ((regoff_t) ((ptr) - string1)) \
+ : ((regoff_t) ((ptr) - string2 + size1)))
+
+/* Macros for dealing with the split strings in re_match_2. */
+
+#define MATCHING_IN_FIRST_STRING (dend == end_match_1)
+
+/* Call before fetching a character with *d. This switches over to
+ string2 if necessary. */
+#define PREFETCH() \
+ while (d == dend) \
+ { \
+ /* End of string2 => fail. */ \
+ if (dend == end_match_2) \
+ goto fail; \
+ /* End of string1 => advance to string2. */ \
+ d = string2; \
+ dend = end_match_2; \
+ }
+
+
+/* Test if at very beginning or at very end of the virtual concatenation
+ of `string1' and `string2'. If only one string, it's `string2'. */
+#define AT_STRINGS_BEG(d) ((d) == (size1 ? string1 : string2) || !size2)
+#define AT_STRINGS_END(d) ((d) == end2)
+
+
+/* Test if D points to a character which is word-constituent. We have
+ two special cases to check for: if past the end of string1, look at
+ the first character in string2; and if before the beginning of
+ string2, look at the last character in string1. */
+#define WORDCHAR_P(d) \
+ (SYNTAX ((d) == end1 ? *string2 \
+ : (d) == string2 - 1 ? *(end1 - 1) : *(d)) \
+ == Sword)
+
+/* Test if the character before D and the one at D differ with respect
+ to being word-constituent. */
+#define AT_WORD_BOUNDARY(d) \
+ (AT_STRINGS_BEG (d) || AT_STRINGS_END (d) \
+ || WORDCHAR_P (d - 1) != WORDCHAR_P (d))
+
+
+/* Free everything we malloc. */
+#ifdef MATCH_MAY_ALLOCATE
+#define FREE_VAR(var) if (var) REGEX_FREE (var); var = NULL
+#define FREE_VARIABLES() \
+ do { \
+ REGEX_FREE_STACK (fail_stack.stack); \
+ FREE_VAR (regstart); \
+ FREE_VAR (regend); \
+ FREE_VAR (old_regstart); \
+ FREE_VAR (old_regend); \
+ FREE_VAR (best_regstart); \
+ FREE_VAR (best_regend); \
+ FREE_VAR (reg_info); \
+ FREE_VAR (reg_dummy); \
+ FREE_VAR (reg_info_dummy); \
+ } while (0)
+#else
+#define FREE_VARIABLES() ((void)0) /* Do nothing! But inhibit gcc warning. */
+#endif /* not MATCH_MAY_ALLOCATE */
+
+/* These values must meet several constraints. They must not be valid
+ register values; since we have a limit of 255 registers (because
+ we use only one byte in the pattern for the register number), we can
+ use numbers larger than 255. They must differ by 1, because of
+ NUM_FAILURE_ITEMS above. And the value for the lowest register must
+ be larger than the value for the highest register, so we do not try
+ to actually save any registers when none are active. */
+#define NO_HIGHEST_ACTIVE_REG (1 << BYTEWIDTH)
+#define NO_LOWEST_ACTIVE_REG (NO_HIGHEST_ACTIVE_REG + 1)
+\f
+/* Matching routines. */
+
+#ifndef emacs /* Emacs never uses this. */
+/* re_match is like re_match_2 except it takes only a single string. */
+
+int
+re_match (bufp, string, size, pos, regs)
+ struct re_pattern_buffer *bufp;
+ const char *string;
+ int size, pos;
+ struct re_registers *regs;
+{
+ int result = re_match_2_internal (bufp, NULL, 0, string, size,
+ pos, regs, size);
+#ifndef REGEX_MALLOC
+ alloca (0);
+#endif
+ return result;
+}
+#endif /* not emacs */
+
+
+/* re_match_2 matches the compiled pattern in BUFP against the
+ the (virtual) concatenation of STRING1 and STRING2 (of length SIZE1
+ and SIZE2, respectively). We start matching at POS, and stop
+ matching at STOP.
+
+ If REGS is non-null and the `no_sub' field of BUFP is nonzero, we
+ store offsets for the substring each group matched in REGS. See the
+ documentation for exactly how many groups we fill.
+
+ We return -1 if no match, -2 if an internal error (such as the
+ failure stack overflowing). Otherwise, we return the length of the
+ matched substring. */
+
+int
+re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int stop;
+{
+ int result = re_match_2_internal (bufp, string1, size1, string2, size2,
+ pos, regs, stop);
+#ifndef REGEX_MALLOC
+ alloca (0);
+#endif
+ return result;
+}
+
+/* This is a separate function so that we can force an alloca cleanup
+ afterwards. */
+static int
+re_match_2_internal (bufp, string1, size1, string2, size2, pos, regs, stop)
+ struct re_pattern_buffer *bufp;
+ const char *string1, *string2;
+ int size1, size2;
+ int pos;
+ struct re_registers *regs;
+ int stop;
+{
+ /* General temporaries. */
+ int mcnt;
+ unsigned char *p1;
+
+ /* Just past the end of the corresponding string. */
+ const char *end1, *end2;
+
+ /* Pointers into string1 and string2, just past the last characters in
+ each to consider matching. */
+ const char *end_match_1, *end_match_2;
+
+ /* Where we are in the data, and the end of the current string. */
+ const char *d, *dend;
+
+ /* Where we are in the pattern, and the end of the pattern. */
+ unsigned char *p = bufp->buffer;
+ register unsigned char *pend = p + bufp->used;
+
+ /* Mark the opcode just after a start_memory, so we can test for an
+ empty subpattern when we get to the stop_memory. */
+ unsigned char *just_past_start_mem = 0;
+
+ /* We use this to map every character in the string. */
+ char *translate = bufp->translate;
+
+ /* Failure point stack. Each place that can handle a failure further
+ down the line pushes a failure point on this stack. It consists of
+ restart, regend, and reg_info for all registers corresponding to
+ the subexpressions we're currently inside, plus the number of such
+ registers, and, finally, two char *'s. The first char * is where
+ to resume scanning the pattern; the second one is where to resume
+ scanning the strings. If the latter is zero, the failure point is
+ a ``dummy''; if a failure happens and the failure point is a dummy,
+ it gets discarded and the next next one is tried. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ fail_stack_type fail_stack;
+#endif
+#ifdef DEBUG
+ static unsigned failure_id = 0;
+ unsigned nfailure_points_pushed = 0, nfailure_points_popped = 0;
+#endif
+
+#ifdef REL_ALLOC
+ /* This holds the pointer to the failure stack, when
+ it is allocated relocatably. */
+ fail_stack_elt_t *failure_stack_ptr;
+#endif
+
+ /* We fill all the registers internally, independent of what we
+ return, for use in backreferences. The number here includes
+ an element for register zero. */
+ unsigned num_regs = bufp->re_nsub + 1;
+
+ /* The currently active registers. */
+ unsigned lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ unsigned highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+
+ /* Information on the contents of registers. These are pointers into
+ the input strings; they record just what was matched (on this
+ attempt) by a subexpression part of the pattern, that is, the
+ regnum-th regstart pointer points to where in the pattern we began
+ matching and the regnum-th regend points to right after where we
+ stopped matching the regnum-th subexpression. (The zeroth register
+ keeps track of what the whole pattern matches.) */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **regstart, **regend;
+#endif
+
+ /* If a group that's operated upon by a repetition operator fails to
+ match anything, then the register for its start will need to be
+ restored because it will have been set to wherever in the string we
+ are when we last see its open-group operator. Similarly for a
+ register's end. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **old_regstart, **old_regend;
+#endif
+
+ /* The is_active field of reg_info helps us keep track of which (possibly
+ nested) subexpressions we are currently in. The matched_something
+ field of reg_info[reg_num] helps us tell whether or not we have
+ matched any of the pattern so far this time through the reg_num-th
+ subexpression. These two fields get reset each time through any
+ loop their register is in. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, this is global. */
+ register_info_type *reg_info;
+#endif
+
+ /* The following record the register info as found in the above
+ variables when we find a match better than any we've seen before.
+ This happens as we backtrack through the failure points, which in
+ turn happens only if we have not yet matched the entire string. */
+ unsigned best_regs_set = false;
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **best_regstart, **best_regend;
+#endif
+
+ /* Logically, this is `best_regend[0]'. But we don't want to have to
+ allocate space for that if we're not allocating space for anything
+ else (see below). Also, we never need info about register 0 for
+ any of the other register vectors, and it seems rather a kludge to
+ treat `best_regend' differently than the rest. So we keep track of
+ the end of the best match so far in a separate variable. We
+ initialize this to NULL so that when we backtrack the first time
+ and need to test it, it's not garbage. */
+ const char *match_end = NULL;
+
+ /* This helps SET_REGS_MATCHED avoid doing redundant work. */
+ int set_regs_matched_done = 0;
+
+ /* Used when we pop values we don't care about. */
+#ifdef MATCH_MAY_ALLOCATE /* otherwise, these are global. */
+ const char **reg_dummy;
+ register_info_type *reg_info_dummy;
+#endif
+
+#ifdef DEBUG
+ /* Counts the total number of registers pushed. */
+ unsigned num_regs_pushed = 0;
+#endif
+
+ DEBUG_PRINT1 ("\n\nEntering re_match_2.\n");
+
+ INIT_FAIL_STACK ();
+
+#ifdef MATCH_MAY_ALLOCATE
+ /* Do not bother to initialize all the register variables if there are
+ no groups in the pattern, as it takes a fair amount of time. If
+ there are groups, we include space for register 0 (the whole
+ pattern), even though we never use it, since it simplifies the
+ array indexing. We should fix this. */
+ if (bufp->re_nsub)
+ {
+ regstart = REGEX_TALLOC (num_regs, const char *);
+ regend = REGEX_TALLOC (num_regs, const char *);
+ old_regstart = REGEX_TALLOC (num_regs, const char *);
+ old_regend = REGEX_TALLOC (num_regs, const char *);
+ best_regstart = REGEX_TALLOC (num_regs, const char *);
+ best_regend = REGEX_TALLOC (num_regs, const char *);
+ reg_info = REGEX_TALLOC (num_regs, register_info_type);
+ reg_dummy = REGEX_TALLOC (num_regs, const char *);
+ reg_info_dummy = REGEX_TALLOC (num_regs, register_info_type);
+
+ if (!(regstart && regend && old_regstart && old_regend && reg_info
+ && best_regstart && best_regend && reg_dummy && reg_info_dummy))
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ }
+ else
+ {
+ /* We must initialize all our variables to NULL, so that
+ `FREE_VARIABLES' doesn't try to free them. */
+ regstart = regend = old_regstart = old_regend = best_regstart
+ = best_regend = reg_dummy = NULL;
+ reg_info = reg_info_dummy = (register_info_type *) NULL;
+ }
+#endif /* MATCH_MAY_ALLOCATE */
+
+ /* The starting position is bogus. */
+ if (pos < 0 || pos > size1 + size2)
+ {
+ FREE_VARIABLES ();
+ return -1;
+ }
+
+ /* Initialize subexpression text positions to -1 to mark ones that no
+ start_memory/stop_memory has been seen for. Also initialize the
+ register information struct. */
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
+ {
+ regstart[mcnt] = regend[mcnt]
+ = old_regstart[mcnt] = old_regend[mcnt] = REG_UNSET_VALUE;
+
+ REG_MATCH_NULL_STRING_P (reg_info[mcnt]) = MATCH_NULL_UNSET_VALUE;
+ IS_ACTIVE (reg_info[mcnt]) = 0;
+ MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ EVER_MATCHED_SOMETHING (reg_info[mcnt]) = 0;
+ }
+
+ /* We move `string1' into `string2' if the latter's empty -- but not if
+ `string1' is null. */
+ if (size2 == 0 && string1 != NULL)
+ {
+ string2 = string1;
+ size2 = size1;
+ string1 = 0;
+ size1 = 0;
+ }
+ end1 = string1 + size1;
+ end2 = string2 + size2;
+
+ /* Compute where to stop matching, within the two strings. */
+ if (stop <= size1)
+ {
+ end_match_1 = string1 + stop;
+ end_match_2 = string2;
+ }
+ else
+ {
+ end_match_1 = end1;
+ end_match_2 = string2 + stop - size1;
+ }
+
+ /* `p' scans through the pattern as `d' scans through the data.
+ `dend' is the end of the input string that `d' points within. `d'
+ is advanced into the following input string whenever necessary, but
+ this happens before fetching; therefore, at the beginning of the
+ loop, `d' can be pointing at the end of a string, but it cannot
+ equal `string2'. */
+ if (size1 > 0 && pos <= size1)
+ {
+ d = string1 + pos;
+ dend = end_match_1;
+ }
+ else
+ {
+ d = string2 + pos - size1;
+ dend = end_match_2;
+ }
+
+ DEBUG_PRINT1 ("The compiled pattern is: ");
+ DEBUG_PRINT_COMPILED_PATTERN (bufp, p, pend);
+ DEBUG_PRINT1 ("The string to match is: `");
+ DEBUG_PRINT_DOUBLE_STRING (d, string1, size1, string2, size2);
+ DEBUG_PRINT1 ("'\n");
+
+ /* This loops over pattern commands. It exits by returning from the
+ function if the match is complete, or it drops through if the match
+ fails at this starting point in the input data. */
+ for (;;)
+ {
+ DEBUG_PRINT2 ("\n0x%x: ", p);
+
+ if (p == pend)
+ { /* End of pattern means we might have succeeded. */
+ DEBUG_PRINT1 ("end of pattern ... ");
+
+ /* If we haven't matched the entire string, and we want the
+ longest match, try backtracking. */
+ if (d != end_match_2)
+ {
+ /* 1 if this match ends in the same string (string1 or string2)
+ as the best previous match. */
+ boolean same_str_p = (FIRST_STRING_P (match_end)
+ == MATCHING_IN_FIRST_STRING);
+ /* 1 if this match is the best seen so far. */
+ boolean best_match_p;
+
+ /* AIX compiler got confused when this was combined
+ with the previous declaration. */
+ if (same_str_p)
+ best_match_p = d > match_end;
+ else
+ best_match_p = !MATCHING_IN_FIRST_STRING;
+
+ DEBUG_PRINT1 ("backtracking.\n");
+
+ if (!FAIL_STACK_EMPTY ())
+ { /* More failure points to try. */
+
+ /* If exceeds best match so far, save it. */
+ if (!best_regs_set || best_match_p)
+ {
+ best_regs_set = true;
+ match_end = d;
+
+ DEBUG_PRINT1 ("\nSAVING match as best so far.\n");
+
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
+ {
+ best_regstart[mcnt] = regstart[mcnt];
+ best_regend[mcnt] = regend[mcnt];
+ }
+ }
+ goto fail;
+ }
+
+ /* If no failure points, don't restore garbage. And if
+ last match is real best match, don't restore second
+ best one. */
+ else if (best_regs_set && !best_match_p)
+ {
+ restore_best_regs:
+ /* Restore best match. It may happen that `dend ==
+ end_match_1' while the restored d is in string2.
+ For example, the pattern `x.*y.*z' against the
+ strings `x-' and `y-z-', if the two strings are
+ not consecutive in memory. */
+ DEBUG_PRINT1 ("Restoring best registers.\n");
+
+ d = match_end;
+ dend = ((d >= string1 && d <= end1)
+ ? end_match_1 : end_match_2);
+
+ for (mcnt = 1; mcnt < num_regs; mcnt++)
+ {
+ regstart[mcnt] = best_regstart[mcnt];
+ regend[mcnt] = best_regend[mcnt];
+ }
+ }
+ } /* d != end_match_2 */
+
+ succeed_label:
+ DEBUG_PRINT1 ("Accepting match.\n");
+
+ /* If caller wants register contents data back, do it. */
+ if (regs && !bufp->no_sub)
+ {
+ /* Have the register data arrays been allocated? */
+ if (bufp->regs_allocated == REGS_UNALLOCATED)
+ { /* No. So allocate them with malloc. We need one
+ extra element beyond `num_regs' for the `-1' marker
+ GNU code uses. */
+ regs->num_regs = MAX (RE_NREGS, num_regs + 1);
+ regs->start = TALLOC (regs->num_regs, regoff_t);
+ regs->end = TALLOC (regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ bufp->regs_allocated = REGS_REALLOCATE;
+ }
+ else if (bufp->regs_allocated == REGS_REALLOCATE)
+ { /* Yes. If we need more elements than were already
+ allocated, reallocate them. If we need fewer, just
+ leave it alone. */
+ if (regs->num_regs < num_regs + 1)
+ {
+ regs->num_regs = num_regs + 1;
+ RETALLOC (regs->start, regs->num_regs, regoff_t);
+ RETALLOC (regs->end, regs->num_regs, regoff_t);
+ if (regs->start == NULL || regs->end == NULL)
+ {
+ FREE_VARIABLES ();
+ return -2;
+ }
+ }
+ }
+ else
+ {
+ /* These braces fend off a "empty body in an else-statement"
+ warning under GCC when assert expands to nothing. */
+ assert (bufp->regs_allocated == REGS_FIXED);
+ }
+
+ /* Convert the pointer data in `regstart' and `regend' to
+ indices. Register zero has to be set differently,
+ since we haven't kept track of any info for it. */
+ if (regs->num_regs > 0)
+ {
+ regs->start[0] = pos;
+ regs->end[0] = (MATCHING_IN_FIRST_STRING
+ ? ((regoff_t) (d - string1))
+ : ((regoff_t) (d - string2 + size1)));
+ }
+
+ /* Go through the first `min (num_regs, regs->num_regs)'
+ registers, since that is all we initialized. */
+ for (mcnt = 1; mcnt < MIN (num_regs, regs->num_regs); mcnt++)
+ {
+ if (REG_UNSET (regstart[mcnt]) || REG_UNSET (regend[mcnt]))
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ else
+ {
+ regs->start[mcnt]
+ = (regoff_t) POINTER_TO_OFFSET (regstart[mcnt]);
+ regs->end[mcnt]
+ = (regoff_t) POINTER_TO_OFFSET (regend[mcnt]);
+ }
+ }
+
+ /* If the regs structure we return has more elements than
+ were in the pattern, set the extra elements to -1. If
+ we (re)allocated the registers, this is the case,
+ because we always allocate enough to have at least one
+ -1 at the end. */
+ for (mcnt = num_regs; mcnt < regs->num_regs; mcnt++)
+ regs->start[mcnt] = regs->end[mcnt] = -1;
+ } /* regs && !bufp->no_sub */
+
+ DEBUG_PRINT4 ("%u failure points pushed, %u popped (%u remain).\n",
+ nfailure_points_pushed, nfailure_points_popped,
+ nfailure_points_pushed - nfailure_points_popped);
+ DEBUG_PRINT2 ("%u registers pushed.\n", num_regs_pushed);
+
+ mcnt = d - pos - (MATCHING_IN_FIRST_STRING
+ ? string1
+ : string2 - size1);
+
+ DEBUG_PRINT2 ("Returning %d from re_match_2.\n", mcnt);
+
+ FREE_VARIABLES ();
+ return mcnt;
+ }
+
+ /* Otherwise match next pattern command. */
+ switch (SWITCH_ENUM_CAST ((re_opcode_t) *p++))
+ {
+ /* Ignore these. Used to ignore the n of succeed_n's which
+ currently have n == 0. */
+ case no_op:
+ DEBUG_PRINT1 ("EXECUTING no_op.\n");
+ break;
+
+ case succeed:
+ DEBUG_PRINT1 ("EXECUTING succeed.\n");
+ goto succeed_label;
+
+ /* Match the next n pattern characters exactly. The following
+ byte in the pattern defines n, and the n bytes after that
+ are the characters to match. */
+ case exactn:
+ mcnt = *p++;
+ DEBUG_PRINT2 ("EXECUTING exactn %d.\n", mcnt);
+
+ /* This is written out as an if-else so we don't waste time
+ testing `translate' inside the loop. */
+ if (translate)
+ {
+ do
+ {
+ PREFETCH ();
+ if (translate[(unsigned char) *d++] != (char) *p++)
+ goto fail;
+ }
+ while (--mcnt);
+ }
+ else
+ {
+ do
+ {
+ PREFETCH ();
+ if (*d++ != (char) *p++) goto fail;
+ }
+ while (--mcnt);
+ }
+ SET_REGS_MATCHED ();
+ break;
+
+
+ /* Match any character except possibly a newline or a null. */
+ case anychar:
+ DEBUG_PRINT1 ("EXECUTING anychar.\n");
+
+ PREFETCH ();
+
+ if ((!(bufp->syntax & RE_DOT_NEWLINE) && TRANSLATE (*d) == '\n')
+ || (bufp->syntax & RE_DOT_NOT_NULL && TRANSLATE (*d) == '\000'))
+ goto fail;
+
+ SET_REGS_MATCHED ();
+ DEBUG_PRINT2 (" Matched `%d'.\n", *d);
+ d++;
+ break;
+
+
+ case charset:
+ case charset_not:
+ {
+ register unsigned char c;
+ boolean not = (re_opcode_t) *(p - 1) == charset_not;
+
+ DEBUG_PRINT2 ("EXECUTING charset%s.\n", not ? "_not" : "");
+
+ PREFETCH ();
+ c = TRANSLATE (*d); /* The character to match. */
+
+ /* Cast to `unsigned' instead of `unsigned char' in case the
+ bit list is a full 32 bytes long. */
+ if (c < (unsigned) (*p * BYTEWIDTH)
+ && p[1 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ p += 1 + *p;
+
+ if (!not) goto fail;
+
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+ }
+
+
+ /* The beginning of a group is represented by start_memory.
+ The arguments are the register number in the next byte, and the
+ number of groups inner to this one in the next. The text
+ matched within the group is recorded (in the internal
+ registers data structure) under the register number. */
+ case start_memory:
+ DEBUG_PRINT3 ("EXECUTING start_memory %d (%d):\n", *p, p[1]);
+
+ /* Find out if this group can match the empty string. */
+ p1 = p; /* To send to group_match_null_string_p. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[*p]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[*p])
+ = group_match_null_string_p (&p1, pend, reg_info);
+
+ /* Save the position in the string where we were the last time
+ we were at this open-group operator in case the group is
+ operated upon by a repetition operator, e.g., with `(a*)*b'
+ against `ab'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regstart[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regstart[*p]) ? d : regstart[*p]
+ : regstart[*p];
+ DEBUG_PRINT2 (" old_regstart: %d\n",
+ POINTER_TO_OFFSET (old_regstart[*p]));
+
+ regstart[*p] = d;
+ DEBUG_PRINT2 (" regstart: %d\n", POINTER_TO_OFFSET (regstart[*p]));
+
+ IS_ACTIVE (reg_info[*p]) = 1;
+ MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* Clear this whenever we change the register activity status. */
+ set_regs_matched_done = 0;
+
+ /* This is the new highest active register. */
+ highest_active_reg = *p;
+
+ /* If nothing was active before, this is the new lowest active
+ register. */
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *p;
+
+ /* Move past the register number and inner group count. */
+ p += 2;
+ just_past_start_mem = p;
+
+ break;
+
+
+ /* The stop_memory opcode represents the end of a group. Its
+ arguments are the same as start_memory's: the register
+ number, and the number of inner groups. */
+ case stop_memory:
+ DEBUG_PRINT3 ("EXECUTING stop_memory %d (%d):\n", *p, p[1]);
+
+ /* We need to save the string position the last time we were at
+ this close-group operator in case the group is operated
+ upon by a repetition operator, e.g., with `((a*)*(b*)*)*'
+ against `aba'; then we want to ignore where we are now in
+ the string in case this attempt to match fails. */
+ old_regend[*p] = REG_MATCH_NULL_STRING_P (reg_info[*p])
+ ? REG_UNSET (regend[*p]) ? d : regend[*p]
+ : regend[*p];
+ DEBUG_PRINT2 (" old_regend: %d\n",
+ POINTER_TO_OFFSET (old_regend[*p]));
+
+ regend[*p] = d;
+ DEBUG_PRINT2 (" regend: %d\n", POINTER_TO_OFFSET (regend[*p]));
+
+ /* This register isn't active anymore. */
+ IS_ACTIVE (reg_info[*p]) = 0;
+
+ /* Clear this whenever we change the register activity status. */
+ set_regs_matched_done = 0;
+
+ /* If this was the only register active, nothing is active
+ anymore. */
+ if (lowest_active_reg == highest_active_reg)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ { /* We must scan for the new highest active register, since
+ it isn't necessarily one less than now: consider
+ (a(b)c(d(e)f)g). When group 3 ends, after the f), the
+ new highest active register is 1. */
+ unsigned char r = *p - 1;
+ while (r > 0 && !IS_ACTIVE (reg_info[r]))
+ r--;
+
+ /* If we end up at register zero, that means that we saved
+ the registers as the result of an `on_failure_jump', not
+ a `start_memory', and we jumped to past the innermost
+ `stop_memory'. For example, in ((.)*) we save
+ registers 1 and 2 as a result of the *, but when we pop
+ back to the second ), we are at the stop_memory 1.
+ Thus, nothing is active. */
+ if (r == 0)
+ {
+ lowest_active_reg = NO_LOWEST_ACTIVE_REG;
+ highest_active_reg = NO_HIGHEST_ACTIVE_REG;
+ }
+ else
+ highest_active_reg = r;
+ }
+
+ /* If just failed to match something this time around with a
+ group that's operated on by a repetition operator, try to
+ force exit from the ``loop'', and restore the register
+ information for this group that we had before trying this
+ last match. */
+ if ((!MATCHED_SOMETHING (reg_info[*p])
+ || just_past_start_mem == p - 1)
+ && (p + 2) < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ p1 = p + 2;
+ mcnt = 0;
+ switch ((re_opcode_t) *p1++)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case pop_failure_jump:
+ case maybe_pop_jump:
+ case jump:
+ case dummy_failure_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (is_a_jump_n)
+ p1 += 2;
+ break;
+
+ default:
+ /* do nothing */ ;
+ }
+ p1 += mcnt;
+
+ /* If the next operation is a jump backwards in the pattern
+ to an on_failure_jump right before the start_memory
+ corresponding to this stop_memory, exit from the loop
+ by forcing a failure after pushing on the stack the
+ on_failure_jump's jump in the pattern, and d. */
+ if (mcnt < 0 && (re_opcode_t) *p1 == on_failure_jump
+ && (re_opcode_t) p1[3] == start_memory && p1[4] == *p)
+ {
+ /* If this group ever matched anything, then restore
+ what its registers were before trying this last
+ failed match, e.g., with `(a*)*b' against `ab' for
+ regstart[1], and, e.g., with `((a*)*(b*)*)*'
+ against `aba' for regend[3].
+
+ Also restore the registers for inner groups for,
+ e.g., `((a*)(b*))*' against `aba' (register 3 would
+ otherwise get trashed). */
+
+ if (EVER_MATCHED_SOMETHING (reg_info[*p]))
+ {
+ unsigned r;
+
+ EVER_MATCHED_SOMETHING (reg_info[*p]) = 0;
+
+ /* Restore this and inner groups' (if any) registers. */
+ for (r = *p; r < *p + *(p + 1); r++)
+ {
+ regstart[r] = old_regstart[r];
+
+ /* xx why this test? */
+ if (old_regend[r] >= regstart[r])
+ regend[r] = old_regend[r];
+ }
+ }
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ PUSH_FAILURE_POINT (p1 + mcnt, d, -2);
+
+ goto fail;
+ }
+ }
+
+ /* Move past the register number and the inner group count. */
+ p += 2;
+ break;
+
+
+ /* \<digit> has been turned into a `duplicate' command which is
+ followed by the numeric value of <digit> as the register number. */
+ case duplicate:
+ {
+ register const char *d2, *dend2;
+ int regno = *p++; /* Get which register to match against. */
+ DEBUG_PRINT2 ("EXECUTING duplicate %d.\n", regno);
+
+ /* Can't back reference a group which we've never matched. */
+ if (REG_UNSET (regstart[regno]) || REG_UNSET (regend[regno]))
+ goto fail;
+
+ /* Where in input to try to start matching. */
+ d2 = regstart[regno];
+
+ /* Where to stop matching; if both the place to start and
+ the place to stop matching are in the same string, then
+ set to the place to stop, otherwise, for now have to use
+ the end of the first string. */
+
+ dend2 = ((FIRST_STRING_P (regstart[regno])
+ == FIRST_STRING_P (regend[regno]))
+ ? regend[regno] : end_match_1);
+ for (;;)
+ {
+ /* If necessary, advance to next segment in register
+ contents. */
+ while (d2 == dend2)
+ {
+ if (dend2 == end_match_2) break;
+ if (dend2 == regend[regno]) break;
+
+ /* End of string1 => advance to string2. */
+ d2 = string2;
+ dend2 = regend[regno];
+ }
+ /* At end of register contents => success */
+ if (d2 == dend2) break;
+
+ /* If necessary, advance to next segment in data. */
+ PREFETCH ();
+
+ /* How many characters left in this segment to match. */
+ mcnt = dend - d;
+
+ /* Want how many consecutive characters we can match in
+ one shot, so, if necessary, adjust the count. */
+ if (mcnt > dend2 - d2)
+ mcnt = dend2 - d2;
+
+ /* Compare that many; failure if mismatch, else move
+ past them. */
+ if (translate
+ ? bcmp_translate (d, d2, mcnt, translate)
+ : bcmp (d, d2, mcnt))
+ goto fail;
+ d += mcnt, d2 += mcnt;
+
+ /* Do this because we've match some characters. */
+ SET_REGS_MATCHED ();
+ }
+ }
+ break;
+
+
+ /* begline matches the empty string at the beginning of the string
+ (unless `not_bol' is set in `bufp'), and, if
+ `newline_anchor' is set, after newlines. */
+ case begline:
+ DEBUG_PRINT1 ("EXECUTING begline.\n");
+
+ if (AT_STRINGS_BEG (d))
+ {
+ if (!bufp->not_bol) break;
+ }
+ else if (d[-1] == '\n' && bufp->newline_anchor)
+ {
+ break;
+ }
+ /* In all other cases, we fail. */
+ goto fail;
+
+
+ /* endline is the dual of begline. */
+ case endline:
+ DEBUG_PRINT1 ("EXECUTING endline.\n");
+
+ if (AT_STRINGS_END (d))
+ {
+ if (!bufp->not_eol) break;
+ }
+
+ /* We have to ``prefetch'' the next character. */
+ else if ((d == end1 ? *string2 : *d) == '\n'
+ && bufp->newline_anchor)
+ {
+ break;
+ }
+ goto fail;
+
+
+ /* Match at the very beginning of the data. */
+ case begbuf:
+ DEBUG_PRINT1 ("EXECUTING begbuf.\n");
+ if (AT_STRINGS_BEG (d))
+ break;
+ goto fail;
+
+
+ /* Match at the very end of the data. */
+ case endbuf:
+ DEBUG_PRINT1 ("EXECUTING endbuf.\n");
+ if (AT_STRINGS_END (d))
+ break;
+ goto fail;
+
+
+ /* on_failure_keep_string_jump is used to optimize `.*\n'. It
+ pushes NULL as the value for the string on the stack. Then
+ `pop_failure_point' will keep the current value for the
+ string, instead of restoring it. To see why, consider
+ matching `foo\nbar' against `.*\n'. The .* matches the foo;
+ then the . fails against the \n. But the next thing we want
+ to do is match the \n against the \n; if we restored the
+ string value, we would be back at the foo.
+
+ Because this is used only in specific cases, we don't need to
+ check all the things that `on_failure_jump' does, to make
+ sure the right things get saved on the stack. Hence we don't
+ share its code. The only reason to push anything on the
+ stack at all is that otherwise we would have to change
+ `anychar's code to do something besides goto fail in this
+ case; that seems worse than this. */
+ case on_failure_keep_string_jump:
+ DEBUG_PRINT1 ("EXECUTING on_failure_keep_string_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x):\n", mcnt, p + mcnt);
+
+ PUSH_FAILURE_POINT (p + mcnt, NULL, -2);
+ break;
+
+
+ /* Uses of on_failure_jump:
+
+ Each alternative starts with an on_failure_jump that points
+ to the beginning of the next alternative. Each alternative
+ except the last ends with a jump that in effect jumps past
+ the rest of the alternatives. (They really jump to the
+ ending jump of the following alternative, because tensioning
+ these jumps is a hassle.)
+
+ Repeats start with an on_failure_jump that points past both
+ the repetition text and either the following jump or
+ pop_failure_jump back to this on_failure_jump. */
+ case on_failure_jump:
+ on_failure:
+ DEBUG_PRINT1 ("EXECUTING on_failure_jump");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" %d (to 0x%x)", mcnt, p + mcnt);
+
+ /* If this on_failure_jump comes right before a group (i.e.,
+ the original * applied to a group), save the information
+ for that group and all inner ones, so that if we fail back
+ to this point, the group's information will be correct.
+ For example, in \(a*\)*\1, we need the preceding group,
+ and in \(\(a*\)b*\)\2, we need the inner group. */
+
+ /* We can't use `p' to check ahead because we push
+ a failure point to `p + mcnt' after we do this. */
+ p1 = p;
+
+ /* We need to skip no_op's before we look for the
+ start_memory in case this on_failure_jump is happening as
+ the result of a completed succeed_n, as in \(a\)\{1,3\}b\1
+ against aba. */
+ while (p1 < pend && (re_opcode_t) *p1 == no_op)
+ p1++;
+
+ if (p1 < pend && (re_opcode_t) *p1 == start_memory)
+ {
+ /* We have a new highest active register now. This will
+ get reset at the start_memory we are about to get to,
+ but we will have saved all the registers relevant to
+ this repetition op, as described above. */
+ highest_active_reg = *(p1 + 1) + *(p1 + 2);
+ if (lowest_active_reg == NO_LOWEST_ACTIVE_REG)
+ lowest_active_reg = *(p1 + 1);
+ }
+
+ DEBUG_PRINT1 (":\n");
+ PUSH_FAILURE_POINT (p + mcnt, d, -2);
+ break;
+
+
+ /* A smart repeat ends with `maybe_pop_jump'.
+ We change it to either `pop_failure_jump' or `jump'. */
+ case maybe_pop_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT2 ("EXECUTING maybe_pop_jump %d.\n", mcnt);
+ {
+ register unsigned char *p2 = p;
+
+ /* Compare the beginning of the repeat with what in the
+ pattern follows its end. If we can establish that there
+ is nothing that they would both match, i.e., that we
+ would have to backtrack because of (as in, e.g., `a*a')
+ then we can change to pop_failure_jump, because we'll
+ never have to backtrack.
+
+ This is not true in the case of alternatives: in
+ `(a|ab)*' we do need to backtrack to the `ab' alternative
+ (e.g., if the string was `ab'). But instead of trying to
+ detect that here, the alternative has put on a dummy
+ failure point which is what we will end up popping. */
+
+ /* Skip over open/close-group commands.
+ If what follows this loop is a ...+ construct,
+ look at what begins its body, since we will have to
+ match at least one of that. */
+ while (1)
+ {
+ if (p2 + 2 < pend
+ && ((re_opcode_t) *p2 == stop_memory
+ || (re_opcode_t) *p2 == start_memory))
+ p2 += 3;
+ else if (p2 + 6 < pend
+ && (re_opcode_t) *p2 == dummy_failure_jump)
+ p2 += 6;
+ else
+ break;
+ }
+
+ p1 = p + mcnt;
+ /* p1[0] ... p1[2] are the `on_failure_jump' corresponding
+ to the `maybe_finalize_jump' of this case. Examine what
+ follows. */
+
+ /* If we're at the end of the pattern, we can change. */
+ if (p2 == pend)
+ {
+ /* Consider what happens when matching ":\(.*\)"
+ against ":/". I don't really understand this code
+ yet. */
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1
+ (" End of pattern: change to `pop_failure_jump'.\n");
+ }
+
+ else if ((re_opcode_t) *p2 == exactn
+ || (bufp->newline_anchor && (re_opcode_t) *p2 == endline))
+ {
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+
+ if ((re_opcode_t) p1[3] == exactn && p1[5] != c)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset
+ || (re_opcode_t) p1[3] == charset_not)
+ {
+ int not = (re_opcode_t) p1[3] == charset_not;
+
+ if (c < (unsigned char) (p1[4] * BYTEWIDTH)
+ && p1[5 + c / BYTEWIDTH] & (1 << (c % BYTEWIDTH)))
+ not = !not;
+
+ /* `not' is equal to 1 if c would match, which means
+ that we can't change to pop_failure_jump. */
+ if (!not)
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ else if ((re_opcode_t) *p2 == charset)
+ {
+#ifdef DEBUG
+ register unsigned char c
+ = *p2 == (unsigned char) endline ? '\n' : p2[2];
+#endif
+
+ if ((re_opcode_t) p1[3] == exactn
+ && ! ((int) p2[1] * BYTEWIDTH > (int) p1[4]
+ && (p2[1 + p1[4] / BYTEWIDTH]
+ & (1 << (p1[4] % BYTEWIDTH)))))
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT3 (" %c != %c => pop_failure_jump.\n",
+ c, p1[5]);
+ }
+
+ else if ((re_opcode_t) p1[3] == charset_not)
+ {
+ int idx;
+ /* We win if the charset_not inside the loop
+ lists every character listed in the charset after. */
+ for (idx = 0; idx < (int) p2[1]; idx++)
+ if (! (p2[2 + idx] == 0
+ || (idx < (int) p1[4]
+ && ((p2[2 + idx] & ~ p1[5 + idx]) == 0))))
+ break;
+
+ if (idx == p2[1])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ else if ((re_opcode_t) p1[3] == charset)
+ {
+ int idx;
+ /* We win if the charset inside the loop
+ has no overlap with the one after the loop. */
+ for (idx = 0;
+ idx < (int) p2[1] && idx < (int) p1[4];
+ idx++)
+ if ((p2[2 + idx] & p1[5 + idx]) != 0)
+ break;
+
+ if (idx == p2[1] || idx == p1[4])
+ {
+ p[-3] = (unsigned char) pop_failure_jump;
+ DEBUG_PRINT1 (" No match => pop_failure_jump.\n");
+ }
+ }
+ }
+ }
+ p -= 2; /* Point at relative address again. */
+ if ((re_opcode_t) p[-1] != pop_failure_jump)
+ {
+ p[-1] = (unsigned char) jump;
+ DEBUG_PRINT1 (" Match => jump.\n");
+ goto unconditional_jump;
+ }
+ /* Note fall through. */
+
+
+ /* The end of a simple repeat has a pop_failure_jump back to
+ its matching on_failure_jump, where the latter will push a
+ failure point. The pop_failure_jump takes off failure
+ points put on by this pop_failure_jump's matching
+ on_failure_jump; we got through the pattern to here from the
+ matching on_failure_jump, so didn't fail. */
+ case pop_failure_jump:
+ {
+ /* We need to pass separate storage for the lowest and
+ highest registers, even though we don't care about the
+ actual values. Otherwise, we will restore only one
+ register from the stack, since lowest will == highest in
+ `pop_failure_point'. */
+ unsigned dummy_low_reg, dummy_high_reg;
+ unsigned char *pdummy;
+ const char *sdummy;
+
+ DEBUG_PRINT1 ("EXECUTING pop_failure_jump.\n");
+ POP_FAILURE_POINT (sdummy, pdummy,
+ dummy_low_reg, dummy_high_reg,
+ reg_dummy, reg_dummy, reg_info_dummy);
+ }
+ /* Note fall through. */
+
+
+ /* Unconditionally jump (without popping any failure points). */
+ case jump:
+ unconditional_jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p); /* Get the amount to jump. */
+ DEBUG_PRINT2 ("EXECUTING jump %d ", mcnt);
+ p += mcnt; /* Do the jump. */
+ DEBUG_PRINT2 ("(to 0x%x).\n", p);
+ break;
+
+
+ /* We need this opcode so we can detect where alternatives end
+ in `group_match_null_string_p' et al. */
+ case jump_past_alt:
+ DEBUG_PRINT1 ("EXECUTING jump_past_alt.\n");
+ goto unconditional_jump;
+
+
+ /* Normally, the on_failure_jump pushes a failure point, which
+ then gets popped at pop_failure_jump. We will end up at
+ pop_failure_jump, also, and with a pattern of, say, `a+', we
+ are skipping over the on_failure_jump, so we have to push
+ something meaningless for pop_failure_jump to pop. */
+ case dummy_failure_jump:
+ DEBUG_PRINT1 ("EXECUTING dummy_failure_jump.\n");
+ /* It doesn't matter what we push for the string here. What
+ the code at `fail' tests is the value for the pattern. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ goto unconditional_jump;
+
+
+ /* At the end of an alternative, we need to push a dummy failure
+ point in case we are followed by a `pop_failure_jump', because
+ we don't want the failure point for the alternative to be
+ popped. For example, matching `(a|ab)*' against `aab'
+ requires that we match the `ab' alternative. */
+ case push_dummy_failure:
+ DEBUG_PRINT1 ("EXECUTING push_dummy_failure.\n");
+ /* See comments just above at `dummy_failure_jump' about the
+ two zeroes. */
+ PUSH_FAILURE_POINT (0, 0, -2);
+ break;
+
+ /* Have to succeed matching what follows at least n times.
+ After that, handle like `on_failure_jump'. */
+ case succeed_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING succeed_n %d.\n", mcnt);
+
+ assert (mcnt >= 0);
+ /* Originally, this is how many times we HAVE to succeed. */
+ if (mcnt > 0)
+ {
+ mcnt--;
+ p += 2;
+ STORE_NUMBER_AND_INCR (p, mcnt);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p, mcnt);
+ }
+ else if (mcnt == 0)
+ {
+ DEBUG_PRINT2 (" Setting two bytes from 0x%x to no_op.\n", p+2);
+ p[2] = (unsigned char) no_op;
+ p[3] = (unsigned char) no_op;
+ goto on_failure;
+ }
+ break;
+
+ case jump_n:
+ EXTRACT_NUMBER (mcnt, p + 2);
+ DEBUG_PRINT2 ("EXECUTING jump_n %d.\n", mcnt);
+
+ /* Originally, this is how many times we CAN jump. */
+ if (mcnt)
+ {
+ mcnt--;
+ STORE_NUMBER (p + 2, mcnt);
+ goto unconditional_jump;
+ }
+ /* If don't have to jump any more, skip over the rest of command. */
+ else
+ p += 4;
+ break;
+
+ case set_number_at:
+ {
+ DEBUG_PRINT1 ("EXECUTING set_number_at.\n");
+
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ p1 = p + mcnt;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p);
+ DEBUG_PRINT3 (" Setting 0x%x to %d.\n", p1, mcnt);
+ STORE_NUMBER (p1, mcnt);
+ break;
+ }
+
+ case wordbound:
+ DEBUG_PRINT1 ("EXECUTING wordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ break;
+ goto fail;
+
+ case notwordbound:
+ DEBUG_PRINT1 ("EXECUTING notwordbound.\n");
+ if (AT_WORD_BOUNDARY (d))
+ goto fail;
+ break;
+
+ case wordbeg:
+ DEBUG_PRINT1 ("EXECUTING wordbeg.\n");
+ if (WORDCHAR_P (d) && (AT_STRINGS_BEG (d) || !WORDCHAR_P (d - 1)))
+ break;
+ goto fail;
+
+ case wordend:
+ DEBUG_PRINT1 ("EXECUTING wordend.\n");
+ if (!AT_STRINGS_BEG (d) && WORDCHAR_P (d - 1)
+ && (!WORDCHAR_P (d) || AT_STRINGS_END (d)))
+ break;
+ goto fail;
+
+#ifdef emacs
+ case before_dot:
+ DEBUG_PRINT1 ("EXECUTING before_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) >= point)
+ goto fail;
+ break;
+
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) != point)
+ goto fail;
+ break;
+
+ case after_dot:
+ DEBUG_PRINT1 ("EXECUTING after_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) <= point)
+ goto fail;
+ break;
+#if 0 /* not emacs19 */
+ case at_dot:
+ DEBUG_PRINT1 ("EXECUTING at_dot.\n");
+ if (PTR_CHAR_POS ((unsigned char *) d) + 1 != point)
+ goto fail;
+ break;
+#endif /* not emacs19 */
+
+ case syntaxspec:
+ DEBUG_PRINT2 ("EXECUTING syntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchsyntax;
+
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs wordchar.\n");
+ mcnt = (int) Sword;
+ matchsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) != (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+ case notsyntaxspec:
+ DEBUG_PRINT2 ("EXECUTING notsyntaxspec %d.\n", mcnt);
+ mcnt = *p++;
+ goto matchnotsyntax;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING Emacs notwordchar.\n");
+ mcnt = (int) Sword;
+ matchnotsyntax:
+ PREFETCH ();
+ /* Can't use *d++ here; SYNTAX may be an unsafe macro. */
+ d++;
+ if (SYNTAX (d[-1]) == (enum syntaxcode) mcnt)
+ goto fail;
+ SET_REGS_MATCHED ();
+ break;
+
+#else /* not emacs */
+ case wordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs wordchar.\n");
+ PREFETCH ();
+ if (!WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+
+ case notwordchar:
+ DEBUG_PRINT1 ("EXECUTING non-Emacs notwordchar.\n");
+ PREFETCH ();
+ if (WORDCHAR_P (d))
+ goto fail;
+ SET_REGS_MATCHED ();
+ d++;
+ break;
+#endif /* not emacs */
+
+ default:
+ abort ();
+ }
+ continue; /* Successfully executed one pattern command; keep going. */
+
+
+ /* We goto here if a matching operation fails. */
+ fail:
+ if (!FAIL_STACK_EMPTY ())
+ { /* A restart point is known. Restore to that state. */
+ DEBUG_PRINT1 ("\nFAIL:\n");
+ POP_FAILURE_POINT (d, p,
+ lowest_active_reg, highest_active_reg,
+ regstart, regend, reg_info);
+
+ /* If this failure point is a dummy, try the next one. */
+ if (!p)
+ goto fail;
+
+ /* If we failed to the end of the pattern, don't examine *p. */
+ assert (p <= pend);
+ if (p < pend)
+ {
+ boolean is_a_jump_n = false;
+
+ /* If failed to a backwards jump that's part of a repetition
+ loop, need to pop this failure point and use the next one. */
+ switch ((re_opcode_t) *p)
+ {
+ case jump_n:
+ is_a_jump_n = true;
+ case maybe_pop_jump:
+ case pop_failure_jump:
+ case jump:
+ p1 = p + 1;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+
+ if ((is_a_jump_n && (re_opcode_t) *p1 == succeed_n)
+ || (!is_a_jump_n
+ && (re_opcode_t) *p1 == on_failure_jump))
+ goto fail;
+ break;
+ default:
+ /* do nothing */ ;
+ }
+ }
+
+ if (d >= string1 && d <= end1)
+ dend = end_match_1;
+ }
+ else
+ break; /* Matching at this starting point really fails. */
+ } /* for (;;) */
+
+ if (best_regs_set)
+ goto restore_best_regs;
+
+ FREE_VARIABLES ();
+
+ return -1; /* Failure to match. */
+} /* re_match_2 */
+\f
+/* Subroutine definitions for re_match_2. */
+
+
+/* We are passed P pointing to a register number after a start_memory.
+
+ Return true if the pattern up to the corresponding stop_memory can
+ match the empty string, and false otherwise.
+
+ If we find the matching stop_memory, sets P to point to one past its number.
+ Otherwise, sets P to an undefined byte less than or equal to END.
+
+ We don't handle duplicates properly (yet). */
+
+static boolean
+group_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ /* Point to after the args to the start_memory. */
+ unsigned char *p1 = *p + 2;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and return true or
+ false, as appropriate, when we get to one that can't, or to the
+ matching stop_memory. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* Could be either a loop or a series of alternatives. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ /* If the next operation is not a jump backwards in the
+ pattern. */
+
+ if (mcnt >= 0)
+ {
+ /* Go through the on_failure_jumps of the alternatives,
+ seeing if any of the alternatives cannot match nothing.
+ The last alternative starts with only a jump,
+ whereas the rest start with on_failure_jump and end
+ with a jump, e.g., here is the pattern for `a|b|c':
+
+ /on_failure_jump/0/6/exactn/1/a/jump_past_alt/0/6
+ /on_failure_jump/0/6/exactn/1/b/jump_past_alt/0/3
+ /exactn/1/c
+
+ So, we have to first go through the first (n-1)
+ alternatives and then deal with the last one separately. */
+
+
+ /* Deal with the first (n-1) alternatives, which start
+ with an on_failure_jump (see above) that jumps to right
+ past a jump_past_alt. */
+
+ while ((re_opcode_t) p1[mcnt-3] == jump_past_alt)
+ {
+ /* `mcnt' holds how many bytes long the alternative
+ is, including the ending `jump_past_alt' and
+ its number. */
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt - 3,
+ reg_info))
+ return false;
+
+ /* Move to right after this alternative, including the
+ jump_past_alt. */
+ p1 += mcnt;
+
+ /* Break if it's the beginning of an n-th alternative
+ that doesn't begin with an on_failure_jump. */
+ if ((re_opcode_t) *p1 != on_failure_jump)
+ break;
+
+ /* Still have to check that it's not an n-th
+ alternative that starts with an on_failure_jump. */
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if ((re_opcode_t) p1[mcnt-3] != jump_past_alt)
+ {
+ /* Get to the beginning of the n-th alternative. */
+ p1 -= 3;
+ break;
+ }
+ }
+
+ /* Deal with the last alternative: go back and get number
+ of the `jump_past_alt' just before it. `mcnt' contains
+ the length of the alternative. */
+ EXTRACT_NUMBER (mcnt, p1 - 2);
+
+ if (!alt_match_null_string_p (p1, p1 + mcnt, reg_info))
+ return false;
+
+ p1 += mcnt; /* Get past the n-th alternative. */
+ } /* if mcnt > 0 */
+ break;
+
+
+ case stop_memory:
+ assert (p1[1] == **p);
+ *p = p1 + 2;
+ return true;
+
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return false;
+} /* group_match_null_string_p */
+
+
+/* Similar to group_match_null_string_p, but doesn't deal with alternatives:
+ It expects P to be the first byte of a single alternative and END one
+ byte past the last. The alternative can contain groups. */
+
+static boolean
+alt_match_null_string_p (p, end, reg_info)
+ unsigned char *p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ unsigned char *p1 = p;
+
+ while (p1 < end)
+ {
+ /* Skip over opcodes that can match nothing, and break when we get
+ to one that can't. */
+
+ switch ((re_opcode_t) *p1)
+ {
+ /* It's a loop. */
+ case on_failure_jump:
+ p1++;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ break;
+
+ default:
+ if (!common_op_match_null_string_p (&p1, end, reg_info))
+ return false;
+ }
+ } /* while p1 < end */
+
+ return true;
+} /* alt_match_null_string_p */
+
+
+/* Deals with the ops common to group_match_null_string_p and
+ alt_match_null_string_p.
+
+ Sets P to one after the op and its arguments, if any. */
+
+static boolean
+common_op_match_null_string_p (p, end, reg_info)
+ unsigned char **p, *end;
+ register_info_type *reg_info;
+{
+ int mcnt;
+ boolean ret;
+ int reg_no;
+ unsigned char *p1 = *p;
+
+ switch ((re_opcode_t) *p1++)
+ {
+ case no_op:
+ case begline:
+ case endline:
+ case begbuf:
+ case endbuf:
+ case wordbeg:
+ case wordend:
+ case wordbound:
+ case notwordbound:
+#ifdef emacs
+ case before_dot:
+ case at_dot:
+ case after_dot:
+#endif
+ break;
+
+ case start_memory:
+ reg_no = *p1;
+ assert (reg_no > 0 && reg_no <= MAX_REGNUM);
+ ret = group_match_null_string_p (&p1, end, reg_info);
+
+ /* Have to set this here in case we're checking a group which
+ contains a group and a back reference to it. */
+
+ if (REG_MATCH_NULL_STRING_P (reg_info[reg_no]) == MATCH_NULL_UNSET_VALUE)
+ REG_MATCH_NULL_STRING_P (reg_info[reg_no]) = ret;
+
+ if (!ret)
+ return false;
+ break;
+
+ /* If this is an optimized succeed_n for zero times, make the jump. */
+ case jump:
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ if (mcnt >= 0)
+ p1 += mcnt;
+ else
+ return false;
+ break;
+
+ case succeed_n:
+ /* Get to the number of times to succeed. */
+ p1 += 2;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+
+ if (mcnt == 0)
+ {
+ p1 -= 4;
+ EXTRACT_NUMBER_AND_INCR (mcnt, p1);
+ p1 += mcnt;
+ }
+ else
+ return false;
+ break;
+
+ case duplicate:
+ if (!REG_MATCH_NULL_STRING_P (reg_info[*p1]))
+ return false;
+ break;
+
+ case set_number_at:
+ p1 += 4;
+
+ default:
+ /* All other opcodes mean we cannot match the empty string. */
+ return false;
+ }
+
+ *p = p1;
+ return true;
+} /* common_op_match_null_string_p */
+
+
+/* Return zero if TRANSLATE[S1] and TRANSLATE[S2] are identical for LEN
+ bytes; nonzero otherwise. */
+
+static int
+bcmp_translate (s1, s2, len, translate)
+ unsigned char *s1, *s2;
+ register int len;
+ char *translate;
+{
+ register unsigned char *p1 = s1, *p2 = s2;
+ while (len)
+ {
+ if (translate[*p1++] != translate[*p2++]) return 1;
+ len--;
+ }
+ return 0;
+}
+\f
+/* Entry points for GNU code. */
+
+/* re_compile_pattern is the GNU regular expression compiler: it
+ compiles PATTERN (of length SIZE) and puts the result in BUFP.
+ Returns 0 if the pattern was valid, otherwise an error string.
+
+ Assumes the `allocated' (and perhaps `buffer') and `translate' fields
+ are set in BUFP on entry.
+
+ We call regex_compile to do the actual compilation. */
+
+const char *
+re_compile_pattern (pattern, length, bufp)
+ const char *pattern;
+ int length;
+ struct re_pattern_buffer *bufp;
+{
+ reg_errcode_t ret;
+
+ /* GNU code is written to assume at least RE_NREGS registers will be set
+ (and at least one extra will be -1). */
+ bufp->regs_allocated = REGS_UNALLOCATED;
+
+ /* And GNU code determines whether or not to get register information
+ by passing null for the REGS argument to re_match, etc., not by
+ setting no_sub. */
+ bufp->no_sub = 0;
+
+ /* Match anchors at newline. */
+ bufp->newline_anchor = 1;
+
+ ret = regex_compile (pattern, length, re_syntax_options, bufp);
+
+ if (!ret)
+ return NULL;
+ return gettext (re_error_msgid[(int) ret]);
+}
+\f
+/* Entry points compatible with 4.2 BSD regex library. We don't define
+ them unless specifically requested. */
+
+#ifdef _REGEX_RE_COMP
+
+/* BSD has one and only one pattern buffer. */
+static struct re_pattern_buffer re_comp_buf;
+
+char *
+re_comp (s)
+ const char *s;
+{
+ reg_errcode_t ret;
+
+ if (!s)
+ {
+ if (!re_comp_buf.buffer)
+ return gettext ("No previous regular expression");
+ return 0;
+ }
+
+ if (!re_comp_buf.buffer)
+ {
+ re_comp_buf.buffer = (unsigned char *) malloc (200);
+ if (re_comp_buf.buffer == NULL)
+ return gettext (re_error_msgid[(int) REG_ESPACE]);
+ re_comp_buf.allocated = 200;
+
+ re_comp_buf.fastmap = (char *) malloc (1 << BYTEWIDTH);
+ if (re_comp_buf.fastmap == NULL)
+ return gettext (re_error_msgid[(int) REG_ESPACE]);
+ }
+
+ /* Since `re_exec' always passes NULL for the `regs' argument, we
+ don't need to initialize the pattern buffer fields which affect it. */
+
+ /* Match anchors at newlines. */
+ re_comp_buf.newline_anchor = 1;
+
+ ret = regex_compile (s, strlen (s), re_syntax_options, &re_comp_buf);
+
+ if (!ret)
+ return NULL;
+
+ /* Yes, we're discarding `const' here if !HAVE_LIBINTL. */
+ return (char *) gettext (re_error_msgid[(int) ret]);
+}
+
+
+int
+re_exec (s)
+ const char *s;
+{
+ const int len = strlen (s);
+ return
+ 0 <= re_search (&re_comp_buf, s, len, 0, len, (struct re_registers *) 0);
+}
+#endif /* _REGEX_RE_COMP */
+\f
+/* POSIX.2 functions. Don't define these for Emacs. */
+
+#ifndef emacs
+
+/* regcomp takes a regular expression as a string and compiles it.
+
+ PREG is a regex_t *. We do not expect any fields to be initialized,
+ since POSIX says we shouldn't. Thus, we set
+
+ `buffer' to the compiled pattern;
+ `used' to the length of the compiled pattern;
+ `syntax' to RE_SYNTAX_POSIX_EXTENDED if the
+ REG_EXTENDED bit in CFLAGS is set; otherwise, to
+ RE_SYNTAX_POSIX_BASIC;
+ `newline_anchor' to REG_NEWLINE being set in CFLAGS;
+ `fastmap' and `fastmap_accurate' to zero;
+ `re_nsub' to the number of subexpressions in PATTERN.
+
+ PATTERN is the address of the pattern string.
+
+ CFLAGS is a series of bits which affect compilation.
+
+ If REG_EXTENDED is set, we use POSIX extended syntax; otherwise, we
+ use POSIX basic syntax.
+
+ If REG_NEWLINE is set, then . and [^...] don't match newline.
+ Also, regexec will try a match beginning after every newline.
+
+ If REG_ICASE is set, then we considers upper- and lowercase
+ versions of letters to be equivalent when matching.
+
+ If REG_NOSUB is set, then when PREG is passed to regexec, that
+ routine will report only success or failure, and nothing about the
+ registers.
+
+ It returns 0 if it succeeds, nonzero if it doesn't. (See regex.h for
+ the return codes and their meanings.) */
+
+int
+regcomp (preg, pattern, cflags)
+ regex_t *preg;
+ const char *pattern;
+ int cflags;
+{
+ reg_errcode_t ret;
+ unsigned syntax
+ = (cflags & REG_EXTENDED) ?
+ RE_SYNTAX_POSIX_EXTENDED : RE_SYNTAX_POSIX_BASIC;
+
+ /* regex_compile will allocate the space for the compiled pattern. */
+ preg->buffer = 0;
+ preg->allocated = 0;
+ preg->used = 0;
+
+ /* Don't bother to use a fastmap when searching. This simplifies the
+ REG_NEWLINE case: if we used a fastmap, we'd have to put all the
+ characters after newlines into the fastmap. This way, we just try
+ every character. */
+ preg->fastmap = 0;
+
+ if (cflags & REG_ICASE)
+ {
+ unsigned i;
+
+ preg->translate = (char *) malloc (CHAR_SET_SIZE);
+ if (preg->translate == NULL)
+ return (int) REG_ESPACE;
+
+ /* Map uppercase characters to corresponding lowercase ones. */
+ for (i = 0; i < CHAR_SET_SIZE; i++)
+ preg->translate[i] = ISUPPER (i) ? tolower (i) : i;
+ }
+ else
+ preg->translate = NULL;
+
+ /* If REG_NEWLINE is set, newlines are treated differently. */
+ if (cflags & REG_NEWLINE)
+ { /* REG_NEWLINE implies neither . nor [^...] match newline. */
+ syntax &= ~RE_DOT_NEWLINE;
+ syntax |= RE_HAT_LISTS_NOT_NEWLINE;
+ /* It also changes the matching behavior. */
+ preg->newline_anchor = 1;
+ }
+ else
+ preg->newline_anchor = 0;
+
+ preg->no_sub = !!(cflags & REG_NOSUB);
+
+ /* POSIX says a null character in the pattern terminates it, so we
+ can use strlen here in compiling the pattern. */
+ ret = regex_compile (pattern, strlen (pattern), syntax, preg);
+
+ /* POSIX doesn't distinguish between an unmatched open-group and an
+ unmatched close-group: both are REG_EPAREN. */
+ if (ret == REG_ERPAREN) ret = REG_EPAREN;
+
+ return (int) ret;
+}
+
+
+/* regexec searches for a given pattern, specified by PREG, in the
+ string STRING.
+
+ If NMATCH is zero or REG_NOSUB was set in the cflags argument to
+ `regcomp', we ignore PMATCH. Otherwise, we assume PMATCH has at
+ least NMATCH elements, and we set them to the offsets of the
+ corresponding matched substrings.
+
+ EFLAGS specifies `execution flags' which affect matching: if
+ REG_NOTBOL is set, then ^ does not match at the beginning of the
+ string; if REG_NOTEOL is set, then $ does not match at the end.
+
+ We return 0 if we find a match and REG_NOMATCH if not. */
+
+int
+regexec (preg, string, nmatch, pmatch, eflags)
+ const regex_t *preg;
+ const char *string;
+ size_t nmatch;
+ regmatch_t pmatch[];
+ int eflags;
+{
+ int ret;
+ struct re_registers regs;
+ regex_t private_preg;
+ int len = strlen (string);
+ boolean want_reg_info = !preg->no_sub && nmatch > 0;
+
+ private_preg = *preg;
+
+ private_preg.not_bol = !!(eflags & REG_NOTBOL);
+ private_preg.not_eol = !!(eflags & REG_NOTEOL);
+
+ /* The user has told us exactly how many registers to return
+ information about, via `nmatch'. We have to pass that on to the
+ matching routines. */
+ private_preg.regs_allocated = REGS_FIXED;
+
+ if (want_reg_info)
+ {
+ regs.num_regs = nmatch;
+ regs.start = TALLOC (nmatch, regoff_t);
+ regs.end = TALLOC (nmatch, regoff_t);
+ if (regs.start == NULL || regs.end == NULL)
+ return (int) REG_NOMATCH;
+ }
+
+ /* Perform the searching operation. */
+ ret = re_search (&private_preg, string, len,
+ /* start: */ 0, /* range: */ len,
+ want_reg_info ? ®s : (struct re_registers *) 0);
+
+ /* Copy the register information to the POSIX structure. */
+ if (want_reg_info)
+ {
+ if (ret >= 0)
+ {
+ unsigned r;
+
+ for (r = 0; r < nmatch; r++)
+ {
+ pmatch[r].rm_so = regs.start[r];
+ pmatch[r].rm_eo = regs.end[r];
+ }
+ }
+
+ /* If we needed the temporary register info, free the space now. */
+ free (regs.start);
+ free (regs.end);
+ }
+
+ /* We want zero return to mean success, unlike `re_search'. */
+ return ret >= 0 ? (int) REG_NOERROR : (int) REG_NOMATCH;
+}
+
+
+/* Returns a message corresponding to an error code, ERRCODE, returned
+ from either regcomp or regexec. We don't use PREG here. */
+
+size_t
+regerror (errcode, preg, errbuf, errbuf_size)
+ int errcode;
+ const regex_t *preg;
+ char *errbuf;
+ size_t errbuf_size;
+{
+ const char *msg;
+ size_t msg_size;
+
+ if (errcode < 0
+ || errcode >= (sizeof (re_error_msgid) / sizeof (re_error_msgid[0])))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg = gettext (re_error_msgid[errcode]);
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
+
+ if (errbuf_size != 0)
+ {
+ if (msg_size > errbuf_size)
+ {
+ strncpy (errbuf, msg, errbuf_size - 1);
+ errbuf[errbuf_size - 1] = 0;
+ }
+ else
+ strcpy (errbuf, msg);
+ }
+
+ return msg_size;
+}
+
+
+/* Free dynamically allocated space used by PREG. */
+
+void
+regfree (preg)
+ regex_t *preg;
+{
+ if (preg->buffer != NULL)
+ free (preg->buffer);
+ preg->buffer = NULL;
+
+ preg->allocated = 0;
+ preg->used = 0;
+
+ if (preg->fastmap != NULL)
+ free (preg->fastmap);
+ preg->fastmap = NULL;
+ preg->fastmap_accurate = 0;
+
+ if (preg->translate != NULL)
+ free (preg->translate);
+ preg->translate = NULL;
+}
+
+#endif /* not emacs */
+\f
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
--- /dev/null
+/* Definitions for data structures and routines for the regular
+ expression library, version 0.12.
+
+ Copyright (C) 1985, 89, 90, 91, 92, 93, 95 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 2, or (at your option)
+ any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#ifndef __REGEXP_LIBRARY_H__
+#define __REGEXP_LIBRARY_H__
+
+/* POSIX says that <sys/types.h> must be included (by the caller) before
+ <regex.h>. */
+
+#if !defined (_POSIX_C_SOURCE) && !defined (_POSIX_SOURCE) && defined (VMS)
+/* VMS doesn't have `size_t' in <sys/types.h>, even though POSIX says it
+ should be there. */
+#include <stddef.h>
+#endif
+
+
+/* The following bits are used to determine the regexp syntax we
+ recognize. The set/not-set meanings are chosen so that Emacs syntax
+ remains the value 0. The bits are given in alphabetical order, and
+ the definitions shifted by one from the previous bit; thus, when we
+ add or remove a bit, only one other definition need change. */
+typedef unsigned reg_syntax_t;
+
+/* If this bit is not set, then \ inside a bracket expression is literal.
+ If set, then such a \ quotes the following character. */
+#define RE_BACKSLASH_ESCAPE_IN_LISTS (1)
+
+/* If this bit is not set, then + and ? are operators, and \+ and \? are
+ literals.
+ If set, then \+ and \? are operators and + and ? are literals. */
+#define RE_BK_PLUS_QM (RE_BACKSLASH_ESCAPE_IN_LISTS << 1)
+
+/* If this bit is set, then character classes are supported. They are:
+ [:alpha:], [:upper:], [:lower:], [:digit:], [:alnum:], [:xdigit:],
+ [:space:], [:print:], [:punct:], [:graph:], and [:cntrl:].
+ If not set, then character classes are not supported. */
+#define RE_CHAR_CLASSES (RE_BK_PLUS_QM << 1)
+
+/* If this bit is set, then ^ and $ are always anchors (outside bracket
+ expressions, of course).
+ If this bit is not set, then it depends:
+ ^ is an anchor if it is at the beginning of a regular
+ expression or after an open-group or an alternation operator;
+ $ is an anchor if it is at the end of a regular expression, or
+ before a close-group or an alternation operator.
+
+ This bit could be (re)combined with RE_CONTEXT_INDEP_OPS, because
+ POSIX draft 11.2 says that * etc. in leading positions is undefined.
+ We already implemented a previous draft which made those constructs
+ invalid, though, so we haven't changed the code back. */
+#define RE_CONTEXT_INDEP_ANCHORS (RE_CHAR_CLASSES << 1)
+
+/* If this bit is set, then special characters are always special
+ regardless of where they are in the pattern.
+ If this bit is not set, then special characters are special only in
+ some contexts; otherwise they are ordinary. Specifically,
+ * + ? and intervals are only special when not after the beginning,
+ open-group, or alternation operator. */
+#define RE_CONTEXT_INDEP_OPS (RE_CONTEXT_INDEP_ANCHORS << 1)
+
+/* If this bit is set, then *, +, ?, and { cannot be first in an re or
+ immediately after an alternation or begin-group operator. */
+#define RE_CONTEXT_INVALID_OPS (RE_CONTEXT_INDEP_OPS << 1)
+
+/* If this bit is set, then . matches newline.
+ If not set, then it doesn't. */
+#define RE_DOT_NEWLINE (RE_CONTEXT_INVALID_OPS << 1)
+
+/* If this bit is set, then . doesn't match NUL.
+ If not set, then it does. */
+#define RE_DOT_NOT_NULL (RE_DOT_NEWLINE << 1)
+
+/* If this bit is set, nonmatching lists [^...] do not match newline.
+ If not set, they do. */
+#define RE_HAT_LISTS_NOT_NEWLINE (RE_DOT_NOT_NULL << 1)
+
+/* If this bit is set, either \{...\} or {...} defines an
+ interval, depending on RE_NO_BK_BRACES.
+ If not set, \{, \}, {, and } are literals. */
+#define RE_INTERVALS (RE_HAT_LISTS_NOT_NEWLINE << 1)
+
+/* If this bit is set, +, ? and | aren't recognized as operators.
+ If not set, they are. */
+#define RE_LIMITED_OPS (RE_INTERVALS << 1)
+
+/* If this bit is set, newline is an alternation operator.
+ If not set, newline is literal. */
+#define RE_NEWLINE_ALT (RE_LIMITED_OPS << 1)
+
+/* If this bit is set, then `{...}' defines an interval, and \{ and \}
+ are literals.
+ If not set, then `\{...\}' defines an interval. */
+#define RE_NO_BK_BRACES (RE_NEWLINE_ALT << 1)
+
+/* If this bit is set, (...) defines a group, and \( and \) are literals.
+ If not set, \(...\) defines a group, and ( and ) are literals. */
+#define RE_NO_BK_PARENS (RE_NO_BK_BRACES << 1)
+
+/* If this bit is set, then \<digit> matches <digit>.
+ If not set, then \<digit> is a back-reference. */
+#define RE_NO_BK_REFS (RE_NO_BK_PARENS << 1)
+
+/* If this bit is set, then | is an alternation operator, and \| is literal.
+ If not set, then \| is an alternation operator, and | is literal. */
+#define RE_NO_BK_VBAR (RE_NO_BK_REFS << 1)
+
+/* If this bit is set, then an ending range point collating higher
+ than the starting range point, as in [z-a], is invalid.
+ If not set, then when ending range point collates higher than the
+ starting range point, the range is ignored. */
+#define RE_NO_EMPTY_RANGES (RE_NO_BK_VBAR << 1)
+
+/* If this bit is set, then an unmatched ) is ordinary.
+ If not set, then an unmatched ) is invalid. */
+#define RE_UNMATCHED_RIGHT_PAREN_ORD (RE_NO_EMPTY_RANGES << 1)
+
+/* If this bit is set, succeed as soon as we match the whole pattern,
+ without further backtracking. */
+#define RE_NO_POSIX_BACKTRACKING (RE_UNMATCHED_RIGHT_PAREN_ORD << 1)
+
+/* This global variable defines the particular regexp syntax to use (for
+ some interfaces). When a regexp is compiled, the syntax used is
+ stored in the pattern buffer, so changing this does not affect
+ already-compiled regexps. */
+extern reg_syntax_t re_syntax_options;
+\f
+/* Define combinations of the above bits for the standard possibilities.
+ (The [[[ comments delimit what gets put into the Texinfo file, so
+ don't delete them!) */
+/* [[[begin syntaxes]]] */
+#define RE_SYNTAX_EMACS 0
+
+#define RE_SYNTAX_AWK \
+ (RE_BACKSLASH_ESCAPE_IN_LISTS | RE_DOT_NOT_NULL \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_NO_EMPTY_RANGES \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+#define RE_SYNTAX_POSIX_AWK \
+ (RE_SYNTAX_POSIX_EXTENDED | RE_BACKSLASH_ESCAPE_IN_LISTS)
+
+#define RE_SYNTAX_GREP \
+ (RE_BK_PLUS_QM | RE_CHAR_CLASSES \
+ | RE_HAT_LISTS_NOT_NEWLINE | RE_INTERVALS \
+ | RE_NEWLINE_ALT)
+
+#define RE_SYNTAX_EGREP \
+ (RE_CHAR_CLASSES | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_HAT_LISTS_NOT_NEWLINE \
+ | RE_NEWLINE_ALT | RE_NO_BK_PARENS \
+ | RE_NO_BK_VBAR)
+
+#define RE_SYNTAX_POSIX_EGREP \
+ (RE_SYNTAX_EGREP | RE_INTERVALS | RE_NO_BK_BRACES)
+
+/* P1003.2/D11.2, section 4.20.7.1, lines 5078ff. */
+#define RE_SYNTAX_ED RE_SYNTAX_POSIX_BASIC
+
+#define RE_SYNTAX_SED RE_SYNTAX_POSIX_BASIC
+
+/* Syntax bits common to both basic and extended POSIX regex syntax. */
+#define _RE_SYNTAX_POSIX_COMMON \
+ (RE_CHAR_CLASSES | RE_DOT_NEWLINE | RE_DOT_NOT_NULL \
+ | RE_INTERVALS | RE_NO_EMPTY_RANGES)
+
+#define RE_SYNTAX_POSIX_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_BK_PLUS_QM)
+
+/* Differs from ..._POSIX_BASIC only in that RE_BK_PLUS_QM becomes
+ RE_LIMITED_OPS, i.e., \? \+ \| are not recognized. Actually, this
+ isn't minimal, since other operators, such as \`, aren't disabled. */
+#define RE_SYNTAX_POSIX_MINIMAL_BASIC \
+ (_RE_SYNTAX_POSIX_COMMON | RE_LIMITED_OPS)
+
+#define RE_SYNTAX_POSIX_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INDEP_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_VBAR \
+ | RE_UNMATCHED_RIGHT_PAREN_ORD)
+
+/* Differs from ..._POSIX_EXTENDED in that RE_CONTEXT_INVALID_OPS
+ replaces RE_CONTEXT_INDEP_OPS and RE_NO_BK_REFS is added. */
+#define RE_SYNTAX_POSIX_MINIMAL_EXTENDED \
+ (_RE_SYNTAX_POSIX_COMMON | RE_CONTEXT_INDEP_ANCHORS \
+ | RE_CONTEXT_INVALID_OPS | RE_NO_BK_BRACES \
+ | RE_NO_BK_PARENS | RE_NO_BK_REFS \
+ | RE_NO_BK_VBAR | RE_UNMATCHED_RIGHT_PAREN_ORD)
+/* [[[end syntaxes]]] */
+\f
+/* Maximum number of duplicates an interval can allow. Some systems
+ (erroneously) define this in other header files, but we want our
+ value, so remove any previous define. */
+#ifdef RE_DUP_MAX
+#undef RE_DUP_MAX
+#endif
+#define RE_DUP_MAX ((1 << 15) - 1)
+
+
+/* POSIX `cflags' bits (i.e., information for `regcomp'). */
+
+/* If this bit is set, then use extended regular expression syntax.
+ If not set, then use basic regular expression syntax. */
+#define REG_EXTENDED 1
+
+/* If this bit is set, then ignore case when matching.
+ If not set, then case is significant. */
+#define REG_ICASE (REG_EXTENDED << 1)
+
+/* If this bit is set, then anchors do not match at newline
+ characters in the string.
+ If not set, then anchors do match at newlines. */
+#define REG_NEWLINE (REG_ICASE << 1)
+
+/* If this bit is set, then report only success or fail in regexec.
+ If not set, then returns differ between not matching and errors. */
+#define REG_NOSUB (REG_NEWLINE << 1)
+
+
+/* POSIX `eflags' bits (i.e., information for regexec). */
+
+/* If this bit is set, then the beginning-of-line operator doesn't match
+ the beginning of the string (presumably because it's not the
+ beginning of a line).
+ If not set, then the beginning-of-line operator does match the
+ beginning of the string. */
+#define REG_NOTBOL 1
+
+/* Like REG_NOTBOL, except for the end-of-line. */
+#define REG_NOTEOL (1 << 1)
+
+
+/* If any error codes are removed, changed, or added, update the
+ `re_error_msg' table in regex.c. */
+typedef enum
+{
+ REG_NOERROR = 0, /* Success. */
+ REG_NOMATCH, /* Didn't find a match (for regexec). */
+
+ /* POSIX regcomp return error codes. (In the order listed in the
+ standard.) */
+ REG_BADPAT, /* Invalid pattern. */
+ REG_ECOLLATE, /* Not implemented. */
+ REG_ECTYPE, /* Invalid character class name. */
+ REG_EESCAPE, /* Trailing backslash. */
+ REG_ESUBREG, /* Invalid back reference. */
+ REG_EBRACK, /* Unmatched left bracket. */
+ REG_EPAREN, /* Parenthesis imbalance. */
+ REG_EBRACE, /* Unmatched \{. */
+ REG_BADBR, /* Invalid contents of \{\}. */
+ REG_ERANGE, /* Invalid range end. */
+ REG_ESPACE, /* Ran out of memory. */
+ REG_BADRPT, /* No preceding re for repetition op. */
+
+ /* Error codes we've added. */
+ REG_EEND, /* Premature end. */
+ REG_ESIZE, /* Compiled pattern bigger than 2^16 bytes. */
+ REG_ERPAREN /* Unmatched ) or \); not returned from regcomp. */
+} reg_errcode_t;
+\f
+/* This data structure represents a compiled pattern. Before calling
+ the pattern compiler, the fields `buffer', `allocated', `fastmap',
+ `translate', and `no_sub' can be set. After the pattern has been
+ compiled, the `re_nsub' field is available. All other fields are
+ private to the regex routines. */
+
+struct re_pattern_buffer
+{
+/* [[[begin pattern_buffer]]] */
+ /* Space that holds the compiled pattern. It is declared as
+ `unsigned char *' because its elements are
+ sometimes used as array indexes. */
+ unsigned char *buffer;
+
+ /* Number of bytes to which `buffer' points. */
+ unsigned long allocated;
+
+ /* Number of bytes actually used in `buffer'. */
+ unsigned long used;
+
+ /* Syntax setting with which the pattern was compiled. */
+ reg_syntax_t syntax;
+
+ /* Pointer to a fastmap, if any, otherwise zero. re_search uses
+ the fastmap, if there is one, to skip over impossible
+ starting points for matches. */
+ char *fastmap;
+
+ /* Either a translate table to apply to all characters before
+ comparing them, or zero for no translation. The translation
+ is applied to a pattern when it is compiled and to a string
+ when it is matched. */
+ char *translate;
+
+ /* Number of subexpressions found by the compiler. */
+ size_t re_nsub;
+
+ /* Zero if this pattern cannot match the empty string, one else.
+ Well, in truth it's used only in `re_search_2', to see
+ whether or not we should use the fastmap, so we don't set
+ this absolutely perfectly; see `re_compile_fastmap' (the
+ `duplicate' case). */
+ unsigned can_be_null : 1;
+
+ /* If REGS_UNALLOCATED, allocate space in the `regs' structure
+ for `max (RE_NREGS, re_nsub + 1)' groups.
+ If REGS_REALLOCATE, reallocate space if necessary.
+ If REGS_FIXED, use what's there. */
+#define REGS_UNALLOCATED 0
+#define REGS_REALLOCATE 1
+#define REGS_FIXED 2
+ unsigned regs_allocated : 2;
+
+ /* Set to zero when `regex_compile' compiles a pattern; set to one
+ by `re_compile_fastmap' if it updates the fastmap. */
+ unsigned fastmap_accurate : 1;
+
+ /* If set, `re_match_2' does not return information about
+ subexpressions. */
+ unsigned no_sub : 1;
+
+ /* If set, a beginning-of-line anchor doesn't match at the
+ beginning of the string. */
+ unsigned not_bol : 1;
+
+ /* Similarly for an end-of-line anchor. */
+ unsigned not_eol : 1;
+
+ /* If true, an anchor at a newline matches. */
+ unsigned newline_anchor : 1;
+
+/* [[[end pattern_buffer]]] */
+};
+
+typedef struct re_pattern_buffer regex_t;
+\f
+/* Type for byte offsets within the string. POSIX mandates this. */
+typedef int regoff_t;
+
+
+/* This is the structure we store register match data in. See
+ regex.texinfo for a full description of what registers match. */
+struct re_registers
+{
+ unsigned num_regs;
+ regoff_t *start;
+ regoff_t *end;
+};
+
+
+/* If `regs_allocated' is REGS_UNALLOCATED in the pattern buffer,
+ `re_match_2' returns information about at least this many registers
+ the first time a `regs' structure is passed. */
+#ifndef RE_NREGS
+#define RE_NREGS 30
+#endif
+
+
+/* POSIX specification for registers. Aside from the different names than
+ `re_registers', POSIX uses an array of structures, instead of a
+ structure of arrays. */
+typedef struct
+{
+ regoff_t rm_so; /* Byte offset from string's start to substring's start. */
+ regoff_t rm_eo; /* Byte offset from string's start to substring's end. */
+} regmatch_t;
+\f
+/* Declarations for routines. */
+
+/* To avoid duplicating every routine declaration -- once with a
+ prototype (if we are ANSI), and once without (if we aren't) -- we
+ use the following macro to declare argument types. This
+ unfortunately clutters up the declarations a bit, but I think it's
+ worth it. */
+
+#if __STDC__
+
+#define _RE_ARGS(args) args
+
+#else /* not __STDC__ */
+
+#define _RE_ARGS(args) ()
+
+#endif /* not __STDC__ */
+
+/* Sets the current default syntax to SYNTAX, and return the old syntax.
+ You can also simply assign to the `re_syntax_options' variable. */
+extern reg_syntax_t re_set_syntax _RE_ARGS ((reg_syntax_t syntax));
+
+/* Compile the regular expression PATTERN, with length LENGTH
+ and syntax given by the global `re_syntax_options', into the buffer
+ BUFFER. Return NULL if successful, and an error string if not. */
+extern const char *re_compile_pattern
+ _RE_ARGS ((const char *pattern, int length,
+ struct re_pattern_buffer *buffer));
+
+
+/* Compile a fastmap for the compiled pattern in BUFFER; used to
+ accelerate searches. Return 0 if successful and -2 if was an
+ internal error. */
+extern int re_compile_fastmap _RE_ARGS ((struct re_pattern_buffer *buffer));
+
+
+/* Search in the string STRING (with length LENGTH) for the pattern
+ compiled into BUFFER. Start searching at position START, for RANGE
+ characters. Return the starting position of the match, -1 for no
+ match, or -2 for an internal error. Also return register
+ information in REGS (if REGS and BUFFER->no_sub are nonzero). */
+extern int re_search
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, int range, struct re_registers *regs));
+
+
+/* Like `re_search', but search in the concatenation of STRING1 and
+ STRING2. Also, stop searching at index START + STOP. */
+extern int re_search_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, int range, struct re_registers *regs, int stop));
+
+
+/* Like `re_search', but return how many characters in STRING the regexp
+ in BUFFER matched, starting at position START. */
+extern int re_match
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string,
+ int length, int start, struct re_registers *regs));
+
+
+/* Relates to `re_match' as `re_search_2' relates to `re_search'. */
+extern int re_match_2
+ _RE_ARGS ((struct re_pattern_buffer *buffer, const char *string1,
+ int length1, const char *string2, int length2,
+ int start, struct re_registers *regs, int stop));
+
+
+/* Set REGS to hold NUM_REGS registers, storing them in STARTS and
+ ENDS. Subsequent matches using BUFFER and REGS will use this memory
+ for recording register information. STARTS and ENDS must be
+ allocated with malloc, and must each be at least `NUM_REGS * sizeof
+ (regoff_t)' bytes long.
+
+ If NUM_REGS == 0, then subsequent matches should allocate their own
+ register data.
+
+ Unless this function is called, the first search or match using
+ PATTERN_BUFFER will allocate its own register data, without
+ freeing the old data. */
+extern void re_set_registers
+ _RE_ARGS ((struct re_pattern_buffer *buffer, struct re_registers *regs,
+ unsigned num_regs, regoff_t *starts, regoff_t *ends));
+
+#ifdef _REGEX_RE_COMP
+/* 4.2 bsd compatibility. */
+extern char *re_comp _RE_ARGS ((const char *));
+extern int re_exec _RE_ARGS ((const char *));
+#endif
+
+/* POSIX compatibility. */
+extern int regcomp _RE_ARGS ((regex_t *preg, const char *pattern, int cflags));
+extern int regexec
+ _RE_ARGS ((const regex_t *preg, const char *string, size_t nmatch,
+ regmatch_t pmatch[], int eflags));
+extern size_t regerror
+ _RE_ARGS ((int errcode, const regex_t *preg, char *errbuf,
+ size_t errbuf_size));
+extern void regfree _RE_ARGS ((regex_t *preg));
+
+#endif /* not __REGEXP_LIBRARY_H__ */
+\f
+/*
+Local variables:
+make-backup-files: t
+version-control: t
+trim-versions-without-asking: nil
+End:
+*/
--- /dev/null
+/* rxvt.c - gives output lines on rxvt with a special rxvt patch
+ Copyright (C) 1997 Paul Sheer
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+#include <stdio.h> /* read, printf */
+#include <stdlib.h> /* getenv */
+#include <sys/types.h>
+#include <string.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <malloc.h> /* malloc */
+
+#ifndef SCO_FLAVOR
+# include <sys/time.h> /* struct timeval */
+#endif /* SCO_FLAVOR */
+
+#if HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#include "tty.h" /* move, addch */
+#include "util.h" /* is_printable */
+#include "cons.saver.h"
+
+int rxvt_extensions = 0;
+
+int look_for_rxvt_extensions (void)
+{
+ static int been_called = 0;
+ char *e;
+ if (!been_called) {
+ rxvt_extensions = 0;
+ e = getenv ("RXVT_EXT");
+ if (e)
+ if (!strcmp (e, "1.0"))
+ rxvt_extensions = 1;
+ been_called = 1;
+ }
+ if (rxvt_extensions)
+ console_flag = 4;
+ return rxvt_extensions;
+}
+
+/* my own wierd protocol base 16 - paul */
+static int rxvt_getc (void)
+{
+ int r;
+ unsigned char c;
+ while (read (0, &c, 1) != 1);
+ if (c == '\n')
+ return -1;
+ r = (c - 'A') * 16;
+ while (read (0, &c, 1) != 1);
+ r += (c - 'A');
+ return r;
+}
+
+extern int keybar_visible;
+
+static int anything_ready ()
+{
+ fd_set fds;
+ struct timeval tv;
+
+ FD_ZERO (&fds);
+ FD_SET (0, &fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = 0;
+ return select (1, &fds, 0, 0, &tv);
+}
+
+void show_rxvt_contents (int starty, unsigned char y1, unsigned char y2)
+{
+ unsigned char *k;
+ int bytes, i, j, cols = 0;
+ y1 += (keybar_visible != 0); /* i don't knwo why we need this - paul */
+ y2 += (keybar_visible != 0);
+ while (anything_ready ())
+ getch ();
+
+/* my own wierd protocol base 26 - paul */
+ printf ("\033CL%c%c%c%c\n",
+ (y1 / 26) + 'A', (y1 % 26) + 'A',
+ (y2 / 26) + 'A', (y2 % 26) + 'A');
+
+ bytes = (y2 - y1) * (COLS + 1) + 1; /* *should* be the number of bytes read */
+ j = 0;
+ k = malloc (bytes);
+ for (;;) {
+ int c;
+ c = rxvt_getc ();
+ if (c < 0)
+ break;
+ if (j < bytes)
+ k[j++] = c;
+ for (cols = 1;;cols++) {
+ c = rxvt_getc ();
+ if (c < 0)
+ break;
+ if (j < bytes)
+ k[j++] = c;
+ }
+ }
+ for (i = 0; i < j; i++) {
+ if ((i % cols) == 0)
+ move (starty + (i / cols), 0);
+ addch (is_printable (k[i]) ? k[i] : ' ');
+ }
+ free (k);
+}
+
--- /dev/null
+/* Panel managing.
+ Copyright (C) 1994, 1995 Miguel de Icaza.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Written by: 1995 Miguel de Icaza
+ 1997 Timur Bakeyev
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include "fs.h"
+#include <sys/param.h>
+#include <string.h>
+#include <stdlib.h> /* For malloc() and free() */
+#include <stdio.h>
+#include <errno.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* For chdir(), readlink() and getwd()/getcwd() */
+#endif
+#include "mem.h"
+#include "mad.h"
+#include "global.h"
+#include "dir.h"
+#include "util.h"
+#include "panel.h"
+#include "color.h"
+#include "tree.h"
+#include "win.h"
+#include "main.h"
+#include "ext.h" /* regexp_command */
+#include "mouse.h" /* For Gpm_Event */
+#include "cons.saver.h" /* For console_flag */
+#include "layout.h" /* Most layout variables are here */
+#include "dialog.h" /* for message (...) */
+#include "cmd.h"
+#include "key.h" /* XCTRL and ALT macros */
+#include "setup.h" /* For loading/saving panel options */
+#include "user.h"
+#include "profile.h"
+#include "widget.h"
+#include "../vfs/vfs.h"
+#include "../vfs/extfs.h"
+
+#if defined(OS2_NT)
+# include "drive.h"
+#endif
+
+#include "x.h"
+
+/* "$Id: screen.c,v 1.1 2001/12/30 09:55:21 sedwards Exp $" */
+#define ELEMENTS(arr) ( sizeof(arr) / sizeof((arr)[0]) )
+
+/* If true, show the mini-info on the panel */
+int show_mini_info = 1;
+
+/* If true, then use stat() on the cwd to determine directory changes */
+int fast_reload = 0;
+
+/* If true, use some usability hacks by Torben */
+int torben_fj_mode = 0;
+
+/* If true, up/down keys scroll the pane listing by pages */
+int panel_scroll_pages = 1;
+
+/* If 1, we use permission hilighting */
+int permission_mode = 0;
+
+/* If 1 - then add per file type hilighting */
+int filetype_mode = 1;
+
+
+/* This gives abilitiy to determine colored user priveleges */
+extern user_in_groups *current_user_gid;
+extern uid_t current_user_uid;
+
+/* If we have an info panel, this points to it */
+WPanel *the_info_panel = 0;
+
+/* The hook list for the select file function */
+Hook *select_file_hook = 0;
+
+static int panel_callback (Dlg_head *h, WPanel *p, int Msg, int Par);
+int panel_event (Gpm_Event *event, WPanel *panel);
+
+#ifndef PORT_HAS_PANEL_ADJUST_TOP_FILE
+# define x_adjust_top_file(p)
+#endif
+
+#ifndef PORT_HAS_PANEL_RESET_SORT_LABELS
+# define x_reset_sort_labels(x)
+#endif
+
+/* This macro extracts the number of available lines in a panel */
+#ifndef PORT_HAS_LLINES
+#define llines(p) (p->widget.lines-3 - (show_mini_info ? 2 : 0))
+#else
+#define llines(p) (p->widget.lines)
+#endif
+
+#ifdef PORT_NOT_FOCUS_SELECT_ITEM
+# define focus_select_item(x)
+#else
+# define focus_select_item(x) select_item(x)
+#endif
+
+#ifdef PORT_NOT_UNFOCUS_UNSELECT_ITEM
+# define unfocus_unselect_item(x)
+#else
+# define unfocus_unselect_item(x) unselect_item(x)
+#endif
+
+#ifdef HAVE_X
+# define set_colors(x)
+#else
+# define x_create_panel(x,y,z) 1;
+# define x_panel_load_index(p,x)
+# define x_panel_select_item(a,b,c)
+# define x_panel_destroy(p)
+
+void
+set_colors (WPanel *panel)
+{
+ standend ();
+ if (hascolors)
+ attrset (NORMAL_COLOR);
+}
+#endif
+
+#ifndef ICONS_PER_ROW
+# define ICONS_PER_ROW(x) 1
+#endif
+
+/* Delete format string, it is a linked list */
+void
+delete_format (format_e *format)
+{
+ format_e *next;
+
+ while (format){
+ next = format->next;
+ free (format);
+ format = next;
+ }
+}
+
+/* This code relies on the default justification!!! */
+void
+add_permission_string (char *dest, int width, file_entry *fe, int attr, int color, int is_octal)
+{
+ int i, r, l;
+
+ l = get_user_rights (&fe->buf);
+
+ if (is_octal){
+ /* Place of the access bit in octal mode */
+ l = width + l - 3;
+ r = l + 1;
+ } else {
+ /* The same to the triplet in string mode */
+ l = l * 3 + 1;
+ r = l + 3;
+ }
+
+ for(i = 0; i < width; i++){
+ if (i >= l && i < r){
+ if (attr == SELECTED || attr == MARKED_SELECTED)
+ attrset (MARKED_SELECTED_COLOR);
+ else
+ attrset (MARKED_COLOR);
+ } else
+ attrset (color);
+
+ addch (dest[i]);
+ }
+}
+
+int
+file_entry_color (file_entry *fe)
+{
+ if (filetype_mode){
+ if (S_ISDIR (fe->buf.st_mode))
+ return (DIRECTORY_COLOR);
+ else if (S_ISLNK (fe->buf.st_mode)) {
+ if (fe->f.link_to_dir)
+ return (DIRECTORY_COLOR);
+ else if (fe->f.stalled_link)
+ return (STALLED_COLOR);
+ else
+ return (LINK_COLOR);
+ } else if (S_ISSOCK (fe->buf.st_mode))
+ return (SPECIAL_COLOR);
+ else if (S_ISCHR (fe->buf.st_mode))
+ return (DEVICE_COLOR);
+ else if (S_ISBLK (fe->buf.st_mode))
+ return (DEVICE_COLOR);
+ else if (S_ISFIFO (fe->buf.st_mode))
+ return (SPECIAL_COLOR);
+ else if (is_exe (fe->buf.st_mode))
+ return (EXECUTABLE_COLOR);
+ else if (fe->fname && (strcmp (fe->fname, "core") == 0))
+ return (CORE_COLOR);
+ }
+ return (NORMAL_COLOR);
+}
+
+/* This functions return a string representation of a file entry */
+char *
+string_file_type (file_entry *fe, int len)
+{
+ static char buffer [2];
+
+ if (S_ISDIR (fe->buf.st_mode))
+ buffer [0] = PATH_SEP;
+ else if (S_ISLNK (fe->buf.st_mode)) {
+ if (fe->f.link_to_dir)
+ buffer [0] = '~';
+ else if (fe->f.stalled_link)
+ buffer [0] = '!';
+ else
+ buffer [0] = '@';
+ } else if (S_ISSOCK (fe->buf.st_mode))
+ buffer [0] = '=';
+ else if (S_ISCHR (fe->buf.st_mode))
+ buffer [0] = '-';
+ else if (S_ISBLK (fe->buf.st_mode))
+ buffer [0] = '+';
+ else if (S_ISFIFO (fe->buf.st_mode))
+ buffer [0] = '|';
+ else if (is_exe (fe->buf.st_mode))
+ buffer [0] = '*';
+ else
+ buffer [0] = ' ';
+ buffer [1] = 0;
+ return buffer;
+}
+
+char *
+string_file_size_brief (file_entry *fe, int len)
+{
+ static char buffer [8];
+
+ if (S_ISDIR (fe->buf.st_mode)){
+ strcpy (buffer, (strcmp (fe->fname, "..") ? "SUB-DIR" : "UP--DIR"));
+ return buffer;
+ }
+
+ return string_file_size (fe, len);
+}
+
+char *
+string_file_permission (file_entry *fe, int len)
+{
+ return string_perm (fe->buf.st_mode);
+}
+
+char *
+string_file_nlinks (file_entry *fe, int len)
+{
+ static char buffer [20];
+
+ sprintf (buffer, "%16d", fe->buf.st_nlink);
+ return buffer;
+}
+
+char *
+string_file_owner (file_entry *fe, int len)
+{
+ return get_owner (fe->buf.st_uid);
+}
+
+char *
+string_file_group (file_entry *fe, int len)
+{
+ return get_group (fe->buf.st_gid);
+}
+
+char *
+string_file_size (file_entry *fe, int len)
+{
+ static char buffer [16];
+ int i;
+
+#ifdef HAVE_ST_RDEV
+ if (S_ISBLK (fe->buf.st_mode) || S_ISCHR (fe->buf.st_mode))
+ sprintf (buffer, "%3d,%3d", (int) (fe->buf.st_rdev >> 8),
+ (int) (fe->buf.st_rdev & 0xff));
+ else
+#endif
+ {
+ sprintf (buffer, "%lu", (unsigned long) fe->buf.st_size);
+ if (len && (i = strlen (buffer)) > len) {
+ if (i - 2 > len) {
+ if (i - 5 > len)
+ sprintf (buffer, "%luG", (unsigned long) ((fe->buf.st_size) >> 30));
+ else
+ sprintf (buffer, "%luM", (unsigned long) ((fe->buf.st_size) >> 20));
+ } else
+ sprintf (buffer, "%luK", (unsigned long) ((fe->buf.st_size) >> 10));
+ }
+ }
+ return buffer;
+}
+
+char *
+string_file_mtime (file_entry *fe, int len)
+{
+ return file_date (fe->buf.st_mtime);
+}
+
+char *
+string_file_atime (file_entry *fe, int len)
+{
+ return file_date (fe->buf.st_atime);
+}
+
+char *
+string_file_ctime (file_entry *fe, int len)
+{
+ return file_date (fe->buf.st_ctime);
+}
+
+#ifdef HAVE_GNOME
+/* In GNOME, the CList truncates the names */
+char *
+string_file_name (file_entry *fe, int len)
+{
+ return fe->fname;
+}
+#else
+char *
+string_file_name (file_entry *fe, int len)
+{
+ if (len)
+ return name_trunc (fe->fname, len);
+ else
+ return fe->fname;
+}
+#endif
+
+char *
+string_space (file_entry *fe, int len)
+{
+ return " ";
+}
+
+char *
+string_dot (file_entry *fe, int len)
+{
+ return ".";
+}
+
+char *
+string_marked (file_entry *fe, int len)
+{
+ return fe->f.marked ? "*" : " ";
+}
+
+char *
+string_file_perm_octal (file_entry *fe, int len)
+{
+ static char buffer [9];
+
+ sprintf (buffer, "0%06o", fe->buf.st_mode);
+ return buffer;
+}
+
+char *
+string_inode (file_entry *fe, int len)
+{
+ static char buffer [9];
+
+ sprintf (buffer, "%ld", (long) fe->buf.st_ino);
+ return buffer;
+}
+
+char *
+string_file_ngid (file_entry *fe, int len)
+{
+ static char buffer [9];
+
+ sprintf (buffer, "%d", fe->buf.st_gid);
+ return buffer;
+}
+
+char *
+string_file_nuid (file_entry *fe, int len)
+{
+ static char buffer [9];
+
+ sprintf (buffer, "%d", fe->buf.st_uid);
+ return buffer;
+}
+
+#ifdef HAVE_GNOME
+# define GT 2
+#else
+# define GT 1
+#endif
+
+static struct {
+ char *id;
+ int min_size;
+ int expands;
+ int default_just;
+ char *title;
+ int use_in_gui;
+ char *(*string_fn)(file_entry *, int);
+ sortfn *sort_routine;
+} formats [] = {
+{ "name", 12, 1, J_LEFT, N_("Name"), 1, string_file_name, (sortfn *) sort_name },
+{ "size", 7, 0, J_RIGHT, N_("Size"), 1, string_file_size, (sortfn *) sort_size },
+{ "type", GT, 0, J_LEFT, "", 1, string_file_type, (sortfn *) sort_type },
+{ "mtime", 12, 0, J_RIGHT, N_("MTime"), 1, string_file_mtime, (sortfn *) sort_time },
+{ "bsize", 7, 0, J_RIGHT, N_("Size"), 1, string_file_size_brief, (sortfn *) sort_size },
+{ "perm", 10, 0, J_LEFT, N_("Permission"), 1, string_file_permission, NULL },
+{ "mode", 6, 0, J_RIGHT, N_("Perm"), 1, string_file_perm_octal, NULL },
+{ "|", 1, 0, J_RIGHT, N_("|"), 0, 0, NULL },
+{ "nlink", 2, 0, J_RIGHT, N_("Nl"), 1, string_file_nlinks, (sortfn *) sort_links },
+{ "ngid", 5, 0, J_RIGHT, N_("GID"), 1, string_file_ngid, (sortfn *) sort_ngid },
+{ "nuid", 5, 0, J_RIGHT, N_("UID"), 1, string_file_nuid, (sortfn *) sort_nuid },
+{ "owner", 8, 0, J_LEFT, N_("Owner"), 1, string_file_owner, (sortfn *) sort_owner },
+{ "group", 8, 0, J_LEFT, N_("Group"), 1, string_file_group, (sortfn *) sort_group },
+{ "atime", 12, 0, J_RIGHT, N_("ATime"), 1, string_file_atime, (sortfn *) sort_atime },
+{ "ctime", 12, 0, J_RIGHT, N_("CTime"), 1, string_file_ctime, (sortfn *) sort_ctime },
+{ "space", 1, 0, J_RIGHT, " ", 0, string_space, NULL },
+{ "dot", 1, 0, J_RIGHT, " ", 0, string_dot, NULL },
+{ "mark", 1, 0, J_RIGHT, " ", 1, string_marked, NULL },
+{ "inode", 5, 0, J_RIGHT, N_("Inode"), 1, string_inode, (sortfn *) sort_inode },
+};
+
+static char *
+to_buffer (char *dest, int just_mode, int len, char *txt)
+{
+ int txtlen = strlen (txt);
+ int still;
+
+ if (txtlen > len){
+ if (just_mode != J_LEFT)
+ txt += txtlen - len;
+ txtlen = len;
+ }
+ still = len - txtlen;
+ if (just_mode == J_LEFT){
+ strcpy (dest, txt);
+ dest += txtlen;
+ while (still--)
+ *dest++ = ' ';
+ *dest = 0;
+ } else {
+ while (still--)
+ *dest++ = ' ';
+ strcpy (dest, txt);
+ dest += txtlen;
+ }
+ return dest;
+}
+
+int
+file_compute_color (int attr, file_entry *fe)
+{
+ int color;
+
+ switch (attr){
+ case SELECTED:
+ color = SELECTED_COLOR;
+ break;
+ case MARKED:
+ color = MARKED_COLOR;
+ break;
+ case MARKED_SELECTED:
+ color = MARKED_SELECTED_COLOR;
+ break;
+ case STATUS:
+ color = NORMAL_COLOR;
+ break;
+ case NORMAL:
+ default:
+ color = file_entry_color(fe);
+ }
+ return color;
+}
+
+/* Formats the file number file_index of panel in the buffer dest */
+void
+format_file (char *dest, WPanel *panel, int file_index, int width, int attr, int isstatus)
+{
+ int color, length, empty_line;
+ char *txt;
+ char *old_pos;
+ char *cdest = dest;
+ format_e *format, *home;
+ file_entry *fe;
+
+ length = 0;
+ empty_line = (file_index >= panel->count);
+ home = (isstatus) ? panel->status_format : panel->format;
+ fe = &panel->dir.list [file_index];
+
+ if (!empty_line)
+ color = file_compute_color (attr, fe);
+ else
+ color = NORMAL_COLOR;
+ for (format = home; format; format = format->next){
+ if (format->string_fn){
+ int len;
+
+ if (empty_line)
+ txt = " ";
+ else
+ txt = (*format->string_fn)(fe, format->field_len);
+
+ old_pos = cdest;
+
+ len = format->field_len;
+ if (len + length > width)
+ len = width - length;
+ cdest = to_buffer (cdest, format->just_mode, len, txt);
+ length += len;
+
+#ifdef HAVE_X
+ if (length == width)
+ break;
+#else
+ /* What shall we do? Will we color each line according to
+ * the file type? Any suggestions to mc@timur.kazan.su
+ */
+
+ attrset (color);
+
+ if (permission_mode && !strcmp(format->id, "perm"))
+ add_permission_string (old_pos, format->field_len, fe, attr, color, 0);
+ else if (permission_mode && !strcmp(format->id, "mode"))
+ add_permission_string (old_pos, format->field_len, fe, attr, color, 1);
+ else
+ addstr (old_pos);
+#endif
+ } else {
+#ifndef HAVE_X
+ /* I'm preffer the view without this 3 lines, try to kill it :-) */
+ if (attr == SELECTED || attr == MARKED_SELECTED)
+ attrset (SELECTED_COLOR);
+ else
+ attrset (NORMAL_COLOR);
+ one_vline ();
+#else
+ *cdest++ = ' ';
+#endif
+ length++;
+ }
+ }
+
+ if (length < width){
+ int still = width - length;
+ while (still--)
+#ifdef HAVE_X
+ *cdest++ = ' ';
+ *cdest = 0;
+#else
+ addch (' ');
+#endif
+ }
+}
+
+#ifndef HAVE_X
+void
+repaint_file (WPanel *panel, int file_index, int mv, int attr, int isstatus)
+{
+ int second_column = 0;
+ int width, offset;
+ char buffer [255];
+
+ offset = 0;
+ if (!isstatus && panel->split){
+
+ second_column = (file_index - panel->top_file) / llines (panel);
+ width = (panel->widget.cols - 2)/2 - 1;
+
+ if (second_column){
+ offset = 1 + width;
+ width = (panel->widget.cols-2) - (panel->widget.cols-2)/2 - 1;
+ }
+ } else
+ width = (panel->widget.cols - 2);
+
+ if (mv){
+ if (!isstatus && panel->split){
+ widget_move (&panel->widget,
+ (file_index - panel->top_file) %
+ llines (panel) + 2,
+ (offset + 1));
+ } else
+ widget_move (&panel->widget, file_index - panel->top_file + 2, 1);
+ }
+
+ format_file (buffer, panel, file_index, width, attr, isstatus);
+
+ if (!isstatus && panel->split){
+ if (second_column)
+ addch (' ');
+ else {
+ attrset (NORMAL_COLOR);
+ one_vline ();
+ }
+ }
+}
+#endif
+
+#ifndef PORT_HAS_DISPLAY_MINI_INFO
+void
+display_mini_info (WPanel *panel)
+{
+ if (!show_mini_info)
+ return;
+
+ widget_move (&panel->widget, llines (panel)+3, 1);
+
+ if (panel->searching){
+ attrset (INPUT_COLOR);
+ printw ("/%-*s", panel->widget.cols-3, panel->search_buffer);
+ attrset (NORMAL_COLOR);
+ return;
+ }
+
+ /* Status displays total marked size */
+ if (panel->marked){
+ char buffer [100];
+ char *p;
+
+ attrset (MARKED_COLOR);
+ printw ("%*s", panel->widget.cols-2, " ");
+ widget_move (&panel->widget, llines (panel)+3, 1);
+ sprintf (buffer, _(" %s bytes in %d file%s"),
+ size_trunc_sep (panel->total), panel->marked,
+ panel->marked == 1 ? "" : "s");
+ p = buffer;
+ if (strlen (buffer) > panel->widget.cols-4){
+ buffer [panel->widget.cols-4] = 0;
+ p += 2;
+ }
+ printw ("%-*s", panel->widget.cols-2, p);
+ return;
+ }
+
+ /* Status resolves links and show them */
+ set_colors (panel);
+#ifndef OS2_NT
+ if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)){
+ char *link, link_target [MC_MAXPATHLEN];
+ int len;
+
+ link = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
+ len = mc_readlink (link, link_target, MC_MAXPATHLEN);
+ free (link);
+ if (len > 0){
+ link_target[len] = 0;
+ printw ("-> %-*s", panel->widget.cols - 5,
+ name_trunc (link_target, panel->widget.cols - 5));
+ } else
+ addstr (_("<readlink failed>"));
+ return;
+ }
+#endif
+ /* Default behaviour */
+ repaint_file (panel, panel->selected, 0, STATUS, 1);
+ return;
+}
+#endif
+
+#ifndef HAVE_X
+void
+paint_dir (WPanel *panel)
+{
+ int i;
+ int color; /* Color value of the line */
+ int items; /* Number of items */
+
+ items = llines (panel) * (panel->split ? 2 : 1);
+
+ for (i = 0; i < items; i++){
+ if (i+panel->top_file >= panel->count)
+ color = 0;
+ else {
+ color = 2 * (panel->dir.list [i+panel->top_file].f.marked);
+ color += (panel->selected==i+panel->top_file && panel->active);
+ }
+ repaint_file (panel, i+panel->top_file, 1, color, 0);
+ }
+ standend ();
+ panel->dirty = 0;
+}
+#endif
+
+#ifdef HAVE_X
+#define mini_info_separator(x)
+#else
+static void
+mini_info_separator (WPanel *panel)
+{
+ if (!show_mini_info)
+ return;
+
+ standend ();
+ widget_move (&panel->widget, llines (panel)+2, 1);
+#ifdef HAVE_SLANG
+ attrset (NORMAL_COLOR);
+ hline (ACS_HLINE, panel->widget.cols-2);
+#else
+ hline ((slow_terminal ? '-' : ACS_HLINE) | NORMAL_COLOR,
+ panel->widget.cols-2);
+#endif
+}
+
+void
+show_dir (WPanel *panel)
+{
+ char tmp [200];
+
+ set_colors (panel);
+ draw_double_box (panel->widget.parent,
+ panel->widget.y, panel->widget.x,
+ panel->widget.lines, panel->widget.cols);
+
+#ifdef HAVE_SLANG
+ if (show_mini_info) {
+#ifdef linux_unicode
+ if (SLtt_Unicode) {
+ SLsmg_draw_unicode (panel->widget.y + llines (panel) + 2,
+ panel->widget.x, SLUNI_DSLTEE_CHAR);
+ SLsmg_draw_unicode (panel->widget.y + llines (panel) + 2,
+ panel->widget.x + panel->widget.cols - 1, SLUNI_DSRTEE_CHAR);
+ } else
+#endif /* linux_unicode */
+ {
+ SLsmg_draw_object (panel->widget.y + llines (panel) + 2,
+ panel->widget.x, SLSMG_LTEE_CHAR);
+ SLsmg_draw_object (panel->widget.y + llines (panel) + 2,
+ panel->widget.x + panel->widget.cols - 1, SLSMG_RTEE_CHAR);
+ }
+ }
+#endif /* have_slang */
+
+ if (panel->active)
+ attrset (REVERSE_COLOR);
+
+ widget_move (&panel->widget, 0, 3);
+
+ trim (strip_home_and_password (panel->cwd), tmp, panel->widget.cols-7);
+ addstr (tmp);
+ widget_move (&panel->widget, 0, 1);
+ addstr ("<");
+ widget_move (&panel->widget, 0, panel->widget.cols-2);
+ addstr (">");
+ widget_move (&panel->widget, 0, panel->widget.cols-3);
+ addstr ("v");
+
+ if (panel->active)
+ standend ();
+}
+#endif
+
+#ifndef HAVE_TK
+/* To be used only by long_frame and full_frame to adjust top_file */
+static void
+adjust_top_file (WPanel *panel)
+{
+ int old_top = panel->top_file;
+
+ if (panel->selected - old_top > llines (panel))
+ panel->top_file = panel->selected;
+ if (old_top - panel->count > llines (panel))
+ panel->top_file = panel->count - llines (panel);
+
+#ifdef HAVE_TK
+ if (old_top != panel->top_file)
+ x_adjust_top_file (panel);
+#endif
+}
+#else
+#define adjust_top_file(p)
+#endif
+
+extern void paint_info_panel (WPanel *panel);
+
+/* Repaints the information that changes after a command */
+void
+panel_update_contents (WPanel *panel)
+{
+ show_dir (panel);
+#ifdef HAVE_X
+ x_fill_panel (panel);
+#else
+ paint_dir (panel);
+#endif
+ display_mini_info (panel);
+}
+
+void
+paint_panel (WPanel *panel)
+{
+ paint_frame (panel);
+ panel_update_contents (panel);
+ mini_info_separator (panel);
+}
+
+void
+Xtry_to_select (WPanel *panel, char *name)
+{
+ int i;
+ char *subdir;
+
+ if (!name){
+ panel->selected = 0;
+ panel->top_file = 0;
+ x_adjust_top_file (panel);
+ return;
+ }
+
+ /* We only want the last component of the directory */
+ for (subdir = name + strlen (name) - 1; subdir >= name; subdir--){
+ if (*subdir == PATH_SEP){
+ subdir++;
+ break;
+ }
+ }
+ if (subdir < name)
+ subdir = name;
+
+ /* Search that subdirectory, if found select it */
+ for (i = 0; i < panel->count; i++){
+ if (strcmp (subdir, panel->dir.list [i].fname))
+ continue;
+
+ if (i != panel->selected){
+ panel->selected = i;
+ panel->top_file = panel->selected - (panel->widget.lines-2)/2;
+ if (panel->top_file < 0)
+ panel->top_file = 0;
+ x_adjust_top_file (panel);
+ }
+ return;
+ }
+
+ /* Try to select a file near the file that is missing */
+ if (panel->selected >= panel->count){
+ panel->selected = panel->count-1;
+ panel->top_file = panel->selected - (panel->widget.lines)/2;
+ if (panel->top_file < 0)
+ panel->top_file = 0;
+ x_adjust_top_file (panel);
+ } else
+ return;
+}
+
+#ifndef PORT_HAS_PANEL_UPDATE_COLS
+void
+panel_update_cols (Widget *widget, int frame_size)
+{
+ int cols, origin;
+
+ if (horizontal_split){
+ widget->cols = COLS;
+ return;
+ }
+
+ if (frame_size == frame_full){
+ cols = COLS;
+ origin = 0;
+ } else {
+ if (widget == get_panel_widget (0)){
+ cols = first_panel_size;
+ origin = 0;
+ } else {
+ cols = COLS-first_panel_size;
+ origin = first_panel_size;
+ }
+ }
+
+ widget->cols = cols;
+ widget->x = origin;
+}
+#endif
+
+static char *
+panel_save_name (WPanel *panel)
+{
+ extern int saving_setup;
+
+ /* If the program is shuting down */
+ if ((midnight_shutdown && auto_save_setup) || saving_setup)
+ return copy_strings (panel->panel_name, 0);
+ else
+ return copy_strings ("Temporal:", panel->panel_name, 0);
+}
+
+static void
+panel_destroy (WPanel *p)
+{
+ int i;
+
+ char *name = panel_save_name (p);
+
+ panel_save_setup (p, name);
+ x_panel_destroy (p);
+ clean_dir (&p->dir, p->count);
+
+/* save and clean history */
+ if (p->dir_history){
+ Hist *current, *old;
+ history_put (p->hist_name, p->dir_history);
+ current = p->dir_history;
+ while (current->next)
+ current = current->next;
+ while (current){
+ old = current;
+ current = current->prev;
+ free (old->text);
+ free (old);
+ }
+ }
+ free (p->hist_name);
+
+ delete_format (p->format);
+ delete_format (p->status_format);
+
+ free (p->user_format);
+ for (i = 0; i < LIST_TYPES; i++)
+ free (p->user_status_format [i]);
+ free (p->dir.list);
+ free (p->panel_name);
+ free (name);
+}
+
+static void
+panel_format_modified (WPanel *panel)
+{
+ panel->format_modified = 1;
+ x_reset_sort_labels (panel);
+}
+
+int
+is_a_panel (Widget *w)
+{
+ return (w->callback == (void *) panel_callback);
+}
+
+void directory_history_add (WPanel * panel, char *s);
+
+/* Panel creation */
+/* The parameter specifies the name of the panel for setup retieving */
+WPanel *
+panel_new (char *panel_name)
+{
+ WPanel *panel;
+ char *section;
+ int i, err;
+
+ panel = xmalloc (sizeof (WPanel), "panel_new");
+ memset (panel, 0, sizeof (WPanel));
+
+ /* No know sizes of the panel at startup */
+ init_widget (&panel->widget, 0, 0, 0, 0, (callback_fn)
+ panel_callback, (destroy_fn) panel_destroy,
+ (mouse_h) panel_event, NULL);
+
+ /* We do not want the cursor */
+ widget_want_cursor (panel->widget, 0);
+
+ mc_get_current_wd (panel->cwd, sizeof (panel->cwd)-2);
+ strcpy (panel->lwd, ".");
+
+ panel->hist_name = copy_strings ("Dir Hist ", panel_name, 0);
+ panel->dir_history = history_get (panel->hist_name);
+ directory_history_add (panel, panel->cwd);
+
+ panel->dir.list = (file_entry *) malloc (MIN_FILES * sizeof (file_entry));
+ panel->dir.size = MIN_FILES;
+ panel->active = 0;
+ panel->filter = 0;
+ panel->split = 0;
+ panel->top_file = 0;
+ panel->selected = 0;
+ panel->marked = 0;
+ panel->total = 0;
+ panel->reverse = 0;
+ panel->dirty = 1;
+ panel->searching = 0;
+ panel->dirs_marked = 0;
+ panel->is_panelized = 0;
+ panel->has_dir_sizes = 0;
+ panel->format = 0;
+ panel->status_format = 0;
+ panel->format_modified = 1;
+
+ panel->panel_name = strdup (panel_name);
+ panel->user_format = strdup (DEFAULT_USER_FORMAT);
+
+ for(i = 0; i < LIST_TYPES; i++)
+ panel->user_status_format [i] = strdup (DEFAULT_USER_FORMAT);
+
+ panel->search_buffer [0] = 0;
+ panel->frame_size = frame_half;
+ section = copy_strings ("Temporal:", panel->panel_name, 0);
+ if (!profile_has_section (section, profile_name)){
+ free (section);
+ section = strdup (panel->panel_name);
+ }
+ panel_load_setup (panel, section);
+ free (section);
+
+ /* Load format strings */
+ err = set_panel_formats (panel);
+ if (err){
+ if (err & 0x01){
+ free (panel->user_format);
+ panel->user_format = strdup (DEFAULT_USER_FORMAT);
+ }
+ if (err & 0x02){
+ free (panel->user_status_format [panel->list_type]);
+ panel->user_status_format [panel->list_type] = strdup (DEFAULT_USER_FORMAT);
+ }
+ set_panel_formats (panel);
+ }
+
+ /* Load the default format */
+ panel->count = do_load_dir (&panel->dir, panel->sort_type,
+ panel->reverse, panel->case_sensitive, panel->filter);
+ return panel;
+}
+
+void
+panel_reload (WPanel *panel)
+{
+ int i;
+ struct stat current_stat;
+
+ if (fast_reload
+ && !stat (panel->cwd, ¤t_stat)
+ && current_stat.st_ctime == panel->dir_stat.st_ctime
+ && current_stat.st_mtime == panel->dir_stat.st_mtime)
+ return;
+
+ while (mc_chdir (panel->cwd) == -1){
+ char *last_slash;
+
+ if (panel->cwd [0] == PATH_SEP && panel->cwd [1] == 0){
+ clean_dir (&panel->dir, panel->count);
+ panel->count = set_zero_dir (&panel->dir);
+ return;
+ }
+ last_slash = strrchr (panel->cwd, PATH_SEP);
+ if (!last_slash || last_slash == panel->cwd)
+ strcpy (panel->cwd, PATH_SEP_STR);
+ else
+ *last_slash = 0;
+ bzero (&(panel->dir_stat), sizeof (panel->dir_stat));
+ show_dir (panel);
+ }
+
+ panel->count = do_reload_dir (&panel->dir, panel->sort_type, panel->count,
+ panel->reverse, panel->case_sensitive, panel->filter);
+ panel->marked = 0;
+ panel->dirs_marked = 0;
+ panel->total = 0;
+ panel->has_dir_sizes = 0;
+
+ for (i = 0; i < panel->count; i++)
+ if (panel->dir.list [i].f.marked){
+ /* do_file_mark will return immediately if newmark == oldmark.
+ So we have to first unmark it to get panel's summary information
+ updated. (Norbert) */
+ panel->dir.list [i].f.marked = 0;
+ do_file_mark (panel, i, 1);
+ }
+}
+
+#ifndef PORT_HAS_PAINT_FRAME
+void
+paint_frame (WPanel *panel)
+{
+ int header_len;
+ int spaces, extra;
+ int side, width;
+
+ char *txt, buffer[30]; /*Hope that this is enough ;-) */
+ if (!panel->split)
+ adjust_top_file (panel);
+
+ widget_erase (&panel->widget);
+ show_dir (panel);
+
+ widget_move (&panel->widget, 1, 1);
+
+ for (side = 0; side <= panel->split; side++){
+ format_e *format;
+
+ if (side){
+ attrset (NORMAL_COLOR);
+ one_vline ();
+ width = panel->widget.cols - panel->widget.cols/2 - 1;
+ } else if (panel->split)
+ width = panel->widget.cols/2 - 3;
+ else
+ width = panel->widget.cols - 2;
+
+ for (format = panel->format; format; format = format->next){
+ if (format->string_fn){
+ txt = format->title;
+
+ header_len = strlen (txt);
+ if (header_len > format->field_len){
+ strcpy (buffer, txt);
+ txt = buffer;
+ txt [format->field_len] = 0;
+ header_len = strlen (txt);
+ }
+
+ attrset (MARKED_COLOR);
+ spaces = (format->field_len - header_len) / 2;
+ extra = (format->field_len - header_len) % 2;
+ printw ("%*s%-s%*s", spaces, "",
+ txt, spaces+extra, "");
+ width -= 2 * spaces + extra + header_len;
+ } else {
+ attrset (NORMAL_COLOR);
+ one_vline ();
+ width --;
+ continue;
+ }
+ }
+
+ if (width > 0)
+ printw ("%*s", width, "");
+ }
+}
+#endif
+
+static char *
+parse_panel_size (WPanel *panel, char *format, int isstatus)
+{
+ int frame = frame_half;
+ format = skip_separators (format);
+
+ if (!strncmp (format, "full", 4)){
+ frame = frame_full;
+ format += 4;
+ } else if (!strncmp (format, "half", 4)){
+ frame = frame_half;
+ format += 4;
+ }
+
+ if (!isstatus){
+ panel->frame_size = frame;
+ panel->split = 0;
+ }
+
+ /* Now, the optional column specifier */
+ format = skip_separators (format);
+
+ if (*format == '1' || *format == '2'){
+ if (!isstatus)
+ panel->split = *format == '2';
+ format++;
+ }
+
+ if (!isstatus)
+ panel_update_cols (&(panel->widget), panel->frame_size);
+
+ return skip_separators (format);
+}
+
+/* Format is:
+
+ all := panel_format? format
+ panel_format := [full|half] [1|2]
+ format := one_format_e
+ | format , one_format_e
+
+ one_format_e := just format.id [opt_size]
+ just := [<|>]
+ opt_size := : size [opt_expand]
+ size := [0-9]+
+ opt_expand := +
+
+*/
+
+format_e *
+parse_display_format (WPanel *panel, char *format, char **error, int isstatus, int *res_total_cols)
+{
+ format_e *darr, *old, *home = 0; /* The formats we return */
+ int total_cols = 0; /* Used columns by the format */
+ int set_justify; /* flag: set justification mode? */
+ int justify = 0; /* Which mode. */
+ int items = 0; /* Number of items in the format */
+ int i;
+
+ *error = 0;
+
+ /*
+ * This makes sure that the panel and mini status full/half mode
+ * setting is equal
+ */
+ format = parse_panel_size (panel, format, isstatus);
+
+ while (*format){ /* format can be an empty string */
+ int found = 0;
+
+ darr = xmalloc (sizeof (format_e), "parse_display_format");
+
+ /* I'm so ugly, don't look at me :-) */
+ if (!home)
+ home = old = darr;
+
+ old->next = darr;
+ darr->next = 0;
+ old = darr;
+
+ format = skip_separators (format);
+
+ if (*format == '<' || *format == '>'){
+ set_justify = 1;
+ justify = *format == '<' ? J_LEFT : J_RIGHT;
+ format = skip_separators (format+1);
+ } else
+ set_justify = 0;
+
+ for (i = 0; i < ELEMENTS(formats); i++){
+ int klen = strlen (formats [i].id);
+
+ if (strncmp (format, formats [i].id, klen) != 0)
+ continue;
+
+ format += klen;
+
+ if (formats [i].use_in_gui)
+ items++;
+
+ darr->use_in_gui = formats [i].use_in_gui;
+ darr->requested_field_len = formats [i].min_size;
+ darr->string_fn = formats [i].string_fn;
+ if (formats [i].title [0])
+ darr->title = _(formats [i].title);
+ else
+ darr->title = "";
+ darr->id = formats [i].id;
+ darr->expand = formats [i].expands;
+
+ if (set_justify)
+ darr->just_mode = justify;
+ else
+ darr->just_mode = formats [i].default_just;
+
+ found = 1;
+
+ format = skip_separators (format);
+
+ /* If we have a size specifier */
+ if (*format == ':'){
+ int req_length;
+
+ /* If the size was specified, we don't want
+ * auto-expansion by default
+ */
+ darr->expand = 0;
+ format++;
+ req_length = atoi (format);
+ darr->requested_field_len = req_length;
+
+ format = skip_numbers (format);
+
+ /* Now, if they insist on expansion */
+ if (*format == '+'){
+ darr->expand = 1;
+ format++;
+ }
+
+ }
+
+ break;
+ }
+ if (!found){
+ char old_char;
+
+ int pos = min (8, strlen (format));
+ delete_format (home);
+ old_char = format [pos];
+ format [pos] = 0;
+ *error = copy_strings(_("Unknow tag on display format: "), format, 0);
+ format [pos] = old_char;
+ return 0;
+ }
+ total_cols += darr->requested_field_len;
+ }
+
+ *res_total_cols = total_cols;
+ if (home)
+ home->items = items;
+ return home;
+}
+
+format_e *
+use_display_format (WPanel *panel, char *format, char **error, int isstatus)
+{
+#define MAX_EXPAND 4
+ int expand_top = 0; /* Max used element in expand */
+ int usable_columns; /* Usable columns in the panel */
+ int total_cols;
+ char *expand_list [MAX_EXPAND]; /* Expand at most 4 fields. */
+ int i;
+ format_e *darr, *home;
+
+ if (!format)
+ format = DEFAULT_USER_FORMAT;
+
+ home = parse_display_format (panel, format, error, isstatus, &total_cols);
+
+ if (*error)
+ return 0;
+
+ /* Status needn't to be split */
+ usable_columns = ((panel->widget.cols-2)/((isstatus)
+ ? 1
+ : (panel->split+1))) - (!isstatus && panel->split);
+
+ /* Clean expand list */
+ for (i = 0; i < MAX_EXPAND; i++)
+ expand_list [i] = '\0';
+
+
+ /* Look for the expandable fields and set field_len based on the requested field len */
+ for (darr = home; darr && expand_top < MAX_EXPAND; darr = darr->next){
+ darr->field_len = darr->requested_field_len;
+ if (darr->expand)
+ expand_list [expand_top++] = darr->id;
+ }
+
+ /* If we used more columns than the available columns, adjust that */
+ if (total_cols > usable_columns){
+ int pdif, dif = total_cols - usable_columns;
+
+ while (dif){
+ pdif = dif;
+ for (darr = home; darr; darr = darr->next){
+ if (dif && darr->field_len - 1){
+ darr->field_len--;
+ dif--;
+ }
+ }
+
+ /* avoid endless loop if num fields > 40 */
+ if (pdif == dif)
+ break;
+ }
+ total_cols = usable_columns; /* give up, the rest should be truncated */
+ }
+
+ /* Expand the available space */
+ if ((usable_columns > total_cols) && expand_top){
+ int spaces = (usable_columns - total_cols) / expand_top;
+ int extra = (usable_columns - total_cols) % expand_top;
+
+ for (i = 0, darr = home; darr && (i < expand_top); darr = darr->next)
+ if (darr->expand){
+ darr->field_len += (spaces + ((i == 0) ? extra : 0));
+ i++;
+ }
+ }
+ return home;
+}
+
+/* Switches the panel to the mode specified in the format */
+/* Seting up both format and status string. Return: 0 - on success; */
+/* 1 - format error; 2 - status error; 3 - errors in both formats. */
+int
+set_panel_formats (WPanel *p)
+{
+ format_e *form;
+ char *err;
+ int retcode = 0;
+
+ form = use_display_format (p, panel_format (p), &err, 0);
+
+ if (err){
+ free (err);
+ retcode = 1;
+ }
+ else {
+ if (p->format)
+ delete_format (p->format);
+
+ p->format = form;
+ }
+
+ if (show_mini_info){
+
+ form = use_display_format (p, mini_status_format (p), &err, 1);
+
+ if (err){
+ free (err);
+ retcode += 2;
+ }
+ else {
+ if (p->status_format)
+ delete_format (p->status_format);
+
+ p->status_format = form;
+ }
+ }
+
+ panel_format_modified (p);
+ panel_update_cols (&(p->widget), p->frame_size);
+
+ return retcode;
+}
+
+/* Given the panel->view_type returns the format string to be parsed */
+char *
+panel_format (WPanel *panel)
+{
+ switch (panel->list_type){
+
+ case list_long:
+ return "full perm,space,nlink,space,owner,space,group,space,size,space,mtime,space,name";
+
+ case list_brief:
+ return "half 2,type,name";
+
+ case list_user:
+ return panel->user_format;
+
+ default:
+ case list_full:
+ return "half type,name,|,size,|,mtime";
+ }
+}
+
+char *
+mini_status_format (WPanel *panel)
+{
+ if (panel->user_mini_status)
+ return panel->user_status_format [panel->list_type];
+
+ switch (panel->list_type){
+
+ case list_long:
+ return "full perm,space,nlink,space,owner,space,group,space,size,space,mtime,space,name";
+
+ case list_brief:
+ return "half type,name,space,bsize,space,perm,space";
+
+ case list_full:
+ return "half type,name";
+
+ default:
+ case list_user:
+ return panel->user_format;
+ }
+}
+
+/* */
+/* Panel operation commands */
+/* */
+
+/* Returns the number of items in the given panel */
+int
+ITEMS (WPanel *p)
+{
+#ifdef HAVE_TK
+ return p->widget.lines;
+#else
+ if (p->split)
+ return llines (p) * 2;
+ else
+ return llines (p);
+#endif
+}
+
+/* This function sets redisplays the selection */
+void
+select_item (WPanel *panel)
+{
+ int repaint = 0;
+ int items = ITEMS (panel);
+
+ /* Although currently all over the code we set the selection and
+ top file to decent values before calling select_item, I could
+ forget it someday, so it's better to do the actual fitting here */
+
+#ifdef HAVE_X
+ int old_top;
+ old_top = panel->top_file;
+#endif
+
+ if (panel->top_file < 0){
+ repaint = 1;
+ panel->top_file = 0;
+ }
+
+ if (panel->selected < 0)
+ panel->selected = 0;
+
+ if (panel->selected > panel->count-1)
+ panel->selected = panel->count - 1;
+
+ if (panel->top_file > panel->count-1){
+ repaint = 1;
+ panel->top_file = panel->count-1;
+ }
+
+ if ((panel->count - panel->top_file) < items){
+ repaint = 1;
+ panel->top_file = panel->count - items;
+ if (panel->top_file < 0)
+ panel->top_file = 0;
+ }
+
+ if (panel->selected < panel->top_file){
+ repaint = 1;
+ panel->top_file = panel->selected;
+ }
+
+ if ((panel->selected - panel->top_file) >= items){
+ repaint = 1;
+ panel->top_file = panel->selected - items + 1;
+ }
+
+#ifndef HAVE_X
+ if (repaint)
+ paint_panel (panel);
+ else
+ repaint_file (panel, panel->selected, 1, 2*selection (panel)->f.marked+1, 0);
+#else
+ if (old_top != panel->top_file)
+ x_adjust_top_file (panel);
+ x_select_item (panel);
+#endif
+
+ display_mini_info (panel);
+
+ execute_hooks (select_file_hook);
+}
+
+/* Clears all files in the panel, used only when one file was marked */
+void
+unmark_files (WPanel *panel)
+{
+ int i;
+
+ if (!panel->marked)
+ return;
+ for (i = 0; i < panel->count; i++)
+ file_mark (panel, i, 0);
+
+ panel->dirs_marked = 0;
+ panel->marked = 0;
+ panel->total = 0;
+}
+
+#ifdef HAVE_X
+void
+unselect_item (WPanel *panel)
+{
+ x_unselect_item (panel);
+}
+#else
+void
+unselect_item (WPanel *panel)
+{
+ repaint_file (panel, panel->selected, 1, 2*selection (panel)->f.marked, 0);
+}
+#endif
+
+static void
+do_move_down (WPanel *panel)
+{
+ if (panel->selected+1 == panel->count)
+ return;
+
+ unselect_item (panel);
+ panel->selected++;
+
+#ifndef HAVE_X
+ if (panel->selected - panel->top_file == ITEMS (panel) &&
+ panel_scroll_pages){
+ /* Scroll window half screen */
+ panel->top_file += ITEMS (panel)/2;
+ if (panel->top_file > panel->count - ITEMS (panel))
+ panel->top_file = panel->count - ITEMS (panel);
+ paint_dir (panel);
+ select_item (panel);
+ }
+#endif
+ select_item (panel);
+}
+
+static void
+do_move_up (WPanel *panel)
+{
+ if (panel->selected == 0)
+ return;
+
+ unselect_item (panel);
+ panel->selected--;
+#ifndef HAVE_X
+ if (panel->selected < panel->top_file && panel_scroll_pages){
+ /* Scroll window half screen */
+ panel->top_file -= ITEMS (panel)/2;
+ if (panel->top_file < 0) panel->top_file = 0;
+ paint_dir (panel);
+ }
+#endif
+ select_item (panel);
+}
+
+static int
+move_rel (WPanel *panel, int rel)
+{
+ unselect_item (panel);
+
+ if (rel < 0){
+ if (panel->selected + rel < 0)
+ panel->selected = 0;
+ else
+ panel->selected = panel->selected + rel;
+ } else {
+ if (panel->selected + rel >= panel->count)
+ panel->selected = panel->count - 1;
+ else
+ panel->selected = panel->selected + rel;
+ }
+ select_item (panel);
+}
+
+/* */
+/* Panel key binded commands */
+/* */
+static void
+move_up (WPanel *panel)
+{
+ if (panel->list_type == list_icons){
+ move_rel (panel, -ICONS_PER_ROW (panel));
+ } else
+ do_move_up (panel);
+}
+
+static void
+move_down (WPanel *panel)
+{
+ if (panel->list_type == list_icons){
+ move_rel (panel, ICONS_PER_ROW (panel));
+ } else
+ do_move_down (panel);
+}
+
+/* Changes the selection by lines (may be negative) */
+static void
+move_selection (WPanel *panel, int lines)
+{
+ int new_pos;
+ int adjust = 0;
+
+ new_pos = panel->selected + lines;
+ if (new_pos >= panel->count)
+ new_pos = panel->count-1;
+
+ if (new_pos < 0)
+ new_pos = 0;
+
+ unselect_item (panel);
+ panel->selected = new_pos;
+
+#ifndef HAVE_X
+ if (panel->selected - panel->top_file >= ITEMS (panel)){
+ panel->top_file += lines;
+ adjust = 1;
+ }
+
+ if (panel->selected - panel->top_file < 0){
+ panel->top_file += lines;
+ adjust = 1;
+ }
+
+ if (adjust){
+ if (panel->top_file > panel->selected)
+ panel->top_file = panel->selected;
+ if (panel->top_file < 0)
+ panel->top_file = 0;
+ paint_dir (panel);
+ }
+#endif
+ select_item (panel);
+}
+
+static int
+move_left (WPanel *panel, int c_code)
+{
+ if (panel->list_type == list_icons){
+ do_move_up (panel);
+ return 1;
+ } else {
+ if (panel->split){
+ move_selection (panel, -llines (panel));
+ return 1;
+ } else
+ return maybe_cd (c_code, 0);
+ }
+}
+
+static int
+move_right (WPanel *panel, int c_code)
+{
+ if (panel->list_type == list_icons){
+ do_move_down (panel);
+ return 1;
+ } else {
+ if (panel->split){
+ move_selection (panel, llines (panel));
+ return 1;
+ } else
+ return maybe_cd (c_code, 1);
+ }
+}
+
+static void
+prev_page (WPanel *panel)
+{
+ int items;
+
+ if (!panel->selected && !panel->top_file)
+ return;
+ unselect_item (panel);
+ items = ITEMS (panel);
+ if (panel->top_file < items)
+ items = panel->top_file;
+ if (!items)
+ panel->selected = 0;
+ else
+ panel->selected -= items;
+ panel->top_file -= items;
+
+ /* This keeps the selection in a reasonable place */
+ if (panel->selected < 0)
+ panel->selected = 0;
+ if (panel->top_file < 0)
+ panel->top_file = 0;
+ x_adjust_top_file (panel);
+ select_item (panel);
+#ifndef HAVE_X
+ paint_dir (panel);
+#endif
+}
+
+static void
+prev_page_key (WPanel *panel)
+{
+ if (console_flag && ctrl_pressed ()){
+ do_cd ("..", cd_exact);
+ } else
+ prev_page (panel);
+}
+
+static void
+next_page (WPanel *panel)
+{
+ int items;
+
+ if (panel->selected == panel->count - 1)
+ return;
+ unselect_item (panel);
+ items = ITEMS (panel);
+ if (panel->top_file > panel->count - 2 * items)
+ items = panel->count - items - panel->top_file;
+ if (panel->top_file + items < 0)
+ items = - panel->top_file;
+ if (!items)
+ panel->selected = panel->count - 1;
+ else
+ panel->selected += items;
+ panel->top_file += items;
+
+ /* This keeps the selection in it's relative position */
+ if (panel->selected >= panel->count)
+ panel->selected = panel->count - 1;
+ if (panel->top_file >= panel->count)
+ panel->top_file = panel->count - 1;
+ x_adjust_top_file (panel);
+ select_item (panel);
+#ifndef HAVE_X
+ paint_dir (panel);
+#endif
+}
+
+static void next_page_key (WPanel *panel)
+{
+ if (console_flag&&ctrl_pressed()&&
+ (S_ISDIR(selection (panel)->buf.st_mode) ||
+ link_isdir (selection (panel))))
+ do_cd (selection (panel)->fname, cd_exact);
+ else
+ next_page (panel);
+}
+
+static void
+goto_top_file (WPanel *panel)
+{
+ unselect_item (panel);
+ panel->selected = panel->top_file;
+ select_item (panel);
+}
+
+static void
+goto_middle_file (WPanel *panel)
+{
+ unselect_item (panel);
+ panel->selected = panel->top_file + (ITEMS (panel)/2);
+ if (panel->selected >= panel->count)
+ panel->selected = panel->count - 1;
+ select_item (panel);
+}
+
+static void
+goto_bottom_file (WPanel *panel)
+{
+ unselect_item (panel);
+ panel->selected = panel->top_file + ITEMS (panel)-1;
+ if (panel->selected >= panel->count)
+ panel->selected = panel->count - 1;
+ select_item (panel);
+}
+
+static void
+move_home (WPanel *panel)
+{
+ if (panel->selected == 0)
+ return;
+ unselect_item (panel);
+
+ if (torben_fj_mode){
+ int middle_pos = panel->top_file + (ITEMS (panel)/2);
+
+ if (panel->selected > middle_pos){
+ goto_middle_file (panel);
+ return;
+ }
+ if (panel->selected != panel->top_file){
+ goto_top_file (panel);
+ return;
+ }
+ }
+
+ panel->top_file = 0;
+ panel->selected = 0;
+
+#ifndef HAVE_X
+ paint_dir (panel);
+#endif
+ select_item (panel);
+}
+
+static void
+move_end (WPanel *panel)
+{
+ if (panel->selected == panel->count-1)
+ return;
+ unselect_item (panel);
+ if (torben_fj_mode){
+ int middle_pos = panel->top_file + (ITEMS (panel)/2);
+
+ if (panel->selected < middle_pos){
+ goto_middle_file (panel);
+ return;
+ }
+ if (panel->selected != (panel->top_file + ITEMS(panel)-1)){
+ goto_bottom_file (panel);
+ return;
+ }
+ }
+
+ panel->selected = panel->count-1;
+#ifndef HAVE_X
+ paint_dir (panel);
+#endif
+ select_item (panel);
+}
+
+/* This routine marks a file or a directory */
+void
+do_file_mark (WPanel *panel, int idx, int mark)
+{
+ if (panel->dir.list [idx].f.marked == mark)
+ return;
+ /*
+ * Only '..' can't be marked, '.' isn't visible.
+ */
+ if (strcmp (panel->dir.list [idx].fname, "..")){
+ file_mark (panel, idx, mark);
+ if (panel->dir.list [idx].f.marked){
+ panel->marked++;
+ if (S_ISDIR (panel->dir.list [idx].buf.st_mode)) {
+ if (panel->has_dir_sizes)
+ panel->total += panel->dir.list [idx].buf.st_size;
+ panel->dirs_marked++;
+ } else
+ panel->total += panel->dir.list [idx].buf.st_size;
+#ifndef HAVE_XVIEW
+ set_colors (panel);
+#endif
+ } else {
+ if (S_ISDIR(panel->dir.list [idx].buf.st_mode)) {
+ if (panel->has_dir_sizes)
+ panel->total -= panel->dir.list [idx].buf.st_size;
+ panel->dirs_marked--;
+ } else
+ panel->total -= panel->dir.list [idx].buf.st_size;
+ panel->marked--;
+ }
+ }
+}
+
+void
+do_file_mark_range (WPanel *panel, int r1, int r2)
+{
+ const int start = min (r1, r2);
+ const int end = max (r1, r2);
+ int i, mark;
+
+ mark = !panel->dir.list [start].f.marked;
+
+ for (i = start; i < end; i++)
+ do_file_mark (panel, i, mark);
+}
+
+static void
+do_mark_file (WPanel *panel, int do_move)
+{
+ int idx = panel->selected;
+ do_file_mark (panel, idx, selection (panel)->f.marked ? 0 : 1);
+#ifndef HAVE_XVIEW
+ repaint_file (panel, idx, 1, 2*panel->dir.list [idx].f.marked+1, 0);
+#endif
+
+ if (mark_moves_down && do_move)
+ move_down (panel);
+ display_mini_info (panel);
+}
+
+static void
+mark_file (WPanel *panel)
+{
+ do_mark_file (panel, 1);
+}
+
+/* Incremental search of a file name in the panel */
+static void
+do_search (WPanel *panel, int c_code)
+{
+ int l, i;
+ int wrapped = 0;
+ int found;
+
+ l = strlen (panel->search_buffer);
+ if (l && (c_code == 8 || c_code == 0177 || c_code == KEY_BACKSPACE))
+ panel->search_buffer [--l] = 0;
+ else {
+ if (c_code && l < sizeof (panel->search_buffer)){
+ panel->search_buffer [l] = c_code;
+ panel->search_buffer [l+1] = 0;
+ l++;
+ }
+ }
+
+ found = 0;
+ for (i = panel->selected; !wrapped || i != panel->selected; i++){
+ if (i >= panel->count){
+ i = 0;
+ if (wrapped)
+ break;
+ wrapped = 1;
+ }
+ if (STRNCOMP (panel->dir.list [i].fname, panel->search_buffer, l) == 0){
+ unselect_item (panel);
+ panel->selected = i;
+ select_item (panel);
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ panel->search_buffer [--l] = 0;
+#ifndef HAVE_X
+ paint_panel (panel);
+#endif
+}
+
+static void
+start_search (WPanel *panel)
+{
+ if (panel->searching){
+ if (panel->selected+1 == panel->count)
+ panel->selected = 0;
+ else
+ move_down (panel);
+ do_search (panel, 0);
+ } else {
+ panel->searching = 1;
+ panel->search_buffer [0] = 0;
+ display_mini_info (panel);
+ mc_refresh ();
+ }
+}
+
+int
+do_enter (WPanel *panel)
+{
+ if (S_ISDIR (selection (panel)->buf.st_mode)
+ || link_isdir (selection (panel))){
+ do_cd (selection (panel)->fname, cd_exact);
+ return 1;
+ } else {
+ if (is_exe (selection (panel)->buf.st_mode) &&
+ if_link_is_exe (selection (panel))) {
+#ifdef USE_VFS
+ if (vfs_current_is_local ())
+#endif
+ {
+ char *tmp = name_quote (selection (panel)->fname, 0);
+ char *cmd = copy_strings (".", PATH_SEP_STR, tmp, 0);
+ if (!confirm_execute || (query_dialog (_(" The Midnight Commander "),
+ _(" Do you really want to execute? "),
+ 0, 2, _("&Yes"), _("&No")) == 0))
+ execute (cmd);
+ free (tmp);
+ free (cmd);
+ }
+#ifdef USE_VFS
+ else if (vfs_current_is_extfs ()) {
+ char *tmp = vfs_get_current_dir();
+ char *tmp2;
+
+ tmp2 = concat_dir_and_file (tmp, selection (panel)->fname);
+ extfs_run(tmp2);
+ free (tmp2);
+ }
+#endif /* USE_VFS */
+ return 1;
+ } else {
+ char *p;
+
+ p = regex_command (selection (panel)->fname, "Open", NULL, 0);
+ if (p && (strcmp (p, "Success") == 0))
+ return 1;
+ else
+ return 0;
+ }
+ }
+}
+
+static void
+chdir_other_panel (WPanel *panel)
+{
+ char *new_dir;
+
+ if (get_other_type () != view_listing)
+ return;
+
+ if (!S_ISDIR (panel->dir.list [panel->selected].buf.st_mode))
+ new_dir = concat_dir_and_file (panel->cwd, "..");
+ else
+ new_dir = concat_dir_and_file (panel->cwd, panel->dir.list [panel->selected].fname);
+
+ change_panel ();
+ do_cd (new_dir, cd_exact);
+ change_panel ();
+
+ move_down (panel);
+
+ free (new_dir);
+}
+
+static void
+chdir_to_readlink (WPanel *panel)
+{
+ char *new_dir;
+
+ if (get_other_type () != view_listing)
+ return;
+
+ if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)) {
+ char buffer [MC_MAXPATHLEN], *p;
+ int i;
+ struct stat mybuf;
+
+ i = readlink (selection (panel)->fname, buffer, MC_MAXPATHLEN);
+ if (i < 0)
+ return;
+ if (mc_stat (selection (panel)->fname, &mybuf) < 0)
+ return;
+ buffer [i] = 0;
+ if (!S_ISDIR (mybuf.st_mode)) {
+ p = strrchr (buffer, PATH_SEP);
+ if (p && !p[1]) {
+ *p = 0;
+ p = strrchr (buffer, PATH_SEP);
+ }
+ if (!p)
+ return;
+ p[1] = 0;
+ }
+ if (*buffer == PATH_SEP)
+ new_dir = strdup (buffer);
+ else
+ new_dir = concat_dir_and_file (panel->cwd, buffer);
+
+ change_panel ();
+ do_cd (new_dir, cd_exact);
+ change_panel ();
+
+ move_down (panel);
+
+ free (new_dir);
+ }
+}
+
+static key_map panel_keymap [] = {
+ { KEY_DOWN, move_down },
+ { KEY_UP, move_up },
+
+ /* The action button :-) */
+ { '\n', do_enter },
+ { KEY_ENTER, do_enter },
+
+ { KEY_IC, mark_file },
+ { KEY_HOME, move_home },
+ { KEY_C1, move_end },
+ { KEY_END, move_end },
+ { KEY_A1, move_home },
+ { KEY_NPAGE, next_page_key },
+ { KEY_PPAGE, prev_page_key },
+
+ /* To quickly move in the panel */
+ { ALT('g'), goto_top_file },
+ { ALT('r'), goto_middle_file }, /* M-r like emacs */
+ { ALT('j'), goto_bottom_file },
+
+#ifdef OS2_NT
+ { ALT(KEY_F(11)), drive_cmd_a },
+ { ALT(KEY_F(12)), drive_cmd_b },
+ { ALT('d'), drive_chg },
+#endif
+
+ /* Emacs-like bindings */
+ { XCTRL('v'), next_page }, /* C-v like emacs */
+ { ALT('v'), prev_page }, /* M-v like emacs */
+ { XCTRL('p'), move_up }, /* C-p like emacs */
+ { XCTRL('n'), move_down }, /* C-n like emacs */
+ { XCTRL('s'), start_search }, /* C-s like emacs */
+ { ALT('s'), start_search }, /* M-s not like emacs */
+ { XCTRL('t'), mark_file },
+ { ALT('o'), chdir_other_panel },
+ { ALT('l'), chdir_to_readlink },
+ { KEY_F(13), view_simple_cmd },
+ { KEY_F(14), edit_cmd_new },
+ { ALT('y'), directory_history_prev },
+ { ALT('u'), directory_history_next },
+ { ALT('H'), directory_history_list },
+ { ALT('+'), select_cmd_panel },
+ { KEY_KP_ADD, select_cmd_panel },
+ { ALT('\\'), unselect_cmd_panel },
+ { ALT('-'), unselect_cmd_panel },
+ { KEY_KP_SUBTRACT, unselect_cmd_panel },
+ { ALT('*'), reverse_selection_cmd_panel },
+ { KEY_KP_MULTIPLY, reverse_selection_cmd_panel },
+
+
+#ifdef HAVE_GNOME
+ { '+', select_cmd_panel },
+ { '\\', unselect_cmd_panel },
+ { '-', unselect_cmd_panel },
+ { '*', reverse_selection_cmd_panel },
+ { XCTRL('r'), reread_cmd },
+ { KEY_F(3), view_panel_cmd },
+ { KEY_F(5), copy_cmd },
+ { KEY_F(6), ren_cmd },
+ { KEY_F(7), mkdir_panel_cmd },
+ { KEY_F(8), delete_cmd },
+#endif
+
+ { 0, 0 }
+};
+
+static inline int
+panel_key (WPanel *panel, int key)
+{
+ int i;
+
+ for (i = 0; panel_keymap [i].key_code; i++){
+ if (key == panel_keymap [i].key_code){
+ if (panel_keymap [i].fn != start_search)
+ panel->searching = 0;
+ (*panel_keymap [i].fn)(panel);
+ return 1;
+ }
+ }
+ if (torben_fj_mode && key == ALT('h')) {
+ goto_middle_file (panel);
+ return 1;
+ }
+
+ /* We do not want to take a key press if nothing can be done with it */
+ /* The command line widget may do something more usefull */
+ if (key == KEY_LEFT)
+ return move_left (panel, key);
+
+ if (key == KEY_RIGHT)
+ return move_right (panel, key);
+
+ if (is_abort_char (key)) {
+ panel->searching = 0;
+ display_mini_info (panel);
+ return 1;
+ }
+
+ /* Do not eat characters not meant for the panel below ' ' (e.g. C-l). */
+ if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
+ if (panel->searching){
+ do_search (panel, key);
+ return 1;
+ }
+
+ if (!command_prompt) {
+ start_search (panel);
+ do_search (panel, key);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int
+panel_callback (Dlg_head *h, WPanel *panel, int msg, int par)
+{
+ switch (msg){
+ case WIDGET_INIT:
+#ifdef HAVE_X
+ define_label (h, (Widget *)panel, 1, _("Help"), help_cmd);
+ define_label (h, (Widget *)panel, 2, _("Menu"), user_menu_cmd);
+ define_label (h, (Widget *)panel, 3, _("View"), view_panel_cmd);
+ define_label (h, (Widget *)panel, 4, _("Edit"), edit_panel_cmd);
+ define_label (h, (Widget *)panel, 5, _("Copy"), copy_cmd);
+ define_label (h, (Widget *)panel, 6, _("RenMov"), ren_cmd);
+ define_label (h, (Widget *)panel, 7, _("Mkdir"), mkdir_panel_cmd);
+ define_label (h, (Widget *)panel, 8, _("Delete"), delete_cmd);
+ x_create_panel (h, h->wdata, panel);
+#endif
+ return 1;
+
+ case WIDGET_DRAW:
+#ifndef HAVE_XVIEW
+ paint_panel (panel);
+#else
+ show_dir (panel);
+#endif
+ break;
+
+ case WIDGET_FOCUS:
+#ifndef HAVE_GNOME
+ current_panel = panel;
+#endif
+ panel->active = 1;
+ if (mc_chdir (panel->cwd) != 0){
+ message (1, " Error ", " Can't chdir to %s \n %s ",
+ panel->cwd, unix_error_string (errno));
+ } else
+ subshell_chdir (panel->cwd);
+
+ show_dir (panel);
+ focus_select_item (panel);
+#ifndef HAVE_X
+ define_label (h, (Widget *)panel, 1, _("Help"), help_cmd);
+ define_label (h, (Widget *)panel, 2, _("Menu"), user_menu_cmd);
+ define_label (h, (Widget *)panel, 3, _("View"), view_panel_cmd);
+ define_label (h, (Widget *)panel, 4, _("Edit"), edit_panel_cmd);
+ define_label (h, (Widget *)panel, 5, _("Copy"), copy_cmd);
+ define_label (h, (Widget *)panel, 6, _("RenMov"), ren_cmd);
+ define_label (h, (Widget *)panel, 7, _("Mkdir"), mkdir_panel_cmd);
+ define_label (h, (Widget *)panel, 8, _("Delete"), delete_cmd);
+ redraw_labels (h, (Widget *)panel);
+#endif
+ /* Chain behaviour */
+ default_proc (h, WIDGET_FOCUS, par);
+ return 1;
+
+ case WIDGET_UNFOCUS:
+ /* Janne: look at this for the multiple panel options */
+ if (panel->searching){
+ panel->searching = 0;
+ display_mini_info (panel);
+ }
+#ifdef HAVE_X
+ show_dir (panel);
+ unfocus_unselect_item (panel);
+ panel->active = 0;
+#else
+ panel->active = 0;
+ show_dir (panel);
+ unselect_item (panel);
+#endif
+ return 1;
+
+ case WIDGET_KEY:
+ return panel_key (panel, par);
+ break;
+ }
+ return default_proc (h, msg, par);
+}
+
+/* */
+/* Panel mouse events support routines */
+/* */
+static int mouse_marking = 0;
+
+static void
+mouse_toggle_mark (WPanel *panel)
+{
+ do_mark_file (panel, 0);
+ mouse_marking = selection (panel)->f.marked;
+}
+
+static void
+mouse_set_mark (WPanel *panel)
+{
+ if (mouse_marking && !(selection (panel)->f.marked))
+ do_mark_file (panel, 0);
+ else if (!mouse_marking && (selection (panel)->f.marked))
+ do_mark_file (panel, 0);
+}
+
+static inline int
+mark_if_marking (WPanel *panel, Gpm_Event *event)
+{
+ if (event->buttons & GPM_B_RIGHT){
+ if (event->type & GPM_DOWN)
+ mouse_toggle_mark (panel);
+ else
+ mouse_set_mark (panel);
+ return 1;
+ }
+ return 0;
+}
+
+void
+file_mark (WPanel *panel, int index, int val)
+{
+ panel->dir.list [index].f.marked = val;
+ x_panel_select_item (panel, index, val);
+}
+
+#ifdef PORT_WANTS_GET_SORT_FN
+sortfn *
+get_sort_fn (char *name)
+{
+ int i;
+
+ /* First, try the long name options, from dir.c */
+ for (i = 0; i < SORT_TYPES_TOTAL; i++)
+ if (strcmp (name, sort_orders [i].sort_name) == 0)
+ return (sortfn *)sort_orders [i].sort_fn;
+
+ /* Then try the short name options, from our local table */
+ for (i = 0; i < ELEMENTS (formats); i++){
+ if (strcmp (name, formats [i].id) == 0 && formats [i].sort_routine)
+ return formats [i].sort_routine;
+ }
+ return NULL;
+}
+
+/* not static because it's called from Tk's version */
+int
+panel_event (Gpm_Event *event, WPanel *panel)
+{
+ const int lines = panel->count;
+
+ int my_index;
+ extern void change_panel (void);
+
+ event->y -= 2;
+ if ((event->type & (GPM_DOWN|GPM_DRAG))){
+
+ if (panel != (WPanel *) current_dlg->current->widget)
+ change_panel ();
+
+ if (event->y <= 0){
+ mark_if_marking (panel, event);
+ return MOU_REPEAT;
+ }
+
+ if (!((panel->top_file + event->y <= panel->count) &&
+ event->y <= lines)){
+ mark_if_marking (panel, event);
+ return MOU_REPEAT;
+ }
+ my_index = panel->top_file + event->y - 1;
+ if (panel->split){
+ if (event->x > ((panel->widget.cols-2)/2))
+ my_index += llines (panel);
+ }
+
+ if (my_index >= panel->count)
+ my_index = panel->count - 1;
+
+ if (my_index != panel->selected){
+ unselect_item (panel);
+ panel->selected = my_index;
+ select_item (panel);
+ }
+
+ /* This one is new */
+ mark_if_marking (panel, event);
+
+ } else if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
+ if (event->y > 0 && event->y <= lines)
+ do_enter (panel);
+ }
+ return MOU_NORMAL;
+}
+
+#else
+
+int
+panel_event (Gpm_Event *event, WPanel *panel)
+{
+ const int lines = llines (panel);
+
+ int my_index;
+ extern void change_panel (void);
+
+ if (event->type & GPM_DOWN && event->x == 1 + 1 && event->y == 0 + 1) {
+ directory_history_prev (panel);
+ return MOU_NORMAL;
+ }
+
+ if (event->type & GPM_DOWN && event->x == panel->widget.cols - 2 + 1 && event->y == 0 + 1) {
+ directory_history_next (panel);
+ return MOU_NORMAL;
+ }
+
+ if (event->type & GPM_DOWN && event->x == panel->widget.cols - 3 + 1 && event->y == 0 + 1) {
+ directory_history_list (panel);
+ return MOU_NORMAL;
+ }
+
+ event->y -= 2;
+ if ((event->type & (GPM_DOWN|GPM_DRAG))){
+
+ if (panel != (WPanel *) current_dlg->current->widget)
+ change_panel ();
+
+ if (event->y <= 0){
+ mark_if_marking (panel, event);
+ if (mouse_move_pages)
+ prev_page (panel);
+ else
+ move_up (panel);
+ return MOU_REPEAT;
+ }
+
+ if (!((panel->top_file + event->y <= panel->count) &&
+ event->y <= lines)){
+ mark_if_marking (panel, event);
+ if (mouse_move_pages)
+ next_page (panel);
+ else
+ move_down (panel);
+ return MOU_REPEAT;
+ }
+ my_index = panel->top_file + event->y - 1;
+ if (panel->split){
+ if (event->x > ((panel->widget.cols-2)/2))
+ my_index += llines (panel);
+ }
+
+ if (my_index >= panel->count)
+ my_index = panel->count - 1;
+
+ if (my_index != panel->selected){
+ unselect_item (panel);
+ panel->selected = my_index;
+ select_item (panel);
+ }
+
+ /* This one is new */
+ mark_if_marking (panel, event);
+
+ } else if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
+ if (event->y > 0 && event->y <= lines)
+ do_enter (panel);
+ }
+ return MOU_NORMAL;
+}
+#endif
+
+void
+panel_update_marks (WPanel *panel)
+{
+#ifdef PORT_HAS_UPDATE_MARKS
+ x_panel_update_marks (panel);
+#endif
+}
--- /dev/null
+/* Setup loading/saving.
+ Copyright (C) 1994 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <sys/types.h> /* Needed to include local .h files */
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <string.h>
+#include "tty.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include "mad.h"
+#include "dir.h"
+#include "file.h"
+#include "global.h"
+#include "util.h" /* Functions and externs */
+#include "panel.h"
+#include "main.h"
+#include "tree.h"
+#include "profile.h"
+#define WANT_DEFAULTS
+#include "setup.h"
+#include "mouse.h" /* To make view.h happy */
+#include "view.h" /* For the externs */
+#include "key.h" /* For the externs */
+#include "hotlist.h" /* load/save/done hotlist */
+#include "panelize.h" /* load/save/done panelize */
+#include "layout.h"
+#include "menu.h" /* menubar_visible declaration */
+#include "win.h" /* lookup_key */
+#include "cmd.h"
+#include "x.h"
+
+#ifdef HAVE_GNOME
+# include "gdesktop.h"
+#endif
+
+#ifndef PORT_LIST_MODE_NAME
+# define PORT_LIST_MODE_NAME "list_mode"
+#endif
+
+#ifndef PORT_LIST_MODE_DEFAULT
+# define PORT_LIST_MODE_DEFAULT "full"
+#endif
+
+#include "../vfs/vfs.h"
+#ifdef USE_NETCODE
+# include "../vfs/ftpfs.h"
+extern int use_netrc;
+extern int ftpfs_retry_seconds;
+extern int ftpfs_use_passive_connections;
+extern int ftpfs_use_unix_list_options;
+#endif
+
+/* "$Id: setup.c,v 1.1 2001/12/30 09:55:21 sedwards Exp $" */
+
+#ifdef USE_VFS
+extern int vfs_timeout;
+extern int tar_gzipped_memlimit;
+#endif
+
+extern char *find_ignore_dirs;
+
+extern int num_history_items_recorded;
+
+char *profile_name;
+
+char setup_color_string [4096];
+char term_color_string [4096];
+char color_terminal_string [512];
+
+#define load_int(a,b,c) GetPrivateProfileInt(a,b,c,profile_name)
+#define load_string(a,b,c,d,e) GetPrivateProfileString(a,b,c,d,e,profile_name)
+#define save_string WritePrivateProfileString
+
+int startup_left_mode;
+int startup_right_mode;
+
+/* Ugly hack to allow panel_save_setup to work as a place holder for */
+/* default panel values */
+int saving_setup;
+
+static struct {
+ char *key;
+ sortfn *sort_type;
+} sort_names [] = {
+ { "name", (sortfn *) sort_name },
+ { "extension", (sortfn *) sort_ext },
+ { "time", (sortfn *) sort_time },
+ { "atime", (sortfn *) sort_atime },
+ { "ctime", (sortfn *) sort_ctime },
+ { "size", (sortfn *) sort_size },
+ { "inode", (sortfn *) sort_inode },
+ { "unsorted", (sortfn *) unsorted },
+ { 0, 0 }
+};
+
+static struct {
+ char *key;
+ int list_type;
+} list_types [] = {
+ { "full", list_full },
+ { "brief", list_brief },
+ { "long", list_long },
+ { "user", list_user },
+ { "icons", list_icons },
+ { 0, 0 }
+};
+
+static struct {
+ char *opt_name;
+ int opt_type;
+} panel_types [] = {
+ { "listing", view_listing },
+ { "quickview", view_quick },
+ { "info", view_info },
+ { "tree", view_tree },
+ { 0, 0 }
+};
+
+static struct {
+ char *opt_name;
+ int *opt_addr;
+} layout [] = {
+#ifndef HAVE_GNOME
+ { "equal_split", &equal_split },
+ { "first_panel_size", &first_panel_size },
+ { "message_visible", &message_visible },
+ { "keybar_visible", &keybar_visible },
+ { "xterm_hintbar", &xterm_hintbar },
+ { "output_lines", &output_lines },
+#endif
+ { "menubar_visible", &menubar_visible },
+ { "command_prompt", &command_prompt },
+ { "show_mini_info", &show_mini_info },
+ { "permission_mode", &permission_mode },
+ { "filetype_mode", &filetype_mode },
+ { 0, 0 }
+};
+
+
+#undef SAVE_CHANGES_OUTSIDE_OPTIONS_MENU
+
+#ifdef SAVE_CHANGES_OUTSIDE_OPTIONS_MENU
+extern int preserve_uidgid;
+#endif
+
+static struct {
+ char *opt_name;
+ int *opt_addr;
+} options [] = {
+ { "show_backups", &show_backups },
+ { "show_dot_files", &show_dot_files },
+ { "verbose", &verbose },
+ { "mark_moves_down", &mark_moves_down },
+ { "pause_after_run", &pause_after_run },
+ { "shell_patterns", &easy_patterns },
+ { "auto_save_setup", &auto_save_setup },
+ { "align_extensions", &align_extensions },
+ { "auto_menu", &auto_menu },
+ { "use_internal_view", &use_internal_view },
+ { "use_internal_edit", &use_internal_edit },
+ { "clear_before_exec", &clear_before_exec },
+ { "mix_all_files", &mix_all_files },
+ { "fast_reload", &fast_reload },
+ { "fast_reload_msg_shown", &fast_reload_w },
+ { "confirm_delete", &confirm_delete },
+ { "confirm_overwrite", &confirm_overwrite },
+ { "confirm_execute", &confirm_execute },
+ { "confirm_exit", &confirm_exit },
+ { "safe_delete", &know_not_what_am_i_doing },
+ { "mouse_repeat_rate", &mou_auto_repeat },
+ { "double_click_speed", &double_click_speed },
+ { "eight_bit_clean", &eight_bit_clean },
+ { "full_eight_bits", &full_eight_bits },
+ { "use_8th_bit_as_meta", &use_8th_bit_as_meta },
+ { "confirm_view_dir", &confirm_view_dir },
+ { "mouse_move_pages", &mouse_move_pages },
+ { "mouse_move_pages_viewer", &mouse_move_pages_viewer },
+ { "fast_refresh", &fast_refresh },
+ { "navigate_with_arrows", &navigate_with_arrows },
+ { "advanced_chown", &advanced_chfns },
+ { "drop_menus", &drop_menus },
+ { "wrap_mode", &global_wrap_mode},
+ { "old_esc_mode", &old_esc_mode },
+ { "cd_symlinks", &cd_symlinks },
+ { "show_all_if_ambiguous", &show_all_if_ambiguous },
+ { "have_fast_cpu", &have_fast_cpu },
+ { "iconify_on_exec", &iconify_on_exec },
+ { "torben_fj_mode", &torben_fj_mode },
+ { "use_file_to_guess_type", &use_file_to_check_type },
+ { "alternate_plus_minus", &alternate_plus_minus },
+ { "only_leading_plus_minus", &only_leading_plus_minus },
+ { "show_output_starts_shell", &output_starts_shell },
+ { "panel_scroll_pages", &panel_scroll_pages },
+ { "xtree_mode", &xtree_mode },
+ { "num_history_items_recorded", &num_history_items_recorded },
+#ifdef SAVE_CHANGES_OUTSIDE_OPTIONS_MENU
+ { "dive_into_subdirs", &dive_into_subdirs },
+ { "preserve_uidgid", &preserve_uidgid },
+ /* What about the other two options in the copy dialog
+ (follow links, stable symlinks) -Norbert */
+ { "tree_navigation_flag", &tree_navigation_flag },
+#endif
+#ifdef USE_VFS
+ { "tar_gzipped_memlimit", &tar_gzipped_memlimit },
+ { "vfs_timeout", &vfs_timeout },
+ { "vfs_use_targz_memlimit", &vfs_use_limit },
+#ifdef USE_NETCODE
+ { "ftpfs_directory_timeout", &ftpfs_directory_timeout },
+ { "use_netrc", &use_netrc },
+ { "ftpfs_retry_seconds", &ftpfs_retry_seconds },
+ { "ftpfs_always_use_proxy", &ftpfs_always_use_proxy },
+ { "ftpfs_use_passive_connections", &ftpfs_use_passive_connections },
+ { "ftpfs_use_unix_list_options", &ftpfs_use_passive_connections },
+#endif
+#endif
+#ifdef USE_INTERNAL_EDIT
+ { "editor_word_wrap_line_length", &option_word_wrap_line_length },
+ { "editor_key_emulation", &edit_key_emulation },
+ { "editor_tab_spacing", &option_tab_spacing },
+ { "editor_fill_tabs_with_spaces", &option_fill_tabs_with_spaces },
+ { "editor_return_does_auto_indent", &option_return_does_auto_indent },
+ { "editor_backspace_through_tabs", &option_backspace_through_tabs },
+ { "editor_fake_half_tabs", &option_fake_half_tabs },
+ { "editor_option_save_mode", &option_save_mode },
+ { "editor_option_backup_ext_int", &option_backup_ext_int },
+ { "editor_option_auto_para_formatting", &option_auto_para_formatting },
+ { "editor_option_typewriter_wrap", &option_typewriter_wrap },
+ { "editor_edit_confirm_save", &edit_confirm_save },
+ { "editor_syntax_highlighting", &option_syntax_highlighting },
+#endif
+
+#ifdef HAVE_GNOME
+ { "want_transparent_text", &want_transparent_text },
+ { "want_transparent_icons", &want_transparent_icons },
+ { "icons_snap_to_grid", &icons_snap_to_grid },
+#else
+ { "nice_rotating_dash", &nice_rotating_dash },
+ { "horizontal_split", &horizontal_split },
+#endif
+ { 0, 0 }
+};
+
+void panel_save_setup (WPanel *panel, char *section)
+{
+ char buffer [40];
+ int i;
+
+ sprintf (buffer, "%d", panel->reverse);
+ save_string (section, "reverse", buffer, profile_name);
+ sprintf (buffer, "%d", panel->case_sensitive);
+ save_string (section, "case_sensitive", buffer, profile_name);
+ for (i = 0; sort_names [i].key; i++)
+ if (sort_names [i].sort_type == (sortfn *) panel->sort_type){
+ save_string (section, "sort_order",
+ sort_names [i].key, profile_name);
+ break;
+ }
+
+ for (i = 0; list_types [i].key; i++)
+ if (list_types [i].list_type == panel->list_type){
+ save_string (section, PORT_LIST_MODE_NAME, list_types [i].key, profile_name);
+ break;
+ }
+
+ save_string (section, "user_format",
+ panel->user_format, profile_name);
+
+ for (i = 0; i < LIST_TYPES; i++){
+ sprintf (buffer, "user_status%d", i);
+ save_string (section, buffer,
+ panel->user_status_format [i], profile_name);
+ }
+
+ sprintf (buffer, "%d", panel->user_mini_status);
+ save_string (section, "user_mini_status", buffer,
+ profile_name);
+}
+
+void save_layout (void)
+{
+ char *profile;
+ int i;
+ char buffer [6];
+
+ profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+
+ /* Save integer options */
+ for (i = 0; layout [i].opt_name; i++){
+ sprintf (buffer, "%d", *layout [i].opt_addr);
+ save_string ("Layout", layout [i].opt_name, buffer, profile);
+ }
+
+ free (profile);
+}
+
+void save_configure (void)
+{
+ char *profile;
+ int i;
+
+ profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+
+ /* Save integer options */
+ for (i = 0; options [i].opt_name; i++)
+ set_int (profile, options [i].opt_name, *options [i].opt_addr);
+
+ free (profile);
+}
+
+static void panel_save_type (char *section, int type)
+{
+ int i;
+
+ for (i = 0; panel_types [i].opt_name; i++)
+ if (panel_types [i].opt_type == type){
+ save_string (section, "display", panel_types [i].opt_name,
+ profile_name);
+ break;
+ }
+}
+
+#ifndef PORT_HAS_SAVE_PANEL_TYPES
+void save_panel_types ()
+{
+ int type;
+
+ type = get_display_type (0);
+ panel_save_type ("New Left Panel", type);
+ if (type == view_listing)
+ panel_save_setup (left_panel, left_panel->panel_name);
+ type = get_display_type (1);
+ panel_save_type ("New Right Panel", type);
+ if (type == view_listing)
+ panel_save_setup (right_panel, right_panel->panel_name);
+}
+#endif
+
+void save_setup (void)
+{
+ char *profile;
+#ifdef USE_VFS
+#ifdef USE_NETCODE
+ extern char *ftpfs_anonymous_passwd;
+ extern char *ftpfs_proxy_host;
+#endif
+#endif
+ saving_setup = 1;
+ profile = concat_dir_and_file (home_dir, PROFILE_NAME);
+
+ save_layout ();
+ save_configure ();
+ save_string ("Dirs", "other_dir",
+ get_other_type () == view_listing
+ ? opanel->cwd : ".", profile);
+ WritePrivateProfileString ("Dirs", "current_is_left",
+ get_current_index () == 0 ? "1" : "0", profile);
+ save_hotlist ();
+ save_panelize ();
+ save_panel_types ();
+/* directory_history_save (); */
+
+#ifdef USE_VFS
+#ifdef USE_NETCODE
+ WritePrivateProfileString ("Misc", "ftpfs_password",
+ ftpfs_anonymous_passwd, profile);
+ if (ftpfs_proxy_host)
+ WritePrivateProfileString ("Misc", "ftp_proxy_host",
+ ftpfs_proxy_host, profile);
+#endif
+#endif
+ free (profile);
+ saving_setup = 0;
+}
+
+void panel_load_setup (WPanel *panel, char *section)
+{
+ int i;
+ char buffer [40];
+
+ panel->reverse = load_int (section, "reverse", 0);
+ panel->case_sensitive = load_int (section, "case_sensitive", OS_SORT_CASE_SENSITIVE_DEFAULT);
+
+ /* Load sort order */
+ load_string (section, "sort_order", "name", buffer, sizeof (buffer));
+ panel->sort_type = (sortfn *) sort_name;
+ for (i = 0; sort_names [i].key; i++)
+ if (strcasecmp (sort_names [i].key, buffer) == 0){
+ panel->sort_type = sort_names [i].sort_type;
+ break;
+ }
+
+ /* Load the listing mode */
+ load_string (section, PORT_LIST_MODE_NAME, PORT_LIST_MODE_DEFAULT, buffer, sizeof (buffer));
+ panel->list_type = list_full;
+ for (i = 0; list_types [i].key; i++)
+ if (strcasecmp (list_types [i].key, buffer) == 0){
+ panel->list_type = list_types [i].list_type;
+ break;
+ }
+#ifndef PORT_HAS_ICON_VIEW
+ if (panel->list_type == list_icons)
+ panel->list_type = list_full;
+#endif
+ /* User formats */
+ if (panel->user_format){
+ free (panel->user_format);
+ panel->user_format = 0;
+ }
+ panel->user_format = strdup (get_profile_string (section, "user_format",
+ DEFAULT_USER_FORMAT,
+ profile_name));
+ for (i = 0; i < LIST_TYPES; i++){
+ if (panel->user_status_format [i])
+ free (panel->user_status_format [i]);
+ sprintf (buffer, "user_status%d", i);
+ panel->user_status_format [i] =
+ strdup (get_profile_string (section, buffer,
+ DEFAULT_USER_FORMAT, profile_name));
+ }
+
+ panel->user_mini_status =
+ load_int (section, "user_mini_status", 0);
+
+}
+
+static void load_layout (char *profile_name)
+{
+ int i;
+
+ for (i = 0; layout [i].opt_name; i++)
+ *layout [i].opt_addr =
+ load_int ("Layout", layout [i].opt_name,
+ *layout [i].opt_addr);
+}
+
+static int load_mode (char *section)
+{
+ char buffer [20];
+ int i;
+
+ int mode = view_listing;
+
+ /* Load the display mode */
+ load_string (section, "display", "listing", buffer, sizeof (buffer));
+
+ for (i = 0; panel_types [i].opt_name; i++)
+ if (strcasecmp (panel_types [i].opt_name, buffer) == 0){
+ mode = panel_types [i].opt_type;
+ break;
+ }
+
+ return mode;
+}
+
+char *do_load_string (char *s, char *ss, char *def)
+{
+ char *buffer = xmalloc (128, "dls");
+ char *p;
+
+ load_string (s, ss, def, buffer, 128);
+
+ p = strdup (buffer);
+ free (buffer);
+ return p;
+}
+
+void load_setup (void)
+{
+ static char *buffer;
+ char *profile;
+ char *inifile;
+ int i;
+#ifdef USE_NETCODE
+ extern char *ftpfs_proxy_host;
+#endif
+ buffer = concat_dir_and_file (home_dir, PROFILE_NAME);
+ inifile = concat_dir_and_file (mc_home, "mc.ini");
+ if (exist_file (buffer)){
+ profile = buffer;
+ } else if (exist_file (inifile)){
+ profile = strdup (inifile);
+ free (buffer);
+ } else {
+ profile = buffer;
+ }
+ free (inifile);
+
+ profile_name = profile;
+
+ /* Load integer boolean options */
+ for (i = 0; options [i].opt_name; i++)
+ *options [i].opt_addr =
+ get_int (profile, options [i].opt_name, *options [i].opt_addr);
+
+ load_layout (profile);
+
+ load_panelize ();
+
+ startup_left_mode = load_mode ("New Left Panel");
+ startup_right_mode = load_mode ("New Right Panel");
+
+ /* At least one of the panels is a listing panel */
+ if (startup_left_mode != view_listing && startup_right_mode!=view_listing)
+ startup_left_mode = view_listing;
+
+ if (!other_dir){
+ buffer = (char*) malloc (MC_MAXPATHLEN);
+ load_string ("Dirs", "other_dir", ".", buffer,
+ MC_MAXPATHLEN);
+ if (vfs_file_is_local (buffer))
+ other_dir = buffer;
+ else
+ free (buffer);
+ }
+#ifdef USE_NETCODE
+ ftpfs_proxy_host = do_load_string ("Misc", "ftp_proxy_host", "gate");
+#endif
+ boot_current_is_left =
+ GetPrivateProfileInt ("Dirs", "current_is_left", 1, profile);
+
+ load_string ("Misc", "find_ignore_dirs", "", setup_color_string,
+ sizeof (setup_color_string));
+ if (setup_color_string [0])
+ find_ignore_dirs = copy_strings (":", setup_color_string, ":", 0);
+
+ /* The default color and the terminal dependent color */
+ load_string ("Colors", "base_color", "", setup_color_string,
+ sizeof (setup_color_string));
+ load_string ("Colors", getenv ("TERM"), "",
+ term_color_string, sizeof (term_color_string));
+ load_string ("Colors", "color_terminals", "",
+ color_terminal_string, sizeof (color_terminal_string));
+
+ /* Load the directory history */
+/* directory_history_load (); */
+ /* Remove the temporal entries */
+ profile_clean_section ("Temporal:New Left Panel", profile_name);
+ profile_clean_section ("Temporal:New Right Panel", profile_name);
+#ifdef USE_VFS
+#ifdef USE_NETCODE
+ ftpfs_init_passwd ();
+#endif
+#endif
+}
+
+#ifdef USE_VFS
+#ifdef USE_NETCODE
+char *load_anon_passwd ()
+{
+ char buffer [255];
+
+ load_string ("Misc", "ftpfs_password", "", buffer, sizeof (buffer));
+ if (buffer [0])
+ return strdup (buffer);
+ else
+ return 0;
+}
+#endif
+#endif
+
+void done_setup (void)
+{
+ free (profile_name);
+ done_hotlist ();
+ done_panelize ();
+/* directory_history_free (); */
+}
+
+void load_keys_from_section (char *terminal, char *profile_name)
+{
+ char *section_name;
+ void *profile_keys;
+ char *key, *value, *valcopy;
+ int key_code;
+
+ if (!terminal)
+ return;
+
+ section_name = copy_strings ("terminal:", terminal, 0);
+ profile_keys = profile_init_iterator (section_name, profile_name);
+ if (!profile_keys){
+ free (section_name);
+ return;
+ }
+
+ while (profile_keys){
+ profile_keys = profile_iterator_next (profile_keys, &key, &value);
+ key_code = lookup_key (key);
+ valcopy = convert_controls (value);
+ if (key_code)
+ define_sequence (key_code, valcopy, MCKEY_NOACTION);
+ free (valcopy);
+ }
+ free (section_name);
+ return;
+}
+
+void load_key_defs (void)
+{
+ char *libfile = concat_dir_and_file (mc_home, "mc.lib");
+ load_keys_from_section (getenv ("TERM"), profile_name);
+ load_keys_from_section ("general", profile_name);
+
+ load_keys_from_section (getenv ("TERM"), libfile);
+ load_keys_from_section ("general", libfile);
+
+ /* We don't want a huge database loaded in core */
+ free_profile_name (libfile);
+ free (libfile);
+}
--- /dev/null
+#ifndef __SETUP_H
+#define __SETUP_H
+
+void save_layout (void);
+void save_configure (void);
+void load_setup (void);
+void save_setup (void);
+void done_setup (void);
+#ifdef WANT_WIDGETS
+void panel_save_setup (WPanel *panel, char *section);
+void panel_load_setup (WPanel *panel, char *section);
+#else
+void panel_save_setup ();
+void panel_load_setup ();
+#endif
+void load_key_defs (void);
+void save_panel_types (void);
+char *load_anon_passwd ();
+
+extern char *profile_name;
+
+extern char setup_color_string [];
+extern char term_color_string [];
+extern char color_terminal_string [];
+
+extern int startup_left_mode;
+extern int startup_right_mode;
+
+#ifdef OS2_NT
+# define PROFILE_NAME "mc.ini"
+# define HOTLIST_FILENAME "mc.hot"
+#else
+# define PROFILE_NAME ".mc/ini"
+# define HOTLIST_FILENAME ".mc/hotlist"
+#endif
+#endif
--- /dev/null
+/* Slang interface to the Midnight Commander
+ This emulates some features of ncurses on top of slang
+
+ Copyright (C) 1995, 1996 The Free Software Foundation.
+
+ Author Miguel de Icaza
+ Norbert Warmuth
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+#include <config.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <termios.h>
+#include <signal.h>
+#include <string.h>
+#include "tty.h"
+#include "mad.h"
+#include "color.h"
+#include "util.h"
+#include "mouse.h" /* Gpm_Event is required in key.h */
+#include "key.h" /* define_sequence */
+#include "main.h" /* extern: force_colors */
+#include "win.h" /* do_exit_ca_mode */
+#include "background.h" /* we_are_background definition */
+#include "setup.h"
+
+#ifdef HAVE_SLANG
+
+/* Taken from S-Lang's slutty.c */
+#ifdef ultrix /* Ultrix gets _POSIX_VDISABLE wrong! */
+# define NULL_VALUE -1
+#else
+# ifdef _POSIX_VDISABLE
+# define NULL_VALUE _POSIX_VDISABLE
+# else
+# define NULL_VALUE 255
+# endif
+#endif
+
+/* Taken from S-Lang's sldisply.c file */
+#ifndef USE_TERMCAP
+# define tgetstr(a,b) SLtt_tgetstr (a)
+#else
+ extern char *tgetstr(char *, char **);
+#endif
+
+#ifndef SA_RESTART
+# define SA_RESTART 0
+#endif
+
+/* Various saved termios settings that we control here */
+static struct termios boot_mode;
+static struct termios new_mode;
+
+/* Set if we get an interrupt */
+static int slinterrupt;
+
+/* Controls whether we should wait for input in getch */
+static int no_slang_delay;
+
+/* {{{ Copied from ../slang/slgetkey.c, removed the DEC_8Bit_HACK, */
+extern unsigned int SLang_Input_Buffer_Len;
+extern unsigned char SLang_Input_Buffer [];
+#if SLANG_VERSION >= 10000
+extern unsigned int _SLsys_getkey (void);
+extern int _SLsys_input_pending (int);
+#else
+extern unsigned int SLsys_getkey (void);
+extern int SLsys_input_pending (int);
+#endif
+
+static unsigned int SLang_getkey2 (void)
+{
+ unsigned int imax;
+ unsigned int ch;
+
+ if (SLang_Input_Buffer_Len)
+ {
+ ch = (unsigned int) *SLang_Input_Buffer;
+ SLang_Input_Buffer_Len--;
+ imax = SLang_Input_Buffer_Len;
+
+ memcpy ((char *) SLang_Input_Buffer,
+ (char *) (SLang_Input_Buffer + 1), imax);
+ return(ch);
+ }
+#if SLANG_VERSION >= 10000
+ else return(_SLsys_getkey ());
+#else
+ else return(SLsys_getkey());
+#endif
+}
+
+static int SLang_input_pending2 (int tsecs)
+{
+ int n;
+ unsigned char c;
+ if (SLang_Input_Buffer_Len) return (int) SLang_Input_Buffer_Len;
+#if SLANG_VERSION >= 10000
+ n = _SLsys_input_pending (tsecs);
+#else
+ n = SLsys_input_pending (tsecs);
+#endif
+ if (n <= 0) return 0;
+
+ c = (unsigned char) SLang_getkey2 ();
+ SLang_ungetkey_string (&c, 1);
+
+ return n;
+}
+/* }}} */
+
+static void
+slang_intr (int signo)
+{
+ slinterrupt = 1;
+}
+
+int
+interrupts_enabled (void)
+{
+ struct sigaction current_act;
+
+ sigaction (SIGINT, NULL, ¤t_act);
+ return current_act.sa_handler == slang_intr;
+}
+
+void
+enable_interrupt_key(void)
+{
+ struct sigaction act;
+
+ act.sa_handler = slang_intr;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = 0;
+ sigaction (SIGINT, &act, NULL);
+ slinterrupt = 0;
+}
+
+void
+disable_interrupt_key(void)
+{
+ struct sigaction act;
+
+ act.sa_handler = SIG_IGN;
+ act.sa_flags = 0;
+ sigemptyset (&act.sa_mask);
+ sigaction (SIGINT, &act, NULL);
+}
+
+int
+got_interrupt ()
+{
+ int t;
+
+ t = slinterrupt;
+ slinterrupt = 0;
+ return t;
+}
+
+/* Only done the first time */
+void
+slang_init (void)
+{
+ extern int SLtt_Blink_Mode;
+ extern int SLtt_Has_Alt_Charset;
+ extern int force_ugly_line_drawing;
+ struct sigaction act, oact;
+
+ SLtt_get_terminfo ();
+ tcgetattr (fileno (stdin), &boot_mode);
+ /* 255 = ignore abort char; XCTRL('g') for abort char = ^g */
+ SLang_init_tty (XCTRL('c'), 1, 0);
+
+ /* If SLang uses fileno(stderr) for terminal input MC will hang
+ if we call SLang_getkey between calls to open_error_pipe and
+ close_error_pipe, e.g. when we do a growing view of an gzipped
+ file. */
+ if (SLang_TT_Read_FD == fileno (stderr))
+ SLang_TT_Read_FD = fileno (stdin);
+
+ if (force_ugly_line_drawing)
+ SLtt_Has_Alt_Charset = 0;
+ if (tcgetattr (SLang_TT_Read_FD, &new_mode) == 0) {
+#ifdef VDSUSP
+ new_mode.c_cc[VDSUSP] = NULL_VALUE; /* to ignore ^Y */
+#endif
+#ifdef VLNEXT
+ new_mode.c_cc[VLNEXT] = NULL_VALUE; /* to ignore ^V */
+#endif
+ tcsetattr (SLang_TT_Read_FD, TCSADRAIN, &new_mode);
+ }
+ slang_prog_mode ();
+ load_terminfo_keys ();
+ act.sa_handler = slang_intr;
+ sigemptyset (&act.sa_mask);
+ act.sa_flags = SA_RESTART;
+ sigaction (SIGINT, &act, &oact);
+ SLtt_Blink_Mode = 0;
+}
+
+void
+slang_set_raw_mode (void)
+{
+ tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
+}
+
+/* Done each time we come back from done mode */
+void
+slang_prog_mode (void)
+{
+ tcsetattr (SLang_TT_Read_FD, TCSANOW, &new_mode);
+ SLsmg_init_smg ();
+ SLsmg_touch_lines (0, LINES);
+}
+
+/* Called each time we want to shutdown slang screen manager */
+void
+slang_shell_mode (void)
+{
+ tcsetattr (SLang_TT_Read_FD, TCSANOW, &boot_mode);
+}
+
+void
+slang_shutdown ()
+{
+ char *op_cap;
+
+ slang_shell_mode ();
+ do_exit_ca_mode ();
+ SLang_reset_tty ();
+
+ /* Load the op capability to reset the colors to those that were
+ * active when the program was started up
+ */
+ op_cap = SLtt_tgetstr ("op");
+ if (op_cap){
+ fprintf (stdout, "%s", op_cap);
+ fflush (stdout);
+ }
+}
+
+/* HP Terminals have capabilities (pfkey, pfloc, pfx) to program function keys.
+ elm 2.4pl15 invoked with the -K option utilizes these softkeys and the
+ consequence is that function keys don't work in MC sometimes.
+ Unfortunately I don't now the one and only escape sequence to turn off
+ softkeys (elm uses three different capabilities to turn on softkeys and two
+ capabilities to turn them off).
+ Among other things elm uses the pair we already use in slang_keypad. That's
+ the reason why I call slang_reset_softkeys from slang_keypad. In lack of
+ something better the softkeys are programmed to their defaults from the
+ termcap/terminfo database.
+ The escape sequence to program the softkeys is taken from elm and it is
+ hardcoded because neither slang nor ncurses 4.1 know how to 'printf' this
+ sequence. -- Norbert
+ */
+
+void
+slang_reset_softkeys (void)
+{
+ int key;
+ char *send;
+ char *display = " ";
+ char tmp[100];
+
+ for ( key = 1; key < 9; key++ ) {
+ sprintf ( tmp, "k%d", key);
+ send = (char *) SLtt_tgetstr (tmp);
+ if (send) {
+ sprintf(tmp, "\033&f%dk%dd%dL%s%s", key,
+ strlen(display), strlen(send), display, send);
+ SLtt_write_string (tmp);
+ }
+ }
+}
+
+/* keypad routines */
+void
+slang_keypad (int set)
+{
+ char *keypad_string;
+ extern int reset_hp_softkeys;
+
+ keypad_string = (char *) SLtt_tgetstr (set ? "ks" : "ke");
+ if (keypad_string)
+ SLtt_write_string (keypad_string);
+ if (set && reset_hp_softkeys)
+ slang_reset_softkeys ();
+}
+
+void
+set_slang_delay (int v)
+{
+ no_slang_delay = v;
+}
+
+void
+hline (int ch, int len)
+{
+ int last_x, last_y;
+
+ last_x = SLsmg_get_column ();
+ last_y = SLsmg_get_row ();
+
+ if (ch == 0)
+ ch = ACS_HLINE;
+
+ if (ch == ACS_HLINE){
+ SLsmg_draw_hline (len);
+ } else {
+ while (len--)
+ addch (ch);
+ }
+ move (last_y, last_x);
+}
+
+void
+vline (int character, int len)
+{
+ if (!slow_terminal){
+ SLsmg_draw_vline (len);
+ } else {
+ int last_x, last_y, pos = 0;
+
+ last_x = SLsmg_get_column ();
+ last_y = SLsmg_get_row ();
+
+ while (len--){
+ move (last_y + pos++, last_x);
+ addch (' ');
+ }
+ move (last_x, last_y);
+ }
+}
+
+int max_index = 0;
+
+void
+init_pair (int index, char *foreground, char *background)
+{
+
+ SLtt_set_color (index, "", foreground, background);
+ if (index > max_index)
+ max_index = index;
+}
+
+int
+alloc_color_pair (char *foreground, char *background)
+{
+ init_pair (++max_index, foreground, background);
+ return max_index;
+}
+
+int
+try_alloc_color_pair (char *fg, char *bg)
+{
+ static struct colors_avail {
+ struct colors_avail *next;
+ char *fg, *bg;
+ int index;
+ } *p, c =
+ {
+ 0, 0, 0, 0
+ };
+
+ c.index = NORMAL_COLOR;
+ p = &c;
+ for (;;) {
+ if (((fg && p->fg) ? !strcmp (fg, p->fg) : fg == p->fg) != 0
+ && ((bg && p->bg) ? !strcmp (bg, p->bg) : bg == p->bg) != 0)
+ return p->index;
+ if (!p->next)
+ break;
+ p = p->next;
+ }
+ p->next = malloc (sizeof (c));
+ p = p->next;
+ p->next = 0;
+ p->fg = fg ? strdup (fg) : 0;
+ p->bg = bg ? strdup (bg) : 0;
+ if (!fg)
+ fg = "white";
+ if (!bg)
+ bg = "blue";
+ p->index = alloc_color_pair (fg, bg);
+ return p->index;
+}
+
+char *color_terminals [] = {
+#ifdef __linux__
+ "console",
+#endif
+ "linux",
+ "xterm-color",
+ "color-xterm",
+ "dtterm",
+ "xtermc",
+ "ansi",
+/* 'qnx*' terminals have non-ANSI-compatible color sequences... */
+ "qansi",
+ "qansi-g",
+ "qansi-m",
+ "qansi-t",
+ "qansi-w",
+ 0
+};
+
+int has_colors ()
+{
+ char *terminal = getenv ("TERM");
+ char *cts = color_terminal_string, *s;
+ int i;
+
+ SLtt_Use_Ansi_Colors = force_colors;
+ if (NULL != getenv ("COLORTERM"))
+ SLtt_Use_Ansi_Colors = 1;
+
+ /* We want to allow overwriding */
+ if (!disable_colors){
+ if (!*cts)
+ {
+ /* check hard-coded terminals */
+ for (i = 0; color_terminals [i]; i++)
+ if (strcmp (color_terminals [i], terminal) == 0)
+ SLtt_Use_Ansi_Colors = 1;
+ }
+ else
+ /* check color_terminal_string */
+ {
+ while (*cts)
+ {
+ while (*cts == ' ' || *cts == '\t') cts++;
+
+ s = cts;
+ i = 0;
+
+ while (*cts && *cts != ',')
+ {
+ cts++;
+ i++;
+ }
+ if (i && i == strlen(terminal) && strncmp(s, terminal, i) == 0)
+ SLtt_Use_Ansi_Colors = 1;
+
+ if (*cts == ',') cts++;
+ }
+ }
+ }
+
+ /* Setup emulated colors */
+ if (SLtt_Use_Ansi_Colors){
+ if (use_colors){
+ init_pair (A_REVERSE, "black", "white");
+ init_pair (A_BOLD, "white", "black");
+ } else {
+ init_pair (A_REVERSE, "black", "lightgray");
+ init_pair (A_BOLD, "white", "black");
+ init_pair (A_BOLD_REVERSE, "white", "lightgray");
+ }
+ } else {
+ SLtt_set_mono (A_BOLD, NULL, SLTT_BOLD_MASK);
+ SLtt_set_mono (A_REVERSE, NULL, SLTT_REV_MASK);
+ SLtt_set_mono (A_BOLD|A_REVERSE, NULL, SLTT_BOLD_MASK | SLTT_REV_MASK);
+ }
+ return SLtt_Use_Ansi_Colors;
+}
+
+void
+attrset (int color)
+{
+ if (!SLtt_Use_Ansi_Colors){
+ SLsmg_set_color (color);
+ return;
+ }
+
+ if (color & A_BOLD){
+ if (color == A_BOLD)
+ SLsmg_set_color (A_BOLD);
+ else
+ SLsmg_set_color ((color & (~A_BOLD)) + 8);
+ return;
+ }
+
+ if (color == A_REVERSE)
+ SLsmg_set_color (A_REVERSE);
+ else
+ SLsmg_set_color (color);
+}
+
+/* This table describes which capabilities we want and which values we
+ * assign to them.
+ */
+struct {
+ int key_code;
+ char *key_name;
+} key_table [] = {
+ { KEY_F(0), "k0" },
+ { KEY_F(1), "k1" },
+ { KEY_F(2), "k2" },
+ { KEY_F(3), "k3" },
+ { KEY_F(4), "k4" },
+ { KEY_F(5), "k5" },
+ { KEY_F(6), "k6" },
+ { KEY_F(7), "k7" },
+ { KEY_F(8), "k8" },
+ { KEY_F(9), "k9" },
+ { KEY_F(10), "k;" },
+ { KEY_F(11), "F1" },
+ { KEY_F(12), "F2" },
+ { KEY_F(13), "F3" },
+ { KEY_F(14), "F4" },
+ { KEY_F(15), "F5" },
+ { KEY_F(16), "F6" },
+ { KEY_F(17), "F7" },
+ { KEY_F(18), "F8" },
+ { KEY_F(19), "F9" },
+ { KEY_F(20), "FA" },
+ { KEY_IC, "kI" },
+ { KEY_NPAGE, "kN" },
+ { KEY_PPAGE, "kP" },
+ { KEY_LEFT, "kl" },
+ { KEY_RIGHT, "kr" },
+ { KEY_UP, "ku" },
+ { KEY_DOWN, "kd" },
+ { KEY_DC, "kD" },
+ { KEY_BACKSPACE, "kb" },
+ { KEY_HOME, "kh" },
+ { KEY_END, "@7" },
+ { 0, 0}
+};
+
+void
+do_define_key (int code, char *strcap)
+{
+ char *seq;
+
+ seq = (char *) SLtt_tgetstr (strcap);
+ if (seq)
+ define_sequence (code, seq, MCKEY_NOACTION);
+}
+
+void
+load_terminfo_keys ()
+{
+ int i;
+
+ for (i = 0; key_table [i].key_code; i++)
+ do_define_key (key_table [i].key_code, key_table [i].key_name);
+}
+
+int getch ()
+{
+ if (no_slang_delay)
+ if (SLang_input_pending2 (0) == 0)
+ return -1;
+
+ return (SLang_getkey2 ());
+}
+
+extern int slow_terminal;
+
+#else
+
+/* Non slang builds do not understand got_interrupt */
+int got_interrupt ()
+{
+ return 0;
+}
+#endif /* HAVE_SLANG */
+
+void
+mc_refresh (void)
+{
+ if (!we_are_background)
+ refresh ();
+}
--- /dev/null
+/* {{{ Copyright notice */
+
+/* Concurrent shell support for the Midnight Commander
+ Copyright (C) 1994, 1995 Dugan Porter
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of Version 2 of the GNU General Public
+ License, as published by the Free Software Foundation.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* }}} */
+
+#include <config.h>
+#ifdef HAVE_SUBSHELL_SUPPORT
+
+/* {{{ Declarations */
+
+#include <stdio.h>
+#include <stdlib.h> /* For errno, putenv, etc. */
+#include <errno.h> /* For errno on SunOS systems */
+#include <termios.h> /* tcgetattr(), struct termios, etc. */
+#if (!defined(__IBMC__) && !defined(__IBMCPP__))
+#include <sys/types.h> /* Required by unistd.h below */
+#endif
+#include <sys/ioctl.h> /* For ioctl() (surprise, surprise) */
+#include <fcntl.h> /* For open(), etc. */
+#include <string.h> /* strstr(), strcpy(), etc. */
+#include <signal.h> /* sigaction(), sigprocmask(), etc. */
+#ifndef SCO_FLAVOR
+# include <sys/time.h> /* select(), gettimeofday(), etc. */
+#endif /* SCO_FLAVOR */
+#include <sys/stat.h> /* Required by dir.h & panel.h below */
+#include <sys/param.h> /* Required by panel.h below */
+#include "tty.h"
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h> /* For pipe, fork, setsid, access etc */
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h> /* For waitpid() */
+#endif
+
+#ifndef WEXITSTATUS
+# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
+#endif
+
+#ifndef WIFEXITED
+# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
+#endif
+
+#ifdef HAVE_GRANTPT
+# include <stropts.h> /* For I_PUSH */
+#else
+# include <grp.h> /* For the group struct & getgrnam() */
+#endif
+
+#ifdef SCO_FLAVOR
+# include <grp.h> /* For the group struct & getgrnam() */
+#endif /* SCO_FLAVOR */
+
+#ifdef __QNX__
+# include <unix.h> /* exec*() from <process.h> */
+#endif
+
+#include "dir.h" /* Required by panel.h below */
+#include "util.h" /* Required by panel.h */
+#include "panel.h" /* For WPanel and current_panel */
+#include "dialog.h" /* For query_dialog() */
+#include "main.h" /* For cpanel, quit & init_sigchld() */
+#include "global.h" /* For home_dir */
+#include "cons.saver.h" /* For handle_console(), etc. */
+#include "key.h" /* XCTRL and ALT macros */
+#include "subshell.h"
+
+/* Local functions */
+static int feed_subshell (int how, int fail_on_error);
+static void synchronize (void);
+static int pty_open_master (char *pty_name);
+static int pty_open_slave (const char *pty_name);
+
+/* }}} */
+/* {{{ Definitions */
+
+#ifndef STDIN_FILENO
+# define STDIN_FILENO 0
+#endif
+
+#ifndef STDOUT_FILENO
+# define STDOUT_FILENO 1
+#endif
+
+#ifndef STDERR_FILENO
+# define STDERR_FILENO 2
+#endif
+
+/* If using a subshell for evaluating commands this is true */
+int use_subshell =
+#ifdef SUBSHELL_OPTIONAL
+FALSE;
+#else
+TRUE;
+#endif
+
+/* File descriptor of the pseudoterminal used by the subshell */
+int subshell_pty = 0;
+
+/* If true, the child forked in init_subshell will wait in a loop to be attached by gdb */
+int debug_subshell = 0;
+
+/* The key for switching back to MC from the subshell */
+char subshell_switch_key = XCTRL('o');
+
+/* State of the subshell:
+ * INACTIVE: the default state; awaiting a command
+ * ACTIVE: remain in the shell until the user hits `subshell_switch_key'
+ * RUNNING_COMMAND: return to MC when the current command finishes */
+enum subshell_state_enum subshell_state;
+
+/* Holds the latest prompt captured from the subshell */
+char *subshell_prompt = NULL;
+
+/* Initial length of the buffer for the subshell's prompt */
+#define INITIAL_PROMPT_SIZE 10
+
+/* Used by the child process to indicate failure to start the subshell */
+#define FORK_FAILURE 69 /* Arbitrary */
+
+/* Initial length of the buffer for all I/O with the subshell */
+#define INITIAL_PTY_BUFFER_SIZE 100 /* Arbitrary; but keep it >= 80 */
+
+/* For pipes */
+enum {READ=0, WRITE=1};
+
+
+/* Local variables */
+
+static char *pty_buffer; /* For reading/writing on the subshell's pty */
+static int pty_buffer_size; /* The buffer grows as needed */
+static int subshell_pipe[2]; /* To pass CWD info from the subshell to MC */
+static pid_t subshell_pid = 1; /* The subshell's process ID */
+static char subshell_cwd[MC_MAXPATHLEN+1]; /* One extra char for final '\n' */
+
+/* Subshell type (gleaned from the SHELL environment variable, if available) */
+static enum {BASH, TCSH, ZSH} subshell_type;
+
+/* Flag to indicate whether the subshell is ready for next command */
+static int subshell_ready;
+
+/* The following two flags can be changed by the SIGCHLD handler. This is */
+/* OK, because the `int' type is updated atomically on all known machines */
+static volatile int subshell_alive, subshell_stopped;
+
+/* We store the terminal's initial mode here so that we can configure
+ the pty similarly, and also so we can restore the real terminal to
+ sanity if we have to exit abruptly */
+static struct termios shell_mode;
+
+/* This counter indicates how many characters of prompt we have read */
+/* FIXME: try to figure out why this had to become global */
+static int prompt_pos;
+
+/* }}} */
+
+/* {{{ init_subshell */
+
+/*
+ * Fork the subshell, and set up many, many things.
+ *
+ * Possibly modifies the global variables:
+ * shell_mode
+ * subshell_type, subshell_alive, subshell_stopped, subshell_pid
+ * use_subshell - Is set to FALSE if we can't run the subshell
+ * quit - Can be set to SUBSHELL_EXIT by the SIGCHLD handler
+ */
+
+#ifdef HAVE_GRANTPT
+# define SYNC_PTY_SIDES
+#else
+# define SYNC_PTY_SIDES
+#endif
+
+#undef SYNC_PTY_SIDES
+
+#ifdef SYNC_PTY_SIDES
+/* Handler for SIGUSR1 (used below), does nothing but accept the signal */
+static void sigusr1_handler (int sig)
+{
+}
+#endif
+
+void init_subshell (void)
+{
+ /* {{{ Local variables */
+
+ /* This must be remembered across calls to init_subshell() */
+ static char pty_name[40];
+ int pty_slave;
+
+ /* Braindead tcsh can't redirect output to a file descriptor? */
+ char tcsh_fifo[sizeof "/tmp/mc.pipe.1234567890"];
+
+
+#ifdef SYNC_PTY_SIDES
+ /* Used to wait for a SIGUSR1 signal from the subprocess */
+ sigset_t sigusr1_mask, old_mask;
+#endif
+
+ /* }}} */
+
+ if (subshell_pty == 0) /* First time through */
+ {
+ /* {{{ Find out what type of shell we have */
+
+ if (strstr (shell, "/zsh"))
+ subshell_type = ZSH;
+ else if (strstr (shell, "/tcsh"))
+ subshell_type = TCSH;
+ else if (strstr (shell, "/bash") || getenv ("BASH"))
+ subshell_type = BASH;
+ else
+ {
+ use_subshell = FALSE;
+ return;
+ }
+
+ /* }}} */
+ /* {{{ Open a pty for talking to the subshell */
+
+ /* FIXME: We may need to open a fresh pty each time on SVR4 */
+
+ subshell_pty = pty_open_master (pty_name);
+ if (subshell_pty == -1)
+ {
+ fputs (__FILE__": couldn't open master side of pty\n", stderr);
+ perror ("pty_open_master");
+ use_subshell = FALSE;
+ return;
+ }
+ pty_slave = pty_open_slave (pty_name);
+ if (pty_slave == -1)
+ {
+ fprintf (stderr, "couldn't open slave side of pty (%s)\n\r",
+ pty_name);
+ use_subshell = FALSE;
+ return;
+ }
+
+
+ /* }}} */
+ /* {{{ Initialise the pty's I/O buffer */
+
+ pty_buffer_size = INITIAL_PTY_BUFFER_SIZE;
+ pty_buffer = (char *) malloc (pty_buffer_size);
+
+ /* }}} */
+ /* {{{ Create a pipe for receiving the subshell's CWD */
+
+ if (subshell_type == TCSH)
+ {
+ sprintf (tcsh_fifo, "/tmp/mc.pipe.%d", getpid ());
+ if (mkfifo (tcsh_fifo, 0600) == -1)
+ {
+ perror (__FILE__": mkfifo");
+ use_subshell = FALSE;
+ return;
+ }
+
+ /* Opening the FIFO as O_RDONLY or O_WRONLY causes deadlock */
+
+ if ((subshell_pipe[READ] = open (tcsh_fifo, O_RDWR)) == -1 ||
+ (subshell_pipe[WRITE] = open (tcsh_fifo, O_RDWR)) == -1)
+ {
+ fprintf (stderr, _("Couldn't open named pipe %s\n"), tcsh_fifo);
+ perror (__FILE__": open");
+ use_subshell = FALSE;
+ return;
+ }
+ }
+ else /* subshell_type is BASH or ZSH */
+ if (pipe (subshell_pipe))
+ {
+ perror (__FILE__": couldn't create pipe");
+ use_subshell = FALSE;
+ return;
+ }
+
+ /* }}} */
+ }
+
+ /* {{{ Define a handler for the sigusr1 signal */
+
+#ifdef SYNC_PTY_SIDES
+ sigemptyset (&sigusr1_mask);
+ sigaddset (&sigusr1_mask, SIGUSR1);
+ sigprocmask (SIG_BLOCK, &sigusr1_mask, &old_mask);
+ signal (SIGUSR1, sigusr1_handler);
+#endif
+
+ /* }}} */
+ /* {{{ Fork the subshell */
+
+ subshell_alive = TRUE;
+ subshell_stopped = FALSE;
+ subshell_pid = fork ();
+
+ if (subshell_pid == -1)
+ {
+ perror (__FILE__": couldn't spawn the subshell process");
+ /* We exit here because, if the process table is full, the */
+ /* other method of running user commands won't work either */
+ exit (1);
+ }
+
+ /* }}} */
+
+ if (subshell_pid == 0) /* We are in the child process */
+ {
+ char *init_file = NULL;
+
+ setsid (); /* Get a fresh terminal session */
+
+ /* {{{ Open the slave side of the pty: again */
+ pty_slave = pty_open_slave (pty_name);
+
+ /* This must be done before closing the master side of the pty, */
+ /* or it will fail on certain idiotic systems, such as Solaris. */
+
+ /* Close master side of pty. This is important; apart from */
+ /* freeing up the descriptor for use in the subshell, it also */
+ /* means that when MC exits, the subshell will get a SIGHUP and */
+ /* exit too, because there will be no more descriptors pointing */
+ /* at the master side of the pty and so it will disappear. */
+
+ close (subshell_pty);
+
+#ifdef SYNC_PTY_SIDES
+ /* Give our parent process (MC) the go-ahead */
+ kill (getppid (), SIGUSR1);
+#endif
+
+ /* }}} */
+ /* {{{ Make sure that it has become our controlling terminal */
+
+ /* Redundant on Linux and probably most systems, but just in case: */
+
+# ifdef TIOCSCTTY
+ ioctl (pty_slave, TIOCSCTTY, 0);
+# endif
+
+ /* }}} */
+ /* {{{ Configure its terminal modes and window size */
+
+ /* Set up the pty with the same termios flags as our own tty, plus */
+ /* TOSTOP, which keeps background processes from writing to the pty */
+
+ shell_mode.c_lflag |= TOSTOP; /* So background writers get SIGTTOU */
+ if (tcsetattr (pty_slave, TCSANOW, &shell_mode))
+ {
+ perror (__FILE__": couldn't set pty terminal modes");
+ _exit (FORK_FAILURE);
+ }
+
+ /* Set the pty's size (80x25 by default on Linux) according to the */
+ /* size of the real terminal as calculated by ncurses, if possible */
+# if defined TIOCSWINSZ && !defined SCO_FLAVOR
+ {
+ struct winsize tty_size;
+ tty_size.ws_row = LINES;
+ tty_size.ws_col = COLS;
+ tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
+
+ if (ioctl (pty_slave, TIOCSWINSZ, &tty_size))
+ perror (__FILE__": couldn't set pty size");
+ }
+# endif
+
+ /* }}} */
+ /* {{{ Set up the subshell's environment and init file name */
+
+ /* It simplifies things to change to our home directory here, */
+ /* and the user's startup file may do a `cd' command anyway */
+ chdir (home_dir); /* FIXME? What about when we re-run the subshell? */
+
+ switch (subshell_type)
+ {
+ case BASH:
+ init_file = ".mc/bashrc";
+ if (access (init_file, R_OK) == -1)
+ init_file = ".bashrc";
+
+ /* Make MC's special commands not show up in bash's history */
+ putenv ("HISTCONTROL=ignorespace");
+
+ /* Allow alternative readline settings for MC */
+ if (access (".mc/inputrc", R_OK) == 0)
+ putenv ("INPUTRC=.mc/inputrc");
+
+ break;
+
+ case TCSH:
+ init_file = ".mc/tcshrc";
+ if (access (init_file, R_OK) == -1)
+ init_file += 3;
+ break;
+
+ case ZSH:
+ break;
+
+ default:
+ fprintf (stderr, __FILE__": unimplemented subshell type %d\n",
+ subshell_type);
+ _exit (FORK_FAILURE);
+ }
+
+ /* }}} */
+ /* {{{ Attach all our standard file descriptors to the pty */
+
+ /* This is done just before the fork, because stderr must still */
+ /* be connected to the real tty during the above error messages; */
+ /* otherwise the user will never see them. */
+
+ dup2 (pty_slave, STDIN_FILENO);
+ dup2 (pty_slave, STDOUT_FILENO);
+ dup2 (pty_slave, STDERR_FILENO);
+
+ /* }}} */
+ /* {{{ Execute the subshell at last */
+
+ close (subshell_pipe[READ]);
+ close (pty_slave); /* These may be FD_CLOEXEC, but just in case... */
+
+ switch (subshell_type)
+ {
+ case BASH:
+ execl (shell, "bash", "-rcfile", init_file, NULL);
+ break;
+
+ case TCSH:
+ execl (shell, "tcsh", NULL); /* What's the -rcfile equivalent? */
+ break;
+
+ case ZSH:
+ execl (shell, "zsh", "+Z", NULL);
+ break;
+ }
+
+ /* If we get this far, everything failed miserably */
+ _exit (FORK_FAILURE);
+
+ /* }}} */
+ }
+
+ close(pty_slave);
+
+#ifdef SYNC_PTY_SIDES
+ sigsuspend (&old_mask);
+ signal (SIGUSR1, SIG_DFL);
+ sigprocmask (SIG_SETMASK, &old_mask, NULL);
+ /* ...before installing our handler for SIGCHLD. */
+#endif
+
+#if 0
+ /* {{{ Install our handler for SIGCHLD */
+
+ init_sigchld ();
+
+ /* We could have received the SIGCHLD signal for the subshell
+ * before installing the init_sigchld */
+ pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
+ if (pid == subshell_pid){
+ use_subshell = FALSE;
+ return;
+ }
+
+ /* }}} */
+#endif
+
+ /* {{{ Set up `precmd' or equivalent for reading the subshell's CWD */
+
+ switch (subshell_type)
+ {
+ char precmd[80];
+
+ case BASH:
+ sprintf (precmd, " PROMPT_COMMAND='pwd>&%d;kill -STOP $$'\n",
+ subshell_pipe[WRITE]);
+ goto write_it;
+
+ case ZSH:
+ sprintf (precmd, "precmd(){ pwd>&%d;kill -STOP $$ }\n",
+ subshell_pipe[WRITE]);
+ goto write_it;
+
+ case TCSH:
+ sprintf (precmd, "alias precmd 'echo $cwd:q >>%s;kill -STOP $$'\n", tcsh_fifo);
+
+ write_it:
+ write (subshell_pty, precmd, strlen (precmd));
+ }
+
+ /* }}} */
+ /* {{{ Wait until the subshell has started up and processed the command */
+
+ subshell_state = RUNNING_COMMAND;
+ enable_interrupt_key ();
+ if (!feed_subshell (QUIETLY, TRUE)){
+ use_subshell = FALSE;
+ }
+ disable_interrupt_key ();
+ if (!subshell_alive)
+ use_subshell = FALSE; /* Subshell died instantly, so don't use it */
+
+ /* }}} */
+}
+
+/* }}} */
+/* {{{ invoke_subshell */
+
+int invoke_subshell (const char *command, int how, char **new_dir)
+{
+ /* {{{ Fiddle with terminal modes */
+
+ static struct termios raw_mode = {0};
+
+ /* MC calls reset_shell_mode() in pre_exec() to set the real tty to its */
+ /* original settings. However, here we need to make this tty very raw, */
+ /* so that all keyboard signals, XON/XOFF, etc. will get through to the */
+ /* pty. So, instead of changing the code for execute(), pre_exec(), */
+ /* etc, we just set up the modes we need here, before each command. */
+
+ if (raw_mode.c_iflag == 0) /* First time: initialise `raw_mode' */
+ {
+ tcgetattr (STDOUT_FILENO, &raw_mode);
+ raw_mode.c_lflag &= ~ICANON; /* Disable line-editing chars, etc. */
+ raw_mode.c_lflag &= ~ISIG; /* Disable intr, quit & suspend chars */
+ raw_mode.c_lflag &= ~ECHO; /* Disable input echoing */
+ raw_mode.c_iflag &= ~IXON; /* Pass ^S/^Q to subshell undisturbed */
+ raw_mode.c_iflag &= ~ICRNL; /* Don't translate CRs into LFs */
+ raw_mode.c_oflag &= ~OPOST; /* Don't postprocess output */
+ raw_mode.c_cc[VTIME] = 0; /* IE: wait forever, and return as */
+ raw_mode.c_cc[VMIN] = 1; /* soon as a character is available */
+ }
+
+ tcsetattr (STDOUT_FILENO, TCSANOW, &raw_mode);
+
+ /* }}} */
+
+ /* Make the subshell change to MC's working directory */
+ if (new_dir)
+ do_subshell_chdir (cpanel->cwd, TRUE, 1);
+
+ if (command == NULL) /* The user has done "C-o" from MC */
+ {
+ if (subshell_state == INACTIVE)
+ {
+ subshell_state = ACTIVE;
+ /* FIXME: possibly take out this hack; the user can
+ re-play it by hitting C-hyphen a few times! */
+ write (subshell_pty, " \b", 2); /* Hack to make prompt reappear */
+ }
+ }
+ else /* MC has passed us a user command */
+ {
+ if (how == QUIETLY)
+ write (subshell_pty, " ", 1);
+ write (subshell_pty, command, strlen (command));
+ write (subshell_pty, "\n", 1);
+ subshell_state = RUNNING_COMMAND;
+ subshell_ready = FALSE;
+ }
+
+ feed_subshell (how, FALSE);
+
+ if (new_dir && subshell_alive && strcmp (subshell_cwd, cpanel->cwd))
+ *new_dir = subshell_cwd; /* Make MC change to the subshell's CWD */
+
+ /* Restart the subshell if it has died by SIGHUP, SIGQUIT, etc. */
+ while (!subshell_alive && !quit && use_subshell)
+ init_subshell ();
+
+ prompt_pos = 0;
+
+ return quit;
+}
+
+/* }}} */
+/* {{{ read_subshell_prompt */
+
+int read_subshell_prompt (int how)
+{
+ /* {{{ Local variables */
+
+ int clear_now = FALSE;
+ static int prompt_size = INITIAL_PROMPT_SIZE;
+ int bytes = 0, i, rc = 0;
+ struct timeval timeleft = {0, 0};
+
+ fd_set tmp;
+ FD_ZERO (&tmp);
+ FD_SET (subshell_pty, &tmp);
+
+ /* }}} */
+
+ if (subshell_prompt == NULL) /* First time through */
+ {
+ subshell_prompt = (char *) malloc (prompt_size);
+ *subshell_prompt = '\0';
+ prompt_pos = 0;
+ }
+
+ while (subshell_alive &&
+ (rc = select (FD_SETSIZE, &tmp, NULL, NULL, &timeleft)))
+ {
+ /* {{{ Check for `select' errors */
+
+ if (rc == -1)
+ if (errno == EINTR)
+ continue;
+ else
+ {
+ tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
+ perror ("\n"__FILE__": select (FD_SETSIZE, &tmp...)");
+ exit (1);
+ }
+
+ /* }}} */
+
+ bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
+ if (how == VISIBLY)
+ write (STDOUT_FILENO, pty_buffer, bytes);
+
+ /* {{{ Extract the prompt from the shell output */
+
+ for (i=0; i<bytes; ++i)
+ if (pty_buffer[i] == '\n' || pty_buffer[i] == '\r'){
+ prompt_pos = 0;
+ clear_now = FALSE;
+ } else {
+ clear_now = TRUE;
+ if (!pty_buffer [i])
+ continue;
+
+ subshell_prompt[prompt_pos++] = pty_buffer[i];
+ if (prompt_pos == prompt_size)
+ subshell_prompt = (char *) realloc (subshell_prompt,
+ prompt_size *= 2);
+ }
+
+ /* Sometimes we get an empty new line and then nothing,
+ * we better just keep the old prompt instead. */
+ if (clear_now)
+ subshell_prompt[prompt_pos] = '\0';
+
+ /* }}} */
+ }
+ if (rc == 0 && bytes == 0)
+ return FALSE;
+ return TRUE;
+}
+
+/* }}} */
+/* {{{ resize_subshell */
+
+void resize_subshell (void)
+{
+#if defined TIOCSWINSZ && !defined SCO_FLAVOR
+ struct winsize tty_size;
+
+ tty_size.ws_row = LINES;
+ tty_size.ws_col = COLS;
+ tty_size.ws_xpixel = tty_size.ws_ypixel = 0;
+
+ if (ioctl (subshell_pty, TIOCSWINSZ, &tty_size))
+ perror (__FILE__": couldn't set pty size");
+#endif
+}
+
+/* }}} */
+/* {{{ exit_subshell */
+
+int exit_subshell (void)
+{
+ int quit = TRUE;
+
+ if (subshell_state != INACTIVE && subshell_alive)
+ quit = !query_dialog (_(" Warning "), _(" The shell is still active. Quit anyway? "),
+ 0, 2, _("&Yes"), _("&No"));
+
+#if AIX_TCSH_CODE_BELOW_IS_IT_FIXED
+ /* New Test code */
+ else
+ {
+ if (subshell_type == TCSH)
+ sprintf (pty_buffer, " echo -n Jobs:>/tmp/mc.pipe.%d;jobs>/tmp/"
+ "mc.pipe.%d;kill -STOP $$\n", getpid (), getpid ());
+ else
+ sprintf (pty_buffer, " echo -n Jobs:>&%d;jobs>&%d;kill -STOP $$\n",
+ subshell_pipe[WRITE], subshell_pipe[WRITE]);
+ write (subshell_pty, pty_buffer, strlen (pty_buffer));
+
+#ifndef HAVE_GRANTPT /* FIXME */
+ if (subshell_type == ZSH)
+ /* Here we have to drain the shell output, because zsh does a */
+ /* tcsetattr(SHTTY, TCSADRAIN...) which will block if we don't */
+ read (subshell_pty, pty_buffer, pty_buffer_size);
+#endif
+
+ /* TCSH + AIX hang here, fix this before removing the ifdef above */
+ if (read (subshell_pipe[READ], pty_buffer, pty_buffer_size) == 5)
+ quit = TRUE;
+ else
+ quit = !query_dialog (_(" Warning "), _(" There are stopped jobs.")
+ _(" Quit anyway? "), 0, 2, _("&Yes"), _("&No"));
+
+ synchronize ();
+ subshell_state = RUNNING_COMMAND;
+ feed_subshell (QUIETLY, FALSE); /* Drain the shell output (again) */
+ }
+#endif
+
+ if (quit && subshell_type == TCSH)
+ {
+ /* We abuse of pty_buffer here, but it doesn't matter at this stage */
+ sprintf (pty_buffer, "/tmp/mc.pipe.%d", getpid ());
+ if (unlink (pty_buffer) == -1)
+ perror (__FILE__": couldn't remove named pipe /tmp/mc.pipe.NNN");
+ }
+
+ return quit;
+}
+
+/* }}} */
+
+/* {{{ do_subshell_chdir */
+/* If it actually changed the directory it returns true */
+void do_subshell_chdir (char *directory, int do_update, int reset_prompt)
+{
+ char *temp;
+
+ if (!(subshell_state == INACTIVE && strcmp (subshell_cwd, cpanel->cwd))){
+ /* We have to repaint the subshell prompt if we read it from
+ * the main program. Please note that in the code after this
+ * if, the cd command that is sent will make the subshell
+ * repaint the prompt, so we don't have to paint it. */
+ if (do_update)
+ do_update_prompt ();
+ return;
+ }
+
+ /* The initial space keeps this out of the command history (in bash
+ because we set "HISTCONTROL=ignorespace") */
+ write (subshell_pty, " cd ", 4);
+ if (*directory) {
+ temp = name_quote (directory, 0);
+ write (subshell_pty, temp, strlen (temp));
+ free (temp);
+ } else {
+ write (subshell_pty, "/", 1);
+ }
+ write (subshell_pty, "\n", 1);
+
+ subshell_state = RUNNING_COMMAND;
+ feed_subshell (QUIETLY, FALSE);
+
+ if (subshell_alive && strcmp (subshell_cwd, cpanel->cwd) && strcmp (cpanel->cwd, "."))
+ fprintf (stderr, _("Warning: Couldn't change to %s.\n"), cpanel->cwd);
+
+ if (reset_prompt)
+ prompt_pos = 0;
+ update_prompt = FALSE;
+ /* Make sure that MC never stores the CWD in a silly format */
+ /* like /usr////lib/../bin, or the strcmp() above will fail */
+}
+
+/* }}} */
+/* {{{ subshell_get_console_attributes */
+
+void subshell_get_console_attributes (void)
+{
+ /* {{{ Get our current terminal modes */
+
+ if (tcgetattr (STDOUT_FILENO, &shell_mode))
+ {
+ perror (__FILE__": couldn't get terminal settings");
+ use_subshell = FALSE;
+ return;
+ }
+
+ /* }}} */
+}
+
+/* }}} */
+/* {{{ sigchld_handler */
+
+/* Figure out whether the subshell has stopped, exited or been killed */
+/* Possibly modifies: `subshell_alive', `subshell_stopped' and `quit' */
+
+void sigchld_handler (int sig)
+{
+ int pid, status;
+
+ pid = waitpid (subshell_pid, &status, WUNTRACED | WNOHANG);
+
+ if (pid == subshell_pid) {
+ /* {{{ Figure out what has happened to the subshell */
+
+ if (WIFSTOPPED (status))
+ {
+ if (WSTOPSIG (status) == SIGTSTP)
+ /* The user has suspended the subshell. Revive it */
+ kill (subshell_pid, SIGCONT);
+ else
+ /* The subshell has received a SIGSTOP signal */
+ subshell_stopped = TRUE;
+ }
+ else /* The subshell has either exited normally or been killed */
+ {
+ subshell_alive = FALSE;
+ if (WIFEXITED (status) && WEXITSTATUS (status) != FORK_FAILURE)
+ quit |= SUBSHELL_EXIT; /* Exited normally */
+ }
+
+ /* }}} */
+ }
+
+#ifndef HAVE_X
+#ifndef SCO_FLAVOR
+ pid = waitpid (cons_saver_pid, &status, WUNTRACED | WNOHANG);
+
+ if (pid == cons_saver_pid) {
+ /* {{{ Someone has stopped or killed cons.saver; restart it */
+
+ if (WIFSTOPPED (status))
+ kill (pid, SIGCONT);
+ else
+ {
+ handle_console (CONSOLE_DONE);
+ handle_console (CONSOLE_INIT);
+ /* Ought to do: if (in_subshell) handle_console (CONSOLE_SAVE)
+ Can't do this without adding a new variable `in_subshell';
+ it hardly seems to be worth the trouble. */
+ }
+
+ /* }}} */
+ }
+#endif /* ! SCO_FLAVOR */
+#endif /* ! HAVE_X */
+ /* If we get here, some other child exited; ignore it */
+}
+
+/* }}} */
+
+/* {{{ feed_subshell */
+
+/* Feed the subshell our keyboard input until it says it's finished */
+
+static int feed_subshell (int how, int fail_on_error)
+{
+ /* {{{ Local variables */
+ fd_set read_set; /* For `select' */
+ int bytes; /* For the return value from `read' */
+ int i; /* Loop counter */
+
+ struct timeval wtime; /* Maximum time we wait for the subshell */
+ struct timeval *wptr;
+ /* }}} */
+
+ /* we wait up to 10 seconds if fail_on_error */
+ wtime.tv_sec = 10;
+ wtime.tv_usec = 0;
+
+ for (wptr = fail_on_error ? &wtime : NULL;;)
+ {
+ if (!subshell_alive)
+ return FALSE;
+
+ /* {{{ Prepare the file-descriptor set and call `select' */
+
+ FD_ZERO (&read_set);
+ FD_SET (subshell_pty, &read_set);
+ FD_SET (subshell_pipe[READ], &read_set);
+ if (how == VISIBLY)
+ FD_SET (STDIN_FILENO, &read_set);
+
+ if (select (FD_SETSIZE, &read_set, NULL, NULL, wptr) == -1){
+
+ /* Despite using SA_RESTART, we still have to check for this */
+ if (errno == EINTR)
+ continue; /* try all over again */
+ tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
+ perror ("\n"__FILE__": select (FD_SETSIZE, &read_set...)");
+ exit (1);
+ }
+ /* }}} */
+
+ /* From now on: block forever on the select call */
+ wptr = NULL;
+
+ if (FD_ISSET (subshell_pty, &read_set))
+ /* {{{ Read from the subshell, write to stdout */
+
+ /* This loop improves performance by reducing context switches
+ by a factor of 20 or so... unfortunately, it also hangs MC
+ randomly, because of an apparent Linux bug. Investigate. */
+ /* for (i=0; i<5; ++i) * FIXME -- experimental */
+ {
+ bytes = read (subshell_pty, pty_buffer, pty_buffer_size);
+ if (bytes == -1 && errno != EIO)
+ {
+ tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
+ perror ("\n"__FILE__": read (subshell_pty...)");
+ exit (1);
+ }
+ if (how == VISIBLY)
+ write (STDOUT_FILENO, pty_buffer, bytes);
+ }
+
+ /* }}} */
+
+ else if (FD_ISSET (subshell_pipe[READ], &read_set))
+ /* {{{ Read the subshell's CWD and capture its prompt */
+
+ {
+ bytes = read (subshell_pipe[READ], subshell_cwd, MC_MAXPATHLEN+1);
+ if (bytes == -1)
+ {
+ tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
+ perror ("\n"__FILE__": read (subshell_pipe[READ]...)");
+ exit (1);
+ }
+ if (bytes >= 1)
+ subshell_cwd[bytes-1] = 0; /* Squash the final '\n' */
+
+ synchronize ();
+
+ subshell_ready = TRUE;
+ if (subshell_state == RUNNING_COMMAND)
+ {
+ subshell_state = INACTIVE;
+ return 1;
+ }
+ }
+
+ /* }}} */
+
+ else if (FD_ISSET (STDIN_FILENO, &read_set))
+ /* {{{ Read from stdin, write to the subshell */
+
+ {
+ bytes = read (STDIN_FILENO, pty_buffer, pty_buffer_size);
+ if (bytes == -1)
+ {
+ tcsetattr (STDOUT_FILENO, TCSANOW, &shell_mode);
+ perror ("\n"__FILE__": read (STDIN_FILENO, pty_buffer...)");
+ exit (1);
+ }
+
+ for (i=0; i<bytes; ++i)
+ if (pty_buffer[i] == subshell_switch_key)
+ {
+ write (subshell_pty, pty_buffer, i);
+ if (subshell_ready)
+ subshell_state = INACTIVE;
+ return TRUE;
+ }
+
+ write (subshell_pty, pty_buffer, bytes);
+ subshell_ready = FALSE;
+ } else {
+ return FALSE;
+ }
+
+ /* }}} */
+ }
+}
+
+/* }}} */
+/* {{{ synchronize */
+
+/* Wait until the subshell dies or stops. If it stops, make it resume. */
+/* Possibly modifies the globals `subshell_alive' and `subshell_stopped' */
+
+static void synchronize (void)
+{
+ sigset_t sigchld_mask, old_mask;
+
+ sigemptyset (&sigchld_mask);
+ sigaddset (&sigchld_mask, SIGCHLD);
+ sigprocmask (SIG_BLOCK, &sigchld_mask, &old_mask);
+
+ /* Wait until the subshell has stopped */
+ while (subshell_alive && !subshell_stopped)
+ sigsuspend (&old_mask);
+ subshell_stopped = FALSE;
+ kill (subshell_pid, SIGCONT);
+
+ sigprocmask (SIG_SETMASK, &old_mask, NULL);
+ /* We can't do any better without modifying the shell(s) */
+}
+
+/* }}} */
+/* {{{ pty opening functions */
+
+#ifdef SCO_FLAVOR
+
+/* {{{ SCO version of pty_open_master */
+
+static int pty_open_master (char *pty_name)
+{
+ int pty_master;
+ int num;
+ char *ptr;
+
+ strcpy (pty_name, "/dev/ptyp");
+ ptr = pty_name+9;
+ for (num=0;;num++)
+ {
+ sprintf(ptr,"%d",num); /* surpriiise ... SCO lacks itoa() */
+ /* Try to open master */
+ if ((pty_master = open (pty_name, O_RDWR)) == -1)
+ if (errno == ENOENT) /* Different from EIO */
+ return -1; /* Out of pty devices */
+ else
+ continue; /* Try next pty device */
+ pty_name [5] = 't'; /* Change "pty" to "tty" */
+ if (access (pty_name, 6)){
+ close (pty_master);
+ pty_name [5] = 'p';
+ continue;
+ }
+ return pty_master;
+ }
+ return -1; /* Ran out of pty devices */
+}
+
+/* }}} */
+/* {{{ SCO version of pty_open_slave */
+
+static int pty_open_slave (const char *pty_name)
+{
+ int pty_slave;
+ struct group *group_info = getgrnam ("terminal");
+
+ if (group_info != NULL)
+ {
+ /* The following two calls will only succeed if we are root */
+ /* [Commented out while permissions problem is investigated] */
+ /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
+ /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
+ }
+ if ((pty_slave = open (pty_name, O_RDWR)) == -1)
+ perror ("open (pty_name, O_RDWR)");
+ return pty_slave;
+}
+
+/* }}} */
+
+#elif HAVE_GRANTPT
+
+/* {{{ System V version of pty_open_master */
+
+static int pty_open_master (char *pty_name)
+{
+ char *slave_name;
+ int pty_master;
+
+ strcpy (pty_name, "/dev/ptmx");
+ if ((pty_master = open (pty_name, O_RDWR)) == -1
+ || grantpt (pty_master) == -1 /* Grant access to slave */
+ || unlockpt (pty_master) == -1 /* Clear slave's lock flag */
+ || !(slave_name = ptsname (pty_master))) /* Get slave's name */
+ {
+ close (pty_master);
+ return -1;
+ }
+ strcpy (pty_name, slave_name);
+ return pty_master;
+}
+
+/* }}} */
+/* {{{ System V version of pty_open_slave */
+
+static int pty_open_slave (const char *pty_name)
+{
+ int pty_slave = open (pty_name, O_RDWR);
+
+ if (pty_slave == -1)
+ {
+ perror ("open (pty_name, O_RDWR)");
+ return -1;
+ }
+
+#if !defined(__osf__)
+ if (!ioctl (pty_slave, I_FIND, "ptem"))
+ if (ioctl (pty_slave, I_PUSH, "ptem") == -1)
+ {
+ perror ("ioctl (pty_slave, I_PUSH, \"ptem\")");
+ close (pty_slave);
+ return -1;
+ }
+
+ if (!ioctl (pty_slave, I_FIND, "ldterm"))
+ if (ioctl (pty_slave, I_PUSH, "ldterm") == -1)
+ {
+ perror ("ioctl (pty_slave, I_PUSH, \"ldterm\")");
+ close (pty_slave);
+ return -1;
+ }
+
+#if !defined(sgi) && !defined(__sgi)
+ if (!ioctl (pty_slave, I_FIND, "ttcompat"))
+ if (ioctl (pty_slave, I_PUSH, "ttcompat") == -1)
+ {
+ perror ("ioctl (pty_slave, I_PUSH, \"ttcompat\")");
+ close (pty_slave);
+ return -1;
+ }
+#endif /* sgi || __sgi */
+#endif /* __osf__ */
+
+ return pty_slave;
+}
+
+/* }}} */
+
+#else
+
+/* {{{ BSD version of pty_open_master */
+
+static int pty_open_master (char *pty_name)
+{
+ int pty_master;
+ char *ptr1, *ptr2;
+
+ strcpy (pty_name, "/dev/ptyXX");
+ for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1; ++ptr1)
+ {
+ pty_name [8] = *ptr1;
+ for (ptr2 = "0123456789abcdef"; *ptr2; ++ptr2)
+ {
+ pty_name [9] = *ptr2;
+
+ /* Try to open master */
+ if ((pty_master = open (pty_name, O_RDWR)) == -1)
+ if (errno == ENOENT) /* Different from EIO */
+ return -1; /* Out of pty devices */
+ else
+ continue; /* Try next pty device */
+ pty_name [5] = 't'; /* Change "pty" to "tty" */
+ if (access (pty_name, 6)){
+ close (pty_master);
+ pty_name [5] = 'p';
+ continue;
+ }
+ return pty_master;
+ }
+ }
+ return -1; /* Ran out of pty devices */
+}
+
+/* }}} */
+/* {{{ BSD version of pty_open_slave */
+
+static int pty_open_slave (const char *pty_name)
+{
+ int pty_slave;
+ struct group *group_info = getgrnam ("tty");
+
+ if (group_info != NULL)
+ {
+ /* The following two calls will only succeed if we are root */
+ /* [Commented out while permissions problem is investigated] */
+ /* chown (pty_name, getuid (), group_info->gr_gid); FIXME */
+ /* chmod (pty_name, S_IRUSR | S_IWUSR | S_IWGRP); FIXME */
+ }
+ if ((pty_slave = open (pty_name, O_RDWR)) == -1)
+ perror ("open (pty_name, O_RDWR)");
+ return pty_slave;
+}
+
+/* }}} */
+
+#endif
+
+/* }}} */
+
+#endif /* HAVE_SUBSHELL_SUPPORT */
+
+/* {{{ Emacs local variables */
+
+/*
+ Cause emacs to enter folding mode for this file:
+ Local variables:
+ end:
+*/
+
+/* }}} */
--- /dev/null
+#ifndef __SUBSHELL_H
+#define __SUBSHELL_H
+
+/* Used to distinguish between a normal MC termination and */
+/* one caused by typing `exit' or `logout' in the subshell */
+#define SUBSHELL_EXIT 128
+
+#ifdef HAVE_SUBSHELL_SUPPORT
+
+/* If using a subshell for evaluating commands this is true */
+extern int use_subshell;
+
+/* File descriptor of the pseudoterminal used by the subshell */
+extern int subshell_pty;
+
+/* If true, the child forked in init_subshell will wait in a loop to be attached by gdb */
+extern int debug_subshell;
+
+/* The key to switch back to MC from the subshell */
+extern char subshell_switch_key;
+
+/* State of the subshell; see subshell.c for an explanation */
+enum subshell_state_enum {INACTIVE, ACTIVE, RUNNING_COMMAND};
+extern enum subshell_state_enum subshell_state;
+
+/* Holds the latest prompt captured from the subshell */
+extern char *subshell_prompt;
+
+/* For the `how' argument to various functions */
+enum {QUIETLY, VISIBLY};
+
+/* Exported functions */
+void init_subshell (void);
+int invoke_subshell (const char *command, int how, char **new_dir);
+int read_subshell_prompt (int how);
+void resize_subshell (void);
+int exit_subshell (void);
+void do_subshell_chdir (char *command, int update_prompt, int reset_prompt);
+void subshell_get_console_attributes (void);
+void sigchld_handler (int sig);
+
+#else
+#define use_subshell 0
+#endif /* not HAVE_SUBSHELL_SUPPORT */
+
+#endif /* __SUBSHELL_H */
--- /dev/null
+/* Term name pollution avoiding.
+ Copyright (C) 1994 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include "global.h"
+#include "main.h"
+
+/* This flag is set by xterm detection routine in function main() */
+/* It is used by function view_other_cmd() */
+int xterm_flag = 0;
+
+/* The following routines only work on xterm terminals */
+
+void do_enter_ca_mode (void)
+{
+ if (!xterm_flag)
+ return;
+ fprintf (stdout, /* ESC_STR ")0" */ ESC_STR "7" ESC_STR "[?47h");
+ fflush (stdout);
+}
+
+void do_exit_ca_mode (void)
+{
+ if (!xterm_flag)
+ return;
+ fprintf (stdout, ESC_STR "[?47l" ESC_STR "8" ESC_STR "[m");
+ fflush (stdout);
+}
--- /dev/null
+/*
+ * Text edition support code
+ *
+ *
+ */
+#include <config.h>
+
+#ifdef HAVE_X
+#error This file is for text-mode editions only.
+#endif
+
+#include <stdio.h>
+
+#define WANT_WIDGETS
+#include "win.h"
+#include "tty.h"
+#include "key.h"
+#include "widget.h"
+#include "main.h"
+#include "cons.saver.h"
+
+char *default_edition_colors =
+"normal=lightgray,blue:"
+"selected=black,cyan:"
+"marked=yellow,blue:"
+"markselect=yellow,cyan:"
+"errors=white,red:"
+"menu=white,cyan:"
+"reverse=black,lightgray:"
+"dnormal=black,lightgray:"
+"dfocus=black,cyan:"
+"dhotnormal=yellow,lightgray:"
+"dhotfocus=yellow,cyan:"
+"viewunderline=brightred,blue:"
+"menuhot=yellow,cyan:"
+"menusel=white,black:"
+"menuhotsel=yellow,black:"
+"helpnormal=black,lightgray:"
+"helpitalic=red,lightgray:"
+"helpbold=blue,lightgray:"
+"helplink=black,cyan:"
+"helpslink=yellow,blue:"
+"gauge=white,black:"
+"input=black,cyan:"
+"directory=white,blue:"
+"execute=brightgreen,blue:"
+"link=lightgray,blue:"
+"device=brightmagenta,blue:"
+"core=red,blue:"
+"special=black,blue";
+
+void
+edition_post_exec (void)
+{
+ do_enter_ca_mode ();
+
+ /* FIXME: Missing on slang endwin? */
+ reset_prog_mode ();
+ flushinp ();
+
+ keypad (stdscr, TRUE);
+ mc_raw_mode ();
+ channels_up ();
+ if (use_mouse_p)
+ init_mouse ();
+ if (alternate_plus_minus)
+ application_keypad_mode ();
+}
+
+void
+edition_pre_exec (void)
+{
+ if (clear_before_exec)
+ clr_scr ();
+ else {
+ if (!(console_flag || xterm_flag))
+ printf ("\n\n");
+ }
+
+ channels_down ();
+ if (use_mouse_p)
+ shut_mouse ();
+
+ reset_shell_mode ();
+ keypad (stdscr, FALSE);
+ endwin ();
+
+ numeric_keypad_mode ();
+
+ /* on xterms: maybe endwin did not leave the terminal on the shell
+ * screen page: do it now.
+ *
+ * Do not move this before endwin: in some systems rmcup includes
+ * a call to clear screen, so it will end up clearing the sheel screen.
+ */
+ if (!status_using_ncurses){
+ do_exit_ca_mode ();
+ }
+}
+
+void
+clr_scr (void)
+{
+ standend ();
+ dlg_erase (midnight_dlg);
+ mc_refresh ();
+ doupdate ();
+}
+
--- /dev/null
+/* Defines what features are to be includes in the text mode edition */
+
+#define COMPUTE_FORMAT_ALLOCATIONS 1
+#define PORT_WIDGET_WANTS_HISTORY 1
+#define PORT_NEEDS_CHANGE_SCREEN_SIZE 1
+
+#define port_shutdown_extra_fds()
--- /dev/null
+* Bugs
+
+ - "Files" message flickers a lot when copying files.
+
+ - Make the extfs handle re-reads.
+
+ - Document C-x C-r, C-x C-l, C-x C-s
+
+ - Check that all the help contexts exist on the help file.
+
+ - Make the buttonbar for the tree box work.
+
+ - In the incremental search mode, when backspacing, select the
+ correct file, do not stop in current file.
+
+ - Make C-y yank back all the killed text at once if you've just done
+ several kill operations in a row (C-k, M-d, etc). [For MC 3.x]
+
+ - In learn keys, warn the user if he is trying to
+ i) define a same sequence as an already defined (if the keycode differs)
+ ii) define a sequence, which is a prefix of other longer and already
+ defined sequence
+
+* Tk/mc
+
+ - Add drag and drop.
+
+ - Fix viewer.
+
+ - Fix WInputs (they currently are not very well coordinated with Tk's entry)
+
+ - Fix problem with enter/enter on most dialogs (should be just one enter).
+
+ - Fix the auto-reload dir problem with the little shortcut option.
+
+ - Change the menus for the Tk version.
+
+ - name_trunc the pathname on top of the panels.
+
+ - Click on the pathname should take you to that directory.
+
+ - Viewer breaks with object libraries prev_color is miss computed.
+
+ - Tk/Winfo: The program should not recompute the file system information
+ for each file, it should keep a cache
+
+ - The control of the buttonbar is broken in Tk, try quick view and
+ then press F3 when focusing the Quick view. It does not change
+ the labels on the buttonbar.
+
+ - UNLINK the file as soon as the ftpfs gets an error during write.
+
+ - Port the WTree and WHelp widgets.
+
+ - The current size detection for the widgets will only work if there
+ was a panel before (they assume winfo width/height container does
+ have useful information), I should encapsulate and fix this.
+
+ - Change of the listing mode is broken.
+
+ - The mini status has not been coded.
+
+ - menubar_arrange, destroy_menu: implement
+
+ - Port the interal editor
+
+ - the interal editor adds it's entries to the wrong menu
+
+* XView/mc
+
+ - Dropping files on root window should create action icon.
+
+ - Fix the viewer.
+
+ - Fix help.
+
+ - Icons for buttonbar.
+
+ - Info panel.
+
+ - Tree panel.
+
+* Configuration
+
+* Documentation
+
+ - Convert the source mc.1 to mc.sgml and create automagically from it
+ mc.1, mc.html, mc.hlp, mc.info, mc.tex, mc.txt etc. [3.x]
+
+* Extensions
+
+ - Hotlist should allow people to edit the entry (like we do in the external
+ panelize thing).
+
+ - Change ext.c to allow the %{..} to recursively expand any other %thingies.
+
+ - Write a general grow_string routine. This code is used in the internal
+ viewer and would also be used in the profile.c code.
+
+ - Allow colors to be defined in the mc.lib file.
+
+ - A command to set the line length to a fixed value for viewing
+ fixed length binary files. LIST does this with Ctrl-B and then
+ prompts for a "record" length.
+
+ - Viewer: have a case match toggle.
+
+ - Viewer: Mark all found matches, and when 'n' is pressed go to the
+ next page, not the next match on the same screen (when there is
+ more than one).
+
+ - In ftpfs_open, extfs_open, if we set local_filename to tmpnam, use
+ a mechanism to set local_filename to another place on the local
+ diskspace (this would be useful for copying, so that we would save
+ some tmp space). This would require special care in file.c afterwards.
+
+ - In Listing mode... give at least three user-definable formats
+ (using Janne's Listing mode editor) and assign hot-keys to both
+ standard and user defined (what about c-x f [fbl123] ?).
+
+ - Multiple panels - really necessary! [3.x]
+
+ - Shift-Home, Shift-End for the input line: home and end.
+
+ - Make a mechanism to lock all the mouse events and send them to
+ the locking widget until unlocking is done.
+
+ - Sort with numerical extensions.
+
+ - Allow the program to execute a command even when we are on a vfs, maybe
+ a special box, or make subshell code ignore the change directory
+ request. Perhaps each vfs should store a local path attached to it,
+ like in tarfs, extfs it would be the directory which contains the
+ topmost tararchive, in ftpfs it would be the directory which we entered
+ to ftp from.
+
+ - auto_hint_lines: a variable that would choose to use hint mode when
+ at least auto_hint_lines are visible.
+
+ - Listbox: Mouse handler for the scrollbar: this will be hard with
+ the current approach (since the listbox scrollbar is drawn *outside*
+ the listbox control area).
+
+ - In file.c, we shouldn't need to get a full path name in order to
+ work, we should instead canon the file name inside the tar.c (the
+ only fs that relies on this), tar.c should know about the cwd (i
+ think).
+
+ - Panelize the selected files.
+
+ - Recursive delete should (perhaps as an option) delete files just after
+ they have been copied and not to delay deleting until everything was
+ moved. [3.x]
+
+ - When copying a tree (or moving or deleting), as an option act primarily
+ on the regular files and at the end on directories recursively, so that
+ we get complete high parts of the tree if something fails (useful for
+ ftpfs). [3.x]
+
+ - Put into a new and bigger Options/Configuration dialog all the options
+ we have now to set using .mc.ini manually. [3.x]
+
+ - When after deleting there are no files in a panelized panel, restore
+ it automagically to the real directory content. [3.x]
+
+ - Files/Symlink and Link should be able to do multiple links (if the
+ target is a directory). [3.x]
+
+ - Directory sizes should work in background using try_channels. [3.x]
+
+ - Support of non-UNIX ls in ftpfs. Perhaps using an ascii configuration
+ file similar to moxftp. [3.x]
+
+ - Have an option to let the user choose the preferred keybindings.
+ Currently, only the emacs keybindings are supported, add support
+ for Norton Commander and vi keybindings.
+
+ - Find command should have a way to specify directories to skip.
+
+ - Add an option that will let listboxes do incremental searches.
+
+* Optimizations and cleanup
+
+ - "How to use help" section should be at the first page of the
+ "Contents" help section.
+
+ - Use RPCbind on SVR4, this currently will be left for 3.5
+
+ - Optimize the mcfs read and write code: make the code ouput 8k
+ blocks all the time (if we have called mc_hint_readall) and probe
+ the input for a possible cancel.
+
+ - When verbose is off, remove all the clutter on the screen about
+ the files being copied.
+
+ - The viewer is calling view_update in many places, I call
+ view_update after handling a key, should all the other
+ view_updates be removed?
+
+ - If the viewer is too slow, some catching could be done.
+ width and cols are currently computed each time they are needed.
+
+ - Add context sensitive help to the f9 menus.
+
+ - Add an overlap when going up or down in the file list.
+
+ - In the user menu, don't use the entries array, we can now grow
+ dynamically. I should take a look at this one day, it's easy to
+ fix.
+
+* Binaries distribution
+ - Including all the necessary terminfo databases compiled for
+ different machines, as well as xterm_color for different machines.
+
+
--- /dev/null
+/* Directory tree browser for the Midnight Commander
+ Copyright (C) 1994, 1995, 1996, 1997 The Free Software Foundation
+
+ Written: 1994, 1996 Janne Kukonlehto
+ 1997 Norbert Warmuth
+ 1996 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This module has been converted to be a widget.
+
+ The program load and saves the tree each time the tree widget is
+ created and destroyed. This is required for the future vfs layer,
+ it will be possible to have tree views over virtual file systems.
+
+ */
+#include <config.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h> /* For free() and atoi() */
+#include <string.h>
+#include "tty.h"
+#include "mad.h"
+#include "global.h"
+#include "util.h"
+#include "color.h"
+#include "dialog.h"
+#include "dir.h"
+#include "dlg.h"
+#include "widget.h"
+#include "panel.h"
+#include "mouse.h"
+#include "main.h"
+#include "file.h" /* For copy_dir_dir(), move_dir_dir(), erase_dir() */
+#include "help.h"
+#include "key.h" /* For mi_getch() */
+#include "tree.h"
+#include "cmd.h"
+#include "../vfs/vfs.h"
+#ifdef OS2_NT
+# include <io.h>
+#endif
+
+extern int command_prompt;
+
+#define TREE_NORMALC HOT_FOCUSC
+
+/* Specifies the display mode: 1d or 2d */
+int tree_navigation_flag;
+
+/* If this is true, then when browsing the tree the other window will
+ * automatically reload it's directory with the contents of the currently
+ * selected directory.
+ */
+int xtree_mode = 0;
+
+/* Forwards */
+static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par);
+#define tcallback (callback_fn) tree_callback
+
+/* "$Id: tree.c,v 1.1 2001/12/30 09:55:21 sedwards Exp $" */
+
+/* Returns number of common characters */
+static inline int str_common (char *s1, char *s2)
+{
+ int result = 0;
+
+ while (*s1++ == *s2++)
+ result++;
+ return result;
+}
+
+static tree_entry *back_ptr (tree_entry *ptr, int *count)
+{
+ int i = 0;
+
+ while (ptr && ptr->prev && i < *count){
+ ptr = ptr->prev;
+ i ++;
+ }
+ *count = i;
+ return ptr;
+}
+
+static tree_entry *forw_ptr (tree_entry *ptr, int *count)
+{
+ int i = 0;
+
+ while (ptr && ptr->next && i < *count){
+ ptr = ptr->next;
+ i ++;
+ }
+ *count = i;
+ return ptr;
+}
+
+/* The directory names are arranged in a single linked list in the same
+ order as they are displayed. When the tree is displayed the expected
+ order is like this:
+ /
+ /bin
+ /etc
+ /etc/X11
+ /etc/rc.d
+ /etc.old/X11
+ /etc.old/rc.d
+ /usr
+
+ i.e. the required collating sequence when comparing two directory names is
+ '\0' < PATH_SEP < all-other-characters-in-encoding-order
+
+ Since strcmp doesn't fulfil this requirement we use pathcmp when
+ inserting directory names into the list. The meaning of the return value
+ of pathcmp and strcmp are the same (an integer less than, equal to, or
+ greater than zero if p1 is found to be less than, to match, or be greater
+ than p2.
+ */
+int
+pathcmp (const char *p1, const char *p2)
+{
+ for ( ;*p1 == *p2; p1++, p2++)
+ if (*p1 == '\0' )
+ return 0;
+
+ if (*p1 == '\0')
+ return -1;
+ if (*p2 == '\0')
+ return 1;
+ if (*p1 == PATH_SEP)
+ return -1;
+ if (*p2 == PATH_SEP)
+ return 1;
+ return (*p1 - *p2);
+}
+
+/* Searches for specified directory */
+static tree_entry *whereis (WTree *tree, char *name)
+{
+ tree_entry *current = tree->tree_first;
+ int flag = -1;
+
+#if 0
+ if (tree->tree_last){
+ flag = strcmp (tree->tree_last->name, name);
+ if (flag <= 0){
+ current = tree->tree_last;
+ } else if (tree->selected_ptr){
+ flag = strcmp (tree->selected_ptr->name, name);
+ if (flag <= 0){
+ current = tree->selected_ptr;
+ }
+ }
+ }
+#endif
+ while (current && (flag = pathcmp (current->name, name)) < 0)
+ current = current->next;
+
+ if (flag == 0)
+ return current;
+ else
+ return NULL;
+}
+
+/* Add a directory to the list of directories */
+tree_entry *tree_add_entry (WTree *tree, char *name)
+{
+ int flag = -1;
+ tree_entry *current = tree->tree_first;
+ tree_entry *old = NULL;
+ tree_entry *new;
+ int i, len;
+ int submask = 0;
+
+ if (!tree)
+ return 0;
+
+ if (tree->tree_last && tree->tree_last->next)
+ abort ();
+#if 0
+ if (tree->tree_last){
+ flag = strcmp (tree->tree_last->name, name);
+ if (flag <= 0){
+ current = tree->tree_last;
+ old = current->prev;
+ } else if (tree->selected_ptr){
+ flag = strcmp (tree->selected_ptr->name, name);
+ if (flag <= 0){
+ current = tree->selected_ptr;
+ old = current->prev;
+ }
+ }
+ }
+#endif
+ /* Search for the correct place */
+ while (current && (flag = pathcmp (current->name, name)) < 0){
+ old = current;
+ current = current->next;
+ }
+
+ if (flag == 0)
+ return current; /* Already in the list */
+
+ /* Not in the list -> add it */
+ new = xmalloc (sizeof (tree_entry), "tree, tree_entry");
+ if (!current){
+ /* Append to the end of the list */
+ if (!tree->tree_first){
+ /* Empty list */
+ tree->tree_first = new;
+ new->prev = NULL;
+ } else {
+ old->next = new;
+ new->prev = old;
+ }
+ new->next = NULL;
+ tree->tree_last = new;
+ } else {
+ /* Insert in to the middle of the list */
+ new->prev = old;
+ if (old){
+ /* Yes, in the middle */
+ new->next = old->next;
+ old->next = new;
+ } else {
+ /* Nope, in the beginning of the list */
+ new->next = tree->tree_first;
+ tree->tree_first = new;
+ }
+ new->next->prev = new;
+ }
+ /* tree_count++; */
+
+ /* Calculate attributes */
+ new->name = strdup (name);
+ len = strlen (new->name);
+ new->sublevel = 0;
+ for (i = 0; i < len; i++)
+ if (new->name [i] == PATH_SEP){
+ new->sublevel++;
+ new->subname = new->name + i + 1;
+ }
+ if (new->next)
+ submask = new->next->submask;
+ else
+ submask = 0;
+ submask |= 1 << new->sublevel;
+ submask &= (2 << new->sublevel) - 1;
+ new->submask = submask;
+ new->mark = 0;
+
+ /* Correct the submasks of the previous entries */
+ current = new->prev;
+ while (current && current->sublevel > new->sublevel){
+ current->submask |= 1 << new->sublevel;
+ current = current->prev;
+ }
+
+ /* The entry has now been added */
+
+ if (new->sublevel > 1){
+ /* Let's check if the parent directory is in the tree */
+ char *parent = strdup (new->name);
+ int i;
+
+ for (i = strlen (parent) - 1; i > 1; i--){
+ if (parent [i] == PATH_SEP){
+ parent [i] = 0;
+ tree_add_entry (tree, parent);
+ break;
+ }
+ }
+ free (parent);
+ }
+
+ return new;
+}
+
+#if 0
+/* Append a directory to the list of directories */
+static tree_entry *tree_append_entry (WTree *tree, char *name)
+{
+ tree_entry *current, *new;
+ int i, len;
+ int submask = 0;
+
+ /* We assume the directory is not yet in the list */
+
+ new = xmalloc (sizeof (tree_entry), "tree, tree_entry");
+ if (!tree->tree_first){
+ /* Empty list */
+ tree->tree_first = new;
+ new->prev = NULL;
+ } else {
+ tree->tree_last->next = new;
+ new->prev = tree->tree_last;
+ }
+ new->next = NULL;
+ tree->tree_last = new;
+
+ /* Calculate attributes */
+ new->name = strdup (name);
+ len = strlen (new->name);
+ new->sublevel = 0;
+ for (i = 0; i < len; i++)
+ if (new->name [i] == PATH_SEP){
+ new->sublevel++;
+ new->subname = new->name + i + 1;
+ }
+ submask = 1 << new->sublevel;
+ submask &= (2 << new->sublevel) - 1;
+ new->submask = submask;
+ new->mark = 0;
+
+ /* Correct the submasks of the previous entries */
+ current = new->prev;
+ while (current && current->sublevel > new->sublevel){
+ current->submask |= 1 << new->sublevel;
+ current = current->prev;
+ }
+
+ /* The entry has now been appended */
+ return new;
+}
+#endif
+
+static void remove_entry (WTree *tree, tree_entry *entry)
+{
+ tree_entry *current = entry->prev;
+ long submask = 0;
+
+ if (tree->selected_ptr == entry){
+ if (tree->selected_ptr->next)
+ tree->selected_ptr = tree->selected_ptr->next;
+ else
+ tree->selected_ptr = tree->selected_ptr->prev;
+ }
+
+ /* Correct the submasks of the previous entries */
+ if (entry->next)
+ submask = entry->next->submask;
+ while (current && current->sublevel > entry->sublevel){
+ submask |= 1 << current->sublevel;
+ submask &= (2 << current->sublevel) - 1;
+ current->submask = submask;
+ current = current->prev;
+ }
+
+ /* Unlink the entry from the list */
+ if (entry->prev)
+ entry->prev->next = entry->next;
+ else
+ tree->tree_first = entry->next;
+ if (entry->next)
+ entry->next->prev = entry->prev;
+ else
+ tree->tree_last = entry->prev;
+ /* tree_count--; */
+
+ /* Free the memory used by the entry */
+ free (entry->name);
+ free (entry);
+}
+
+void tree_remove_entry (WTree *tree, char *name)
+{
+ tree_entry *current, *base, *old;
+ int len, base_sublevel;
+
+ /* Miguel Ugly hack */
+ if (name [0] == PATH_SEP && name [1] == 0)
+ return;
+ /* Miguel Ugly hack end */
+
+ base = whereis (tree, name);
+ if (!base)
+ return; /* Doesn't exist */
+ if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
+ base_sublevel = base->sublevel;
+ else
+ base_sublevel = base->sublevel + 1;
+ len = strlen (base->name);
+ current = base->next;
+ while (current
+ && strncmp (current->name, base->name, len) == 0
+ && (current->name[len] == '\0' || current->name[len] == PATH_SEP)){
+ old = current;
+ current = current->next;
+ remove_entry (tree, old);
+ }
+ remove_entry (tree, base);
+}
+
+void tree_destroy (WTree *tree)
+{
+ tree_entry *current, *old;
+
+ save_tree (tree);
+ current = tree->tree_first;
+ while (current){
+ old = current;
+ current = current->next;
+ free (old->name);
+ free (old);
+ }
+ if (tree->tree_shown){
+ free (tree->tree_shown);
+ tree->tree_shown = 0;
+ }
+ tree->selected_ptr = tree->tree_first = tree->tree_last = NULL;
+}
+
+/* Mark the subdirectories of the current directory for delete */
+void start_tree_check (WTree *tree)
+{
+ tree_entry *current;
+ int len;
+
+ if (!tree)
+ tree = (WTree *) find_widget_type (current_dlg, tcallback);
+ if (!tree)
+ return;
+
+ /* Search for the start of subdirectories */
+ mc_get_current_wd (tree->check_name, MC_MAXPATHLEN);
+ tree->check_start = NULL;
+ current = whereis (tree, tree->check_name);
+ if (!current){
+ /* Cwd doesn't exist -> add it */
+ current = tree_add_entry (tree, tree->check_name);
+ return;
+ }
+
+ /* Mark old subdirectories for delete */
+ tree->check_start = current->next;
+ len = strlen (tree->check_name);
+
+ current = tree->check_start;
+ while (current
+ && strncmp (current->name, tree->check_name, len) == 0
+ && (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
+ current->mark = 1;
+ current = current->next;
+ }
+}
+
+/* This subdirectory exists -> clear deletion mark */
+void do_tree_check (WTree *tree, const char *subname)
+{
+ char *name;
+ tree_entry *current, *base;
+ int flag = 1, len;
+
+ /* Calculate the full name of the subdirectory */
+ if (subname [0] == '.' &&
+ (subname [1] == 0 || (subname [1] == '.' && subname [2] == 0)))
+ return;
+ if (tree->check_name [0] == PATH_SEP && tree->check_name [1] == 0)
+ name = copy_strings (PATH_SEP_STR, subname, 0);
+ else
+ name = concat_dir_and_file (tree->check_name, subname);
+
+ /* Search for the subdirectory */
+ current = tree->check_start;
+ while (current && (flag = pathcmp (current->name, name)) < 0)
+ current = current->next;
+
+ if (flag != 0)
+ /* Doesn't exist -> add it */
+ current = tree_add_entry (tree, name);
+ free (name);
+
+ /* Clear the deletion mark from the subdirectory and its children */
+ base = current;
+ if (base){
+ len = strlen (base->name);
+ base->mark = 0;
+ current = base->next;
+ while (current
+ && strncmp (current->name, base->name, len) == 0
+ && (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
+ current->mark = 0;
+ current = current->next;
+ }
+ }
+}
+
+/* Tree check searchs a tree widget in the current dialog and
+ * if it finds it, it calls do_tree_check on the subname
+ */
+void tree_check (const char *subname)
+{
+ WTree *tree;
+
+ tree = (WTree *) find_widget_type (current_dlg, tcallback);
+ if (!tree)
+ return;
+ do_tree_check (tree, subname);
+}
+
+
+/* Delete subdirectories which still have the deletion mark */
+void end_tree_check (WTree *tree)
+{
+ tree_entry *current, *old;
+ int len;
+
+ if (!tree)
+ tree = (WTree *) find_widget_type (current_dlg, tcallback);
+ if (!tree)
+ return;
+
+ /* Check delete marks and delete if found */
+ len = strlen (tree->check_name);
+
+ current = tree->check_start;
+ while (current
+ && strncmp (current->name, tree->check_name, len) == 0
+ && (current->name[len] == '\0' || current->name[len] == PATH_SEP || len == 1)){
+ old = current;
+ current = current->next;
+ if (old->mark)
+ remove_entry (tree, old);
+ }
+}
+
+/* Loads the .mc.tree file */
+void load_tree (WTree *tree)
+{
+ char *filename;
+ FILE *file;
+ char name [MC_MAXPATHLEN], oldname[MC_MAXPATHLEN];
+ char *different;
+ int len, common;
+
+ filename = concat_dir_and_file (home_dir, MC_TREE);
+ file = fopen (filename, "r");
+ free (filename);
+ if (!file){
+ /* No new tree file -> let's try the old file */
+ filename = concat_dir_and_file (home_dir, MC_TREE);
+ file = fopen (filename, "r");
+ free (filename);
+ }
+
+ if (file){
+ /* File open -> read contents */
+ oldname [0] = 0;
+ while (fgets (name, MC_MAXPATHLEN, file)){
+ len = strlen (name);
+ if (name [len - 1] == '\n'){
+ name [--len] = 0;
+ }
+#ifdef OS2_NT
+ /* .ado: Drives for NT and OS/2 */
+ if ((len > 2) &&
+ isalpha(name[0]) &&
+ (name[1] == ':') &&
+ (name[2] == '\\')) {
+ tree_add_entry (tree, name);
+ strcpy (oldname, name);
+ } else
+#endif
+ /* UNIX Version */
+ if (name [0] != PATH_SEP){
+ /* Clear-text decompression */
+ char *s = strtok (name, " ");
+
+ if (s){
+ common = atoi (s);
+ different = strtok (NULL, "");
+ if (different){
+ strcpy (oldname + common, different);
+ tree_add_entry (tree, oldname);
+ }
+ }
+ } else {
+ tree_add_entry (tree, name);
+ strcpy (oldname, name);
+ }
+ }
+ fclose (file);
+ }
+ if (!tree->tree_first){
+ /* Nothing loaded -> let's add some standard directories */
+ tree_add_entry (tree, PATH_SEP_STR);
+ tree->selected_ptr = tree->tree_first;
+ tree_rescan_cmd (tree);
+ tree_add_entry (tree, home_dir);
+ tree_chdir (tree, home_dir);
+ tree_rescan_cmd (tree);
+ }
+}
+
+/* Save the .mc.tree file */
+void save_tree (WTree *tree)
+{
+ tree_entry *current;
+ char *filename;
+ FILE *file;
+ int i, common;
+
+ filename = concat_dir_and_file (home_dir, MC_TREE);
+ file = fopen (filename, "w");
+ free (filename);
+ if (!file){
+ fprintf (stderr, _("Can't open the %s file for writing:\n%s\n"), MC_TREE,
+ unix_error_string (errno));
+ return;
+ }
+
+ current = tree->tree_first;
+ while (current){
+ if (current->prev && (common = str_common (current->prev->name, current->name)) > 2)
+ /* Clear-text compression */
+ i = fprintf (file, "%d %s\n", common, current->name + common);
+ else
+ i = fprintf (file, "%s\n", current->name);
+ if (i == EOF){
+ fprintf (stderr, _("Can't write to the %s file:\n%s\n"), MC_TREE,
+ unix_error_string (errno));
+ break;
+ }
+ current = current->next;
+ }
+ fclose (file);
+}
+
+static void tree_show_mini_info (WTree *tree, int tree_lines, int tree_cols)
+{
+ Dlg_head *h = tree->widget.parent;
+ int line;
+
+ /* Show mini info */
+ if (tree->is_panel){
+ if (!show_mini_info)
+ return;
+ line = tree_lines+2;
+ } else
+ line = tree_lines+1;
+
+ widget_move (&tree->widget, line, 1);
+ hline (' ', tree_cols);
+ widget_move (&tree->widget, line, 1);
+
+ if (tree->searching){
+ /* Show search string */
+ attrset (TREE_NORMALC);
+ attrset (FOCUSC);
+ addch (PATH_SEP);
+
+ addstr (name_trunc (tree->search_buffer, tree_cols-2));
+ addch (' ');
+ attrset (FOCUSC);
+ } else {
+ /* Show full name of selected directory */
+ addstr (name_trunc (tree->selected_ptr->name, tree_cols));
+ }
+}
+
+void show_tree (WTree *tree)
+{
+ Dlg_head *h = tree->widget.parent;
+ tree_entry *current;
+ int i, j, topsublevel;
+ int x, y;
+ int tree_lines, tree_cols;
+
+ /* Initialize */
+ x = y = 0;
+ tree_lines = tlines (tree);
+ tree_cols = tree->widget.cols;
+
+ attrset (TREE_NORMALC);
+ widget_move ((Widget*)tree, y, x);
+ if (tree->is_panel){
+ tree_cols -= 2;
+ x = y = 1;
+ }
+
+ if (tree->tree_shown)
+ free (tree->tree_shown);
+ tree->tree_shown = (tree_entry**)xmalloc (sizeof (tree_entry*)*tree_lines,
+ "tree, show_tree");
+ for (i = 0; i < tree_lines; i++)
+ tree->tree_shown [i] = NULL;
+ if (tree->tree_first)
+ topsublevel = tree->tree_first->sublevel;
+ else
+ topsublevel = 0;
+ if (!tree->selected_ptr){
+ tree->selected_ptr = tree->tree_first;
+ tree->topdiff = 0;
+ }
+ current = tree->selected_ptr;
+
+ /* Calculate the directory which is to be shown on the topmost line */
+ if (tree_navigation_flag){
+ i = 0;
+ while (current->prev && i < tree->topdiff){
+ current = current->prev;
+ if (current->sublevel < tree->selected_ptr->sublevel){
+ if (strncmp (current->name, tree->selected_ptr->name,
+ strlen (current->name)) == 0)
+ i++;
+ } else if (current->sublevel == tree->selected_ptr->sublevel){
+ for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
+ if (strncmp (current->name, tree->selected_ptr->name, j) == 0)
+ i++;
+ } else if (current->sublevel == tree->selected_ptr->sublevel + 1
+ && strlen (tree->selected_ptr->name) > 1){
+ if (strncmp (current->name, tree->selected_ptr->name,
+ strlen (tree->selected_ptr->name)) == 0)
+ i++;
+ }
+ }
+ tree->topdiff = i;
+ } else
+ current = back_ptr (current, &tree->topdiff);
+
+ /* Loop for every line */
+ for (i = 0; i < tree_lines; i++){
+ /* Move to the beginning of the line */
+ widget_move (&tree->widget, y+i, x);
+
+ hline (' ', tree_cols);
+ widget_move (&tree->widget, y+i, x);
+
+ if (!current)
+ continue;
+
+ tree->tree_shown [i] = current;
+ if (current->sublevel == topsublevel){
+
+ /* Top level directory */
+ if (tree->active && current == tree->selected_ptr)
+ if (!use_colors && !tree->is_panel)
+ attrset (MARKED_COLOR);
+ else
+ attrset (SELECTED_COLOR);
+
+ /* Show full name */
+ addstr (name_trunc (current->name, tree_cols - 6));
+ } else{
+ /* Sub level directory */
+
+ acs ();
+ /* Output branch parts */
+ for (j = 0; j < current->sublevel - topsublevel - 1; j++){
+ if (tree_cols - 8 - 3 * j < 9)
+ break;
+ addch (' ');
+ if (current->submask & (1 << (j + topsublevel + 1)))
+ addch (ACS_VLINE);
+ else
+ addch (' ');
+ addch (' ');
+ }
+ addch (' '); j++;
+ if (!current->next || !(current->next->submask & (1 << current->sublevel)))
+ addch (ACS_LLCORNER);
+ else
+ addch (ACS_LTEE);
+ addch (ACS_HLINE);
+ noacs ();
+
+ if (tree->active && current == tree->selected_ptr)
+ /* Selected directory -> change color */
+ if (!use_colors && !tree->is_panel)
+ attrset (MARKED_COLOR);
+ else
+ attrset (SELECTED_COLOR);
+
+ /* Show sub-name */
+ addch (' ');
+ addstr (name_trunc (current->subname,
+ tree_cols - 2 - 4 - 3 * j));
+ }
+ addch (' ');
+
+ /* Return to normal color */
+ attrset (TREE_NORMALC);
+
+ /* Calculate the next value for current */
+ if (tree_navigation_flag){
+ current = current->next;
+ while (current){
+ if (current->sublevel < tree->selected_ptr->sublevel){
+ if (strncmp (current->name, tree->selected_ptr->name,
+ strlen (current->name)) == 0)
+ break;
+ } else if (current->sublevel == tree->selected_ptr->sublevel){
+ for (j = strlen (current->name) - 1; current->name [j] != PATH_SEP; j--);
+ if (strncmp (current->name,tree->selected_ptr->name,j)== 0)
+ break;
+ } else if (current->sublevel == tree->selected_ptr->sublevel+1
+ && strlen (tree->selected_ptr->name) > 1){
+ if (strncmp (current->name, tree->selected_ptr->name,
+ strlen (tree->selected_ptr->name)) == 0)
+ break;
+ }
+ current = current->next;
+ }
+ } else
+ current = current->next;
+ }
+ tree_show_mini_info (tree, tree_lines, tree_cols);
+}
+
+static void check_focus (WTree *tree)
+{
+ if (tree->topdiff < 3)
+ tree->topdiff = 3;
+ else if (tree->topdiff >= tlines (tree) - 3)
+ tree->topdiff = tlines (tree) - 3 - 1;
+}
+
+void tree_move_backward (WTree *tree, int i)
+{
+ tree_entry *current;
+ int j = 0;
+
+ if (tree_navigation_flag){
+ current = tree->selected_ptr;
+ while (j < i && current->prev
+ && current->prev->sublevel >= tree->selected_ptr->sublevel){
+ current = current->prev;
+ if (current->sublevel == tree->selected_ptr->sublevel){
+ tree->selected_ptr = current;
+ j ++;
+ }
+ }
+ i = j;
+ } else
+ tree->selected_ptr = back_ptr (tree->selected_ptr, &i);
+ tree->topdiff -= i;
+ check_focus (tree);
+}
+
+void tree_move_forward (WTree *tree, int i)
+{
+ tree_entry *current;
+ int j = 0;
+
+ if (tree_navigation_flag){
+ current = tree->selected_ptr;
+ while (j < i && current->next
+ && current->next->sublevel >= tree->selected_ptr->sublevel){
+ current = current->next;
+ if (current->sublevel == tree->selected_ptr->sublevel){
+ tree->selected_ptr = current;
+ j ++;
+ }
+ }
+ i = j;
+ } else
+ tree->selected_ptr = forw_ptr (tree->selected_ptr, &i);
+ tree->topdiff += i;
+ check_focus (tree);
+}
+
+void tree_move_to_child (WTree *tree)
+{
+ tree_entry *current;
+
+ /* Do we have a starting point? */
+ if (!tree->selected_ptr)
+ return;
+ /* Take the next entry */
+ current = tree->selected_ptr->next;
+ /* Is it the child of the selected entry */
+ if (current && current->sublevel > tree->selected_ptr->sublevel){
+ /* Yes -> select this entry */
+ tree->selected_ptr = current;
+ tree->topdiff++;
+ check_focus (tree);
+ } else {
+ /* No -> rescan and try again */
+ tree_rescan_cmd (tree);
+ current = tree->selected_ptr->next;
+ if (current && current->sublevel > tree->selected_ptr->sublevel){
+ tree->selected_ptr = current;
+ tree->topdiff++;
+ check_focus (tree);
+ }
+ }
+}
+
+int tree_move_to_parent (WTree *tree)
+{
+ tree_entry *current;
+ tree_entry *old;
+
+ if (!tree->selected_ptr)
+ return 0;
+ old = tree->selected_ptr;
+ current = tree->selected_ptr->prev;
+ while (current && current->sublevel >= tree->selected_ptr->sublevel){
+ current = current->prev;
+ tree->topdiff--;
+ }
+ if (!current)
+ current = tree->tree_first;
+ tree->selected_ptr = current;
+ check_focus (tree);
+ return tree->selected_ptr != old;
+}
+
+void tree_move_to_top (WTree *tree)
+{
+ tree->selected_ptr = tree->tree_first;
+ tree->topdiff = 0;
+}
+
+void tree_move_to_bottom (WTree *tree)
+{
+ tree->selected_ptr = tree->tree_last;
+ tree->topdiff = tlines (tree) - 3 - 1;
+}
+
+void tree_chdir (WTree *tree, char *dir)
+{
+ tree_entry *current;
+
+ current = whereis (tree, dir);
+ if (current){
+ tree->selected_ptr = current;
+ check_focus (tree);
+ }
+}
+
+/* Handle mouse click */
+void tree_event (WTree *tree, int y)
+{
+ if (tree->tree_shown [y]){
+ tree->selected_ptr = tree->tree_shown [y];
+ tree->topdiff = y;
+ }
+ show_tree (tree);
+}
+
+static void chdir_sel (WTree *tree);
+
+static void maybe_chdir (WTree *tree)
+{
+ if (!(xtree_mode && tree->is_panel))
+ return;
+ if (is_idle ())
+ chdir_sel (tree);
+}
+
+/* Mouse callback */
+static int event_callback (Gpm_Event *event, WTree *tree)
+{
+ if (!(event->type & GPM_UP))
+ return MOU_ENDLOOP;
+
+ if (tree->is_panel)
+ event->y--;
+
+ event->y--;
+
+ if (!tree->active)
+ change_panel ();
+
+ if (event->y < 0){
+ tree_move_backward (tree, tlines (tree) - 1);
+ show_tree (tree);
+ }
+ else if (event->y >= tlines (tree)){
+ tree_move_forward (tree, tlines (tree) - 1);
+ show_tree (tree);
+ } else {
+ tree_event (tree, event->y);
+ if ((event->type & (GPM_UP|GPM_DOUBLE)) == (GPM_UP|GPM_DOUBLE)){
+ chdir_sel (tree);
+ }
+ }
+ return MOU_ENDLOOP;
+}
+
+/* Search tree for text */
+int search_tree (WTree *tree, char *text)
+{
+ tree_entry *current;
+ int len;
+ int wrapped = 0;
+ int found = 0;
+
+ len = strlen (text);
+ current = tree->selected_ptr;
+ found = 0;
+ while (!wrapped || current != tree->selected_ptr){
+ if (strncmp (current->subname, text, len) == 0){
+ tree->selected_ptr = current;
+ found = 1;
+ break;
+ }
+ current = current->next;
+ if (!current){
+ current = tree->tree_first;
+ wrapped = 1;
+ }
+ tree->topdiff++;
+ }
+ check_focus (tree);
+ return found;
+}
+
+static void tree_do_search (WTree *tree, int key)
+{
+ int l;
+
+ l = strlen (tree->search_buffer);
+ if (l && (key == 8 || key == 0177 || key == KEY_BACKSPACE))
+ tree->search_buffer [--l] = 0;
+ else {
+ if (key && l < sizeof (tree->search_buffer)){
+ tree->search_buffer [l] = key;
+ tree->search_buffer [l+1] = 0;
+ l++;
+ }
+ }
+
+ if (!search_tree (tree, tree->search_buffer))
+ tree->search_buffer [--l] = 0;
+
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+void tree_rescan_cmd (WTree *tree)
+{
+ DIR *dirp;
+ struct dirent *dp;
+ struct stat buf;
+ char old_dir [MC_MAXPATHLEN];
+
+ if (!tree->selected_ptr || !mc_get_current_wd (old_dir, MC_MAXPATHLEN) ||
+ mc_chdir (tree->selected_ptr->name))
+ return;
+
+ start_tree_check (tree);
+ dirp = opendir (".");
+ if (dirp){
+ for (dp = readdir (dirp); dp; dp = readdir (dirp)){
+ lstat (dp->d_name, &buf);
+ if (S_ISDIR (buf.st_mode))
+ do_tree_check (tree, dp->d_name);
+ }
+ closedir (dirp);
+ }
+ end_tree_check (tree);
+ mc_chdir (old_dir);
+}
+
+int tree_forget_cmd (WTree *tree)
+{
+ if (tree->selected_ptr)
+ tree_remove_entry (tree, tree->selected_ptr->name);
+ return 1;
+}
+
+#if 0
+static int toggle_nav_mode (void)
+{
+ tree_navigation_flag = 1 - tree_navigation_flag;
+
+ return 1;
+}
+#endif
+
+void tree_copy (WTree *tree, char *default_dest)
+{
+ char *dest;
+
+ if (!tree->selected_ptr)
+ return;
+ sprintf (cmd_buf, _("Copy \"%s\" directory to:"),
+ name_trunc (tree->selected_ptr->name, 50));
+ dest = input_expand_dialog (_(" Copy "), cmd_buf, default_dest);
+ if (!dest || !*dest){
+ return;
+ }
+ create_op_win (OP_COPY, 0);
+ file_mask_defaults ();
+ copy_dir_dir (tree->selected_ptr->name, dest, 1, 0, 0, 0);
+ destroy_op_win ();
+ free (dest);
+}
+
+static void tree_help_cmd (void)
+{
+ char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
+ interactive_display (hlpfile, "[Directory Tree]");
+ free (hlpfile);
+}
+
+static int tree_copy_cmd (WTree *tree)
+{
+ tree_copy (tree, "");
+ return 1;
+}
+
+void tree_move (WTree *tree, char *default_dest)
+{
+ char *dest;
+ struct stat buf;
+
+ if (!tree->selected_ptr)
+ return;
+ sprintf (cmd_buf, _("Move \"%s\" directory to:"),
+ name_trunc (tree->selected_ptr->name, 50));
+ dest = input_expand_dialog (_(" Move "), cmd_buf, default_dest);
+ if (!dest || !*dest){
+ return;
+ }
+ if (stat (dest, &buf)){
+ message (1, _(" Error "), _(" Can't stat the destination \n %s "),
+ unix_error_string (errno));
+ free (dest);
+ return;
+ }
+ if (!S_ISDIR (buf.st_mode)){
+ message (1, _(" Error "), _(" The destination isn't a directory "));
+ free (dest);
+ return;
+ }
+ create_op_win (OP_MOVE, 0);
+ file_mask_defaults ();
+ move_dir_dir (tree->selected_ptr->name, dest);
+ destroy_op_win ();
+ free (dest);
+}
+
+static int tree_move_cmd (WTree *tree)
+{
+ tree_move (tree, "");
+ return 1;
+}
+
+static int tree_mkdir_cmd (WTree *tree)
+{
+ char old_dir [MC_MAXPATHLEN];
+
+ if (!tree->selected_ptr)
+ return 0;
+ if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
+ return 0;
+ if (chdir (tree->selected_ptr->name))
+ return 0;
+ /* FIXME
+ mkdir_cmd (tree);
+ */
+ tree_rescan_cmd (tree);
+ chdir (old_dir);
+ return 1;
+}
+
+static void tree_rmdir_cmd (WTree *tree)
+{
+ char old_dir [MC_MAXPATHLEN];
+
+ if (tree->selected_ptr){
+ if (!mc_get_current_wd (old_dir, MC_MAXPATHLEN))
+ return;
+ if (mc_chdir (PATH_SEP_STR))
+ return;
+ if (confirm_delete){
+ char *cmd_buf;
+ int result;
+
+ cmd_buf = xmalloc (strlen (tree->selected_ptr->name) + 20,
+ "tree, rmdir_cmd");
+ sprintf (cmd_buf, _(" Delete %s? "), tree->selected_ptr->name);
+ result = query_dialog (_(" Delete "), cmd_buf, 3, 2, _("&Yes"), _("&No"));
+ free (cmd_buf);
+ if (result != 0){
+ return;
+ }
+ }
+ create_op_win (OP_DELETE, 0);
+ if (erase_dir (tree->selected_ptr->name) == FILE_CONT)
+ tree_forget_cmd (tree);
+ destroy_op_win ();
+ mc_chdir (old_dir);
+ return;
+ } else
+ return;
+}
+
+#if 0
+static int tree_quit_cmd (void)
+{
+ /*
+ FIXME
+ return done = 1;
+ */
+ return 1;
+}
+#endif
+
+static void set_navig_label (Dlg_head *h);
+static void tree_toggle_navig (Dlg_head *h)
+{
+ tree_navigation_flag = 1 - tree_navigation_flag;
+ set_navig_label (h);
+}
+
+void set_navig_label (Dlg_head *h)
+{
+ define_label_data (h, (Widget *)tree,
+ 4, tree_navigation_flag ? _("Static") : _("Dynamc"),
+ (void (*)(void *))tree_toggle_navig, h);
+}
+
+static void move_down (WTree *tree)
+{
+ tree_move_forward (tree, 1);
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+static void move_up (WTree *tree)
+{
+ tree_move_backward (tree, 1);
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+static void move_home (WTree *tree)
+{
+ tree_move_to_top (tree);
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+static void move_end (WTree *tree)
+{
+ tree_move_to_bottom (tree);
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+static int move_left (WTree *tree)
+{
+ int v;
+
+ if (tree_navigation_flag){
+ v = tree_move_to_parent (tree);
+ show_tree (tree);
+ maybe_chdir (tree);
+ return v;
+ }
+ return 0;
+}
+
+static int move_right (WTree *tree)
+{
+ if (tree_navigation_flag){
+ tree_move_to_child (tree);
+ show_tree (tree);
+ maybe_chdir (tree);
+ return 1;
+ }
+ return 0;
+}
+
+static void move_prevp (WTree *tree)
+{
+ tree_move_backward (tree, tlines (tree) - 1);
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+static void move_nextp (WTree *tree)
+{
+ tree_move_forward (tree, tlines (tree) - 1);
+ show_tree (tree);
+ maybe_chdir (tree);
+}
+
+static void chdir_sel (WTree *tree)
+{
+ if (!tree->is_panel){
+ tree->done = 1;
+ return;
+ }
+ change_panel ();
+ if (do_cd (tree->selected_ptr->name, cd_exact)){
+ paint_panel (cpanel);
+ select_item (cpanel);
+ } else {
+ message (1, MSG_ERROR, _(" Can't chdir to \"%s\" \n %s "),
+ tree->selected_ptr->name, unix_error_string (errno));
+ }
+ change_panel ();
+ show_tree (tree);
+ return;
+}
+
+static void start_search (WTree *tree)
+{
+ int i;
+
+ if (tree->searching){
+
+ if (tree->selected_ptr == tree->tree_last)
+ tree_move_to_top(tree);
+ else {
+ /* set navigation mode temporarily to 'Static' because in
+ * dynamic navigation mode tree_move_forward will not move
+ * to a lower sublevel if necessary (sequent searches must
+ * start with the directory followed the last found directory)
+ */
+ i = tree_navigation_flag;
+ tree_navigation_flag = 0;
+ tree_move_forward (tree, 1);
+ tree_navigation_flag = i;
+ }
+ tree_do_search (tree, 0);
+ }
+ else {
+ tree->searching = 1;
+ tree->search_buffer[0] = 0;
+ }
+}
+
+static key_map tree_keymap [] = {
+ { XCTRL('n'), move_down },
+ { XCTRL('p'), move_up },
+ { KEY_DOWN, move_down },
+ { KEY_UP, move_up },
+ { '\n', chdir_sel },
+ { KEY_ENTER, chdir_sel },
+ { KEY_HOME, move_home },
+ { KEY_C1, move_end },
+ { KEY_END, move_end },
+ { KEY_A1, move_home },
+ { KEY_NPAGE, move_nextp },
+ { KEY_PPAGE, move_prevp },
+ { XCTRL('v'), move_nextp },
+ { ALT('v'), move_prevp },
+ { XCTRL('p'), move_up },
+ { XCTRL('p'), move_down },
+ { XCTRL('s'), start_search },
+ { ALT('s'), start_search },
+ { XCTRL('r'), tree_rescan_cmd },
+ { KEY_DC, tree_rmdir_cmd },
+ { 0, 0 }
+ };
+
+static inline int tree_key (WTree *tree, int key)
+{
+ int i;
+
+ for (i = 0; tree_keymap [i].key_code; i++){
+ if (key == tree_keymap [i].key_code){
+ if (tree_keymap [i].fn != start_search)
+ tree->searching = 0;
+ (*tree_keymap [i].fn)(tree);
+ show_tree (tree);
+ return 1;
+ }
+ }
+
+ /* We do not want to use them if we do not need to */
+ /* Input line may want to take the motion key event */
+ if (key == KEY_LEFT)
+ return move_left (tree);
+
+ if (key == KEY_RIGHT)
+ return move_right (tree);
+
+ if (is_abort_char (key)) {
+ if (tree->is_panel) {
+ tree->searching = 0;
+ show_tree (tree);
+ return 1; /* eat abort char */
+ }
+ return 0; /* modal tree dialog: let upper layer see the
+ abort character and close the dialog */
+ }
+
+ /* Do not eat characters not meant for the tree below ' ' (e.g. C-l). */
+ if ((key >= ' '&& key <= 255) || key == 8 || key == KEY_BACKSPACE) {
+ if (tree->searching){
+ tree_do_search (tree, key);
+ show_tree (tree);
+ return 1;
+ }
+
+ if (!command_prompt) {
+ start_search (tree);
+ tree_do_search (tree, key);
+ return 1;
+ }
+ return tree->is_panel;
+ }
+
+ return 0;
+}
+
+static void tree_frame (Dlg_head *h, WTree *tree)
+{
+ attrset (NORMAL_COLOR);
+ widget_erase ((Widget*) tree);
+ if (tree->is_panel)
+ draw_double_box (h, tree->widget.y, tree->widget.x, tree->widget.lines,
+ tree->widget.cols);
+
+ if (show_mini_info && tree->is_panel){
+ widget_move (tree, tlines (tree) + 1, 1);
+ hline (ACS_HLINE, tree->widget.cols - 2);
+ }
+}
+
+
+static int tree_callback (Dlg_head *h, WTree *tree, int msg, int par)
+{
+ switch (msg){
+ case WIDGET_DRAW:
+ tree_frame (h, tree);
+ show_tree (tree);
+ return 1;
+
+ case WIDGET_KEY:
+ return tree_key (tree, par);
+
+ case WIDGET_FOCUS:
+ tree->active = 1;
+ define_label (h, (Widget *)tree, 1, _("Help"), (voidfn) tree_help_cmd);
+ define_label_data (h, (Widget *)tree,
+ 2, _("Rescan"), (buttonbarfn)tree_rescan_cmd, tree);
+ define_label_data (h, (Widget *)tree,
+ 3, _("Forget"), (buttonbarfn)tree_forget_cmd, tree);
+ define_label_data (h, (Widget *)tree,
+ 5, _("Copy"), (buttonbarfn) tree_copy_cmd, tree);
+ define_label_data (h, (Widget *)tree,
+ 6, _("RenMov"), (buttonbarfn) tree_move_cmd, tree);
+#if 0
+ /* FIXME: mkdir is currently defunct */
+ define_label_data (h, (Widget *)tree,
+ 7, _("Mkdir"), (buttonbarfn) tree_mkdir_cmd, tree);
+#else
+ define_label (h, (Widget *)tree, 7, "", 0);
+#endif
+ define_label_data (h, (Widget *)tree,
+ 8, _("Rmdir"), (buttonbarfn) tree_rmdir_cmd, tree);
+ set_navig_label (h);
+ redraw_labels (h, (Widget *)tree);
+
+
+ /* FIXME: Should find a better way of only displaying the
+ currently selected item */
+ show_tree (tree);
+ return 1;
+
+ /* FIXME: Should find a better way of changing the color of the
+ selected item */
+ case WIDGET_UNFOCUS:
+ tree->active = 0;
+ show_tree (tree);
+ return 1;
+ }
+ return default_proc (h, msg, par);
+}
+
+WTree *tree_new (int is_panel, int y, int x, int lines, int cols)
+{
+ WTree *tree = xmalloc (sizeof (WTree), "tree_new");
+
+ init_widget (&tree->widget, y, x, lines, cols, tcallback,
+ (destroy_fn) tree_destroy, (mouse_h) event_callback, NULL);
+ tree->is_panel = is_panel;
+ tree->selected_ptr = 0;
+ tree->tree_shown = 0;
+ tree->search_buffer [0] = 0;
+ tree->tree_first = tree->tree_last = 0;
+ tree->topdiff = tree->widget.lines / 2;
+ tree->searching = 0;
+ tree->done = 0;
+ tree->active = 0;
+
+ /* We do not want to keep the cursor */
+ widget_want_cursor (tree->widget, 0);
+ load_tree (tree);
+ return tree;
+}
+
+static char *get_absolute_name (char *file)
+{
+ char dir [MC_MAXPATHLEN];
+
+ if (file [0] == PATH_SEP)
+ return strdup (file);
+ mc_get_current_wd (dir, MC_MAXPATHLEN);
+ return get_full_name (dir, file);
+}
+
+static int my_mkdir_rec (char *s, mode_t mode)
+{
+ char *p, *q;
+ int result;
+
+ if (!mc_mkdir (s, mode))
+ return 0;
+
+ /* FIXME: should check instead if s is at the root of that filesystem */
+ if (!vfs_file_is_local (s))
+ return -1;
+ if (!strcmp (vfs_path(s), PATH_SEP_STR))
+ return ENOTDIR;
+ p = concat_dir_and_file (s, "..");
+ q = vfs_canon (p);
+ free (p);
+ if (!(result = my_mkdir_rec (q, mode))) {
+ result = mc_mkdir (s, mode);
+ }
+ free (q);
+ return result;
+}
+
+int my_mkdir (char *s, mode_t mode)
+{
+ int result;
+#if FIXME
+ WTree *tree = 0;
+#endif
+
+ result = mc_mkdir (s, mode);
+#ifdef OS2_NT
+ /* .ado: it will be disabled in OS/2 and NT */
+ /* otherwise crash if directory already exists. */
+ return result;
+#endif
+ if (result) {
+ char *p = vfs_canon (s);
+
+ result = my_mkdir_rec (p, mode);
+ free (p);
+ }
+ if (result == 0){
+ s = get_absolute_name (s);
+#if FIXME
+ /* FIXME: Should receive a Wtree! */
+
+ tree_add_entry (tree, s);
+#endif
+ free (s);
+ }
+ return result;
+}
+
+int my_rmdir (char *s)
+{
+ int result;
+#if FIXME
+ WTree *tree = 0;
+#endif
+
+ /* FIXME: Should receive a Wtree! */
+ result = mc_rmdir (s);
+ if (result == 0){
+ s = get_absolute_name (s);
+#if FIXME
+ tree_remove_entry (tree, s);
+#endif
+ free (s);
+ }
+ return result;
+}
+
+
--- /dev/null
+#ifndef __TREE_H
+#define __TREE_H
+
+typedef struct tree_entry {
+ char *name; /* The full path of directory */
+ int sublevel; /* Number of parent directories (slashes) */
+ long submask; /* Bitmask of existing sublevels after this entry */
+ char *subname; /* The last part of name (the actual name) */
+ int mark; /* Flag: Is this entry marked (e. g. for delete)? */
+ struct tree_entry *next; /* Next item in the list */
+ struct tree_entry *prev; /* Previous item in the list */
+} tree_entry;
+
+#include "dlg.h"
+typedef struct {
+ Widget widget;
+ tree_entry *tree_first; /* First entry in the list */
+ tree_entry *tree_last; /* Last entry in the list */
+ tree_entry *selected_ptr; /* The selected directory */
+ char search_buffer [256]; /* Current search string */
+ int done; /* Flag: exit tree */
+ char check_name [MC_MAXPATHLEN];/* Directory which is been checked */
+ tree_entry *check_start; /* Start of checked subdirectories */
+ tree_entry **tree_shown; /* Entries currently on screen */
+ int is_panel; /* panel or plain widget flag */
+ int active; /* if it's currently selected */
+ int searching; /* Are we on searching mode? */
+ int topdiff; /* The difference between the topmost shown and the selected */
+} WTree;
+
+#define tlines(t) (t->is_panel ? t->widget.lines-2 - (show_mini_info ? 2 : 0) : t->widget.lines)
+
+int tree_init (char *current_dir, int lines);
+void load_tree (WTree *tree);
+void save_tree (WTree *tree);
+void show_tree (WTree *tree);
+void tree_chdir (WTree *tree, char *dir);
+void tree_rescan_cmd (WTree *tree);
+int tree_forget_cmd (WTree *tree);
+void tree_copy (WTree *tree, char *default_dest);
+void tree_move (WTree *tree, char *default_dest);
+void tree_event (WTree *tree, int y);
+char *tree (char *current_dir);
+
+int search_tree (WTree *tree, char *text);
+
+tree_entry *tree_add_entry (WTree *tree, char *name);
+void tree_remove_entry (WTree *tree, char *name);
+void tree_destroy (WTree *tree);
+void tree_check (const char *subname);
+void start_tree_check (WTree *tree);
+void do_tree_check (WTree *tree, const char *subname);
+void end_tree_check (WTree *tree);
+
+void tree_move_backward (WTree *tree, int i);
+void tree_move_forward (WTree *tree, int i);
+int tree_move_to_parent (WTree *tree);
+void tree_move_to_child (WTree *tree);
+void tree_move_to_top (WTree *tree);
+void tree_move_to_bottom (WTree *tree);
+
+extern int tree_navigation_flag;
+extern int xtree_mode;
+
+WTree *tree_new (int is_panel, int y, int x, int lines, int cols);
+extern WTree *the_tree;
+
+#ifdef OS2_NT
+# define MC_TREE "mc.tre"
+#else
+# define MC_TREE ".mc/tree"
+#endif
+
+#endif
--- /dev/null
+/* This file takes care of loading ncurses or slang */
+
+int got_interrupt (void);
+void mc_refresh (void);
+
+#ifdef HAVE_SLANG
+# include "myslang.h"
+
+# define TTY_H_DONE
+#else
+# define enable_interrupt_key()
+# define disable_interrupt_key()
+# define slang_shutdown()
+# define slang_done_screen()
+# define slang_init()
+# define slang_init_screen()
+# define slang_init_tty()
+# define slang_done_tty();
+# define acs()
+# define noacs()
+# define one_vline() addch (slow_terminal ? ' ' : ACS_VLINE)
+# define one_hline() addch (slow_terminal ? ' ' : ACS_HLINE)
+#endif
+
+#if !defined(TTY_H_DONE) && defined(USE_NCURSES)
+ /* This is required since ncurses 1.8.6 and newer changed the name of */
+ /* the include files (July 1994) */
+# ifdef RENAMED_NCURSES
+# include <curses.h>
+# else
+# include <ncurses.h>
+# endif
+# ifdef INCLUDE_TERM
+# include <term.h>
+# define TERM_INCLUDED 1
+# endif
+# define TTY_H_DONE
+#endif
+
+#if !defined(TTY_H_DONE) && defined(USE_BSD_CURSES)
+
+ /* This is only to let people that don't want to install ncurses */
+ /* run this nice program; they get what they deserve. */
+
+ /* Ultrix has a better curses: cursesX */
+# ifdef ultrix
+# include <cursesX.h>
+# else
+# include <curses.h>
+# endif
+
+# ifndef ACS_VLINE
+# define ACS_VLINE '|'
+# endif
+
+# ifndef ACS_HLINE
+# define ACS_HLINE '-'
+# endif
+
+# ifndef ACS_ULCORNER
+# define ACS_ULCORNER '+'
+# endif
+
+# ifndef ACS_LLCORNER
+# define ACS_LLCORNER '+'
+# endif
+
+# ifndef ACS_URCORNER
+# define ACS_URCORNER '+'
+# endif
+
+# ifndef ACS_LRCORNER
+# define ACS_LRCORNER '+'
+# endif
+
+# ifndef ACS_LTEE
+# define ACS_LTEE '+'
+# endif
+
+# ifndef KEY_BACKSPACE
+# define KEY_BACKSPACE 0
+# endif
+
+# ifndef KEY_END
+# define KEY_END 0
+# endif
+
+# define ACS_MAP(x) '*'
+
+# define NO_COLOR_SUPPORT
+# define untouchwin(win)
+# define xgetch x_getch
+# define wtouchln(win,b,c,d) touchwin(win)
+# define derwin(win,x,y,z,w) win
+# define wscrl(win,n)
+# define TTY_H_DONE
+#endif
+
+#if !defined(TTY_H_DONE) && defined(USE_SYSV_CURSES)
+# include <curses.h>
+# ifdef INCLUDE_TERM
+# include <term.h>
+ /* Ugly hack to avoid name space pollution */
+# undef cols
+# undef lines
+# undef buttons
+
+# define TERM_INCLUDED 1
+# endif
+
+# if defined(sparc) || defined(__sgi) || defined(_SGI_SOURCE)
+ /* We are dealing with Solaris or SGI buggy curses :-) */
+# define BUGGY_CURSES 1
+# endif
+# if defined(mips) && defined(sgi)
+ /* GNU C compiler, buggy sgi */
+# define BUGGY_CURSES 1
+# endif
+
+# ifdef __osf__
+# define untouchwin(win)
+# endif
+
+#endif /* USE_SYSV_CURSES */
+
+#ifdef NO_COLOR_SUPPORT
+# define COLOR_PAIR(x) 1
+
+enum {
+ COLOR_BLACK, COLOR_RED, COLOR_GREEN, COLOR_YELLOW,
+ COLOR_BLUE, COLOR_MAGENTA, COLOR_CYAN, COLOR_WHITE
+};
+
+int init_pair (int, int, int);
+
+#endif
+
+#define KEY_KP_ADD 4001
+#define KEY_KP_SUBTRACT 4002
+#define KEY_KP_MULTIPLY 4003
+
--- /dev/null
+/* User Menu implementation
+ Copyright (C) 1994 Miguel de Icaza, Janne Kukonlehto
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#ifdef OS2_NT
+# include <io.h>
+#endif
+#include "tty.h"
+#include <stdlib.h> /* For free() */
+#include "fs.h"
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "mad.h"
+#include "util.h"
+#include "global.h"
+#include "dialog.h"
+#include "color.h"
+#include "dir.h"
+#include "panel.h"
+#include "main.h"
+#include "user.h"
+#include "layout.h"
+#include "../vfs/vfs.h"
+
+/* For the simple listbox manager */
+#include "dlg.h"
+#include "widget.h"
+#include "wtools.h"
+
+#include "view.h" /* for default_* externs */
+
+/* "$Id: user.c,v 1.1 2001/12/30 09:55:20 sedwards Exp $" */
+
+#define MAX_ENTRIES 40
+#define MAX_ENTRY_LEN 60
+
+static char *data;
+static char *entries [MAX_ENTRIES];
+static int max_cols;
+static int menu_lines;
+static int debug_flag = 0;
+static int debug_error = 0;
+extern char *search_string (char *, char *);
+
+/* Formats defined:
+ %% The % character
+ %f The current file (if non-local vfs, file will be copied locally and
+ %f will be full path to it).
+ %p The current file
+ %d The current working directory
+ %s "Selected files"; the tagged files if any, otherwise the current file
+ %t Tagged files
+ %u Tagged files (and they are untagged on return from expand_format)
+ %view Runs the commands and pipes standard output to the view command
+ if %view is directly followed by '{', a list of keywords
+ ascii, hex, nroff, unformated and
+
+ If the format letter is in uppercase, it refers to the other panel.
+
+ With a number followed the % character you can turn quoting on (default)
+ and off. For example:
+ %f quote expanded macro
+ %1f ditto
+ %0f don't quote expanded macro
+
+ expand_format returns a memory block that must be free()d.
+*/
+
+/* Returns how many characters we should advance if %view was found */
+int check_format_view (char *p)
+{
+ char *q = p;
+ if (!strncmp (p, "view", 4)){
+ q += 4;
+ if (*q == '{'){
+ for (q++;*q && *q != '}';q++){
+ if (!strncmp (q, "ascii", 5)){
+ default_hex_mode = 0;
+ q += 4;
+ } else if (!strncmp (q, "hex", 3)){
+ default_hex_mode = 1;
+ q += 2;
+ } else if (!strncmp (q, "nroff", 5)){
+ default_nroff_flag = 1;
+ q += 4;
+ } else if (!strncmp (q, "unformated", 10)){
+ default_nroff_flag = 0;
+ q += 9;
+ }
+ }
+ if (*q == '}')
+ q++;
+ }
+ return q - p;
+ } else
+ return 0;
+}
+
+int check_format_cd (char *p)
+{
+ if (!strncmp (p, "cd", 2))
+ return 3;
+ else
+ return 0;
+}
+
+/* Check if p has a "^var\{var-name\}" */
+/* Returns the number of skipped characters (zero on not found) */
+/* V will be set to the expanded variable name */
+int check_format_var (char *p, char **v)
+{
+ char *q = p;
+ char *var_name;
+ char *value;
+ char *dots;
+
+ *v = 0;
+ dots = 0;
+ if (!strncmp (p, "var{", 4)){
+ for (q += 4; *q && *q != '}'; q++){
+ if (*q == ':')
+ dots = q+1;
+ ;
+ }
+ if (!*q)
+ return 0;
+
+ if (!dots || dots == q+5){
+ message (1,
+ " Format error on file Extensions File ",
+ !dots ? " The %%var macro does not have a default "
+ : " The %%var macros does not have a variable " );
+ return 0;
+ }
+
+ /* Copy the variable name */
+ var_name = xmalloc (dots - p, "check_format_var");
+ strncpy (var_name, p+4, dots-2 - (p+3));
+ var_name [dots-2 - (p+3)] = 0;
+
+ value = getenv (var_name);
+ if (value){
+ *v = strdup (value);
+ return q-p;
+ }
+ free (var_name);
+ var_name = xmalloc (q - dots + 1, "check_format_var_2");
+ strncpy (var_name, dots, q - dots + 1);
+ var_name [q-dots] = 0;
+ *v = var_name;
+ return q-p;
+ }
+ return 0;
+}
+
+/* strip file's extension */
+char *strip_ext(char *ss)
+{
+ register char *s = ss;
+ char *e = NULL;
+ while(*s) {
+ if(*s == '.') e = s;
+ if(*s == PATH_SEP && e) e=NULL; /* '.' in *directory* name */
+ s++;
+ }
+ if(e) *e = 0;
+ return ss;
+}
+
+char *expand_format (char c, int quote)
+{
+ WPanel *panel;
+ char *(*quote_func)(const char *, int);
+
+ if (quote)
+ quote_func = name_quote;
+ else
+ quote_func = fake_name_quote;
+
+ if (c == '%')
+ return strdup ("%");
+
+ if (islower (c))
+ panel = cpanel;
+ else {
+ if (get_other_type () == view_listing){
+ panel = other_panel;
+ } else
+ return strdup ("");
+ }
+ if (!panel)
+ panel = cpanel;
+
+ c = tolower (c);
+
+ switch (c){
+ case 'f':
+ case 'p': return (*quote_func) (panel->dir.list [panel->selected].fname, 0);
+ case 'b':
+ return strip_ext((*quote_func) (panel->dir.list [panel->selected].fname, 0));
+ case 'd': return (*quote_func) (panel->cwd, 0);
+ case 's':
+ if (!panel->marked)
+ return (*quote_func) (panel->dir.list [panel->selected].fname, 0);
+
+ /* Fall through */
+
+ case 't':
+ case 'u':
+ {
+ int length = 2, i;
+ char *block, *tmp;
+
+ for (i = 0; i < panel->count; i++)
+ if (panel->dir.list [i].f.marked)
+ length += strlen (panel->dir.list [i].fname) + 1;
+
+ block = xmalloc (length*2+1, "expand_format");
+ *block = 0;
+ for (i = 0; i < panel->count; i++)
+ if (panel->dir.list [i].f.marked){
+ strcat (block, tmp = (*quote_func) (panel->dir.list [i].fname, 0));
+ free (tmp);
+ strcat (block, " ");
+ if (c == 'u')
+ do_file_mark (panel, i, 0);
+ }
+ return block;
+ } /* sub case block */
+ } /* switch */
+ return strdup ("");
+}
+
+/* Checks for shell patterns defination */
+char *check_patterns (char *p)
+{
+ const char *def_name = "shell_patterns=";
+ int value;
+
+ if (strncmp (p, def_name, sizeof (def_name)) == 0){
+ p += strlen (def_name);
+ value = *p++ - '0';
+ if (value == 0 || value == 1)
+ easy_patterns = value;
+ else
+ message (1, MSG_ERROR, _(" Invalid shell pattern defination \"%c\". "), value + '0');
+ }
+ while (*p == '\n' || *p == '\t' || *p == ' ') p++;
+ return p;
+}
+
+/* Copies a whitespace separated argument from p to arg. Returns the
+ point after argument. */
+static char *extract_arg (char *p, char *arg)
+{
+ while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
+ p++;
+ while (*p && *p != ' ' && *p != '\t' && *p != '\n')
+ *arg++ = *p++;
+ *arg = 0;
+ if (!*p || *p == '\n')
+ p --;
+ return p;
+}
+
+/* Tests whether the selected file in the panel is of any of the types
+ specified in argument. */
+static int test_type (WPanel *panel, char *arg)
+{
+ int result = 0; /* False by default */
+ int st_mode = panel->dir.list [panel->selected].buf.st_mode;
+
+ for (;*arg != 0; arg++){
+ switch (*arg){
+ case 'n': /* Not a directory */
+ result |= !S_ISDIR (st_mode);
+ break;
+ case 'r': /* Regular file */
+ result |= S_ISREG (st_mode);
+ break;
+ case 'd': /* Directory */
+ result |= S_ISDIR (st_mode);
+ break;
+ case 'l': /* Link */
+ result |= S_ISLNK (st_mode);
+ break;
+ case 'c': /* Character special */
+ result |= S_ISCHR (st_mode);
+ break;
+ case 'b': /* Block special */
+ result |= S_ISBLK (st_mode);
+ break;
+ case 'f': /* Fifo (named pipe) */
+ result |= S_ISFIFO (st_mode);
+ break;
+ case 's': /* Socket */
+ result |= S_ISSOCK (st_mode);
+ break;
+ case 'x': /* Executable */
+ result |= (st_mode & 0111) ? 1 : 0;
+ break;
+ case 't':
+ result |= panel->marked ? 1 : 0;
+ break;
+ default:
+ debug_error = 1;
+ break;
+ }
+ }
+ return result;
+}
+
+/* Calculates the truth value of the next condition starting from
+ p. Returns the point after condition. */
+static char *test_condition (char *p, int *condition)
+{
+ WPanel *panel;
+ char arg [256];
+
+ /* Handle one condition */
+ for (;*p != '\n' && *p != '&' && *p != '|'; p++){
+ if (*p == ' ' || *p == '\t')
+ continue;
+ if (*p >= 'a')
+ panel = cpanel;
+ else {
+ if (get_other_type () == view_listing)
+ panel = other_panel;
+ else
+ panel = NULL;
+ }
+ *p |= 0x20;
+
+ switch (*p++){
+ case '!':
+ p = test_condition (p, condition);
+ *condition = ! *condition;
+ p--;
+ break;
+ case 'f':
+ p = extract_arg (p, arg);
+ *condition = panel && regexp_match (arg, panel->dir.list [panel->selected].fname, match_file);
+ break;
+ case 'd':
+ p = extract_arg (p, arg);
+ *condition = panel && regexp_match (arg, panel->cwd, match_file);
+ break;
+ case 't':
+ p = extract_arg (p, arg);
+ *condition = panel && test_type (panel, arg);
+ break;
+ default:
+ debug_error = 1;
+ break;
+ } /* switch */
+
+ } /* while */
+ return p;
+}
+
+/* General purpose condition debug output handler */
+void debug_out (char *start, char *end, int cond)
+{
+ static char msg [256];
+ int len;
+
+ if (start == NULL && end == NULL){
+ if (cond == 0){
+ /* Init */
+ msg [0] = 0;
+ } else {
+ /* Show output */
+ if (!debug_flag)
+ return;
+ len = strlen (msg);
+ if (len)
+ msg [len - 1] = 0;
+ message (0, _(" Debug "), msg);
+ debug_flag = 0;
+ }
+ } else {
+ /* Save debug info for later output */
+ if (!debug_flag)
+ return;
+ /* Save the result of the condition */
+ if (debug_error){
+ strcat (msg, _(" ERROR: "));
+ debug_error = 0;
+ }
+ else if (cond)
+ strcat (msg, _(" True: "));
+ else
+ strcat (msg, _(" False: "));
+ /* Copy condition statement */
+ len = strlen (msg);
+ if (end == NULL){
+ /* Copy one character */
+ msg [len] = *start;
+ msg [len + 1] = 0;
+ } else {
+ /* Copy many characters */
+ while (start < end){
+ msg [len++] = *start++;
+ }
+ msg [len] = 0;
+ }
+ strcat (msg, " \n");
+ }
+}
+
+/* Calculates the truth value of one lineful of conditions. Returns
+ the point just before the end of line. */
+static char *test_line (char *p, int *result)
+{
+ int condition;
+ char operator;
+ char *debug_start, *debug_end;
+
+ /* Init debugger */
+ debug_out (NULL, NULL, 0);
+ /* Repeat till end of line */
+ while (*p && *p != '\n'){
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!*p || *p == '\n')
+ break;
+ operator = *p++;
+ if (*p == '?'){
+ debug_flag = 1;
+ p++;
+ }
+ while (*p == ' ' || *p == '\t')
+ p++;
+ if (!*p || *p == '\n')
+ break;
+ condition = 1; /* True by default */
+
+ debug_start = p;
+ p = test_condition (p, &condition);
+ debug_end = p;
+ /* Add one debug statement */
+ debug_out (debug_start, debug_end, condition);
+
+ switch (operator){
+ case '+':
+ case '=':
+ /* Assignment */
+ *result = condition;
+ break;
+ case '&': /* Logical and */
+ *result &= condition;
+ break;
+ case '|': /* Logical or */
+ *result |= condition;
+ break;
+ default:
+ debug_error = 1;
+ break;
+ } /* switch */
+ /* Add one debug statement */
+ debug_out (&operator, NULL, *result);
+
+ } /* while (*p != '\n') */
+ /* Report debug message */
+ debug_out (NULL, NULL, 1);
+
+ if (!*p || *p == '\n')
+ p --;
+ return p;
+}
+
+/* FIXME: recode this routine on version 3.0, it could be cleaner */
+void execute_menu_command (char *s)
+{
+ char *commands;
+ FILE *cmd_file;
+ int cmd_file_fd;
+ int expand_prefix_found = 0;
+ int parameter_found = 0;
+ int do_quote;
+ char prompt [80] = "";
+ int col;
+ char *file_name = tmpnam (0);
+
+#ifdef OS2_NT
+ /* OS/2 and NT requires the command to end in .cmd */
+ file_name = copy_strings (file_name, ".cmd", NULL);
+#endif
+ if ((cmd_file_fd = open (file_name, O_RDWR | O_CREAT | O_TRUNC | O_EXCL, 0600)) == -1){
+ message (1, MSG_ERROR, _(" Can't create temporary command file \n %s "),
+ unix_error_string (errno));
+ return;
+ }
+ cmd_file = fdopen (cmd_file_fd, "w");
+ commands = strchr (s, '\n');
+ if (!commands){
+ fclose (cmd_file);
+ unlink (file_name);
+ return;
+ }
+ commands++;
+
+ for (col = 0; *commands; commands++){
+ if (col == 0 && (*commands != ' ' && *commands != '\t'))
+ break;
+ else if (col == 0)
+ while (*commands == ' ' || *commands == '\t')
+ commands++;
+ col++;
+ if (*commands == '\n')
+ col = 0;
+ if (parameter_found){
+ if (*commands == '}'){
+ char *parameter;
+ char *tmp;
+ parameter_found = 0;
+ parameter = input_dialog (_(" Parameter "), prompt, "");
+ if (!parameter || !*parameter){
+ /* User canceled */
+ fclose (cmd_file);
+ unlink (file_name);
+ return;
+ }
+ if (do_quote) {
+ fputs (tmp = name_quote (parameter, 0), cmd_file);
+ free (tmp);
+ } else
+ fputs (parameter, cmd_file);
+ free (parameter);
+ } else {
+ int len = strlen (prompt);
+
+ if (len+1 < sizeof (prompt)){
+ prompt [len] = *commands;
+ prompt [len+1] = 0;
+ } else
+ prompt [sizeof (prompt)-1] = 0;
+ }
+ } else if (expand_prefix_found){
+ expand_prefix_found = 0;
+ if (isdigit (*commands)) {
+ do_quote = atoi (commands);
+ for ( ; isdigit (*commands); commands++)
+ ;
+ }
+ if (*commands == '{')
+ parameter_found = 1;
+ else{
+ char *text = expand_format (*commands, do_quote);
+ fputs (text, cmd_file);
+ free (text);
+ }
+ } else {
+ if (*commands == '%') {
+ do_quote = 1; /* Default: Quote expanded macro */
+ expand_prefix_found = 1;
+ } else
+ fputc (*commands, cmd_file);
+ }
+ }
+ fclose (cmd_file);
+ chmod (file_name, S_IRWXU);
+ execute (file_name);
+ unlink (file_name);
+}
+
+/*
+** Check owner of the menu file. Using menu file is allowed, if
+** owner of the menu is root or the actual user. In either case
+** file should not be group and word-writable.
+**
+** Q. Should we apply this routine to system and home menu (and .ext files)?
+*/
+static int
+menu_file_own(char* path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == 0
+ && (!st.st_uid || (st.st_uid == geteuid ()))
+ && ((st.st_mode & (S_IWGRP | S_IWOTH)) == 0)
+ ) {
+ return 1;
+ }
+ else
+ {
+ extern int verbose;
+ if (verbose)
+ {
+ message (0, _(" Warning -- ignoring file "),
+ _("File %s is not owned by root or you or is world writable.\n"
+ "Using it may compromise your security"),
+ path
+ );
+ }
+ return 0;
+ }
+}
+
+void user_menu_cmd (void)
+{
+ char *menu, *p;
+ int col, i, accept_entry = 1;
+ int selected, old_patterns;
+ Listbox *listbox;
+
+ if (!vfs_current_is_local ()){
+ message (1, _(" Oops... "),
+ _(" I can't run programs while logged on a non local directory "));
+ return;
+ }
+
+ menu = strdup (MC_LOCAL_MENU);
+ if (!exist_file (menu) || !menu_file_own (menu)){
+ free (menu);
+ menu = concat_dir_and_file (home_dir, MC_HOME_MENU);
+ if (!exist_file (menu)){
+ free (menu);
+ menu = concat_dir_and_file (mc_home, MC_GLOBAL_MENU);
+ }
+ }
+
+ if ((data = load_file (menu)) == NULL){
+ message (1, MSG_ERROR, _(" Can't open file %s \n %s "),
+ menu, unix_error_string (errno));
+ free (menu);
+ return;
+ }
+ free (menu);
+
+ max_cols = 0;
+ for (i = 0; i < MAX_ENTRIES; i++)
+ entries [i] = 0;
+ selected = 0;
+
+ /* Parse the menu file */
+ old_patterns = easy_patterns;
+ p = check_patterns (data);
+ for (menu_lines = col = 0; *p; p++){
+ if (col == 0 && !entries [menu_lines]){
+ if (*p == '#'){
+ /* A commented menu entry */
+ accept_entry = 1;
+ } else if (*p == '+'){
+ if (*(p+1) == '='){
+ /* Combined adding and default */
+ char *q = p++;
+
+ p = test_line (q, &accept_entry);
+ if (selected == 0 && accept_entry)
+ selected = menu_lines;
+ } else {
+ /* A condition for adding the entry */
+ p = test_line (p, &accept_entry);
+ }
+ } else if (*p == '='){
+ if (*(p+1) == '+'){
+ char *q = p++;
+ /* Combined adding and default */
+ p = test_line (q, &accept_entry);
+ if (selected == 0 && accept_entry)
+ selected = menu_lines;
+ } else {
+ /* A condition for making the entry default */
+ i = 1;
+ p = test_line (p, &i);
+ if (selected == 0 && i)
+ selected = menu_lines;
+ }
+ }
+ else if (*p > ' ' && *p < 127){
+ /* A menu entry title line */
+ if (accept_entry)
+ entries [menu_lines] = p;
+ else
+ accept_entry = 1;
+ }
+ }
+ if (menu_lines == MAX_ENTRIES)
+ break;
+ if (*p == '\t')
+ *p = ' ';
+ col++;
+ if (*p == '\n'){
+ if (entries [menu_lines]){
+ menu_lines++;
+ accept_entry = 1;
+ }
+ max_cols = max (max_cols, col);
+ col = 0;
+ }
+ }
+ max_cols = min (max (max_cols, col), MAX_ENTRY_LEN);
+
+ /* Create listbox */
+ listbox = create_listbox_window (max_cols+2, menu_lines, _(" User menu "),
+ "[Menu File Edit]");
+
+ /* insert all the items found */
+ for (i = 0; i < menu_lines; i++)
+ LISTBOX_APPEND_TEXT (listbox, entries [i][0],
+ extract_line (entries [i],
+ entries [i]+MAX_ENTRY_LEN),
+ entries [i]);
+
+ /* Select the default entry */
+ listbox_select_by_number (listbox->list, selected);
+
+ selected = run_listbox (listbox);
+ if (selected >= 0)
+ execute_menu_command (entries [selected]);
+
+ easy_patterns = old_patterns;
+ do_refresh ();
+ free (data);
+}
--- /dev/null
+#ifndef __USER_H
+#define __USER_H
+
+void user_menu_cmd (void);
+char *expand_format (char, int);
+int check_format_view (char *);
+int check_format_var (char *p, char **v);
+int check_format_cd (char *);
+char *check_patterns (char*);
+
+#ifdef OS2_NT
+# define MC_LOCAL_MENU "mc.mnu"
+# define MC_GLOBAL_MENU "mc.mnu"
+# define MC_HOME_MENU "mc.mnu"
+# define MC_HINT "mc.hnt"
+#else
+# define MC_GLOBAL_MENU "mc.menu"
+# define MC_LOCAL_MENU ".mc.menu"
+# define MC_HOME_MENU ".mc/menu"
+# define MC_HINT "mc.hint"
+#endif
+
+#endif
--- /dev/null
+/* Various utilities
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+ Written 1994, 1995, 1996 by:
+ Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
+ Jakub Jelinek, Mauricio Plaza.
+
+ The file_date routine is mostly from GNU's fileutils package,
+ written by Richard Stallman and David MacKenzie.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#if defined(__os2__) /* OS/2 need io.h! .ado */
+# include <io.h>
+#endif
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <signal.h> /* my_system */
+#include <limits.h> /* INT_MAX */
+#ifndef SCO_FLAVOR
+#if defined (__MINGW32__) || defined(_MSC_VER)
+# include <sys/time.h___>
+#else
+# include <sys/time.h> /* alex: sys/select.h defines struct timeval */
+#endif
+#endif /* SCO_FLAVOR */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#include <errno.h> /* my_system */
+#ifdef SCO_FLAVOR
+# include <sys/timeb.h> /* alex: for struct timeb, used in time.h */
+#endif /* SCO_FLAVOR */
+#include <time.h>
+#ifndef OS2_NT
+# include <pwd.h>
+# include <grp.h>
+#endif
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+
+#ifdef __linux__
+# if defined(__GLIBC__) && (__GLIBC__ < 2)
+# include <linux/termios.h> /* This is needed for TIOCLINUX */
+# else
+# include <termios.h>
+# endif
+# include <sys/ioctl.h>
+#endif
+
+#include "fs.h"
+#include "mountlist.h"
+
+/* From dialog.h (not wanting to include it as
+ it requires including a lot of other files, too) */
+int message (int error, char *header, char *text, ...);
+
+#include "mad.h"
+#if defined(HAVE_RX_H) && defined(HAVE_REGCOMP)
+#include <rx.h>
+#else
+#include "regex.h"
+#endif
+#include "util.h"
+#include "global.h"
+#include "profile.h"
+#include "user.h" /* expand_format */
+#include "../vfs/vfs.h"
+
+/* "$Id: util.c,v 1.1 2001/12/30 09:55:20 sedwards Exp $" */
+
+char app_text [] = "Midnight-Commander";
+
+int easy_patterns = 1;
+int align_extensions = 1;
+int tilde_trunc = 1;
+
+struct mount_entry *mount_list = NULL;
+
+#ifndef HAVE_STRDUP
+char *strdup (const char *s)
+{
+ char *t = malloc (strlen (s)+1);
+ strcpy (t, s);
+ return t;
+}
+#endif
+
+int is_printable (int c)
+{
+ static const unsigned char xterm_printable[] = {
+ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,
+ 1,1,1,1,0,0,1,1,0,1,1,1,1,0,0,0,0,1,1,1,1,1,0,0,0,1,0,0,0,0,0,0,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
+ };
+
+ extern int xterm_flag;
+ extern int eight_bit_clean;
+ extern int full_eight_bits;
+
+ c &= 0xff;
+ if (eight_bit_clean){
+ if (full_eight_bits){
+ if (xterm_flag)
+ return xterm_printable [c];
+ else
+ return (c > 31 && c != 127);
+ } else
+ return ((c >31 && c < 127) || c >= 160);
+ } else
+ return (c > 31 && c < 127);
+}
+
+/* Returns the message dimensions (lines and columns) */
+int msglen (char *text, int *lines)
+{
+ int max = 0;
+ int line_len = 0;
+
+ for (*lines = 1;*text; text++){
+ if (*text == '\n'){
+ line_len = 0;
+ (*lines)++;
+ } else {
+ line_len++;
+ if (line_len > max)
+ max = line_len;
+ }
+ }
+ return max;
+}
+
+char *trim (char *s, char *d, int len)
+{
+ int source_len = strlen (s);
+
+ if (source_len > len){
+ strcpy (d, s+(source_len-len));
+ d [0] = '.';
+ d [1] = '.';
+ d [2] = '.';
+ } else
+ strcpy (d, s);
+ return d;
+}
+
+char *
+name_quote (const char *s, int quote_percent)
+{
+ char *ret, *d;
+
+ d = ret = xmalloc (strlen (s)*2 + 2 + 1, "quote_name");
+ if (*s == '-') {
+ *d++ = '.';
+ *d++ = '/';
+ }
+
+ for (; *s; s++, d++) {
+ switch (*s)
+ {
+ case '%':
+ if (quote_percent)
+ *d++ = '%';
+ break;
+ case '\'':
+ case '\\':
+ case '\r':
+ case '\n':
+ case '\t':
+ case '$':
+ case '?':
+ case '*':
+ case '(':
+ case ')':
+ case '[':
+ case ']':
+ case '"':
+ case '!':
+ case '&':
+ case '#':
+ case '`':
+ case ' ':
+ *d++ = '\\';
+ }
+ *d = *s;
+ }
+ *d = '\0';
+ return ret;
+}
+
+char *
+fake_name_quote (const char *s, int quote_percent)
+{
+ return strdup (s);
+}
+
+/* If passed an empty txt (this usually means that there is an error)
+ * in the upper layers, we return "/"
+ */
+char *name_trunc (char *txt, int trunc_len)
+{
+ static char x [MC_MAXPATHLEN+MC_MAXPATHLEN];
+ int txt_len;
+ char *p;
+
+ if (!txt)
+ txt = PATH_SEP_STR;
+
+ if (trunc_len > sizeof (x)-1){
+ fprintf (stderr, _("name_trunc: too big"));
+ trunc_len = sizeof (x)-1;
+ }
+ txt_len = strlen (txt);
+ if (txt_len <= trunc_len)
+ strcpy (x, txt);
+ else if (tilde_trunc){
+ int y = trunc_len % 2;
+ strncpy (x, txt, (trunc_len/2)+y);
+ strncpy (x+(trunc_len/2)+y, txt+txt_len-(trunc_len/2), trunc_len/2);
+ x [(trunc_len/2)+y] = '~';
+ } else {
+ strncpy (x, txt, trunc_len-1);
+ x [trunc_len-1] = '>';
+ }
+ x [trunc_len] = 0;
+ for (p = x; *p; p++)
+ if (!is_printable (*p))
+ *p = '?';
+ return x;
+}
+
+char *size_trunc (long int size)
+{
+ static char x [30];
+ long int divisor = 1;
+ char *xtra = "";
+
+ if (size > 999999999L){
+ divisor = 1024;
+ xtra = "kb";
+ if (size/divisor > 999999999L){
+ divisor = 1024*1024;
+ xtra = "Mb";
+ }
+ }
+ sprintf (x, "%ld%s", (size/divisor), xtra);
+ return x;
+}
+
+char *size_trunc_sep (long int size)
+{
+ static char x [60];
+ int count;
+ char *p, *d, *y;
+
+ p = y = size_trunc (size);
+ p += strlen (p) - 1;
+ d = x + sizeof (x) - 1;
+ *d-- = 0;
+ while (p >= y && isalpha (*p))
+ *d-- = *p--;
+ for (count = 0; p >= y; count++){
+ if (count == 3){
+ *d-- = ',';
+ count = 0;
+ }
+ *d-- = *p--;
+ }
+ d++;
+ if (*d == ',')
+ d++;
+ return d;
+}
+
+int is_exe (mode_t mode)
+{
+ if ((S_IXUSR & mode) || (S_IXGRP & mode) || (S_IXOTH & mode))
+ return 1;
+ return 0;
+}
+
+#define ismode(n,m) ((n & m) == m)
+
+char *string_perm (mode_t mode_bits)
+{
+ static char mode [11];
+
+ strcpy (mode, "----------");
+ if (ismode (mode_bits, S_IFDIR)) mode [0] = 'd';
+#ifdef S_IFSOCK
+ if (ismode (mode_bits, S_IFSOCK)) mode [0] = 's';
+#endif
+ if (ismode (mode_bits, S_IXOTH)) mode [9] = 'x';
+ if (ismode (mode_bits, S_IWOTH)) mode [8] = 'w';
+ if (ismode (mode_bits, S_IROTH)) mode [7] = 'r';
+ if (ismode (mode_bits, S_IXGRP)) mode [6] = 'x';
+ if (ismode (mode_bits, S_IWGRP)) mode [5] = 'w';
+ if (ismode (mode_bits, S_IRGRP)) mode [4] = 'r';
+ if (ismode (mode_bits, S_IXUSR)) mode [3] = 'x';
+ if (ismode (mode_bits, S_IWUSR)) mode [2] = 'w';
+ if (ismode (mode_bits, S_IRUSR)) mode [1] = 'r';
+#ifndef OS2_NT
+ if (ismode (mode_bits, S_ISUID)) mode [3] = (mode [3] == 'x') ? 's' : 'S';
+ if (ismode (mode_bits, S_ISGID)) mode [6] = (mode [6] == 'x') ? 's' : 'S';
+ if (ismode (mode_bits, S_IFCHR)) mode [0] = 'c';
+ if (ismode (mode_bits, S_IFBLK)) mode [0] = 'b';
+ if (ismode (mode_bits, S_ISVTX)) mode [9] = (mode [9] == 'x') ? 't' : 'T';
+ if (ismode (mode_bits, S_IFLNK)) mode [0] = 'l';
+ if (ismode (mode_bits, S_IFIFO)) mode [0] = 's';
+#endif
+ return mode;
+}
+
+static char *
+strip_password (char *path)
+{
+ char *at, *inner_colon, *dir;
+
+ if ((dir = strchr (path, PATH_SEP)) != NULL)
+ *dir = '\0';
+ /* search for any possible user */
+ at = strchr (path, '@');
+
+ /* We have a username */
+ if (at) {
+ *at = 0;
+ inner_colon = strchr (path, ':');
+ *at = '@';
+ if (inner_colon)
+ strcpy (inner_colon, at);
+ }
+ if (dir)
+ *dir = PATH_SEP;
+ return (path);
+}
+
+char *strip_home_and_password(char *dir)
+{
+ static char newdir [MC_MAXPATHLEN], *p, *q;
+
+ if (home_dir && !strncmp (dir, home_dir, strlen (home_dir))){
+ newdir [0] = '~';
+ strcpy (&newdir [1], &dir [strlen (home_dir)]);
+ return newdir;
+ }
+#ifdef USE_NETCODE
+ else if (!strncmp (dir, "ftp://", 6)) {
+ strip_password (strcpy (newdir, dir) + 6);
+ if ((p = strchr (newdir + 6, PATH_SEP)) != NULL) {
+ *p = 0;
+ q = ftpfs_gethome (newdir);
+ *p = PATH_SEP;
+ if (q != 0 && strcmp (q, PATH_SEP_STR) && !strncmp (p, q, strlen (q) - 1)) {
+ strcpy (p, "/~");
+ strcat (newdir, p + strlen (q) - 1);
+ }
+ }
+ return newdir;
+ } else if (!strncmp (dir, "mc:", 3)) {
+ char *pth;
+ strcpy (newdir, dir);
+ if (newdir[3] == '/' && newdir[4] == '/') {
+ pth = newdir + 5;
+ strip_password ( newdir + 5);
+ } else {
+ pth = newdir + 3;
+ strip_password (newdir + 3);
+ }
+ if ((p = strchr (pth, PATH_SEP)) != NULL) {
+ *p = 0;
+ q = mcfs_gethome (newdir);
+ *p = PATH_SEP;
+ if (q != NULL ) {
+ if (strcmp (q, PATH_SEP_STR) && !strncmp (p, q, strlen (q) - 1)) {
+ strcpy (p, "/~");
+ strcat (newdir, p + strlen (q) - 1);
+ }
+ free (q);
+ }
+ }
+ return (newdir);
+ }
+#endif
+ return dir;
+}
+
+static char *maybe_start_group (char *d, int do_group, int *was_wildcard)
+{
+ if (!do_group)
+ return d;
+ if (*was_wildcard)
+ return d;
+ *was_wildcard = 1;
+ *d++ = '\\';
+ *d++ = '(';
+ return d;
+}
+
+static char *maybe_end_group (char *d, int do_group, int *was_wildcard)
+{
+ if (!do_group)
+ return d;
+ if (!*was_wildcard)
+ return d;
+ *was_wildcard = 0;
+ *d++ = '\\';
+ *d++ = ')';
+ return d;
+}
+
+/* If shell patterns are on converts a shell pattern to a regular
+ expression. Called by regexp_match and mask_rename. */
+/* Shouldn't we support [a-fw] type wildcards as well ?? */
+char *convert_pattern (char *pattern, int match_type, int do_group)
+{
+ char *s, *d;
+ char *new_pattern;
+ int was_wildcard = 0;
+
+ if (easy_patterns){
+ new_pattern = malloc (MC_MAXPATHLEN);
+ d = new_pattern;
+ if (match_type == match_file)
+ *d++ = '^';
+ for (s = pattern; *s; s++, d++){
+ switch (*s){
+ case '*':
+ d = maybe_start_group (d, do_group, &was_wildcard);
+ *d++ = '.';
+ *d = '*';
+ break;
+
+ case '?':
+ d = maybe_start_group (d, do_group, &was_wildcard);
+ *d = '.';
+ break;
+
+ case '.':
+ d = maybe_end_group (d, do_group, &was_wildcard);
+ *d++ = '\\';
+ *d = '.';
+ break;
+
+ default:
+ d = maybe_end_group (d, do_group, &was_wildcard);
+ *d = *s;
+ break;
+ }
+ }
+ d = maybe_end_group (d, do_group, &was_wildcard);
+ if (match_type == match_file)
+ *d++ = '$';
+ *d = 0;
+ return new_pattern;
+ } else
+ return strdup (pattern);
+}
+
+int regexp_match (char *pattern, char *string, int match_type)
+{
+ static regex_t r;
+ static char *old_pattern = NULL;
+ static int old_type;
+ int rval;
+
+ if (!old_pattern || STRCOMP (old_pattern, pattern) || old_type != match_type){
+ if (old_pattern){
+ regfree (&r);
+ free (old_pattern);
+ }
+ pattern = convert_pattern (pattern, match_type, 0);
+ if (regcomp (&r, pattern, REG_EXTENDED|REG_NOSUB|MC_ARCH_FLAGS)) {
+ free (pattern);
+ return -1;
+ }
+ old_pattern = pattern;
+ old_type = match_type;
+ }
+ rval = !regexec (&r, string, 0, NULL, 0);
+ return rval;
+}
+
+char *extension (char *filename)
+{
+ char *d;
+
+ if (!strlen (filename))
+ return "";
+
+ d = filename + strlen (filename) - 1;
+ for (;d >= filename; d--){
+ if (*d == '.')
+ return d+1;
+ }
+ return "";
+}
+
+/* This routine uses the fact that x is at most 14 chars or so */
+char *split_extension (char *x, int pad)
+{
+ return x;
+
+ /* Buggy code
+ if (!align_extensions)
+ return x;
+
+ if (strlen (x) >= pad)
+ return x;
+
+ if ((ext = extension (x)) == x || *ext == 0)
+ return x;
+
+ strcpy (xbuf, x);
+ for (i = strlen (x); i < pad; i++)
+ xbuf [i] = ' ';
+ xbuf [pad] = 0;
+
+ l = strlen (ext);
+ for (i = 0; i < l; i++)
+ xbuf [pad-i] = *(ext+l-i-1);
+ for (i = xbuf + (ext - x); i <
+ return xbuf; */
+}
+
+#ifndef HAVE_MAD
+void *do_xmalloc (int size)
+{
+ void *m = malloc (size);
+
+ if (!m){
+ fprintf (stderr, "memory exhausted\n");
+ exit (1);
+ }
+ return m;
+}
+#endif /* HAVE_MAD */
+
+int get_int (char *file, char *key, int def)
+{
+ return GetPrivateProfileInt (app_text, key, def, file);
+}
+
+int set_int (char *file, char *key, int value)
+{
+ char buffer [30];
+
+ sprintf (buffer, "%d", value);
+ return WritePrivateProfileString (app_text, key, buffer, file);
+}
+
+int exist_file (char *name)
+{
+ return access (name, R_OK) == 0;
+}
+
+char *load_file (char *filename)
+{
+ FILE *data_file;
+ struct stat s;
+ char *data;
+ long read_size,i;
+
+ if (stat (filename, &s) != 0){
+ return 0;
+ }
+#ifdef OS2_NT
+ if ((data_file = fopen (filename, "rt")) == NULL){
+#else
+ if ((data_file = fopen (filename, "r")) == NULL){
+#endif
+ return 0;
+ }
+ data = (char *) xmalloc (s.st_size+1, "util, load_file");
+#ifdef OS2_NT
+ memset(data,0,s.st_size+1);
+#endif
+ read_size = fread (data, 1, s.st_size, data_file);
+ data [read_size] = 0;
+ fclose (data_file);
+
+ if (read_size > 0){
+ return data;
+ }
+ else {
+ free (data);
+ return 0;
+ }
+}
+
+char *file_date (time_t when)
+{
+ static char timebuf [40];
+ time_t current_time = time ((time_t) 0);
+
+#ifdef OS2_NT
+ char *p;
+
+ p = ctime (&when);
+ strcpy (timebuf, p ? p : "-----");
+#else
+ strcpy (timebuf, ctime (&when));
+#endif
+ if (current_time > when + 6L * 30L * 24L * 60L * 60L /* Old. */
+ || current_time < when - 60L * 60L) /* In the future. */
+ {
+ /* The file is fairly old or in the future.
+ POSIX says the cutoff is 6 months old;
+ approximate this by 6*30 days.
+ Allow a 1 hour slop factor for what is considered "the future",
+ to allow for NFS server/client clock disagreement.
+ Show the year instead of the time of day. */
+ strcpy (timebuf + 11, timebuf + 19);
+ }
+ timebuf[16] = 0;
+ return &timebuf [4];
+}
+
+/* Like file_date, but packs the data to fit in 10 columns */
+char *file_date_pck (time_t when)
+{
+ /* FIXME: Should return only 10 chars, not 14 */
+ return file_date (when);
+}
+
+char *extract_line (char *s, char *top)
+{
+ static char tmp_line [500];
+ char *t = tmp_line;
+
+ while (*s && *s != '\n' && (t - tmp_line) < sizeof (tmp_line)-1 && s < top)
+ *t++ = *s++;
+ *t = 0;
+ return tmp_line;
+}
+
+/* FIXME: I should write a faster version of this (Aho-Corasick stuff) */
+char * _icase_search (char *text, char *data, int *lng)
+{
+ char *d = text;
+ char *e = data;
+ int dlng = 0;
+
+ if (lng)
+ *lng = 0;
+ for (;*e; e++) {
+ while (*(e+1) == '\b' && *(e+2)) {
+ e += 2;
+ dlng += 2;
+ }
+ if (toupper((unsigned char) *d) == toupper((unsigned char) *e))
+ d++;
+ else {
+ e -= d - text;
+ d = text;
+ dlng = 0;
+ }
+ if (!*d) {
+ if (lng)
+ *lng = strlen (text) + dlng;
+ return e+1;
+ }
+ }
+ return 0;
+}
+
+/* The basename routine */
+char *x_basename (char *s)
+{
+ char *where;
+ return ((where = strrchr (s, PATH_SEP)))? where + 1 : s;
+}
+
+char *get_full_name (char *dir, char *file)
+{
+ int i;
+ char *d = malloc (strlen (dir) + strlen (file) + 2);
+
+ strcpy (d, dir);
+ i = strlen (dir);
+ if (dir [i - 1] != PATH_SEP || dir [i] != 0)
+ strcat (d, PATH_SEP_STR);
+ file = x_basename (file);
+ strcat (d, file);
+ return d;
+}
+
+void my_putenv (char *name, char *data)
+{
+ char *full;
+
+ full = xmalloc (strlen (name) + strlen (data) + 2, "util, my_putenv");
+ sprintf (full, "%s=%s", name, data);
+ putenv (full);
+ /* WARNING: NEVER FREE THE full VARIABLE!!!!!!!!!!!!!!!!!!!!!!!! */
+ /* It is used by putenv. Freeing it will corrupt the environment */
+}
+
+#if 0
+static void my_putenv_expand (char *name, char macro_code)
+{
+ char *data;
+
+ data = expand_format (macro_code);
+ my_putenv (name, data);
+ free (data);
+}
+
+/* Puts some status information in to the environment so that
+ processes to be executed can access it. */
+static void prepare_environment (void)
+{
+ my_putenv_expand ("MC_CURRENT_DIR", 'd');
+ my_putenv_expand ("MC_OTHER_DIR", 'D');
+ my_putenv_expand ("MC_CURRENT_FILE", 'f');
+ my_putenv_expand ("MC_OTHER_FILE", 'F');
+ my_putenv_expand ("MC_CURRENT_TAGGED", 't');
+ my_putenv_expand ("MC_OTHER_TAGGED", 'T');
+ /* MC_CONTROL_FILE has been added to environment on startup */
+}
+#endif
+
+char *unix_error_string (int error_num)
+{
+ static char buffer [256];
+ char *error_msg;
+
+#ifdef HAVE_STRERROR
+ error_msg = strerror (error_num);
+#else
+ extern int sys_nerr;
+ extern char *sys_errlist [];
+ if ((0 <= error_num) && (error_num < sys_nerr))
+ error_msg = sys_errlist[error_num];
+ else
+ error_msg = "strange errno";
+#endif
+ sprintf (buffer, "%s (%d)", error_msg, error_num);
+ return buffer;
+}
+
+char *copy_strings (const char *first,...)
+{
+ va_list ap;
+ int len;
+ char *data, *result;
+
+ if (!first)
+ return 0;
+
+ len = strlen (first);
+ va_start (ap, first);
+
+ while ((data = va_arg (ap, char *))!=0)
+ len += strlen (data);
+
+ len++;
+
+ result = xmalloc (len, "copy_strings");
+ va_end (ap);
+ va_start (ap, first);
+ strcpy (result, first);
+ while ((data = va_arg (ap, char *)) != 0)
+ strcat (result, data);
+ va_end (ap);
+
+ return result;
+}
+
+long blocks2kilos (int blocks, int bsize)
+{
+ if (bsize > 1024){
+ return blocks * (bsize / 1024);
+ } else if (bsize < 1024){
+ return blocks / (1024 /bsize);
+ } else
+ return blocks;
+}
+
+void init_my_statfs (void)
+{
+#ifndef NO_INFOMOUNT
+ mount_list = read_filesystem_list (1, 1);
+#endif
+}
+
+char *skip_separators (char *s)
+{
+ for (;*s; s++)
+ if (*s != ' ' && *s != '\t' && *s != ',')
+ break;
+ return s;
+}
+
+char *skip_numbers (char *s)
+{
+ for (;*s; s++)
+ if (!isdigit (*s))
+ break;
+ return s;
+}
+
+/* Remove all control sequences from the argument string. We define
+ * "control sequence", in a sort of pidgin BNF, as follows:
+ *
+ * control-seq = Esc non-'['
+ * | Esc '[' (0 or more digits or ';' or '?') (any other char)
+ *
+ * This scheme works for all the terminals described in my termcap /
+ * terminfo databases, except the Hewlett-Packard 70092 and some Wyse
+ * terminals. If I hear from a single person who uses such a terminal
+ * with MC, I'll be glad to add support for it. (Dugan)
+ */
+
+char *strip_ctrl_codes (char *s)
+{
+ int i; /* Current length of the string's correct (stripped) prefix */
+ int j; /* Number of control characters we have skipped so far */
+
+ if (!s)
+ return 0;
+
+ for (i = 0, j = 0; s [i+j]; ++i)
+ if (s [i+j] != ESC_CHAR){
+ if (j)
+ s [i] = s [i+j];
+ } else {
+ ++j;
+ if (s [i+j++] == '[')
+ while (strchr ("0123456789;?", s [i+j++]))
+ /* Skip the control sequence's arguments */ ;
+ --i;
+ }
+ s[i] = 0;
+ return s;
+}
+
+#ifndef HAVE_STRCASECMP
+/* At least one version of HP/UX lacks this */
+/* Assumes ASCII encoding */
+int strcasecmp (const char *s, const char *d)
+{
+ register signed int result;
+
+ while (1){
+ if (result = (0x20 | *s) - (0x20 | *d))
+ break;
+ if (!*s)
+ return 0;
+ s++;
+ d++;
+ }
+ return result;
+}
+#endif /* HAVE_STRCASECMP */
+
+/* getwd is better than getcwd, the later uses a popen ("pwd"); */
+char *get_current_wd (char *buffer, int size)
+{
+ char *p;
+
+#ifdef HAVE_GETWD
+ p = (char *) getwd (buffer);
+#else
+ p = getcwd (buffer, size);
+#endif
+ return p;
+}
+
+#define CHECK(x) if (x == -1) return 0;
+
+long get_small_endian_long (int fd)
+{
+ unsigned char a, b, c, d;
+
+ /* It needs to be read one byte at the time to avoid endianess
+ portability problems */
+ CHECK (mc_read (fd, &a, 1));
+ CHECK (mc_read (fd, &b, 1));
+ CHECK (mc_read (fd, &c, 1));
+ CHECK (mc_read (fd, &d, 1));
+ return (d << 24) | (c << 16) | (b << 8) | a;
+}
+
+/* This function returns 0 if the file is not in gunzip format */
+/* or how much memory must be allocated to load the gziped file */
+/* Warning: this function moves the current file pointer */
+long int is_gunzipable (int fd, int *type)
+{
+ unsigned char magic [4];
+
+ *type = ISGUNZIPABLE_GUNZIP;
+
+ /* Read the magic signature */
+ CHECK (mc_read (fd, &magic [0], 1));
+ CHECK (mc_read (fd, &magic [1], 1));
+ CHECK (mc_read (fd, &magic [2], 1));
+ CHECK (mc_read (fd, &magic [3], 1));
+
+ /* GZIP_MAGIC and OLD_GZIP_MAGIC */
+ if (magic [0] == 037 && (magic [1] == 0213 || magic [1] == 0236)){
+ /* Read the uncompressed size of the file */
+ mc_lseek (fd, -4, SEEK_END);
+ return get_small_endian_long (fd);
+ }
+
+ /* PKZIP_MAGIC */
+ if (magic [0] == 0120 && magic [1] == 0113 && magic [2] == 003 && magic [3] == 004){
+ /* Read compression type */
+ mc_lseek (fd, 8, SEEK_SET);
+ CHECK (mc_read (fd, &magic [0], 1));
+ CHECK (mc_read (fd, &magic [1], 1));
+
+ /* Gzip can handle only deflated (8) or stored (0) files */
+ if ((magic [0] != 8 && magic [0] != 0) || magic [1] != 0)
+ return 0;
+ /* Read the uncompressed size of the first file in the archive */
+ mc_lseek (fd, 22, SEEK_SET);
+ return get_small_endian_long (fd);
+ }
+
+ /* PACK_MAGIC and LZH_MAGIC and compress magic */
+ if (magic [0] == 037 && (magic [1] == 036 || magic [1] == 0240 || magic [1] == 0235)){
+ /* In case the file is packed, sco lzhed or compress_magic, the */
+ /* program guesses that the uncompressed size is (at most) four */
+ /* times the length of the compressed size, if the compression */
+ /* ratio is more than 4:1 the end of the file is not displayed */
+ return 4*mc_lseek (fd, 0, SEEK_END);
+ }
+
+ /* BZIP and BZIP2 files */
+ if ((magic[0] == 'B') && (magic[1] == 'Z') &&
+ (magic [3] >= '1') && (magic [3] <= '9')){
+ switch (magic[2]) {
+ case '0':
+ *type = ISGUNZIPABLE_BZIP;
+ return 5*mc_lseek (fd, 0, SEEK_END);
+ case 'h':
+ *type = ISGUNZIPABLE_BZIP2;
+ return 5*mc_lseek (fd, 0, SEEK_END);
+ }
+ }
+ return 0;
+}
+
+char *
+decompress_command (int type)
+{
+ switch (type){
+ case ISGUNZIPABLE_GUNZIP:
+ return "gzip -cdf";
+
+ case ISGUNZIPABLE_BZIP:
+ return "bzip -d";
+
+ case ISGUNZIPABLE_BZIP2:
+ return "bzip2 -dc";
+ }
+ /* Should never reach this place */
+ fprintf (stderr, "Fatal: decompress_command called with an unknown argument\n");
+ return 0;
+}
+
+void
+decompress_command_and_arg (int type, char **cmd, char **flags)
+{
+ switch (type){
+ case ISGUNZIPABLE_GUNZIP:
+ *cmd = "gzip";
+ *flags = "-cdf";
+ return;
+
+ case ISGUNZIPABLE_BZIP:
+ *cmd = "bzip";
+ *flags = "-d";
+ return;
+
+
+ case ISGUNZIPABLE_BZIP2:
+ *cmd = "bzip2";
+ *flags = "-dc";
+ return;
+ }
+ *cmd = 0;
+ *flags = 0;
+
+ /* Should never reach this place */
+ fprintf (stderr, "Fatal: decompress_command called with an unknown argument\n");
+}
+
+/* Hooks */
+void add_hook (Hook **hook_list, void (*hook_fn)(void *), void *data)
+{
+ Hook *new_hook = xmalloc (sizeof (Hook), "add_hook");
+
+ new_hook->hook_fn = hook_fn;
+ new_hook->next = *hook_list;
+ new_hook->hook_data = data;
+
+ *hook_list = new_hook;
+}
+
+void execute_hooks (Hook *hook_list)
+{
+ Hook *new_hook = 0;
+ Hook *p;
+
+ /* We copy the hook list first so tahat we let the hook
+ * function call delete_hook
+ */
+
+ while (hook_list){
+ add_hook (&new_hook, hook_list->hook_fn, hook_list->hook_data);
+ hook_list = hook_list->next;
+ }
+ p = new_hook;
+
+ while (new_hook){
+ (*new_hook->hook_fn)(new_hook->hook_data);
+ new_hook = new_hook->next;
+ }
+
+ for (hook_list = p; hook_list;){
+ p = hook_list;
+ hook_list = hook_list->next;
+ free (p);
+ }
+}
+
+void delete_hook (Hook **hook_list, void (*hook_fn)(void *))
+{
+ Hook *current, *new_list, *next;
+
+ new_list = 0;
+
+ for (current = *hook_list; current; current = next){
+ next = current->next;
+ if (current->hook_fn == hook_fn)
+ free (current);
+ else
+ add_hook (&new_list, current->hook_fn, current->hook_data);
+ }
+ *hook_list = new_list;
+}
+
+int hook_present (Hook *hook_list, void (*hook_fn)(void *))
+{
+ Hook *p;
+
+ for (p = hook_list; p; p = p->next)
+ if (p->hook_fn == hook_fn)
+ return 1;
+ return 0;
+}
+
+void wipe_password (char *passwd)
+{
+ char *p = passwd;
+
+ for (;*p ; p++)
+ *p = 0;
+ free (passwd);
+}
+
+/* Convert "\E" -> esc character and ^x to control-x key and ^^ to ^ key */
+/* Returns a newly allocated string */
+char *convert_controls (char *s)
+{
+ char *valcopy = strdup (s);
+ char *p, *q;
+
+ /* Parse the escape special character */
+ for (p = s, q = valcopy; *p;){
+ if (*p == '\\'){
+ p++;
+ if ((*p == 'e') || (*p == 'E')){
+ p++;
+ *q++ = ESC_CHAR;
+ }
+ } else {
+ if (*p == '^'){
+ p++;
+ if (*p == '^')
+ *q++ = *p++;
+ else {
+ *p = (*p | 0x20);
+ if (*p >= 'a' && *p <= 'z') {
+ *q++ = *p++ - 'a' + 1;
+ } else
+ p++;
+ }
+ } else
+ *q++ = *p++;
+ }
+ }
+ *q++ = 0;
+ return valcopy;
+}
+
+/* Reverse the string */
+char *reverse_string (char *string)
+{
+ int len = strlen (string);
+ int i;
+ const int steps = len/2;
+
+ for (i = 0; i < steps; i++){
+ char c = string [i];
+
+ string [i] = string [len-i-1];
+ string [len-i-1] = c;
+ }
+ return string;
+}
+
+char *resolve_symlinks (char *path)
+{
+ char *buf, *buf2, *p, *q, *r, c;
+ int len;
+ struct stat mybuf;
+
+ if (*path != PATH_SEP)
+ return NULL;
+ r = buf = xmalloc (MC_MAXPATHLEN, "resolve symlinks");
+ buf2 = xmalloc (MC_MAXPATHLEN, "resolve symlinks");
+ *r++ = PATH_SEP;
+ *r = 0;
+ p = path;
+ for (;;) {
+ q = strchr (p + 1, PATH_SEP);
+ if (!q) {
+ q = strchr (p + 1, 0);
+ if (q == p + 1)
+ break;
+ }
+ c = *q;
+ *q = 0;
+ if (mc_lstat (path, &mybuf) < 0) {
+ free (buf);
+ free (buf2);
+ *q = c;
+ return NULL;
+ }
+ if (!S_ISLNK (mybuf.st_mode))
+ strcpy (r, p + 1);
+ else {
+ len = mc_readlink (path, buf2, MC_MAXPATHLEN);
+ if (len < 0) {
+ free (buf);
+ free (buf2);
+ *q = c;
+ return NULL;
+ }
+ buf2 [len] = 0;
+ if (*buf2 == PATH_SEP)
+ strcpy (buf, buf2);
+ else
+ strcpy (r, buf2);
+ }
+ canonicalize_pathname (buf);
+ r = strchr (buf, 0);
+ if (!*r || *(r - 1) != PATH_SEP) {
+ *r++ = PATH_SEP;
+ *r = 0;
+ }
+ *q = c;
+ p = q;
+ if (!c)
+ break;
+ }
+ if (!*buf)
+ strcpy (buf, PATH_SEP_STR);
+ else if (*(r - 1) == PATH_SEP && r != buf + 1)
+ *(r - 1) = 0;
+ free (buf2);
+ return buf;
+}
+
+/* Finds out a relative path from first to second, i.e. goes as many ..
+ * as needed up in first and then goes down using second */
+char *diff_two_paths (char *first, char *second)
+{
+ char *p, *q, *r, *s, *buf = 0;
+ int i, j, prevlen = -1, currlen;
+
+ first = resolve_symlinks (first);
+ if (first == NULL)
+ return NULL;
+ for (j = 0; j < 2; j++) {
+ p = first;
+ if (j) {
+ second = resolve_symlinks (second);
+ if (second == NULL) {
+ free (first);
+ return buf;
+ }
+ }
+ q = second;
+ for (;;) {
+ r = strchr (p, PATH_SEP);
+ s = strchr (q, PATH_SEP);
+ if (!r || !s)
+ break;
+ *r = 0; *s = 0;
+ if (strcmp (p, q)) {
+ *r = PATH_SEP; *s = PATH_SEP;
+ break;
+ } else {
+ *r = PATH_SEP; *s = PATH_SEP;
+ }
+ p = r + 1;
+ q = s + 1;
+ }
+ p--;
+ for (i = 0; (p = strchr (p + 1, PATH_SEP)) != NULL; i++);
+ currlen = (i + 1) * 3 + strlen (q) + 1;
+ if (j) {
+ if (currlen < prevlen)
+ free (buf);
+ else {
+ free (first);
+ free (second);
+ return buf;
+ }
+ }
+ p = buf = xmalloc (currlen, "diff 2 paths");
+ prevlen = currlen;
+ for (; i >= 0; i--, p += 3)
+ strcpy (p, "../");
+ strcpy (p, q);
+ }
+ free (first);
+ free (second);
+ return buf;
+}
+
+#ifndef HAVE_TRUNCATE
+/* On SCO and Windows NT systems */
+int my_ftruncate (int fd, long size)
+{
+#ifdef OS2_NT
+ if(_chsize(fd, size))
+ return -1;
+ else
+ return 0;
+#else
+ struct flock lk;
+
+ lk.l_whence = 0;
+ lk.l_start = size;
+ lk.l_len = 0;
+
+ return fcntl (fd, F_FREESP, &lk);
+#endif
+}
+
+int truncate (const char *path, long size)
+{
+ int fd;
+ int res;
+
+ fd = open (path, O_RDWR, 0);
+ if (fd < 0)
+ return fd;
+ res = my_ftruncate (fd, size);
+ if (res < 0)
+ return res;
+ close (fd);
+ return 0;
+
+}
+
+#endif
+
+char *
+concat_dir_and_file (const char *dir, const char *file)
+{
+ int l = strlen (dir);
+
+ if (dir [l-1] == PATH_SEP)
+ return copy_strings (dir, file, 0);
+ else
+ return copy_strings (dir, PATH_SEP_STR, file, 0);
+}
--- /dev/null
+#ifndef __UTIL_H
+#define __UTIL_H
+
+
+#include <sys/types.h>
+
+/* String managing functions */
+
+#if defined(SCO_FLAVOR) && defined(__GNUC__)
+extern char* strdup(const char*);
+#endif
+
+int is_printable (int c);
+int msglen (char *text, int *lines);
+char *trim (char *s, char *d, int len);
+char *name_quote (const char *c, int quote_percent);
+char *fake_name_quote (const char *c, int quote_percent);
+char *name_trunc (char *txt, int trunc_len);
+char *size_trunc (long int size);
+char *size_trunc_sep (long int size);
+int is_exe (mode_t mode);
+char *string_perm (mode_t mode_bits);
+char *strip_home_and_password(char *dir);
+char *extension (char *);
+char *split_extension (char *, int pad);
+char *get_full_name (char *dir, char *file);
+char *copy_strings (const char *first, ...);
+char *concat_dir_and_file (const char *dir, const char *file);
+char *unix_error_string (int error_num);
+char *skip_separators (char *s);
+char *skip_numbers (char *s);
+char *strip_ctrl_codes (char *s);
+char *convert_controls (char *s);
+void wipe_password (char *passwd);
+char *reverse_string (char *string);
+char *resolve_symlinks (char *path);
+char *diff_two_paths (char *first, char *second);
+int set_nonblocking (int fd);
+
+#ifndef HAVE_STRCASECMP
+int strcasecmp (const char *s, const char *d);
+#endif
+
+char *x_basename (char *s);
+
+extern int align_extensions;
+#ifndef HAVE_MAD
+void *do_xmalloc (int);
+#define xmalloc(a,b) do_xmalloc (a)
+#endif
+
+/* Profile managing functions */
+int set_int (char *, char *, int);
+int get_int (char *, char *, int);
+
+char *load_file (char *filename);
+
+#include "fs.h"
+#ifndef S_ISLNK
+# define S_ISLNK(x) (((x) & S_IFLNK) == S_IFLNK)
+#endif
+
+#ifndef S_ISSOCK
+# ifdef S_IFSOCK
+# define S_ISSOCK(x) (((x) & S_IFSOCK) == S_IFSOCK)
+# else
+# define S_ISSOCK(x) 0
+# endif
+#endif
+
+/* uid/gid managing */
+typedef struct user_in_groups{
+ struct user_in_groups *next;
+ int gid;
+} user_in_groups;
+
+void init_groups (void);
+void delete_groups (void);
+int get_user_rights (struct stat *buf);
+
+void init_uid_gid_cache (void);
+char *get_group (int);
+char *get_owner (int);
+
+char *file_date (time_t);
+char *file_date_pck (time_t);
+int exist_file (char *name);
+
+/* Returns a copy of *s until a \n is found and is below top */
+char *extract_line (char *s, char *top);
+char *_icase_search (char *text, char *data, int *lng);
+#define icase_search(T,D) _icase_search((T), (D), NULL)
+
+/* Matching */
+enum { match_file, match_normal };
+extern int easy_patterns;
+char *convert_pattern (char *pattern, int match_type, int do_group);
+int regexp_match (char *pattern, char *string, int match_type);
+
+/* Error pipes */
+void open_error_pipe (void);
+void check_error_pipe (void);
+void close_error_pipe (int error, char *text);
+
+/* Process spawning */
+void my_putenv (char*, char*);
+#define EXECUTE_INTERNAL 1
+#define EXECUTE_TEMPFILE 2
+#define EXECUTE_AS_SHELL 4
+int my_system (int flags, const char *shell, const char *command);
+int my_system_get_child_pid (int flags, const char *shell, const char *command, pid_t *pid);
+void save_stop_handler (void);
+extern struct sigaction startup_handler;
+
+/* Tilde expansion */
+char *tilde_expand (char *);
+
+/* Pathname canonicalization */
+char *canonicalize_pathname (char *);
+
+/* Misc Unix functions */
+long blocks2kilos (int blocks, int bsize);
+char *get_current_wd (char *buffer, int size);
+int my_mkdir (char *s, mode_t mode);
+int my_rmdir (char *s);
+
+/* Filesystem status */
+struct my_statfs {
+ int type;
+ char *typename;
+ char *mpoint;
+ char *device;
+ unsigned int avail;
+ unsigned int total;
+ unsigned int nfree;
+ unsigned int nodes;
+};
+
+void init_my_statfs (void);
+void my_statfs (struct my_statfs *myfs_stats, char *path);
+
+/* Rotating dash routines */
+void use_dash (int flag); /* Disable/Enable rotate_dash routines */
+void rotate_dash (void);
+void remove_dash (void);
+
+extern char app_text [];
+
+enum {
+ ISGUNZIPABLE_GUNZIP,
+ ISGUNZIPABLE_BZIP,
+ ISGUNZIPABLE_BZIP2
+};
+
+long int is_gunzipable (int fd, int *type);
+char *decompress_command (int type);
+void decompress_command_and_arg (int type, char **cmd, char **flags);
+
+int mc_doublepopen (int inhandle, int inlen, pid_t *tp, char *command, ...);
+int mc_doublepclose (int pipehandle, pid_t pid);
+
+/* Hook functions */
+
+typedef struct hook {
+ void (*hook_fn)(void *);
+ void *hook_data;
+ struct hook *next;
+} Hook;
+
+void add_hook (Hook **hook_list, void (*hook_fn)(void *), void *data);
+void execute_hooks (Hook *hook_list);
+void delete_hook (Hook **hook_list, void (*hook_fn)(void *));
+int hook_present (Hook *hook_list, void (*hook_fn)(void *));
+
+/* message stubs: used by those routines that may output something during the panel_operate process */
+void message_1s (int flags, char *title, char *str1);
+void message_2s (int flags, char *title, char *str1, char *str2);
+void message_3s (int flags, char *title, char *str1, char *str2, const char *str3);
+void message_1s1d (int flags, char *title, char *str, int d);
+void tell_parent (int msg);
+int max_open_files (void);
+
+#ifdef OS2_NT
+# define PATH_SEP '\\'
+# define PATH_SEP_STR "\\"
+# define PATH_ENV_SEP ';'
+# define OS_SORT_CASE_SENSITIVE_DEFAULT 0
+# define STRCOMP stricmp
+# define STRNCOMP strnicmp
+# define MC_ARCH_FLAGS REG_ICASE
+ char *get_default_shell (void);
+ char *get_default_editor (void);
+ int lstat (const char* pathname, struct stat *buffer);
+#else
+# define PATH_SEP '/'
+# define PATH_SEP_STR "/"
+# define PATH_ENV_SEP ':'
+# define get_default_editor() "vi"
+# define OS_SORT_CASE_SENSITIVE_DEFAULT 1
+# define STRCOMP strcmp
+# define STRNCOMP strncmp
+# define MC_ARCH_FLAGS 0
+#endif
+
+#include "i18n.h"
+
+/* taken from regex.c: */
+/* Jim Meyering writes:
+
+ "... Some ctype macros are valid only for character codes that
+ isascii says are ASCII (SGI's IRIX-4.0.5 is one such system --when
+ using /bin/cc or gcc but without giving an ansi option). So, all
+ ctype uses should be through macros like ISPRINT... If
+ STDC_HEADERS is defined, then autoconf has verified that the ctype
+ macros don't need to be guarded with references to isascii. ...
+ Defining isascii to 1 should let any compiler worth its salt
+ eliminate the && through constant folding." */
+
+#if defined (STDC_HEADERS) || (!defined (isascii) && !defined (HAVE_ISASCII))
+#define ISASCII(c) 1
+#else
+#define ISASCII(c) isascii(c)
+#endif
+
+#endif
--- /dev/null
+/* Various utilities - Unix variants
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation.
+ Written 1994, 1995, 1996 by:
+ Miguel de Icaza, Janne Kukonlehto, Dugan Porter,
+ Jakub Jelinek, Mauricio Plaza.
+
+ The file_date routine is mostly from GNU's fileutils package,
+ written by Richard Stallman and David MacKenzie.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <fcntl.h>
+#include <signal.h> /* my_system */
+#include <limits.h> /* INT_MAX */
+#include <sys/time.h> /* select: timeout */
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdarg.h>
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h> /* my_system */
+#endif
+#include <errno.h> /* my_system */
+#include <pwd.h>
+#include <grp.h>
+#include <string.h>
+#include <ctype.h>
+#ifdef HAVE_SYS_SELECT_H
+# include <sys/select.h>
+#endif
+#ifdef SCO_FLAVOR
+# include <sys/timeb.h>
+#endif
+#include <time.h>
+#ifdef __linux__
+# if defined(__GLIBC__) && (__GLIBC__ < 2)
+# include <linux/termios.h> /* This is needed for TIOCLINUX */
+# else
+# include <termios.h>
+# endif
+# include <sys/ioctl.h>
+#endif
+#ifdef __QNX__
+# include <unix.h> /* exec*() from <process.h> */
+#endif
+#include "util.h"
+#include "global.h"
+#include "fsusage.h"
+#include "fsusage.h"
+#include "mountlist.h"
+#include "mad.h"
+#include "dialog.h" /* message() */
+#include "../vfs/vfs.h" /* mc_read() */
+#include "x.h"
+
+struct sigaction startup_handler;
+extern struct mount_entry *mount_list;
+
+uid_t current_user_uid;
+user_in_groups *current_user_gid;
+
+int
+max_open_files (void)
+{
+ static int files;
+
+ if (files)
+ return files;
+
+#ifdef HAVE_SYSCONF
+ files = sysconf (_SC_OPEN_MAX);
+ if (files != -1)
+ return files;
+#endif
+#ifdef OPEN_MAX
+ return files = OPEN_MAX;
+#else
+ return files = 256;
+#endif
+}
+
+void init_groups (void)
+{
+ int i;
+ struct passwd *pwd;
+ struct group *grp;
+ user_in_groups *cug, *pug;
+
+ pwd = getpwuid (current_user_uid=getuid ());
+
+ current_user_gid = (pug = xmalloc (sizeof (user_in_groups), "init_groups"));
+ current_user_gid->gid = getgid (); current_user_gid->next = 0;
+
+ if (pwd == 0)
+ return;
+
+ setgrent ();
+ while ((grp = getgrent ()))
+ for (i = 0; grp->gr_mem[i]; i++)
+ if (!strcmp (pwd->pw_name,grp->gr_mem[i]))
+ {
+ cug = xmalloc (sizeof (user_in_groups), "init_groups");
+ cug->gid = grp->gr_gid;
+ pug->next = cug;
+ cug->next = 0;
+ pug = cug;
+ break;
+ }
+ endgrent ();
+}
+
+/* Return the index of permission triplet */
+int
+get_user_rights (struct stat *buf)
+{
+ user_in_groups *cug;
+
+ if (buf->st_uid == current_user_uid || current_user_uid == 0)
+ return 0;
+
+ for (cug = current_user_gid; cug; cug = cug->next)
+ if (cug->gid == buf->st_gid) return 1;
+
+ return 2;
+}
+
+
+void
+delete_groups (void)
+{
+ user_in_groups *pug, *cug = current_user_gid;
+
+ while (cug){
+ pug = cug->next;
+ free (cug);
+ cug = pug;
+ }
+}
+
+#define UID_CACHE_SIZE 200
+#define GID_CACHE_SIZE 30
+
+typedef struct {
+ int index;
+ char *string;
+} int_cache;
+
+int_cache uid_cache [UID_CACHE_SIZE];
+int_cache gid_cache [GID_CACHE_SIZE];
+
+void init_uid_gid_cache (void)
+{
+ int i;
+
+ for (i = 0; i < UID_CACHE_SIZE; i++)
+ uid_cache [i].string = 0;
+
+ for (i = 0; i < GID_CACHE_SIZE; i++)
+ gid_cache [i].string = 0;
+}
+
+static char *i_cache_match (int id, int_cache *cache, int size)
+{
+ int i;
+
+ for (i = 0; i < size; i++)
+ if (cache [i].index == id)
+ return cache [i].string;
+ return 0;
+}
+
+static void i_cache_add (int id, int_cache *cache, int size, char *text,
+ int *last)
+{
+ if (cache [*last].string)
+ free (cache [*last].string);
+ cache [*last].string = strdup (text);
+ cache [*last].index = id;
+ *last = ((*last)+1) % size;
+}
+
+char *get_owner (int uid)
+{
+ struct passwd *pwd;
+ static char ibuf [8];
+ char *name;
+ static int uid_last;
+
+ if ((name = i_cache_match (uid, uid_cache, UID_CACHE_SIZE)) != NULL)
+ return name;
+
+ pwd = getpwuid (uid);
+ if (pwd){
+ i_cache_add (uid, uid_cache, UID_CACHE_SIZE, pwd->pw_name, &uid_last);
+ return pwd->pw_name;
+ }
+ else {
+ sprintf (ibuf, "%d", uid);
+ return ibuf;
+ }
+}
+
+char *get_group (int gid)
+{
+ struct group *grp;
+ static char gbuf [8];
+ char *name;
+ static int gid_last;
+
+ if ((name = i_cache_match (gid, gid_cache, GID_CACHE_SIZE)) != NULL)
+ return name;
+
+ grp = getgrgid (gid);
+ if (grp){
+ i_cache_add (gid, gid_cache, GID_CACHE_SIZE, grp->gr_name, &gid_last);
+ return grp->gr_name;
+ } else {
+ sprintf (gbuf, "%d", gid);
+ return gbuf;
+ }
+}
+
+/* Since ncurses uses a handler that automatically refreshes the */
+/* screen after a SIGCONT, and we don't want this behavior when */
+/* spawning a child, we save the original handler here */
+void save_stop_handler (void)
+{
+ sigaction (SIGTSTP, NULL, &startup_handler);
+}
+
+#ifdef HAVE_GNOME
+#define PORT_HAS_MY_SYSTEM 1
+#endif
+
+#ifndef PORT_HAS_MY_SYSTEM
+int my_system (int flags, const char *shell, const char *command)
+{
+ struct sigaction ignore, save_intr, save_quit, save_stop;
+ pid_t pid;
+ int status = 0;
+ int as_shell_command = flags & EXECUTE_AS_SHELL;
+
+ ignore.sa_handler = SIG_IGN;
+ sigemptyset (&ignore.sa_mask);
+ ignore.sa_flags = 0;
+
+ sigaction (SIGINT, &ignore, &save_intr);
+ sigaction (SIGQUIT, &ignore, &save_quit);
+
+ /* Restore the original SIGTSTP handler, we don't want ncurses' */
+ /* handler messing the screen after the SIGCONT */
+ sigaction (SIGTSTP, &startup_handler, &save_stop);
+
+ if ((pid = fork ()) < 0){
+ fprintf (stderr, "\n\nfork () = -1\n");
+ return -1;
+ }
+ if (pid == 0){
+ sigaction (SIGINT, &save_intr, NULL);
+ sigaction (SIGQUIT, &save_quit, NULL);
+
+#if 0
+ prepare_environment ();
+#endif
+
+ if (as_shell_command)
+ execl (shell, shell, "-c", command, (char *) 0);
+ else
+ execlp (shell, shell, command, (char *) 0);
+
+ _exit (127); /* Exec error */
+ } else {
+ while (waitpid (pid, &status, 0) < 0)
+ if (errno != EINTR){
+ status = -1;
+ break;
+ }
+ }
+ sigaction (SIGINT, &save_intr, NULL);
+ sigaction (SIGQUIT, &save_quit, NULL);
+ sigaction (SIGTSTP, &save_stop, NULL);
+
+#ifdef SCO_FLAVOR
+ waitpid(-1, NULL, WNOHANG);
+#endif /* SCO_FLAVOR */
+
+ return WEXITSTATUS(status);
+}
+#endif
+
+/* Returns a newly allocated string, if directory does not exist, return 0 */
+char *tilde_expand (char *directory)
+{
+ struct passwd *passwd;
+ char *p;
+ char *name;
+ int len;
+
+ if (*directory != '~')
+ return strdup (directory);
+
+ directory++;
+
+ p = strchr (directory, PATH_SEP);
+
+ /* d = "~" or d = "~/" */
+ if (!(*directory) || (*directory == PATH_SEP)){
+ passwd = getpwuid (geteuid ());
+ p = (*directory == PATH_SEP) ? directory+1 : "";
+ } else {
+ if (!p){
+ p = "";
+ passwd = getpwnam (directory);
+ } else {
+ name = xmalloc (p - directory + 1, "tilde_expand");
+ strncpy (name, directory, p - directory);
+ name [p - directory] = 0;
+ passwd = getpwnam (name);
+ free (name);
+ }
+ }
+
+ /* If we can't figure the user name, return NULL */
+ if (!passwd)
+ return 0;
+
+ len = strlen (passwd->pw_dir) + strlen (p) + 2;
+ directory = xmalloc (len, "tilde_expand");
+ strcpy (directory, passwd->pw_dir);
+ strcat (directory, PATH_SEP_STR);
+ strcat (directory, p);
+ return directory;
+}
+
+int
+set_nonblocking (int fd)
+{
+ int val;
+
+ val = fcntl (fd, F_GETFL, 0);
+ val |= O_NONBLOCK;
+ return fcntl (fd, F_SETFL, val) != -1;
+}
+
+/* Pipes are guaranteed to be able to hold at least 4096 bytes */
+/* More than that would be unportable */
+#define MAX_PIPE_SIZE 4096
+
+static int error_pipe[2]; /* File descriptors of error pipe */
+static int old_error; /* File descriptor of old standard error */
+
+/* Creates a pipe to hold standard error for a later analysis. */
+/* The pipe can hold 4096 bytes. Make sure no more is written */
+/* or a deadlock might occur. */
+void open_error_pipe (void)
+{
+ if (pipe (error_pipe) < 0){
+ message (0, _(" Warning "), _(" Pipe failed "));
+ }
+ old_error = dup (2);
+ if(old_error < 0 || close(2) || dup (error_pipe[1]) != 2){
+ message (0, _(" Warning "), _(" Dup failed "));
+ close (error_pipe[0]);
+ close (error_pipe[1]);
+ }
+ close (error_pipe[1]);
+}
+
+void close_error_pipe (int error, char *text)
+{
+ char *title;
+ char msg[MAX_PIPE_SIZE];
+ int len = 0;
+
+ if (error)
+ title = MSG_ERROR;
+ else
+ title = " Warning ";
+ if (old_error >= 0){
+ close (2);
+ dup (old_error);
+ close (old_error);
+ len = read (error_pipe[0], msg, MAX_PIPE_SIZE);
+
+ if (len >= 0)
+ msg[len] = 0;
+ close (error_pipe[0]);
+ }
+ if (error < 0)
+ return; /* Just ignore error message */
+ if (text == NULL){
+ if (len == 0) return; /* Nothing to show */
+
+ /* Show message from pipe */
+ message (error, title, msg);
+ } else {
+ /* Show given text and possible message from pipe */
+ message (error, title, " %s \n %s ", text, msg);
+ }
+}
+
+/* Checks for messages in the error pipe,
+ * closes the pipe and displays an error box if needed
+ */
+void check_error_pipe (void)
+{
+ char error[MAX_PIPE_SIZE];
+ int len = 0;
+ if (old_error >= 0){
+ while (len < MAX_PIPE_SIZE)
+ {
+ fd_set select_set;
+ struct timeval timeout;
+ FD_ZERO (&select_set);
+ FD_SET (error_pipe[0], &select_set);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 0;
+ select (FD_SETSIZE, &select_set, 0, 0, &timeout);
+ if (!FD_ISSET (0, &select_set))
+ break;
+ read (error_pipe[0], error + len, 1);
+ len ++;
+ }
+ error[len] = 0;
+ close (error_pipe[0]);
+ }
+ if (len > 0)
+ message (0, _(" Warning "), error);
+}
+
+static struct sigaction ignore, save_intr, save_quit, save_stop;
+
+/* INHANDLE is a result of some mc_open call to any vfs, this function
+ returns a normal handle (to be used with read) of a pipe for reading
+ of the output of COMMAND with arguments ... (must include argv[0] as
+ well) which gets as its input at most INLEN bytes from the INHANDLE
+ using mc_read. You have to call mc_doublepclose to close the returned
+ handle afterwards. If INLEN is -1, we read as much as we can :) */
+int mc_doublepopen (int inhandle, int inlen, pid_t *the_pid, char *command, ...)
+{
+ int pipe0 [2], pipe1 [2];
+ pid_t pid;
+
+#define closepipes() close(pipe0[0]);close(pipe0[1]);close(pipe1[0]);close(pipe1[1])
+#define is_a_pipe_fd(f) ((pipe0[0] == f) || (pipe0[1] == f) || (pipe1[0] == f) || (pipe1[1] == f))
+
+ pipe (pipe0); pipe (pipe1);
+ ignore.sa_handler = SIG_IGN;
+ sigemptyset (&ignore.sa_mask);
+ ignore.sa_flags = 0;
+
+ sigaction (SIGINT, &ignore, &save_intr);
+ sigaction (SIGQUIT, &ignore, &save_quit);
+ sigaction (SIGTSTP, &startup_handler, &save_stop);
+
+ switch (pid = fork ()) {
+ case -1:
+ closepipes ();
+ return -1;
+ case 0: {
+ sigaction (SIGINT, &save_intr, NULL);
+ sigaction (SIGQUIT, &save_quit, NULL);
+
+ switch (pid = fork ()) {
+ case -1:
+ closepipes ();
+ exit (1);
+ case 0: {
+#define MAXARGS 16
+ int argno;
+ char *args[MAXARGS];
+ va_list ap;
+ int nulldevice;
+
+ port_shutdown_extra_fds ();
+
+ nulldevice = open ("/dev/null", O_WRONLY);
+ close (0);
+ dup (pipe0 [0]);
+ close (1);
+ dup (pipe1 [1]);
+ close (2);
+ dup (nulldevice);
+ close (nulldevice);
+ closepipes ();
+ va_start (ap, command);
+ argno = 0;
+ while ((args[argno++] = va_arg(ap, char *)) != NULL)
+ if (argno == (MAXARGS - 1)) {
+ args[argno] = NULL;
+ break;
+ }
+ va_end (ap);
+ execvp (command, args);
+ exit (0);
+ }
+ default:
+ {
+ char buffer [8192];
+ int i;
+
+ close (pipe0 [0]);
+ close (pipe1 [0]);
+ close (pipe1 [1]);
+ while ((i = mc_read (inhandle, buffer,
+ (inlen == -1 || inlen > 8192)
+ ? 8192 : inlen)) > 0) {
+ write (pipe0 [1], buffer, i);
+ if (inlen != -1) {
+ inlen -= i;
+ if (!inlen)
+ break;
+ }
+ }
+ close (pipe0 [1]);
+ while (waitpid (pid, &i, 0) < 0)
+ if (errno != EINTR)
+ break;
+
+ port_shutdown_extra_fds ();
+ exit (i);
+ }
+ }
+ }
+ default:
+ *the_pid = pid;
+ break;
+ }
+ close (pipe0 [0]);
+ close (pipe0 [1]);
+ close (pipe1 [1]);
+ return pipe1 [0];
+}
+
+int mc_doublepclose (int pipe, pid_t pid)
+{
+ int status = 0;
+
+ close (pipe);
+ waitpid (pid, &status, 0);
+#ifdef SCO_FLAVOR
+ waitpid (-1, NULL, WNOHANG);
+#endif /* SCO_FLAVOR */
+ sigaction (SIGINT, &save_intr, NULL);
+ sigaction (SIGQUIT, &save_quit, NULL);
+ sigaction (SIGTSTP, &save_stop, NULL);
+
+ return status;
+}
+
+/* Canonicalize path, and return a new path. Do everything in situ.
+ The new path differs from path in:
+ Multiple `/'s are collapsed to a single `/'.
+ Leading `./'s and trailing `/.'s are removed.
+ Trailing `/'s are removed.
+ Non-leading `../'s and trailing `..'s are handled by removing
+ portions of the path. */
+char *canonicalize_pathname (char *path)
+{
+ int i, start;
+ char stub_char;
+
+ stub_char = (*path == PATH_SEP) ? PATH_SEP : '.';
+
+ /* Walk along path looking for things to compact. */
+ i = 0;
+ for (;;) {
+ if (!path[i])
+ break;
+
+ while (path[i] && path[i] != PATH_SEP)
+ i++;
+
+ start = i++;
+
+ /* If we didn't find any slashes, then there is nothing left to do. */
+ if (!path[start])
+ break;
+
+#if defined(__QNX__)
+ /*
+ ** QNX accesses the directories of nodes on its peer-to-peer
+ ** network by prefixing their directories with "//[nid]".
+ ** We don't want to collapse two '/'s if they're at the start
+ ** of the path, followed by digits, and ending with a '/'.
+ */
+ if (start == 0 && i == 1)
+ {
+ char *p = path + 2;
+ char *q = strchr(p, PATH_SEP);
+
+ if (q > p)
+ {
+ *q = 0;
+ if (!strcspn(p, "0123456789"))
+ {
+ start = q - path;
+ i = start + 1;
+ }
+ *q = PATH_SEP;
+ }
+ }
+#endif
+
+ /* Handle multiple `/'s in a row. */
+ while (path[i] == PATH_SEP)
+ i++;
+
+ if ((start + 1) != i) {
+ strcpy (path + start + 1, path + i);
+ i = start + 1;
+ }
+
+ /* Handle backquoted `/'. */
+ if (start > 0 && path[start - 1] == '\\')
+ continue;
+
+ /* Check for trailing `/'. */
+ if (start && !path[i]) {
+ zero_last:
+ path[--i] = '\0';
+ break;
+ }
+
+ /* Check for `../', `./' or trailing `.' by itself. */
+ if (path[i] == '.') {
+ /* Handle trailing `.' by itself. */
+ if (!path[i + 1])
+ goto zero_last;
+
+ /* Handle `./'. */
+ if (path[i + 1] == PATH_SEP) {
+ strcpy (path + i, path + i + 1);
+ i = start;
+ continue;
+ }
+
+ /* Handle `../' or trailing `..' by itself.
+ Remove the previous ?/ part with the exception of
+ ../, which we should leave intact. */
+ if (path[i + 1] == '.' && (path[i + 2] == PATH_SEP || !path[i + 2])) {
+ while (--start > -1 && path[start] != PATH_SEP);
+ if (!strncmp (path + start + 1, "../", 3))
+ continue;
+ strcpy (path + start + 1, path + i + 2);
+ i = start;
+ continue;
+ }
+ }
+ }
+
+ if (!*path) {
+ *path = stub_char;
+ path[1] = '\0';
+ }
+ return path;
+}
+
+#ifdef SCO_FLAVOR
+int gettimeofday( struct timeval * tv, struct timezone * tz)
+{
+ struct timeb tb;
+ struct tm * l;
+
+ ftime( &tb );
+ if (errno == EFAULT)
+ return -1;
+ l = localtime(&tb.time);
+ tv->tv_sec = l->tm_sec;
+ tv->tv_usec = (long) tb.millitm;
+ return 0;
+}
+#endif /* SCO_FLAVOR */
+
+#ifndef HAVE_PUTENV
+
+/* The following piece of code was copied from the GNU C Library */
+/* And is provided here for nextstep who lacks putenv */
+
+extern char **environ;
+
+#ifndef HAVE_GNU_LD
+#define __environ environ
+#endif
+
+
+/* Put STRING, which is of the form "NAME=VALUE", in the environment. */
+int
+putenv (const char *string)
+{
+ const char *const name_end = strchr (string, '=');
+ register size_t size;
+ register char **ep;
+
+ if (name_end == NULL){
+ /* Remove the variable from the environment. */
+ size = strlen (string);
+ for (ep = __environ; *ep != NULL; ++ep)
+ if (!strncmp (*ep, string, size) && (*ep)[size] == '='){
+ while (ep[1] != NULL){
+ ep[0] = ep[1];
+ ++ep;
+ }
+ *ep = NULL;
+ return 0;
+ }
+ }
+
+ size = 0;
+ for (ep = __environ; *ep != NULL; ++ep)
+ if (!strncmp (*ep, string, name_end - string) &&
+ (*ep)[name_end - string] == '=')
+ break;
+ else
+ ++size;
+
+ if (*ep == NULL){
+ static char **last_environ = NULL;
+ char **new_environ = (char **) malloc ((size + 2) * sizeof (char *));
+ if (new_environ == NULL)
+ return -1;
+ (void) memcpy ((void *) new_environ, (void *) __environ,
+ size * sizeof (char *));
+ new_environ[size] = (char *) string;
+ new_environ[size + 1] = NULL;
+ if (last_environ != NULL)
+ free ((void *) last_environ);
+ last_environ = new_environ;
+ __environ = new_environ;
+ }
+ else
+ *ep = (char *) string;
+
+ return 0;
+}
+#endif /* !HAVE_PUTENV */
+
+void my_statfs (struct my_statfs *myfs_stats, char *path)
+{
+ int i, len = 0;
+
+#ifndef NO_INFOMOUNT
+ struct mount_entry *entry = NULL;
+ struct mount_entry *temp = mount_list;
+ struct fs_usage fs_use;
+
+ while (temp){
+ i = strlen (temp->me_mountdir);
+ if (i > len && (strncmp (path, temp->me_mountdir, i) == 0))
+ if (!entry || (path [i] == PATH_SEP || path [i] == 0)){
+ len = i;
+ entry = temp;
+ }
+ temp = temp->me_next;
+ }
+
+ if (entry){
+ get_fs_usage (entry->me_mountdir, &fs_use);
+
+ myfs_stats->type = entry->me_dev;
+ myfs_stats->typename = entry->me_type;
+ myfs_stats->mpoint = entry->me_mountdir;
+ myfs_stats->device = entry->me_devname;
+ myfs_stats->avail = getuid () ? fs_use.fsu_bavail/2 : fs_use.fsu_bfree/2;
+ myfs_stats->total = fs_use.fsu_blocks/2;
+ myfs_stats->nfree = fs_use.fsu_ffree;
+ myfs_stats->nodes = fs_use.fsu_files;
+ } else
+#endif
+#if defined(NO_INFOMOUNT) && defined(__QNX__)
+/*
+** This is the "other side" of the hack to read_filesystem_list() in
+** mountlist.c.
+** It's not the most efficient approach, but consumes less memory. It
+** also accomodates QNX's ability to mount filesystems on the fly.
+*/
+ struct mount_entry *entry;
+ struct fs_usage fs_use;
+
+ if ((entry = read_filesystem_list(0, 0)) != NULL)
+ {
+ get_fs_usage(entry->me_mountdir, &fs_use);
+
+ myfs_stats->type = entry->me_dev;
+ myfs_stats->typename = entry->me_type;
+ myfs_stats->mpoint = entry->me_mountdir;
+ myfs_stats->device = entry->me_devname;
+
+ myfs_stats->avail = fs_use.fsu_bfree / 2;
+ myfs_stats->total = fs_use.fsu_blocks / 2;
+ myfs_stats->nfree = fs_use.fsu_ffree;
+ myfs_stats->nodes = fs_use.fsu_files;
+ }
+ else
+#endif
+ {
+ myfs_stats->type = 0;
+ myfs_stats->mpoint = "unknown";
+ myfs_stats->device = "unknown";
+ myfs_stats->avail = 0;
+ myfs_stats->total = 0;
+ myfs_stats->nfree = 0;
+ myfs_stats->nodes = 0;
+ }
+}
+
+#ifdef HAVE_GET_PROCESS_STATS
+# include <sys/procstats.h>
+
+int gettimeofday (struct timeval *tp, void *tzp)
+{
+ return get_process_stats(tp, PS_SELF, 0, 0);
+}
+#endif
+
+#ifdef SCO_FLAVOR
+/* Define this only for SCO */
+#ifdef USE_NETCODE
+#ifndef HAVE_SOCKETPAIR
+
+/*
+ The code for s_pipe function is adapted from Section 7.9
+ of the "UNIX Network Programming" by W. Richard Stevens,
+ published by Prentice Hall, ISBN 0-13-949876-1
+ (c) 1990 by P T R Prentice Hall
+
+ It is used to implement socketpair function for SVR3 systems
+ that lack it.
+*/
+
+#include <sys/types.h>
+#include <sys/stream.h> /* defines queue_t */
+#include <stropts.h> /* defines struct strtdinsert */
+#include <fcntl.h>
+
+#define SPX_DEVICE "/dev/spx"
+#define S_PIPE_HANDLE_ERRNO 1
+/* if the above is defined to 1, we will attempt to
+ save and restore errno to indicate failure
+ reason to the caller;
+ Please note that this will not work in environments
+ where errno is not just an integer
+*/
+
+#if S_PIPE_HANDLE_ERRNO
+#include <errno.h>
+/* This is for "extern int errno;" */
+#endif
+
+ /* s_pipe returns 0 if OK, -1 on error */
+ /* two file descriptors are returned */
+int s_pipe(int fd[2])
+{
+ struct strfdinsert ins; /* stream I_FDINSERT ioctl format */
+ queue_t *pointer;
+ #if S_PIPE_HANDLE_ERRNO
+ int err_save;
+ #endif
+ /*
+ * First open the stream clone device "dev/spx" twice,
+ * obtaining the two file descriptors
+ */
+
+ if ( (fd[0] = open(SPX_DEVICE, O_RDWR)) < 0)
+ return -1;
+ if ( (fd[1] = open(SPX_DEVICE, O_RDWR)) < 0) {
+ #if S_PIPE_HANDLE_ERRNO
+ err_save = errno;
+ #endif
+ close(fd[0]);
+ #if S_PIPE_HANDLE_ERRNO
+ errno = err_save;
+ #endif
+ return -1;
+ }
+
+ /*
+ * Now link these two stream together with an I_FDINSERT ioctl.
+ */
+
+ ins.ctlbuf.buf = (char *) &pointer; /* no control information, just the pointer */
+ ins.ctlbuf.maxlen = sizeof pointer;
+ ins.ctlbuf.len = sizeof pointer;
+ ins.databuf.buf = (char *) 0; /* no data to be sent */
+ ins.databuf.maxlen = 0;
+ ins.databuf.len = -1; /* magic: must be -1 rather than 0 for stream pipes */
+
+ ins.fildes = fd[1]; /* the fd to connect with fd[0] */
+ ins.flags = 0; /* nonpriority message */
+ ins.offset = 0; /* offset of pointer in control buffer */
+
+ if (ioctl(fd[0], I_FDINSERT, (char *) &ins) < 0) {
+ #if S_PIPE_HANDLE_ERRNO
+ err_save = errno;
+ #endif
+ close(fd[0]);
+ close(fd[1]);
+ #if S_PIPE_HANDLE_ERRNO
+ errno = err_save;
+ #endif
+ return -1;
+ }
+ /* all is OK if we came here, indicate success */
+ return 0;
+}
+
+int socketpair(int dummy1, int dummy2, int dummy3, int fd[2])
+{
+ return s_pipe(fd);
+}
+
+#endif /* ifndef HAVE_SOCKETPAIR */
+#endif /* ifdef USE_NETCODE */
+#endif /* SCO_FLAVOR */
--- /dev/null
+/* {{{ Copyright notice */
+
+/* View file module for the Midnight Commander
+ Copyright (C) 1994, 1995, 1996 The Free Software Foundation
+ Written by: 1994, 1995, 1998 Miguel de Icaza
+ 1994, 1995 Janne Kukonlehto
+ 1995 Jakub Jelinek
+ 1996 Joseph M. Hinkle
+ 1997 Norbert Warmuth
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* }}} */
+/* {{{ Declarations */
+#include <config.h>
+#include "x.h"
+#include <stdio.h>
+#ifdef OS2_NT
+# include <io.h>
+#endif
+#include <sys/types.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <string.h>
+#include "tty.h"
+#include <sys/stat.h>
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+#endif
+#include <fcntl.h>
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+#include <ctype.h> /* For toupper() */
+#include <stdlib.h> /* atoi() */
+#include <malloc.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/param.h>
+#include "mem.h"
+#include "mad.h"
+#include "util.h"
+#include "dlg.h" /* Needed by widget.h */
+#include "widget.h" /* Needed for buttonbar_new */
+#include "color.h"
+#include "dialog.h"
+#include "file.h"
+#include "mouse.h"
+#include "global.h"
+#include "help.h"
+#include "key.h" /* For mi_getch() */
+#include "layout.h"
+#include "wtools.h" /* For query_set_sel() */
+#if defined(HAVE_RX_H) && defined(HAVE_REGCOMP)
+# include <rx.h>
+#else
+# include "regex.h"
+#endif
+#include "fs.h"
+#include "../vfs/vfs.h"
+#include "dir.h"
+#include "panel.h" /* Needed for current_panel and other_panel */
+#include "win.h"
+#include "main.h" /* For the externs */
+#define WANT_WIDGETS
+#include "view.h"
+
+#ifndef MAP_FILE
+#define MAP_FILE 0
+#endif
+
+/* Block size for reading files in parts */
+#define READ_BLOCK 8192
+#define VIEW_PAGE_SIZE 8192
+
+#ifdef IS_AIX
+# define IFAIX(x) case (x):
+#else
+# define IFAIX(x)
+#endif
+
+/* Maxlimit for skipping updates */
+int max_dirt_limit =
+#ifdef OS2_NT
+0;
+#else
+10;
+#endif
+
+/* Our callback */
+static int view_callback (Dlg_head *h, WView *view, int msg, int par);
+
+/* If set, show a ruler */
+int ruler = 0;
+
+/* Scrolling is done in pages or line increments */
+int mouse_move_pages_viewer = 1;
+
+/* Used to compute the bottom first variable */
+int have_fast_cpu = 0;
+
+/* wrap mode default */
+int global_wrap_mode = 1;
+
+int default_hex_mode = 0;
+int default_hexedit_mode = 0;
+int default_magic_flag = 1;
+int default_nroff_flag = 1;
+int altered_hex_mode = 0;
+int altered_magic_flag = 0;
+int altered_nroff_flag = 0;
+/* }}} */
+
+/* "$Id: view.c,v 1.1 2001/12/30 09:55:20 sedwards Exp $" */
+
+static char hex_char[] = "0123456789ABCDEF";
+
+/* }}} */
+/* {{{ Clean-up functions */
+
+void
+close_view_file (WView *view)
+{
+ if (view->file != -1){
+ mc_close (view->file);
+ view->file = -1;
+ }
+}
+
+void
+free_file (WView *view)
+{
+ int i;
+
+#ifdef HAVE_MMAP
+
+ if (view->mmapping){
+ mc_munmap (view->data, view->s.st_size);
+ close_view_file (view);
+ } else
+#endif /* HAVE_MMAP */
+ {
+ if (view->reading_pipe){
+ /* Check error messages */
+ if (!view->have_frame)
+ check_error_pipe ();
+
+ /* Close pipe */
+ pclose (view->stdfile);
+ view->stdfile = NULL;
+
+ /* Ignore errors because we don't want to hear about broken pipe */
+ close_error_pipe (-1, NULL);
+ } else
+ close_view_file (view);
+ }
+ /* Block_ptr may be zero if the file was a file with 0 bytes */
+ if (view->growing_buffer && view->block_ptr){
+ for (i = 0; i < view->blocks; i++){
+ free (view->block_ptr [i].data);
+ }
+ free (view->block_ptr);
+ }
+}
+
+/* Valid parameters for second parameter to set_monitor */
+enum { off, on };
+
+/* Both views */
+void
+view_done (WView *view)
+{
+ set_monitor (view, off);
+#ifndef HAVE_MMAP
+ /* alex: release core, used to replace mmap */
+ if (!view->growing_buffer && view->data != (unsigned char*)0)
+ {
+ free(view->data);
+ view->data = NULL;
+ }
+#endif /* HAVE_MMAP */
+
+ if (view->view_active){
+ if (view->localcopy)
+ mc_ungetlocalcopy (view->filename, view->localcopy, 0);
+ free_file (view);
+ free (view->filename);
+ if (view->command)
+ free (view->command);
+ }
+ view->view_active = 0;
+ default_hex_mode = view->hex_mode;
+ default_nroff_flag = view->viewer_nroff_flag;
+ default_magic_flag = view->viewer_magic_flag;
+}
+
+static void view_hook (void *);
+
+void
+view_destroy (WView *view)
+{
+ view_done (view);
+ if (view->have_frame)
+ delete_hook (&select_file_hook, view_hook);
+ x_destroy_view (view);
+}
+
+static int
+get_byte (WView *view, int byte_index)
+{
+ int page = byte_index / VIEW_PAGE_SIZE + 1;
+ int offset = byte_index % VIEW_PAGE_SIZE;
+ int i, n;
+ block_ptr_t *tmp;
+
+ if (view->growing_buffer){
+ if (page > view->blocks){
+ tmp = xmalloc (sizeof (block_ptr_t) * page, "get_byte");
+ if (view->block_ptr){
+ bcopy (view->block_ptr, tmp, sizeof (block_ptr_t) *
+ view->blocks);
+ free (view->block_ptr);
+ }
+ view->block_ptr = tmp;
+ for (i = view->blocks; i < page; i++){
+ char *p = malloc (VIEW_PAGE_SIZE);
+ view->block_ptr [i].data = p;
+ if (!p)
+ return '\n';
+ if (view->stdfile != NULL)
+ n = fread (p, 1, VIEW_PAGE_SIZE, view->stdfile);
+ else
+ n = mc_read (view->file, p, VIEW_PAGE_SIZE);
+ if (n != -1)
+ view->bytes_read += n;
+ if (view->s.st_size < view->bytes_read){
+ view->bottom_first = -1; /* Invalidate cache */
+ view->s.st_size = view->bytes_read;
+ view->last_byte = view->bytes_read;
+ if (view->reading_pipe)
+ view->last_byte = view->first + view->bytes_read;
+ }
+ /* To force loading the next page */
+ if (n == VIEW_PAGE_SIZE && view->reading_pipe){
+ view->last_byte++;
+ }
+ }
+ view->blocks = page;
+ }
+ if (byte_index > view->bytes_read){
+ return -1;
+ } else
+ return view->block_ptr [page-1].data [offset];
+ } else {
+ if (byte_index >= view->last_byte)
+ return -1;
+ else
+ return view->data [byte_index];
+ }
+}
+
+static void
+enqueue_change (struct hexedit_change_node **head, struct hexedit_change_node *node)
+{
+ struct hexedit_change_node *curr = *head;
+
+ while (curr) {
+ if (node->offset < curr->offset) {
+ *head = node;
+ node->next = curr;
+ return;
+ }
+ head = (struct hexedit_change_node **) curr;
+ curr = curr->next;
+ }
+ *head = node;
+ node->next = curr;
+}
+
+static void move_right (WView *);
+
+static void
+put_editkey (WView *view, unsigned char key)
+{
+ struct hexedit_change_node *node;
+ unsigned char byte_val;
+
+ if (!view->hexedit_mode || view->growing_buffer != 0)
+ return;
+
+ /* Has there been a change at this position ? */
+ node = view->change_list;
+ while (node) {
+ if (node->offset != view->edit_cursor)
+ node = node->next;
+ else
+ break;
+ }
+
+ if (view->view_side == view_side_left) {
+ /* Hex editing */
+
+ if (key >= '0' && key <= '9')
+ key -= '0';
+ else if (key >= 'A' && key <= 'F')
+ key -= '7';
+ else if (key >= 'a' && key <= 'f')
+ key -= 'W';
+ else
+ return;
+
+ if (node)
+ byte_val = node->value;
+ else
+ byte_val = get_byte(view, view->edit_cursor);
+
+ if (view->nib_shift == 0) {
+ byte_val = (byte_val & 0x0f) | (key << 4);
+ } else {
+ byte_val = (byte_val & 0xf0) | (key);
+ }
+ } else {
+ /* Text editing */
+ byte_val = key;
+ }
+ if (!node) {
+ node = (struct hexedit_change_node *)
+ xmalloc(sizeof(struct hexedit_change_node), "HexEdit");
+
+ if (node) {
+#ifndef HAVE_MMAP
+ /*
+ ** alex@bcs.zaporizhzhe.ua: here we are using file copy
+ ** completely loaded into memory, so we can replace bytes
+ ** in view->data array to allow changes to be reflected
+ ** when user switches back to ascii mode
+ */
+ view->data[view->edit_cursor] = byte_val;
+#endif /* HAVE_MMAP */
+ node->offset = view->edit_cursor;
+ node->value = byte_val;
+ enqueue_change (&view->change_list, node);
+ }
+ } else {
+ node->value = byte_val;
+ }
+ view->dirty++;
+ view_update (view);
+ move_right (view);
+}
+
+static void
+free_change_list (WView *view)
+{
+ struct hexedit_change_node *n = view->change_list;
+
+ while (n) {
+ view->change_list = n->next;
+ free (n);
+ n = view->change_list;
+ }
+ view->file_dirty = 0;
+ view->dirty++;
+}
+
+static void
+save_edit_changes (WView *view)
+{
+ struct hexedit_change_node *node = view->change_list;
+ int fp;
+
+ fp = open (view->filename, O_WRONLY);
+ if (fp >= 0) {
+ while (node) {
+ lseek (fp, node->offset, SEEK_SET);
+ write (fp, &node->value, 1);
+ node = node->next;
+ }
+ close (fp);
+ }
+ free_change_list (view);
+}
+
+static int
+view_ok_to_quit (WView *view)
+{
+ int r;
+ char *text;
+
+ if (!view->change_list)
+ return 1;
+
+ query_set_sel (1);
+ text = copy_strings (_("File: \n\n "), view->filename,
+ _("\n\nhas been modified, do you want to save the changes?\n"), NULL);
+
+ r = query_dialog (_(" Save changes "), text, 2, 3, _("&Yes"), _("&No"), _("&Cancel"));
+ free (text);
+
+ switch (r) {
+ case 0:
+ save_edit_changes (view);
+ return 1;
+ case 1:
+ free_change_list (view);
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static char *
+set_view_init_error (WView *view, char *msg)
+{
+ view->growing_buffer = 0;
+ view->reading_pipe = 0;
+ view->first = 0;
+ view->last_byte = 0;
+ if (msg){
+ view->bytes_read = strlen (msg);
+ return strdup (msg);
+ }
+ return 0;
+}
+
+/* return values: 0 for success, else points to error message */
+static char *
+init_growing_view (WView *view, char *name, char *filename)
+{
+ view->growing_buffer = 1;
+
+ if (name){
+ view->reading_pipe = 1;
+ view->s.st_size = 0;
+
+ open_error_pipe ();
+ if ((view->stdfile = popen (name, "r")) == NULL){
+ close_error_pipe (view->have_frame?-1:1, view->data);
+ return set_view_init_error (view, _(" Can't spawn child program "));
+ }
+
+#ifndef HAVE_XVIEW
+ /* First, check if filter produced any output */
+ get_byte (view, 0);
+ if (view->bytes_read <= 0){
+ pclose (view->stdfile);
+ view->stdfile = NULL;
+ close_error_pipe (view->have_frame?-1:1, view->data);
+ return set_view_init_error (view, _(" Empty output from child filter "));
+ }
+#endif
+ } else {
+ view->stdfile = NULL;
+ if ((view->file = mc_open (filename, O_RDONLY)) == -1)
+ return set_view_init_error (view, _(" Could not open file "));
+ }
+ return 0;
+}
+
+/* Load filename into core */
+/* returns:
+ -1 on failure.
+ if (have_frame), we return success, but data points to a
+ error message instead of the file buffer (quick_view feature).
+*/
+static char *load_view_file (WView *view, char *filename)
+{
+ char *cmd;
+ int type;
+
+ if ((view->file = mc_open (filename, O_RDONLY)) < 0){
+ set_view_init_error (view, 0);
+ return (copy_strings (_(" Can't open file \""),
+ filename, "\"\n ",
+ unix_error_string (errno), " ", 0));
+
+ }
+ if (mc_fstat (view->file, &view->s) < 0){
+ set_view_init_error (view, 0);
+ close_view_file (view);
+ return copy_strings (_(" Can't stat file \n "),
+ unix_error_string (errno), " ", 0);
+ }
+ if (S_ISDIR (view->s.st_mode) || S_ISSOCK (view->s.st_mode)
+ || S_ISFIFO (view->s.st_mode)){
+ close_view_file (view);
+ return set_view_init_error (view, _(" Can't view: not a regular file "));
+ }
+
+ if (view->s.st_size == 0){
+ /* Must be one of those nice files that grow (/proc) */
+ close_view_file (view);
+ return init_growing_view (view, 0, filename);
+ }
+
+ /* First, try to open a compressed file */
+ if (view->viewer_magic_flag && (is_gunzipable (view->file, &type)) != 0){
+ close_view_file (view);
+ if (vfs_file_is_local (filename)) {
+ char *tmp = name_quote (filename, 0);
+ cmd = copy_strings (decompress_command (type), " ", tmp, 0);
+ free (tmp);
+ }
+ else {
+ char *tmp;
+ if ((view->localcopy = mc_getlocalcopy (filename)) == 0)
+ return set_view_init_error (view, _(" Can not fetch local copy ") );
+ tmp = name_quote (view->localcopy, 0);
+ cmd = copy_strings (decompress_command (type), " ", tmp, 0);
+ free (tmp);
+ }
+ return init_growing_view (view, cmd, filename);
+ }
+
+ /* Otherwise, the file wasn't compressed */
+#ifdef HAVE_MMAP
+ view->data = mc_mmap (0, view->s.st_size, PROT_READ, MAP_FILE | MAP_SHARED,
+ view->file, 0);
+ if ((caddr_t) view->data == (caddr_t) -1){
+ close_view_file (view);
+/* set_view_init_error (view, 0);
+ return copy_strings (" Can't mmap file \n ",
+ unix_error_string (errno), " ", 0);*/
+ return init_growing_view (view, 0, filename);
+
+ }
+
+ view->first = 0;
+ view->bytes_read = view->s.st_size;
+ view->mmapping = 1;
+ return 0;
+#else /* ! HAVE_MMAP */
+ /*
+ ** For those OS that dont provide mmap call. Try to load all the file
+ ** into memory (alex@bcs.zaporizhzhe.ua)
+ */
+ view->data = (unsigned char*) xmalloc (view->s.st_size, "load_view_file");
+ if (view->data == (unsigned char*) 0
+ || mc_lseek(view->file,0,0) != 0
+ || mc_read(view->file, view->data, view->s.st_size) != view->s.st_size
+ ) {
+ if (view->data != (unsigned char*)0)
+ free(view->data);
+ close_view_file (view);
+ return init_growing_view (view, 0, filename);
+ }
+ view->first = 0;
+ view->bytes_read = view->s.st_size;
+ return 0;
+#endif
+}
+
+/* Return zero on success, -1 on failure */
+int
+do_view_init (WView *view, char *_command, char *_file, int start_line)
+{
+ char *error = 0;
+ int i;
+
+ if (view->view_active)
+ view_done (view);
+
+ /* Set up the state */
+ view->block_ptr = 0;
+ view->data = NULL;
+ view->growing_buffer = 0;
+ view->reading_pipe = 0;
+ view->mmapping = 0;
+ view->blocks = 0;
+ view->block_ptr = 0;
+ view->first = view->bytes_read = 0;
+ view->last_byte = 0;
+ view->filename = 0;
+ view->localcopy = 0;
+ view->command = 0;
+ view->last = view->first + ((LINES-2) * view->bytes_per_line);
+
+ /* Clear the markers */
+ view->marker = 0;
+ for (i = 0; i < 10; i++)
+ view->marks [i] = 0;
+
+
+ if (!view->have_frame){
+ view->start_col = 0;
+ }
+ if (_command && (view->viewer_magic_flag || _file[0] == '\0'))
+ error = init_growing_view (view, _command, _file);
+ else
+ error = load_view_file (view, _file);
+
+ if (error){
+ if (!view->have_frame){
+ message (1, MSG_ERROR, error);
+ free (error);
+ return -1;
+ }
+ }
+
+ view->view_active = 1;
+ view->filename = strdup (_file);
+ if (_command)
+ view->command = strdup (_command);
+ else
+ view->command = 0;
+ view->search_start = view->start_display = view->start_save = view->first;
+ view->found_len = 0;
+ view->start_col = 0;
+ view->last_search = 0; /* Start a new search */
+
+ /* Special case: The data points to the error message */
+ if (error){
+ view->data = error;
+ view->s.st_size = view->bytes_read = strlen (view->data);
+ }
+ view->last_byte = view->first + view->s.st_size;
+
+ if (start_line > 1 && !error){
+ int saved_wrap_mode = view->wrap_mode;
+
+ view->wrap_mode = 0;
+ get_byte (view, 0);
+ view_move_forward (view, start_line - 1);
+ view->wrap_mode = saved_wrap_mode;
+ }
+ view->edit_cursor = view->first;
+ view->file_dirty = 0;
+ view->nib_shift = 0;
+ view->view_side = view_side_left;
+ view->change_list = NULL;
+
+ return 0;
+}
+
+
+/* Both views */
+/* Return zero on success, -1 on failure */
+int
+view_init (WView *view, char *_command, char *_file, int start_line)
+{
+ int cols;
+
+ if (view->have_frame)
+ cols = view->widget.cols - 2;
+ else
+ cols = view->widget.cols;
+
+ view->bottom_first = -1;
+ view->bytes_per_line = 2 * (cols - 7) / 9;
+ view->bytes_per_line &= 0xfffc;
+ view->dirty = max_dirt_limit + 1; /* To force refresh */
+ if (!view->view_active || strcmp (_file, view->filename) || altered_magic_flag)
+ return do_view_init (view, _command, _file, start_line);
+ else
+ return 0;
+}
+
+/* }}} */
+
+/* {{{ Screen update functions */
+
+#ifndef HAVE_X
+void
+view_percent (WView *view, int p, int w)
+{
+ int percent;
+
+ percent = (view->s.st_size == 0 || view->last_byte == view->last) ? 100 :
+ (p > (INT_MAX/100) ?
+ p / (view->s.st_size / 100) :
+ p * 100 / view->s.st_size);
+
+#if 0
+ percent = view->s.st_size == 0 ? 100 :
+ (view->last_byte == view->last ? 100 :
+ (p)*100 / view->s.st_size);
+#endif
+
+ widget_move (view, view->have_frame, w - 5);
+ printw ("%3d%% ", percent);
+}
+
+void
+view_status (WView *view)
+{
+ int w = view->widget.cols - (view->have_frame * 2);
+ int i;
+
+ attrset (SELECTED_COLOR);
+ widget_move (view, view->have_frame, view->have_frame);
+ hline (' ', w);
+ if (w > 6){
+ i = w > 24 ? 18 : w - 6;
+ printw (_("File: %s"), name_trunc (view->filename ? view->filename:
+ view->command ? view->command:"", i));
+ if (w > 30){
+ widget_move (view, view->have_frame, 24);
+ if (view->hex_mode)
+ printw (_("Offset 0x%08x"), view->edit_cursor);
+ else
+ printw (_("Col %d"), -view->start_col);
+ }
+ if (w > 60){
+ widget_move (view, view->have_frame, 42);
+ printw (_("%s bytes"), size_trunc (view->s.st_size));
+ }
+ if (w > 70){
+ printw (" ");
+ if (view->growing_buffer)
+ addstr (_(" [grow]"));
+ }
+ if (w - i > 4)
+ if (view->hex_mode)
+ view_percent (view, view->edit_cursor - view->first, w);
+ else
+ view_percent (view, view->start_display - view->first, w);
+ }
+ attrset (SELECTED_COLOR);
+}
+
+#define view_set_color(view,font) attrset (font)
+
+static inline void
+view_display_clean (WView *view, int height, int width)
+{
+ /* FIXME: Should I use widget_erase only and repaint the box? */
+ if (view->have_frame){
+ int i;
+
+ draw_double_box (view->widget.parent, view->widget.y, view->widget.x,
+ view->widget.lines, view->widget.cols);
+ for (i = 1; i < height; i++){
+ widget_move (view, i, 1);
+ printw ("%*s", width-1, "");
+ }
+ } else
+ widget_erase ((Widget *) view);
+}
+
+#define view_add_character(view,c) addch (c)
+#define view_add_string(view,s) addstr (s)
+#define view_gotoyx(v,r,c) widget_move (v,r,c)
+#endif
+
+#ifndef HAVE_TK
+/* Both the text mode and gnome editions use this */
+#define BOLD_COLOR MARKED_COLOR
+#define UNDERLINE_COLOR VIEW_UNDERLINED_COLOR
+#define MARK_COLOR SELECTED_COLOR
+#define DEF_COLOR NORMAL_COLOR
+#endif
+
+#ifndef PORT_HAS_VIEW_FREEZE
+# define view_freeze(view)
+# define view_thaw(view)
+#endif
+
+#ifdef HAVE_GNOME
+# define PICK_COLOR(a,b) BOLD_COLOR : DEF_COLOR
+#else
+# define PICK_COLOR(a,b) a : b
+#endif
+
+/* Shows the file pointed to by *start_display on view_win */
+static long
+display (WView *view)
+{
+#ifdef HAVE_X
+# define frame_shift 0
+# define STATUS_LINES 0
+#else
+ const int frame_shift = view->have_frame;
+# define STATUS_LINES 1
+#endif
+ int col = 0 + frame_shift;
+ int row = STATUS_LINES + frame_shift;
+ int height, width;
+ long from;
+ int c;
+ int boldflag = 0;
+ struct hexedit_change_node *curr = view->change_list;
+
+ height = view->widget.lines - frame_shift;
+ width = view->widget.cols - frame_shift;
+ from = view->start_display;
+ view_set_color (view, DEF_COLOR);
+
+ view_freeze (view);
+ view_display_clean (view, height, width);
+
+ /* Optionally, display a ruler */
+ if ((!view->hex_mode) && (ruler)){
+ char r_buff[4];
+ int cl;
+
+ view_set_color (view, BOLD_COLOR);
+ for (c = frame_shift; c < width; c++) {
+ cl = c-view->start_col;
+ if (ruler == 1)
+ view_gotoyx (view, row, c);
+ else
+ view_gotoyx (view, row+height-2, c);
+ r_buff[0] = '-';
+ if ((cl % 10) == 0)
+ r_buff[0] = '|';
+ else
+ if ((cl % 5) == 0)
+ r_buff[0] = '*';
+ view_add_character (view, r_buff[0]);
+ if ((cl != 0) && (cl % 10) == 0){
+ sprintf(r_buff, "%03d", cl);
+ if (ruler == 1)
+ widget_move (view, row + 1, c - 1);
+ else
+ widget_move (view, row + height - 3, c - 1);
+ view_add_string (view, r_buff);
+ }
+ }
+ view_set_color (view, DEF_COLOR);
+ if (ruler == 1)
+ row += 2;
+ else
+ height -= 2;
+ }
+
+ /* Find the first displayable changed byte */
+ while (curr) {
+ if (curr->offset < from)
+ curr = curr->next;
+ else
+ break;
+ }
+ if (view->hex_mode){
+ char hex_buff[10]; /* A temporary buffer for sprintf and mvwaddstr */
+ int bytes; /* Number of bytes already printed on the line */
+
+ /* Start of text column */
+ int text_start = width - view->bytes_per_line - 1 + frame_shift;
+
+ for (;row < height && from < view->last_byte; row++){
+ /* Print the hex offset */
+ sprintf (hex_buff, "%05X", (int) (from - view->first));
+ widget_move (view, row, frame_shift);
+ view_add_string (view, hex_buff);
+
+ /* Hex dump starts from column seven */
+ col = 7;
+
+ /* Each hex number is two digits */
+ hex_buff[2] = 0;
+ for (bytes = 0; bytes < view->bytes_per_line
+ && from < view->last_byte; bytes++, from++){
+ /* Display and mark changed bytes */
+ if (curr && from == curr->offset) {
+ c = curr->value;
+ curr = curr->next;
+ boldflag = 3;
+ view_set_color (view, 7);
+ } else
+ c = (unsigned char) get_byte (view, from);
+
+ if (view->found_len && from >= view->search_start
+ && from < view->search_start + view->found_len){
+ boldflag = 1;
+ view_set_color (view, BOLD_COLOR);
+ }
+ /* Display the navigation cursor */
+ if (from == view->edit_cursor) {
+ if (view->view_side == view_side_left){
+ view->cursor_row = row;
+ view->cursor_col = col;
+ }
+ boldflag = 2;
+ view_set_color (view, view->view_side == view_side_left ? PICK_COLOR (15, 31));
+ }
+
+ /* Print a hex number (sprintf is too slow) */
+ hex_buff [0] = hex_char [(c >> 4)];
+ hex_buff [1] = hex_char [c & 15];
+ view_gotoyx (view, row, col);
+ view_add_string (view, hex_buff);
+ col += 3;
+ /* Turn off the cursor or changed byte highlighting here */
+ if (boldflag > 1)
+ view_set_color (view, DEF_COLOR);
+ if ((bytes & 3) == 3 && bytes + 1 < view->bytes_per_line){
+ /* Turn off the search highlighting */
+ if (boldflag == 1 &&
+ from == view->search_start + view->found_len - 1)
+ view_set_color (view, DEF_COLOR);
+
+ /* Hex numbers are printed in the groups of four */
+ /* Groups are separated by a vline */
+
+ view_add_character (view, ' ');
+ one_vline ();
+ view_gotoyx (view, row, col + 1);
+ col += 2;
+
+ if (boldflag && from==view->search_start+view->found_len-1)
+ view_set_color (view, BOLD_COLOR);
+
+ }
+ if (boldflag && from < view->search_start + view->found_len - 1
+ && bytes != view->bytes_per_line - 1)
+ view_add_character (view, ' ');
+
+ /* Print the corresponding ascii character */
+ view_gotoyx (view, row, text_start + bytes);
+
+ if (!is_printable (c))
+ c = '.';
+ switch (boldflag) {
+ default:
+ break;
+ case 1:
+ view_set_color (view, BOLD_COLOR);
+ goto setcursor;
+ case 2:
+ view_set_color (view, view->view_side == view_side_left ? PICK_COLOR (31, 15));
+ goto setcursor;
+ case 3:
+ view_set_color (view, 7);
+
+ setcursor:
+ if (view->view_side == view_side_right){
+ view->cursor_col = text_start + bytes;
+ view->cursor_row = row;
+ }
+ }
+ view_add_character (view, c);
+
+ if (boldflag){
+ boldflag = 0;
+ view_set_color (view, DEF_COLOR);
+ }
+ }
+ }
+ } else {
+ if (view->growing_buffer && from == view->last_byte)
+ get_byte (view, from);
+ for (; row < height && from < view->last_byte; from++){
+ c = get_byte (view, from);
+ if ((c == '\n') || (col == width && view->wrap_mode)){
+ col = frame_shift;
+ row++;
+ if (c == '\n' || row >= height)
+ continue;
+ }
+ if (c == '\r')
+ continue;
+ if (c == '\t'){
+ col = ((col - frame_shift)/8)*8 + 8 + frame_shift;
+ continue;
+ }
+ if (view->viewer_nroff_flag && c == '\b'){
+ if (from + 1 < view->last_byte
+ && is_printable (get_byte (view, from + 1)) &&
+ from > view->first
+ && is_printable (get_byte (view, from - 1)))
+ {
+ if (col <= frame_shift){
+ /* So it has to be wrap_mode - do not need to check for it */
+ if (row == 1 + frame_shift){
+ from++;
+ continue; /* There had to be a bold character on the rightmost position
+ of the previous undisplayed line */
+ }
+ row--;
+ col = width;
+ }
+ col--;
+ boldflag = 1;
+ if (get_byte (view, from - 1) == '_' && get_byte (view, from + 1) != '_')
+ view_set_color (view, UNDERLINE_COLOR);
+ else
+ view_set_color (view, BOLD_COLOR);
+ continue;
+ }
+ }
+ if (view->found_len && from >= view->search_start
+ && from < view->search_start + view->found_len){
+ boldflag = 1;
+ view_set_color (view, MARK_COLOR);
+ }
+ if (col >= frame_shift-view->start_col
+ && col < width-view->start_col)
+ {
+ view_gotoyx (view, row, col+view->start_col);
+ if (!is_printable (c))
+ c = '.';
+
+ view_add_character (view, c);
+ }
+ col++;
+ if (boldflag){
+ boldflag = 0;
+ view_set_color (view, DEF_COLOR);
+ }
+
+ /* Very last thing */
+ if (view->growing_buffer && from+1 == view->last_byte)
+ get_byte (view, from+1);
+ }
+#ifdef HAVE_TK
+ view_gotoyx (view, view->current_line+1, 0);
+#endif
+ }
+ view->last = from;
+ view_thaw (view);
+ return from;
+}
+
+void
+view_place_cursor (WView *view)
+{
+ int shift;
+
+ if (view->view_side == view_side_left)
+ shift = view->nib_shift;
+ else
+ shift = 0;
+
+ widget_move (&view->widget, view->cursor_row, view->cursor_col + shift);
+}
+
+void
+view_update (WView *view)
+{
+ static int dirt_limit = 1;
+
+ if (view->dirty > dirt_limit){
+ /* Too many updates skipped -> force a update */
+ display (view);
+ view_status (view);
+ view->dirty = 0;
+ /* Raise the update skipping limit */
+ dirt_limit++;
+ if (dirt_limit > max_dirt_limit)
+ dirt_limit = max_dirt_limit;
+ }
+ if (view->dirty){
+ if (is_idle ()){
+ /* We have time to update the screen properly */
+ display (view);
+ view_status (view);
+ view->dirty = 0;
+ if (dirt_limit > 1)
+ dirt_limit--;
+ } else {
+ /* We are busy -> skipping full update,
+ only the status line is updated */
+ view_status (view);
+ }
+ /* Here we had a refresh, if fast scrolling does not work
+ restore the refresh, although this should not happen */
+ }
+}
+
+static inline void
+my_define (Dlg_head *h, int idx, char *text,
+ void (*fn)(WView *), WView *view)
+{
+ define_label_data (h, (Widget *) view, idx, text, (buttonbarfn) fn, view);
+}
+
+/* }}} */
+/* {{{ Movement functions */
+/* If the last parameter is nonzero, it means we want get the count of lines
+ from current up to the the upto position inclusive */
+static long
+move_forward2 (WView *view, long current, int lines, long upto)
+{
+ long p, q;
+ int line;
+ int col = 0;
+
+ if (view->hex_mode){
+ p = current + lines * view->bytes_per_line;
+ p = (p >= view->last_byte) ? current : p;
+ if (lines == 1) {
+ q = view->edit_cursor + view->bytes_per_line;
+ line = q / view->bytes_per_line;
+ col = (view->last_byte-1) / view->bytes_per_line;
+ view->edit_cursor = (line > col) ? view->edit_cursor : q;
+ view->edit_cursor = (view->edit_cursor < view->last_byte) ?
+ view->edit_cursor : view->last_byte-1;
+ q = current + ((LINES-2) * view->bytes_per_line);
+ p = (view->edit_cursor < q) ? current : p;
+ } else {
+ view->edit_cursor = (view->edit_cursor < p) ?
+ p : view->edit_cursor;
+ }
+ return p;
+ } else {
+ if (upto){
+ lines = -1;
+ q = upto;
+ } else
+ q = view->last_byte;
+ if (get_byte (view, q) != '\n')
+ q++;
+ for (line = col = 0, p = current; p < q; p++){
+ int c;
+
+ if (lines != -1 && line >= lines)
+ return p;
+
+ c = get_byte (view, p);
+
+ if (view->wrap_mode){
+ if (c == '\r')
+ continue; /* This characters is never displayed */
+ else if (c == '\t')
+ col = ((col - view->have_frame)/8)*8 +8+ view->have_frame;
+ else
+ col++;
+ if (view->viewer_nroff_flag && c == '\b'){
+ if (p + 1 < view->last_byte
+ && is_printable (get_byte (view, p + 1))
+ && p > view->first
+ && is_printable (get_byte (view, p - 1)))
+ col -= 2;
+ } else if (col == vwidth){
+ /* FIXME: the c in is_printable was a p, that is a bug,
+ I suspect I got that fix from Jakub, same applies
+ for d. */
+ int d = get_byte (view, p+2);
+
+ if (p + 2 >= view->last_byte || !is_printable (c) ||
+ !view->viewer_nroff_flag || get_byte (view, p + 1) != '\b' ||
+ !is_printable (d)){
+ col = 0;
+
+ if (c == '\n' || get_byte (view, p+1) != '\n')
+ line++;
+ }
+ } else if (c == '\n'){
+ line++;
+ col = 0;
+ }
+ } else if (c == '\n')
+ line++;
+ }
+ if (upto)
+ return line;
+ }
+ return current;
+}
+
+/* returns the new current pointer */
+/* Cause even the forward routine became very complex, we in the wrap_mode
+ just find the nearest '\n', use move_forward2(p, 0, q) to get the count
+ of lines up to there and then use move_forward2(p, something, 0), which we
+ return */
+static long
+move_backward2 (WView *view, long current, int lines)
+{
+ long p, q, pm;
+ int line;
+
+ if (!view->hex_mode && current == view->first)
+ return current;
+
+ if (view->hex_mode){
+ p = current - lines * view->bytes_per_line;
+ p = (p < view->first) ? view->first : p;
+ if (lines == 1) {
+ q = view->edit_cursor - view->bytes_per_line;
+ view->edit_cursor = (q < view->first) ? view->edit_cursor : q;
+ p = (view->edit_cursor >= current) ? current : p;
+ } else {
+ q = p + ((LINES-2) * view->bytes_per_line);
+ view->edit_cursor = (view->edit_cursor >= q) ?
+ p : view->edit_cursor;
+ }
+ return p;
+ } else {
+ if (current == view->last_byte
+ && get_byte (view, current - 1) != '\n')
+ /* There is one virtual '\n' at the end,
+ so that the last line is shown */
+ line = 1;
+ else
+ line = 0;
+ for (q = p = current - 1; p >= view->first; p--)
+ if (get_byte (view, p) == '\n' || p == view->first) {
+ pm = p > view->first ? p + 1 : view->first;
+ if (!view->wrap_mode){
+ if (line == lines)
+ return pm;
+ line++;
+ } else {
+ line += move_forward2 (view, pm, 0, q);
+ if (line >= lines){
+ if (line == lines)
+ return pm;
+ else
+ return move_forward2 (view, pm, line - lines, 0);
+ }
+ q = p + 1;
+ }
+ }
+ }
+ return p > view->first ? p : view->first;
+}
+
+void
+view_move_backward (WView *view, int i)
+{
+ view->search_start = view->start_display =
+ move_backward2 (view, view->start_display, i);
+ view->found_len = 0;
+ view->last = view->first + ((LINES-2) * view->bytes_per_line);
+ view->dirty++;
+}
+
+static long
+get_bottom_first (WView *view, int do_not_cache, int really)
+{
+ int bottom_first;
+
+ if (!have_fast_cpu && !really)
+ return INT_MAX;
+
+ if (!do_not_cache && view->bottom_first != -1)
+ return view->bottom_first;
+
+ /* Force loading */
+ if (view->growing_buffer){
+ int old_last_byte;
+
+ old_last_byte = -1;
+ while (old_last_byte != view->last_byte){
+ old_last_byte = view->last_byte;
+ get_byte (view, view->last_byte+VIEW_PAGE_SIZE);
+ }
+ }
+
+ bottom_first = move_backward2 (view, view->last_byte, vheight - 1);
+
+ if (view->hex_mode)
+ bottom_first = (bottom_first + view->bytes_per_line - 1)
+ / view->bytes_per_line * view->bytes_per_line;
+ view->bottom_first = bottom_first;
+
+ return view->bottom_first;
+}
+
+void
+view_move_forward (WView *view, int i)
+{
+ view->start_display = move_forward2 (view, view->start_display, i, 0);
+ if (!view->reading_pipe && view->start_display > get_bottom_first (view, 0, 0))
+ view->start_display = view->bottom_first;
+ view->search_start = view->start_display;
+ view->found_len = 0;
+ view->last = view->first + ((LINES-2) * view->bytes_per_line);
+ view->dirty++;
+}
+
+
+static void
+move_to_top (WView *view)
+{
+ view->search_start = view->start_display = view->first;
+ view->found_len = 0;
+ view->last = view->first + ((LINES-2) * view->bytes_per_line);
+ view->nib_shift = 0;
+ view->edit_cursor = view->start_display;
+ view->dirty++;
+}
+
+static void
+move_to_bottom (WView *view)
+{
+ view->search_start = view->start_display = get_bottom_first (view, 0, 1);
+ view->found_len = 0;
+ view->last = view->first + ((LINES-2) * view->bytes_per_line);
+ view->edit_cursor = (view->edit_cursor < view->start_display) ?
+ view->start_display : view->edit_cursor;
+ view->dirty++;
+}
+
+/* Scroll left/right the view panel functions */
+static void
+move_right (WView *view)
+{
+ if (view->wrap_mode && !view->hex_mode)
+ return;
+ if (view->hex_mode) {
+ view->last = view->first + ((LINES-2) * view->bytes_per_line);
+
+ if (view->hex_mode && view->view_side == view_side_left) {
+ view->nib_shift = 1 - view->nib_shift;
+ if (view->nib_shift == 1)
+ return;
+ }
+ view->edit_cursor = (++view->edit_cursor < view->last_byte) ?
+ view->edit_cursor : view->last_byte - 1;
+ if (view->edit_cursor >= view->last) {
+ view->edit_cursor -= view->bytes_per_line;
+ view_move_forward(view, 1);
+ }
+ } else
+ if (--view->start_col > 0)
+ view->start_col = 0;
+ view->dirty++;
+}
+
+static void
+move_left (WView *view)
+{
+ if (view->wrap_mode && !view->hex_mode)
+ return;
+ if (view->hex_mode) {
+ if (view->hex_mode && view->view_side == view_side_left) {
+ view->nib_shift = 1 - view->nib_shift;
+ if (view->nib_shift == 0)
+ return;
+ }
+ view->edit_cursor = (--view->edit_cursor < view->first) ?
+ view->first : view->edit_cursor;
+ if (view->edit_cursor < view->start_display) {
+ view->edit_cursor += view->bytes_per_line;
+ view_move_backward(view, 1);
+ }
+ } else
+ if (++view->start_col > 0)
+ view->start_col = 0;
+ view->dirty++;
+}
+
+/* }}} */
+/* {{{ Search routines */
+
+/* Case insensitive search of text in data */
+static int
+icase_search_p (WView *view, char *text, char *data, int nothing)
+{
+ int p = 0, lng;
+ char *q;
+
+ p = (q = _icase_search (text, data, &lng)) != 0;
+ if (p) {
+ view->found_len = lng;
+ view->search_start = q - data - view->found_len;
+ }
+ return p;
+}
+
+static char *
+grow_string_buffer (char *text, int *size)
+{
+ char *new;
+ int old_size = *size;
+
+ /* The grow steps */
+ *size += 160;
+ new = xmalloc (*size, "grow_string_buffer");
+ if (text){
+ strncpy (new, text, old_size);
+ free (text);
+ } else {
+ *new = 0;
+ }
+ return new;
+}
+
+static char *
+get_line_at (WView *view, long *p)
+{
+ char *buffer = 0;
+ int buffer_size, usable_size;
+ int ch;
+ int direction;
+ long pos = *p;
+ long i;
+
+ direction = view->direction;
+ buffer_size = usable_size = 0;
+
+ i = ch = 0;
+ for (;pos >= 0 && (ch = get_byte (view, pos))!= -1; pos += direction, i++){
+
+ /* skip over all the possible zeros in the file */
+ if (ch == 0 && i == 0){
+ while (pos >= 0 && ((ch = get_byte (view, pos)) != -1) && ch == 0)
+ pos+= direction;
+ if (ch == -1)
+ break;
+ }
+ if (i == usable_size){
+ buffer = grow_string_buffer (buffer, &buffer_size);
+ usable_size = buffer_size - 2;
+ buffer [0] = ' '; /* This makes possible strcpy of buffer */
+ }
+ buffer [i+1] = ch;
+ if (ch == '\n' || !ch || ch == -1){
+ pos += direction; i++;
+ break;
+ }
+ }
+ if (buffer){
+ i--;
+ buffer [0] = ' ';
+ buffer [i+1] = 0;
+
+ /* If we are searching backwards, reverse the string */
+ if (view->direction < 0)
+ reverse_string (buffer);
+ }
+
+ *p = pos;
+ return buffer;
+}
+
+/** Search status optmizations **/
+
+/* The number of bytes between percent increments */
+int update_steps;
+
+/* Last point where we updated the status */
+long update_activate;
+
+static void
+search_update_steps (WView *view)
+{
+ if (view->s.st_size)
+ update_steps = 40000;
+ else
+ update_steps = view->last_byte / 100;
+
+ /* Do not update the percent display but every 20 ks */
+ if (update_steps < 20000)
+ update_steps = 20000;
+}
+
+static void
+search (WView *view, char *text, int (*search)(WView *, char *, char *, int))
+{
+ int w = view->widget.cols - (view->have_frame * 2);
+ char *s = NULL; /* The line we read from the view buffer */
+ long p, beginning;
+ int ch;
+ int isatbeg; /* Nonzero means we start search at beginning of some line */
+ int found_len, search_start;
+ Dlg_head *d = 0;
+ int search_status;
+
+ /* Used to keep track of where the line starts, when looking forward */
+ /* is the index before transfering the line; the reverse case uses */
+ /* the position returned after the line has been read */
+ long forward_line_start;
+ long reverse_line_start;
+ long t;
+ /* Clear interrupt status */
+ got_interrupt ();
+
+ if (verbose){
+ d = message (D_INSERT, _(" Search "), _("Searching %s"), text);
+ mc_refresh ();
+ }
+ ch = 0;
+ if (view->direction == 1){
+ p = view->found_len ? view->search_start + 1 : view->search_start;
+ } else {
+ p = (view->found_len ? view->search_start : view->last) - 1;
+ }
+ beginning = p;
+
+ isatbeg = view->found_len == 0;
+ found_len = view->found_len;
+ search_start = view->search_start;
+
+ /* Compute the percent steps */
+ search_update_steps (view);
+ update_activate = 0;
+
+ for (; ; isatbeg = 1, free (s)){
+#ifdef PORT_HAS_FLUSH_EVENTS
+ static int count;
+
+ if ((count++ % 32) == 0)
+ x_flush_events ();
+ if (!d->running)
+ break;
+#endif
+ if (p >= update_activate){
+ update_activate += update_steps;
+ if (verbose){
+ view_percent (view, p, w);
+ mc_refresh ();
+ }
+ if (got_interrupt ())
+ break;
+ }
+ forward_line_start = p;
+ disable_interrupt_key ();
+ s = get_line_at (view, &p);
+ reverse_line_start = p;
+ enable_interrupt_key ();
+ if (!s)
+ break;
+
+ search_status = (*search) (view, text, s + 1, match_normal);
+ if (search_status < 0)
+ break;
+
+ if (search_status == 0)
+ continue;
+
+ /* We found the string */
+
+ if (!isatbeg && !view->search_start){
+
+ /* We do not want to match a
+ * ^ regexp when not at the real
+ * beginning of some line
+ */
+ view->found_len = found_len;
+ view->search_start = search_start;
+ if ((*search) (view, text, s, match_normal) <= 0)
+ continue;
+ (*search) (view, text, s + 1, match_normal);
+ }
+ /* Record the position used to continue the search */
+ if (view->direction == 1)
+ t = forward_line_start;
+ else
+ t = reverse_line_start ? reverse_line_start + 3 : 0;
+ view->search_start += t;
+
+ if (t != beginning){
+ if (t > get_bottom_first (view, 0, 0))
+ view->start_display = view->bottom_first;
+ else
+ view->start_display = t;
+ }
+
+ free (s);
+ break;
+ }
+ disable_interrupt_key ();
+ if (verbose){
+ dlg_run_done (d);
+ destroy_dlg (d);
+ }
+
+ if (!s){
+ message (0, _(" Search "), _(" Search string not found "));
+ view->found_len = 0;
+ }
+}
+
+/* Search buffer (it's size is len) in the complete buffer */
+/* returns the position where the block was found or -1 if not found */
+static long
+block_search (WView *view, char *buffer, int len)
+{
+ int w = view->widget.cols - (view->have_frame * 2);
+ char *d = buffer, b;
+ long e;
+
+ /* clear interrupt status */
+ got_interrupt ();
+ enable_interrupt_key ();
+ e = view->found_len ? view->search_start + 1 : view->search_start;
+
+ search_update_steps (view);
+ update_activate = 0;
+
+ for (; e < view->last_byte; e++){
+ if (e >= update_activate){
+ update_activate += update_steps;
+ if (verbose){
+ view_percent (view, e, w);
+ mc_refresh ();
+ }
+ if (got_interrupt ())
+ break;
+ }
+ b = get_byte (view, e);
+
+ if (*d == b){
+ d++;
+ } else {
+ e -= d - buffer;
+ d = buffer;
+ }
+ if (d - buffer == len){
+ disable_interrupt_key ();
+ return e - len;
+ }
+ }
+ disable_interrupt_key ();
+ return -1;
+}
+
+/* States of our funny recognizer */
+enum {
+ normal,
+ inside_quotes,
+ zero,
+ hex1,
+ hex2,
+ oct1
+};
+
+/* This routine doesn't report all the user mistakes, it just ignores them */
+static void
+hex_search (WView *view, char *text)
+{
+ char buffer [120]; /* Where we hold the information */
+ int i, block_len;
+ int v = 0;
+ long pos; /* Where did we found the string */
+ char *p; /* Temporary */
+ int state = normal; /* Initial state of the micro-scanner */
+
+ /* First convert the string to a stream of bytes */
+ for (i = block_len = 0; text [i] && block_len < sizeof (buffer); i++){
+ switch (state){
+ case inside_quotes:
+ if (text [i] == '"')
+ state = normal;
+ else
+ buffer [block_len++] = text [i];
+ break;
+
+ case normal:
+ if (text [i] == '"'){
+ state = inside_quotes;
+ break;
+ }
+ if (text [i] == '0'){
+ state = zero;
+ break;
+ }
+ if (text [i] == 'x'){
+ state = hex1;
+ break;
+ }
+ break;
+
+ case zero:
+ if (text [i] == 'x')
+ state = hex1;
+ break;
+
+ case hex1:
+ v = 0;
+ text [i] = toupper (text [i]);
+ if ((p = strchr (hex_char, text [i])) != 0){
+ v = (p - hex_char) << 4;
+ state = hex2;
+ }
+ break;
+
+ case hex2:
+ text [i] = toupper (text [i]);
+ if ((p = strchr (hex_char, text [i])) != 0){
+ v |= (p - hex_char);
+ state = normal;
+ }
+ buffer [block_len++] = v;
+ break;
+ }
+ }
+ /* Then start the search */
+ pos = block_search (view, buffer, block_len);
+ if (pos == -1){
+ message (0, _(" Search "), _(" Search string not found "));
+ view->found_len = 0;
+ return;
+ }
+
+ view->search_start = pos + 1;
+ view->found_len = block_len;
+ /* Set the edit cursor to the search position, left nibble */
+ view->edit_cursor = view->search_start;
+ view->nib_shift = 0;
+
+ /* Adjust the file offset */
+ view->start_display = (pos & (~(view->bytes_per_line-1)));
+ if (view->start_display > get_bottom_first (view, 0, 0))
+ view->start_display = view->bottom_first;
+}
+
+static int regexp_view_search (WView *view, char *pattern, char *string, int match_type)
+{
+ static regex_t r;
+ static char *old_pattern = NULL;
+ static int old_type;
+ regmatch_t pmatch[1];
+ int i, flags = REG_ICASE;
+
+ if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type){
+ if (old_pattern){
+ regfree (&r);
+ free (old_pattern);
+ old_pattern = 0;
+ }
+ for (i = 0; pattern[i] != 0; i++){
+ if (isupper ((unsigned char) pattern[i])){
+ flags = 0;
+ break;
+ }
+ }
+ flags |= REG_EXTENDED;
+ if (regcomp (&r, pattern, flags)){
+ message (1, MSG_ERROR, _(" Invalid regular expression "));
+ return -1;
+ }
+ old_pattern = strdup (pattern);
+ old_type = match_type;
+ }
+ if (regexec (&r, string, 1, pmatch, 0) != 0)
+ return 0;
+ view->found_len = pmatch[0].rm_eo - pmatch[0].rm_so;
+ view->search_start = pmatch[0].rm_so;
+ return 1;
+}
+
+static void do_regexp_search (void *xview, char *regexp)
+{
+ WView *view = (WView *) xview;
+
+ view->search_exp = regexp;
+ search (view, regexp, regexp_view_search);
+ /* Had a refresh here */
+ view->dirty++;
+ view_update (view);
+}
+
+static void do_normal_search (void *xview, char *text)
+{
+ WView *view = (WView *) xview;
+
+ view->search_exp = text;
+ if (view->hex_mode)
+ hex_search (view, text);
+ else
+ search (view, text, icase_search_p);
+ /* Had a refresh here */
+ view->dirty++;
+ view_update (view);
+}
+
+/* }}} */
+/* {{{ Mouse and keyboard handling */
+
+/* Real view only */
+static void help_cmd (void)
+{
+ char *hlpfile = concat_dir_and_file (mc_home, "mc.hlp");
+ interactive_display (hlpfile, "[Internal File Viewer]");
+ free (hlpfile);
+ /*
+ view_refresh (0);
+ */
+}
+
+/* Both views */
+void toggle_wrap_mode (WView *view)
+{
+ if (view->hex_mode) {
+ if (view->growing_buffer != 0) {
+ return;
+ }
+ get_bottom_first (view, 1, 1);
+ if (view->hexedit_mode) {
+ view->view_side = 1 - view->view_side;
+ } else {
+ view->hexedit_mode = 1 - view->hexedit_mode;
+ }
+ view_labels (view);
+ view->dirty++;
+ view_update (view);
+ return;
+ }
+ view->wrap_mode = 1 - view->wrap_mode;
+ get_bottom_first (view, 1, 1);
+ if (view->wrap_mode)
+ view->start_col = 0;
+ else {
+ if (have_fast_cpu){
+ if (view->bottom_first < view->start_display)
+ view->search_start = view->start_display = view->bottom_first;
+ view->found_len = 0;
+ }
+ }
+ view_labels (view);
+ view->dirty++;
+ view_update (view);
+}
+
+/* Both views */
+void
+toggle_hex_mode (WView *view)
+{
+ view->hex_mode = 1 - view->hex_mode;
+
+ if (view->hex_mode){
+ /* Shift the line start to 0x____0 on entry, restore it for Ascii */
+ view->start_save = view->start_display;
+ view->start_display -= view->start_display % view->bytes_per_line;
+ view->edit_cursor = view->start_display;
+ view->widget.options |= W_WANT_CURSOR;
+ view->widget.parent->raw = 1;
+ } else {
+ view->start_display = view->start_save;
+ view->widget.parent->raw = 0;
+ view->widget.options &= ~W_WANT_CURSOR;
+ }
+ altered_hex_mode = 1;
+ get_bottom_first (view, 1, 1);
+ view_labels (view);
+ view->dirty++;
+ view_update (view);
+}
+
+/* Both views */
+void
+toggle_hexedit_mode(WView *view)
+{
+ view->hexedit_mode = 1 - view->hexedit_mode;
+}
+
+/* Both views */
+void
+goto_line (WView *view)
+{
+ char *line, prompt [100];
+ int i, oldline = 1;
+ int saved_wrap_mode = view->wrap_mode;
+
+ view->wrap_mode = 0;
+ for (i = view->first; i < view->start_display; i++)
+ if (get_byte (view, i) == '\n')
+ oldline ++;
+ sprintf (prompt, _(" The current line number is %d.\n"
+ " Enter the new line number:"), oldline);
+ line = input_dialog (_(" Goto line "), prompt, "");
+ if (line){
+ if (*line){
+ move_to_top (view);
+ view_move_forward (view, atoi (line) - 1);
+ }
+ free (line);
+ }
+ view->dirty++;
+ view->wrap_mode = saved_wrap_mode;
+ view_update (view);
+}
+
+/* Both views */
+void
+regexp_search (WView *view, int direction)
+{
+ char *regexp = "";
+ static char *old = 0;
+
+ /* This is really an F6 key handler */
+ if (view->hex_mode){
+ /* Save it without a confirmation prompt */
+ save_edit_changes(view);
+ return;
+ }
+
+ regexp = old ? old : regexp;
+ regexp = input_dialog (_(" Search "), _(" Enter regexp:"), regexp);
+ if ((!regexp) || (!*regexp)){
+ return;
+ }
+ if (old)
+ free (old);
+ old = regexp;
+#if 0
+ /* Mhm, do we really need to load all the file in the core? */
+ if (view->bytes_read < view->last_byte)
+ get_byte (view, view->last_byte-1);/* Get the whole file in to memory */
+#endif
+ view->direction = direction;
+ do_regexp_search (view, regexp);
+
+ view->last_search = do_regexp_search;
+}
+
+void
+regexp_search_cmd (WView *view)
+{
+ regexp_search (view, 1);
+}
+
+/* Both views */
+void
+normal_search (WView *view, int direction)
+{
+ static char *old;
+ char *exp = "";
+
+ exp = old ? old : exp;
+ exp = input_dialog (_(" Search "), _(" Enter search string:"), exp);
+ if ((!exp) || (!*exp)){
+ return;
+ }
+ if (old)
+ free (old);
+ old = exp;
+
+ view->direction = direction;
+ do_normal_search (view, exp);
+ view->last_search = do_normal_search;
+}
+
+void
+normal_search_cmd (WView *view)
+{
+ normal_search (view, 1);
+}
+
+void
+change_viewer (WView *view)
+{
+ char *s;
+ char *t;
+
+
+ if (*view->filename) {
+ altered_magic_flag = 1;
+ view->viewer_magic_flag = !view->viewer_magic_flag;
+ s = strdup (view->filename);
+ if (view->command)
+ t = strdup (view->command);
+ else
+ t = 0;
+
+ view_done (view);
+ view_init (view, t, s, 0);
+ free (s);
+ if (t)
+ free (t);
+ view_labels (view);
+ view->dirty++;
+ view_update (view);
+ }
+}
+
+void
+change_nroff (WView *view)
+{
+ view->viewer_nroff_flag = !view->viewer_nroff_flag;
+ altered_nroff_flag = 1;
+ view_labels (view);
+ view->dirty++;
+ view_update (view);
+}
+
+/* Real view only */
+static void
+view_quit_cmd (WView *view)
+{
+ if (view_ok_to_quit (view))
+ dlg_stop (view->widget.parent);
+}
+
+/* Both views */
+void
+view_labels (WView *view)
+{
+ Dlg_head *h = view->widget.parent;
+
+ define_label (h, (Widget *) view, 1, _("Help"), help_cmd);
+
+ my_define (h, 10, _("Quit"), view_quit_cmd, view);
+ my_define (h, 4, view->hex_mode ? _("Ascii"): _("Hex"), toggle_hex_mode, view);
+ my_define (h, 5, _("Line"), goto_line, view);
+ my_define (h, 6, view->hex_mode ? _("Save") : _("RxSrch"), regexp_search_cmd, view);
+
+ my_define (h, 2, view->hex_mode ? view->hexedit_mode ?
+ view->view_side == view_side_left ? _("EdText") : _("EdHex") :
+ view->growing_buffer ? "" : _("Edit") :
+ view->wrap_mode ? _("UnWrap") : _("Wrap"),
+ toggle_wrap_mode, view);
+
+ my_define (h, 7, view->hex_mode ? _("HxSrch") : _("Search"),
+ normal_search_cmd, view);
+
+ my_define (h, 8, view->viewer_magic_flag ? _("Raw") : _("Parse"),
+ change_viewer, view);
+
+ if (!view->have_frame){
+ my_define (h, 9, view->viewer_nroff_flag ? _("Unform") : _("Format"),
+ change_nroff, view);
+ my_define (h, 3, _("Quit"), view_quit_cmd, view);
+ }
+
+ redraw_labels (h, (Widget *) view);
+}
+
+/* Both views */
+static int
+check_left_right_keys (WView *view, int c)
+{
+ if (c == KEY_LEFT)
+ move_left (view);
+ else if (c == KEY_RIGHT)
+ move_right (view);
+ else return 0;
+
+ return 1;
+}
+
+void
+set_monitor (WView *view, int set_on)
+{
+ int old = view->monitor;
+
+ view->monitor = set_on;
+
+ if (view->monitor){
+ move_to_bottom (view);
+ view->bottom_first = -1;
+ set_idle_proc (view->widget.parent, 1);
+ } else {
+ if (old)
+ set_idle_proc (view->widget.parent, 0);
+ }
+}
+
+void
+continue_search (WView *view)
+{
+ if (view->last_search){
+ (*view->last_search)(view, view->search_exp);
+ } else {
+ /* if not... then ask for an expression */
+ normal_search (view, 1);
+ }
+}
+
+/* Both views */
+static int
+view_handle_key (WView *view, int c)
+{
+ int prev_monitor = view->monitor;
+
+ set_monitor (view, off);
+
+ if (view->hex_mode) {
+ switch (c) {
+ case 0x09: /* Tab key */
+ view->view_side = 1 - view->view_side;
+ view->dirty++;
+ return 1;
+
+ case XCTRL('a'): /* Beginning of line */
+ view->edit_cursor -= view->edit_cursor % view->bytes_per_line;
+ view->dirty++;
+ return 1;
+
+ case XCTRL('b'): /* Character back */
+ move_left(view);
+ return 1;
+
+ case XCTRL('e'): /* End of line */
+ view->edit_cursor -= view->edit_cursor % view->bytes_per_line;
+ view->edit_cursor += view->bytes_per_line - 1;
+ view->dirty++;
+ return 1;
+
+ case XCTRL('f'): /* Character forward */
+ move_right(view);
+ return 1;
+ }
+
+ /* Trap 0-9,A-F,a-f for left side data entry (hex editing) */
+ if (view->view_side == view_side_left){
+ if ((c >= '0' && c <= '9') ||
+ (c >= 'A' && c <= 'F') ||
+ (c >= 'a' && c <= 'f')){
+
+ put_editkey (view, c);
+ return 1;
+ }
+ }
+
+ /* Trap all printable characters for right side data entry */
+ /* Also enter the value of the Enter key */
+ if (view->view_side == view_side_right){
+ if (c < 256 && (is_printable (c) || (c == '\n'))){
+ put_editkey(view, c);
+ return 1;
+ }
+ }
+ }
+
+ if (check_left_right_keys (view, c))
+ return 1;
+
+ if (check_movement_keys (c, 1, vheight, view, (movefn) view_move_backward, (movefn) view_move_forward,
+ (movefn) move_to_top, (movefn) move_to_bottom)){
+ return 1;
+ }
+ switch (c){
+
+ case '?':
+ regexp_search (view, -1);
+ return 1;
+
+ case '/':
+ regexp_search (view, 1);
+ return 1;
+
+ /* Continue search */
+ case XCTRL('s'):
+ case 'n':
+ case KEY_F(17):
+ continue_search (view);
+ return 1;
+
+ case XCTRL('r'):
+ if (view->last_search){
+ (*view->last_search)(view, view->search_exp);
+ } else {
+ normal_search (view, -1);
+ }
+ return 1;
+
+ /* toggle ruler */
+ case ALT('r'):
+ switch (ruler){
+ case 0:
+ ruler = 1; break;
+ case 1:
+ ruler = 2; break;
+ default:
+ ruler = 0; break;
+ }
+ view->dirty++;
+ return 1;
+
+ case 'h':
+ move_left (view);
+ return 1;
+
+ case 'j':
+ case '\n':
+ case 'e':
+ view_move_forward (view, 1);
+ return 1;
+
+ case 'd':
+ view_move_forward (view, vheight / 2);
+ return 1;
+
+ case 'u':
+ view_move_backward (view, vheight / 2);
+ return 1;
+
+ case 'k':
+ case 'y':
+ view_move_backward (view, 1);
+ return 1;
+
+ case 'l':
+ move_right (view);
+ return 1;
+
+ case ' ':
+ case 'f':
+ view_move_forward (view, vheight - 1);
+ return 1;
+
+ case '!':
+ exec_shell ();
+ return 1;
+
+ case 'F':
+ set_monitor (view, on);
+ return 1;
+
+ case 'b':
+ view_move_backward (view, vheight - 1);
+ return 1;
+
+ case KEY_IC:
+ view_move_backward (view, 2);
+ return 1;
+
+ case KEY_DC:
+ view_move_forward (view, 2);
+ return 1;
+
+ case 'm':
+ view->marks [view->marker] = view->start_display;
+ return 1;
+
+ case 'r':
+ view->start_display = view->marks [view->marker];
+ view->dirty++;
+ return 1;
+
+ /* Use to indicate parent that we want to see the next/previous file */
+ /* Only works on full screen mode */
+ case XCTRL('f'):
+ case XCTRL('b'):
+ if (!view->have_frame)
+ view->move_dir = c == XCTRL('f') ? 1 : -1;
+ /* fall */
+
+ case 'q':
+ case XCTRL('g'):
+ case ESC_CHAR:
+ if (view_ok_to_quit (view))
+ view->view_quit = 1;
+ return 1;
+
+ }
+ if (c >= '0' && c <= '9')
+ view->marker = c - '0';
+
+ /* Restore the monitor status */
+ set_monitor (view, prev_monitor);
+
+ /* Key not used */
+ return 0;
+}
+
+/* Both views */
+int
+view_event (WView *view, Gpm_Event *event, int *result)
+{
+ *result = MOU_NORMAL;
+ if (event->type & (GPM_DOWN|GPM_DRAG)){
+ if (!view->wrap_mode){
+ if (event->x < view->widget.cols / 4){
+ move_left (view);
+ *result = MOU_REPEAT;
+ return 1;
+ }
+ if (event->x > 3 * vwidth / 4){
+ move_right (view);
+ *result = MOU_REPEAT;
+ return 1;
+ }
+ }
+ if (event->y < view->widget.lines / 3){
+ if (mouse_move_pages_viewer)
+ view_move_backward (view, view->widget.lines / 2 - 1);
+ else
+ view_move_backward (view, 1);
+ *result = MOU_REPEAT;
+ return 1;
+ }
+ else if (event->y > 2 * vheight /3){
+ if (mouse_move_pages_viewer)
+ view_move_forward (view, vheight / 2 - 1);
+ else
+ view_move_forward (view, 1);
+ *result = MOU_REPEAT;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* Real view only */
+int
+real_view_event (Gpm_Event *event, void *x)
+{
+ int result;
+
+ if (view_event ((WView *) x, event, &result))
+ view_update ((WView *) x);
+ return result;
+}
+
+/* }}} */
+/* {{{ Window creation, destruction and a driver stub for real view */
+
+static int
+view_mode_callback (struct Dlg_head *h, int id, int msg)
+{
+ return default_dlg_callback (h, id, msg);
+}
+
+#ifdef HAVE_XVIEW
+/* Real view only */
+
+void
+view_adjust_size (Dlg_head *unused)
+{
+}
+
+int
+view (char *_command, char *_file, int *move_dir_p, int start_line)
+{
+ int midnight_colors [4];
+ int error;
+ WView *wview;
+
+ wview = view_new (0, 0, COLS, LINES - 1, 0);
+
+ error = view_init (wview, _command, _file, start_line);
+ if (!error){
+ x_view (wview);
+ }
+ *move_dir_p = 0;
+ return !error;
+}
+#endif
+
+#ifndef PORT_WANTS_VIEW
+void
+view_adjust_size (Dlg_head *h)
+{
+ WView *view;
+ WButtonBar *bar;
+
+ /* Look up the viewer and the buttonbar, we assume only two widgets here */
+ view = (WView *) find_widget_type (h, (callback_fn) view_callback);
+ bar = (WButtonBar *) view->widget.parent->current->next->widget;
+ widget_set_size (&view->widget, 0, 0, LINES-1, COLS);
+ widget_set_size (&bar->widget, LINES-1, 0, 1, COLS);
+}
+
+/* Only the text mode edition uses this */
+Dlg_head *view_dlg;
+
+/* Real view only */
+int
+view (char *_command, char *_file, int *move_dir_p, int start_line)
+{
+ int midnight_colors [4];
+ int error;
+ WView *wview;
+ WButtonBar *bar;
+ Dlg_head *our_dlg;
+
+ /* Create dialog and widgets, put them on the dialog */
+ our_dlg = create_dlg (0, 0, LINES, COLS, midnight_colors,
+ view_mode_callback, "[Internal File Viewer]",
+ "view",
+ DLG_NONE);
+
+#ifndef HAVE_X
+ view_dlg = our_dlg;
+#endif
+ wview = view_new (0, 0, COLS, LINES-1, 0);
+
+ bar = buttonbar_new (1);
+
+ add_widget (our_dlg, wview);
+ add_widget (our_dlg, bar);
+
+ error = view_init (wview, _command, _file, start_line);
+ if (move_dir_p)
+ *move_dir_p = 0;
+
+ /* Please note that if you add another widget,
+ * you have to modify view_adjust_size to
+ * be aware of it
+ */
+ if (!error){
+ run_dlg (our_dlg);
+ if (move_dir_p)
+ *move_dir_p = wview->move_dir;
+ }
+ destroy_dlg (our_dlg);
+
+ return !error;
+}
+#endif
+
+static void
+view_hook (void *v)
+{
+ WView *view = (WView *) v;
+ WPanel *panel;
+ struct stat s;
+
+ /* If the user is busy typing, wait until he finishes to update the
+ screen */
+ if (!is_idle ()){
+ if (!hook_present (idle_hook, view_hook))
+ add_hook (&idle_hook, view_hook, v);
+ return;
+ }
+
+ delete_hook (&idle_hook, view_hook);
+
+ if (get_current_type () == view_listing)
+ panel = cpanel;
+ else if (get_other_type () == view_listing)
+ panel = other_panel;
+ else
+ return;
+
+ if (S_ISLNK (panel->dir.list [panel->selected].buf.st_mode)){
+ if (mc_stat (panel->dir.list [panel->selected].fname, &s) != 0)
+ return;
+ if (!S_ISREG (s.st_mode))
+ return;
+ } else {
+ if (!S_ISREG (panel->dir.list [panel->selected].buf.st_mode))
+ return;
+ }
+
+ view_init (view, 0, panel->dir.list [panel->selected].fname, 0);
+ display (view);
+ view_status (view);
+}
+
+static int
+view_callback (Dlg_head *h, WView *v, int msg, int par)
+{
+ WView *view = (WView *) v;
+ int i;
+
+ switch (msg){
+ case WIDGET_INIT:
+ x_create_viewer (view);
+ if (view->have_frame)
+ add_hook (&select_file_hook, view_hook, view);
+ else
+ view_labels (view);
+ break;
+
+ case WIDGET_DRAW:
+ display (view);
+ view_status (view);
+ break;
+
+ case WIDGET_CURSOR:
+ if (view->hex_mode)
+ view_place_cursor (view);
+ break;
+
+ case WIDGET_KEY:
+ i = view_handle_key ((WView *)view, par);
+ if (view->view_quit)
+ dlg_stop (h);
+ else {
+ view_update (view);
+ }
+ return i;
+
+ case WIDGET_IDLE:
+ /* This event is generated when the user is using the 'F' flag */
+ view->bottom_first = -1;
+ move_to_bottom (view);
+ display (view);
+ view_status (view);
+ sleep (1);
+ return 1;
+
+ case WIDGET_FOCUS:
+ x_focus_view (view);
+ view_labels (view);
+ return 1;
+
+ }
+ return default_proc (h, msg, par);
+}
+
+WView *
+view_new (int y, int x, int cols, int lines, int is_panel)
+{
+ WView *view = xmalloc (sizeof (WView), "view_new");
+
+ init_widget (&view->widget, y, x, lines, cols,
+ (callback_fn) view_callback,
+ (destroy_fn) view_destroy,
+ (mouse_h) real_view_event, NULL);
+
+ view->filename = 0;
+ view->view_active = 0;
+ view->bottom_first = 0;
+ view->start_col = 0;
+ view->dirty = 0;
+ view->hex_mode = default_hex_mode;
+ view->hexedit_mode = default_hexedit_mode;
+ view->viewer_magic_flag = default_magic_flag;
+ view->viewer_nroff_flag = default_nroff_flag;
+ view->view_quit = 0;
+ view->move_dir = 0;
+ view->have_frame = is_panel;
+ view->last_byte = -1;
+ view->monitor = 0;
+ view->wrap_mode = global_wrap_mode;
+
+ x_init_view (view);
+
+ widget_want_cursor (view->widget, 0);
+
+ return view;
+}
+
+/* }}} */
+/* {{{ Emacs local variables */
+/*
+ Cause emacs to enter folding mode for this file:
+ Local variables:
+ end:
+ */
+/* }}} */
--- /dev/null
+#ifndef __VIEW_H
+#define __VIEW_H
+
+#ifdef WANT_WIDGETS
+/* The growing buffers data types */
+typedef struct {
+ unsigned char *data;
+ int present; /* Unused, for DOS port maybe */
+} block_ptr_t;
+
+enum ViewSide {
+ view_side_left,
+ view_side_right
+};
+
+typedef struct {
+ Widget widget;
+
+ char *filename; /* Name of the file */
+ char *command; /* Command used to pipe data in */
+ char *localcopy;
+ int view_active;
+ int have_frame;
+
+ unsigned char *data; /* Memory area for the file to be viewed */
+
+ /* File information */
+ int file; /* File descriptor (for mmap and munmap) */
+ FILE *stdfile; /* Stdio struct for reading file in parts */
+ int reading_pipe; /* Flag: Reading from pipe(use popen/pclose) */
+ long bytes_read; /* How much of file is read */
+ int mmapping; /* Did we use mmap on the file? */
+
+ /* Display information */
+ long last; /* Last byte shown */
+ long last_byte; /* Last byte of file */
+ long first; /* First byte in file */
+ long bottom_first; /* First byte shown when very last page is displayed */
+ /* For the case of WINCH we should reset it to -1 */
+ long start_display; /* First char displayed */
+ int start_col; /* First displayed column, negative */
+ int edit_cursor; /* HexEdit cursor position in file */
+ char hexedit_mode; /* Hexidecimal editing mode flag */
+ char nib_shift; /* A flag for inserting nibbles into bytes */
+ enum ViewSide view_side; /* A flag for the active editing panel */
+ int file_dirty; /* Number of changes */
+ int start_save; /* Line start shift between Ascii and Hex */
+ int cursor_col; /* Cursor column */
+ int cursor_row; /* Cursor row */
+ struct hexedit_change_node *change_list; /* Linked list of changes */
+
+ int dirty; /* Number of skipped updates */
+ int wrap_mode; /* wrap_mode */
+
+ /* Mode variables */
+ int hex_mode; /* Hexadecimal mode flag */
+ int bytes_per_line; /* Number of bytes per line in hex mode */
+ int viewer_magic_flag; /* Selected viewer */
+ int viewer_nroff_flag; /* Do we do nroff style highlighting? */
+
+ /* Growing buffers information */
+ int growing_buffer; /* Use the growing buffers? */
+ block_ptr_t *block_ptr; /* Pointer to the block pointers */
+ int blocks; /* The number of blocks in *block_ptr */
+
+
+ /* Search variables */
+ int search_start; /* First character to start searching from */
+ int found_len; /* Length of found string or 0 if none was found */
+ char *search_exp; /* The search expression */
+ int direction; /* 1= forward; -1 backward */
+ void (*last_search)(void *, char *);
+ /* Pointer to the last search command */
+ int view_quit; /* Quit flag */
+
+ int monitor; /* Monitor file growth (like tail -f) */
+ /* Markers */
+ int marker; /* mark to use */
+ int marks [10]; /* 10 marks: 0..9 */
+
+#ifdef HAVE_TK
+ /* Tk version, line cache */
+ int current_line; /* The current screen line cached */
+ char *cache; /* Current cache */
+ char *color_cache; /* Attributes: keep in sync with cache */
+ int dest; /* Index in the cache to write to */
+ int cache_len; /* Length of the cache buffer -1 */
+ int last_col; /* last column used */
+ int status_shown; /* Have we show the file information? */
+#endif
+
+#ifdef HAVE_GNOME
+ int current_x, current_y; /* Current x,y position */
+ int color; /* Current color */
+ void *gtk_fname; /* filename widget */
+ void *gtk_offset; /* offset widget */
+ void *gtk_bytes; /* bytes */
+ void *gtk_flags; /* flags (growing) */
+ void *gtk_percent; /* percent */
+ void *sadj; /* scrollbar adjustment */
+#endif
+
+ int move_dir; /* return value from widget:
+ * 0 do nothing
+ * -1 view previous file
+ * 1 view next file
+ */
+ struct stat s; /* stat for file */
+} WView;
+
+#define vwidth (view->widget.cols - (view->have_frame ? 2 : 0))
+#define vheight (view->widget.lines - (view->have_frame ? 2 : 0))
+
+/* Creation/initialization of a new view widget */
+WView *view_new (int y, int x, int cols, int lines, int is_panel);
+int view_init (WView *view, char *_command, char *_file, int start_line);
+int view_file (char *filename, int normal, int internal);
+
+/* Internal view routines */
+void view_status (WView *);
+void view_percent (WView *, int, int);
+void view_update (WView *view);
+void view_labels (WView *view);
+int view_event (WView *view, Gpm_Event *event,int *result);
+void toggle_wrap_mode (WView *);
+void toggle_hex_mode (WView *);
+void goto_line (WView *);
+void regexp_search_cmd (WView *);
+void normal_search_cmd (WView *);
+void continue_search (WView *);
+void change_nroff (WView *view);
+void set_monitor (WView *view, int set_on);
+void view_move_forward (WView *view, int i);
+void view_move_backward (WView *view, int i);
+#endif
+
+/* Command: view a file, if _command != NULL we use popen on _command */
+/* move direction should be apointer that will hold the direction in which the user */
+/* wants to move (-1 previous file, 1 next file, 0 do nothing) */
+int view (char *_command, char *_file, int *move_direction, int start_line);
+
+extern int mouse_move_pages_viewer;
+extern int max_dirt_limit;
+extern int global_wrap_mode;
+extern int have_fast_cpu;
+extern int default_hex_mode;
+extern int default_magic_flag;
+extern int default_nroff_flag;
+extern int altered_hex_mode;
+extern int altered_magic_flag;
+extern int altered_nroff_flag;
+
+void view_adjust_size ();
+
+/* A node for building a change list on change_list */
+struct hexedit_change_node {
+ struct hexedit_change_node *next;
+ long offset;
+ unsigned char value;
+};
+
+#ifdef HAVE_TK
+#define DEF_COLOR 0
+#define BOLD_COLOR 1
+#define UNDERLINE_COLOR 2
+#define MARK_COLOR 3
+#endif
+
+#ifdef HAVE_X
+#ifdef WANT_WIDGETS
+void view_add_character (WView *view, int c);
+void view_add_string (WView *view, char *s);
+void view_gotoyx (WView *view, int r, int c);
+void view_set_color (WView *view, int font);
+void view_display_clean (WView *view, int h, int w);
+
+void x_destroy_view (WView *);
+void x_create_viewer (WView *);
+void x_focus_view (WView *);
+void x_init_view (WView *);
+
+#ifdef PORT_HAS_VIEW_FREEZE
+void view_freeze (WView *view);
+void view_thaw (WView *view);
+#endif
+
+#endif
+#else
+# define x_init_view(x)
+# define x_destroy_view(x)
+# define x_create_viewer(x)
+# define x_focus_view(x)
+#endif
+
+#endif /* __VIEW_H */
--- /dev/null
+/* Widgets for the Midnight Commander
+
+ Copyright (C) 1994, 1995, 1996 the Free Software Foundation
+
+ Authors: 1994, 1995 Radek Doulik
+ 1994, 1995 Miguel de Icaza
+ 1995 Jakub Jelinek
+ 1996 Andrej Borsenkow
+ 1997 Norbert Warmuth
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+/* "$Id: widget.c,v 1.1 2001/12/30 09:55:20 sedwards Exp $" */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "tty.h"
+#include <ctype.h>
+#include "mad.h"
+#include "global.h"
+#include "util.h"
+#include "color.h"
+#include "mouse.h"
+#include "dlg.h"
+#include "widget.h"
+#include "win.h"
+#include "complete.h"
+#include "key.h" /* XCTRL and ALT macros */
+#include "x.h"
+#include "profile.h" /* for history loading and saving */
+
+#ifndef HAVE_X
+# define x_create_button(a,b,c) 1
+# define x_create_radio(a,b,c) 1
+# define x_create_check(a,b,c) 1
+# define x_create_label(a,b,c) 1
+# define x_create_input(a,b,c) 1
+# define x_create_listbox(a,b,c) 1
+# define x_create_buttonbar(a,b,c) 1
+# define x_create_gauge(a,b,c) 1
+# define x_listbox_select_nth(a,b)
+# define x_list_insert(a,b,c)
+# define x_redefine_label(a,b)
+#endif
+
+#ifndef PORT_HAS_DESTROY_CMD
+# define x_destroy_cmd(w)
+#endif
+
+#ifndef PORT_HAS_RADIO_FOCUS_ITEM
+# define x_radio_focus_item(r)
+#endif
+
+#ifndef PORT_HAS_RADIO_TOGGLE
+# define x_radio_toggle
+#endif
+
+static int button_event (Gpm_Event *event, WButton *b);
+
+int quote = 0;
+
+static int
+button_callback (Dlg_head *h, WButton *b, int Msg, int Par)
+{
+ char *txt, buf[256];
+ int stop = 0;
+ int off = 0;
+
+ switch (Msg){
+ case WIDGET_INIT:
+ return x_create_button (h, h->wdata, b);
+#ifndef HAVE_XVIEW
+ case WIDGET_HOTKEY:
+ if (b->hotkey == Par || toupper(b->hotkey) == Par){
+ button_callback (h, b, WIDGET_KEY, ' '); /* to make action */
+ return 1;
+ } else
+ return 0;
+
+ case WIDGET_KEY:
+ if (Par != ' ' && Par != '\n')
+ break;
+
+ if (b->callback)
+ stop = (*b->callback)(b->action, b->callback_data);
+ if (!b->callback || stop){
+ h->ret_value = b->action;
+ dlg_stop (h);
+ }
+ return 1;
+
+#ifdef HAVE_TK
+ case WIDGET_FOCUS:
+ case WIDGET_CURSOR:
+ {
+ char *s = b->action == B_ENTER ? ".button" : "";
+
+ tk_evalf ("focus %s%s", (char *)(b->widget.wdata)+1, s);
+ /* Do not call default_proc: we did the tk focus command */
+ return 1;
+ }
+#else
+
+ case WIDGET_CURSOR:
+ switch (b->flags) {
+ case DEFPUSH_BUTTON:
+ off = 3;
+ break;
+ case NORMAL_BUTTON:
+ off = 2;
+ break;
+ case NARROW_BUTTON:
+ off = 1;
+ break;
+ case HIDDEN_BUTTON:
+ default:
+ off = 0;
+ break;
+ }
+ widget_move (&b->widget, 0, b->hotpos + off);
+ return 1;
+
+ case WIDGET_UNFOCUS:
+ case WIDGET_FOCUS:
+ case WIDGET_DRAW:
+ if (Msg==WIDGET_UNFOCUS)
+ b->selected = 0;
+ else if (Msg==WIDGET_FOCUS)
+ b->selected = 1;
+
+ switch (b->flags){
+ case DEFPUSH_BUTTON:
+ sprintf (buf, "[< %s >]", b->text);
+ off = 3;
+ break;
+ case NORMAL_BUTTON:
+ sprintf (buf, "[ %s ]", b->text);
+ off = 2;
+ break;
+ case NARROW_BUTTON:
+ sprintf (buf, "[%s]", b->text);
+ off = 1;
+ break;
+ case HIDDEN_BUTTON:
+ default:
+ buf[0] = '\0';
+ off = 0;
+ break;
+ }
+ txt = buf;
+
+ attrset ((b->selected) ? FOCUSC : NORMALC);
+ widget_move (&b->widget, 0, 0);
+
+ addstr (txt);
+
+ if (b->hotpos >= 0){
+ attrset ((b->selected) ? HOT_FOCUSC : HOT_NORMALC);
+ widget_move (&b->widget, 0, b->hotpos+off);
+ addch ((unsigned char)b->text [b->hotpos]);
+ }
+ if (Msg == WIDGET_FOCUS)
+ break;
+ else
+ return 1;
+ break;
+#endif
+#endif /* !HAVE_XVIEW */
+ }
+ return default_proc (h, Msg, Par);
+}
+
+static int
+button_event (Gpm_Event *event, WButton *b)
+{
+#ifndef HAVE_X
+ if (event->type & (GPM_DOWN|GPM_UP)){
+ Dlg_head *h=b->widget.parent;
+ dlg_select_widget (h, b);
+ if (event->type & GPM_UP){
+ button_callback (h, b, WIDGET_KEY, ' ');
+ (*h->callback) (h, ' ', DLG_POST_KEY);
+ return MOU_NORMAL;
+ }
+ }
+#endif
+ return MOU_NORMAL;
+}
+
+static void
+button_destroy (WButton *b)
+{
+ x_destroy_cmd (b);
+ free (b->text);
+}
+
+static int
+button_len (const char *text, unsigned int flags)
+{
+#ifndef HAVE_X
+ int ret = strlen (text);
+ switch (flags){
+ case DEFPUSH_BUTTON:
+ ret += 6;
+ break;
+ case NORMAL_BUTTON:
+ ret += 4;
+ break;
+ case NARROW_BUTTON:
+ ret += 2;
+ break;
+ case HIDDEN_BUTTON:
+ default:
+ return 0;
+ }
+ return ret;
+#else
+ return strlen (text);
+#endif
+}
+
+/*
+ * Assuming that button text is malloc'ed, we may safely change it
+ * (as opposed to statically allocated); from other hand, excluding &
+ * and shifting data past it to the left results to one unused byte.
+ * This does not harm though :)
+ */
+void
+button_scan_hotkey(WButton* b)
+{
+ char* cp = strchr (b->text, '&');
+
+ if (cp != NULL && cp[1] != '\0'){
+ strcpy (cp, cp+1);
+ b->hotkey = tolower (*cp);
+ b->hotpos = cp - b->text;
+ }
+}
+
+WButton *
+button_new (int y, int x, int action, int flags, char *text,
+ int (*callback)(int, void *), void *callback_data, char *tkname)
+{
+ WButton *b = xmalloc (sizeof (WButton), "new_button");
+
+ init_widget (&b->widget, y, x, 1, button_len (text, flags),
+ (callback_fn) button_callback,
+ (destroy_fn) button_destroy, (mouse_h)button_event, tkname);
+
+ b->action = action;
+ b->flags = flags;
+ b->selected = 0;
+ b->text = strdup (text);
+ b->callback = callback;
+ b->callback_data = callback_data;
+ widget_want_hotkey (b->widget, 1);
+ b->hotkey = 0;
+ b->hotpos = -1;
+
+ button_scan_hotkey(b);
+ return b;
+}
+
+void
+button_set_text (WButton *b, char *text)
+{
+ free (b->text);
+ b->text = strdup (text);
+ b->widget.cols = button_len (text, b->flags);
+ button_scan_hotkey(b);
+#ifdef HAVE_X
+ x_button_set (b, b->text);
+#else
+ dlg_redraw (b->widget.parent);
+#endif
+}
+
+\f
+/* Radio button widget */
+static int radio_event (Gpm_Event *event, WRadio *r);
+
+static int
+radio_callback (Dlg_head *h, WRadio *r, int Msg, int Par)
+{
+ int i;
+
+ switch (Msg) {
+ case WIDGET_INIT:
+ return x_create_radio (h, h->wdata, r);
+
+#ifndef HAVE_XVIEW
+ case WIDGET_HOTKEY:
+ {
+ int i, lp = tolower(Par);
+ char *cp;
+
+ for (i = 0; i < r->count; i++){
+ cp = strchr (r->texts [i], '&');
+ if (cp != NULL && cp[1] != '\0'){
+ int c = tolower (cp [1]);
+
+ if (c != lp)
+ continue;
+ r->pos = i;
+ radio_callback (h, r, WIDGET_KEY, ' '); /* Take action */
+ return 1;
+ }
+ }
+ }
+ return 0;
+
+ case WIDGET_KEY:
+ switch (Par){
+ case ' ':
+ r->sel = r->pos;
+ (*h->callback) (h, h->current->dlg_id, DLG_ACTION);
+ radio_callback (h, r, WIDGET_FOCUS, ' ');
+ x_radio_toggle (r);
+ return 1;
+
+ case KEY_UP:
+ case KEY_LEFT:
+ if (r->pos > 0){
+ r->pos--;
+ x_radio_focus_item (r);
+ return 1;
+ }
+ return 0;
+
+ case KEY_DOWN:
+ case KEY_RIGHT:
+ if (r->count - 1 > r->pos) {
+ r->pos++;
+ x_radio_focus_item (r);
+ return 1;
+ }
+ }
+ return 0;
+
+#ifdef HAVE_X
+ case WIDGET_FOCUS:
+ case WIDGET_CURSOR:
+ x_radio_focus_item (r);
+ return 1;
+#endif
+#endif
+
+#ifndef HAVE_X
+ case WIDGET_CURSOR:
+ (*h->callback) (h, h->current->dlg_id, DLG_ACTION);
+ radio_callback (h, r, WIDGET_FOCUS, ' ');
+ widget_move (&r->widget, r->pos, 1);
+ break;
+
+ case WIDGET_UNFOCUS:
+ case WIDGET_FOCUS:
+ case WIDGET_DRAW:
+ for (i = 0; i < r->count; i++){
+ register unsigned char* cp;
+ attrset ((i==r->pos && Msg==WIDGET_FOCUS) ? FOCUSC :NORMALC);
+ widget_move (&r->widget, i, 0);
+
+ printw("(%c) ", (r->sel == i) ? '*' : ' ');
+ for (cp = r->texts[i]; *cp; cp++)
+ {
+ if (*cp == '&')
+ {
+ attrset ((i==r->pos && Msg==WIDGET_FOCUS)
+ ? HOT_FOCUSC : HOT_NORMALC);
+ addch(*++cp);
+ attrset ((i==r->pos && Msg==WIDGET_FOCUS) ? FOCUSC : NORMALC);
+ }
+ else
+ addch(*cp);
+ }
+ }
+ return 1;
+ break;
+#endif
+ }
+ return default_proc (h, Msg, Par);
+}
+
+#ifdef HAVE_TK
+ static void Radio_destroy (WRadio *r)
+ {
+ x_destroy_cmd (r);
+ }
+# define radio_destroy (destroy_fn) Radio_destroy
+#else
+# define radio_destroy 0
+#endif
+
+static int
+radio_event (Gpm_Event *event, WRadio *r)
+{
+#ifndef HAVE_X
+ if (event->type & (GPM_DOWN|GPM_UP)){
+ Dlg_head *h = r->widget.parent;
+
+ r->pos = event->y - 1;
+ dlg_select_widget (h, r);
+ if (event->type & GPM_UP){
+ radio_callback (h, r, WIDGET_KEY, ' ');
+ radio_callback (h, r, WIDGET_FOCUS, 0);
+ (*h->callback) (h, ' ', DLG_POST_KEY);
+ return MOU_NORMAL;
+ }
+ }
+#endif
+ return MOU_NORMAL;
+}
+
+WRadio *
+radio_new (int y, int x, int count, char **texts, int use_hotkey, char *tkname)
+{
+ WRadio *r = xmalloc (sizeof (WRadio), "radio_new");
+ int i, max, m;
+
+ /* Compute the longest string */
+ max = 0;
+ for (i = 0; i < count; i++){
+ m = strlen (texts [i]);
+ if (m > max)
+ max = m;
+ }
+
+ init_widget (&r->widget, y, x, count, max, (callback_fn) radio_callback,
+ radio_destroy, (mouse_h) radio_event, tkname);
+ r->state = 1;
+ r->pos = 0;
+ r->sel = 0;
+ r->count = count;
+ r->texts = texts;
+ r->upper_letter_is_hotkey = use_hotkey;
+ widget_want_hotkey (r->widget, 1);
+
+ return r;
+}
+
+\f
+/* Checkbutton widget */
+
+static int check_event (Gpm_Event *event, WCheck *b);
+
+static int
+check_callback (Dlg_head *h, WCheck *c, int Msg, int Par)
+{
+ switch (Msg) {
+ case WIDGET_INIT:
+ return x_create_check (h, h->wdata, c);
+
+#ifndef HAVE_XVIEW
+ case WIDGET_HOTKEY:
+ if (c->hotkey==Par ||
+ (c->hotkey>='a' && c->hotkey<='z' && c->hotkey-32==Par)){
+ check_callback (h, c, WIDGET_KEY, ' '); /* make action */
+ return 1;
+ } else
+ return 0;
+
+ case WIDGET_KEY:
+ if (Par != ' ')
+ break;
+ c->state ^= C_BOOL;
+ c->state ^= C_CHANGE;
+ (*h->callback) (h, h->current->dlg_id, DLG_ACTION);
+ check_callback (h, c, WIDGET_FOCUS, ' ');
+ return 1;
+
+#ifndef HAVE_X
+ case WIDGET_CURSOR:
+ widget_move (&c->widget, 0, 1);
+ break;
+
+ case WIDGET_FOCUS:
+ case WIDGET_UNFOCUS:
+ case WIDGET_DRAW:
+ attrset ((Msg == WIDGET_FOCUS) ? FOCUSC : NORMALC);
+ widget_move (&c->widget, 0, 0);
+ printw ("[%c] %s", (c->state & C_BOOL) ? 'x' : ' ', c->text);
+
+ if (c->hotpos >= 0){
+ attrset ((Msg == WIDGET_FOCUS) ? HOT_FOCUSC : HOT_NORMALC);
+ widget_move (&c->widget, 0, + c->hotpos+4);
+ addch ((unsigned char)c->text [c->hotpos]);
+ }
+ return 1;
+#endif /* !HAVE_X */
+#endif /* !HAVE_XVIEW */
+ }
+ return default_proc (h, Msg, Par);
+}
+
+static int
+check_event (Gpm_Event *event, WCheck *c)
+{
+#ifndef HAVE_X
+ if (event->type & (GPM_DOWN|GPM_UP)){
+ Dlg_head *h = c->widget.parent;
+
+ dlg_select_widget (h, c);
+ if (event->type & GPM_UP){
+ check_callback (h, c, WIDGET_KEY, ' ');
+ check_callback (h, c, WIDGET_FOCUS, 0);
+ (*h->callback) (h, ' ', DLG_POST_KEY);
+ return MOU_NORMAL;
+ }
+ }
+#endif
+ return MOU_NORMAL;
+}
+
+static void
+check_destroy (WCheck *c)
+{
+ x_destroy_cmd (c);
+ free (c->text);
+}
+
+WCheck *
+check_new (int y, int x, int state, char *text, char *tkname)
+{
+ WCheck *c = xmalloc (sizeof (WCheck), "check_new");
+ char *s, *t;
+
+ init_widget (&c->widget, y, x, 1, strlen (text),
+ (callback_fn)check_callback,
+ (destroy_fn)check_destroy, (mouse_h) check_event, tkname);
+ c->state = state ? C_BOOL : 0;
+ c->text = strdup (text);
+ c->hotkey = 0;
+ c->hotpos = -1;
+ widget_want_hotkey (c->widget, 1);
+
+ /* Scan for the hotkey */
+ for (s = text, t = c->text; *s; s++, t++){
+ if (*s != '&'){
+ *t = *s;
+ continue;
+ }
+ s++;
+ if (*s){
+ c->hotkey = tolower (*s);
+ c->hotpos = t - c->text;
+ }
+ *t = *s;
+ }
+ *t = 0;
+ return c;
+}
+
+\f
+/* Label widget */
+
+static int
+label_callback (Dlg_head *h, WLabel *l, int Msg, int Par)
+{
+ if (Msg == WIDGET_INIT)
+ return x_create_label (h, h->wdata, l);
+
+ /* We don't want to get the focus */
+ if (Msg == WIDGET_FOCUS)
+ return 0;
+#ifndef HAVE_X
+ if (Msg == WIDGET_DRAW && l->text){
+ char *p = l->text, *q, c = 0;
+ int y = 0;
+ if (l->transparent)
+ attrset (DEFAULT_COLOR);
+ else
+ attrset (NORMALC);
+ for (;;){
+ int xlen;
+
+ q = strchr (p, '\n');
+ if (q){
+ c = *q;
+ *q = 0;
+ }
+ widget_move (&l->widget, y, 0);
+ printw ("%s", p);
+ xlen = l->widget.cols - strlen (p);
+ if (xlen > 0)
+ printw ("%*s", xlen, " ");
+ if (!q)
+ break;
+ *q = c;
+ p = q + 1;
+ y++;
+ }
+ return 1;
+ }
+#endif
+ return default_proc (h, Msg, Par);
+}
+
+void
+label_set_text (WLabel *label, char *text)
+{
+ int newcols = label->widget.cols;
+
+ if (label->text && text && !strcmp (label->text, text))
+ return; /* Flickering is not nice */
+
+ if (label->text){
+ free (label->text);
+ }
+ if (text){
+ label->text = strdup (text);
+ if (label->auto_adjust_cols) {
+ newcols = strlen (text);
+ if (newcols > label->widget.cols)
+ label->widget.cols = newcols;
+ }
+ } else
+ label->text = 0;
+
+ if (label->widget.parent)
+#ifdef HAVE_X
+ x_label_set_text (label, text);
+#else
+ label_callback (label->widget.parent, label, WIDGET_DRAW, 0);
+#endif
+ if (newcols < label->widget.cols)
+ label->widget.cols = newcols;
+}
+
+static void
+label_destroy (WLabel *l)
+{
+ x_destroy_cmd (l);
+ if (l->text)
+ free (l->text);
+}
+
+WLabel *
+label_new (int y, int x, char *text, char *tkname)
+{
+ WLabel *l = xmalloc (sizeof (WLabel), "label_new");
+
+ init_widget (&l->widget, y, x, 1, 1,
+ (callback_fn) label_callback,
+ (destroy_fn) label_destroy, NULL, tkname);
+ l->text = text ? strdup (text) : 0;
+ l->auto_adjust_cols = 1;
+ l->transparent = 0;
+ widget_want_cursor (l->widget, 0);
+ return l;
+}
+
+\f
+/* Gauge widget (progress indicator) */
+/* Currently width is hardcoded here for text mode */
+#define gauge_len 47
+
+static int
+gauge_callback (Dlg_head *h, WGauge *g, int Msg, int Par)
+{
+
+ if (Msg == WIDGET_INIT)
+ return x_create_gauge (h, h->wdata, g);
+
+ /* We don't want to get the focus */
+ if (Msg == WIDGET_FOCUS)
+ return 0;
+
+#ifndef HAVE_X
+ if (Msg == WIDGET_DRAW){
+ widget_move (&g->widget, 0, 0);
+ attrset (NORMALC);
+ if (!g->shown)
+ printw ("%*s", gauge_len, "");
+ else {
+ long percentage, columns;
+ long total = g->max, done = g->current;
+
+ if (total <= 0 || done < 0) {
+ done = 0;
+ total = 100;
+ }
+ if (done > total)
+ done = total;
+ while (total > 65535) {
+ total /= 256;
+ done /= 256;
+ }
+ percentage = (200 * done / total + 1) / 2;
+ columns = (2 * (gauge_len - 7) * done / total + 1) / 2;
+ addch ('[');
+ attrset (GAUGE_COLOR);
+ printw ("%*s", columns, "");
+ attrset (NORMALC);
+ printw ("%*s] %3d%%", gauge_len - 7 - columns, "", percentage);
+ }
+ return 1;
+ }
+#endif
+ return default_proc (h, Msg, Par);
+}
+
+void
+gauge_set_value (WGauge *g, int max, int current)
+{
+ if (g->current == current && g->max == max)
+ return; /* Do not flicker */
+ if (max == 0)
+ max = 1; /* I do not like division by zero :) */
+#ifdef HAVE_X
+/* NOTE: x_gauge_set_value has to be called before we change actual
+ * max and current values in g, since it assumes g->max and
+ * g->current as the previous values and max and current
+ * as the new ones :) */
+ x_gauge_set_value (g, max, current);
+#endif
+ g->current = current;
+ g->max = max;
+#ifndef HAVE_X
+ gauge_callback (g->widget.parent, g, WIDGET_DRAW, 0);
+#endif
+}
+
+void
+gauge_show (WGauge *g, int shown)
+{
+ if (g->shown == shown)
+ return;
+ g->shown = shown;
+#ifdef HAVE_X
+ x_gauge_show (g);
+#else
+ gauge_callback (g->widget.parent, g, WIDGET_DRAW, 0);
+#endif
+}
+
+static void
+gauge_destroy (WGauge *g)
+{
+ /* nothing */
+}
+
+WGauge *
+gauge_new (int y, int x, int shown, int max, int current, char *tkname)
+{
+ WGauge *g = xmalloc (sizeof (WGauge), "gauge_new");
+
+ init_widget (&g->widget, y, x, 1, gauge_len,
+ (callback_fn) gauge_callback,
+ (destroy_fn) gauge_destroy, NULL, tkname);
+ g->shown = shown;
+ if (max == 0)
+ max = 1; /* I do not like division by zero :) */
+ g->max = max;
+ g->current = current;
+ g->pixels = 0;
+ widget_want_cursor (g->widget, 0);
+ return g;
+}
+
+\f
+/* Input widget */
+
+/* {{{ history button */
+
+#define LARGE_HISTORY_BUTTON 1
+
+#ifdef LARGE_HISTORY_BUTTON
+# define HISTORY_BUTTON_WIDTH 3
+#else
+# define HISTORY_BUTTON_WIDTH 1
+#endif
+
+#define should_show_history_button(in) \
+ (in->history && in->field_len > HISTORY_BUTTON_WIDTH * 2 + 1 && in->widget.parent)
+
+static void draw_history_button (WInput * in)
+{
+ char c;
+ c = in->history->next ? (in->history->prev ? '|' : 'v') : '^';
+ widget_move (&in->widget, 0, in->field_len - HISTORY_BUTTON_WIDTH);
+#ifdef LARGE_HISTORY_BUTTON
+ {
+ Dlg_head *h;
+ h = in->widget.parent;
+#if 0
+ attrset (NORMALC); /* button has the same colour as other buttons */
+ addstr ("[ ]");
+ attrset (HOT_NORMALC);
+#else
+ attrset (NORMAL_COLOR);
+ addstr ("[ ]");
+ /* Too distracting: attrset (MARKED_COLOR); */
+#endif
+ widget_move (&in->widget, 0, in->field_len - HISTORY_BUTTON_WIDTH + 1);
+ addch (c);
+ }
+#else
+ attrset (MARKED_COLOR);
+ addch (c);
+#endif
+}
+
+/* }}} history button */
+
+
+/* Input widgets now have a global kill ring */
+/* Pointer to killed data */
+static char *kill_buffer = 0;
+
+void
+update_input (WInput *in, int clear_first)
+{
+#ifndef HAVE_XVIEW
+ int has_history = 0;
+ int i, j;
+ char c;
+ int buf_len = strlen (in->buffer);
+
+ if (should_show_history_button (in))
+ has_history = HISTORY_BUTTON_WIDTH;
+
+ if (in->disable_update)
+ return;
+
+ /* Make the point visible */
+ if ((in->point < in->first_shown) ||
+ (in->point >= in->first_shown+in->field_len - has_history)){
+ in->first_shown = in->point - (in->field_len / 3);
+ if (in->first_shown < 0)
+ in->first_shown = 0;
+ }
+
+ /* Adjust the mark */
+ if (in->mark > buf_len)
+ in->mark = buf_len;
+
+#ifdef HAVE_X
+ if (clear_first && in->first)
+ in->first = -1;
+ x_update_input (in);
+#else
+
+ if (has_history)
+ draw_history_button (in);
+
+ attrset (in->color);
+
+ widget_move (&in->widget, 0, 0);
+ for (i = 0; i < in->field_len - has_history; i++)
+ addch (' ');
+ widget_move (&in->widget, 0, 0);
+
+ for (i = 0, j = in->first_shown; i < in->field_len - has_history && in->buffer [j]; i++){
+ c = in->buffer [j++];
+ c = is_printable (c) ? c : '.';
+ if (in->is_password)
+ c = '*';
+ addch (c);
+ }
+ widget_move (&in->widget, 0, in->point - in->first_shown);
+
+ if (clear_first)
+ in->first = 0;
+#endif
+
+#endif
+}
+
+void
+winput_set_origin (WInput *in, int x, int field_len)
+{
+ in->widget.x = x;
+ in->field_len = in->widget.cols = field_len;
+ update_input (in, 0);
+}
+
+/* {{{ history saving and loading */
+
+/*
+ This loads and saves the history of an input line to and from the
+ widget. It is called with the widgets tk name on creation of the
+ widget, and returns the Hist list. It stores histories in the file
+ ~/.mc/history in using the profile code.
+
+ If def_text is passed as INPUT_LAST_TEXT (to the input_new()
+ function) then input_new assigns the default text to be the last text
+ entered, or "" if not found.
+ */
+
+int num_history_items_recorded = 60;
+
+Hist *history_get (char *input_name)
+{
+ int i;
+ Hist *old = 0, *new = 0;
+ char *profile;
+
+ if (!num_history_items_recorded) /* this is how to disable */
+ return 0;
+ if (!input_name)
+ return 0;
+ if (!*input_name)
+ return 0;
+ profile = concat_dir_and_file (home_dir, HISTORY_FILE_NAME);
+ for (i = 0;; i++) {
+ char key_name[32];
+ char this_entry[1024];
+ sprintf (key_name, "%d", i);
+ GetPrivateProfileString (input_name, key_name, "", this_entry, sizeof (this_entry), profile);
+ if (!*this_entry)
+ break;
+ new = xmalloc (sizeof (Hist), "history_get");
+ memset (new, 0, sizeof (Hist));
+ new->text = strdup (this_entry);
+ new->prev = old; /* set up list pointers */
+ if (old)
+ old->next = new;
+ old = new;
+ }
+ free (profile);
+ return new; /* return pointer to last entry in list */
+}
+
+#ifdef PORT_WIDGET_WANTS_HISTORY
+void history_put (char *input_name, Hist *h)
+{
+ int i;
+ char *profile;
+
+ if (!input_name)
+ return;
+
+ if (!*input_name)
+ return;
+
+ if (!h)
+ return;
+
+ if (!num_history_items_recorded) /* this is how to disable */
+ return;
+
+ profile = concat_dir_and_file (home_dir, HISTORY_FILE_NAME);
+ while (h->next) /* go to end of list */
+ h = h->next;
+
+ /* go back 60 places */
+ for (i = 0; i < num_history_items_recorded - 1 && h->prev; i++)
+ h = h->prev;
+ i = 0;
+
+ if (input_name)
+ profile_clean_section (input_name, profile);
+
+ /* dump histories into profile */
+ while (h){
+ if (h->text){
+
+ /* probably aren't any null entries, but lets be sure */
+ if (*(h->text)){
+ char key_name[32];
+ sprintf (key_name, "%d", i++);
+ WritePrivateProfileString (input_name, key_name, h->text, profile);
+ }
+ }
+ h = h->next;
+ }
+ free (profile);
+}
+#else
+void history_put (char *input_name, Hist *h)
+{
+}
+#endif
+
+/* }}} history saving and loading */
+
+
+/* {{{ history display */
+
+static const char history_title[] = " History ";
+
+int history_callback (Dlg_head * h, int Par, int Msg)
+{
+#ifndef HAVE_X
+ switch (Msg) {
+ case DLG_DRAW:
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 0, 0, h->lines, h->cols);
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 0, (h->cols - strlen (history_title)) / 2);
+ printw ((char *) history_title);
+ break;
+ }
+#endif
+ return 0;
+}
+
+static inline int listbox_fwd (WListbox *l);
+
+char *show_hist (Hist *history, int widget_x, int widget_y)
+{
+ Hist *hi, *z;
+ int maxlen = strlen(history_title), i, count = 0;
+ int x, y, w, h;
+ char *q, *r = 0;
+ Dlg_head *query_dlg;
+ WListbox *query_list;
+
+ z = history;
+ if (!z)
+ return 0;
+
+ while (z->prev) /* goto first */
+ z = z->prev;
+ hi = z;
+ while (hi) {
+ if ((i = strlen (hi->text)) > maxlen)
+ maxlen = i;
+ count++;
+ hi = hi->next;
+ }
+
+ y = widget_y;
+ h = count + 2;
+ if (h <= y || y > LINES - 6)
+ {
+ h = min(h, y - 1);
+ y -= h;
+ }
+ else
+ {
+ y++;
+ h = min(h, LINES - y);
+ }
+
+ x = widget_x - 2;
+ if ((w = maxlen + 4) + x > COLS)
+ {
+ w = min(w,COLS);
+ x = COLS - w;
+ }
+
+ query_dlg = create_dlg (y, x, h, w, dialog_colors, history_callback,
+ "[History-query]", "history", DLG_NONE);
+ query_list = listbox_new (1, 1, w - 2, h - 2, listbox_finish, 0, NULL);
+ add_widget (query_dlg, query_list);
+ hi = z;
+ if (y < widget_y) {
+ while (hi) { /* traverse */
+ listbox_add_item (query_list, 0, 0, hi->text, NULL);
+ hi = hi->next;
+ }
+ while (listbox_fwd (query_list));
+ } else {
+ while (hi->next)
+ hi = hi->next;
+ while (hi) { /* traverse backwards */
+ listbox_add_item (query_list, 0, 0, hi->text, NULL);
+ hi = hi->prev;
+ }
+ }
+ run_dlg (query_dlg);
+ q = NULL;
+ if (query_dlg->ret_value != B_CANCEL) {
+ listbox_get_current (query_list, &q, NULL);
+ if (q)
+ r = strdup (q);
+ }
+ destroy_dlg (query_dlg);
+ return r;
+}
+
+static void do_show_hist (WInput * in)
+{
+ char *r;
+ r = show_hist (in->history, in->widget.x, in->widget.y);
+ if (r) {
+ assign_text (in, r);
+ free (r);
+ }
+}
+
+/* }}} history display */
+
+static void
+input_destroy (WInput *in)
+{
+ if (!in){
+ fprintf (stderr, "Internal error: null Input *\n");
+ exit (1);
+ }
+
+ new_input (in);
+ if (in->history){
+ Hist *current, *old;
+
+ if (!in->is_password && PORT_WIDGET_WANTS_HISTORY) /* don't save passwords ;-) */
+ history_put (in->history_name, in->history);
+
+ current = in->history;
+ while (current->next)
+ current = current->next;
+ while (current){
+ old = current;
+ current = current->prev;
+ free (old->text);
+ free (old);
+ }
+ }
+ x_destroy_cmd (in);
+ free (in->buffer);
+ free_completions (in);
+ if (in->history_name)
+ free (in->history_name);
+}
+
+static char disable_update = 0;
+
+void
+input_disable_update (WInput *in)
+{
+ in->disable_update++;
+}
+
+void
+input_enable_update (WInput *in)
+{
+ in->disable_update--;
+ update_input (in, 0);
+}
+
+int
+push_history (WInput *in, char *text)
+{
+ Hist *new;
+ char *p;
+
+ for (p = text; *p == ' ' || *p == '\t'; p++);
+ if (!*p)
+ return 0;
+ if (in->history){
+ while (in->history->next)
+ in->history = in->history->next;
+ if (!strcmp (in->history->text, text))
+ return 1;
+ new = xmalloc (sizeof (Hist), "push_history");
+ in->history->next = new;
+ } else
+ new = xmalloc (sizeof (Hist), "push_history");
+ in->need_push = 0;
+ new->next = 0;
+ new->prev = in->history;
+ new->text = strdup (text);
+ in->history = new;
+ return 2;
+}
+
+/* Cleans the input line and adds the current text to the history */
+void
+new_input (WInput *in)
+{
+ if (in->buffer)
+ push_history (in, in->buffer);
+ in->need_push = 1;
+ in->buffer [0] = 0;
+ in->point = 0;
+ in->mark = 0;
+ free_completions (in);
+ update_input (in, 0);
+}
+
+static int
+insert_char (WInput *in, int c_code)
+{
+ int i;
+
+ if (c_code == -1)
+ return 0;
+
+ in->need_push = 1;
+ if (strlen (in->buffer)+1 == in->current_max_len){
+ /* Expand the buffer */
+ char *narea = xmalloc(in->current_max_len + in->field_len, "string expansion");
+ if (narea){
+ char *p = in->buffer;
+
+ strcpy (narea, in->buffer);
+ in->buffer = narea;
+ in->current_max_len += in->field_len;
+ free (p);
+ }
+ }
+ if (strlen (in->buffer)+1 < in->current_max_len){
+ int l = strlen (&in->buffer [in->point]);
+ for (i = l+1; i > 0; i--)
+ in->buffer [in->point+i] = in->buffer [in->point+i-1];
+ in->buffer [in->point] = c_code;
+ in->point++;
+ }
+ return 1;
+}
+
+static void
+beginning_of_line (WInput *in)
+{
+ in->point = 0;
+}
+
+static void
+end_of_line (WInput *in)
+{
+ in->point = strlen (in->buffer);
+}
+
+static void
+backward_char (WInput *in)
+{
+ if (in->point)
+ in->point--;
+}
+
+static void
+forward_char (WInput *in)
+{
+ if (in->buffer [in->point])
+ in->point++;
+}
+
+static void
+forward_word (WInput *in)
+{
+ char *p = in->buffer+in->point;
+
+ while ((*p && isspace (*p)) || ispunct (*p))
+ p++;
+ while (*p && isalnum (*p))
+ p++;
+ in->point = p - in->buffer;
+}
+
+static void
+backward_word (WInput *in)
+{
+ char *p = in->buffer+in->point;
+
+ while (p-1 > in->buffer-1 && (isspace (*(p-1)) || ispunct (*(p-1))))
+ p--;
+ while (p-1 > in->buffer-1 && isalnum (*(p-1)))
+ p--;
+ in->point = p - in->buffer;
+}
+
+#ifdef __linux__
+static void
+key_left (WInput *in)
+{
+ if (ctrl_pressed ())
+ backward_word (in);
+ else
+ backward_char (in);
+}
+
+static void
+key_right (WInput *in)
+{
+ if (ctrl_pressed ())
+ forward_word (in);
+ else
+ forward_char (in);
+}
+#else
+#define key_left backward_char
+#define key_right forward_char
+#endif
+
+static void
+backward_delete (WInput *in)
+{
+ int i;
+
+ if (!in->point)
+ return;
+ for (i = in->point; in->buffer [i-1]; i++)
+ in->buffer [i-1] = in->buffer [i];
+ in->need_push = 1;
+ in->point--;
+}
+
+static void
+delete_char (WInput *in)
+{
+ int i;
+
+ for (i = in->point; in->buffer [i]; i++)
+ in->buffer [i] = in->buffer [i+1];
+ in->need_push = 1;
+}
+
+static void
+copy_region (WInput *in, int x_first, int x_last)
+{
+ int first = min (x_first, x_last);
+ int last = max (x_first, x_last);
+
+ if (last == first)
+ return;
+
+ if (kill_buffer)
+ free (kill_buffer);
+
+ kill_buffer = xmalloc (last-first + 1, "copy_region");
+ strncpy (kill_buffer, in->buffer+first, last-first);
+ kill_buffer [last-first] = 0;
+}
+
+static void
+delete_region (WInput *in, int x_first, int x_last)
+{
+ int first = min (x_first, x_last);
+ int last = max (x_first, x_last);
+
+ in->point = first;
+ in->mark = first;
+ strcpy (&in->buffer [first], &in->buffer [last]);
+ in->need_push = 1;
+}
+
+static void
+kill_word (WInput *in)
+{
+ int old_point = in->point;
+ int new_point;
+
+ forward_word (in);
+ new_point = in->point;
+ in->point = old_point;
+
+ copy_region (in, old_point, new_point);
+ delete_region (in, old_point, new_point);
+ in->need_push = 1;
+}
+
+static void
+back_kill_word (WInput *in)
+{
+ int old_point = in->point;
+ int new_point;
+
+ backward_word (in);
+ new_point = in->point;
+ in->point = old_point;
+
+ copy_region (in, old_point, new_point);
+ delete_region (in, old_point, new_point);
+ in->need_push = 1;
+}
+
+static void
+set_mark (WInput *in)
+{
+ in->mark = in->point;
+}
+
+static void
+kill_save (WInput *in)
+{
+ copy_region (in, in->mark, in->point);
+}
+
+static void
+kill_region (WInput *in)
+{
+ kill_save (in);
+ delete_region (in, in->point, in->mark);
+}
+
+static void
+yank (WInput *in)
+{
+ char *p;
+
+ if (!kill_buffer)
+ return;
+ for (p = kill_buffer; *p; p++)
+ insert_char (in, *p);
+}
+
+static void
+kill_line (WInput *in)
+{
+ if (kill_buffer)
+ free (kill_buffer);
+ kill_buffer = strdup (&in->buffer [in->point]);
+ in->buffer [in->point] = 0;
+}
+
+void
+assign_text (WInput *in, char *text)
+{
+ free_completions (in);
+ free (in->buffer);
+ in->buffer = strdup (text); /* was in->buffer->text */
+ in->current_max_len = strlen (in->buffer) + 1;
+ in->point = strlen (in->buffer);
+ in->mark = 0;
+ in->need_push = 1;
+}
+
+static void
+hist_prev (WInput *in)
+{
+ if (!in->history)
+ return;
+
+ if (in->need_push) {
+ switch (push_history (in, in->buffer)) {
+ case 2: in->history = in->history->prev; break;
+ case 1: if (in->history->prev) in->history = in->history->prev; break;
+ case 0: break;
+ }
+ } else if (in->history->prev)
+ in->history = in->history->prev;
+ else
+ return;
+ assign_text (in, in->history->text);
+ in->need_push = 0;
+}
+
+static void
+hist_next (WInput *in)
+{
+ if (in->need_push) {
+ switch (push_history (in, in->buffer)) {
+ case 2:
+ assign_text (in, "");
+ return;
+ case 0:
+ return;
+ }
+ }
+
+ if (!in->history)
+ return;
+
+ if (!in->history->next) {
+ assign_text (in, "");
+ return;
+ }
+
+ in->history = in->history->next;
+ assign_text (in, in->history->text);
+ in->need_push = 0;
+}
+
+static struct {
+ int key_code;
+ void (*fn)(WInput *in);
+} input_map [] = {
+ /* Motion */
+ { XCTRL('a'), beginning_of_line },
+ { KEY_HOME, beginning_of_line },
+ { KEY_A1, beginning_of_line },
+ { XCTRL('e'), end_of_line },
+ { KEY_END, end_of_line },
+ { KEY_C1, end_of_line },
+ { KEY_LEFT, key_left },
+ { XCTRL('b'), backward_char },
+ { ALT('b'), backward_word },
+ { KEY_RIGHT, key_right },
+ { XCTRL('f'), forward_char },
+ { ALT('f'), forward_word },
+
+ /* Editing */
+ { 0177, backward_delete },
+ { KEY_BACKSPACE, backward_delete },
+ { XCTRL('h'), backward_delete },
+ { KEY_DC, delete_char },
+ { XCTRL('d'), delete_char },
+ { ALT('d'), kill_word },
+ { ALT(KEY_BACKSPACE), back_kill_word },
+ { ALT(XCTRL('h')), back_kill_word },
+ { ALT(127), back_kill_word },
+
+ /* Region manipulation */
+ { 0, set_mark },
+ { XCTRL('w'), kill_region },
+ { ALT('w'), kill_save },
+ { XCTRL('y'), yank },
+ { XCTRL('k'), kill_line },
+
+ /* History */
+ { ALT('p'), hist_prev },
+ { ALT('n'), hist_next },
+ { ALT('h'), do_show_hist },
+
+ /* Completion */
+ { ALT('\t'), complete },
+
+ { 0, 0 }
+};
+
+/* This function is a test for a special input key used in complete.c */
+/* Returns 0 if it is not a special key, 1 if it is a non-complete key
+ and 2 if it is a complete key */
+int
+is_in_input_map (WInput *in, int c_code)
+{
+ int i;
+
+ for (i = 0; input_map [i].fn; i++)
+ if (c_code == input_map [i].key_code)
+ if (input_map [i].fn == complete)
+ return 2;
+ else
+ return 1;
+ return 0;
+}
+
+#ifdef PORT_WINPUT_DELETES_MARKED
+static void
+port_region_marked_for_delete (WInput *in)
+{
+ kill_region (in);
+}
+#else
+static void
+port_region_marked_for_delete (WInput *in)
+{
+ *in->buffer = 0;
+ in->point = 0;
+ in->first = 0;
+}
+#endif
+
+int
+handle_char (WInput *in, int c_code)
+{
+ int i;
+ int v;
+
+ v = 0;
+
+#ifdef HAVE_TK
+ in->inserted_one = 0;
+#endif
+ if (quote){
+ free_completions (in);
+ v = insert_char (in, c_code);
+ update_input (in, 1);
+ quote = 0;
+ return v;
+ }
+
+ for (i = 0; input_map [i].fn; i++){
+ if (c_code == input_map [i].key_code){
+ if (input_map [i].fn != complete)
+ free_completions (in);
+ (*input_map [i].fn)(in);
+ v = 1;
+ break;
+ }
+ }
+ if (!input_map [i].fn){
+ if (c_code > 255 || !is_printable (c_code))
+ return 0;
+ if (in->first){
+ port_region_marked_for_delete (in);
+ }
+ free_completions (in);
+ v = insert_char (in, c_code);
+ in->inserted_one = c_code;
+ }
+ if (!disable_update)
+ update_input (in, 1);
+ return v;
+}
+
+/* Inserts text in input line */
+void
+stuff (WInput *in, char *text, int insert_extra_space)
+{
+ input_disable_update (in);
+ while (*text)
+ handle_char (in, *text++);
+ if (insert_extra_space)
+ handle_char (in, ' ');
+ input_enable_update (in);
+ update_input (in, 1);
+}
+
+void
+input_set_point (WInput *in, int pos)
+{
+ if (pos > in->current_max_len)
+ pos = in->current_max_len;
+ if (pos != in->point)
+ free_completions (in);
+ in->point = pos;
+ update_input (in, 1);
+}
+
+int input_event (Gpm_Event *event, WInput *b);
+
+static int
+input_callback (Dlg_head *h, WInput *in, int Msg, int Par)
+{
+ switch (Msg){
+ case WIDGET_INIT:
+ return x_create_input (h, h->wdata, in);
+
+#ifndef HAVE_XVIEW
+ case WIDGET_KEY:
+ if (Par == XCTRL('q')){
+ int v;
+
+ quote = 1;
+ v = handle_char (in, mi_getch ());
+ quote = 0;
+ return v;
+ }
+ if (Par == KEY_UP || Par == KEY_DOWN ||
+ Par == ESC_CHAR || Par == KEY_F(10) ||
+ Par == XCTRL('g'))
+ return 0; /* We don't handle up/down */
+
+ if (Par == '\n'){
+ dlg_one_down (h);
+ return 1;
+ }
+ return handle_char (in, Par);
+
+ case WIDGET_FOCUS:
+ case WIDGET_UNFOCUS:
+ case WIDGET_DRAW:
+ update_input (in, 0);
+ break;
+#endif /* !HAVE_XVIEW */
+#ifndef HAVE_X
+ case WIDGET_CURSOR:
+ widget_move (&in->widget, 0, in->point - in->first_shown);
+ return 1;
+#endif
+
+ }
+ return default_proc (h, Msg, Par);
+}
+
+/* Not declared static, since we check against this value in dlg.c */
+/* FIXME: Declare static again and provide an identification mechanism */
+int
+input_event (Gpm_Event *event, WInput *in)
+{
+#ifndef HAVE_X
+ if (event->type & (GPM_DOWN|GPM_DRAG)){
+ dlg_select_widget (in->widget.parent, in);
+
+ if (event->x >= in->field_len - HISTORY_BUTTON_WIDTH + 1 && should_show_history_button (in)) {
+ do_show_hist (in);
+ update_input (in, 1);
+ } else {
+ in->point = strlen (in->buffer);
+ if (event->x - in->first_shown - 1 < in->point)
+ in->point = event->x - in->first_shown - 1;
+ if (in->point < 0)
+ in->point = 0;
+
+ update_input (in, 1);
+ }
+ }
+#endif
+ return MOU_NORMAL;
+}
+
+WInput *
+input_new (int y, int x, int color, int len, char *def_text, char *tkname)
+{
+ WInput *in = xmalloc (sizeof (WInput), "input_new");
+ int initial_buffer_len;
+
+ init_widget (&in->widget, y, x, 1, len,
+ (callback_fn) input_callback,
+ (destroy_fn) input_destroy, (mouse_h) input_event, tkname);
+
+ /* history setup */
+ in->history = NULL;
+ in->history_name = 0;
+ if (tkname && PORT_WIDGET_WANTS_HISTORY){
+ if (*tkname) {
+ in->history_name = strdup (tkname);
+ in->history = history_get (tkname);
+ }
+ }
+ if (def_text == INPUT_LAST_TEXT) {
+ def_text = "";
+ if (in->history)
+ if (in->history->text)
+ def_text = in->history->text;
+ }
+ initial_buffer_len = 1 + max (len, strlen (def_text));
+ in->widget.options |= W_IS_INPUT;
+ in->completions = NULL;
+ in->completion_flags =
+ INPUT_COMPLETE_FILENAMES | INPUT_COMPLETE_HOSTNAMES |
+ INPUT_COMPLETE_VARIABLES | INPUT_COMPLETE_USERNAMES;
+ in->current_max_len = initial_buffer_len;
+ in->buffer = xmalloc (initial_buffer_len, "create_input: in->buffer");
+ in->color = color;
+ in->field_len = len;
+ in->first = 1;
+ in->first_shown = 0;
+ in->disable_update = 0;
+ in->mark = 0;
+ in->need_push = 1;
+ in->is_password = 0;
+
+ strcpy (in->buffer, def_text);
+ in->point = strlen (in->buffer);
+ in->first = 1;
+ return in;
+}
+
+\f
+/* Listbox widget */
+
+/* Should draw the scrollbar, but currently draws only
+ * indications that there is more information
+ */
+static int listbox_cdiff (WLEntry *s, WLEntry *e);
+
+static void
+listbox_drawscroll (WListbox *l)
+{
+ extern int slow_terminal;
+ int line;
+ int i, top;
+ int max_line = l->height-1;
+
+ /* Are we at the top? */
+ widget_move (&l->widget, 0, l->width);
+ if (l->list == l->top)
+ one_vline ();
+ else
+ addch ('^');
+
+ /* Are we at the bottom? */
+ widget_move (&l->widget, max_line, l->width);
+ top = listbox_cdiff (l->list, l->top);
+ if ((top + l->height == l->count) || l->height >= l->count)
+ one_vline ();
+ else
+ addch ('v');
+
+ /* Now draw the nice relative pointer */
+ if (l->count)
+ line = 1+ ((l->pos * (l->height-2)) / l->count);
+ else
+ line = 0;
+
+ for (i = 1; i < max_line; i++){
+ widget_move (&l->widget, i, l->width);
+ if (i != line)
+ one_vline ();
+ else
+ addch ('*');
+ }
+}
+
+static void
+listbox_draw (WListbox *l, Dlg_head *h, int focused)
+{
+ WLEntry *e;
+ int i;
+ int sel_line;
+ int normalc, selc;
+ char *text;
+
+ if (focused){
+ normalc = NORMALC;
+ selc = FOCUSC;
+ } else {
+ normalc = NORMALC;
+ selc = HOT_FOCUSC;
+ }
+ sel_line = -1;
+
+ for (e = l->top, i = 0; (i < l->height); i++){
+
+ /* Display the entry */
+ if (e == l->current && sel_line == -1){
+ sel_line = i;
+ attrset (selc);
+ } else
+ attrset (normalc);
+
+ widget_move (&l->widget, i, 0);
+
+ if ((i > 0 && e == l->list) || !l->list)
+ text = "";
+ else {
+ text = e->text;
+ e = e->next;
+ }
+ printw (" %-*s ", l->width-2, name_trunc (text, l->width-2));
+ }
+ l->cursor_y = sel_line;
+ if (!l->scrollbar)
+ return;
+ attrset (normalc);
+ listbox_drawscroll (l);
+}
+
+/* Returns the number of items between s and e,
+ must be on the same linked list */
+static int
+listbox_cdiff (WLEntry *s, WLEntry *e)
+{
+ int count;
+
+ for (count = 0; s != e; count++)
+ s = s->next;
+ return count;
+}
+
+static WLEntry *
+listbox_check_hotkey (WListbox *l, int key)
+{
+ int i;
+ WLEntry *e;
+
+ i = 0;
+ e = l->list;
+ if (!e)
+ return 0;
+
+ while (1){
+
+ /* If we didn't find anything, return */
+ if (i && e == l->list)
+ return 0;
+
+ if (e->hotkey == key)
+ return e;
+
+ i++;
+ e = e->next;
+ }
+}
+
+/* Used only for display updating, for avoiding line at a time scroll */
+void
+listbox_select_last (WListbox *l, int set_top)
+{
+ if (l->list){
+ l->current = l->list->prev;
+ l->pos = l->count - 1;
+ if (set_top)
+ l->top = l->list->prev;
+ x_listbox_select_nth (l, l->pos);
+ }
+}
+
+void
+listbox_remove_list (WListbox *l)
+{
+ WLEntry *p, *q;
+
+ if (!l->count)
+ return;
+
+#ifdef HAVE_X
+ if (l->widget.wdata != (widget_data) NULL) {
+ int i;
+ for (i = 0; i < l->count; i++)
+ x_listbox_delete_nth (l, i);
+ }
+#endif
+ p = l->list;
+
+ while (l->count--) {
+ q = p->next;
+ free (p->text);
+ free (p);
+ p = q;
+ }
+ l->pos = l->count = 0;
+ l->list = l->top = l->current = 0;
+}
+
+/*
+ * bor 30.10.96: added force flag to remove *last* entry as well
+ * bor 30.10.96: corrected selection bug if last entry was removed
+ */
+
+void
+listbox_remove_current (WListbox *l, int force)
+{
+ WLEntry *p;
+
+ /* Ok, note: this won't allow for emtpy lists */
+ if (!force && (!l->count || l->count == 1))
+ return;
+
+#ifdef HAVE_X
+ if (l->widget.wdata != (widget_data) NULL) {
+ x_listbox_delete_nth (l, l->pos);
+ if (l->count > 1)
+ if (l->current->next != l->list)
+ x_listbox_select_nth (l, l->pos);
+ else if (l->current != l->list)
+ x_listbox_select_nth (l, l->pos - 1);
+ else
+ x_listbox_select_nth (l, 0);
+ }
+#endif
+ l->count--;
+ p = l->current;
+
+ if (l->count) {
+ l->current->next->prev = l->current->prev;
+ l->current->prev->next = l->current->next;
+ if (p->next == l->list) {
+ l->current = p->prev;
+ l->pos--;
+ }
+ else
+ l->current = p->next;
+
+ if (p == l->list)
+ l->list = l->top = p->next;
+ } else {
+ l->pos = 0;
+ l->list = l->top = l->current = 0;
+ }
+
+ free (p->text);
+ free (p);
+}
+
+/* Makes *e the selected entry (sets current and pos) */
+void
+listbox_select_entry (WListbox *l, WLEntry *dest)
+{
+ WLEntry *e;
+ int pos;
+ int top_seen;
+
+ top_seen = 0;
+
+ /* Special case */
+ for (pos = 0, e = l->list; pos < l->count; e = e->next, pos++){
+
+ if (e == l->top)
+ top_seen = 1;
+
+ if (e == dest){
+ l->current = e;
+ if (top_seen){
+ while (listbox_cdiff (l->top, l->current) >= l->height)
+ l->top = l->top->next;
+ } else {
+ l->top = l->current;
+ }
+ l->pos = pos;
+ x_listbox_select_nth (l, l->pos);
+ return;
+ }
+ }
+ /* If we are unable to find it, set decent values */
+ l->current = l->top = l->list;
+ l->pos = 0;
+ x_listbox_select_nth (l, l->pos);
+}
+
+/* Selects from base the pos element */
+static WLEntry *
+listbox_select_pos (WListbox *l, WLEntry *base, int pos)
+{
+ WLEntry *last = l->list->prev;
+
+ if (base == last)
+ return last;
+ while (pos--){
+ base = base->next;
+ if (base == last)
+ break;
+ }
+ return base;
+}
+
+static inline int
+listbox_back (WListbox *l)
+{
+ if (l->pos){
+ listbox_select_entry (l, listbox_select_pos (l, l->list, l->pos-1));
+ return 1;
+ }
+ return 0;
+}
+
+static inline int
+listbox_fwd (WListbox *l)
+{
+ if (l->current != l->list->prev){
+ listbox_select_entry (l, listbox_select_pos (l, l->list, l->pos+1));
+ return 1;
+ }
+ return 0;
+}
+
+/* Returns 1 if we want a redraw */
+static int
+listbox_key (WListbox *l, int key)
+{
+ int i;
+ int j = 0;
+
+ if (!l->list)
+ return 0;
+
+ switch (key){
+ case KEY_HOME:
+ case KEY_A1:
+ l->current = l->top = l->list;
+ l->pos = 0;
+ return 1;
+
+ case KEY_END:
+ case KEY_C1:
+ l->current = l->top = l->list->prev;
+ for (i = min (l->height - 1, l->count - 1); i; i--)
+ l->top = l->top->prev;
+ l->pos = l->count - 1;
+ return 1;
+
+ case XCTRL('p'):
+ case KEY_UP:
+ listbox_back (l);
+ return 1;
+
+ case XCTRL('n'):
+ case KEY_DOWN:
+ listbox_fwd (l);
+ return 1;
+
+ case KEY_NPAGE:
+ case XCTRL('v'):
+ for (i = 0; i < l->height-1; i++)
+ j |= listbox_fwd (l);
+ return j > 0;
+
+ case KEY_PPAGE:
+ case ALT('v'):
+ for (i = 0; i < l->height-1; i++)
+ j |= listbox_back (l);
+ return j > 0;
+ }
+ return 0;
+}
+
+static int listbox_event (Gpm_Event *event, WListbox *l);
+static int
+listbox_callback (Dlg_head *h, WListbox *l, int msg, int par)
+{
+ WLEntry *e;
+ /* int selected_color; Never used */
+ int ret_code;
+
+ switch (msg){
+ case WIDGET_INIT:
+ return x_create_listbox (h, h->wdata, l);
+
+#ifndef HAVE_XVIEW
+ case WIDGET_HOTKEY:
+ if ((e = listbox_check_hotkey (l, par)) != NULL){
+ listbox_select_entry (l, e);
+
+ /* Take the appropriate action */
+ if (l->action == listbox_finish){
+ l->widget.parent->running = 0;
+ l->widget.parent->ret_value = B_ENTER;
+ } else if (l->action == listbox_cback){
+ if ((*l->cback)(l) == listbox_finish){
+ l->widget.parent->running = 0;
+ l->widget.parent->ret_value = B_ENTER;
+ }
+ }
+ return 1;
+ } else
+ return 0;
+
+ case WIDGET_KEY:
+ if ((ret_code = listbox_key (l, par)))
+ listbox_draw (l, h, 1);
+ return ret_code;
+
+#ifndef HAVE_X
+ case WIDGET_CURSOR:
+ widget_move (&l->widget, l->cursor_y, 0);
+ return 1;
+
+ case WIDGET_FOCUS:
+ case WIDGET_UNFOCUS:
+ case WIDGET_DRAW:
+ listbox_draw (l, h, msg != WIDGET_UNFOCUS);
+ return 1;
+#endif
+#endif /* !HAVE_XVIEW */
+ }
+ return default_proc (h, msg, par);
+}
+
+static int
+listbox_event (Gpm_Event *event, WListbox *l)
+{
+#ifndef HAVE_X
+ int i;
+
+ Dlg_head *h = l->widget.parent;
+
+ /* Single click */
+ if (event->type & GPM_DOWN)
+ dlg_select_widget (l->widget.parent, l);
+ if (!l->list)
+ return MOU_NORMAL;
+ if (event->type & (GPM_DOWN|GPM_DRAG)){
+ if (event->x < 0 || event->x >= l->width)
+ return MOU_REPEAT;
+ if (event->y < 1)
+ for (i = -event->y; i >= 0; i--)
+ listbox_back (l);
+ else if (event->y > l->height)
+ for (i = event->y - l->height; i > 0; i--)
+ listbox_fwd (l);
+ else
+ listbox_select_entry (l, listbox_select_pos (l, l->top,
+ event->y - 1));
+
+ /* We need to refresh ourselves since the dialog manager doesn't */
+ /* know about this event */
+ listbox_callback (h, l, WIDGET_DRAW, 0);
+ mc_refresh ();
+ return MOU_REPEAT;
+ }
+
+ /* Double click */
+ if ((event->type & (GPM_DOUBLE|GPM_UP)) == (GPM_UP|GPM_DOUBLE)){
+ if (event->x < 0 || event->x >= l->width)
+ return MOU_NORMAL;
+ if (event->y < 1 || event->y > l->height)
+ return MOU_NORMAL;
+
+ dlg_select_widget (l->widget.parent, l);
+ listbox_select_entry (l, listbox_select_pos (l, l->top, event->y - 1));
+
+ switch (l->action){
+ case listbox_nothing:
+ break;
+
+ case listbox_finish:
+ h->ret_value = B_ENTER;
+ dlg_stop (h);
+ return MOU_ENDLOOP;
+
+ case listbox_cback:
+ if ((*l->cback)(l) == listbox_finish)
+ return MOU_ENDLOOP;
+ }
+ }
+#endif
+ return MOU_NORMAL;
+}
+
+static void
+listbox_destroy (WListbox *l)
+{
+ WLEntry *n, *p = l->list;
+ int i;
+
+ x_destroy_cmd (l);
+ for (i = 0; i < l->count; i++){
+ n = p->next;
+ free (p->text);
+ free (p);
+ p = n;
+ }
+}
+
+WListbox *
+listbox_new (int y, int x, int width, int height,
+ int action, lcback callback, char *tkname)
+{
+ WListbox *l = xmalloc (sizeof (WListbox), "listbox_new");
+ extern int slow_terminal;
+
+ init_widget (&l->widget, y, x, height, width,
+ (callback_fn)listbox_callback,
+ (destroy_fn) listbox_destroy, (mouse_h)listbox_event, tkname);
+
+ l->list = l->top = l->current = 0;
+ l->pos = 0;
+ l->width = width;
+ l->height = height;
+ l->count = 0;
+ l->top = 0;
+ l->current= 0;
+ l->cback = callback;
+ l->action = action;
+ l->allow_duplicates = 1;
+ l->scrollbar = slow_terminal ? 0 : 1;
+ widget_want_hotkey (l->widget, 1);
+
+ return l;
+}
+
+/* Listbox item adding function. They still lack a lot of functionality */
+/* any takers? */
+/* 1.11.96 bor: added pos argument to control placement of new entry */
+static void
+listbox_append_item (WListbox *l, WLEntry *e, enum append_pos pos)
+{
+ if (!l->list){
+ l->list = e;
+ l->top = e;
+ l->current = e;
+ e->next = l->list;
+ e->prev = l->list;
+ } else if (pos == LISTBOX_APPEND_AT_END) {
+ e->next = l->list;
+ e->prev = l->list->prev;
+ l->list->prev->next = e;
+ l->list->prev = e;
+ } else if (pos == LISTBOX_APPEND_BEFORE){
+ e->next = l->current;
+ e->prev = l->current->prev;
+ l->current->prev->next = e;
+ l->current->prev = e;
+ if (l->list == l->current) { /* move list one position down */
+ l->list = e;
+ l->top = e;
+ }
+ } else if (pos == LISTBOX_APPEND_AFTER) {
+ e->prev = l->current;
+ e->next = l->current->next;
+ l->current->next->prev = e;
+ l->current->next = e;
+ }
+ x_list_insert (l, l->list, e);
+ l->count++;
+}
+
+char *
+listbox_add_item (WListbox *l, enum append_pos pos, int hotkey, char *text,
+ void *data)
+{
+ WLEntry *entry;
+
+ if (!l)
+ return 0;
+
+ if (!l->allow_duplicates)
+ if (listbox_search_text (l, text))
+ return 0;
+
+ entry = xmalloc (sizeof (WLEntry), "listbox_add_item");
+ entry->text = strdup (text);
+ entry->data = data;
+ entry->hotkey = hotkey;
+
+ listbox_append_item (l, entry, pos);
+
+ return entry->text;
+}
+
+/* Selects the nth entry in the listbox */
+void
+listbox_select_by_number (WListbox *l, int n)
+{
+ listbox_select_entry (l, listbox_select_pos (l, l->list, n));
+}
+
+WLEntry *
+listbox_search_text (WListbox *l, char *text)
+{
+ WLEntry *e;
+
+ e = l->list;
+ if (!e)
+ return NULL;
+
+ do {
+ if(!strcmp (e->text, text))
+ return e;
+ e = e->next;
+ } while (e!=l->list);
+
+ return NULL;
+}
+
+/* Returns the current string text as well as the associated extra data */
+void
+listbox_get_current (WListbox *l, char **string, char **extra)
+{
+ if (!l->current){
+ *string = 0;
+ *extra = 0;
+ }
+ if (string && l->current)
+ *string = l->current->text;
+ if (extra && l->current)
+ *extra = l->current->data;
+}
+
+int
+buttonbar_callback (Dlg_head *h, WButtonBar *bb, int msg, int par)
+{
+ int i;
+
+ switch (msg){
+ case WIDGET_INIT:
+ return x_create_buttonbar (h, h->wdata, bb);
+
+ case WIDGET_FOCUS:
+ return 0;
+
+#ifndef HAVE_XVIEW
+ case WIDGET_HOTKEY:
+ for (i = 0; i < 10; i++){
+ if (par == KEY_F(i+1) && bb->labels [i].function){
+ (*bb->labels [i].function)(bb->labels [i].data);
+ return 1;
+ }
+ }
+ return 0;
+
+#ifndef HAVE_X
+ case WIDGET_DRAW:
+ if (!bb->visible)
+ return 1;
+ widget_move (&bb->widget, 0, 0);
+ attrset (DEFAULT_COLOR);
+ printw ("%-*s", bb->widget.cols - 1, "");
+ for (i = 0; i < COLS/8 && i < 10; i++){
+ widget_move (&bb->widget, 0, i*8);
+ attrset (DEFAULT_COLOR);
+ printw ("%d", i+1);
+ attrset (SELECTED_COLOR);
+ printw ("%-*s", ((i+1) * 8 == COLS ? 5 : 6),
+ bb->labels [i].text ? bb->labels [i].text : "");
+ attrset (DEFAULT_COLOR);
+ }
+ attrset (SELECTED_COLOR);
+ return 1;
+#endif
+#endif /* !HAVE_XVIEW */
+ }
+ return default_proc (h, msg, par);
+}
+
+static void
+buttonbar_destroy (WButtonBar *bb)
+{
+ int i;
+
+ for (i = 0; i < 10; i++){
+ if (bb->labels [i].text)
+ free (bb->labels [i].text);
+ }
+}
+
+static int
+buttonbar_event (Gpm_Event *event, WButtonBar *bb)
+{
+#ifndef HAVE_X
+ int button;
+
+ if (!(event->type & GPM_UP))
+ return MOU_NORMAL;
+ if (event->y == 2)
+ return MOU_NORMAL;
+ button = event->x / 8;
+ if (button < 10 && bb->labels [button].function)
+ (*bb->labels [button].function)(bb->labels [button].data);
+#endif
+ return MOU_NORMAL;
+}
+
+WButtonBar *
+buttonbar_new (int visible)
+{
+ int i;
+ WButtonBar *bb = xmalloc (sizeof (WButtonBar), "buttonbar_new");
+
+ init_widget (&bb->widget, LINES-1, 0, 1, COLS,
+ (callback_fn) buttonbar_callback,
+ (destroy_fn) buttonbar_destroy, (mouse_h) buttonbar_event, NULL);
+
+ bb->visible = visible;
+ for (i = 0; i < 10; i++){
+ bb->labels [i].text = 0;
+ bb->labels [i].function = 0;
+ }
+ widget_want_hotkey (bb->widget, 1);
+ widget_want_cursor (bb->widget, 0);
+
+ return bb;
+}
+
+void
+set_label_text (WButtonBar *bb, int index, char *text)
+{
+ if (bb->labels [index-1].text)
+ free (bb->labels [index-1].text);
+
+ bb->labels [index-1].text = strdup (text);
+}
+
+/* paneletc is either the panel widget, or info or view or tree widget */
+WButtonBar *
+find_buttonbar (Dlg_head *h, Widget *paneletc)
+{
+ WButtonBar *bb;
+ Widget_Item *item;
+ int i;
+
+ bb = 0;
+ for (i = 0, item = h->current; i < h->count; i++, item = item->next){
+ if (item->widget->callback == (callback_fn) buttonbar_callback){
+ bb = (WButtonBar *) item->widget;
+#ifdef HAVE_XVIEW
+ /* Jakub: do we really need this routine here?
+ * Does XView hold more that a buttonbar per Dlg_head?
+ */
+ if (x_find_buttonbar_check (bb, paneletc)) {
+ bb = 0;
+ continue;
+ }
+#endif
+ break;
+ }
+ }
+ return bb;
+}
+
+void
+define_label_data (Dlg_head *h, Widget *paneletc, int idx, char *text,
+ buttonbarfn cback, void *data)
+{
+ WButtonBar *bb = find_buttonbar (h, paneletc);
+ if (!bb)
+ return;
+
+ set_label_text (bb, idx, text);
+ bb->labels [idx-1].function = (void (*)(void *)) cback;
+ bb->labels [idx-1].data = data;
+ x_redefine_label (bb, idx);
+}
+
+void
+define_label (Dlg_head *h, Widget *paneletc, int idx, char *text, void (*cback)(void))
+{
+ define_label_data (h, paneletc, idx, text, (void (*)(void *)) cback, 0);
+}
+
+#ifdef HAVE_X
+void redraw_labels (Dlg_head *h, Widget *paneletc)
+{
+}
+
+#else
+void
+redraw_labels (Dlg_head *h, Widget *paneletc)
+{
+ Widget_Item *item;
+ int i;
+
+ for (i = 0, item = h->current; i < h->count; i++, item = item->next){
+ if (item->widget->callback == (callback_fn) buttonbar_callback){
+ widget_redraw (h, item);
+ return;
+ }
+ }
+}
+#endif
--- /dev/null
+#ifndef __WIDGET_H
+#define __WIDGET_H
+
+#define C_BOOL 1
+#define C_CHANGE 2
+
+/* Please note that the first element in all the widgets is a */
+/* widget variable of type Widget. We abuse this fact everywhere */
+/* Widget_Items */
+
+#define HIDDEN_BUTTON 0
+#define NARROW_BUTTON 1
+#define NORMAL_BUTTON 2
+#define DEFPUSH_BUTTON 3
+
+typedef struct WButton {
+ Widget widget;
+ int action; /* what to do when pressed */
+ int selected; /* button state */
+ unsigned int flags; /* button flags */
+ char *text; /* text of button */
+ int hotkey; /* hot KEY */
+ int hotpos; /* offset hot KEY char in text */
+ int (*callback)(int, void*); /* Callback function */
+ void *callback_data;
+} WButton;
+
+typedef struct WRadio {
+ Widget widget;
+ unsigned int state; /* radio button state */
+ int pos, sel;
+ int count; /* number of members */
+ char **texts; /* texts of labels */
+ int upper_letter_is_hotkey; /* If true, then the capital letter is a hk */
+#ifdef HAVE_GNOME
+ void *first_gtk_radio;
+#endif
+} WRadio;
+
+typedef struct WCheck {
+ Widget widget;
+ unsigned int state; /* check button state */
+ char *text; /* text of check button */
+ int hotkey; /* hot KEY */
+ int hotpos; /* offset hot KEY char in text */
+} WCheck;
+
+typedef struct WGauge {
+ Widget widget;
+ int shown;
+ int max;
+ int current;
+ int pixels; /* Only used for Tk:
+ * We keep the pixel size in the C code
+ * so that we can compute quickly compute
+ * the size of the rectangle in the Tk
+ * canvas. Using Tcl would be too slow.
+ */
+} WGauge;
+
+typedef struct hist_entry {
+ struct hist_entry *prev;
+ struct hist_entry *next;
+ char *text;
+} Hist;
+
+Hist *history_get (char *input_name);
+void history_put (char *input_name, Hist *h);
+char *show_hist (Hist *history, int widget_y, int widget_x);
+
+typedef struct {
+ Widget widget;
+ int point; /* cursor position in the input line */
+ int mark; /* The mark position */
+ int first_shown; /* Index of the first shown character */
+ int current_max_len; /* Maximum length of input line */
+ int field_len; /* Length of the editing field */
+ int color; /* color used */
+ int first; /* Is first keystroke? */
+ int disable_update; /* Do we want to skip updates? */
+ int is_password; /* Is this a password input line? */
+ char *buffer; /* pointer to editing buffer */
+ Hist *history; /* The history */
+ int need_push; /* need to push the current Input on hist? */
+ char **completions; /* Possible completions array */
+ int completion_flags; /* INPUT_COMPLETE* bitwise flags(complete.h) */
+ int inserted_one; /* TK: just one char inserted, nothing fancy */
+ char *history_name; /* name of history for loading and saving */
+} WInput;
+
+/* For history load-save functions */
+#define INPUT_LAST_TEXT ((char *) 2)
+#define HISTORY_FILE_NAME ".mc/history"
+
+typedef struct {
+ Widget widget;
+ int auto_adjust_cols; /* compute widget.cols from strlen(text)? */
+ char *text;
+ int transparent; /* Paint in the default color fg/bg */
+} WLabel;
+
+typedef struct WLEntry {
+ char *text; /* Text to display */
+ int hotkey;
+ void *data; /* Client information */
+ struct WLEntry *next;
+ struct WLEntry *prev;
+} WLEntry;
+
+enum {
+ listbox_begin, listbox_end
+} /* listbox_insert */;
+
+/* Listbox actions when selecting an option: */
+enum {
+ listbox_nothing,
+ listbox_finish, /* finish dialog */
+ listbox_cback /* call the callback routine */
+} /* listbox_action */;
+
+typedef int (*lcback) (void *);
+
+typedef struct {
+ Widget widget;
+ WLEntry *list; /* Pointer to the circular double linked list. */
+ WLEntry *top; /* The first element displayed */
+ WLEntry *current; /* The current element displayed */
+ int pos; /* Cur. pos, must be kept in sync with current */
+ int count; /* Number of items in the listbox */
+ int width;
+ int height; /* Size of the widget */
+ int action; /* Action type */
+ int allow_duplicates; /* Do we allow duplicates on the list? */
+ int scrollbar; /* Draw a scrollbar? */
+ lcback cback; /* The callback function */
+ int cursor_x, cursor_y; /* Cache the values */
+} WListbox;
+
+typedef struct {
+ Widget widget;
+ int visible; /* Is it visible? */
+ struct {
+ char *text;
+ void (*function)(void *data);
+ void *data;
+ } labels [10];
+} WButtonBar;
+
+/* Constructors */
+WButton *button_new (int y, int x, int action, int flags, char *text,
+ int (*callback)(int, void *), void *extra, char *tkname);
+WRadio *radio_new (int y, int x, int count, char **text, int use_hotkey, char *tkname);
+WCheck *check_new (int y, int x, int state, char *text, char *tkname);
+WInput *input_new (int y, int x, int color, int len, char *text, char *tkname);
+WLabel *label_new (int y, int x, char *text, char *tkname);
+WGauge *gauge_new (int y, int x, int shown, int max, int current, char *tkname);
+WListbox *listbox_new (int x, int y, int width, int height, int action,
+ lcback, char *tkname);
+
+/* Input lines */
+void winput_set_origin (WInput *i, int x, int field_len);
+int handle_char (WInput *in, int c_code);
+int is_in_input_map (WInput *in, int c_code);
+void update_input (WInput *in, int clear_first);
+void new_input (WInput *in);
+int push_history (WInput *in, char *text);
+void stuff (WInput *in, char *text, int insert_extra_space);
+void input_disable_update (WInput *in);
+void input_set_prompt (WInput *in, int field_len, char *prompt);
+void input_enable_update (WInput *in);
+void input_set_point (WInput *in, int pos);
+void input_show_cursor (WInput *in);
+void assign_text (WInput *in, char *text);
+
+/* Labels */
+void label_set_text (WLabel *label, char *text);
+
+/* Gauges */
+void gauge_set_value (WGauge *g, int max, int current);
+void gauge_show (WGauge *g, int shown);
+
+/* Buttons */
+void button_set_text (WButton *b, char *text);
+
+/* Listbox manager */
+WLEntry *listbox_get_data (WListbox *l, int pos);
+
+/* search text int listbox entries */
+WLEntry *listbox_search_text (WListbox *l, char *text);
+void listbox_select_entry (WListbox *l, WLEntry *dest);
+void listbox_select_by_number (WListbox *l, int n);
+void listbox_select_last (WListbox *l, int set_top);
+void listbox_remove_current (WListbox *l, int force);
+void listbox_remove_list (WListbox *l);
+void listbox_get_current (WListbox *l, char **string, char **extra);
+
+enum append_pos {
+ LISTBOX_APPEND_AT_END, /* append at the end */
+ LISTBOX_APPEND_BEFORE, /* insert before current */
+ LISTBOX_APPEND_AFTER /* insert after current */
+};
+
+char *listbox_add_item (WListbox *l, enum append_pos pos, int
+ hotkey, char *text, void *data);
+
+/* Hintbar routines */
+
+/* Buttonbar routines */
+WButtonBar *buttonbar_new (int visible);
+typedef void (*buttonbarfn )(void *);
+typedef void (*voidfn)(void);
+void define_label (Dlg_head *, Widget *paneletc, int index, char *text, voidfn);
+void define_label_data (Dlg_head *h, Widget *paneletc, int idx, char *text,
+ buttonbarfn cback, void *data);
+void set_label_text (WButtonBar *, int, char *);
+void redraw_labels (Dlg_head *h, Widget *paneletc);
+WButtonBar *find_buttonbar (Dlg_head *h, Widget *paneletc);
+void buttonbar_hint (WButtonBar *bb, char *s);
+
+#ifdef HAVE_X
+int x_create_radio (Dlg_head *h, widget_data parent, WRadio *r);
+int x_create_button (Dlg_head *h, widget_data parent, WButton *b);
+int x_create_check (Dlg_head *h, widget_data parent, WCheck *c);
+int x_create_label (Dlg_head *h, widget_data parent, WLabel *l);
+int x_create_input (Dlg_head *h, widget_data parent, WInput *in);
+int x_create_listbox (Dlg_head *h, widget_data parent, WListbox *l);
+int x_create_buttonbar (Dlg_head *h, widget_data parent, WButtonBar *bb);
+
+void x_button_set (WButton *b, char *text);
+void x_label_set_text (WLabel *label, char *text);
+void x_listbox_select_nth (WListbox *l, int nth);
+void x_listbox_delete_nth (WListbox *l, int nth);
+void x_label_set_text (WLabel *label, char *text);
+int x_create_gauge (Dlg_head *h, widget_data parent, WGauge *g);
+void x_gauge_show (WGauge *g);
+void x_gauge_set_value (WGauge *g, int max, int current);
+void x_radio_toggle (WRadio *);
+void x_radio_focus_item (WRadio *radio);
+void x_listbox_select_nth (WListbox *, int);
+void x_list_insert (WListbox *, WLEntry *, WLEntry *);
+void x_redefine_label (WButtonBar *, int);
+void x_update_input (WInput *in);
+#endif
+
+#endif /* __WIDGET_H */
--- /dev/null
+/* Curses utilities
+ Copyright (C) 1995 Miguel de Icaza, Janne Kukonlehto
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <config.h>
+#include "tty.h"
+#include <stdio.h>
+#include <stdlib.h> /* For free() */
+#include <string.h>
+#if (!defined(__IBMC__) && !defined(__IBMCPP__)) && !defined(OS2_NT)
+# include <termios.h>
+#endif
+#include "mad.h"
+#include "color.h"
+#include "mouse.h"
+#include "util.h" /* For xmalloc() */
+
+#include "dlg.h"
+#include "widget.h"
+#include "win.h"
+#include "key.h" /* XCTRL and ALT macros */
+#include "layout.h"
+#include "global.h"
+
+/* "$Id: win.c,v 1.1 2001/12/30 09:55:20 sedwards Exp $" */
+
+typedef void (*fnptr)(void);
+
+typedef struct Fkey_Table_List {
+ fnptr actions[11];
+ struct Fkey_Table_List *next;
+ int has_labels;
+} Fkey_Table_List;
+
+static Fkey_Table_List *fkey_table_list = NULL;
+
+/* Width of output is always seven characters */
+void sprint_bytesize (char *buffer, int size, int scale)
+{
+ char scales[] = " kMGT";
+
+ if (size > 0){
+ while (size > 9999 && scale < sizeof (scales)){
+ size = (size + 512) / 1024;
+ scale ++;
+ }
+ }
+ if (scale > 0)
+ sprintf (buffer, "%4d %cb", size, scales[scale]);
+ else
+ sprintf (buffer, "%4d b ", size);
+}
+
+void print_bytesize (int size, int scale)
+{
+ char buffer [10];
+
+ sprint_bytesize (buffer, size, scale);
+ printw (buffer);
+}
+
+/* Return values: 0 = not a fkey, other = was a fkey */
+int check_fkeys (int c)
+{
+ int fkey;
+
+ if (!fkey_table_list)
+ return 0;
+
+ switch (c){
+ case KEY_F(1):
+ fkey = 1;
+ break;
+ case KEY_F(2):
+ fkey = 2;
+ break;
+ case KEY_F(3):
+ fkey = 3;
+ break;
+ case KEY_F(4):
+ fkey = 4;
+ break;
+ case KEY_F(5):
+ fkey = 5;
+ break;
+ case KEY_F(6):
+ fkey = 6;
+ break;
+ case KEY_F(7):
+ fkey = 7;
+ break;
+ case KEY_F(8):
+ fkey = 8;
+ break;
+ case KEY_F(9):
+ fkey = 9;
+ break;
+ case KEY_F(10):
+ fkey = 10;
+ break;
+ default:
+ return 0;
+ }
+ if (fkey_table_list->actions [fkey]){
+ fkey_table_list->actions [fkey] ();
+ return fkey;
+ }
+ else
+ return 0;
+}
+
+/* Return values: 0 = not a movement key, 1 = was a movement key */
+int check_movement_keys (int c, int additional, int page_size, void *data,
+ movefn backfn, movefn forfn, movefn topfn,
+ movefn bottomfn)
+{
+ switch (c){
+ case KEY_UP:
+ case XCTRL ('p'):
+ (*backfn)(data, 1);
+ return 1;
+
+ case KEY_DOWN:
+ case XCTRL ('n'):
+ (*forfn)(data, 1);
+ return 1;
+
+ case KEY_PPAGE:
+ case ALT('v'):
+ (*backfn)(data, page_size-1);
+ return 1;
+
+ case KEY_NPAGE:
+ case XCTRL('v'):
+ (*forfn)(data, page_size-1);
+ return 1;
+
+ case KEY_HOME:
+ case KEY_A1:
+ (*topfn)(data, 0);
+ return 1;
+ case KEY_END:
+ case KEY_C1:
+ (*bottomfn)(data, 0);
+ return 1;
+ }
+ if (additional)
+ switch (c){
+ case 'b':
+ case XCTRL('h'):
+ case KEY_BACKSPACE:
+ case 0177:
+ (*backfn)(data, page_size-1);
+ return 1;
+ case ' ':
+ (*forfn)(data, page_size-1);
+ return 1;
+ case 'u':
+ (*backfn)(data, page_size / 2);
+ return 1;
+ case 'd':
+ (*forfn)(data, page_size / 2);
+ return 1;
+ case 'g':
+ (*topfn)(data, 0);
+ return 1;
+ case 'G':
+ (*bottomfn)(data, 0);
+ return 1;
+ }
+ return 0;
+}
+
+void mc_raw_mode (void)
+{
+ raw ();
+}
+
+void mc_noraw_mode (void)
+{
+ noraw ();
+}
+
+/* Classification routines */
+int is_abort_char (int c)
+{
+ return (c == XCTRL('c') || c == XCTRL('g') || c == ESC_CHAR ||
+ c == KEY_F(10));
+}
+
+int is_quit_char (int c)
+{
+ return (c == XCTRL('g') || (c == ESC_CHAR) || (c == KEY_F(10)));
+}
+
+/* This table is a mapping between names and the constants we use
+ * We use this to allow users to define alternate definitions for
+ * certain keys that may be missing from the terminal database
+ */
+key_code_name_t key_name_conv_tab [] = {
+/* KEY_F(0) is not here, since we are mapping it to f10, so there is no reason
+ to define f0 as well. Also, it makes Learn keys a bunch of problems :( */
+ { KEY_F(1), "f1", N_("Function key 1") },
+ { KEY_F(2), "f2", N_("Function key 2") },
+ { KEY_F(3), "f3", N_("Function key 3") },
+ { KEY_F(4), "f4", N_("Function key 4") },
+ { KEY_F(5), "f5", N_("Function key 5") },
+ { KEY_F(6), "f6", N_("Function key 6") },
+ { KEY_F(7), "f7", N_("Function key 7") },
+ { KEY_F(8), "f8", N_("Function key 8") },
+ { KEY_F(9), "f9", N_("Function key 9") },
+ { KEY_F(10), "f10", N_("Function key 10") },
+ { KEY_F(11), "f11", N_("Function key 11") },
+ { KEY_F(12), "f12", N_("Function key 12") },
+ { KEY_F(13), "f13", N_("Function key 13") },
+ { KEY_F(14), "f14", N_("Function key 14") },
+ { KEY_F(15), "f15", N_("Function key 15") },
+ { KEY_F(16), "f16", N_("Function key 16") },
+ { KEY_F(17), "f17", N_("Function key 17") },
+ { KEY_F(18), "f18", N_("Function key 18") },
+ { KEY_F(19), "f19", N_("Function key 19") },
+ { KEY_F(20), "f20", N_("Function key 20") },
+ { KEY_BACKSPACE, "bs", N_("Backspace key") },
+ { KEY_END, "end", N_("End key") },
+ { KEY_UP, "up", N_("Up arrow key") },
+ { KEY_DOWN, "down", N_("Down arrow key") },
+ { KEY_LEFT, "left", N_("Left arrow key") },
+ { KEY_RIGHT, "right", N_("Right arrow key") },
+ { KEY_HOME, "home", N_("Home key") },
+ { KEY_NPAGE, "pgdn", N_("Page Down key") },
+ { KEY_PPAGE, "pgup", N_("Page Up key") },
+ { KEY_IC, "insert", N_("Insert key") },
+ { KEY_DC, "delete", N_("Delete key") },
+ { ALT('\t'), "complete", N_("Completion/M-tab") },
+ { KEY_KP_ADD, "kpplus", N_("+ on keypad") },
+ { KEY_KP_SUBTRACT,"kpminus", N_("- on keypad") },
+ { KEY_KP_MULTIPLY,"kpasterix", N_("* on keypad") },
+/* From here on, these won't be shown in Learn keys (no space) */
+ { KEY_LEFT, "kpleft", N_("Left arrow keypad") },
+ { KEY_RIGHT, "kpright", N_("Right arrow keypad") },
+ { KEY_UP, "kpup", N_("Up arrow keypad") },
+ { KEY_DOWN, "kpdown", N_("Down arrow keypad") },
+ { KEY_HOME, "kphome", N_("Home on keypad") },
+ { KEY_END, "kpend", N_("End on keypad") },
+ { KEY_NPAGE, "kpnpage", N_("Page Down keypad") },
+ { KEY_PPAGE, "kpppage", N_("Page Up keypad") },
+ { KEY_IC, "kpinsert", N_("Insert on keypad") },
+ { KEY_DC, "kpdelete", N_("Delete on keypad") },
+ { (int) '\n', "kpenter", N_("Enter on keypad") },
+ { (int) '/', "kpslash", N_("Slash on keypad") },
+ { (int) '#', "kpnumlock", N_("NumLock on keypad") },
+ { 0, 0 }
+ };
+
+/* Return the code associated with the symbolic name keyname */
+int lookup_key (char *keyname)
+{
+ int i;
+
+ for (i = 0; key_name_conv_tab [i].code; i++){
+ if (strcasecmp (key_name_conv_tab [i].name, keyname))
+ continue;
+ return key_name_conv_tab [i].code;
+ }
+ return 0;
+}
+
--- /dev/null
+#ifndef __WIN_H
+#define __WIN_H
+
+/* Window utilities */
+#include "dlg.h"
+
+void print_bytesize (int size, int scale);
+void sprint_bytesize (char *buffer, int size, int scale);
+
+/* Labels at the screen bottom */
+
+/* Keys managing */
+int check_fkeys (int c);
+int check_movement_keys (int c, int additional, int page_size, void *,
+ movefn backfn, movefn forfn, movefn topfn, movefn bottomfn);
+int lookup_key (char *keyname);
+
+/* Terminal managing */
+extern int xterm_flag;
+void do_enter_ca_mode (void);
+void do_exit_ca_mode (void);
+#define wclr(w) wclrn(w, 0)
+
+void mc_raw_mode (void);
+void mc_noraw_mode (void);
+void mc_init_cbreak (void);
+#endif /* __WIN_H */
--- /dev/null
+/* {{{ */
+
+/* {{{ Copyright Notice */
+
+/* Widget based utility functions.
+ Copyright (C) 1994, 1995 the Free Software Foundation
+
+ Authors: 1994, 1995, 1996 Miguel de Icaza
+ 1994, 1995 Radek Doulik
+ 1995 Jakub Jelinek
+ 1995 Andrej Borsenkow
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+/* }}} */
+
+/* [] = "$Id: wtools.c,v 1.1 2001/12/30 09:55:20 sedwards Exp $" */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+#include <malloc.h>
+#include "tty.h"
+#include <stdarg.h>
+#include "mad.h"
+#include "global.h"
+#include "util.h"
+#include "win.h"
+#include "color.h"
+#include "mouse.h"
+#include "dlg.h"
+#include "widget.h"
+#include "menu.h"
+#include "wtools.h"
+#include "key.h" /* For mi_getch() */
+#include "dialog.h" /* For do_refresh() and my_wputs() */
+#include "complete.h" /* INPUT_COMPLETE_CD */
+#include "x.h"
+
+/* }}} */
+
+/* {{{ Common dialog callback */
+#ifdef HAVE_X
+void dialog_repaint (struct Dlg_head *h, int back, int title_fore)
+{
+}
+#else
+void
+dialog_repaint (struct Dlg_head *h, int back, int title_fore)
+{
+ attrset (back);
+ dlg_erase (h);
+ draw_box (h, 1, 1, h->lines - 2, h->cols - 2);
+ attrset (title_fore);
+ if (h->title){
+ dlg_move (h, 1, (h->cols-strlen (h->title))/2);
+ addstr (h->title);
+ }
+}
+#endif
+void
+common_dialog_repaint (struct Dlg_head *h)
+{
+ dialog_repaint (h, COLOR_NORMAL, COLOR_HOT_NORMAL);
+}
+
+int
+common_dialog_callback (struct Dlg_head *h, int id, int msg)
+{
+ if (msg == DLG_DRAW)
+ common_dialog_repaint (h);
+ return 0;
+}
+
+/* }}} */
+/* {{{ Listbox utility functions */
+
+void
+listbox_refresh (Dlg_head *h)
+{
+ dialog_repaint (h, COLOR_NORMAL, COLOR_HOT_NORMAL);
+}
+
+static int listbox_callback (Dlg_head *h, int id, int msg)
+{
+ switch (msg) {
+ case DLG_DRAW:
+#ifndef HAVE_X
+ listbox_refresh(h);
+#endif
+ return 1;
+ }
+ return 0;
+}
+
+Listbox *create_listbox_window (int cols, int lines, char *title, char *help)
+{
+ int xpos, ypos, len;
+ Listbox *listbox = xmalloc (sizeof (Listbox), "create_listbox_window");
+ char* cancel_string = _("&Cancel");
+
+ /* Adjust sizes */
+ lines = (lines > LINES-6) ? LINES - 6 : lines;
+
+ if (title && (cols < (len = strlen(title) + 2)))
+ cols = len;
+
+ /* no &, but 4 spaces around button for brackets and such */
+ if (cols < (len = strlen(cancel_string) + 3))
+ cols = len;
+
+ cols = cols > COLS-6 ? COLS-6 : cols;
+
+ /* I'm not sure if this -2 is safe, should test it */
+ xpos = (COLS-cols)/2;
+ ypos = (LINES-lines)/2 - 2;
+
+ /* Create components */
+ listbox->dlg = create_dlg (ypos, xpos, lines+6, cols+4, dialog_colors,
+ listbox_callback, help, "listbox", DLG_CENTER|DLG_GRID);
+ x_set_dialog_title (listbox->dlg, title);
+
+ listbox->list = listbox_new (2, 2, cols, lines, listbox_finish, 0, "li");
+
+ add_widget (listbox->dlg,
+ button_new (lines+3, (cols/2 + 2) - len/2,
+ B_CANCEL, NORMAL_BUTTON, cancel_string, 0, 0, "c"));
+ add_widget (listbox->dlg, listbox->list);
+#ifndef HAVE_X
+ listbox_refresh(listbox->dlg);
+#endif /* !HAVE_X */
+ return listbox;
+}
+
+/* Returns the number of the item selected */
+int run_listbox (Listbox *l)
+{
+ int val;
+
+ run_dlg (l->dlg);
+ if (l->dlg->ret_value == B_CANCEL)
+ val = -1;
+ else
+ val = l->list->pos;
+ destroy_dlg (l->dlg);
+ free (l);
+ return val;
+}
+
+/* }}} */
+
+
+/* {{{ Query Dialog functions */
+#ifndef HAVE_GNOME
+struct text_struct {
+ char *text;
+ char *header;
+};
+
+static int query_callback (struct Dlg_head *h, int Id, int Msg)
+{
+ struct text_struct *info;
+
+ info = (struct text_struct *) h->data;
+
+ switch (Msg){
+#ifndef HAVE_X
+ case DLG_DRAW:
+ /* designate window */
+ attrset (NORMALC);
+ dlg_erase (h);
+ draw_box (h, 1, 1, h->lines-2, h->cols-2);
+ attrset (HOT_NORMALC);
+ dlg_move (h, 1, (h->cols-strlen (info->header))/2);
+ addstr (info->header);
+ break;
+#endif
+ }
+ return 0;
+}
+
+
+Dlg_head *last_query_dlg;
+
+static int sel_pos = 0;
+
+/* Used to ask questions to the user */
+int query_dialog (char *header, char *text, int flags, int count, ...)
+{
+ va_list ap;
+ Dlg_head *query_dlg;
+ int win_len = 0;
+ int i;
+ int result = -1;
+ int xpos, ypos;
+ int cols, lines;
+ char *cur_name;
+ static int query_colors [4];
+ static struct text_struct pass;
+#ifdef HAVE_X
+ static char *buttonnames [10];
+#endif
+
+ /* set dialog colors */
+ query_colors [0] = (flags & D_ERROR) ? ERROR_COLOR : Q_UNSELECTED_COLOR;
+ query_colors [1] = (flags & D_ERROR) ? REVERSE_COLOR : Q_SELECTED_COLOR;
+ query_colors [2] = (flags & D_ERROR) ? ERROR_COLOR : COLOR_HOT_NORMAL;
+ query_colors [3] = (flags & D_ERROR) ? COLOR_HOT_NORMAL : COLOR_HOT_FOCUS;
+
+ if (header == MSG_ERROR)
+ header = _(" Error ");
+
+ if (count > 0){
+ va_start (ap, count);
+ for (i = 0; i < count; i++)
+ {
+ char* cp = va_arg (ap, char *);
+ win_len += strlen (cp) + 6;
+ if (strchr (cp, '&') != NULL)
+ win_len--;
+ }
+ va_end (ap);
+ }
+
+ /* count coordinates */
+ cols = 6 + max (win_len, max (strlen (header), msglen (text, &lines)));
+ lines += 4 + (count > 0 ? 2 : 0);
+ xpos = COLS/2 - cols/2;
+ ypos = LINES/3 - (lines-3)/2;
+ pass.header = header;
+ pass.text = text;
+
+ /* prepare dialog */
+ query_dlg = create_dlg (ypos, xpos, lines, cols, query_colors,
+ query_callback, "[QueryBox]", "query", DLG_NONE);
+ x_set_dialog_title (query_dlg, header);
+
+ /* The data we need to pass to the callback */
+ query_dlg->cols = cols;
+ query_dlg->lines = lines;
+ query_dlg->data = &pass;
+
+ query_dlg->direction = DIR_BACKWARD;
+
+ if (count > 0){
+
+ cols = (cols-win_len-2)/2+2;
+ va_start (ap, count);
+ for (i = 0; i < count; i++){
+ cur_name = va_arg (ap, char *);
+ xpos = strlen (cur_name)+6;
+ if (strchr(cur_name, '&') != NULL)
+ xpos--;
+#ifndef HAVE_XVIEW
+ add_widget (query_dlg, button_new
+ (lines-3, cols, B_USER+i, NORMAL_BUTTON, cur_name,
+ 0, 0, NULL));
+#else
+ buttonnames [i] = cur_name;
+#endif
+ cols += xpos;
+ if (i == sel_pos)
+ query_dlg->initfocus = query_dlg->current;
+ }
+ va_end (ap);
+
+#ifdef HAVE_XVIEW
+ for (i = count - 1; i >= 0; i--)
+ add_widgetl (query_dlg, button_new
+ (0, 0, B_USER+i, NORMAL_BUTTON, buttonnames [i], 0, 0, NULL),
+ i ? XV_WLAY_RIGHTOF : XV_WLAY_CENTERROW);
+#endif
+ add_widget (query_dlg, label_new (2, 3, text, NULL));
+
+ /* run dialog and make result */
+ run_dlg (query_dlg);
+ switch (query_dlg->ret_value){
+ case B_CANCEL:
+ break;
+ default:
+ result = query_dlg->ret_value-B_USER;
+ }
+
+ /* free used memory */
+ destroy_dlg (query_dlg);
+ } else {
+#ifdef HAVE_X
+ add_widgetl (query_dlg, button_new(0, 0, B_EXIT, NORMAL_BUTTON, _("&Ok"), 0, 0, NULL),
+ XV_WLAY_CENTERROW);
+
+ add_widget (query_dlg, label_new (2, 3, text, NULL));
+#ifdef HAVE_TK
+ if (flags & D_INSERT){
+ } else
+#endif
+ {
+ run_dlg (query_dlg);
+ destroy_dlg (query_dlg);
+ }
+#else
+ add_widget (query_dlg, label_new (2, 3, text, NULL));
+ add_widget (query_dlg, button_new(0, 0, 0, HIDDEN_BUTTON, "-", 0, 0, NULL));
+#endif /* HAVE_X */
+ last_query_dlg = query_dlg;
+ }
+ sel_pos = 0;
+ return result;
+}
+
+void query_set_sel (int new_sel)
+{
+ sel_pos = new_sel;
+}
+
+/* }}} */
+
+/* {{{ The message function */
+
+/* To show nice messages to the users */
+Dlg_head *message (int error, char *header, char *text, ...)
+{
+ va_list args;
+ char buffer [4096];
+ Dlg_head *d;
+
+ /* Setup the display information */
+ strcpy (buffer, "\n");
+ va_start (args, text);
+ vsprintf (&buffer [1], text, args);
+ strcat (buffer, "\n");
+ va_end (args);
+
+ query_dialog (header, buffer, error, 0);
+#ifndef HAVE_XVIEW
+ d = last_query_dlg;
+#ifdef HAVE_TK
+ if (error & D_INSERT){
+ init_dlg (d);
+ tk_dispatch_all ();
+ return d;
+ }
+#else
+ init_dlg (d);
+ if (!(error & D_INSERT)){
+ mi_getch ();
+ dlg_run_done (d);
+ destroy_dlg (d);
+ } else
+ return d;
+#endif
+#endif
+ return 0;
+}
+#endif
+/* }}} */
+
+/* {{{ The chooser routines */
+
+static int remove_callback (int i, void *data)
+{
+ Chooser *c = (Chooser *) data;
+
+ listbox_remove_current (c->listbox, 0);
+
+ dlg_select_widget (c->dialog, c->listbox);
+ dlg_select_nth_widget (c->dialog, 0);
+
+ /* Return: do not abort dialog */
+ return 0;
+}
+
+Chooser *new_chooser (int lines, int cols, char *help, int flags)
+{
+ Chooser *c;
+ int button_lines;
+
+ c = (Chooser *) xmalloc (sizeof (Chooser), "new_chooser");
+ c->dialog = create_dlg (0, 0, lines, cols, dialog_colors, common_dialog_callback,
+ help, "chooser", DLG_CENTER | DLG_GRID);
+
+ c->dialog->lines = lines;
+ c->dialog->cols = cols;
+
+ button_lines = flags & CHOOSE_EDITABLE ? 3 : 0;
+
+ c->listbox = listbox_new (1, 1, cols-2, lines-button_lines,
+ listbox_finish, 0, "listbox");
+
+ if (button_lines){
+ add_widget (c->dialog, button_new (lines-button_lines+1,
+ 20, B_ENTER, DEFPUSH_BUTTON, _("&Remove"),
+ remove_callback, c, "button-remove"));
+ add_widget (c->dialog, button_new (lines-button_lines+1,
+ 4, B_CANCEL, NORMAL_BUTTON, _("&Cancel"),
+ 0, 0, "button-cancel"));
+ }
+ add_widget (c->dialog, c->listbox);
+ return c;
+}
+
+int run_chooser (Chooser *c)
+{
+ run_dlg (c->dialog);
+ return c->dialog->ret_value;
+}
+
+void destroy_chooser (Chooser *c)
+{
+ destroy_dlg (c->dialog);
+}
+
+/* }}} */
+
+/* {{{ Quick dialog routines */
+
+static int quick_callback (struct Dlg_head *h, int id, int Msg)
+{
+ switch (Msg){
+#ifndef HAVE_X
+ case DLG_DRAW:
+ attrset (COLOR_NORMAL);
+ dlg_erase (h);
+ draw_box (h, 1, 1, h->lines-2, h->cols-2);
+
+ attrset (COLOR_HOT_NORMAL);
+ dlg_move (h, 1,((h->cols-strlen (h->data))/2));
+ addstr (h->data);
+ break;
+#endif
+ case DLG_KEY:
+ if (id == '\n'){
+ h->ret_value = B_ENTER;
+ dlg_stop (h);
+ break;
+ }
+ }
+ return 0;
+}
+
+#define I18N(x) (do_int && *x ? (x = _(x)): x)
+
+int quick_dialog_skip (QuickDialog *qd, int nskip)
+{
+ Dlg_head *dd;
+ void *widget;
+ WRadio *r;
+ int xpos;
+ int ypos;
+ int return_val;
+ WInput *input;
+ QuickWidget *qw;
+ int do_int;
+
+ if (!qd->i18n){
+ qd->i18n = 1;
+ do_int = 1;
+ if (*qd->title)
+ qd->title = _(qd->title);
+ } else
+ do_int = 0;
+
+ if (qd->xpos == -1)
+ dd = create_dlg (0, 0, qd->ylen, qd->xlen, dialog_colors, quick_callback,
+ qd->help, qd->class, DLG_CENTER | DLG_TRYUP | DLG_GRID);
+ else
+ dd = create_dlg (qd->ypos, qd->xpos, qd->ylen, qd->xlen, dialog_colors,
+ quick_callback,
+ qd->help, qd->class, DLG_GRID);
+
+ x_set_dialog_title (dd, qd->title);
+
+ /* We pass this to the callback */
+ dd->cols = qd->xlen;
+ dd->lines = qd->ylen;
+ dd->data = qd->title;
+
+ for (qw = qd->widgets; qw->widget_type; qw++){
+#ifdef HAVE_X
+ xpos = ypos = 0;
+#else
+ xpos = (qd->xlen * qw->relative_x)/qw->x_divisions;
+ ypos = (qd->ylen * qw->relative_y)/qw->y_divisions;
+#endif
+
+ switch (qw->widget_type){
+ case quick_checkbox:
+ widget = check_new (ypos, xpos, *qw->result, I18N (qw->text), qw->tkname);
+ break;
+
+ case quick_radio:
+ r = radio_new (ypos, xpos, qw->hotkey_pos, qw->str_result, 1, qw->tkname);
+ r->pos = r->sel = qw->value;
+ widget = r;
+ break;
+
+ case quick_button:
+ widget = button_new (ypos, xpos, qw->value, (qw->value==B_ENTER) ? DEFPUSH_BUTTON : NORMAL_BUTTON,
+ I18N (qw->text), 0, 0, qw->tkname);
+ break;
+
+ /* We use the hotkey pos as the field length */
+ case quick_input:
+ input = input_new (ypos, xpos, INPUT_COLOR,
+ qw->hotkey_pos, qw->text, qw->tkname);
+ input->is_password = qw->value == 1;
+ input->point = 0;
+ if (qw->value & 2)
+ input->completion_flags |= INPUT_COMPLETE_CD;
+ widget = input;
+ break;
+
+ case quick_label:
+ widget = label_new (ypos, xpos, I18N(qw->text), qw->tkname);
+ break;
+
+ default:
+ widget = 0;
+ fprintf (stderr, "QuickWidget: unknown widget type\n");
+ break;
+ }
+ qw->the_widget = widget;
+ add_widgetl (dd, widget, qw->layout);
+ }
+
+ while (nskip--)
+ dd->current = dd->current->next;
+
+ run_dlg (dd);
+
+ /* Get the data if we found something interesting */
+ if (dd->ret_value != B_CANCEL){
+ for (qw = qd->widgets; qw->widget_type; qw++){
+ switch (qw->widget_type){
+ case quick_checkbox:
+ *qw->result = ((WCheck *) qw->the_widget)->state & C_BOOL;
+ break;
+
+ case quick_radio:
+ *qw->result = ((WRadio *) qw->the_widget)->sel;
+ break;
+
+ case quick_input:
+ *qw->str_result = strdup (((WInput *) qw->the_widget)->buffer);
+ break;
+ }
+ }
+ }
+ return_val = dd->ret_value;
+ destroy_dlg (dd);
+
+ return return_val;
+}
+
+int quick_dialog (QuickDialog *qd)
+{
+ return quick_dialog_skip (qd, 0);
+}
+
+/* }}} */
+
+/* {{{ Input routines */
+#define INPUT_INDEX 2
+char *real_input_dialog_help (char *header, char *text, char *help, char *def_text)
+{
+ QuickDialog Quick_input;
+ QuickWidget quick_widgets [] = {
+ { quick_button, 6, 10, 1, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
+ XV_WLAY_RIGHTOF, "button-cancel" },
+ { quick_button, 3, 10, 1, 0, N_("&Ok"), 0, B_ENTER, 0, 0,
+ XV_WLAY_CENTERROW, "button-ok" },
+ { quick_input, 4, 80, 0, 0, "", 58, 0, 0, 0, XV_WLAY_NEXTROW, 0 },
+ { quick_label, 3, 80, 2, 0, "", 0, 0, 0, 0, XV_WLAY_NEXTROW, "label" },
+ { 0 } };
+
+ int len;
+ int i;
+ int lines;
+ char *my_str;
+ char tk_name[64] = "inp|";
+
+/* we need a unique name for tkname because widget.c:history_tool()
+ needs a unique name for each dialog - using the header is ideal */
+
+#ifdef HAVE_GNOME
+ strncpy (tk_name + 4, header, 59);
+#else
+ strncpy (tk_name + 3, header, 60);
+#endif
+ tk_name[63] = '\0';
+ quick_widgets[2].tkname = tk_name;
+
+ len = max (strlen (header), msglen (text, &lines)) + 4;
+ len = max (len, 64);
+
+ if (strncmp (text, _("Password:"), strlen (_("Password"))) == 0){
+ quick_widgets [INPUT_INDEX].value = 1;
+ tk_name[3]=0;
+ } else {
+ quick_widgets [INPUT_INDEX].value = 0;
+ }
+
+#ifdef ENABLE_NLS
+ /*
+ * An attempt to place buttons symmetrically, based on actual i18n
+ * length of the string. It looks nicer with i18n (IMO) - alex
+ */
+ quick_widgets [0].relative_x = len/2 + 4;
+ quick_widgets [1].relative_x =
+ len/2 - (strlen (_(quick_widgets [1].text)) + 9);
+ quick_widgets [0].x_divisions = quick_widgets [1].x_divisions = len;
+#endif /* ENABLE_NLS */
+
+ Quick_input.xlen = len;
+ Quick_input.xpos = -1;
+ Quick_input.title = header;
+ Quick_input.help = help;
+ Quick_input.class = "quick_input";
+ Quick_input.i18n = 0;
+ quick_widgets [INPUT_INDEX+1].text = text;
+ quick_widgets [INPUT_INDEX].text = def_text;
+
+ for (i = 0; i < 4; i++)
+ quick_widgets [i].y_divisions = lines+6;
+ Quick_input.ylen = lines + 6;
+
+ for (i = 0; i < 3; i++)
+ quick_widgets [i].relative_y += 2 + lines;
+
+ quick_widgets [INPUT_INDEX].str_result = &my_str;
+
+ Quick_input.widgets = quick_widgets;
+ if (quick_dialog (&Quick_input) != B_CANCEL){
+ return *(quick_widgets [INPUT_INDEX].str_result);
+ } else
+ return 0;
+}
+
+char *input_dialog (char *header, char *text, char *def_text)
+{
+ return input_dialog_help (header, text, "[Input Line Keys]", def_text);
+}
+
+int input_dialog_help_2 (char *header, char *text1, char *text2, char *help, char **r1, char **r2)
+{
+ QuickDialog Quick_input;
+ QuickWidget quick_widgets [] = {
+ { quick_button, 6, 10, 4, 0, N_("&Cancel"), 0, B_CANCEL, 0, 0,
+ XV_WLAY_DONTCARE, "button-cancel" },
+ { quick_button, 3, 10, 4, 0, N_("Ok")
+, 0, B_ENTER, 0, 0,
+ XV_WLAY_DONTCARE, "button-ok" },
+ { quick_input, 4, 80, 4, 0, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-pth" },
+ { quick_label, 3, 80, 3, 0, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-pth" },
+ { quick_input, 4, 80, 3, 0, "", 58, 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-lbl" },
+ { quick_label, 3, 80, 2, 0, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "label-lbl" },
+ { 0 } };
+
+ int len;
+ int i;
+ int lines1, lines2;
+ char *my_str1, *my_str2;
+
+ len = max (strlen (header), msglen (text1, &lines1));
+ len = max (len, msglen (text2, &lines2)) + 4;
+ len = max (len, 64);
+
+ Quick_input.xlen = len;
+ Quick_input.xpos = -1;
+ Quick_input.title = header;
+ Quick_input.help = help;
+ Quick_input.class = "quick_input_2";
+ Quick_input.i18n = 0;
+ quick_widgets [5].text = text1;
+ quick_widgets [3].text = text2;
+
+ for (i = 0; i < 6; i++)
+ quick_widgets [i].y_divisions = lines1+lines2+7;
+ Quick_input.ylen = lines1 + lines2 + 7;
+
+ quick_widgets [0].relative_y += (lines1 + lines2);
+ quick_widgets [1].relative_y += (lines1 + lines2);
+ quick_widgets [2].relative_y += (lines1);
+ quick_widgets [3].relative_y += (lines1);
+
+ quick_widgets [4].str_result = &my_str1;
+ quick_widgets [2].str_result = &my_str2;
+
+ Quick_input.widgets = quick_widgets;
+ if (quick_dialog (&Quick_input) != B_CANCEL){
+ *r1 = *(quick_widgets [4].str_result);
+ *r2 = *(quick_widgets [2].str_result);
+ return 1;
+ } else
+ return 0;
+}
+
+int input_dialog_2 (char *header, char *text1, char *text2, char **r1, char **r2)
+{
+ return input_dialog_help_2 (header, text1, text2, "[Input Line Keys]", r1, r2);
+}
+
+char *input_expand_dialog (char *header, char *text, char *def_text)
+{
+ char *result;
+ char *expanded;
+
+ result = input_dialog (header, text, def_text);
+ if (result){
+ expanded = tilde_expand (result);
+ if (expanded){
+ free (result);
+ return expanded;
+ } else
+ return result;
+ }
+ return result;
+}
+
+/* }}} */
+
+/* }}} */
+/*
+ Cause emacs to enter folding mode for this file:
+ Local variables:
+ end:
+*/
--- /dev/null
+#ifndef __WTOOLS_H
+#define __WTOOLS_H
+
+/* Dialog default background repaint routines */
+void dialog_repaint (struct Dlg_head *h, int back, int title_fore);
+void common_dialog_repaint (struct Dlg_head *h);
+
+/* For common dialogs, just repaint background */
+int common_dialog_callback (struct Dlg_head *h, int id, int msg);
+
+/* Listbox utility functions */
+typedef struct {
+ Dlg_head *dlg;
+ WListbox *list;
+} Listbox;
+
+Listbox *create_listbox_window (int cols, int lines, char *title, char *help);
+#define LISTBOX_APPEND_TEXT(l,h,t,d) \
+ listbox_add_item (l->list, 0, h, t, d);
+
+int run_listbox (Listbox *l);
+
+/* Quick Widgets */
+enum {
+ quick_end, quick_checkbox,
+ quick_button, quick_input,
+ quick_label, quick_radio
+} /* quick_t */;
+
+/* The widget is placed on relative_?/divisions_? of the parent widget */
+/* Please note that the contents of the fields in the union are just */
+/* used for setting up the dialog. They are a convenient place to put */
+/* the values for a widget */
+
+typedef struct {
+ int widget_type;
+ int relative_x;
+ int x_divisions;
+ int relative_y;
+ int y_divisions;
+
+ char *text; /* Text */
+ int hotkey_pos; /* the hotkey position */
+ int value; /* Buttons only: value of button */
+ int *result; /* Checkbutton: where to store result */
+ char **str_result; /* Input lines: destination */
+ WLay layout; /* XView Layouting stuff */
+ char *tkname; /* Name of the widget used for Tk only */
+ void *the_widget; /* For the quick quick dialog manager */
+} QuickWidget;
+
+typedef struct {
+ int xlen, ylen;
+ int xpos, ypos; /* if -1, then center the dialog */
+ char *title;
+ char *help;
+ char *class; /* Used for Tk's class name */
+ QuickWidget *widgets;
+ int i18n; /* If true, internationalization has happened */
+} QuickDialog;
+
+int quick_dialog (QuickDialog *qd);
+int quick_dialog_skip (QuickDialog *qd, int nskip);
+
+/* Choosers */
+
+#define CHOOSE_EDITABLE 1
+#define CHOOSE_BROWSE 0
+
+/* Chooser dialog boxes */
+typedef struct {
+ Dlg_head *dialog;
+ WListbox *listbox;
+} Chooser;
+
+Chooser *new_chooser (int lines, int cols, char *help, int flags);
+int run_chooser (Chooser *c);
+void destroy_chooser (Chooser *c);
+
+/* The input dialogs */
+char *input_dialog (char *header, char *text, char *def_text);
+int input_dialog_2 (char *header, char *text1, char *text2, char **r1, char **r2);
+char *input_dialog_help (char *header, char *text, char *help, char *def_text);
+char *input_expand_dialog (char *header, char *text, char *def_text);
+char *real_input_dialog (char *header, char *text, char *def_text);
+char *real_input_dialog_help (char *header, char *text, char *help, char *def_text);
+
+void query_set_sel (int new_sel);
+#endif /* __WTOOLS_H */
--- /dev/null
+
+#ifndef HAVE_X
+# include "textconf.h"
+#endif
+
+#ifdef HAVE_XVIEW
+# include "xvconf.h"
+# include "xvmain.h"
+#endif
+
+#ifdef HAVE_TK
+# include "tkconf.h"
+# include "tkmain.h"
+# include "tkwidget.h"
+# include "tkscreen.h"
+#endif
+
+#ifdef HAVE_GNOME
+# include <gnome.h>
+# include "gconf.h"
+# undef MIN
+# undef MAX
+# include "gmain.h"
+#endif
+
--- /dev/null
+/* Glue code to run with bsd curses.
+ Copyright (C) 1994 Miguel de Icaza
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ */
+
+#include <config.h>
+#include "tty.h"
+
+int has_colors (void)
+{
+ return 0;
+}
+
+int init_pair (int pair, int fore, int back)
+{
+ return 0;
+}
+
+int start_color ()
+{
+ return 0;
+}
+
+#ifndef SUNOS_CURSES
+void hline (int character, int len)
+{
+ int i, x, y;
+
+ getyx (stdscr, y, x);
+ while (len--)
+ addch (character);
+ move(y, x);
+}
+
+void vline (int character, int len)
+{
+ int i, x, y;
+
+ getyx (stdscr, y, x);
+ while (len--)
+ mvaddch (y++, x, character);
+}
+#endif
+
--- /dev/null
+#!/bin/sh
+# mkinstalldirs --- make directory hierarchy
+# Author: Noah Friedman <friedman@prep.ai.mit.edu>
+# Created: 1993-05-16
+# Last modified: 1994-03-25
+# Public domain
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
+ shift
+
+ pathcomp=
+ for d in ${1+"$@"} ; do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ esac
+
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "$pathcomp" || errstatus=$?
+ fi
+
+ pathcomp="$pathcomp/"
+ done
+done
+
+exit $errstatus
+
+# mkinstalldirs ends here
--- /dev/null
+/* Routines expected by the Midnight Commander
+
+ Copyright (C) 1999 The Free Software Foundation.
+
+ Author Miguel de Icaza
+
+ FIXME: This expects the user to always use slang instead of ncurses.
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ This file just has dummy procedures that don't do nothing under X11
+ editions. I will make macros once I feel right with the Tk edition.
+
+ */
+
+#include <stdio.h>
+
+int
+interrupts_enabled (void) { return 0; }
+
+void
+enable_interrupt_key(void) {}
+
+void
+disable_interrupt_key(void) {}
+
+/* FIXME: We could provide a better way of doing this */
+int
+got_interrupt () { return 0; }
+
+void
+slang_init (void) {}
+
+void
+slang_set_raw_mode (void) {}
+
+void
+slang_prog_mode (void) {}
+
+void
+slang_shell_mode (void) {}
+
+void
+slang_shutdown () {}
+
+void
+slang_keypad (int set) {}
+
+void
+set_slang_delay (int v) {}
+
+void
+hline (int ch, int len) {}
+
+void
+vline (int character, int len) {}
+
+#ifndef HAVE_GNOME
+void
+init_pair (int index, char *foreground, char *background) {}
+#endif
+
+int has_colors ()
+{
+ return 1;
+}
+
+void
+attrset (int color) { }
+
+void
+do_define_key (int code, char *strcap) {}
+
+void
+load_terminfo_keys () {}
+
+int
+getch ()
+{
+ return getchar ();
+}
+
+void
+mc_refresh (void)
+{
+}
--- /dev/null
+#define VERSION "@VERSION@"
--- /dev/null
+/* Declarations for the extfs.
+
+ Copyright (C) 1995 The Free Software Foundation
+
+ Written by: 1995 Jakub Jelinek
+
+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 2, or (at your option)
+any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <sys/types.h>
+
+struct extfs_inode;
+
+struct extfs_entry {
+ int has_changed;
+ struct extfs_entry *next_in_dir;
+ struct extfs_entry *dir;
+ char *name;
+ struct extfs_inode *inode;
+};
+
+struct extfs_archive;
+
+struct extfs_inode {
+ int has_changed;
+ nlink_t nlink;
+ struct extfs_entry *first_in_subdir; /* only used if this is a directory */
+ struct extfs_entry *last_in_subdir;
+ ino_t inode; /* This is inode # */
+ dev_t dev; /* This is an internal identification of the extfs archive */
+ struct extfs_archive *archive; /* And this is an archive structure */
+ dev_t rdev;
+ umode_t mode;
+ uid_t uid;
+ gid_t gid;
+ int size;
+ time_t mtime;
+ char linkflag;
+ char *linkname;
+ time_t atime;
+ time_t ctime;
+ char *local_filename;
+};
+
+struct extfs_archive {
+ int fstype;
+ char *name;
+ char *local_name;
+ struct stat extfsstat;
+ struct stat local_stat;
+ dev_t rdev;
+ int fd_usage;
+ ino_t __inode_counter;
+ struct extfs_entry *root_entry;
+ struct extfs_entry *current_dir;
+ struct extfs_archive *next;
+};
+
+void extfs_init (void);
+void extfs_fill_names (void (*func)(char *));
+int extfs_prefix_to_type (char *path);
+char *extfs_get_prefix (int fstype);
+char *extfs_analysis (char *path, char **arc_name, int *fstype, int is_dir);
+void extfs_run (char *path);
+void extfs_done (void);
--- /dev/null
+#ifndef __VFS_H
+#define __VFS_H
+
+#if !defined(_MSC_VER)
+#if !defined(SCO_FLAVOR) || !defined(_SYS_SELECT_H)
+# include <sys/time.h> /* alex: this redefines struct timeval */
+#endif /* SCO_FLAVOR */
+#else
+#include <time.h>
+#endif
+
+#ifdef HAVE_UTIME_H
+# include <utime.h>
+#else
+struct utimbuf {
+ time_t actime;
+ time_t modtime;
+};
+#endif
+
+#ifdef USE_VFS
+
+#ifdef HAVE_MMAP
+#include <sys/mman.h>
+#endif
+
+ /* Our virtual file system layer */
+
+ typedef void * vfsid;
+
+ struct vfs_stamping;
+
+ typedef struct {
+ void *(*open)(char *fname, int flags, int mode);
+ int (*close)(void *vfs_info);
+ int (*read)(void *vfs_info, char *buffer, int count);
+ int (*write)(void *vfs_info, char *buf, int count);
+
+ void *(*opendir)(char *dirname);
+ void *(*readdir)(void *vfs_info);
+ int (*closedir)(void *vfs_info);
+
+ int (*stat)(char *path, struct stat *buf);
+ int (*lstat)(char *path, struct stat *buf);
+ int (*fstat)(void *vfs_info, struct stat *buf);
+
+ int (*chmod)(char *path, int mode);
+ int (*chown)(char *path, int owner, int group);
+ int (*utime)(char *path, struct utimbuf *times);
+
+ int (*readlink)(char *path, char *buf, int size);
+ int (*symlink)(char *n1, char *n2);
+ int (*link)(char *p1, char *p2);
+ int (*unlink)(char *path);
+ int (*rename)(char *p1, char *p2);
+ int (*chdir)(char *path);
+ int (*ferrno)(void);
+ int (*lseek)(void *vfs_info, off_t offset, int whence);
+ int (*mknod)(char *path, int mode, int dev);
+
+ vfsid (*getid)(char *path, struct vfs_stamping **parent);
+ int (*nothingisopen)(vfsid id);
+ void (*free)(vfsid id);
+
+ char *(*getlocalcopy)(char *filename);
+ void (*ungetlocalcopy)(char *filename, char *local, int has_changed);
+
+ int (*mkdir)(char *path, mode_t mode);
+ int (*rmdir)(char *path);
+
+ int (*ctl)(void *vfs_info, int ctlop, int arg);
+ int (*setctl)(char *path, int ctlop, char *arg);
+ void (*forget_about)(char *path);
+#ifdef HAVE_MMAP
+ caddr_t (*mmap)(caddr_t addr, size_t len, int prot, int flags, void *vfs_info, off_t offset);
+ int (*munmap)(caddr_t addr, size_t len, void *vfs_info);
+#endif
+ } vfs;
+
+ /* Other file systems */
+ extern vfs local_vfs_ops;
+ extern vfs tarfs_vfs_ops;
+
+ extern vfs ftpfs_vfs_ops;
+ extern vfs mcfs_vfs_ops;
+
+ extern vfs extfs_vfs_ops;
+
+ extern vfs undelfs_vfs_ops;
+
+ struct vfs_stamping {
+ vfs *v;
+ vfsid id;
+ struct vfs_stamping *parent; /* At the moment applies to tarfs only */
+ struct vfs_stamping *next;
+ struct timeval time;
+ };
+
+ void vfs_init (void);
+ void vfs_shut (void);
+
+ extern int vfs_type_absolute;
+ vfs *vfs_type (char *path);
+ vfsid vfs_ncs_getid (vfs *nvfs, char *dir, struct vfs_stamping **par);
+ void vfs_rm_parents (struct vfs_stamping *stamp);
+ char *vfs_path (char *path);
+ char *vfs_canon (char *path);
+ char *mc_get_current_wd (char *buffer, int bufsize);
+ int vfs_current_is_local (void);
+ int vfs_current_is_extfs (void);
+ int vfs_current_is_tarfs (void);
+ int vfs_file_is_local (char *name);
+ int vfs_file_is_ftp (char *filename);
+ char *vfs_get_current_dir (void);
+
+ void vfs_stamp (vfs *, vfsid);
+ void vfs_rmstamp (vfs *, vfsid, int);
+ void vfs_addstamp (vfs *, vfsid, struct vfs_stamping *);
+ void vfs_add_noncurrent_stamps (vfs *, vfsid, struct vfs_stamping *);
+ void vfs_add_current_stamps (void);
+ void vfs_free_resources(char *path);
+ void vfs_timeout_handler ();
+ int vfs_timeouts ();
+ void vfs_force_expire (char *pathname);
+
+ void vfs_fill_names (void (*)(char *));
+
+ /* Required for the vfs_canon routine */
+ char *tarfs_analysis (char *inname, char **archive, int is_dir);
+
+ void ftpfs_init(void);
+ void ftpfs_done(void);
+ void ftpfs_set_debug (char *file);
+#ifdef USE_NETCODE
+ void ftpfs_hint_reread(int reread);
+ void ftpfs_flushdir(void);
+#else
+# define ftpfs_flushdir()
+# define ftpfs_hint_reread(x)
+#endif
+ /* They fill the file system names */
+ void mcfs_fill_names (void (*)(char *));
+ void ftpfs_fill_names (void (*)(char *));
+ void tarfs_fill_names (void (*)(char *));
+
+ char *ftpfs_gethome (char *);
+ char *mcfs_gethome (char *);
+
+ char *ftpfs_getupdir (char *);
+ char *mcfs_getupdir (char *);
+
+ /* Only the routines outside of the VFS module need the emulation macros */
+
+ int mc_open (char *file, int flags, ...);
+ int mc_close (int handle);
+ int mc_read (int handle, char *buffer, int count);
+ int mc_write (int hanlde, char *buffer, int count);
+ off_t mc_lseek (int fd, off_t offset, int whence);
+ int mc_chdir (char *);
+
+ DIR *mc_opendir (char *dirname);
+ struct dirent *mc_readdir(DIR *dirp);
+ int mc_closedir (DIR *dir);
+
+ int mc_stat (char *path, struct stat *buf);
+ int mc_lstat (char *path, struct stat *buf);
+ int mc_fstat (int fd, struct stat *buf);
+
+ int mc_chmod (char *path, int mode);
+ int mc_chown (char *path, int owner, int group);
+ int mc_utime (char *path, struct utimbuf *times);
+ int mc_readlink(char *path, char *buf, int bufsiz);
+ int mc_unlink (char *path);
+ int mc_symlink (char *name1, char *name2);
+ int mc_link (char *name1, char *name2);
+ int mc_mknod (char *, int, int);
+ int mc_rename (char *original, char *target);
+ int mc_write (int fd, char *buf, int nbyte);
+ int mc_rmdir (char *path);
+ int mc_mkdir (char *path, mode_t mode);
+ char *mc_getlocalcopy (char *filename);
+ void mc_ungetlocalcopy (char *filename, char *local, int has_changed);
+ char *mc_def_getlocalcopy (char *filename);
+ void mc_def_ungetlocalcopy (char *filename, char *local, int has_changed);
+ int mc_ctl (int fd, int ctlop, int arg);
+ int mc_setctl (char *path, int ctlop, char *arg);
+#ifdef HAVE_MMAP
+ caddr_t mc_mmap (caddr_t, size_t, int, int, int, off_t);
+ int mc_unmap (caddr_t, size_t);
+ int mc_munmap (caddr_t addr, size_t len);
+#endif /* HAVE_MMAP */
+
+#else
+
+#ifdef USE_NETCODE
+# undef USE_NETCODE
+#endif
+
+# define vfs_fill_names(x)
+# define vfs_add_current_stamps()
+# define vfs_current_is_local() 1
+# define vfs_file_is_local(x) 1
+# define vfs_file_is_ftp(x) 0
+# define vfs_current_is_tarfs() 0
+# define vfs_current_is_extfs() 0
+# define vfs_path(x) x
+# define mc_close close
+# define mc_read read
+# define mc_write write
+# define mc_lseek lseek
+# define mc_opendir opendir
+# define mc_readdir readdir
+# define mc_closedir closedir
+
+# define mc_get_current_wd(x,size) get_current_wd (x, size)
+# define mc_fstat fstat
+# define mc_lstat lstat
+
+# define mc_readlink readlink
+# define mc_symlink symlink
+# define mc_rename rename
+
+#ifndef __os2__
+# define mc_open open
+# define mc_utime utime
+# define mc_chmod chmod
+# define mc_chown chown
+# define mc_chdir chdir
+# define mc_unlink unlink
+#endif
+
+# define mc_mmap mmap
+# define mc_munmap munmap
+
+# define mc_ctl(a,b,c) 0
+# define mc_setctl(a,b,c)
+
+# define mc_stat stat
+# define mc_mknod mknod
+# define mc_link link
+# define mc_mkdir mkdir
+# define mc_rmdir rmdir
+# define is_special_prefix(x) 0
+# define vfs_type(x) (vfs *)(NULL)
+# define vfs_setup_wd()
+# define vfs_init()
+# define vfs_shut()
+# define vfs_canon(p) strdup (canonicalize_pathname(p))
+# define vfs_free_resources()
+# define vfs_timeout_handler()
+# define vfs_timeouts() 0
+# define vfs_force_expire ()
+
+ typedef int vfs;
+
+# define mc_getlocalcopy(x) NULL
+# define mc_ungetlocalcopy(x,y,z)
+
+# define ftpfs_hint_reread(x)
+# define ftpfs_flushdir()
+
+#ifdef _OS_NT
+# undef mc_rmdir
+#endif
+
+#ifdef OS2_NT
+# undef mc_ctl
+# undef mc_unlink
+# define mc_ctl(a,b,c) 0
+# ifndef __EMX__
+# undef mc_mkdir
+# define mc_mkdir(a,b) mkdir(a)
+# endif
+#endif
+
+#endif /* USE_VFS */
+
+#define mc_errno errno
+
+#ifdef WANT_PARSE_LS_LGA
+int parse_ls_lga (char *p, struct stat *s, char **filename, char **linkname);
+#endif
+
+#define MCCTL_SETREMOTECOPY 0
+#define MCCTL_ISREMOTECOPY 1
+#define MCCTL_REMOTECOPYCHUNK 2
+#define MCCTL_FINISHREMOTE 3
+#define MCCTL_FLUSHDIR 4
+
+/* Return codes from the ${fs}_ctl routine */
+
+#define MCERR_TARGETOPEN -1
+ /* Can't open target file */
+#define MCERR_READ -2
+ /* Read error on source file */
+#define MCERR_WRITE -3
+ /* Write error on target file */
+#define MCERR_FINISH -4
+ /* Finished transfer */
+#define MCERR_DATA_ON_STDIN -5
+ /* Data waiting on stdin to be processed */
+
+#endif /* __VFS_H */
+