Midnight Commander for Win32
authorSteven Edwards <winehacker@gmail.com>
Sun, 30 Dec 2001 10:02:14 +0000 (10:02 +0000)
committerSteven Edwards <winehacker@gmail.com>
Sun, 30 Dec 2001 10:02:14 +0000 (10:02 +0000)
svn path=/trunk/; revision=2456

222 files changed:
rosapps/mc/Make.common [new file with mode: 0644]
rosapps/mc/Makefile [new file with mode: 0644]
rosapps/mc/Makefile.PC [new file with mode: 0644]
rosapps/mc/VERSION [new file with mode: 0644]
rosapps/mc/about-nls [new file with mode: 0644]
rosapps/mc/acconfig.h [new file with mode: 0644]
rosapps/mc/autogen.sh [new file with mode: 0644]
rosapps/mc/config.cache [new file with mode: 0644]
rosapps/mc/config.h [new file with mode: 0644]
rosapps/mc/config.h.in [new file with mode: 0644]
rosapps/mc/config.status [new file with mode: 0644]
rosapps/mc/create_vcs [new file with mode: 0644]
rosapps/mc/doc/Makefile [new file with mode: 0644]
rosapps/mc/doc/faq [new file with mode: 0644]
rosapps/mc/doc/install [new file with mode: 0644]
rosapps/mc/doc/install.fast [new file with mode: 0644]
rosapps/mc/doc/mc.1 [new file with mode: 0644]
rosapps/mc/doc/mcedit.1 [new file with mode: 0644]
rosapps/mc/doc/mcserv.8 [new file with mode: 0644]
rosapps/mc/doc/news [new file with mode: 0644]
rosapps/mc/doc/readme [new file with mode: 0644]
rosapps/mc/doc/readme.nt [new file with mode: 0644]
rosapps/mc/edit/Makefile [new file with mode: 0644]
rosapps/mc/edit/edit.c [new file with mode: 0644]
rosapps/mc/edit/edit.h [new file with mode: 0644]
rosapps/mc/edit/edit_key_translator.c [new file with mode: 0644]
rosapps/mc/edit/editcmd.c [new file with mode: 0644]
rosapps/mc/edit/editcmddef.h [new file with mode: 0644]
rosapps/mc/edit/editdraw.c [new file with mode: 0644]
rosapps/mc/edit/editmenu.c [new file with mode: 0644]
rosapps/mc/edit/editoptions.c [new file with mode: 0644]
rosapps/mc/edit/editwidget.c [new file with mode: 0644]
rosapps/mc/edit/makefile.in [new file with mode: 0644]
rosapps/mc/edit/readme.edit [new file with mode: 0644]
rosapps/mc/edit/syntax.c [new file with mode: 0644]
rosapps/mc/edit/wordproc.c [new file with mode: 0644]
rosapps/mc/install-sh [new file with mode: 0644]
rosapps/mc/make.common.in [new file with mode: 0644]
rosapps/mc/mc.rc [new file with mode: 0644]
rosapps/mc/mcfn_install [new file with mode: 0644]
rosapps/mc/mcfn_install.in [new file with mode: 0644]
rosapps/mc/mkinstalldirs [new file with mode: 0644]
rosapps/mc/pc/Makefile [new file with mode: 0644]
rosapps/mc/pc/Makefile.PC [new file with mode: 0644]
rosapps/mc/pc/bugs [new file with mode: 0644]
rosapps/mc/pc/changelog [new file with mode: 0644]
rosapps/mc/pc/chmod.c [new file with mode: 0644]
rosapps/mc/pc/config.h [new file with mode: 0644]
rosapps/mc/pc/cons_nt.c [new file with mode: 0644]
rosapps/mc/pc/cons_os2.c [new file with mode: 0644]
rosapps/mc/pc/dirent.h [new file with mode: 0644]
rosapps/mc/pc/dirent_nt.c [new file with mode: 0644]
rosapps/mc/pc/dirent_os2.c [new file with mode: 0644]
rosapps/mc/pc/drive.c [new file with mode: 0644]
rosapps/mc/pc/drive.h [new file with mode: 0644]
rosapps/mc/pc/key_nt.c [new file with mode: 0644]
rosapps/mc/pc/key_os2.c [new file with mode: 0644]
rosapps/mc/pc/mc.rc [new file with mode: 0644]
rosapps/mc/pc/readme [new file with mode: 0644]
rosapps/mc/pc/slint_pc.c [new file with mode: 0644]
rosapps/mc/pc/sys/param.h [new file with mode: 0644]
rosapps/mc/pc/sys/time.h___ [new file with mode: 0644]
rosapps/mc/pc/todo [new file with mode: 0644]
rosapps/mc/pc/trace_nt.c [new file with mode: 0644]
rosapps/mc/pc/trace_nt.h [new file with mode: 0644]
rosapps/mc/pc/util_nt.c [new file with mode: 0644]
rosapps/mc/pc/util_os2.c [new file with mode: 0644]
rosapps/mc/pc/util_win32.c [new file with mode: 0644]
rosapps/mc/pc/util_win32.h [new file with mode: 0644]
rosapps/mc/pc/util_winnt.c [new file with mode: 0644]
rosapps/mc/pc/utime.h [new file with mode: 0644]
rosapps/mc/slang/Makefile [new file with mode: 0644]
rosapps/mc/slang/_slang.h [new file with mode: 0644]
rosapps/mc/slang/jdmacros.h [new file with mode: 0644]
rosapps/mc/slang/makefile.in [new file with mode: 0644]
rosapps/mc/slang/readme [new file with mode: 0644]
rosapps/mc/slang/sl-feat.h [new file with mode: 0644]
rosapps/mc/slang/slang.h [new file with mode: 0644]
rosapps/mc/slang/sldisply.c [new file with mode: 0644]
rosapps/mc/slang/slerr.c [new file with mode: 0644]
rosapps/mc/slang/slgetkey.c [new file with mode: 0644]
rosapps/mc/slang/slmemcpy.c [new file with mode: 0644]
rosapps/mc/slang/slmemset.c [new file with mode: 0644]
rosapps/mc/slang/slos2tty.c [new file with mode: 0644]
rosapps/mc/slang/slsignal.c [new file with mode: 0644]
rosapps/mc/slang/slsmg.c [new file with mode: 0644]
rosapps/mc/slang/sltermin.c [new file with mode: 0644]
rosapps/mc/slang/sltoken.c [new file with mode: 0644]
rosapps/mc/slang/slutty.c [new file with mode: 0644]
rosapps/mc/slang/slvideo.c [new file with mode: 0644]
rosapps/mc/slang/slw32tty.c [new file with mode: 0644]
rosapps/mc/src/Makefile [new file with mode: 0644]
rosapps/mc/src/achown.c [new file with mode: 0644]
rosapps/mc/src/achown.h [new file with mode: 0644]
rosapps/mc/src/background.c [new file with mode: 0644]
rosapps/mc/src/background.h [new file with mode: 0644]
rosapps/mc/src/boxes.c [new file with mode: 0644]
rosapps/mc/src/boxes.h [new file with mode: 0644]
rosapps/mc/src/changelog [new file with mode: 0644]
rosapps/mc/src/chmod.c [new file with mode: 0644]
rosapps/mc/src/chmod.h [new file with mode: 0644]
rosapps/mc/src/chown.c [new file with mode: 0644]
rosapps/mc/src/chown.h [new file with mode: 0644]
rosapps/mc/src/cmd.c [new file with mode: 0644]
rosapps/mc/src/cmd.h [new file with mode: 0644]
rosapps/mc/src/color.c [new file with mode: 0644]
rosapps/mc/src/color.h [new file with mode: 0644]
rosapps/mc/src/command.c [new file with mode: 0644]
rosapps/mc/src/command.h [new file with mode: 0644]
rosapps/mc/src/complete.c [new file with mode: 0644]
rosapps/mc/src/complete.h [new file with mode: 0644]
rosapps/mc/src/cons.handler.c [new file with mode: 0644]
rosapps/mc/src/cons.saver.c [new file with mode: 0644]
rosapps/mc/src/cons.saver.h [new file with mode: 0644]
rosapps/mc/src/depend.awk [new file with mode: 0644]
rosapps/mc/src/dialog.c [new file with mode: 0644]
rosapps/mc/src/dialog.h [new file with mode: 0644]
rosapps/mc/src/dir.c [new file with mode: 0644]
rosapps/mc/src/dir.h [new file with mode: 0644]
rosapps/mc/src/dlg.c [new file with mode: 0644]
rosapps/mc/src/dlg.h [new file with mode: 0644]
rosapps/mc/src/ext.c [new file with mode: 0644]
rosapps/mc/src/ext.h [new file with mode: 0644]
rosapps/mc/src/features.inc [new file with mode: 0644]
rosapps/mc/src/file.c [new file with mode: 0644]
rosapps/mc/src/file.h [new file with mode: 0644]
rosapps/mc/src/find.c [new file with mode: 0644]
rosapps/mc/src/find.h [new file with mode: 0644]
rosapps/mc/src/fixhlp.c [new file with mode: 0644]
rosapps/mc/src/fs.h [new file with mode: 0644]
rosapps/mc/src/fsusage.c [new file with mode: 0644]
rosapps/mc/src/fsusage.h [new file with mode: 0644]
rosapps/mc/src/gindex.pl [new file with mode: 0644]
rosapps/mc/src/global.h [new file with mode: 0644]
rosapps/mc/src/help.c [new file with mode: 0644]
rosapps/mc/src/help.h [new file with mode: 0644]
rosapps/mc/src/hotlist.c [new file with mode: 0644]
rosapps/mc/src/hotlist.h [new file with mode: 0644]
rosapps/mc/src/i18n.h [new file with mode: 0644]
rosapps/mc/src/info.c [new file with mode: 0644]
rosapps/mc/src/info.h [new file with mode: 0644]
rosapps/mc/src/key.c [new file with mode: 0644]
rosapps/mc/src/key.h [new file with mode: 0644]
rosapps/mc/src/keyxdef.c [new file with mode: 0644]
rosapps/mc/src/layout.c [new file with mode: 0644]
rosapps/mc/src/layout.h [new file with mode: 0644]
rosapps/mc/src/learn.c [new file with mode: 0644]
rosapps/mc/src/learn.h [new file with mode: 0644]
rosapps/mc/src/listmode.c [new file with mode: 0644]
rosapps/mc/src/listmode.h [new file with mode: 0644]
rosapps/mc/src/mad.c [new file with mode: 0644]
rosapps/mc/src/mad.h [new file with mode: 0644]
rosapps/mc/src/main.c [new file with mode: 0644]
rosapps/mc/src/main.h [new file with mode: 0644]
rosapps/mc/src/makefile.in [new file with mode: 0644]
rosapps/mc/src/man2hlp.c [new file with mode: 0644]
rosapps/mc/src/mc.hlp [new file with mode: 0644]
rosapps/mc/src/mem.h [new file with mode: 0644]
rosapps/mc/src/menu.c [new file with mode: 0644]
rosapps/mc/src/menu.h [new file with mode: 0644]
rosapps/mc/src/mfmt.c [new file with mode: 0644]
rosapps/mc/src/mountlist.c [new file with mode: 0644]
rosapps/mc/src/mountlist.h [new file with mode: 0644]
rosapps/mc/src/mouse.c [new file with mode: 0644]
rosapps/mc/src/mouse.h [new file with mode: 0644]
rosapps/mc/src/myslang.h [new file with mode: 0644]
rosapps/mc/src/ncurses.patch [new file with mode: 0644]
rosapps/mc/src/ochangelog [new file with mode: 0644]
rosapps/mc/src/option.c [new file with mode: 0644]
rosapps/mc/src/option.h [new file with mode: 0644]
rosapps/mc/src/panel.h [new file with mode: 0644]
rosapps/mc/src/panelize.c [new file with mode: 0644]
rosapps/mc/src/panelize.h [new file with mode: 0644]
rosapps/mc/src/popt.c [new file with mode: 0644]
rosapps/mc/src/popt.h [new file with mode: 0644]
rosapps/mc/src/profile.c [new file with mode: 0644]
rosapps/mc/src/profile.h [new file with mode: 0644]
rosapps/mc/src/regex.c [new file with mode: 0644]
rosapps/mc/src/regex.h [new file with mode: 0644]
rosapps/mc/src/rxvt.c [new file with mode: 0644]
rosapps/mc/src/screen.c [new file with mode: 0644]
rosapps/mc/src/setup.c [new file with mode: 0644]
rosapps/mc/src/setup.h [new file with mode: 0644]
rosapps/mc/src/slint.c [new file with mode: 0644]
rosapps/mc/src/subshell.c [new file with mode: 0644]
rosapps/mc/src/subshell.h [new file with mode: 0644]
rosapps/mc/src/terms.c [new file with mode: 0644]
rosapps/mc/src/text.c [new file with mode: 0644]
rosapps/mc/src/textconf.h [new file with mode: 0644]
rosapps/mc/src/todo [new file with mode: 0644]
rosapps/mc/src/tree.c [new file with mode: 0644]
rosapps/mc/src/tree.h [new file with mode: 0644]
rosapps/mc/src/tty.h [new file with mode: 0644]
rosapps/mc/src/user.c [new file with mode: 0644]
rosapps/mc/src/user.h [new file with mode: 0644]
rosapps/mc/src/util.c [new file with mode: 0644]
rosapps/mc/src/util.h [new file with mode: 0644]
rosapps/mc/src/utilunix.c [new file with mode: 0644]
rosapps/mc/src/view.c [new file with mode: 0644]
rosapps/mc/src/view.h [new file with mode: 0644]
rosapps/mc/src/widget.c [new file with mode: 0644]
rosapps/mc/src/widget.h [new file with mode: 0644]
rosapps/mc/src/win.c [new file with mode: 0644]
rosapps/mc/src/win.h [new file with mode: 0644]
rosapps/mc/src/wtools.c [new file with mode: 0644]
rosapps/mc/src/wtools.h [new file with mode: 0644]
rosapps/mc/src/x.h [new file with mode: 0644]
rosapps/mc/src/xcurses.c [new file with mode: 0644]
rosapps/mc/src/xmkdir [new file with mode: 0644]
rosapps/mc/src/xslint.c [new file with mode: 0644]
rosapps/mc/version.in [new file with mode: 0644]
rosapps/mc/vfs/Makefile [new file with mode: 0644]
rosapps/mc/vfs/extfs.h [new file with mode: 0644]
rosapps/mc/vfs/extfs/cpio [new file with mode: 0644]
rosapps/mc/vfs/extfs/deb [new file with mode: 0644]
rosapps/mc/vfs/extfs/ftplist [new file with mode: 0644]
rosapps/mc/vfs/extfs/lha [new file with mode: 0644]
rosapps/mc/vfs/extfs/lslR [new file with mode: 0644]
rosapps/mc/vfs/extfs/rar [new file with mode: 0644]
rosapps/mc/vfs/extfs/zip [new file with mode: 0644]
rosapps/mc/vfs/extfs/zoo [new file with mode: 0644]
rosapps/mc/vfs/vfs.h [new file with mode: 0644]

diff --git a/rosapps/mc/Make.common b/rosapps/mc/Make.common
new file mode 100644 (file)
index 0000000..11a535b
--- /dev/null
@@ -0,0 +1,105 @@
+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
diff --git a/rosapps/mc/Makefile b/rosapps/mc/Makefile
new file mode 100644 (file)
index 0000000..a7e01a3
--- /dev/null
@@ -0,0 +1,28 @@
+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) 
diff --git a/rosapps/mc/Makefile.PC b/rosapps/mc/Makefile.PC
new file mode 100644 (file)
index 0000000..fa6274a
--- /dev/null
@@ -0,0 +1,180 @@
+# 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
diff --git a/rosapps/mc/VERSION b/rosapps/mc/VERSION
new file mode 100644 (file)
index 0000000..7fbca0f
--- /dev/null
@@ -0,0 +1 @@
+#define VERSION "4.1.36"
diff --git a/rosapps/mc/about-nls b/rosapps/mc/about-nls
new file mode 100644 (file)
index 0000000..dacb8b1
--- /dev/null
@@ -0,0 +1,225 @@
+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.
+
diff --git a/rosapps/mc/acconfig.h b/rosapps/mc/acconfig.h
new file mode 100644 (file)
index 0000000..0019175
--- /dev/null
@@ -0,0 +1,249 @@
+/* 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
+
diff --git a/rosapps/mc/autogen.sh b/rosapps/mc/autogen.sh
new file mode 100644 (file)
index 0000000..b217750
--- /dev/null
@@ -0,0 +1,11 @@
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+
+(
+cd $srcdir
+cat macros/gnome.m4 mc-aclocal.m4 gettext.m4 > aclocal.m4
+autoheader
+autoconf
+)
+
+$srcdir/configure $*
diff --git a/rosapps/mc/config.cache b/rosapps/mc/config.cache
new file mode 100644 (file)
index 0000000..84016ba
--- /dev/null
@@ -0,0 +1,179 @@
+# 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'}
diff --git a/rosapps/mc/config.h b/rosapps/mc/config.h
new file mode 100644 (file)
index 0000000..d8cf12e
--- /dev/null
@@ -0,0 +1,575 @@
+/* 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
+
diff --git a/rosapps/mc/config.h.in b/rosapps/mc/config.h.in
new file mode 100644 (file)
index 0000000..1c5e449
--- /dev/null
@@ -0,0 +1,574 @@
+/* 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
+
diff --git a/rosapps/mc/config.status b/rosapps/mc/config.status
new file mode 100644 (file)
index 0000000..0733db4
--- /dev/null
@@ -0,0 +1,810 @@
+#! /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
diff --git a/rosapps/mc/create_vcs b/rosapps/mc/create_vcs
new file mode 100644 (file)
index 0000000..389216f
--- /dev/null
@@ -0,0 +1,20 @@
+#!/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
diff --git a/rosapps/mc/doc/Makefile b/rosapps/mc/doc/Makefile
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/doc/faq b/rosapps/mc/doc/faq
new file mode 100644 (file)
index 0000000..df9f119
--- /dev/null
@@ -0,0 +1,934 @@
+                                       
+                              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>.
+   
diff --git a/rosapps/mc/doc/install b/rosapps/mc/doc/install
new file mode 100644 (file)
index 0000000..c6d28d8
--- /dev/null
@@ -0,0 +1,529 @@
+-*-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.
+
diff --git a/rosapps/mc/doc/install.fast b/rosapps/mc/doc/install.fast
new file mode 100644 (file)
index 0000000..1bb3453
--- /dev/null
@@ -0,0 +1,70 @@
+-*-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!
diff --git a/rosapps/mc/doc/mc.1 b/rosapps/mc/doc/mc.1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/doc/mcedit.1 b/rosapps/mc/doc/mcedit.1
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/doc/mcserv.8 b/rosapps/mc/doc/mcserv.8
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/doc/news b/rosapps/mc/doc/news
new file mode 100644 (file)
index 0000000..136a885
--- /dev/null
@@ -0,0 +1,516 @@
+
+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.
diff --git a/rosapps/mc/doc/readme b/rosapps/mc/doc/readme
new file mode 100644 (file)
index 0000000..6d11894
--- /dev/null
@@ -0,0 +1,191 @@
+-*-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
+
+
+
diff --git a/rosapps/mc/doc/readme.nt b/rosapps/mc/doc/readme.nt
new file mode 100644 (file)
index 0000000..8f13dd6
--- /dev/null
@@ -0,0 +1,126 @@
+
+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.
+
diff --git a/rosapps/mc/edit/Makefile b/rosapps/mc/edit/Makefile
new file mode 100644 (file)
index 0000000..4dbfbcd
--- /dev/null
@@ -0,0 +1,86 @@
+# 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***
diff --git a/rosapps/mc/edit/edit.c b/rosapps/mc/edit/edit.c
new file mode 100644 (file)
index 0000000..f5dbb4e
--- /dev/null
@@ -0,0 +1,2279 @@
+/* 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);
+}
+
diff --git a/rosapps/mc/edit/edit.h b/rosapps/mc/edit/edit.h
new file mode 100644 (file)
index 0000000..5f965c5
--- /dev/null
@@ -0,0 +1,633 @@
+#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 */
diff --git a/rosapps/mc/edit/edit_key_translator.c b/rosapps/mc/edit/edit_key_translator.c
new file mode 100644 (file)
index 0000000..068a21a
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+    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:
+
+
diff --git a/rosapps/mc/edit/editcmd.c b/rosapps/mc/edit/editcmd.c
new file mode 100644 (file)
index 0000000..7e846ad
--- /dev/null
@@ -0,0 +1,2541 @@
+/* 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, ", &macro[n].command, &macro[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, ", &macro[*n].command, &macro[*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
+
diff --git a/rosapps/mc/edit/editcmddef.h b/rosapps/mc/edit/editcmddef.h
new file mode 100644 (file)
index 0000000..891c4c3
--- /dev/null
@@ -0,0 +1,138 @@
+#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
+
diff --git a/rosapps/mc/edit/editdraw.c b/rosapps/mc/edit/editdraw.c
new file mode 100644 (file)
index 0000000..4936b6b
--- /dev/null
@@ -0,0 +1,648 @@
+/* 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
diff --git a/rosapps/mc/edit/editmenu.c b/rosapps/mc/edit/editmenu.c
new file mode 100644 (file)
index 0000000..ffaf156
--- /dev/null
@@ -0,0 +1,455 @@
+/* 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 */
+
diff --git a/rosapps/mc/edit/editoptions.c b/rosapps/mc/edit/editoptions.c
new file mode 100644 (file)
index 0000000..aea5884
--- /dev/null
@@ -0,0 +1,182 @@
+/* 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;
+       }
+    }
+}
+
diff --git a/rosapps/mc/edit/editwidget.c b/rosapps/mc/edit/editwidget.c
new file mode 100644 (file)
index 0000000..b5d2e90
--- /dev/null
@@ -0,0 +1,1082 @@
+/* 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
diff --git a/rosapps/mc/edit/makefile.in b/rosapps/mc/edit/makefile.in
new file mode 100644 (file)
index 0000000..ccff9f1
--- /dev/null
@@ -0,0 +1,84 @@
+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***
diff --git a/rosapps/mc/edit/readme.edit b/rosapps/mc/edit/readme.edit
new file mode 100644 (file)
index 0000000..8b13789
--- /dev/null
@@ -0,0 +1 @@
+
diff --git a/rosapps/mc/edit/syntax.c b/rosapps/mc/edit/syntax.c
new file mode 100644 (file)
index 0000000..af958bb
--- /dev/null
@@ -0,0 +1,1712 @@
+/* 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) */
+
+
+
+
diff --git a/rosapps/mc/edit/wordproc.c b/rosapps/mc/edit/wordproc.c
new file mode 100644 (file)
index 0000000..5b147d8
--- /dev/null
@@ -0,0 +1,350 @@
+/* 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);
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/rosapps/mc/install-sh b/rosapps/mc/install-sh
new file mode 100644 (file)
index 0000000..0ff4b6a
--- /dev/null
@@ -0,0 +1,119 @@
+#!/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
diff --git a/rosapps/mc/make.common.in b/rosapps/mc/make.common.in
new file mode 100644 (file)
index 0000000..63d2bde
--- /dev/null
@@ -0,0 +1,105 @@
+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
diff --git a/rosapps/mc/mc.rc b/rosapps/mc/mc.rc
new file mode 100644 (file)
index 0000000..8340ee4
--- /dev/null
@@ -0,0 +1,60 @@
+#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 */
+
diff --git a/rosapps/mc/mcfn_install b/rosapps/mc/mcfn_install
new file mode 100644 (file)
index 0000000..de6bc32
--- /dev/null
@@ -0,0 +1,67 @@
+#/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
diff --git a/rosapps/mc/mcfn_install.in b/rosapps/mc/mcfn_install.in
new file mode 100644 (file)
index 0000000..9aed408
--- /dev/null
@@ -0,0 +1,67 @@
+#/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
diff --git a/rosapps/mc/mkinstalldirs b/rosapps/mc/mkinstalldirs
new file mode 100644 (file)
index 0000000..f140f01
--- /dev/null
@@ -0,0 +1,40 @@
+#! /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
diff --git a/rosapps/mc/pc/Makefile b/rosapps/mc/pc/Makefile
new file mode 100644 (file)
index 0000000..a7e01a3
--- /dev/null
@@ -0,0 +1,28 @@
+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) 
diff --git a/rosapps/mc/pc/Makefile.PC b/rosapps/mc/pc/Makefile.PC
new file mode 100644 (file)
index 0000000..9220c16
--- /dev/null
@@ -0,0 +1,178 @@
+# 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
diff --git a/rosapps/mc/pc/bugs b/rosapps/mc/pc/bugs
new file mode 100644 (file)
index 0000000..940445e
--- /dev/null
@@ -0,0 +1,15 @@
+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!
+
diff --git a/rosapps/mc/pc/changelog b/rosapps/mc/pc/changelog
new file mode 100644 (file)
index 0000000..1068122
--- /dev/null
@@ -0,0 +1,23 @@
+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
diff --git a/rosapps/mc/pc/chmod.c b/rosapps/mc/pc/chmod.c
new file mode 100644 (file)
index 0000000..f8f5502
--- /dev/null
@@ -0,0 +1,495 @@
+/* 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 ();
+}
diff --git a/rosapps/mc/pc/config.h b/rosapps/mc/pc/config.h
new file mode 100644 (file)
index 0000000..93276d1
--- /dev/null
@@ -0,0 +1,248 @@
+/****************************************************************************
+ 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 */
diff --git a/rosapps/mc/pc/cons_nt.c b/rosapps/mc/pc/cons_nt.c
new file mode 100644 (file)
index 0000000..1d18d70
--- /dev/null
@@ -0,0 +1,112 @@
+/* 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));
+    }
+}
diff --git a/rosapps/mc/pc/cons_os2.c b/rosapps/mc/pc/cons_os2.c
new file mode 100644 (file)
index 0000000..09cd121
--- /dev/null
@@ -0,0 +1,110 @@
+/* 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;
+}
diff --git a/rosapps/mc/pc/dirent.h b/rosapps/mc/pc/dirent.h
new file mode 100644 (file)
index 0000000..0f153f5
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  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 */
diff --git a/rosapps/mc/pc/dirent_nt.c b/rosapps/mc/pc/dirent_nt.c
new file mode 100644 (file)
index 0000000..c0b7900
--- /dev/null
@@ -0,0 +1,92 @@
+
+#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;
+}
+
diff --git a/rosapps/mc/pc/dirent_os2.c b/rosapps/mc/pc/dirent_os2.c
new file mode 100644 (file)
index 0000000..973ebac
--- /dev/null
@@ -0,0 +1,110 @@
+#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;
+}
diff --git a/rosapps/mc/pc/drive.c b/rosapps/mc/pc/drive.c
new file mode 100644 (file)
index 0000000..2059f94
--- /dev/null
@@ -0,0 +1,226 @@
+/* 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 "));
+}
diff --git a/rosapps/mc/pc/drive.h b/rosapps/mc/pc/drive.h
new file mode 100644 (file)
index 0000000..7b7c01f
--- /dev/null
@@ -0,0 +1,4 @@
+void drive_cmd_a(WPanel *);
+void drive_cmd_b(WPanel *);
+void drive_chg(WPanel *panel);
+
diff --git a/rosapps/mc/pc/key_nt.c b/rosapps/mc/pc/key_nt.c
new file mode 100644 (file)
index 0000000..00e9f3a
--- /dev/null
@@ -0,0 +1,325 @@
+/* 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 */
diff --git a/rosapps/mc/pc/key_os2.c b/rosapps/mc/pc/key_os2.c
new file mode 100644 (file)
index 0000000..c67c734
--- /dev/null
@@ -0,0 +1,408 @@
+/* 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__ */
diff --git a/rosapps/mc/pc/mc.rc b/rosapps/mc/pc/mc.rc
new file mode 100644 (file)
index 0000000..79299fd
--- /dev/null
@@ -0,0 +1,60 @@
+#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 */
+
diff --git a/rosapps/mc/pc/readme b/rosapps/mc/pc/readme
new file mode 100644 (file)
index 0000000..f9bc036
--- /dev/null
@@ -0,0 +1,41 @@
+ 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>
diff --git a/rosapps/mc/pc/slint_pc.c b/rosapps/mc/pc/slint_pc.c
new file mode 100644 (file)
index 0000000..291d832
--- /dev/null
@@ -0,0 +1,269 @@
+/* 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;
+}
diff --git a/rosapps/mc/pc/sys/param.h b/rosapps/mc/pc/sys/param.h
new file mode 100644 (file)
index 0000000..5e2a01c
--- /dev/null
@@ -0,0 +1,7 @@
+/* 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
diff --git a/rosapps/mc/pc/sys/time.h___ b/rosapps/mc/pc/sys/time.h___
new file mode 100644 (file)
index 0000000..c410cca
--- /dev/null
@@ -0,0 +1,16 @@
+
+#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
diff --git a/rosapps/mc/pc/todo b/rosapps/mc/pc/todo
new file mode 100644 (file)
index 0000000..5e8d1fe
--- /dev/null
@@ -0,0 +1,12 @@
+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()
diff --git a/rosapps/mc/pc/trace_nt.c b/rosapps/mc/pc/trace_nt.c
new file mode 100644 (file)
index 0000000..61aea9f
--- /dev/null
@@ -0,0 +1,186 @@
+/* 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*/
diff --git a/rosapps/mc/pc/trace_nt.h b/rosapps/mc/pc/trace_nt.h
new file mode 100644 (file)
index 0000000..1eda396
--- /dev/null
@@ -0,0 +1,72 @@
+/* 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
diff --git a/rosapps/mc/pc/util_nt.c b/rosapps/mc/pc/util_nt.c
new file mode 100644 (file)
index 0000000..a8497c7
--- /dev/null
@@ -0,0 +1,749 @@
+/* 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)
+{
+}
diff --git a/rosapps/mc/pc/util_os2.c b/rosapps/mc/pc/util_os2.c
new file mode 100644 (file)
index 0000000..17b73a7
--- /dev/null
@@ -0,0 +1,854 @@
+/* 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)
+{
+}
diff --git a/rosapps/mc/pc/util_win32.c b/rosapps/mc/pc/util_win32.c
new file mode 100644 (file)
index 0000000..6c092b0
--- /dev/null
@@ -0,0 +1,187 @@
+/* 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__ */
+}
+
+
diff --git a/rosapps/mc/pc/util_win32.h b/rosapps/mc/pc/util_win32.h
new file mode 100644 (file)
index 0000000..2ed74c7
--- /dev/null
@@ -0,0 +1,42 @@
+/* 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
+};
+
diff --git a/rosapps/mc/pc/util_winnt.c b/rosapps/mc/pc/util_winnt.c
new file mode 100644 (file)
index 0000000..cddf6ef
--- /dev/null
@@ -0,0 +1,85 @@
+/* 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;
+}
+
diff --git a/rosapps/mc/pc/utime.h b/rosapps/mc/pc/utime.h
new file mode 100644 (file)
index 0000000..8285f38
--- /dev/null
@@ -0,0 +1 @@
+#include <sys/utime.h>
diff --git a/rosapps/mc/slang/Makefile b/rosapps/mc/slang/Makefile
new file mode 100644 (file)
index 0000000..f67dd12
--- /dev/null
@@ -0,0 +1,80 @@
+# 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***
diff --git a/rosapps/mc/slang/_slang.h b/rosapps/mc/slang/_slang.h
new file mode 100644 (file)
index 0000000..c42f73d
--- /dev/null
@@ -0,0 +1,325 @@
+/* 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;
+
diff --git a/rosapps/mc/slang/jdmacros.h b/rosapps/mc/slang/jdmacros.h
new file mode 100644 (file)
index 0000000..e822b3b
--- /dev/null
@@ -0,0 +1,76 @@
+#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_ */
diff --git a/rosapps/mc/slang/makefile.in b/rosapps/mc/slang/makefile.in
new file mode 100644 (file)
index 0000000..babcaf4
--- /dev/null
@@ -0,0 +1,78 @@
+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***
diff --git a/rosapps/mc/slang/readme b/rosapps/mc/slang/readme
new file mode 100644 (file)
index 0000000..4561416
--- /dev/null
@@ -0,0 +1,12 @@
+
+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.
diff --git a/rosapps/mc/slang/sl-feat.h b/rosapps/mc/slang/sl-feat.h
new file mode 100644 (file)
index 0000000..2fea3ca
--- /dev/null
@@ -0,0 +1,2 @@
+/* Set this to 1 to enable Kanji support */
+#define SLANG_HAS_KANJI_SUPPORT 0
diff --git a/rosapps/mc/slang/slang.h b/rosapps/mc/slang/slang.h
new file mode 100644 (file)
index 0000000..8f28fb8
--- /dev/null
@@ -0,0 +1,1284 @@
+#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_ */
diff --git a/rosapps/mc/slang/sldisply.c b/rosapps/mc/slang/sldisply.c
new file mode 100644 (file)
index 0000000..711af71
--- /dev/null
@@ -0,0 +1,2240 @@
+/* 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;
+}
diff --git a/rosapps/mc/slang/slerr.c b/rosapps/mc/slang/slerr.c
new file mode 100644 (file)
index 0000000..3a59829
--- /dev/null
@@ -0,0 +1,59 @@
+/* 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);
+}
diff --git a/rosapps/mc/slang/slgetkey.c b/rosapps/mc/slang/slgetkey.c
new file mode 100644 (file)
index 0000000..5a43f85
--- /dev/null
@@ -0,0 +1,125 @@
+/* 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;
+}
diff --git a/rosapps/mc/slang/slmemcpy.c b/rosapps/mc/slang/slmemcpy.c
new file mode 100644 (file)
index 0000000..5edf25b
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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
+}
diff --git a/rosapps/mc/slang/slmemset.c b/rosapps/mc/slang/slmemset.c
new file mode 100644 (file)
index 0000000..a83ae19
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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
+}
diff --git a/rosapps/mc/slang/slos2tty.c b/rosapps/mc/slang/slos2tty.c
new file mode 100644 (file)
index 0000000..e056fff
--- /dev/null
@@ -0,0 +1,261 @@
+/* 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;
+}
diff --git a/rosapps/mc/slang/slsignal.c b/rosapps/mc/slang/slsignal.c
new file mode 100644 (file)
index 0000000..7d4c19d
--- /dev/null
@@ -0,0 +1,139 @@
+#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
+}
diff --git a/rosapps/mc/slang/slsmg.c b/rosapps/mc/slang/slsmg.c
new file mode 100644 (file)
index 0000000..ababdf3
--- /dev/null
@@ -0,0 +1,1185 @@
+/* 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;
+}
diff --git a/rosapps/mc/slang/sltermin.c b/rosapps/mc/slang/sltermin.c
new file mode 100644 (file)
index 0000000..4f3d717
--- /dev/null
@@ -0,0 +1,913 @@
+/* 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 */
diff --git a/rosapps/mc/slang/sltoken.c b/rosapps/mc/slang/sltoken.c
new file mode 100644 (file)
index 0000000..0f17186
--- /dev/null
@@ -0,0 +1,355 @@
+/*--------------------------------*-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;
+}
diff --git a/rosapps/mc/slang/slutty.c b/rosapps/mc/slang/slutty.c
new file mode 100644 (file)
index 0000000..ed2ee8c
--- /dev/null
@@ -0,0 +1,537 @@
+/* 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);
+}
+
diff --git a/rosapps/mc/slang/slvideo.c b/rosapps/mc/slang/slvideo.c
new file mode 100644 (file)
index 0000000..d92c280
--- /dev/null
@@ -0,0 +1,1594 @@
+/* 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) ///////////////////// */
diff --git a/rosapps/mc/slang/slw32tty.c b/rosapps/mc/slang/slw32tty.c
new file mode 100644 (file)
index 0000000..d7ee89a
--- /dev/null
@@ -0,0 +1,224 @@
+/* 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))
+{
+
+}
diff --git a/rosapps/mc/src/Makefile b/rosapps/mc/src/Makefile
new file mode 100644 (file)
index 0000000..43a114d
--- /dev/null
@@ -0,0 +1,153 @@
+# 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***
diff --git a/rosapps/mc/src/achown.c b/rosapps/mc/src/achown.c
new file mode 100644 (file)
index 0000000..83f4baa
--- /dev/null
@@ -0,0 +1,710 @@
+/* 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 ();
+}
diff --git a/rosapps/mc/src/achown.h b/rosapps/mc/src/achown.h
new file mode 100644 (file)
index 0000000..ee40f03
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __ACHOWN_H
+#define __ACHOWN_H
+void chown_advanced_cmd (void);
+#endif
diff --git a/rosapps/mc/src/background.c b/rosapps/mc/src/background.c
new file mode 100644 (file)
index 0000000..c812651
--- /dev/null
@@ -0,0 +1,562 @@
+/* {{{ 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);
+}
+
+/* }}} */
diff --git a/rosapps/mc/src/background.h b/rosapps/mc/src/background.h
new file mode 100644 (file)
index 0000000..51a050c
--- /dev/null
@@ -0,0 +1,60 @@
+#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
diff --git a/rosapps/mc/src/boxes.c b/rosapps/mc/src/boxes.c
new file mode 100644 (file)
index 0000000..0c0506f
--- /dev/null
@@ -0,0 +1,991 @@
+/* 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
diff --git a/rosapps/mc/src/boxes.h b/rosapps/mc/src/boxes.h
new file mode 100644 (file)
index 0000000..06544d1
--- /dev/null
@@ -0,0 +1,16 @@
+#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
diff --git a/rosapps/mc/src/changelog b/rosapps/mc/src/changelog
new file mode 100644 (file)
index 0000000..3302310
--- /dev/null
@@ -0,0 +1,1317 @@
+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.
diff --git a/rosapps/mc/src/chmod.c b/rosapps/mc/src/chmod.c
new file mode 100644 (file)
index 0000000..e66f4a2
--- /dev/null
@@ -0,0 +1,453 @@
+/* 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 ();
+}
+
diff --git a/rosapps/mc/src/chmod.h b/rosapps/mc/src/chmod.h
new file mode 100644 (file)
index 0000000..36dd573
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/rosapps/mc/src/chown.c b/rosapps/mc/src/chown.c
new file mode 100644 (file)
index 0000000..43f8a11
--- /dev/null
@@ -0,0 +1,356 @@
+/* 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 ();
+}
diff --git a/rosapps/mc/src/chown.h b/rosapps/mc/src/chown.h
new file mode 100644 (file)
index 0000000..f2ae188
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef __CHOWN_H
+#define __CHOWN_H
+
+void chown_cmd (void);
+void chown_advanced_cmd (void);
+
+#endif
diff --git a/rosapps/mc/src/cmd.c b/rosapps/mc/src/cmd.c
new file mode 100644 (file)
index 0000000..6f07d63
--- /dev/null
@@ -0,0 +1,1573 @@
+/* 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);
+}
+
diff --git a/rosapps/mc/src/cmd.h b/rosapps/mc/src/cmd.h
new file mode 100644 (file)
index 0000000..80eaebe
--- /dev/null
@@ -0,0 +1,71 @@
+#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 */
diff --git a/rosapps/mc/src/color.c b/rosapps/mc/src/color.c
new file mode 100644 (file)
index 0000000..0bf2e37
--- /dev/null
@@ -0,0 +1,318 @@
+/* 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;
+}
+
diff --git a/rosapps/mc/src/color.h b/rosapps/mc/src/color.h
new file mode 100644 (file)
index 0000000..808b2a5
--- /dev/null
@@ -0,0 +1,80 @@
+#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 */
+
diff --git a/rosapps/mc/src/command.c b/rosapps/mc/src/command.c
new file mode 100644 (file)
index 0000000..2fee81b
--- /dev/null
@@ -0,0 +1,285 @@
+/* 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;
+}
+
+
diff --git a/rosapps/mc/src/command.h b/rosapps/mc/src/command.h
new file mode 100644 (file)
index 0000000..8804a54
--- /dev/null
@@ -0,0 +1,18 @@
+#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 */
diff --git a/rosapps/mc/src/complete.c b/rosapps/mc/src/complete.c
new file mode 100644 (file)
index 0000000..c52e52a
--- /dev/null
@@ -0,0 +1,1056 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/complete.h b/rosapps/mc/src/complete.h
new file mode 100644 (file)
index 0000000..212f197
--- /dev/null
@@ -0,0 +1,16 @@
+#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 */
diff --git a/rosapps/mc/src/cons.handler.c b/rosapps/mc/src/cons.handler.c
new file mode 100644 (file)
index 0000000..ae53464
--- /dev/null
@@ -0,0 +1,426 @@
+/* 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) */
+
+
diff --git a/rosapps/mc/src/cons.saver.c b/rosapps/mc/src/cons.saver.c
new file mode 100644 (file)
index 0000000..f6012ff
--- /dev/null
@@ -0,0 +1,391 @@
+#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 */
diff --git a/rosapps/mc/src/cons.saver.h b/rosapps/mc/src/cons.saver.h
new file mode 100644 (file)
index 0000000..561300d
--- /dev/null
@@ -0,0 +1,30 @@
+#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 */
diff --git a/rosapps/mc/src/depend.awk b/rosapps/mc/src/depend.awk
new file mode 100644 (file)
index 0000000..ec28b55
--- /dev/null
@@ -0,0 +1,163 @@
+#! /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
+       }
+}
diff --git a/rosapps/mc/src/dialog.c b/rosapps/mc/src/dialog.c
new file mode 100644 (file)
index 0000000..cc26831
--- /dev/null
@@ -0,0 +1,106 @@
+/* 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);
+    }
+}
+
diff --git a/rosapps/mc/src/dialog.h b/rosapps/mc/src/dialog.h
new file mode 100644 (file)
index 0000000..4f26434
--- /dev/null
@@ -0,0 +1,43 @@
+#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 */
diff --git a/rosapps/mc/src/dir.c b/rosapps/mc/src/dir.c
new file mode 100644 (file)
index 0000000..68a7686
--- /dev/null
@@ -0,0 +1,659 @@
+/* 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;
+}
+
diff --git a/rosapps/mc/src/dir.h b/rosapps/mc/src/dir.h
new file mode 100644 (file)
index 0000000..b79fe92
--- /dev/null
@@ -0,0 +1,88 @@
+#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 */
diff --git a/rosapps/mc/src/dlg.c b/rosapps/mc/src/dlg.c
new file mode 100644 (file)
index 0000000..9dafd2b
--- /dev/null
@@ -0,0 +1,1055 @@
+/* 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
+
diff --git a/rosapps/mc/src/dlg.h b/rosapps/mc/src/dlg.h
new file mode 100644 (file)
index 0000000..097ae6d
--- /dev/null
@@ -0,0 +1,317 @@
+#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 */
diff --git a/rosapps/mc/src/ext.c b/rosapps/mc/src/ext.c
new file mode 100644 (file)
index 0000000..0f2b6bf
--- /dev/null
@@ -0,0 +1,701 @@
+/* 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;
+}
diff --git a/rosapps/mc/src/ext.h b/rosapps/mc/src/ext.h
new file mode 100644 (file)
index 0000000..1d86c41
--- /dev/null
@@ -0,0 +1,18 @@
+#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
diff --git a/rosapps/mc/src/features.inc b/rosapps/mc/src/features.inc
new file mode 100644 (file)
index 0000000..93dee59
--- /dev/null
@@ -0,0 +1,104 @@
+/* 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
+
+
diff --git a/rosapps/mc/src/file.c b/rosapps/mc/src/file.c
new file mode 100644 (file)
index 0000000..b49da5b
--- /dev/null
@@ -0,0 +1,2968 @@
+/* {{{ 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, &regs);
+    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:
+*/
diff --git a/rosapps/mc/src/file.h b/rosapps/mc/src/file.h
new file mode 100644 (file)
index 0000000..c2730c5
--- /dev/null
@@ -0,0 +1,51 @@
+#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
diff --git a/rosapps/mc/src/find.c b/rosapps/mc/src/find.c
new file mode 100644 (file)
index 0000000..84ae4b1
--- /dev/null
@@ -0,0 +1,951 @@
+/* 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;
+       }
+    }
+}
+
diff --git a/rosapps/mc/src/find.h b/rosapps/mc/src/find.h
new file mode 100644 (file)
index 0000000..5ebc50a
--- /dev/null
@@ -0,0 +1,27 @@
+#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
diff --git a/rosapps/mc/src/fixhlp.c b/rosapps/mc/src/fixhlp.c
new file mode 100644 (file)
index 0000000..db3fa65
--- /dev/null
@@ -0,0 +1,247 @@
+/* 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;
+}
diff --git a/rosapps/mc/src/fs.h b/rosapps/mc/src/fs.h
new file mode 100644 (file)
index 0000000..5f1085b
--- /dev/null
@@ -0,0 +1,46 @@
+/* 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
diff --git a/rosapps/mc/src/fsusage.c b/rosapps/mc/src/fsusage.c
new file mode 100644 (file)
index 0000000..b8a3ab0
--- /dev/null
@@ -0,0 +1,192 @@
+/* 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 */
diff --git a/rosapps/mc/src/fsusage.h b/rosapps/mc/src/fsusage.h
new file mode 100644 (file)
index 0000000..dd23ea0
--- /dev/null
@@ -0,0 +1,33 @@
+/* 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
diff --git a/rosapps/mc/src/gindex.pl b/rosapps/mc/src/gindex.pl
new file mode 100644 (file)
index 0000000..77999ee
--- /dev/null
@@ -0,0 +1,26 @@
+#!/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;
diff --git a/rosapps/mc/src/global.h b/rosapps/mc/src/global.h
new file mode 100644 (file)
index 0000000..c91d5a5
--- /dev/null
@@ -0,0 +1,33 @@
+#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
diff --git a/rosapps/mc/src/help.c b/rosapps/mc/src/help.c
new file mode 100644 (file)
index 0000000..343cf62
--- /dev/null
@@ -0,0 +1,833 @@
+/* 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
+}
+
diff --git a/rosapps/mc/src/help.h b/rosapps/mc/src/help.h
new file mode 100644 (file)
index 0000000..db85690
--- /dev/null
@@ -0,0 +1,32 @@
+#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 */
diff --git a/rosapps/mc/src/hotlist.c b/rosapps/mc/src/hotlist.c
new file mode 100644 (file)
index 0000000..45f0eaa
--- /dev/null
@@ -0,0 +1,1610 @@
+/* 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;
+}
+
+
diff --git a/rosapps/mc/src/hotlist.h b/rosapps/mc/src/hotlist.h
new file mode 100644 (file)
index 0000000..fefe49f
--- /dev/null
@@ -0,0 +1,14 @@
+#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
diff --git a/rosapps/mc/src/i18n.h b/rosapps/mc/src/i18n.h
new file mode 100644 (file)
index 0000000..4a561c4
--- /dev/null
@@ -0,0 +1,14 @@
+/* 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_ */
diff --git a/rosapps/mc/src/info.c b/rosapps/mc/src/info.c
new file mode 100644 (file)
index 0000000..ead75e3
--- /dev/null
@@ -0,0 +1,275 @@
+/* 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;
+}
+
diff --git a/rosapps/mc/src/info.h b/rosapps/mc/src/info.h
new file mode 100644 (file)
index 0000000..35c8328
--- /dev/null
@@ -0,0 +1,11 @@
+#ifndef __INFO_H
+#define __INFO_H
+
+typedef struct {
+    Widget widget;
+    int ready;
+} WInfo;
+
+WInfo *info_new ();
+
+#endif
diff --git a/rosapps/mc/src/key.c b/rosapps/mc/src/key.c
new file mode 100644 (file)
index 0000000..e803eed
--- /dev/null
@@ -0,0 +1,1022 @@
+/* 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 */
diff --git a/rosapps/mc/src/key.h b/rosapps/mc/src/key.h
new file mode 100644 (file)
index 0000000..db2492f
--- /dev/null
@@ -0,0 +1,91 @@
+#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 */
diff --git a/rosapps/mc/src/keyxdef.c b/rosapps/mc/src/keyxdef.c
new file mode 100644 (file)
index 0000000..055552c
--- /dev/null
@@ -0,0 +1,418 @@
+/* {{{ 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
+}
+
+
diff --git a/rosapps/mc/src/layout.c b/rosapps/mc/src/layout.c
new file mode 100644 (file)
index 0000000..767eb37
--- /dev/null
@@ -0,0 +1,1192 @@
+/* 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;
+}
+
diff --git a/rosapps/mc/src/layout.h b/rosapps/mc/src/layout.h
new file mode 100644 (file)
index 0000000..22a5923
--- /dev/null
@@ -0,0 +1,42 @@
+#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 */
diff --git a/rosapps/mc/src/learn.c b/rosapps/mc/src/learn.c
new file mode 100644 (file)
index 0000000..76a7663
--- /dev/null
@@ -0,0 +1,369 @@
+/* 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 ();
+}
+
diff --git a/rosapps/mc/src/learn.h b/rosapps/mc/src/learn.h
new file mode 100644 (file)
index 0000000..5188e16
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __LEARN_H
+#define __LEARN_H
+
+void learn_keys (void);
+
+#endif
diff --git a/rosapps/mc/src/listmode.c b/rosapps/mc/src/listmode.c
new file mode 100644 (file)
index 0000000..42b4693
--- /dev/null
@@ -0,0 +1,329 @@
+/* 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;
+}
diff --git a/rosapps/mc/src/listmode.h b/rosapps/mc/src/listmode.h
new file mode 100644 (file)
index 0000000..d9abc7f
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef __LISTMODE_H
+#define __LISTMODE_H
+
+char *listmode_edit (char*);
+
+#endif
diff --git a/rosapps/mc/src/mad.c b/rosapps/mc/src/mad.c
new file mode 100644 (file)
index 0000000..d89ae91
--- /dev/null
@@ -0,0 +1,250 @@
+/* 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 */
diff --git a/rosapps/mc/src/mad.h b/rosapps/mc/src/mad.h
new file mode 100644 (file)
index 0000000..0119e1c
--- /dev/null
@@ -0,0 +1,45 @@
+#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 */
diff --git a/rosapps/mc/src/main.c b/rosapps/mc/src/main.c
new file mode 100644 (file)
index 0000000..ec6f87c
--- /dev/null
@@ -0,0 +1,3203 @@
+/* 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;
+}
diff --git a/rosapps/mc/src/main.h b/rosapps/mc/src/main.h
new file mode 100644 (file)
index 0000000..f4d4ddc
--- /dev/null
@@ -0,0 +1,197 @@
+#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
diff --git a/rosapps/mc/src/makefile.in b/rosapps/mc/src/makefile.in
new file mode 100644 (file)
index 0000000..d68ad6d
--- /dev/null
@@ -0,0 +1,151 @@
+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***
diff --git a/rosapps/mc/src/man2hlp.c b/rosapps/mc/src/man2hlp.c
new file mode 100644 (file)
index 0000000..d216c29
--- /dev/null
@@ -0,0 +1,533 @@
+/* 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;
+}
diff --git a/rosapps/mc/src/mc.hlp b/rosapps/mc/src/mc.hlp
new file mode 100644 (file)
index 0000000..7709836
--- /dev/null
@@ -0,0 +1,3193 @@
+\ 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:
diff --git a/rosapps/mc/src/mem.h b/rosapps/mc/src/mem.h
new file mode 100644 (file)
index 0000000..a1ba18f
--- /dev/null
@@ -0,0 +1,28 @@
+#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 */
+
diff --git a/rosapps/mc/src/menu.c b/rosapps/mc/src/menu.c
new file mode 100644 (file)
index 0000000..d94ff9e
--- /dev/null
@@ -0,0 +1,529 @@
+/* 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;
+}
diff --git a/rosapps/mc/src/menu.h b/rosapps/mc/src/menu.h
new file mode 100644 (file)
index 0000000..5abd4d4
--- /dev/null
@@ -0,0 +1,62 @@
+#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 */
+
diff --git a/rosapps/mc/src/mfmt.c b/rosapps/mc/src/mfmt.c
new file mode 100644 (file)
index 0000000..5327710
--- /dev/null
@@ -0,0 +1,153 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/mountlist.c b/rosapps/mc/src/mountlist.c
new file mode 100644 (file)
index 0000000..93298cd
--- /dev/null
@@ -0,0 +1,557 @@
+/* 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__ */
+
diff --git a/rosapps/mc/src/mountlist.h b/rosapps/mc/src/mountlist.h
new file mode 100644 (file)
index 0000000..895804b
--- /dev/null
@@ -0,0 +1,32 @@
+/* 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        */
diff --git a/rosapps/mc/src/mouse.c b/rosapps/mc/src/mouse.c
new file mode 100644 (file)
index 0000000..ddb9b64
--- /dev/null
@@ -0,0 +1,279 @@
+/* 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
+
diff --git a/rosapps/mc/src/mouse.h b/rosapps/mc/src/mouse.h
new file mode 100644 (file)
index 0000000..2e42c23
--- /dev/null
@@ -0,0 +1,91 @@
+#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 */
diff --git a/rosapps/mc/src/myslang.h b/rosapps/mc/src/myslang.h
new file mode 100644 (file)
index 0000000..7ab7bba
--- /dev/null
@@ -0,0 +1,141 @@
+#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
diff --git a/rosapps/mc/src/ncurses.patch b/rosapps/mc/src/ncurses.patch
new file mode 100644 (file)
index 0000000..30e5884
--- /dev/null
@@ -0,0 +1,19 @@
+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++)
diff --git a/rosapps/mc/src/ochangelog b/rosapps/mc/src/ochangelog
new file mode 100644 (file)
index 0000000..8b054a8
--- /dev/null
@@ -0,0 +1,12744 @@
+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.
+
diff --git a/rosapps/mc/src/option.c b/rosapps/mc/src/option.c
new file mode 100644 (file)
index 0000000..beb1116
--- /dev/null
@@ -0,0 +1,278 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/option.h b/rosapps/mc/src/option.h
new file mode 100644 (file)
index 0000000..923ea19
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef __OPTION_H
+#define __OPTION_H
+void configure_box (void);
+#endif 
diff --git a/rosapps/mc/src/panel.h b/rosapps/mc/src/panel.h
new file mode 100644 (file)
index 0000000..122a0ec
--- /dev/null
@@ -0,0 +1,265 @@
+#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 */
diff --git a/rosapps/mc/src/panelize.c b/rosapps/mc/src/panelize.c
new file mode 100644 (file)
index 0000000..de5fc1b
--- /dev/null
@@ -0,0 +1,463 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/panelize.h b/rosapps/mc/src/panelize.h
new file mode 100644 (file)
index 0000000..e411ba9
--- /dev/null
@@ -0,0 +1,10 @@
+#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
diff --git a/rosapps/mc/src/popt.c b/rosapps/mc/src/popt.c
new file mode 100644 (file)
index 0000000..edffee1
--- /dev/null
@@ -0,0 +1,681 @@
+/*
+ *
+ * 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;
+}
diff --git a/rosapps/mc/src/popt.h b/rosapps/mc/src/popt.h
new file mode 100644 (file)
index 0000000..c341a83
--- /dev/null
@@ -0,0 +1,66 @@
+#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
diff --git a/rosapps/mc/src/profile.c b/rosapps/mc/src/profile.c
new file mode 100644 (file)
index 0000000..3b84d0f
--- /dev/null
@@ -0,0 +1,563 @@
+/*
+ * 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, &section)){
+       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, &section)){
+       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, &section)){
+       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, &section)){
+       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;
+    }
+}
+
+
diff --git a/rosapps/mc/src/profile.h b/rosapps/mc/src/profile.h
new file mode 100644 (file)
index 0000000..70724ea
--- /dev/null
@@ -0,0 +1,49 @@
+#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 */
diff --git a/rosapps/mc/src/regex.c b/rosapps/mc/src/regex.c
new file mode 100644 (file)
index 0000000..bb80ea0
--- /dev/null
@@ -0,0 +1,5416 @@
+/* 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 (&reg_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 ? &regs : (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:
+*/
diff --git a/rosapps/mc/src/regex.h b/rosapps/mc/src/regex.h
new file mode 100644 (file)
index 0000000..31eaf84
--- /dev/null
@@ -0,0 +1,491 @@
+/* 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:
+*/
diff --git a/rosapps/mc/src/rxvt.c b/rosapps/mc/src/rxvt.c
new file mode 100644 (file)
index 0000000..8994964
--- /dev/null
@@ -0,0 +1,127 @@
+/* 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);
+}
+
diff --git a/rosapps/mc/src/screen.c b/rosapps/mc/src/screen.c
new file mode 100644 (file)
index 0000000..178fdb4
--- /dev/null
@@ -0,0 +1,2520 @@
+/* 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, &current_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
+}
diff --git a/rosapps/mc/src/setup.c b/rosapps/mc/src/setup.c
new file mode 100644 (file)
index 0000000..0840e6b
--- /dev/null
@@ -0,0 +1,626 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/setup.h b/rosapps/mc/src/setup.h
new file mode 100644 (file)
index 0000000..65f8ec6
--- /dev/null
@@ -0,0 +1,36 @@
+#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
diff --git a/rosapps/mc/src/slint.c b/rosapps/mc/src/slint.c
new file mode 100644 (file)
index 0000000..e61a7f4
--- /dev/null
@@ -0,0 +1,589 @@
+/* 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, &current_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 ();
+}
diff --git a/rosapps/mc/src/subshell.c b/rosapps/mc/src/subshell.c
new file mode 100644 (file)
index 0000000..d6762d3
--- /dev/null
@@ -0,0 +1,1211 @@
+/* {{{ 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:
+*/
+
+/* }}} */
diff --git a/rosapps/mc/src/subshell.h b/rosapps/mc/src/subshell.h
new file mode 100644 (file)
index 0000000..5cc9c68
--- /dev/null
@@ -0,0 +1,46 @@
+#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 */
diff --git a/rosapps/mc/src/terms.c b/rosapps/mc/src/terms.c
new file mode 100644 (file)
index 0000000..377b730
--- /dev/null
@@ -0,0 +1,43 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/text.c b/rosapps/mc/src/text.c
new file mode 100644 (file)
index 0000000..4d34826
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 ();
+}
+
diff --git a/rosapps/mc/src/textconf.h b/rosapps/mc/src/textconf.h
new file mode 100644 (file)
index 0000000..6399234
--- /dev/null
@@ -0,0 +1,7 @@
+/* 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()
diff --git a/rosapps/mc/src/todo b/rosapps/mc/src/todo
new file mode 100644 (file)
index 0000000..ca44a60
--- /dev/null
@@ -0,0 +1,215 @@
+* 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.
+  
+
diff --git a/rosapps/mc/src/tree.c b/rosapps/mc/src/tree.c
new file mode 100644 (file)
index 0000000..91a185d
--- /dev/null
@@ -0,0 +1,1593 @@
+/* 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;
+}
+
+
diff --git a/rosapps/mc/src/tree.h b/rosapps/mc/src/tree.h
new file mode 100644 (file)
index 0000000..f5833ef
--- /dev/null
@@ -0,0 +1,74 @@
+#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
diff --git a/rosapps/mc/src/tty.h b/rosapps/mc/src/tty.h
new file mode 100644 (file)
index 0000000..c5e2460
--- /dev/null
@@ -0,0 +1,141 @@
+/* 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
+
diff --git a/rosapps/mc/src/user.c b/rosapps/mc/src/user.c
new file mode 100644 (file)
index 0000000..e1df3a4
--- /dev/null
@@ -0,0 +1,733 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/user.h b/rosapps/mc/src/user.h
new file mode 100644 (file)
index 0000000..9bbdd5d
--- /dev/null
@@ -0,0 +1,23 @@
+#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
diff --git a/rosapps/mc/src/util.c b/rosapps/mc/src/util.c
new file mode 100644 (file)
index 0000000..e42f9b5
--- /dev/null
@@ -0,0 +1,1309 @@
+/* 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);
+}
diff --git a/rosapps/mc/src/util.h b/rosapps/mc/src/util.h
new file mode 100644 (file)
index 0000000..005b05d
--- /dev/null
@@ -0,0 +1,225 @@
+#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
diff --git a/rosapps/mc/src/utilunix.c b/rosapps/mc/src/utilunix.c
new file mode 100644 (file)
index 0000000..91eb799
--- /dev/null
@@ -0,0 +1,933 @@
+/* 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 */
diff --git a/rosapps/mc/src/view.c b/rosapps/mc/src/view.c
new file mode 100644 (file)
index 0000000..5d96cc6
--- /dev/null
@@ -0,0 +1,2521 @@
+/* {{{ 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:
+   */
+/* }}} */
diff --git a/rosapps/mc/src/view.h b/rosapps/mc/src/view.h
new file mode 100644 (file)
index 0000000..6430044
--- /dev/null
@@ -0,0 +1,195 @@
+#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 */
diff --git a/rosapps/mc/src/widget.c b/rosapps/mc/src/widget.c
new file mode 100644 (file)
index 0000000..4741c9a
--- /dev/null
@@ -0,0 +1,2499 @@
+/* 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
diff --git a/rosapps/mc/src/widget.h b/rosapps/mc/src/widget.h
new file mode 100644 (file)
index 0000000..d4db09d
--- /dev/null
@@ -0,0 +1,245 @@
+#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 */
diff --git a/rosapps/mc/src/win.c b/rosapps/mc/src/win.c
new file mode 100644 (file)
index 0000000..68f0615
--- /dev/null
@@ -0,0 +1,280 @@
+/* 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;
+}
+
diff --git a/rosapps/mc/src/win.h b/rosapps/mc/src/win.h
new file mode 100644 (file)
index 0000000..19d4295
--- /dev/null
@@ -0,0 +1,27 @@
+#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 */
diff --git a/rosapps/mc/src/wtools.c b/rosapps/mc/src/wtools.c
new file mode 100644 (file)
index 0000000..3069025
--- /dev/null
@@ -0,0 +1,740 @@
+/* {{{  */
+
+/* {{{ 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:
+*/
diff --git a/rosapps/mc/src/wtools.h b/rosapps/mc/src/wtools.h
new file mode 100644 (file)
index 0000000..3afc551
--- /dev/null
@@ -0,0 +1,89 @@
+#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 */
diff --git a/rosapps/mc/src/x.h b/rosapps/mc/src/x.h
new file mode 100644 (file)
index 0000000..65a3357
--- /dev/null
@@ -0,0 +1,25 @@
+
+#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
+
diff --git a/rosapps/mc/src/xcurses.c b/rosapps/mc/src/xcurses.c
new file mode 100644 (file)
index 0000000..f0e0135
--- /dev/null
@@ -0,0 +1,58 @@
+/* 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
+
diff --git a/rosapps/mc/src/xmkdir b/rosapps/mc/src/xmkdir
new file mode 100644 (file)
index 0000000..91f6d04
--- /dev/null
@@ -0,0 +1,32 @@
+#!/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
diff --git a/rosapps/mc/src/xslint.c b/rosapps/mc/src/xslint.c
new file mode 100644 (file)
index 0000000..43d2416
--- /dev/null
@@ -0,0 +1,98 @@
+/* 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)
+{
+}
diff --git a/rosapps/mc/version.in b/rosapps/mc/version.in
new file mode 100644 (file)
index 0000000..a44b122
--- /dev/null
@@ -0,0 +1 @@
+#define VERSION "@VERSION@"
diff --git a/rosapps/mc/vfs/Makefile b/rosapps/mc/vfs/Makefile
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs.h b/rosapps/mc/vfs/extfs.h
new file mode 100644 (file)
index 0000000..172a99a
--- /dev/null
@@ -0,0 +1,76 @@
+/* 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);
diff --git a/rosapps/mc/vfs/extfs/cpio b/rosapps/mc/vfs/extfs/cpio
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/deb b/rosapps/mc/vfs/extfs/deb
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/ftplist b/rosapps/mc/vfs/extfs/ftplist
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/lha b/rosapps/mc/vfs/extfs/lha
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/lslR b/rosapps/mc/vfs/extfs/lslR
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/rar b/rosapps/mc/vfs/extfs/rar
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/zip b/rosapps/mc/vfs/extfs/zip
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/extfs/zoo b/rosapps/mc/vfs/extfs/zoo
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/rosapps/mc/vfs/vfs.h b/rosapps/mc/vfs/vfs.h
new file mode 100644 (file)
index 0000000..0a5f341
--- /dev/null
@@ -0,0 +1,304 @@
+#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 */
+