From e5c0c7185e7ef48fb994bb407b2d18f15858ece0 Mon Sep 17 00:00:00 2001 From: Steven Edwards Date: Sun, 30 Dec 2001 10:02:14 +0000 Subject: [PATCH] Midnight Commander for Win32 svn path=/trunk/; revision=2456 --- rosapps/mc/Make.common | 105 + rosapps/mc/Makefile | 28 + rosapps/mc/Makefile.PC | 180 + rosapps/mc/VERSION | 1 + rosapps/mc/about-nls | 225 + rosapps/mc/acconfig.h | 249 + rosapps/mc/autogen.sh | 11 + rosapps/mc/config.cache | 179 + rosapps/mc/config.h | 575 ++ rosapps/mc/config.h.in | 574 ++ rosapps/mc/config.status | 810 ++ rosapps/mc/create_vcs | 20 + rosapps/mc/doc/Makefile | 0 rosapps/mc/doc/faq | 934 ++ rosapps/mc/doc/install | 529 + rosapps/mc/doc/install.fast | 70 + rosapps/mc/doc/mc.1 | 0 rosapps/mc/doc/mcedit.1 | 0 rosapps/mc/doc/mcserv.8 | 0 rosapps/mc/doc/news | 516 + rosapps/mc/doc/readme | 191 + rosapps/mc/doc/readme.nt | 126 + rosapps/mc/edit/Makefile | 86 + rosapps/mc/edit/edit.c | 2279 +++++ rosapps/mc/edit/edit.h | 633 ++ rosapps/mc/edit/edit_key_translator.c | 294 + rosapps/mc/edit/editcmd.c | 2541 +++++ rosapps/mc/edit/editcmddef.h | 138 + rosapps/mc/edit/editdraw.c | 648 ++ rosapps/mc/edit/editmenu.c | 455 + rosapps/mc/edit/editoptions.c | 182 + rosapps/mc/edit/editwidget.c | 1082 ++ rosapps/mc/edit/makefile.in | 84 + rosapps/mc/edit/readme.edit | 1 + rosapps/mc/edit/syntax.c | 1712 ++++ rosapps/mc/edit/wordproc.c | 350 + rosapps/mc/install-sh | 119 + rosapps/mc/make.common.in | 105 + rosapps/mc/mc.rc | 60 + rosapps/mc/mcfn_install | 67 + rosapps/mc/mcfn_install.in | 67 + rosapps/mc/mkinstalldirs | 40 + rosapps/mc/pc/Makefile | 28 + rosapps/mc/pc/Makefile.PC | 178 + rosapps/mc/pc/bugs | 15 + rosapps/mc/pc/changelog | 23 + rosapps/mc/pc/chmod.c | 495 + rosapps/mc/pc/config.h | 248 + rosapps/mc/pc/cons_nt.c | 112 + rosapps/mc/pc/cons_os2.c | 110 + rosapps/mc/pc/dirent.h | 35 + rosapps/mc/pc/dirent_nt.c | 92 + rosapps/mc/pc/dirent_os2.c | 110 + rosapps/mc/pc/drive.c | 226 + rosapps/mc/pc/drive.h | 4 + rosapps/mc/pc/key_nt.c | 325 + rosapps/mc/pc/key_os2.c | 408 + rosapps/mc/pc/mc.rc | 60 + rosapps/mc/pc/readme | 41 + rosapps/mc/pc/slint_pc.c | 269 + rosapps/mc/pc/sys/param.h | 7 + rosapps/mc/pc/sys/time.h___ | 16 + rosapps/mc/pc/todo | 12 + rosapps/mc/pc/trace_nt.c | 186 + rosapps/mc/pc/trace_nt.h | 72 + rosapps/mc/pc/util_nt.c | 749 ++ rosapps/mc/pc/util_os2.c | 854 ++ rosapps/mc/pc/util_win32.c | 187 + rosapps/mc/pc/util_win32.h | 42 + rosapps/mc/pc/util_winnt.c | 85 + rosapps/mc/pc/utime.h | 1 + rosapps/mc/slang/Makefile | 80 + rosapps/mc/slang/_slang.h | 325 + rosapps/mc/slang/jdmacros.h | 76 + rosapps/mc/slang/makefile.in | 78 + rosapps/mc/slang/readme | 12 + rosapps/mc/slang/sl-feat.h | 2 + rosapps/mc/slang/slang.h | 1284 +++ rosapps/mc/slang/sldisply.c | 2240 +++++ rosapps/mc/slang/slerr.c | 59 + rosapps/mc/slang/slgetkey.c | 125 + rosapps/mc/slang/slmemcpy.c | 51 + rosapps/mc/slang/slmemset.c | 43 + rosapps/mc/slang/slos2tty.c | 261 + rosapps/mc/slang/slsignal.c | 139 + rosapps/mc/slang/slsmg.c | 1185 +++ rosapps/mc/slang/sltermin.c | 913 ++ rosapps/mc/slang/sltoken.c | 355 + rosapps/mc/slang/slutty.c | 537 + rosapps/mc/slang/slvideo.c | 1594 +++ rosapps/mc/slang/slw32tty.c | 224 + rosapps/mc/src/Makefile | 153 + rosapps/mc/src/achown.c | 710 ++ rosapps/mc/src/achown.h | 4 + rosapps/mc/src/background.c | 562 ++ rosapps/mc/src/background.h | 60 + rosapps/mc/src/boxes.c | 991 ++ rosapps/mc/src/boxes.h | 16 + rosapps/mc/src/changelog | 1317 +++ rosapps/mc/src/chmod.c | 453 + rosapps/mc/src/chmod.h | 14 + rosapps/mc/src/chown.c | 356 + rosapps/mc/src/chown.h | 7 + rosapps/mc/src/cmd.c | 1573 +++ rosapps/mc/src/cmd.h | 71 + rosapps/mc/src/color.c | 318 + rosapps/mc/src/color.h | 80 + rosapps/mc/src/command.c | 285 + rosapps/mc/src/command.h | 18 + rosapps/mc/src/complete.c | 1056 ++ rosapps/mc/src/complete.h | 16 + rosapps/mc/src/cons.handler.c | 426 + rosapps/mc/src/cons.saver.c | 391 + rosapps/mc/src/cons.saver.h | 30 + rosapps/mc/src/depend.awk | 163 + rosapps/mc/src/dialog.c | 106 + rosapps/mc/src/dialog.h | 43 + rosapps/mc/src/dir.c | 659 ++ rosapps/mc/src/dir.h | 88 + rosapps/mc/src/dlg.c | 1055 ++ rosapps/mc/src/dlg.h | 317 + rosapps/mc/src/ext.c | 701 ++ rosapps/mc/src/ext.h | 18 + rosapps/mc/src/features.inc | 104 + rosapps/mc/src/file.c | 2968 ++++++ rosapps/mc/src/file.h | 51 + rosapps/mc/src/find.c | 951 ++ rosapps/mc/src/find.h | 27 + rosapps/mc/src/fixhlp.c | 247 + rosapps/mc/src/fs.h | 46 + rosapps/mc/src/fsusage.c | 192 + rosapps/mc/src/fsusage.h | 33 + rosapps/mc/src/gindex.pl | 26 + rosapps/mc/src/global.h | 33 + rosapps/mc/src/help.c | 833 ++ rosapps/mc/src/help.h | 32 + rosapps/mc/src/hotlist.c | 1610 +++ rosapps/mc/src/hotlist.h | 14 + rosapps/mc/src/i18n.h | 14 + rosapps/mc/src/info.c | 275 + rosapps/mc/src/info.h | 11 + rosapps/mc/src/key.c | 1022 ++ rosapps/mc/src/key.h | 91 + rosapps/mc/src/keyxdef.c | 418 + rosapps/mc/src/layout.c | 1192 +++ rosapps/mc/src/layout.h | 42 + rosapps/mc/src/learn.c | 369 + rosapps/mc/src/learn.h | 6 + rosapps/mc/src/listmode.c | 329 + rosapps/mc/src/listmode.h | 6 + rosapps/mc/src/mad.c | 250 + rosapps/mc/src/mad.h | 45 + rosapps/mc/src/main.c | 3203 ++++++ rosapps/mc/src/main.h | 197 + rosapps/mc/src/makefile.in | 151 + rosapps/mc/src/man2hlp.c | 533 + rosapps/mc/src/mc.hlp | 3193 ++++++ rosapps/mc/src/mem.h | 28 + rosapps/mc/src/menu.c | 529 + rosapps/mc/src/menu.h | 62 + rosapps/mc/src/mfmt.c | 153 + rosapps/mc/src/mountlist.c | 557 ++ rosapps/mc/src/mountlist.h | 32 + rosapps/mc/src/mouse.c | 279 + rosapps/mc/src/mouse.h | 91 + rosapps/mc/src/myslang.h | 141 + rosapps/mc/src/ncurses.patch | 19 + rosapps/mc/src/ochangelog | 12744 ++++++++++++++++++++++++ rosapps/mc/src/option.c | 278 + rosapps/mc/src/option.h | 4 + rosapps/mc/src/panel.h | 265 + rosapps/mc/src/panelize.c | 463 + rosapps/mc/src/panelize.h | 10 + rosapps/mc/src/popt.c | 681 ++ rosapps/mc/src/popt.h | 66 + rosapps/mc/src/profile.c | 563 ++ rosapps/mc/src/profile.h | 49 + rosapps/mc/src/regex.c | 5416 ++++++++++ rosapps/mc/src/regex.h | 491 + rosapps/mc/src/rxvt.c | 127 + rosapps/mc/src/screen.c | 2520 +++++ rosapps/mc/src/setup.c | 626 ++ rosapps/mc/src/setup.h | 36 + rosapps/mc/src/slint.c | 589 ++ rosapps/mc/src/subshell.c | 1211 +++ rosapps/mc/src/subshell.h | 46 + rosapps/mc/src/terms.c | 43 + rosapps/mc/src/text.c | 109 + rosapps/mc/src/textconf.h | 7 + rosapps/mc/src/todo | 215 + rosapps/mc/src/tree.c | 1593 +++ rosapps/mc/src/tree.h | 74 + rosapps/mc/src/tty.h | 141 + rosapps/mc/src/user.c | 733 ++ rosapps/mc/src/user.h | 23 + rosapps/mc/src/util.c | 1309 +++ rosapps/mc/src/util.h | 225 + rosapps/mc/src/utilunix.c | 933 ++ rosapps/mc/src/view.c | 2521 +++++ rosapps/mc/src/view.h | 195 + rosapps/mc/src/widget.c | 2499 +++++ rosapps/mc/src/widget.h | 245 + rosapps/mc/src/win.c | 280 + rosapps/mc/src/win.h | 27 + rosapps/mc/src/wtools.c | 740 ++ rosapps/mc/src/wtools.h | 89 + rosapps/mc/src/x.h | 25 + rosapps/mc/src/xcurses.c | 58 + rosapps/mc/src/xmkdir | 32 + rosapps/mc/src/xslint.c | 98 + rosapps/mc/version.in | 1 + rosapps/mc/vfs/Makefile | 0 rosapps/mc/vfs/extfs.h | 76 + rosapps/mc/vfs/extfs/cpio | 0 rosapps/mc/vfs/extfs/deb | 0 rosapps/mc/vfs/extfs/ftplist | 0 rosapps/mc/vfs/extfs/lha | 0 rosapps/mc/vfs/extfs/lslR | 0 rosapps/mc/vfs/extfs/rar | 0 rosapps/mc/vfs/extfs/zip | 0 rosapps/mc/vfs/extfs/zoo | 0 rosapps/mc/vfs/vfs.h | 304 + 222 files changed, 102081 insertions(+) create mode 100644 rosapps/mc/Make.common create mode 100644 rosapps/mc/Makefile create mode 100644 rosapps/mc/Makefile.PC create mode 100644 rosapps/mc/VERSION create mode 100644 rosapps/mc/about-nls create mode 100644 rosapps/mc/acconfig.h create mode 100644 rosapps/mc/autogen.sh create mode 100644 rosapps/mc/config.cache create mode 100644 rosapps/mc/config.h create mode 100644 rosapps/mc/config.h.in create mode 100644 rosapps/mc/config.status create mode 100644 rosapps/mc/create_vcs create mode 100644 rosapps/mc/doc/Makefile create mode 100644 rosapps/mc/doc/faq create mode 100644 rosapps/mc/doc/install create mode 100644 rosapps/mc/doc/install.fast create mode 100644 rosapps/mc/doc/mc.1 create mode 100644 rosapps/mc/doc/mcedit.1 create mode 100644 rosapps/mc/doc/mcserv.8 create mode 100644 rosapps/mc/doc/news create mode 100644 rosapps/mc/doc/readme create mode 100644 rosapps/mc/doc/readme.nt create mode 100644 rosapps/mc/edit/Makefile create mode 100644 rosapps/mc/edit/edit.c create mode 100644 rosapps/mc/edit/edit.h create mode 100644 rosapps/mc/edit/edit_key_translator.c create mode 100644 rosapps/mc/edit/editcmd.c create mode 100644 rosapps/mc/edit/editcmddef.h create mode 100644 rosapps/mc/edit/editdraw.c create mode 100644 rosapps/mc/edit/editmenu.c create mode 100644 rosapps/mc/edit/editoptions.c create mode 100644 rosapps/mc/edit/editwidget.c create mode 100644 rosapps/mc/edit/makefile.in create mode 100644 rosapps/mc/edit/readme.edit create mode 100644 rosapps/mc/edit/syntax.c create mode 100644 rosapps/mc/edit/wordproc.c create mode 100644 rosapps/mc/install-sh create mode 100644 rosapps/mc/make.common.in create mode 100644 rosapps/mc/mc.rc create mode 100644 rosapps/mc/mcfn_install create mode 100644 rosapps/mc/mcfn_install.in create mode 100644 rosapps/mc/mkinstalldirs create mode 100644 rosapps/mc/pc/Makefile create mode 100644 rosapps/mc/pc/Makefile.PC create mode 100644 rosapps/mc/pc/bugs create mode 100644 rosapps/mc/pc/changelog create mode 100644 rosapps/mc/pc/chmod.c create mode 100644 rosapps/mc/pc/config.h create mode 100644 rosapps/mc/pc/cons_nt.c create mode 100644 rosapps/mc/pc/cons_os2.c create mode 100644 rosapps/mc/pc/dirent.h create mode 100644 rosapps/mc/pc/dirent_nt.c create mode 100644 rosapps/mc/pc/dirent_os2.c create mode 100644 rosapps/mc/pc/drive.c create mode 100644 rosapps/mc/pc/drive.h create mode 100644 rosapps/mc/pc/key_nt.c create mode 100644 rosapps/mc/pc/key_os2.c create mode 100644 rosapps/mc/pc/mc.rc create mode 100644 rosapps/mc/pc/readme create mode 100644 rosapps/mc/pc/slint_pc.c create mode 100644 rosapps/mc/pc/sys/param.h create mode 100644 rosapps/mc/pc/sys/time.h___ create mode 100644 rosapps/mc/pc/todo create mode 100644 rosapps/mc/pc/trace_nt.c create mode 100644 rosapps/mc/pc/trace_nt.h create mode 100644 rosapps/mc/pc/util_nt.c create mode 100644 rosapps/mc/pc/util_os2.c create mode 100644 rosapps/mc/pc/util_win32.c create mode 100644 rosapps/mc/pc/util_win32.h create mode 100644 rosapps/mc/pc/util_winnt.c create mode 100644 rosapps/mc/pc/utime.h create mode 100644 rosapps/mc/slang/Makefile create mode 100644 rosapps/mc/slang/_slang.h create mode 100644 rosapps/mc/slang/jdmacros.h create mode 100644 rosapps/mc/slang/makefile.in create mode 100644 rosapps/mc/slang/readme create mode 100644 rosapps/mc/slang/sl-feat.h create mode 100644 rosapps/mc/slang/slang.h create mode 100644 rosapps/mc/slang/sldisply.c create mode 100644 rosapps/mc/slang/slerr.c create mode 100644 rosapps/mc/slang/slgetkey.c create mode 100644 rosapps/mc/slang/slmemcpy.c create mode 100644 rosapps/mc/slang/slmemset.c create mode 100644 rosapps/mc/slang/slos2tty.c create mode 100644 rosapps/mc/slang/slsignal.c create mode 100644 rosapps/mc/slang/slsmg.c create mode 100644 rosapps/mc/slang/sltermin.c create mode 100644 rosapps/mc/slang/sltoken.c create mode 100644 rosapps/mc/slang/slutty.c create mode 100644 rosapps/mc/slang/slvideo.c create mode 100644 rosapps/mc/slang/slw32tty.c create mode 100644 rosapps/mc/src/Makefile create mode 100644 rosapps/mc/src/achown.c create mode 100644 rosapps/mc/src/achown.h create mode 100644 rosapps/mc/src/background.c create mode 100644 rosapps/mc/src/background.h create mode 100644 rosapps/mc/src/boxes.c create mode 100644 rosapps/mc/src/boxes.h create mode 100644 rosapps/mc/src/changelog create mode 100644 rosapps/mc/src/chmod.c create mode 100644 rosapps/mc/src/chmod.h create mode 100644 rosapps/mc/src/chown.c create mode 100644 rosapps/mc/src/chown.h create mode 100644 rosapps/mc/src/cmd.c create mode 100644 rosapps/mc/src/cmd.h create mode 100644 rosapps/mc/src/color.c create mode 100644 rosapps/mc/src/color.h create mode 100644 rosapps/mc/src/command.c create mode 100644 rosapps/mc/src/command.h create mode 100644 rosapps/mc/src/complete.c create mode 100644 rosapps/mc/src/complete.h create mode 100644 rosapps/mc/src/cons.handler.c create mode 100644 rosapps/mc/src/cons.saver.c create mode 100644 rosapps/mc/src/cons.saver.h create mode 100644 rosapps/mc/src/depend.awk create mode 100644 rosapps/mc/src/dialog.c create mode 100644 rosapps/mc/src/dialog.h create mode 100644 rosapps/mc/src/dir.c create mode 100644 rosapps/mc/src/dir.h create mode 100644 rosapps/mc/src/dlg.c create mode 100644 rosapps/mc/src/dlg.h create mode 100644 rosapps/mc/src/ext.c create mode 100644 rosapps/mc/src/ext.h create mode 100644 rosapps/mc/src/features.inc create mode 100644 rosapps/mc/src/file.c create mode 100644 rosapps/mc/src/file.h create mode 100644 rosapps/mc/src/find.c create mode 100644 rosapps/mc/src/find.h create mode 100644 rosapps/mc/src/fixhlp.c create mode 100644 rosapps/mc/src/fs.h create mode 100644 rosapps/mc/src/fsusage.c create mode 100644 rosapps/mc/src/fsusage.h create mode 100644 rosapps/mc/src/gindex.pl create mode 100644 rosapps/mc/src/global.h create mode 100644 rosapps/mc/src/help.c create mode 100644 rosapps/mc/src/help.h create mode 100644 rosapps/mc/src/hotlist.c create mode 100644 rosapps/mc/src/hotlist.h create mode 100644 rosapps/mc/src/i18n.h create mode 100644 rosapps/mc/src/info.c create mode 100644 rosapps/mc/src/info.h create mode 100644 rosapps/mc/src/key.c create mode 100644 rosapps/mc/src/key.h create mode 100644 rosapps/mc/src/keyxdef.c create mode 100644 rosapps/mc/src/layout.c create mode 100644 rosapps/mc/src/layout.h create mode 100644 rosapps/mc/src/learn.c create mode 100644 rosapps/mc/src/learn.h create mode 100644 rosapps/mc/src/listmode.c create mode 100644 rosapps/mc/src/listmode.h create mode 100644 rosapps/mc/src/mad.c create mode 100644 rosapps/mc/src/mad.h create mode 100644 rosapps/mc/src/main.c create mode 100644 rosapps/mc/src/main.h create mode 100644 rosapps/mc/src/makefile.in create mode 100644 rosapps/mc/src/man2hlp.c create mode 100644 rosapps/mc/src/mc.hlp create mode 100644 rosapps/mc/src/mem.h create mode 100644 rosapps/mc/src/menu.c create mode 100644 rosapps/mc/src/menu.h create mode 100644 rosapps/mc/src/mfmt.c create mode 100644 rosapps/mc/src/mountlist.c create mode 100644 rosapps/mc/src/mountlist.h create mode 100644 rosapps/mc/src/mouse.c create mode 100644 rosapps/mc/src/mouse.h create mode 100644 rosapps/mc/src/myslang.h create mode 100644 rosapps/mc/src/ncurses.patch create mode 100644 rosapps/mc/src/ochangelog create mode 100644 rosapps/mc/src/option.c create mode 100644 rosapps/mc/src/option.h create mode 100644 rosapps/mc/src/panel.h create mode 100644 rosapps/mc/src/panelize.c create mode 100644 rosapps/mc/src/panelize.h create mode 100644 rosapps/mc/src/popt.c create mode 100644 rosapps/mc/src/popt.h create mode 100644 rosapps/mc/src/profile.c create mode 100644 rosapps/mc/src/profile.h create mode 100644 rosapps/mc/src/regex.c create mode 100644 rosapps/mc/src/regex.h create mode 100644 rosapps/mc/src/rxvt.c create mode 100644 rosapps/mc/src/screen.c create mode 100644 rosapps/mc/src/setup.c create mode 100644 rosapps/mc/src/setup.h create mode 100644 rosapps/mc/src/slint.c create mode 100644 rosapps/mc/src/subshell.c create mode 100644 rosapps/mc/src/subshell.h create mode 100644 rosapps/mc/src/terms.c create mode 100644 rosapps/mc/src/text.c create mode 100644 rosapps/mc/src/textconf.h create mode 100644 rosapps/mc/src/todo create mode 100644 rosapps/mc/src/tree.c create mode 100644 rosapps/mc/src/tree.h create mode 100644 rosapps/mc/src/tty.h create mode 100644 rosapps/mc/src/user.c create mode 100644 rosapps/mc/src/user.h create mode 100644 rosapps/mc/src/util.c create mode 100644 rosapps/mc/src/util.h create mode 100644 rosapps/mc/src/utilunix.c create mode 100644 rosapps/mc/src/view.c create mode 100644 rosapps/mc/src/view.h create mode 100644 rosapps/mc/src/widget.c create mode 100644 rosapps/mc/src/widget.h create mode 100644 rosapps/mc/src/win.c create mode 100644 rosapps/mc/src/win.h create mode 100644 rosapps/mc/src/wtools.c create mode 100644 rosapps/mc/src/wtools.h create mode 100644 rosapps/mc/src/x.h create mode 100644 rosapps/mc/src/xcurses.c create mode 100644 rosapps/mc/src/xmkdir create mode 100644 rosapps/mc/src/xslint.c create mode 100644 rosapps/mc/version.in create mode 100644 rosapps/mc/vfs/Makefile create mode 100644 rosapps/mc/vfs/extfs.h create mode 100644 rosapps/mc/vfs/extfs/cpio create mode 100644 rosapps/mc/vfs/extfs/deb create mode 100644 rosapps/mc/vfs/extfs/ftplist create mode 100644 rosapps/mc/vfs/extfs/lha create mode 100644 rosapps/mc/vfs/extfs/lslR create mode 100644 rosapps/mc/vfs/extfs/rar create mode 100644 rosapps/mc/vfs/extfs/zip create mode 100644 rosapps/mc/vfs/extfs/zoo create mode 100644 rosapps/mc/vfs/vfs.h diff --git a/rosapps/mc/Make.common b/rosapps/mc/Make.common new file mode 100644 index 00000000000..11a535b7582 --- /dev/null +++ b/rosapps/mc/Make.common @@ -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 index 00000000000..a7e01a38d68 --- /dev/null +++ b/rosapps/mc/Makefile @@ -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 index 00000000000..fa6274a3290 --- /dev/null +++ b/rosapps/mc/Makefile.PC @@ -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 index 00000000000..7fbca0fef6b --- /dev/null +++ b/rosapps/mc/VERSION @@ -0,0 +1 @@ +#define VERSION "4.1.36" diff --git a/rosapps/mc/about-nls b/rosapps/mc/about-nls new file mode 100644 index 00000000000..dacb8b18bed --- /dev/null +++ b/rosapps/mc/about-nls @@ -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 index 00000000000..00191755013 --- /dev/null +++ b/rosapps/mc/acconfig.h @@ -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 + + +@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, , libXext, */ +#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 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 +#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 index 00000000000..b2177508ca6 --- /dev/null +++ b/rosapps/mc/autogen.sh @@ -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 index 00000000000..84016bab44d --- /dev/null +++ b/rosapps/mc/config.cache @@ -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 index 00000000000..d8cf12eb348 --- /dev/null +++ b/rosapps/mc/config.h @@ -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 + + + +/* 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 doesn't define. */ +/* #undef gid_t */ + +/* Define if you have alloca, as a function or macro. */ +#define HAVE_ALLOCA 1 + +/* Define if you have 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 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 . */ +/* #undef MAJOR_IN_MKDEV */ + +/* Define if major, minor, and makedev are declared in . */ +#define MAJOR_IN_SYSMACROS 1 + +/* Define if on MINIX. */ +/* #undef _MINIX */ + +/* Define to `int' if doesn't define. */ +/* #undef mode_t */ + +/* Define to `long' if doesn't define. */ +/* #undef off_t */ + +/* Define to `int' if 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 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 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, , libXext, */ +/* #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 header file. */ +/* #undef HAVE_ARGZ_H */ + +/* Define if you have the header file. */ +#define HAVE_CRYPT_H 1 + +/* Define if you have the header file. */ +#define HAVE_DIRENT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_EXT2FS_EXT2FS_H */ + +/* Define if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define if you have the header file. */ +#define HAVE_GRP_H 1 + +/* Define if you have the header file. */ +#define HAVE_LIMITS_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_LINUX_EXT2_FS_H */ + +/* Define if you have the header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you have the header file. */ +#define HAVE_MALLOC_H 1 + +/* Define if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define if you have the header file. */ +#define HAVE_MNTENT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_MNTTAB_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NDIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_NL_TYPES_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_RPC_PMAP_CLNT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SHADOW_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SHADOW_SHADOW_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SLANG_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SLANG_SLANG_H */ + +/* Define if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DIR_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_DUSTAT_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FILSYS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FS_TYPES_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_FSTYP_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_MOUNT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_NDIR_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_STATFS_H */ + +/* Define if you have the header file. */ +/* #undef HAVE_SYS_STATVFS_H */ + +/* Define if you have the header file. */ +#define HAVE_SYS_VFS_H 1 + +/* Define if you have the header file. */ +#define HAVE_TERMIOS_H 1 + +/* Define if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define if you have the 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 +#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 index 00000000000..1c5e449afb8 --- /dev/null +++ b/rosapps/mc/config.h.in @@ -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 + + + +/* 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 doesn't define. */ +#undef gid_t + +/* Define if you have alloca, as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define if you have 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 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 . */ +#undef MAJOR_IN_MKDEV + +/* Define if major, minor, and makedev are declared in . */ +#undef MAJOR_IN_SYSMACROS + +/* Define if on MINIX. */ +#undef _MINIX + +/* Define to `int' if doesn't define. */ +#undef mode_t + +/* Define to `long' if doesn't define. */ +#undef off_t + +/* Define to `int' if 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 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 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, , libXext, */ +#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 header file. */ +#undef HAVE_ARGZ_H + +/* Define if you have the header file. */ +#undef HAVE_CRYPT_H + +/* Define if you have the header file. */ +#undef HAVE_DIRENT_H + +/* Define if you have the header file. */ +#undef HAVE_EXT2FS_EXT2FS_H + +/* Define if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define if you have the header file. */ +#undef HAVE_GRP_H + +/* Define if you have the header file. */ +#undef HAVE_LIMITS_H + +/* Define if you have the header file. */ +#undef HAVE_LINUX_EXT2_FS_H + +/* Define if you have the header file. */ +#undef HAVE_LOCALE_H + +/* Define if you have the header file. */ +#undef HAVE_MALLOC_H + +/* Define if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define if you have the header file. */ +#undef HAVE_MNTENT_H + +/* Define if you have the header file. */ +#undef HAVE_MNTTAB_H + +/* Define if you have the header file. */ +#undef HAVE_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_NL_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_RPC_PMAP_CLNT_H + +/* Define if you have the header file. */ +#undef HAVE_SHADOW_H + +/* Define if you have the header file. */ +#undef HAVE_SHADOW_SHADOW_H + +/* Define if you have the header file. */ +#undef HAVE_SLANG_H + +/* Define if you have the header file. */ +#undef HAVE_SLANG_SLANG_H + +/* Define if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define if you have the header file. */ +#undef HAVE_STRING_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_DUSTAT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FILSYS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FS_TYPES_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_FSTYP_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_NDIR_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STATFS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_STATVFS_H + +/* Define if you have the header file. */ +#undef HAVE_SYS_VFS_H + +/* Define if you have the header file. */ +#undef HAVE_TERMIOS_H + +/* Define if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define if you have the 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 +#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 index 00000000000..0733db4a8a1 --- /dev/null +++ b/rosapps/mc/config.status @@ -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 %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 < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < conftest.out + rm -f conftest.in + mv conftest.out conftest.in + + cat > conftest.frag < 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 index 00000000000..389216f566a --- /dev/null +++ b/rosapps/mc/create_vcs @@ -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 index 00000000000..e69de29bb2d diff --git a/rosapps/mc/doc/faq b/rosapps/mc/doc/faq new file mode 100644 index 00000000000..df9f119ac54 --- /dev/null +++ b/rosapps/mc/doc/faq @@ -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 + + 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 [optional-address] + + Replace 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 + . + diff --git a/rosapps/mc/doc/install b/rosapps/mc/doc/install new file mode 100644 index 00000000000..c6d28d83312 --- /dev/null +++ b/rosapps/mc/doc/install @@ -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 +, 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 + + + +- 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 [address] + +The address is optional and list-name is one of the above list names +(mc, mc-announce, mc-patches or mc-digest). + + +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). + + +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 + + +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 index 00000000000..1bb3453e619 --- /dev/null +++ b/rosapps/mc/doc/install.fast @@ -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 index 00000000000..e69de29bb2d diff --git a/rosapps/mc/doc/mcedit.1 b/rosapps/mc/doc/mcedit.1 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/rosapps/mc/doc/mcserv.8 b/rosapps/mc/doc/mcserv.8 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/rosapps/mc/doc/news b/rosapps/mc/doc/news new file mode 100644 index 00000000000..136a8855f92 --- /dev/null +++ b/rosapps/mc/doc/news @@ -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 ). +- 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 index 00000000000..6d118941cb9 --- /dev/null +++ b/rosapps/mc/doc/readme @@ -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: +. + + +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 + 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 index 00000000000..8f13dd67f44 --- /dev/null +++ b/rosapps/mc/doc/readme.nt @@ -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 index 00000000000..4dbfbcd81a1 --- /dev/null +++ b/rosapps/mc/edit/Makefile @@ -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 index 00000000000..f5dbb4efedd --- /dev/null +++ b/rosapps/mc/edit/edit.c @@ -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 +#if defined(OS2_NT) +# include +# include +# define CR_LF_TRANSLATION +#endif +#include "edit.h" + +#ifdef SCO_FLAVOR +# include +#endif /* SCO_FLAVOR */ +#include /* 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–linefeed (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 index 00000000000..5f965c526a3 --- /dev/null +++ b/rosapps/mc/edit/edit.h @@ -0,0 +1,633 @@ +#ifndef __EDIT_H +#define __EDIT_H + +#ifdef MIDNIGHT + +#ifdef HAVE_SLANG +#define HAVE_SYNTAXH 1 +#endif + +# include +# include +# include +# ifdef HAVE_UNISTD_H +# include +# endif +# include +# include "../src/tty.h" +# include +# include + +# ifdef HAVE_FCNTL_H +# include +# endif + +# include +# include + +#else /* ! MIDNIGHT */ + +# include "global.h" +# include +# include +# include + +# ifdef HAVE_UNISTD_H +# include +# endif + +# include +# include + +# ifdef HAVE_FCNTL_H +# include +# endif + +# include +# include + +# if TIME_WITH_SYS_TIME +# include +# include +# else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +# endif + +# include "regex.h" + +#endif + +#ifndef MIDNIGHT + +# include +# include +# include +# include +# 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 index 00000000000..068a21a9d81 --- /dev/null +++ b/rosapps/mc/edit/edit_key_translator.c @@ -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 index 00000000000..7e846adc58f --- /dev/null +++ b/rosapps/mc/edit/editcmd.c @@ -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 +#ifdef OS2_NT +#include +#include +#endif +#include +#include "edit.h" +#include "editcmddef.h" + +#ifndef MIDNIGHT +#include +#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" added backup filenames + ...thanks -paul */ + +/* If 0 (quick save) then a) create/truncate file, + b) save to ; + if 1 (safe save) then a) save to , + b) rename to ; + if 2 (do backups) then a) save to , + b) rename to , + c) rename to . */ + +/* returns 0 on error */ +int edit_save_file (WEdit * edit, const char *filename) +{ + long buf; + long filelen = 0; + int file; + char *savename = (char *) filename; + int this_save_mode; + + if ((file = open (savename, O_WRONLY)) == -1) { + this_save_mode = 0; /* the file does not exists yet, so no safe save or backup necessary */ + } else { + close (file); + this_save_mode = option_save_mode; + } + + if (this_save_mode > 0) { + char *savedir = ".", *slashpos = strrchr (filename, '/'); + if (slashpos != 0) { + savedir = strdup (filename); + if (savedir == 0) + return 0; + savedir[slashpos - filename + 1] = '\0'; + } +#ifdef HAVE_MAD + savename = strdup (tempnam (savedir, "cooledit")); +#else + savename = tempnam (savedir, "cooledit"); +#endif + if (slashpos) + free (savedir); + if (!savename) + return 0; + } + if ((file = open (savename, O_CREAT | O_WRONLY | O_TRUNC | MY_O_TEXT, edit->stat.st_mode)) == -1) { + if (this_save_mode > 0) + free (savename); + return 0; + } + chown (savename, edit->stat.st_uid, edit->stat.st_gid); + buf = 0; + while (buf <= (edit->curs1 >> S_EDIT_BUF_SIZE) - 1) { + filelen += write (file, (char *) edit->buffers1[buf], EDIT_BUF_SIZE); + buf++; + } + filelen += write (file, (char *) edit->buffers1[buf], edit->curs1 & M_EDIT_BUF_SIZE); + + if (edit->curs2) { + edit->curs2--; + buf = (edit->curs2 >> S_EDIT_BUF_SIZE); + filelen += write (file, (char *) edit->buffers2[buf] + EDIT_BUF_SIZE - (edit->curs2 & M_EDIT_BUF_SIZE) - 1, 1 + (edit->curs2 & M_EDIT_BUF_SIZE)); + buf--; + while (buf >= 0) { + filelen += write (file, (char *) edit->buffers2[buf], EDIT_BUF_SIZE); + buf--; + } + edit->curs2++; + } + close (file); + + if (filelen == edit->last_byte) { + if (this_save_mode == 2) { + if (rename (filename, catstrs (filename, option_backup_ext, 0)) == -1) { /* catstrs free's automatically */ + free (savename); + return 0; + } + } + if (this_save_mode > 0) { + if (rename (savename, filename) == -1) { + free (savename); + return 0; + } + free (savename); + } + return 1; + } else { + if (this_save_mode > 0) + free (savename); + return 0; + } +} + +#ifdef MIDNIGHT +/* + I changed this from Oleg's original routine so + that option_backup_ext works with coolwidgets as well. This + does mean there is a memory leak - paul. + */ +void menu_save_mode_cmd (void) +{ +#define DLG_X 36 +#define DLG_Y 10 + static char *str_result; + static int save_mode_new; + static char *str[] = + { + "Quick save ", + "Safe save ", + "Do backups -->"}; + static QuickWidget widgets[] = + { + {quick_button, 18, DLG_X, 7, DLG_Y, "&Cancel", 0, + B_CANCEL, 0, 0, XV_WLAY_DONTCARE, "c"}, + {quick_button, 6, DLG_X, 7, DLG_Y, "&Ok", 0, + B_ENTER, 0, 0, XV_WLAY_DONTCARE, "o"}, + {quick_input, 23, DLG_X, 5, DLG_Y, 0, 9, + 0, 0, &str_result, XV_WLAY_DONTCARE, "i"}, + {quick_label, 22, DLG_X, 4, DLG_Y, "Extension:", 0, + 0, 0, 0, XV_WLAY_DONTCARE, "savemext"}, + {quick_radio, 4, DLG_X, 3, DLG_Y, "", 3, + 0, &save_mode_new, str, XV_WLAY_DONTCARE, "t"}, + {0}}; + static QuickDialog dialog = +/* NLS ? */ + {DLG_X, DLG_Y, -1, -1, " Edit Save Mode ", "[Edit Save Mode]", + "esm", widgets}; + + widgets[2].text = option_backup_ext; + widgets[4].value = option_save_mode; + if (quick_dialog (&dialog) != B_ENTER) + return; + option_save_mode = save_mode_new; + option_backup_ext = str_result; /* this is a memory leak */ + option_backup_ext_int = 0; + str_result[min (strlen (str_result), sizeof (int))] = '\0'; + memcpy ((char *) &option_backup_ext_int, str_result, strlen (option_backup_ext)); +} + +#endif + +#ifdef MIDNIGHT + +void edit_split_filename (WEdit * edit, char *f) +{ + if (edit->filename) + free (edit->filename); + edit->filename = strdup (f); + if (edit->dir) + free (edit->dir); + edit->dir = strdup (""); +} + +#else + +void edit_split_filename (WEdit * edit, char *longname) +{ + char *exp, *p; + exp = canonicalize_pathname (longname); /* this ensures a full path */ + if (edit->filename) + free (edit->filename); + if (edit->dir) + free (edit->dir); + p = strrchr (exp, '/'); + edit->filename = strdup (++p); + *p = 0; + edit->dir = strdup (exp); + free (exp); +} + +#endif + +/* here we want to warn the user of overwriting an existing file, but only if they + have made a change to the filename */ +/* returns 1 on success */ +int edit_save_as_cmd (WEdit * edit) +{ +/* This heads the 'Save As' dialog box */ + char *exp = edit_get_save_file (edit->dir, edit->filename, _(" Save As ")); + int different_filename = 0; + edit_push_action (edit, KEY_PRESS + edit->start_display); + edit->force |= REDRAW_COMPLETELY; + + if (exp) { + if (!*exp) { + free (exp); + return 0; + } else { + if (strcmp(catstrs (edit->dir, edit->filename, 0), exp)) { + int file; + different_filename = 1; + if ((file = open ((char *) exp, O_RDONLY)) != -1) { /* the file exists */ + close (file); + if (edit_query_dialog2 (_(" Warning "), + _(" A file already exists with this name. "), +/* Push buttons to over-write the current file, or cancel the operation */ + _("Overwrite"), _("Cancel"))) + return 0; + } + } + if (edit_save_file (edit, exp)) { + edit_split_filename (edit, exp); + free (exp); + edit->modified = 0; +#ifdef MIDNIGHT + edit->delete_file = 0; +#endif + if (different_filename && !edit->explicit_syntax) + edit_load_syntax (edit, 0, 0); + return 1; + } else { + free (exp); + edit_error_dialog (_(" Save as "), get_sys_error (_(" Error trying to save file. "))); + return 0; + } + } + } else + return 0; +} + +/* {{{ Macro stuff starts here */ + +#ifdef MIDNIGHT +int raw_callback (struct Dlg_head *h, int key, int Msg) +{ + switch (Msg) { + case DLG_DRAW: + attrset (REVERSE_COLOR); + dlg_erase (h); + draw_box (h, 1, 1, h->lines - 2, h->cols - 2); + + attrset (COLOR_HOT_NORMAL); + dlg_move (h, 1, 2); + printw (h->title); + break; + + case DLG_KEY: + h->running = 0; + h->ret_value = key; + return 1; + } + return 0; +} + +/* gets a raw key from the keyboard. Passing cancel = 1 draws + a cancel button thus allowing c-c etc.. Alternatively, cancel = 0 + will return the next key pressed */ +int edit_raw_key_query (char *heading, char *query, int cancel) +{ + int w = strlen (query) + 7; + struct Dlg_head *raw_dlg = create_dlg (0, 0, 7, w, dialog_colors, +/* NLS ? */ + raw_callback, "[Raw Key Query]", + "raw_key_input", + DLG_CENTER | DLG_TRYUP); + x_set_dialog_title (raw_dlg, heading); + raw_dlg->raw = 1; /* to return even a tab key */ + if (cancel) + add_widget (raw_dlg, button_new (4, w / 2 - 5, B_CANCEL, NORMAL_BUTTON, "Cancel", 0, 0, 0)); + add_widget (raw_dlg, label_new (3 - cancel, 2, query, 0)); + add_widget (raw_dlg, input_new (3 - cancel, w - 5, INPUT_COLOR, 2, "", 0)); + run_dlg (raw_dlg); + w = raw_dlg->ret_value; + destroy_dlg (raw_dlg); + if (cancel) + if (w == XCTRL ('g') || w == XCTRL ('c') || w == ESC_CHAR || w == B_CANCEL) + return 0; +/* hence ctrl-a (=B_CANCEL), ctrl-g, ctrl-c, and Esc are cannot returned */ + return w; +} + +#else + +int edit_raw_key_query (char *heading, char *query, int cancel) +{ + return CKeySymMod (CRawkeyQuery (0, 0, 0, heading, query)); +} + +#endif + +/* creates a macro file if it doesn't exist */ +static FILE *edit_open_macro_file (const char *r) +{ + char *filename; + int file; + filename = catstrs (home_dir, MACRO_FILE, 0); + if ((file = open (filename, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) + return 0; + close (file); + return fopen (filename, r); +} + +#define MAX_MACROS 1024 +static int saved_macro[MAX_MACROS + 1] = +{0, 0}; +static int saved_macros_loaded = 0; + +/* + This is just to stop the macro file be loaded over and over for keys + that aren't defined to anything. On slow systems this could be annoying. + */ +int macro_exists (int k) +{ + int i; + for (i = 0; i < MAX_MACROS && saved_macro[i]; i++) + if (saved_macro[i] == k) + return i; + return -1; +} + +/* returns 1 on error */ +int edit_delete_macro (WEdit * edit, int k) +{ + struct macro macro[MAX_MACRO_LENGTH]; + FILE *f, *g; + int s, i, n, j = 0; + + if (saved_macros_loaded) + if ((j = macro_exists (k)) < 0) + return 0; + g = fopen (catstrs (home_dir, TEMP_FILE, 0), "w"); + if (!g) { +/* This heads the delete macro error dialog box */ + edit_error_dialog (_(" Delete macro "), +/* 'Open' = load temp file */ + get_sys_error (_(" Error trying to open temp file "))); + return 1; + } + f = edit_open_macro_file ("r"); + if (!f) { +/* This heads the delete macro error dialog box */ + edit_error_dialog (_(" Delete macro "), +/* 'Open' = load temp file */ + get_sys_error (_(" Error trying to open macro file "))); + fclose (g); + return 1; + } + for (;;) { + n = fscanf (f, _("key '%d 0': "), &s); + if (!n || n == EOF) + break; + n = 0; + while (fscanf (f, "%hd %hd, ", ¯o[n].command, ¯o[n].ch)) + n++; + fscanf (f, ";\n"); + if (s != k) { + fprintf (g, _("key '%d 0': "), s); + for (i = 0; i < n; i++) + fprintf (g, "%hd %hd, ", macro[i].command, macro[i].ch); + fprintf (g, ";\n"); + } + }; + fclose (f); + fclose (g); + if (rename (catstrs (home_dir, TEMP_FILE, 0), catstrs (home_dir, MACRO_FILE, 0)) == -1) { +/* This heads the delete macro error dialog box */ + edit_error_dialog (_(" Delete macro "), + get_sys_error (_(" Error trying to overwrite macro file "))); + return 1; + } + if (saved_macros_loaded) + memmove (saved_macro + j, saved_macro + j + 1, sizeof (int) * (MAX_MACROS - j - 1)); + return 0; +} + +/* returns 0 on error */ +int edit_save_macro_cmd (WEdit * edit, struct macro macro[], int n) +{ + FILE *f; + int s, i; + + edit->force |= REDRAW_COMPLETELY; + edit_push_action (edit, KEY_PRESS + edit->start_display); +/* This heads the 'Macro' dialog box */ + s = edit_raw_key_query (_(" Macro "), +/* Input line for a single key press follows the ':' */ + _(" Press the macro's new hotkey: "), 1); + if (s) { + if (edit_delete_macro (edit, s)) + return 0; + f = edit_open_macro_file ("a+"); + if (f) { + fprintf (f, _("key '%d 0': "), s); + for (i = 0; i < n; i++) + fprintf (f, "%hd %hd, ", macro[i].command, macro[i].ch); + fprintf (f, ";\n"); + fclose (f); + if (saved_macros_loaded) { + for (i = 0; i < MAX_MACROS && saved_macro[i]; i++); + saved_macro[i] = s; + } + return 1; + } else +/* This heads the 'Save Macro' dialog box */ + edit_error_dialog (_(" Save macro "), get_sys_error (_(" Error trying to open macro file "))); + } + return 0; +} + +void edit_delete_macro_cmd (WEdit * edit) +{ + int command; + +#ifdef MIDNIGHT + command = CK_Macro (edit_raw_key_query (_(" Delete Macro "), _(" Press macro hotkey: "), 1)); +#else +/* This heads the 'Delete Macro' dialog box */ + command = CK_Macro (CKeySymMod (CRawkeyQuery (0, 0, 0, _(" Delete Macro "), +/* Input line for a single key press follows the ':' */ + _(" Press macro hotkey: ")))); +#endif + + if (command == CK_Macro (0)) + return; + + edit_delete_macro (edit, command - 2000); +} + +/* return 0 on error */ +int edit_load_macro_cmd (WEdit * edit, struct macro macro[], int *n, int k) +{ + FILE *f; + int s, i = 0, found = 0; + + if (saved_macros_loaded) + if (macro_exists (k) < 0) + return 0; + + if ((f = edit_open_macro_file ("r"))) { + struct macro dummy; + do { + int u; + u = fscanf (f, _("key '%d 0': "), &s); + if (!u || u == EOF) + break; + if (!saved_macros_loaded) + saved_macro[i++] = s; + if (!found) { + *n = 0; + while (*n < MAX_MACRO_LENGTH && 2 == fscanf (f, "%hd %hd, ", ¯o[*n].command, ¯o[*n].ch)) + (*n)++; + } else { + while (2 == fscanf (f, "%hd %hd, ", &dummy.command, &dummy.ch)); + } + fscanf (f, ";\n"); + if (s == k) + found = 1; + } while (!found || !saved_macros_loaded); + if (!saved_macros_loaded) { + saved_macro[i] = 0; + saved_macros_loaded = 1; + } + fclose (f); + return found; + } else +/* This heads the 'Load Macro' dialog box */ + edit_error_dialog (_(" Load macro "), + get_sys_error (_(" Error trying to open macro file "))); + return 0; +} + +/* }}} Macro stuff starts here */ + +/* returns 1 on success */ +int edit_save_confirm_cmd (WEdit * edit) +{ + char *f; + + if (edit_confirm_save) { +#ifdef MIDNIGHT + f = catstrs (_(" Confirm save file? : "), edit->filename, " ", 0); +#else + f = catstrs (_(" Confirm save file? : "), edit->dir, edit->filename, " ", 0); +#endif +/* Buttons to 'Confirm save file' query */ + if (edit_query_dialog2 (_(" Save file "), f, _("Save"), _("Cancel"))) + return 0; + } + return edit_save_cmd (edit); +} + + +/* returns 1 on success */ +int edit_save_cmd (WEdit * edit) +{ + edit->force |= REDRAW_COMPLETELY; + if (!edit_save_file (edit, catstrs (edit->dir, edit->filename, 0))) + return edit_save_as_cmd (edit); + edit->modified = 0; +#ifdef MIDNIGHT + edit->delete_file = 0; +#endif + + return 1; +} + + +/* returns 1 on success */ +int edit_new_cmd (WEdit * edit) +{ + edit->force |= REDRAW_COMPLETELY; + if (edit->modified) + if (edit_query_dialog2 (_(" Warning "), _(" Current text was modified without a file save. \n Continue discards these changes. "), _("Continue"), _("Cancel"))) + return 0; + edit->modified = 0; + return edit_renew (edit); /* if this gives an error, something has really screwed up */ +} + +int edit_load_cmd (WEdit * edit) +{ + char *exp; + edit->force |= REDRAW_COMPLETELY; + + if (edit->modified) + if (edit_query_dialog2 (_(" Warning "), _(" Current text was modified without a file save. \n Continue discards these changes. "), _("Continue"), _("Cancel"))) + return 0; + + exp = edit_get_load_file (edit->dir, edit->filename, _(" Load ")); + + if (exp) { + if (!*exp) { + free (exp); + } else { + int file; + if ((file = open ((char *) exp, O_RDONLY, MY_O_TEXT)) != -1) { + close (file); + edit_reload (edit, exp, 0, "", 0); + edit_split_filename (edit, exp); + free (exp); + edit->modified = 0; + return 1; + } else { + free (exp); +/* Heads the 'Load' file dialog box */ + edit_error_dialog (_(" Load "), get_sys_error (_(" Error trying to open file for reading "))); + } + } + } + return 0; +} + +/* + if mark2 is -1 then marking is from mark1 to the cursor. + Otherwise its between the markers. This handles this. + Returns 1 if no text is marked. + */ +int eval_marks (WEdit * edit, long *start_mark, long *end_mark) +{ + if (edit->mark1 != edit->mark2) { + if (edit->mark2 >= 0) { + *start_mark = min (edit->mark1, edit->mark2); + *end_mark = max (edit->mark1, edit->mark2); + } else { + *start_mark = min (edit->mark1, edit->curs1); + *end_mark = max (edit->mark1, edit->curs1); + edit->column2 = edit->curs_col; + } + return 0; + } else { + *start_mark = *end_mark = 0; + edit->column2 = edit->column1 = 0; + return 1; + } +} + +/*Block copy, move and delete commands */ + +void edit_block_copy_cmd (WEdit * edit) +{ + long start_mark, end_mark, current = edit->curs1; + long count; + char *copy_buf; + + if (eval_marks (edit, &start_mark, &end_mark)) + return; + + + copy_buf = malloc (end_mark - start_mark); + +/* all that gets pushed are deletes hence little space is used on the stack */ + + edit_push_markers (edit); + + count = start_mark; + while (count < end_mark) { + copy_buf[end_mark - count - 1] = edit_get_byte (edit, count); + count++; + } + while (count-- > start_mark) { + edit_insert_ahead (edit, copy_buf[end_mark - count - 1]); + } + free (copy_buf); + edit_scroll_screen_over_cursor (edit); + + if (start_mark < current && end_mark > current) + edit_set_markers (edit, start_mark, end_mark + end_mark - start_mark, 0, 0); + + edit->force |= REDRAW_PAGE; +} + + +void edit_block_move_cmd (WEdit * edit) +{ + long count; + long current; + char *copy_buf; + long start_mark, end_mark; + + if (eval_marks (edit, &start_mark, &end_mark)) + return; + + if (start_mark <= edit->curs1 && end_mark >= edit->curs1) + return; + + if ((end_mark - start_mark) > option_max_undo / 2) + if (edit_query_dialog2 (_(" Warning "), _(" Block is large, you may not be able to undo this action. "), _("Continue"), _("Cancel"))) + return; + + copy_buf = malloc (end_mark - start_mark); + + edit_push_markers (edit); + + current = edit->curs1; + edit_cursor_move (edit, start_mark - edit->curs1); + edit_scroll_screen_over_cursor (edit); + + count = start_mark; + while (count < end_mark) { + copy_buf[end_mark - count - 1] = edit_delete (edit); + count++; + } + edit_scroll_screen_over_cursor (edit); + + edit_cursor_move (edit, current - edit->curs1 + - (((current - edit->curs1) > 0) ? end_mark - start_mark : 0)); + edit_scroll_screen_over_cursor (edit); + + while (count-- > start_mark) { + edit_insert_ahead (edit, copy_buf[end_mark - count - 1]); + edit_set_markers (edit, edit->curs1, edit->curs1 + end_mark - start_mark, 0, 0); + } + edit_scroll_screen_over_cursor (edit); + + free (copy_buf); + edit->force |= REDRAW_PAGE; +} + +void edit_cursor_to_bol (WEdit * edit); + +extern int column_highlighting; + +void edit_delete_column_of_text (WEdit * edit) +{ + long p, q, r, m1, m2; + int b, c, d, fin; + + eval_marks (edit, &m1, &m2); + c = edit_move_forward3 (edit, edit_bol (edit, m1), 0, m1); + d = edit_move_forward3 (edit, edit_bol (edit, m2), 0, m2); + + b = min (c, d); + c = max (c, d); + + fin = 0; + while (!fin) { + eval_marks (edit, &m1, &m2); + r = edit_bol (edit, edit->curs1); + p = edit_move_forward3 (edit, r, b, 0); + q = edit_move_forward3 (edit, r, c, 0); + if (p < m1) + p = m1; + if (q >= m2) { + q = m2; + fin = 1; + } + edit_cursor_move (edit, p - edit->curs1); + while (p != q) { /* delete line between margins */ + if (edit_get_byte (edit, edit->curs1) != '\n') + edit_delete (edit); + q--; + } + if (!fin) /* next line */ + edit_cursor_move (edit, edit_move_forward (edit, edit->curs1, 1, 0) - edit->curs1); + } +} + +/* returns 1 if canceelled by user */ +int edit_block_delete_cmd (WEdit * edit) +{ + long count; + long start_mark, end_mark; + + if (eval_marks (edit, &start_mark, &end_mark)) { + start_mark = edit_bol (edit, edit->curs1); + end_mark = edit_eol (edit, edit->curs1) + 1; + } + if ((end_mark - start_mark) > option_max_undo / 2) +/* Warning message with a query to continue or cancel the operation */ + if (edit_query_dialog2 (_(" Warning "), _(" Block is large, you may not be able to undo this action. "), _(" Continue "), _(" Cancel "))) + return 1; + + edit_push_markers (edit); + + edit_cursor_move (edit, start_mark - edit->curs1); + edit_scroll_screen_over_cursor (edit); + + count = start_mark; + if (start_mark < end_mark) { + if (column_highlighting) { + edit_delete_column_of_text (edit); + } else { + while (count < end_mark) { + edit_delete (edit); + count++; + } + } + } + edit_set_markers (edit, 0, 0, 0, 0); + edit->force |= REDRAW_PAGE; + + return 0; +} + + +#ifdef MIDNIGHT + +#define INPUT_INDEX 9 +#define SEARCH_DLG_HEIGHT 10 +#define REPLACE_DLG_HEIGHT 15 +#define B_REPLACE_ALL B_USER+1 +#define B_SKIP_REPLACE B_USER+2 + +int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos) +{ + if (replace_prompt) { + QuickWidget quick_widgets[] = + { +/* NLS for hotkeys? */ + {quick_button, 14, 18, 3, 6, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 9, 18, 3, 6, "Replace &all", 0, B_REPLACE_ALL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 6, 18, 3, 6, "&Skip", 0, B_SKIP_REPLACE, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 18, 3, 6, "&Replace", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_label, 2, 50, 2, 6, 0, + 0, 0, 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[4].text = catstrs (_(" Replace with: "), replace_text, 0); + + { + QuickDialog Quick_input = + {66, 6, 0, 0, N_(" Replace "), + "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ }; + + Quick_input.widgets = quick_widgets; + + Quick_input.xpos = xpos; + Quick_input.ypos = ypos; + return quick_dialog (&Quick_input); + } + } else + return 0; +} + + + +void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order) +{ + int treplace_scanf = replace_scanf; + int treplace_regexp = replace_regexp; + int treplace_all = replace_all; + int treplace_prompt = replace_prompt; + int treplace_backwards = replace_backwards; + int treplace_whole = replace_whole; + int treplace_case = replace_case; + + char *tsearch_text; + char *treplace_text; + char *targ_order; + QuickWidget quick_widgets[] = + { + {quick_button, 6, 10, 12, REPLACE_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 10, 12, REPLACE_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 11, REPLACE_DLG_HEIGHT, "Scanf &expression", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 10, REPLACE_DLG_HEIGHT, "Replace &all", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 9, REPLACE_DLG_HEIGHT, "Pr&ompt on replace", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 11, REPLACE_DLG_HEIGHT, "&Backwards", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 10, REPLACE_DLG_HEIGHT, "&Regular exprssn", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 9, REPLACE_DLG_HEIGHT, "&Whole words only", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 8, REPLACE_DLG_HEIGHT, "Case &sensitive", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_input, 3, 50, 7, REPLACE_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-argord"}, + {quick_label, 2, 50, 6, REPLACE_DLG_HEIGHT, " Enter replacement argument order eg. 3,2,1,4 ", 0, 0, + 0, 0, XV_WLAY_DONTCARE, 0}, + {quick_input, 3, 50, 5, REPLACE_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-replace"}, + {quick_label, 2, 50, 4, REPLACE_DLG_HEIGHT, " Enter replacement string", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {quick_input, 3, 50, 3, REPLACE_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-search"}, + {quick_label, 2, 50, 2, REPLACE_DLG_HEIGHT, " Enter search string", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[2].result = &treplace_scanf; + quick_widgets[3].result = &treplace_all; + quick_widgets[4].result = &treplace_prompt; + quick_widgets[5].result = &treplace_backwards; + quick_widgets[6].result = &treplace_regexp; + quick_widgets[7].result = &treplace_whole; + quick_widgets[8].result = &treplace_case; + quick_widgets[9].str_result = &targ_order; + quick_widgets[9].text = *arg_order; + quick_widgets[11].str_result = &treplace_text; + quick_widgets[11].text = *replace_text; + quick_widgets[13].str_result = &tsearch_text; + quick_widgets[13].text = *search_text; + { + QuickDialog Quick_input = + {50, REPLACE_DLG_HEIGHT, -1, 0, N_(" Replace "), + "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ }; + + Quick_input.widgets = quick_widgets; + + if (quick_dialog (&Quick_input) != B_CANCEL) { + *arg_order = *(quick_widgets[INPUT_INDEX].str_result); + *replace_text = *(quick_widgets[INPUT_INDEX + 2].str_result); + *search_text = *(quick_widgets[INPUT_INDEX + 4].str_result); + replace_scanf = treplace_scanf; + replace_backwards = treplace_backwards; + replace_regexp = treplace_regexp; + replace_all = treplace_all; + replace_prompt = treplace_prompt; + replace_whole = treplace_whole; + replace_case = treplace_case; + return; + } else { + *arg_order = NULL; + *replace_text = NULL; + *search_text = NULL; + return; + } + } +} + + +void edit_search_dialog (WEdit * edit, char **search_text) +{ + int treplace_scanf = replace_scanf; + int treplace_regexp = replace_regexp; + int treplace_whole = replace_whole; + int treplace_case = replace_case; + int treplace_backwards = replace_backwards; + + char *tsearch_text; + QuickWidget quick_widgets[] = + { + {quick_button, 6, 10, 7, SEARCH_DLG_HEIGHT, "&Cancel", 0, B_CANCEL, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_button, 2, 10, 7, SEARCH_DLG_HEIGHT, "&Ok", 0, B_ENTER, 0, + 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 25, 50, 6, SEARCH_DLG_HEIGHT, "Scanf &expression", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL }, + {quick_checkbox, 25, 50, 5, SEARCH_DLG_HEIGHT, "&Backwards", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 6, SEARCH_DLG_HEIGHT, "&Regular exprssn", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 5, SEARCH_DLG_HEIGHT, "&Whole words only", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_checkbox, 4, 50, 4, SEARCH_DLG_HEIGHT, "Case &sensitive", 0, 0, + 0, 0, XV_WLAY_DONTCARE, NULL}, + {quick_input, 3, 50, 3, SEARCH_DLG_HEIGHT, "", 44, 0, 0, + 0, XV_WLAY_BELOWCLOSE, "edit-search"}, + {quick_label, 2, 50, 2, SEARCH_DLG_HEIGHT, " Enter search string", 0, 0, 0, + 0, XV_WLAY_DONTCARE, 0}, + {0}}; + + quick_widgets[2].result = &treplace_scanf; + quick_widgets[3].result = &treplace_backwards; + quick_widgets[4].result = &treplace_regexp; + quick_widgets[5].result = &treplace_whole; + quick_widgets[6].result = &treplace_case; + quick_widgets[7].str_result = &tsearch_text; + quick_widgets[7].text = *search_text; + + { + QuickDialog Quick_input = + {50, SEARCH_DLG_HEIGHT, -1, 0, N_(" Search "), + "[Input Line Keys]", "quick_input", 0 /*quick_widgets */ }; + + Quick_input.widgets = quick_widgets; + + if (quick_dialog (&Quick_input) != B_CANCEL) { + *search_text = *(quick_widgets[7].str_result); + replace_scanf = treplace_scanf; + replace_backwards = treplace_backwards; + replace_regexp = treplace_regexp; + replace_whole = treplace_whole; + replace_case = treplace_case; + return; + } else { + *search_text = NULL; + return; + } + } +} + + +#else + +#define B_ENTER 0 +#define B_SKIP_REPLACE 1 +#define B_REPLACE_ALL 2 +#define B_CANCEL 3 + +extern CWidget *wedit; + +void edit_search_replace_dialog (Window parent, int x, int y, char **search_text, char **replace_text, char **arg_order, char *heading, int option) +{ + Window win; + XEvent xev; + CEvent cev; + CState s; + int xh, yh, h, xb, ys, yc, yb, yr; + CWidget *m; + + CBackupState (&s); + CDisable ("*"); + + win = CDrawHeadedDialog ("replace", parent, x, y, heading); + CGetHintPos (&xh, &h); + +/* NLS hotkey ? */ + CIdent ("replace")->position = WINDOW_ALWAYS_RAISED; +/* An input line comes after the ':' */ + (CDrawText ("replace.t1", win, xh, h, _(" Enter search text : ")))->hotkey = 'E'; + + CGetHintPos (0, &yh); + (m = CDrawTextInput ("replace.sinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *search_text))->hotkey = 'E'; + + if (replace_text) { + CGetHintPos (0, &yh); + (CDrawText ("replace.t2", win, xh, yh, _(" Enter replace text : ")))->hotkey = 'n'; + CGetHintPos (0, &yh); + (CDrawTextInput ("replace.rinp", win, xh, yh, 10, AUTO_HEIGHT, 256, *replace_text))->hotkey = 'n'; + CGetHintPos (0, &yh); + (CDrawText ("replace.t3", win, xh, yh, _(" Enter argument order : ")))->hotkey = 'o'; + CGetHintPos (0, &yh); + (CDrawTextInput ("replace.ainp", win, xh, yh, 10, AUTO_HEIGHT, 256, *arg_order))->hotkey = 'o'; +/* Tool hint */ + CSetToolHint ("replace.ainp", _("Enter the order of replacement of your scanf format specifiers")); + CSetToolHint ("replace.t3", _("Enter the order of replacement of your scanf format specifiers")); + } + CGetHintPos (0, &yh); + ys = yh; +/* The following are check boxes */ + CDrawSwitch ("replace.ww", win, xh, yh, replace_whole, _(" Whole words only "), 0); + CGetHintPos (0, &yh); + CDrawSwitch ("replace.case", win, xh, yh, replace_case, _(" Case sensitive "), 0); + yc = yh; + CGetHintPos (0, &yh); + CDrawSwitch ("replace.reg", win, xh, yh, replace_regexp, _(" Regular expression "), 1); + CSetToolHint ("replace.reg", _("See the regex man page for how to compose a regular expression")); + CSetToolHint ("replace.reg.label", _("See the regex man page for how to compose a regular expression")); + yb = yh; + CGetHintPos (0, &yh); + CGetHintPos (&xb, 0); + + if (option & SEARCH_DIALOG_OPTION_BACKWARDS) { + CDrawSwitch ("replace.bkwd", win, xh, yh, replace_backwards, _(" Backwards "), 0); +/* Tool hint */ + CSetToolHint ("replace.bkwd", _("Warning: Searching backward can be slow")); + CSetToolHint ("replace.bkwd.label", _("Warning: Searching backward can be slow")); + yb = yh; + } + if (replace_text) { + if (option & SEARCH_DIALOG_OPTION_BACKWARDS) + yr = yc; + else + yr = ys; + } else { + yr = yb; + } + + if (replace_text) { + CDrawSwitch ("replace.pr", win, xb, yr, replace_prompt, _(" Prompt on replace "), 0); +/* Tool hint */ + CSetToolHint ("replace.pr", _("Ask before making each replacement")); + CGetHintPos (0, &yr); + CDrawSwitch ("replace.all", win, xb, yr, replace_all, _(" Replace all "), 0); + CGetHintPos (0, &yr); + } + CDrawSwitch ("replace.scanf", win, xb, yr, replace_scanf, _(" Scanf expression "), 1); +/* Tool hint */ + CSetToolHint ("replace.scanf", _("Allows entering of a C format string, see the scanf man page")); + + get_hint_limits (&x, &y); + CDrawPixmapButton ("replace.ok", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h, PIXMAP_BUTTON_TICK); +/* Tool hint */ + CSetToolHint ("replace.ok", _("Begin search, Enter")); + CDrawPixmapButton ("replace.cancel", win, x - WIDGET_SPACING - TICK_BUTTON_WIDTH, h + WIDGET_SPACING + TICK_BUTTON_WIDTH, PIXMAP_BUTTON_CROSS); +/* Tool hint */ + CSetToolHint ("replace.cancel", _("Abort this dialog, Esc")); + CSetSizeHintPos ("replace"); + CMapDialog ("replace"); + + m = CIdent ("replace"); + CSetWidgetSize ("replace.sinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.sinp"))->height); + if (replace_text) { + CSetWidgetSize ("replace.rinp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.rinp"))->height); + CSetWidgetSize ("replace.ainp", m->width - WIDGET_SPACING * 3 - 4 - TICK_BUTTON_WIDTH, (CIdent ("replace.ainp"))->height); + } + CFocus (CIdent ("replace.sinp")); + + for (;;) { + CNextEvent (&xev, &cev); + if (!CIdent ("replace")) { + *search_text = 0; + break; + } + if (!strcmp (cev.ident, "replace.cancel") || cev.command == CK_Cancel) { + *search_text = 0; + break; + } + if (!strcmp (cev.ident, "replace.reg") || !strcmp (cev.ident, "replace.scanf")) { + if (CIdent ("replace.reg")->keypressed || CIdent ("replace.scanf")->keypressed) { + if (!(CIdent ("replace.case")->keypressed)) { + CIdent ("replace.case")->keypressed = 1; + CExpose ("replace.case"); + } + } + } + if (!strcmp (cev.ident, "replace.ok") || cev.command == CK_Enter) { + if (replace_text) { + replace_all = CIdent ("replace.all")->keypressed; + replace_prompt = CIdent ("replace.pr")->keypressed; + *replace_text = strdup (CIdent ("replace.rinp")->text); + *arg_order = strdup (CIdent ("replace.ainp")->text); + } + *search_text = strdup (CIdent ("replace.sinp")->text); + replace_whole = CIdent ("replace.ww")->keypressed; + replace_case = CIdent ("replace.case")->keypressed; + replace_scanf = CIdent ("replace.scanf")->keypressed; + replace_regexp = CIdent ("replace.reg")->keypressed; + + if (option & SEARCH_DIALOG_OPTION_BACKWARDS) { + replace_backwards = CIdent ("replace.bkwd")->keypressed; + } else { + replace_backwards = 0; + } + + break; + } + } + CDestroyWidget ("replace"); + CRestoreState (&s); +} + + + +void edit_search_dialog (WEdit * edit, char **search_text) +{ +/* Heads the 'Search' dialog box */ + edit_search_replace_dialog (WIN_MESSAGES, search_text, 0, 0, _(" Search "), SEARCH_DIALOG_OPTION_BACKWARDS); +} + +void edit_replace_dialog (WEdit * edit, char **search_text, char **replace_text, char **arg_order) +{ +/* Heads the 'Replace' dialog box */ + edit_search_replace_dialog (WIN_MESSAGES, search_text, replace_text, arg_order, _(" Replace "), SEARCH_DIALOG_OPTION_BACKWARDS); +} + +int edit_replace_prompt (WEdit * edit, char *replace_text, int xpos, int ypos) +{ + if (replace_prompt) { + int q; + char *p, *r = 0; + r = p = malloc (strlen (replace_text) + NUM_REPL_ARGS * 2); + strcpy (p, replace_text); + while ((p = strchr (p, '%'))) { /* convert "%" to "%%" so no convertion is attempted */ + memmove (p + 2, p + 1, strlen (p) + 1); + *(++p) = '%'; + p++; + } + edit->force |= REDRAW_COMPLETELY; + q = edit_query_dialog4 (_(" Replace "), +/* This is for the confirm replace dialog box. The replaced string comes after the ':' */ + catstrs (_(" Replace with: "), r, 0), +/* Buttons for the confirm replace dialog box. */ + _("Replace"), _("Skip"), _("Replace all"), _("Cancel")); + if (r) + free (r); + switch (q) { + case 0: + return B_ENTER; + case 1: + return B_SKIP_REPLACE; + case 2: + return B_REPLACE_ALL; + case -1: + case 3: + return B_CANCEL; + } + } + return 0; +} + + +#endif + +long sargs[NUM_REPL_ARGS][256 / sizeof (long)]; + +#define SCANF_ARGS sargs[0], sargs[1], sargs[2], sargs[3], \ + sargs[4], sargs[5], sargs[6], sargs[7], \ + sargs[8], sargs[9], sargs[10], sargs[11], \ + sargs[12], sargs[13], sargs[14], sargs[15] + +#define PRINTF_ARGS sargs[argord[0]], sargs[argord[1]], sargs[argord[2]], sargs[argord[3]], \ + sargs[argord[4]], sargs[argord[5]], sargs[argord[6]], sargs[argord[7]], \ + sargs[argord[8]], sargs[argord[9]], sargs[argord[10]], sargs[argord[11]], \ + sargs[argord[12]], sargs[argord[13]], sargs[argord[14]], sargs[argord[15]] + +/* This function is a modification of mc-3.2.10/src/view.c:regexp_view_search() */ +/* returns -3 on error in pattern, -1 on not found, found_len = 0 if either */ +int string_regexp_search (char *pattern, char *string, int len, int match_type, int match_bol, int icase, int *found_len) +{ + static regex_t r; + regmatch_t pmatch[1]; + static char *old_pattern = NULL; + static int old_type, old_icase; + + if (!old_pattern || strcmp (old_pattern, pattern) || old_type != match_type || old_icase != icase) { + if (old_pattern) { + regfree (&r); + free (old_pattern); + old_pattern = 0; + } + if (regcomp (&r, pattern, REG_EXTENDED | (icase ? REG_ICASE : 0))) { + *found_len = 0; + return -3; + } + old_pattern = strdup (pattern); + old_type = match_type; + old_icase = icase; + } + if (regexec (&r, string, 1, pmatch, ((match_bol || match_type != match_normal) ? 0 : REG_NOTBOL)) != 0) { + *found_len = 0; + return -1; + } + *found_len = pmatch[0].rm_eo - pmatch[0].rm_so; + return (pmatch[0].rm_so); +} + +/* thanks to Liviu Daia 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 -c ", 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 index 00000000000..891c4c3c055 --- /dev/null +++ b/rosapps/mc/edit/editcmddef.h @@ -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 index 00000000000..4936b6b70cc --- /dev/null +++ b/rosapps/mc/edit/editdraw.c @@ -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 +#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 index 00000000000..ffaf15612a6 --- /dev/null +++ b/rosapps/mc/edit/editmenu.c @@ -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 +#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 index 00000000000..aea58843488 --- /dev/null +++ b/rosapps/mc/edit/editoptions.c @@ -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 +#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 index 00000000000..b5d2e9063e3 --- /dev/null +++ b/rosapps/mc/edit/editwidget.c @@ -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 +#include "edit.h" + +#ifndef MIDNIGHT +#include /* CARD32 */ +#include +#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 & + mods by mj olesen + + 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 index 00000000000..ccff9f174ee --- /dev/null +++ b/rosapps/mc/edit/makefile.in @@ -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 index 00000000000..8b137891791 --- /dev/null +++ b/rosapps/mc/edit/readme.edit @@ -0,0 +1 @@ + diff --git a/rosapps/mc/edit/syntax.c b/rosapps/mc/edit/syntax.c new file mode 100644 index 00000000000..af958bb3181 --- /dev/null +++ b/rosapps/mc/edit/syntax.c @@ -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 +#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 index 00000000000..5b147d87580 --- /dev/null +++ b/rosapps/mc/edit/wordproc.c @@ -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 +#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 index 00000000000..0ff4b6a08e8 --- /dev/null +++ b/rosapps/mc/install-sh @@ -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 index 00000000000..63d2bde175d --- /dev/null +++ b/rosapps/mc/make.common.in @@ -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 index 00000000000..8340ee46a4c --- /dev/null +++ b/rosapps/mc/mc.rc @@ -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 index 00000000000..de6bc326afe --- /dev/null +++ b/rosapps/mc/mcfn_install @@ -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 index 00000000000..9aed408052d --- /dev/null +++ b/rosapps/mc/mcfn_install.in @@ -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 index 00000000000..f140f01d83b --- /dev/null +++ b/rosapps/mc/mkinstalldirs @@ -0,0 +1,40 @@ +#! /bin/sh +# mkinstalldirs --- make directory hierarchy +# Author: Noah Friedman +# 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 index 00000000000..a7e01a38d68 --- /dev/null +++ b/rosapps/mc/pc/Makefile @@ -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 index 00000000000..9220c16efe3 --- /dev/null +++ b/rosapps/mc/pc/Makefile.PC @@ -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 index 00000000000..940445e471e --- /dev/null +++ b/rosapps/mc/pc/bugs @@ -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 index 00000000000..1068122ce6c --- /dev/null +++ b/rosapps/mc/pc/changelog @@ -0,0 +1,23 @@ +Tue May 12 17:16:43 1998 Pavel Roskin + + * 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 + + * 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 + + * 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 index 00000000000..f8f5502066a --- /dev/null +++ b/rosapps/mc/pc/chmod.c @@ -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 + +#ifdef __os2__ +#define INCL_DOSFILEMGR +#include +#endif + +#ifdef _OS_NT +#include +#endif + +#include +#include +/* for chmod and stat */ +#include +#include +#include +#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 index 00000000000..93276d1bc0b --- /dev/null +++ b/rosapps/mc/pc/config.h @@ -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(, ) + +#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 index 00000000000..1d18d704a4a --- /dev/null +++ b/rosapps/mc/pc/cons_nt.c @@ -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 + + 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 + +#include +#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 index 00000000000..09cd12152b8 --- /dev/null +++ b/rosapps/mc/pc/cons_os2.c @@ -0,0 +1,110 @@ +/* Client interface for General purpose OS/2 console save/restore server. + 1997 Alexander Dong + Having the same interface as its Linux counterpart: + Copyright (C) 1994 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 + +#ifdef __os2__ +#define INCL_BASE +#define INCL_NOPM +#define INCL_VIO +#define INCL_KBD +#define INCL_DOS +#define INCL_SUB +#define INCL_DOSERRORS +#include +#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 index 00000000000..0f153f53f28 --- /dev/null +++ b/rosapps/mc/pc/dirent.h @@ -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 + +#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 index 00000000000..c0b7900e874 --- /dev/null +++ b/rosapps/mc/pc/dirent_nt.c @@ -0,0 +1,92 @@ + +#include +#include +#include +#include +#include +#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 index 00000000000..973ebac8c2b --- /dev/null +++ b/rosapps/mc/pc/dirent_os2.c @@ -0,0 +1,110 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#define INCL_DOSFILEMGR +#define INCL_DOSERRORS +#include + +#include +#include +#include +#include +#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 index 00000000000..2059f947a11 --- /dev/null +++ b/rosapps/mc/pc/drive.c @@ -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 +#ifdef _OS_NT +#include +#include "util_win32.h" +#endif +#include +#include +#include +#include +#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 index 00000000000..7b7c01f2dcc --- /dev/null +++ b/rosapps/mc/pc/drive.h @@ -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 index 00000000000..00e9f3a9363 --- /dev/null +++ b/rosapps/mc/pc/key_nt.c @@ -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 +#ifndef _OS_NT +#error This file is for Win32 systems. +#else + +#include +#include +#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 index 00000000000..c67c7341742 --- /dev/null +++ b/rosapps/mc/pc/key_os2.c @@ -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 +#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 +#include +#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 index 00000000000..79299fd12f0 --- /dev/null +++ b/rosapps/mc/pc/mc.rc @@ -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 index 00000000000..f9bc036be19 --- /dev/null +++ b/rosapps/mc/pc/readme @@ -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 +and the port for OS/2 by + Alexander Dong +and is currently maintained by + Pavel Roskin + + 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 diff --git a/rosapps/mc/pc/slint_pc.c b/rosapps/mc/pc/slint_pc.c new file mode 100644 index 00000000000..291d832cf5f --- /dev/null +++ b/rosapps/mc/pc/slint_pc.c @@ -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 +#include +#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 index 00000000000..5e2a01c23be --- /dev/null +++ b/rosapps/mc/pc/sys/param.h @@ -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 index 00000000000..c410cca95b2 --- /dev/null +++ b/rosapps/mc/pc/sys/time.h___ @@ -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 index 00000000000..5e8d1feb7ab --- /dev/null +++ b/rosapps/mc/pc/todo @@ -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 index 00000000000..61aea9f56f3 --- /dev/null +++ b/rosapps/mc/pc/trace_nt.c @@ -0,0 +1,186 @@ +/* trace_nt.c - Debugging routines + for Midnight Commander, under Win32 + + Written 951215 by Juan Grigera + + 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 +#ifdef HAVE_TRACE + +#include +#ifdef _OS_NT +#include +#endif +#include +#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 index 00000000000..1eda3963ff9 --- /dev/null +++ b/rosapps/mc/pc/trace_nt.h @@ -0,0 +1,72 @@ +/* trace_nt.h - Debugging routines + + Written by Juan Grigera + + 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 index 00000000000..a8497c7abaf --- /dev/null +++ b/rosapps/mc/pc/util_nt.c @@ -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 +#include +#include +#include +#include +#include +#include +#include /* my_system */ +#include /* INT_MAX */ +#include +#if defined(_MSC_VER) +#include /* select: timeout */ +#else +#include /* select: timeout */ +#endif +#include +#include +#include +#include +#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 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 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; jst_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 index 00000000000..17b73a7eb32 --- /dev/null +++ b/rosapps/mc/pc/util_os2.c @@ -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 + +#define INCL_DOS +#define INCL_PM +#define INCL_DOSPROCESS +#define INCL_DOSFILEMGR +#define INCL_DOSDEVICES /* Device values */ +#define INCL_DOSDATETIME +#define INCL_DOSERRORS +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* my_system */ +#include /* INT_MAX */ +#include /* select: timeout */ +#include +#include +#include +#include +#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 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; jst_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 index 00000000000..6c092b03c9d --- /dev/null +++ b/rosapps/mc/pc/util_win32.c @@ -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 + + 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 +#include +#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 index 00000000000..2ed74c7fea1 --- /dev/null +++ b/rosapps/mc/pc/util_win32.h @@ -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 + + 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 index 00000000000..cddf6eff846 --- /dev/null +++ b/rosapps/mc/pc/util_winnt.c @@ -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 + + 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 +#include +#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;xGroupCount;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 index 00000000000..8285f38fdef --- /dev/null +++ b/rosapps/mc/pc/utime.h @@ -0,0 +1 @@ +#include diff --git a/rosapps/mc/slang/Makefile b/rosapps/mc/slang/Makefile new file mode 100644 index 00000000000..f67dd12cb91 --- /dev/null +++ b/rosapps/mc/slang/Makefile @@ -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 index 00000000000..c42f73d009c --- /dev/null +++ b/rosapps/mc/slang/_slang.h @@ -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 + +#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 index 00000000000..e822b3bbbcc --- /dev/null +++ b/rosapps/mc/slang/jdmacros.h @@ -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 +#endif + +#ifdef HAVE_MALLOC_H +# include +#endif + +#ifdef HAVE_MEMORY_H +# include +#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 index 00000000000..babcaf4d5b5 --- /dev/null +++ b/rosapps/mc/slang/makefile.in @@ -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 index 00000000000..4561416cb6d --- /dev/null +++ b/rosapps/mc/slang/readme @@ -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 index 00000000000..2fea3ca2a1b --- /dev/null +++ b/rosapps/mc/slang/sl-feat.h @@ -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 index 00000000000..8f28fb8fbd7 --- /dev/null +++ b/rosapps/mc/slang/slang.h @@ -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 +# endif + typedef void *VOID_STAR; +# define VOID void +# include +#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 +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 index 00000000000..711af7186fd --- /dev/null +++ b/rosapps/mc/slang/sldisply.c @@ -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 +#include +#ifdef SCO_FLAVOR +# include +# include /* for struct timeb, used in time.h */ +#endif +#include +#include + +#ifndef VMS +# include +# ifdef __QNX__ +# include +# endif +# include +#endif + +#ifdef __BEOS__ +/* Prototype for select */ +# include +#endif + +#ifdef HAVE_TERMIOS_H +# include +#endif + +#ifdef VMS +# include +# include +# include +# include +# include +# include +#else +# if !defined(sun) +# include +# endif +#endif + + +#ifdef SYSV +# include +# include +# include +# include +#endif + +#if defined (_AIX) && !defined (FD_SET) +# include /* for FD_ISSET, FD_SET, FD_ZERO */ +#endif + +#include +#include "slang.h" +#include "_slang.h" + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#if defined(__DECC) && defined(VMS) +/* These get prototypes for write an sleep */ +# include +#endif +#include + + +/* 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 index 00000000000..3a598296ffc --- /dev/null +++ b/rosapps/mc/slang/slerr.c @@ -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 +#include +#include + +#ifdef HAVE_STDLIB_H +# include +#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 index 00000000000..5a43f855432 --- /dev/null +++ b/rosapps/mc/slang/slgetkey.c @@ -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 +#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 index 00000000000..5edf25b3520 --- /dev/null +++ b/rosapps/mc/slang/slmemcpy.c @@ -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 +#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 index 00000000000..a83ae19193b --- /dev/null +++ b/rosapps/mc/slang/slmemset.c @@ -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 + + +#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 index 00000000000..e056fff3c17 --- /dev/null +++ b/rosapps/mc/slang/slos2tty.c @@ -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 + +#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 + +#include +#include + +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 index 00000000000..7d4c19d17b8 --- /dev/null +++ b/rosapps/mc/slang/slsignal.c @@ -0,0 +1,139 @@ +#include "config.h" + +#include +#include + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include + +#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 index 00000000000..ababdf30d11 --- /dev/null +++ b/rosapps/mc/slang/slsmg.c @@ -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 +#include + +#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 index 00000000000..4f3d71712ac --- /dev/null +++ b/rosapps/mc/slang/sltermin.c @@ -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 +#ifdef HAVE_STDLIB_H +# include +#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 + * . + */ + +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 ($) 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 +#include + +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 index 00000000000..0f17186dc25 --- /dev/null +++ b/rosapps/mc/slang/sltoken.c @@ -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 + + +#ifdef HAVE_STDLIB_H +# include +#endif +#include +#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 index 00000000000..ed2ee8c0550 --- /dev/null +++ b/rosapps/mc/slang/slutty.c @@ -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 +#include +/* sequent support thanks to Kenneth Lorber */ +/* 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 */ +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#ifdef HAVE_UNISTD_H +# include +#endif + +#include +#include + +#ifdef SYSV +# include +# ifndef CRAY +# include +# include +# include +# include +# endif +#endif + + +#ifdef __BEOS__ +/* Prototype for select */ +# include +#endif + +#include + +#ifndef sun +# include +#endif + +#ifdef __QNX__ +# include +#endif + +#include +#include + +#if defined (_AIX) && !defined (FD_SET) +# include /* for FD_ISSET, FD_SET, FD_ZERO */ +#endif + +#ifndef O_RDWR +# include +#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 +# endif + +typedef struct + { + struct tchars t; + struct ltchars lt; + struct sgttyb s; + } +TTY_Termio_Type; +#else +# include +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 index 00000000000..d92c2807f53 --- /dev/null +++ b/rosapps/mc/slang/slvideo.c @@ -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 +#include + +#include + +#ifdef __WIN32__ +# include +#endif + +#ifdef __GO32__ +# undef msdos +#endif + +#if defined (msdos) +# include +# include +# include +#endif +#if defined (__WATCOMC__) +# include +# define int86 int386 /* simplify code writing */ +#endif + +#if defined (__GO32__) +# include +# define GO32_VIDEO +#endif + +#if defined (__os2__) && !defined (EMX_VIDEO) +# define INCL_BASE +# define INCL_NOPM +# define INCL_VIO +# define INCL_KBD +# include +#else +# if defined (__EMX__) /* EMX video does both DOS & OS/2 */ +# ifndef EMX_VIDEO +# define EMX_VIDEO +# endif +# include +# endif +#endif + +#include +#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 +\*----------------------------------------------------------------------*/ +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 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 index 00000000000..d7ee89a64d6 --- /dev/null +++ b/rosapps/mc/slang/slw32tty.c @@ -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 + +#include +#include + +#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 index 00000000000..43a114dfb36 --- /dev/null +++ b/rosapps/mc/src/Makefile @@ -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 index 00000000000..83f4baaf8f5 --- /dev/null +++ b/rosapps/mc/src/achown.c @@ -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 +/* Needed for the extern declarations of integer parameters */ +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include /* For malloc() */ +#include /* 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, "", 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 index 00000000000..ee40f03ef59 --- /dev/null +++ b/rosapps/mc/src/achown.h @@ -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 index 00000000000..c8126510e15 --- /dev/null +++ b/rosapps/mc/src/background.c @@ -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 +#include +#include +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +#include +#include +#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 +#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 index 00000000000..51a050c47e9 --- /dev/null +++ b/rosapps/mc/src/background.h @@ -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 index 00000000000..0c0506fec92 --- /dev/null +++ b/rosapps/mc/src/boxes.c @@ -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 +#include "tty.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 index 00000000000..06544d10426 --- /dev/null +++ b/rosapps/mc/src/boxes.h @@ -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 index 00000000000..3302310ff41 --- /dev/null +++ b/rosapps/mc/src/changelog @@ -0,0 +1,1317 @@ +Mon Oct 5 21:33:14 1998 Norbert Warmuth + + * 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 + + * 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 + + * find.c: Changed hotkey of the continue-button (both Chdir and + Continue used `C'). + +Tue Sep 15 21:52:00 1998 Norbert Warmuth + + * mc.hlp, doc/mc.1.in, doc/mc.sgml: updated my EMail address + +1998-09-14 Norbert Warmuth + + * file.c (move_dir_dir): Fixed severe bug reported by Andrew Pechenov + (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 + + * Made the program relocatable by using the MCHOME environment + variable. + +Mon May 25 23:32:35 1998 Norbert Warmuth + + * 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 + + * 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 + + * utilunix.c, util.h (errno_dir_not_empty): deleted + +Sat May 23 22:29:57 1998 Norbert Warmuth + + * 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 (?) + 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 to get + prototype for exec*()!!! [See README.QNX/Section 1.4 about the + dangerous "No prototype for " warnings emitted by Watcom C, + if 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. + + * /README.QNX: QNX-specific notes. + + * /configure (line 3369), /configure.in (line 88): + 'test x$CCOPTS = x;' modified to 'test "x$CCOPTS" = x;' + + * /Makefile.in: README.QNX added to DISTMAIN. + +Thu May 21 00:09:45 1998 Norbert Warmuth + + * 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 + + * 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 + + * src/*: Until I get a better ChangeLog: Tamasi's port of the + code to QNX. + +1998-05-19 Alexander Lukyanov + + * Makefile.in: Distirbution fix so that people are not forced to + install gettext. + +1998-05-19 Miguel de Icaza + + * ext.c: Memory leak fixed. + +Mon May 18 22:24:09 1998 Norbert Warmuth + * 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 + + * menu.c (menubar_drop_compute): Check for inrange items. + +1998-05-15 Miguel de Icaza + + * color.c (init_colors): Provide X-only version of color + initialization. + +Thu May 14 01:56:11 1998 Norbert Warmuth + + * 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 + + * syntax.c: yet more minor modifications. + +1998-05-11 Miguel de Icaza + + * 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 + + * setup.c (panel_load_setup): On non-icon editions, fall back to + list_full + +Sun May 10 13:27:50 1998 Norbert Warmuth + + * 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 + + * 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 + + * edit/syntax.c: Disable debug messages on stderr. + + * edit/edit.h: Added missing _() + +1998-05-06 Miguel de Icaza + + * 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 + + * syntax.c: more bug fixes. + +1998-05-04 Miguel de Icaza + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * syntax.c: syntax highlighting segfaults when editing a binary + file - now fixed. + +Thu Apr 30 12:23:50 1998 Alex Tkachenko + + * 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 + + * main.c (parse_an_arg): GNOME edition keeps track of various + --geometry and various directories passed. + +1998-04-29 Miguel de Icaza + + * 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 + + * 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 + + * 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 + + * screen.c (is_a_panel): Added a routine to determine if a widget + is a panel. + +1998-04-27 Miguel de Icaza + + * screen.c (file_entry_color): Check if fe->fname has something. + +Sun Apr 26 00:21:12 1998 Norbert Warmuth + + * slint.c: Applied the patch from Bill Nottingham + 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 + + * edit.h, syntax.h: some optimisations to improve syntax + highlighting speed. + +1998-04-24 Miguel de Icaza + + * color.h: Move the CTYPE definition + +Fri Apr 24 16:43:25 1998 Paul Sheer + + * main.h, setup.c: editor_syntax_highlighting option added + for ini file. + +Fri Apr 24 14:54:06 1998 Paul Sheer + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * cmd.c: Report failed chdir attempts. + +Wed Apr 15 10:48:41 1998 Alex Tkachenko + + * 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 + + * 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 + + * 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 + + * xv/xvscreen.c: removed duplicate (conflicting) definition + of do_enter() + +Sun Apr 12 02:24:57 1998 Norbert Warmuth + + * 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 + + * 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 + + * file.c (file_mask_dialog): When the shell patterns option was + off source_mask was freed twice. + +1998-04-10 Marc Ewing + + * panel.h: added up_b + +1998-04-08 Miguel de Icaza + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * Makefile.in: "make dist" works with bash 1.x again + +Fri Apr 3 05:23:20 1998 Alex Tkachenko + + * 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 + + * 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 + + * 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 + + * cmd.c (nice_cd): Forgot to invoke the history registration in + one spot. + +1998-03-30 Miguel de Icaza + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * main.c: Deleted some old and unused code + +1998-03-24 Miguel de Icaza + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * screen.c: Remove KEY_DC forever. This should have never been + here. + +Wed Mar 18 22:08:34 1998 Miguel de Icaza + + * achown.c (do_enter_key): call endgrent, endpwent. + + * chown.c (init_chown): call endgrent, endpwent. + +Tue Mar 17 23:58:40 1998 Pavel Machek + + * src/file.c: Fix for the case where the disk gets full. + +Tue Mar 16 18:35:53 1998 Stas Maximov + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * xslint.c (getch): Added missing "return". + + * utilunix.c (init_groups): Added parentheses around + assignment/truth value. + + * boxes.c: #include + + * 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 + + * 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 + + * 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 + + * popt.c (poptParseArgvString): make it compile with the native + compiler on AIX 4.1.3 + +1998-03-04 Federico Mena Quintero + + * cmd.c: Added #include "x.h" + +Wed Mar 4 14:49:55 1998 Norbert Warmuth + + * 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 + + * 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 + + * 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 + + * 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 + + * subshell.c: Set subshell_pid to 1 on startup + +Fri Feb 13 19:59:39 1998 Alexander Savelyev + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * 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 + + * nt/drive.nt.c, nt/chmod.nt.c: Updated button_new and check_new + calls + +Fri Jan 16 12:47:39 1998 Norbert Warmuth + + * 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 index 00000000000..e66f4a2e640 --- /dev/null +++ b/rosapps/mc/src/chmod.c @@ -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 +#include +#include +#include /* For errno on SunOS systems */ +/* Needed for the extern declarations of integer parameters */ +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#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 index 00000000000..36dd573c611 --- /dev/null +++ b/rosapps/mc/src/chmod.h @@ -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 index 00000000000..43f8a1141c1 --- /dev/null +++ b/rosapps/mc/src/chown.c @@ -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 +#include +#include +#include /* For malloc() */ +#include /* For errno on SunOS systems */ + +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#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, _(""), NULL); /* add fields for unknown names (numbers) */ + listbox_add_item (l_group, 0, 0, _(""), 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 index 00000000000..f2ae1883750 --- /dev/null +++ b/rosapps/mc/src/chown.h @@ -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 index 00000000000..6f07d63dbe7 --- /dev/null +++ b/rosapps/mc/src/cmd.c @@ -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 +#ifdef __os2__ +# define INCL_DOSFILEMGR +# define INCL_DOSMISC +# define INCL_DOSERROR +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include "tty.h" +#include +#include /* getenv (), rand */ +#include +#include +#include +#if defined (__MINGW32__) || defined(_MSC_VER) +#include +#else +#include +#endif +#include +#include +#include /* open, O_RDWR */ +#include + +#ifdef OS2_NT +# include +#endif + +#ifdef USE_NETCODE +#include +#endif + +#ifdef HAVE_MMAP +# include +#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 index 00000000000..80eaebe61a2 --- /dev/null +++ b/rosapps/mc/src/cmd.h @@ -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 index 00000000000..0bf2e37676e --- /dev/null +++ b/rosapps/mc/src/color.c @@ -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 +#include "tty.h" +#include +#include +#include +#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 index 00000000000..808b2a59cac --- /dev/null +++ b/rosapps/mc/src/color.h @@ -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 index 00000000000..2fee81b7fc3 --- /dev/null +++ b/rosapps/mc/src/command.c @@ -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 +#include +#include "tty.h" +#include "fs.h" +#include +#include +#include +#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 index 00000000000..8804a54c77d --- /dev/null +++ b/rosapps/mc/src/command.h @@ -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 index 00000000000..c52e52abdd6 --- /dev/null +++ b/rosapps/mc/src/complete.c @@ -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 +#include "tty.h" +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#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 +# endif +# define NLENGTH(dirent) (strlen ((dirent)->d_name)) +#else +# define dirent direct +# define NLENGTH(dirent) ((dirent)->d_namlen) + +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ + +# ifdef HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ + +# ifdef HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ +#include +#include +#ifndef OS2_NT +# include +#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 index 00000000000..212f197c550 --- /dev/null +++ b/rosapps/mc/src/complete.h @@ -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 index 00000000000..ae53464c9a6 --- /dev/null +++ b/rosapps/mc/src/cons.handler.c @@ -0,0 +1,426 @@ +/* Client interface for General purpose Linux console save/restore server + Copyright (C) 1994 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. */ + +/* The cons saver can't have a pid of 1, used to prevent bunches of */ +/*#ifdef linux */ +#include + +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 +#endif +#include +#include +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#include +#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 +*/ + +#include +#include +#include +#include +#include +#include +#include +#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 index 00000000000..f6012ff7604 --- /dev/null +++ b/rosapps/mc/src/cons.saver.c @@ -0,0 +1,391 @@ +#if defined(linux) || defined(__linux__) + +/* General purpose Linux console screen save/restore server + Copyright (C) 1994 Janne Kukonlehto + 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 +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include /* 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 \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 index 00000000000..561300dd0cd --- /dev/null +++ b/rosapps/mc/src/cons.saver.h @@ -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 index 00000000000..ec28b55fd97 --- /dev/null +++ b/rosapps/mc/src/depend.awk @@ -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 index 00000000000..cc26831bbc1 --- /dev/null +++ b/rosapps/mc/src/dialog.c @@ -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 +#include "tty.h" +#include +#include /* For free() */ +#include +#include +#include +#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 index 00000000000..4f264342232 --- /dev/null +++ b/rosapps/mc/src/dialog.h @@ -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 index 00000000000..68a7686c3f7 --- /dev/null +++ b/rosapps/mc/src/dir.c @@ -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 +#include "tty.h" +#include "fs.h" + +#include +#include +#include +#include +#include +#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 index 00000000000..b79fe922771 --- /dev/null +++ b/rosapps/mc/src/dir.h @@ -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 index 00000000000..9dafd2b7364 --- /dev/null +++ b/rosapps/mc/src/dlg.c @@ -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 +/* "$Id: dlg.c,v 1.1 2001/12/30 09:55:26 sedwards Exp $" */ +#include +#include +#include +#include +#include "tty.h" +#include +#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 index 00000000000..097ae6d57e1 --- /dev/null +++ b/rosapps/mc/src/dlg.h @@ -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 index 00000000000..0f2b6bf2b08 --- /dev/null +++ b/rosapps/mc/src/ext.c @@ -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 +#include +#include +#include +#ifdef __os2__ +# include +#endif + +#include "tty.h" +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#include +#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 +#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 + ** 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 index 00000000000..1d86c41561a --- /dev/null +++ b/rosapps/mc/src/ext.h @@ -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 index 00000000000..93dee59294c --- /dev/null +++ b/rosapps/mc/src/features.inc @@ -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 index 00000000000..b49da5b7a81 --- /dev/null +++ b/rosapps/mc/src/file.c @@ -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 +/* Hack: the vfs code should not rely on this */ +#define WITH_FULL_PATHS 1 + +#include +#include +#include +#ifdef OS2_NT +# include +#endif + +#include +#include "tty.h" +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include +#ifdef SCO_FLAVOR +# include /* alex: for struct timeb, used in time.h */ +#endif /* SCO_FLAVOR */ +#if defined (__MINGW32__) || defined(_MSC_VER) +#include +#else +#include +#endif +#include +#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 +static int +check_buttons (void) +{ + x_flush_events (); + + if (op_dlg->running) + return FILE_CONT; + + if (op_dlg->ret_value == B_CANCEL) + return FILE_ABORT; + else + return op_dlg->ret_value; +} +#endif /* HAVE_GNOME */ + +#endif /* HAVE_X */ + +static int +op_win_callback (struct Dlg_head *h, int id, int msg) +{ + switch (msg){ +#ifndef HAVE_X + case DLG_DRAW: + attrset (COLOR_NORMAL); + dlg_erase (h); + draw_box (h, 1, 2, h->lines-2, h->cols-4); + return 1; +#endif + } + return 0; +} + +void +create_op_win (int op, int with_eta) +{ + int i, x_size; + int minus = verbose ? 0 : 3; + int eta_offset = with_eta ? (WX_ETA_EXTRA) / 2 : 0; + +#ifdef HAVE_XVIEW + char *sixty = " "; + char *fifteen = " "; +#else + char *sixty = ""; + char *fifteen = ""; +#endif + replace_result = 0; + recursive_result = 0; + showing_eta = with_eta; + showing_bps = with_eta; + eta_extra = with_eta ? WX_ETA_EXTRA : 0; + x_size = (WX + 4) + eta_extra; + + op_dlg = create_dlg (0, 0, WY-minus+4, x_size, dialog_colors, + op_win_callback, "", "opwin", DLG_CENTER); + +#ifndef HAVE_X + last_hint_line = the_hint->widget.y; + if ((op_dlg->y + op_dlg->lines) > last_hint_line) + the_hint->widget.y = op_dlg->y + op_dlg->lines+1; +#endif + + x_set_dialog_title (op_dlg, ""); + + tk_new_frame (op_dlg, "b."); + add_widgetl (op_dlg, button_new (BY-minus, WX - 19 + eta_offset, FILE_ABORT, + NORMAL_BUTTON, _("&Abort"), 0, 0, "abort"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, button_new (BY-minus, 14 + eta_offset, FILE_SKIP, + NORMAL_BUTTON, _("&Skip"), 0, 0, "skip"), + XV_WLAY_CENTERROW); + + tk_new_frame (op_dlg, "2."); + add_widgetl (op_dlg, ProgressGauge [2] = gauge_new (7, FCOPY_GAUGE_X, 0, 100, 0, "g-1"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, ProgressLabel [2] = label_new (7, FCOPY_LABEL_X, fifteen, "l-1"), + XV_WLAY_NEXTROW); + add_widgetl (op_dlg, bps_label = label_new (7, WX, "", "bps-label"), XV_WLAY_NEXTROW); + + tk_new_frame (op_dlg, "1."); + add_widgetl (op_dlg, ProgressGauge [1] = gauge_new (8, FCOPY_GAUGE_X, 0, 100, 0, "g-2"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, ProgressLabel [1] = label_new (8, FCOPY_LABEL_X, fifteen, "l-2"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, stalled_label = label_new (8, WX, "", "stalled"), XV_WLAY_NEXTROW); + + tk_new_frame (op_dlg, "0."); + add_widgetl (op_dlg, ProgressGauge [0] = gauge_new (6, FCOPY_GAUGE_X, 0, 100, 0, "g-3"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, ProgressLabel [0] = label_new (6, FCOPY_LABEL_X, fifteen, "l-3"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, eta_label = label_new (6, WX, "", "eta_label"), XV_WLAY_NEXTROW); + + tk_new_frame (op_dlg, "f1."); + add_widgetl (op_dlg, FileString [1] = label_new (4, FCOPY_GAUGE_X, sixty, "fs-l-1"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, FileLabel [1] = label_new (4, FCOPY_LABEL_X, fifteen, "fs-l-2"), + XV_WLAY_NEXTROW); + tk_new_frame (op_dlg, "f0."); + add_widgetl (op_dlg, FileString [0] = label_new (3, FCOPY_GAUGE_X, sixty, "fs-x-1"), + XV_WLAY_RIGHTOF); + add_widgetl (op_dlg, FileLabel [0] = label_new (3, FCOPY_LABEL_X, fifteen, "fs-x-2"), + XV_WLAY_NEXTROW); + + /* We will manage the dialog without any help, that's why + we have to call init_dlg */ + init_dlg (op_dlg); + op_dlg->running = 1; + selected_button = FILE_SKIP; + for (i = 0; i < 3; i++) + last_percentage [i] = -99; +} + +void +destroy_op_win (void) +{ +#ifdef HAVE_XVIEW + xtoolkit_kill_dialog (op_dlg); +#endif + dlg_run_done (op_dlg); + destroy_dlg (op_dlg); +#ifndef HAVE_X + the_hint->widget.y = last_hint_line; +#endif +} + +static int +show_no_bar (int n) +{ + if (n >= 0) { + label_set_text (ProgressLabel [n], ""); + gauge_show (ProgressGauge [n], 0); + } + return check_buttons (); +} + +#ifndef HAVE_X +#define truncFileString(s) name_trunc (s, eta_extra + 47) +#else +#define truncFileString(s) s +#endif + +static int +show_source (char *s) +{ + if (s != NULL){ + +#ifdef WITH_FULL_PATHS + int i = strlen (cpanel->cwd); + + /* We remove the full path we have added before */ + if (!strncmp (s, cpanel->cwd, i)){ + if (s[i] == PATH_SEP) + s += i + 1; + } +#endif /* WITH_FULL_PATHS */ + + label_set_text (FileLabel [0], _("Source")); + label_set_text (FileString [0], truncFileString (s)); + return check_buttons (); + } else { + label_set_text (FileLabel [0], ""); + label_set_text (FileString [0], ""); + return check_buttons (); + } +} + +static int +show_target (char *s) +{ + if (s != NULL){ + label_set_text (FileLabel [1], _("Target")); + label_set_text (FileString [1], truncFileString (s)); + return check_buttons (); + } else { + label_set_text (FileLabel [1], ""); + label_set_text (FileString [1], ""); + return check_buttons (); + } +} + +static int +show_deleting (char *s) +{ + label_set_text (FileLabel [0], _("Deleting")); + label_set_text (FileString [0], truncFileString (s)); + return check_buttons (); +} + +static int +show_bar (int n, long done, long total) +{ + gauge_set_value (ProgressGauge [n], (int) total, (int) done); + gauge_show (ProgressGauge [n], 1); + return check_buttons (); +} + +static void +file_eta_show () +{ + int eta_hours, eta_mins, eta_s; + char eta_buffer [30]; + + if (!showing_eta) + return; + + eta_hours = eta_secs / (60 * 60); + eta_mins = (eta_secs - (eta_hours * 60 * 60)) / 60; + eta_s = eta_secs - ((eta_hours * 60 * 60) + eta_mins * 60 ); + sprintf (eta_buffer, "ETA %d:%02d.%02d", eta_hours, eta_mins, eta_s); + label_set_text (eta_label, eta_buffer); +} + +static void +file_bps_show () +{ + char bps_buffer [30]; + + if (!showing_bps) + return; + + if (bps > 1024){ + if (bps > 1024*1024){ + sprintf (bps_buffer, "%.2f MBS", bps / (1024*1024.0)); + } else + sprintf (bps_buffer, "%.2f KBS", bps / 1024.0); + } else + sprintf (bps_buffer, "%ld BPS", bps); + label_set_text (bps_label, bps_buffer); +} + +static int +show_file_progress (long done, long total) +{ + if (!verbose) + return check_buttons (); + if (total > 0){ + label_set_text (ProgressLabel [0], _("File")); + file_eta_show (); + file_bps_show (); + return show_bar (0, done, total); + } else + return show_no_bar (0); +} + +static int +show_count_progress (long done, long total) +{ + if (!verbose) + return check_buttons (); + if (total > 0){ + label_set_text (ProgressLabel [1], _("Count")); + return show_bar (1, done, total); + } else + return show_no_bar (1); +} + +static int +show_bytes_progress (long done, long total) +{ + if (!verbose) + return check_buttons (); + if (total > 0){ + label_set_text (ProgressLabel [2], _("Bytes")); + return show_bar (2, done, total); + } else + return show_no_bar (2); +} + +/* }}} */ + + +/* {{{ Copy routines */ + +enum CaseConvs { NO_CONV=0, UP_CHAR=1, LOW_CHAR=2, UP_SECT=4, LOW_SECT=8 }; + +int +convert_case (int c, enum CaseConvs *conversion) +{ + if (*conversion & UP_CHAR){ + *conversion &= ~UP_CHAR; + return toupper (c); + } else if (*conversion & LOW_CHAR){ + *conversion &= ~LOW_CHAR; + return tolower (c); + } else if (*conversion & UP_SECT){ + return toupper (c); + } else if (*conversion & LOW_SECT){ + return tolower (c); + } else + return c; +} + +static int transform_error = 0; +static char * +do_transform_source (char *source) +{ + int j, k, l, len; + char *fnsource = x_basename (source); + int next_reg; + enum CaseConvs case_conv = NO_CONV; + static char fntarget [MC_MAXPATHLEN]; + + len = strlen (fnsource); + j = re_match (&rx, fnsource, len, 0, ®s); + if (j != len) { + transform_error = FILE_SKIP; + return NULL; + } + for (next_reg = 1, j = 0, k = 0; j < strlen (dest_mask); j++) { + switch (dest_mask [j]) { + case '\\': + j++; + if (! isdigit (dest_mask [j])){ + /* Backslash followed by non-digit */ + switch (dest_mask [j]){ + case 'U': + case_conv |= UP_SECT; + case_conv &= ~LOW_SECT; + break; + case 'u': + case_conv |= UP_CHAR; + break; + case 'L': + case_conv |= LOW_SECT; + case_conv &= ~UP_SECT; + break; + case 'l': + case_conv |= LOW_CHAR; + break; + case 'E': + case_conv = NO_CONV; + break; + default: + /* Backslash as quote mark */ + fntarget [k++] = convert_case (dest_mask [j], &case_conv); + } + break; + } else { + /* Backslash followed by digit */ + next_reg = dest_mask [j] - '0'; + /* Fall through */ + } + + case '*': + if (next_reg < 0 || next_reg >= RE_NREGS + || regs.start [next_reg] < 0) { + message_1s (1, MSG_ERROR, _(" Invalid target mask ")); + transform_error = FILE_ABORT; + return NULL; + } + for (l = regs.start [next_reg]; l < regs.end [next_reg]; l++) + fntarget [k++] = convert_case (fnsource [l], &case_conv); + next_reg ++; + break; + + default: + fntarget [k++] = convert_case (dest_mask [j], &case_conv); + break; + } + } + fntarget [k] = 0; + return fntarget; +} + +static char * +transform_source (char *source) +{ + char *s = strdup (source); + char *q; + + /* We remove \n from the filename since regex routines would use \n as an anchor */ + /* this is just to be allowed to maniupulate file names with \n on it */ + for (q = s; *q; q++){ + if (*q == '\n') + *q = ' '; + } + q = do_transform_source (s); + free (s); + return q; +} + +void +free_linklist (struct link **linklist) +{ + struct link *lp, *lp2; + + for (lp = *linklist; lp != NULL; lp = lp2){ + lp2 = lp -> next; + free (lp); + } + *linklist = NULL; +} + +#ifdef USE_VFS +int +is_in_linklist (struct link *lp, char *path, struct stat *sb) +{ + ino_t ino = sb->st_ino; + dev_t dev = sb->st_dev; + vfs *vfs = vfs_type (path); + + while (lp) { + if (lp->vfs == vfs && lp->ino == ino && lp->dev == dev ) + return 1; + lp = lp->next; + } + return 0; +} +#else +int +is_in_linklist (struct link *lp, char *path, struct stat *sb) +{ + ino_t ino = sb->st_ino; + dev_t dev = sb->st_dev; + + while (lp) { + if (lp->ino == ino && lp->dev == dev ) + return 1; + lp = lp->next; + } + return 0; +} +#endif + +/* Returns 0 if the inode wasn't found in the cache and 1 if it was found + and a hardlink was succesfully made */ +int +check_hardlinks (char *src_name, char *dst_name, struct stat *pstat) +{ + struct link *lp; + vfs *my_vfs = vfs_type (src_name); + ino_t ino = pstat->st_ino; + dev_t dev = pstat->st_dev; + struct stat link_stat; + char *p; + + if (vfs_file_is_ftp (src_name)) + return 0; + for (lp = linklist; lp != NULL; lp = lp -> next) + if (lp->vfs == my_vfs && lp->ino == ino && lp->dev == dev){ + if (!mc_stat (lp->name, &link_stat) && link_stat.st_ino == ino && + link_stat.st_dev == dev && vfs_type (lp->name) == my_vfs){ + p = strchr (lp->name, 0) + 1; /* i.e. where the `name' file + was copied to */ + if (vfs_type (dst_name) == vfs_type (p)){ + if (!mc_stat (p, &link_stat)){ + if (!mc_link (p, dst_name)) + return 1; + } + } + } + /* FIXME: Announce we couldn't make the hardlink */ + return 0; + } + lp = (struct link *) xmalloc (sizeof (struct link) + strlen (src_name) + + strlen (dst_name) + 1, "Hardlink cache"); + if (lp){ + lp->vfs = my_vfs; + lp->ino = ino; + lp->dev = dev; + strcpy (lp->name, src_name); + p = strchr (lp->name, 0) + 1; + strcpy (p, dst_name); + lp->next = linklist; + linklist = lp; + } + return 0; +} + +/* Duplicate the contents of the symbolic link src_path in dst_path. + Try to make a stable symlink if the option "stable symlink" was + set in the file mask dialog. + If dst_path is an existing symlink it will be deleted silently + (upper levels take already care of existing files at dst_path). + */ +static int +make_symlink (char *src_path, char *dst_path) +{ + char link_target[MC_MAXPATHLEN]; + int len; + int return_status; + struct stat sb; + int dst_is_symlink; + + if (mc_lstat (dst_path, &sb) == 0 && S_ISLNK (sb.st_mode)) + dst_is_symlink = 1; + else + dst_is_symlink = 0; + + retry_src_readlink: + len = mc_readlink (src_path, link_target, MC_MAXPATHLEN); + if (len < 0) { + return_status = file_error + (_(" Cannot read source link \"%s\" \n %s "), src_path); + if (return_status == FILE_RETRY) + goto retry_src_readlink; + return return_status; + } + link_target[len] = 0; + + if (stable_symlinks && (!vfs_file_is_local (src_path) || + !vfs_file_is_local (dst_path))) { + message_1s (1, MSG_ERROR, _(" Cannot make stable symlinks across " + "non-local filesystems: \n\n" + " Option Stable Symlinks will be disabled ")); + stable_symlinks = 0; + } + + if (stable_symlinks && *link_target != PATH_SEP) { + char *p, *q, *r, *s; + + p = strdup (src_path); + r = strrchr (p, PATH_SEP); + if (r) { + r[1] = 0; + if (*dst_path == PATH_SEP) + q = strdup (dst_path); + else + q = copy_strings (p, dst_path, 0); + r = strrchr (q, PATH_SEP); + if (r) { + r[1] = 0; + s = copy_strings (p, link_target, NULL); + strcpy (link_target, s); + free (s); + s = diff_two_paths (q, link_target); + if (s) { + strcpy (link_target, s); + free (s); + } + } + free (q); + } + free (p); + } + retry_dst_symlink: + if (mc_symlink (link_target, dst_path) == 0) + /* Success */ + return FILE_CONT; + /* + * if dst_exists, it is obvious that this had failed. + * We can delete the old symlink and try again... + */ + if (dst_is_symlink) { + if (!mc_unlink (dst_path)) + if (mc_symlink (link_target, dst_path) == 0) + /* Success */ + return FILE_CONT; + } + return_status = file_error + (_(" Cannot create target symlink \"%s\" \n %s "), dst_path); + if (return_status == FILE_RETRY) + goto retry_dst_symlink; + return return_status; +} + + +int +copy_file_file (char *src_path, char *dst_path, int ask_overwrite) +{ +#ifndef OS2_NT + uid_t src_uid; + gid_t src_gid; +#endif + char *buf = 0; + int buf_size = 8*1024; + int dest_desc = 0; + int source_desc; + int n_read; + int n_written; + int src_mode; /* The mode of the source file */ + struct stat sb, sb2; + struct utimbuf utb; + int dst_exists = 0; + long n_read_total = 0; + long file_size; + int return_status, temp_status; + int do_remote_copy = 0; + int appending = 0; + /* bitmask used to remember which resourses we should release on return + A single goto label is much easier to handle than a bunch of gotos ;-). */ + unsigned resources = 0; + + return_status = FILE_RETRY; + + if (show_source (src_path) == FILE_ABORT + || show_target (dst_path) == FILE_ABORT) + return FILE_ABORT; + mc_refresh (); + + retry_dst_stat: + if (mc_stat (dst_path, &sb2) == 0){ + if (S_ISDIR (sb2.st_mode)){ + return_status = file_error (_(" Cannot overwrite directory \"%s\" \n %s "), + dst_path); + if (return_status == FILE_RETRY) + goto retry_dst_stat; + return return_status; + } + dst_exists = 1; + } + + retry_src_xstat: + if ((*xstat)(src_path, &sb)){ + return_status = file_error (_(" Cannot stat source file \"%s\" \n %s "), + src_path); + if (return_status == FILE_RETRY) + goto retry_src_xstat; + return return_status; + } + + if (dst_exists){ + /* .ado: For OS/2 or NT: no st_ino exists, it is better to just try to + * overwrite the target file + */ +#ifndef OS2_NT + /* Destination already exists */ + if (sb.st_dev == sb2.st_dev && sb.st_ino == sb2.st_ino){ + message_3s (1, MSG_ERROR, _(" `%s' and `%s' are the same file. "), + src_path, dst_path); + do_refresh (); + return FILE_SKIP; + } +#endif + + /* Should we replace destination? */ + if (ask_overwrite) { + if (vfs_file_is_ftp (src_path)) + do_reget = -1; + else + do_reget = 0; + + return_status = query_replace (dst_path, &sb, &sb2); + if (return_status != FILE_CONT) + return return_status; + } + } + + if (!do_append) { + /* .ado: OS2 and NT don't have hardlinks */ +#ifndef OS2_NT + /* Check the hardlinks */ + if (!op_follow_links && sb.st_nlink > 1 && + check_hardlinks (src_path, dst_path, &sb) == 1) { + /* We have made a hardlink - no more processing is necessary */ + return return_status; + } + + if (S_ISLNK (sb.st_mode)) + return make_symlink (src_path, dst_path); + +#endif /* !OS_NT */ + + if (S_ISCHR (sb.st_mode) || S_ISBLK (sb.st_mode) || S_ISFIFO (sb.st_mode) + || S_ISSOCK (sb.st_mode)){ + retry_mknod: + if (mc_mknod (dst_path, sb.st_mode & umask_kill, sb.st_rdev) < 0){ + return_status = file_error + (_(" Cannot create special file \"%s\" \n %s "), dst_path); + if (return_status == FILE_RETRY) + goto retry_mknod; + return return_status; + } + /* Success */ + +#ifndef OS2_NT + retry_mknod_uidgid: + if (preserve_uidgid && mc_chown (dst_path, sb.st_uid, sb.st_gid)){ + temp_status = file_error + (_(" Cannot chown target file \"%s\" \n %s "), dst_path); + if (temp_status == FILE_RETRY) + goto retry_mknod_uidgid; + return temp_status; + } +#endif +#ifndef __os2__ + retry_mknod_chmod: + if (preserve && mc_chmod (dst_path, sb.st_mode & umask_kill) < 0){ + temp_status = file_error (_(" Cannnot chmod target file \"%s\" \n %s "), dst_path); + if (temp_status == FILE_RETRY) + goto retry_mknod_chmod; + return temp_status; + } +#endif + return FILE_CONT; + } + } + + if (!do_append && !vfs_file_is_local (src_path) && vfs_file_is_local (dst_path)){ + mc_setctl (src_path, MCCTL_SETREMOTECOPY, dst_path); + } + retry_src_open: + if ((source_desc = mc_open (src_path, O_RDONLY)) < 0){ + return_status = file_error + (_(" Cannot open source file \"%s\" \n %s "), src_path); + if (return_status == FILE_RETRY) + goto retry_src_open; + do_append = 0; + return return_status; + } + + resources |= 1; + do_remote_copy = mc_ctl (source_desc, MCCTL_ISREMOTECOPY, 0); + + if (!do_remote_copy) { + retry_src_fstat: + if (mc_fstat (source_desc, &sb)){ + return_status = file_error + (_(" Cannot fstat source file \"%s\" \n %s "), src_path); + if (return_status == FILE_RETRY) + goto retry_src_fstat; + do_append = 0; + goto ret; + } +#if 0 + /* Im not sure if we can delete this. sb is already filled by + (*xstat)() - Norbert. */ + } else { + retry_src_rstat: + if (mc_stat (src_path, &sb)){ + return_status = file_error + (_(" Cannot stat source file \"%s\" \n %s "), src_path); + if (return_status == FILE_RETRY) + goto retry_src_rstat; + do_append = 0; + goto ret; + } +#endif + } + src_mode = sb.st_mode; +#ifndef OS2_NT + src_uid = sb.st_uid; + src_gid = sb.st_gid; +#endif + utb.actime = sb.st_atime; + utb.modtime = sb.st_mtime; + file_size = sb.st_size; + + /* Create the new regular file with small permissions initially, + do not create a security hole. */ + + if (!do_remote_copy) { + retry_dst_open: + if ((do_append && + (dest_desc = mc_open (dst_path, O_WRONLY | O_APPEND)) < 0) || + (!do_append && + (dest_desc = mc_open (dst_path, O_WRONLY | O_CREAT | O_TRUNC, 0600)) < 0)) { + return_status = file_error + (_(" Cannot create target file \"%s\" \n %s "), dst_path); + if (return_status == FILE_RETRY) + goto retry_dst_open; + do_append = 0; + goto ret; + } + resources |= 2; /* dst_path exists/dst_path opened */ + resources |= 4; /* remove short file */ + } + appending = do_append; + do_append = 0; + + if (!do_remote_copy) { + retry_dst_fstat: + /* Find out the optimal buffer size. */ + if (mc_fstat (dest_desc, &sb)){ + return_status = file_error + (_(" Cannot fstat target file \"%s\" \n %s "), dst_path); + if (return_status == FILE_RETRY) + goto retry_dst_fstat; + goto ret; + } + buf_size = 8*1024; + + buf = (char *) xmalloc (buf_size, "copy_file_file"); + } + + return_status = show_file_progress (0, file_size); + mc_refresh (); + if (return_status != FILE_CONT) + goto ret; + + if (!do_remote_copy){ + for (;;){ + retry_src_read: + n_read = mc_read (source_desc, buf, buf_size); + if (n_read < 0){ + return_status = file_error + (_(" Cannot read source file \"%s\" \n %s "), src_path); + if (return_status == FILE_RETRY) + goto retry_src_read; + goto ret; + } + if (n_read == 0) + break; + + n_read_total += n_read; + + retry_dst_write: + n_written = mc_write (dest_desc, buf, n_read); + if (n_written < n_read){ + return_status = file_error + (_(" Cannot write target file \"%s\" \n %s "), dst_path); + if (return_status == FILE_RETRY) + goto retry_dst_write; + goto ret; + } + return_status = show_file_progress (n_read_total, file_size); + mc_refresh (); + if (return_status != FILE_CONT) + goto ret; + } + } else { + struct timeval tv_current; + struct timeval tv_transfer_start; + struct timeval tv_last_update; + struct timeval tv_last_input; + int i, size, secs, update_secs; + long dt; + char *stalled_msg; + + gettimeofday (&tv_transfer_start, (struct timezone *) NULL); + tv_last_update = tv_transfer_start; + eta_secs = 0.0; + + for (i = 1; i;) { + switch (size = mc_ctl (source_desc, MCCTL_REMOTECOPYCHUNK, 8192)) { + case MCERR_TARGETOPEN: + message_1s (1, MSG_ERROR, _(" Can't open target file ")); + goto ret; + case MCERR_READ: + goto ret; + case MCERR_WRITE: + message_1s (1, MSG_ERROR, _(" Can't write to local target file ")); + goto ret; + case MCERR_DATA_ON_STDIN: + break; + case MCERR_FINISH: + resources |= 8; + i = 0; + break; + } + + /* the first time we reach this line the target file has been created + or truncated and we actually have a short target file. + Do we really want to delete the target file when the ftp transfer + fails? If we don't delete it we would be able to use reget later. + (Norbert) */ + resources |= 4; /* remove short file */ + + if (i && size != MCERR_DATA_ON_STDIN){ + n_read_total += size; + + /* Windows NT ftp servers report that files have no + * permissions: -------, so if we happen to have actually + * read something, we should fix the permissions. + */ + if (!(src_mode & + ((S_IRUSR|S_IWUSR|S_IXUSR) /* user */ + |(S_IXOTH|S_IWOTH|S_IROTH) /* other */ + |(S_IXGRP|S_IWGRP|S_IRGRP)))) /* group */ + src_mode = S_IRUSR|S_IWUSR|S_IROTH|S_IRGRP; + + gettimeofday (&tv_last_input, NULL); + } + /* Timed operations: */ + gettimeofday (&tv_current, NULL); + + /* 1. Update rotating dash after some time (hardcoded to 2 seconds) */ + secs = (tv_current.tv_sec - tv_last_update.tv_sec); + if (secs > 2){ + rotate_dash (); + tv_last_update = tv_current; + } + + /* 2. Check for a stalled condition */ + update_secs = (tv_current.tv_sec - tv_last_input.tv_sec); + stalled_msg = ""; + if (update_secs > 4){ + stalled_msg = _("(stalled)"); + } + + /* 3. Compute ETA */ + if (secs > 2 || eta_secs == 0.0){ + dt = (tv_current.tv_sec - tv_transfer_start.tv_sec); + + if (n_read_total){ + eta_secs = ((dt / (double) n_read_total) * file_size) - dt; + bps = n_read_total / ((dt < 1) ? 1 : dt); + } else + eta_secs = 0.0; + } + + /* 4. Compute BPS rate */ + if (secs > 2){ + bps_time = (tv_current.tv_sec - tv_transfer_start.tv_sec); + if (bps_time < 1) + bps_time = 1; + bps = n_read_total / bps_time; + } + + label_set_text (stalled_label, stalled_msg); + + return_status = show_file_progress (n_read_total, file_size); + mc_refresh (); + if (return_status != FILE_CONT) + goto ret; + } + } + resources &= ~4; /* copy successful, don't remove target file */ + +ret: + if (buf) + free (buf); + + retry_src_close: + if ((resources & 1) && mc_close (source_desc) < 0){ + temp_status = file_error + (_(" Cannot close source file \"%s\" \n %s "), src_path); + if (temp_status == FILE_RETRY) + goto retry_src_close; + if (temp_status == FILE_ABORT) + return_status = temp_status; + } + + retry_dst_close: + if ((resources & 2) && mc_close (dest_desc) < 0){ + temp_status = file_error + (_(" Cannot close target file \"%s\" \n %s "), dst_path); + if (temp_status == FILE_RETRY) + goto retry_dst_close; + return_status = temp_status; + } + + if (resources & 4) { + /* Remove short file */ + mc_unlink (dst_path); + if (do_remote_copy) { + mc_ctl (source_desc, MCCTL_FINISHREMOTE, -1); + } + } else if (resources & (2|8)) { + /* no short file and destination file exists */ +#ifndef OS2_NT + if (!appending && preserve_uidgid) { + retry_dst_chown: + if (mc_chown (dst_path, src_uid, src_gid)){ + temp_status = file_error + (_(" Cannot chown target file \"%s\" \n %s "), dst_path); + if (temp_status == FILE_RETRY) + goto retry_dst_chown; + return_status = temp_status; + } + } +#endif + + /* .ado: according to the XPG4 standard, the file must be closed before + * chmod can be invoked + */ + retry_dst_chmod: + if (!appending && mc_chmod (dst_path, src_mode & umask_kill)){ + temp_status = file_error + (_(" Cannot chmod target file \"%s\" \n %s "), dst_path); + if (temp_status == FILE_RETRY) + goto retry_dst_chmod; + return_status = temp_status; + } + + if (!appending && preserve) + mc_utime (dst_path, &utb); + } + return return_status; +} + +/* + * I think these copy_*_* functions should have a return type. + * anyway, this function *must* have two directories as arguments. + */ +/* FIXME: This function needs to check the return values of the + function calls */ +int +copy_dir_dir (char *s, char *d, int toplevel, int move_over, int delete, + struct link *parent_dirs) +{ +#ifdef __os2__ + DIR *next; +#else + struct dirent *next; +#endif + struct stat buf, cbuf; + DIR *reading; + char *path, *mdpath, *dest_file, *dest_dir; + int return_status = FILE_CONT; + struct utimbuf utb; + struct link *lp; + + /* First get the mode of the source dir */ + retry_src_stat: + if ((*xstat) (s, &cbuf)){ + return_status = file_error (_(" Cannot stat source directory \"%s\" \n %s "), s); + if (return_status == FILE_RETRY) + goto retry_src_stat; + return return_status; + } + + if (is_in_linklist (dest_dirs, s, &cbuf)) { + /* Don't copy a directory we created before (we don't want to copy + infinitely if a directory is copied into itself) */ + /* FIXME: should there be an error message and FILE_SKIP? - Norbert */ + return FILE_CONT; + } + +/* Hmm, hardlink to directory??? - Norbert */ +/* FIXME: In this step we should do something + in case the destination already exist */ + /* Check the hardlinks */ + if (preserve && cbuf.st_nlink > 1 && check_hardlinks (s, d, &cbuf) == 1) { + /* We have made a hardlink - no more processing is necessary */ + return return_status; + } + + if (!S_ISDIR (cbuf.st_mode)){ + return_status = file_error (_(" Source directory \"%s\" is not a directory \n %s "), s); + if (return_status == FILE_RETRY) + goto retry_src_stat; + return return_status; + } + +#ifndef OS2_NT + if (is_in_linklist (parent_dirs, s, &cbuf)) { + /* we found a cyclic symbolic link */ + message_2s (1, MSG_ERROR, _(" Cannot copy cyclic symbolic link \n `%s' "), s); + return FILE_SKIP; + } +#endif + + lp = xmalloc (sizeof (struct link), "parent_dirs"); + lp->vfs = vfs_type (s); + lp->ino = cbuf.st_ino; + lp->dev = cbuf.st_dev; + lp->next = parent_dirs; + parent_dirs = lp; + + /* Now, check if the dest dir exists, if not, create it. */ + if (mc_stat (d, &buf)){ + /* Here the dir doesn't exist : make it !*/ + + if (move_over) { + if (mc_rename (s, d) == 0) { + free (parent_dirs); + return FILE_CONT; + } + } + dest_dir = copy_strings (d, 0); + } else { + /* + * If the destination directory exists, we want to copy the whole + * directory, but we only want this to happen once. + * + * Escape sequences added to the * to avoid compiler warnings. + * so, say /bla exists, if we copy /tmp/\* to /bla, we get /bla/tmp/\* + * or ( /bla doesn't exist ) /tmp/\* to /bla -> /bla/\* + */ +#if 1 +/* Again, I'm getting curious. Is not d already what we wanted, incl. + * masked source basename? Is not this just a relict of the past versions? + * I'm afraid this will lead into a two level deep dive :( + * + * I think this is indeed the problem. I can not remember any case where + * we actually would like that behaviour -miguel + * + * It's a documented feature (option `Dive into subdir if exists' in the + * copy/move dialog). -Norbert + */ + if (toplevel && dive_into_subdirs){ + dest_dir = concat_dir_and_file (d, x_basename (s)); + } else +#endif + { + dest_dir = copy_strings (d, 0); + goto dont_mkdir; + } + } + retry_dst_mkdir: + if (my_mkdir (dest_dir, (cbuf.st_mode & umask_kill) | S_IRWXU)){ + return_status = file_error (_(" Cannot create target directory \"%s\" \n %s "), dest_dir); + if (return_status == FILE_RETRY) + goto retry_dst_mkdir; + goto ret; + } + + lp = xmalloc (sizeof (struct link), "dest_dirs"); + mc_stat (dest_dir, &buf); + lp->vfs = vfs_type (dest_dir); + lp->ino = buf.st_ino; + lp->dev = buf.st_dev; + lp->next = dest_dirs; + dest_dirs = lp; + +#ifndef OS2_NT + if (preserve_uidgid) { + retry_dst_chown: + if (mc_chown (dest_dir, cbuf.st_uid, cbuf.st_gid)){ + return_status = file_error + (_(" Cannot chown target directory \"%s\" \n %s "), dest_dir); + if (return_status == FILE_RETRY) + goto retry_dst_chown; + goto ret; + } + } +#endif + + dont_mkdir: + /* open the source dir for reading */ + if ((reading = mc_opendir (s)) == 0){ + goto ret; + } + + while ((next = mc_readdir (reading)) && return_status != FILE_ABORT){ + /* + * Now, we don't want '.' and '..' to be created / copied at any time + */ + if (!strcmp (next->d_name, ".")) + continue; + if (!strcmp (next->d_name, "..")) + continue; + + /* get the filename and add it to the src directory */ + path = concat_dir_and_file (s, next->d_name); + + (*xstat)(path, &buf); + if (S_ISDIR (buf.st_mode)){ + mdpath = concat_dir_and_file (dest_dir, next->d_name); + /* + * From here, we just intend to recursively copy subdirs, not + * the double functionality of copying different when the target + * dir already exists. So, we give the recursive call the flag 0 + * meaning no toplevel. + */ + return_status = copy_dir_dir (path, mdpath, 0, 0, delete, parent_dirs); + free (mdpath); + } else { + dest_file = concat_dir_and_file (dest_dir, x_basename (path)); + return_status = copy_file_file (path, dest_file, 1); + free (dest_file); + } + if (delete && return_status == FILE_CONT) { + if (erase_at_end) { + static struct link *tail; + lp = xmalloc (sizeof (struct link) + strlen (path), "erase_list"); + strcpy (lp->name, path); + lp->st_mode = buf.st_mode; + lp->next = 0; + if (erase_list) { + tail->next = lp; + tail = lp; + } else + erase_list = tail = lp; + } else { + if (S_ISDIR (buf.st_mode)) { + return_status = erase_dir_iff_empty (path); + } else + return_status = erase_file (path); + } + } + +#ifdef __os2__ + /* The OS/2 mc_readdir returns a block of memory DIR + * next should be freed: .ado + */ + if (!next) + free (next); +#endif + free (path); + } + mc_closedir (reading); + + /* .ado: Directories can not have permission set in OS/2 */ +#ifndef __os2__ + if (preserve) { + mc_chmod (dest_dir, cbuf.st_mode & umask_kill); + utb.actime = cbuf.st_atime; + utb.modtime = cbuf.st_mtime; + mc_utime(dest_dir, &utb); + } + +#endif +ret: + free (dest_dir); + free (parent_dirs); + return return_status; +} + +/* }}} */ + +/* {{{ Move routines */ + +int +move_file_file (char *s, char *d) +{ + struct stat src_stats, dst_stats; + int return_status = FILE_CONT; + + if (show_source (s) == FILE_ABORT + || show_target (d) == FILE_ABORT) + return FILE_ABORT; + + mc_refresh (); + + retry_src_lstat: + if (mc_lstat (s, &src_stats) != 0){ + /* Source doesn't exist */ + return_status = file_error (_(" Cannot stat file \"%s\" \n %s "), s); + if (return_status == FILE_RETRY) + goto retry_src_lstat; + return return_status; + } + + if (mc_lstat (d, &dst_stats) == 0){ + /* Destination already exists */ + /* .ado: for OS/2 and NT, no st_ino exists */ +#ifndef OS2_NT + if (src_stats.st_dev == dst_stats.st_dev + && src_stats.st_ino == dst_stats.st_ino){ + int msize = COLS - 36; + char st[MC_MAXPATHLEN]; + char dt[MC_MAXPATHLEN]; + + if (msize < 0) + msize = 40; + msize /= 2; + + strcpy (st, name_trunc (s, msize)); + strcpy (dt, name_trunc (d, msize)); + message_3s (1, MSG_ERROR, _(" `%s' and `%s' are the same file "), + st, dt ); + do_refresh (); + return FILE_SKIP; + } +#endif /* OS2_NT */ + if (S_ISDIR (dst_stats.st_mode)){ + message_2s (1, MSG_ERROR, _(" Cannot overwrite directory `%s' "), d); + do_refresh (); + return FILE_SKIP; + } + + if (confirm_overwrite){ + if (vfs_file_is_ftp (s)) + do_reget = -1; + else + do_reget = 0; + + return_status = query_replace (d, &src_stats, &dst_stats); + if (return_status != FILE_CONT) + return return_status; + } + /* Ok to overwrite */ + } +#if 0 + retry_rename: +#endif + if (!do_append) { + if (S_ISLNK (src_stats.st_mode) && stable_symlinks) { + if ((return_status = make_symlink (s, d)) == FILE_CONT) + goto retry_src_remove; + else + return return_status; + } + + if (mc_rename (s, d) == 0) + return FILE_CONT; + } +#if 0 +/* Comparison to EXDEV seems not to work in nfs if you're moving from + one nfs to the same, but on the server it is on two different + filesystems. Then nfs returns EIO instead of EXDEV. + Hope it will not hurt if we always in case of error try to copy/delete. */ + else + errno = EXDEV; /* Hack to copy (append) the file and then delete it */ + + if (errno != EXDEV){ + return_status = files_error (_(" Cannot move file \"%s\" to \"%s\" \n %s "), s, d); + if (return_status == FILE_RETRY) + goto retry_rename; + return return_status; + } +#endif + + /* Failed because filesystem boundary -> copy the file instead */ + if ((return_status = copy_file_file (s, d, 0)) != FILE_CONT) + return return_status; + if ((return_status = show_source (NULL)) != FILE_CONT + || (return_status = show_file_progress (0, 0)) != FILE_CONT) + return return_status; + + mc_refresh (); + + retry_src_remove: + if (mc_unlink (s)){ + return_status = file_error (_(" Cannot remove file \"%s\" \n %s "), s); + if (return_status == FILE_RETRY) + goto retry_src_remove; + return return_status; + } + + return FILE_CONT; +} + +int +move_dir_dir (char *s, char *d) +{ + struct stat sbuf, dbuf, destbuf; + struct link *lp; + char *destdir; + int return_status; + int move_over = 0; + + if (show_source (s) == FILE_ABORT + || show_target (d) == FILE_ABORT) + return FILE_ABORT; + + mc_refresh (); + + mc_stat (s, &sbuf); + if (mc_stat (d, &dbuf)) + destdir = copy_strings (d, 0); /* destination doesn't exist */ + else if (!dive_into_subdirs) { + destdir = copy_strings (d, 0); + move_over = 1; + } else + destdir = concat_dir_and_file (d, x_basename (s)); + + /* Check if the user inputted an existing dir */ + retry_dst_stat: + if (!mc_stat (destdir, &destbuf)){ + if (move_over) { + if ((return_status = copy_dir_dir (s, destdir, 0, 1, 1, 0)) != FILE_CONT) + goto ret; + goto oktoret; + } else { + if (S_ISDIR (destbuf.st_mode)) + return_status = file_error (_(" Cannot overwrite directory \"%s\" %s "), destdir); + else + return_status = file_error (_(" Cannot overwrite file \"%s\" %s "), destdir); + if (return_status == FILE_RETRY) + goto retry_dst_stat; + } + free (destdir); + return return_status; + } + + retry_rename: + if (mc_rename (s, destdir) == 0){ + return_status = FILE_CONT; + goto ret; + } +/* .ado: Drive, Do we need this anymore? */ +#ifdef WIN32 + else { + /* EXDEV: cross device; does not work everywhere */ + if (toupper(s[0]) != toupper(destdir[0])) + goto w32try; + } +#endif + + if (errno != EXDEV){ + return_status = files_error (_(" Cannot move directory \"%s\" to \"%s\" \n %s "), s, d); + if (return_status == FILE_RETRY) + goto retry_rename; + goto ret; + } + +w32try: + /* Failed because of filesystem boundary -> copy dir instead */ + if ((return_status = copy_dir_dir (s, destdir, 0, 0, 1, 0)) != FILE_CONT) + goto ret; +oktoret: + if ((return_status = show_source (NULL)) != FILE_CONT + || (return_status = show_file_progress (0, 0)) != FILE_CONT) + goto ret; + + mc_refresh (); + if (erase_at_end) { + for ( ; erase_list && return_status != FILE_ABORT; ) { + if (S_ISDIR (erase_list->st_mode)) { + return_status = erase_dir_iff_empty (erase_list->name); + } else + return_status = erase_file (erase_list->name); + lp = erase_list; + erase_list = erase_list->next; + free (lp); + } + } + erase_dir_iff_empty (s); + + ret: + free (destdir); + for ( ; erase_list; ) { + lp = erase_list; + erase_list = erase_list->next; + free (lp); + } + return return_status; +} + +/* }}} */ + +/* {{{ Erase routines */ + +static int +erase_file (char *s) +{ + int return_status; + + if (show_deleting (s) == FILE_ABORT) + return FILE_ABORT; + + mc_refresh (); + + retry_unlink: + if (mc_unlink (s)){ + return_status = file_error (_(" Cannot delete file \"%s\" \n %s "), s); + if (return_status == FILE_RETRY) + goto retry_unlink; + return return_status; + } + return FILE_CONT; +} + +static int +recursive_erase (char *s) +{ + struct dirent *next; + struct stat buf; + DIR *reading; + char *path; + int return_status = FILE_CONT; + + if (!strcmp (s, "..")) + return 1; + + reading = mc_opendir (s); + + if (!reading) + return 1; + + while ((next = mc_readdir (reading)) && return_status == FILE_CONT){ + if (!strcmp (next->d_name, ".")) + continue; + if (!strcmp (next->d_name, "..")) + continue; + path = concat_dir_and_file (s, next->d_name); + if (mc_lstat (path, &buf)){ + free (path); + return 1; + } + if (S_ISDIR (buf.st_mode)) + return_status = (recursive_erase (path) != FILE_CONT); + else + return_status = erase_file (path); + free (path); + /* .ado: OS/2 returns a block of memory DIR to next and must be freed */ +#ifdef __os2__ + if (!next) + free (next); +#endif + } + mc_closedir (reading); + if (return_status != FILE_CONT) + return return_status; + if (show_deleting (s) == FILE_ABORT) + return FILE_ABORT; + mc_refresh (); + retry_rmdir: + if (my_rmdir (s)){ + return_status = file_error (_(" Cannot remove directory \"%s\" \n %s "), s); + if (return_status == FILE_RETRY) + goto retry_rmdir; + return return_status; + } + return FILE_CONT; +} + +/* Return -1 on error, 1 if there are no entries besides "." and ".." + in the directory path points to, 0 else. */ +static int +check_dir_is_empty(char *path) +{ + DIR *dir; + struct dirent *d; + int i; + + dir = mc_opendir (path); + if (!dir) + return -1; + + for (i = 1, d = mc_readdir (dir); d; d = mc_readdir (dir)) { + if (d->d_name[0] == '.' && (d->d_name[1] == '\0' || + (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; /* "." or ".." */ + i = 0; + break; + } + + mc_closedir (dir); + return i; +} + +int +erase_dir (char *s) +{ + int error; + + if (strcmp (s, "..") == 0) + return FILE_SKIP; + + if (strcmp (s, ".") == 0) + return FILE_SKIP; + + if (show_deleting (s) == FILE_ABORT) + return FILE_ABORT; + mc_refresh (); + + /* The old way to detect a non empty directory was: + error = my_rmdir (s); + if (error && (errno == ENOTEMPTY || errno == EEXIST))) { + For the linux user space nfs server (nfs-server-2.2beta29-2) + we would have to check also for EIO. I hope the new way is + fool proof. (Norbert) + */ + error = check_dir_is_empty (s); + if (error == 0) { /* not empty */ + error = query_recursive (s); + if (error == FILE_CONT) + return recursive_erase (s); + else + return error; + } + + retry_rmdir: + error = my_rmdir (s); + if (error == -1){ + error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s); + if (error == FILE_RETRY) + goto retry_rmdir; + return error; + } + return FILE_CONT; +} + +int +erase_dir_iff_empty (char *s) +{ + int error; + + if (strcmp (s, "..") == 0) + return FILE_SKIP; + + if (strcmp (s, ".") == 0) + return FILE_SKIP; + + if (show_deleting (s) == FILE_ABORT) + return FILE_ABORT; + mc_refresh (); + + if (1 != check_dir_is_empty (s)) /* not empty or error */ + return FILE_CONT; + + retry_rmdir: + error = my_rmdir (s); + if (error) { + error = file_error (_(" Cannot remove directory \"%s\" \n %s "), s); + if (error == FILE_RETRY) + goto retry_rmdir; + return error; + } + return FILE_CONT; +} + +/* }}} */ + +/* {{{ Panel operate routines */ + +/* Returns currently selected file or the first marked file if there is one */ +static char * +get_file (WPanel *panel, struct stat *stat_buf) +{ + int i; + + /* No problem with Gnome, as get_current_type never returns view_tree there */ + if (get_current_type () == view_tree){ + WTree *tree = (WTree *)get_panel_widget (get_current_index ()); + + mc_stat (tree->selected_ptr->name, stat_buf); + return tree->selected_ptr->name; + } + + if (panel->marked){ + for (i = 0; i < panel->count; i++) + if (panel->dir.list [i].f.marked){ + *stat_buf = panel->dir.list [i].buf; + return panel->dir.list [i].fname; + } + } else { + *stat_buf = panel->dir.list [panel->selected].buf; + return panel->dir.list [panel->selected].fname; + } + fprintf (stderr, _(" Internal error: get_file \n")); + mi_getch (); + return ""; +} + +static int +is_wildcarded (char *p) +{ + for (; *p; p++) { + if (*p == '*') + return 1; + else if (*p == '\\' && p [1] >= '1' && p [1] <= '9') + return 1; + } + return 0; +} + +/* Sets all global variables used by copy_file_file/move_file_file to a + resonable default + (file_mask_dialog sets these global variables interactively) + */ +void +file_mask_defaults (void) +{ + stable_symlinks = 0; + op_follow_links = 0; + dive_into_subdirs = 0; + xstat = mc_lstat; + + preserve = 1; + umask_kill = 0777777; + preserve_uidgid = (geteuid () == 0) ? 1 : 0; +} + +#define FMDY 13 +#define FMD_XLEN 64 +static int fmd_xlen = FMD_XLEN, fmd_i18n_flag = 0; +static QuickWidget fmd_widgets [] = { + +#define FMCB0 FMDC +#define FMCB12 0 +#define FMCB11 1 + /* follow symlinks and preserve Attributes must be the first */ + { quick_checkbox, 3, 64, 8, FMDY, N_("preserve &Attributes"), 9, 0, + &op_preserve, 0, XV_WLAY_BELOWCLOSE, "preserve" }, + { quick_checkbox, 3, 64, 7, FMDY, N_("follow &Links"), 7, 0, + &op_follow_links, 0, XV_WLAY_BELOWCLOSE, "follow" }, +#ifdef HAVE_XVIEW +#define FMDI1 5 +#define FMDI2 2 +#define FMDC 4 + { quick_input, 3, 64, 6, FMDY, "", 58, 0, + 0, 0, XV_WLAY_BELOWCLOSE, "input2" }, +#endif + { quick_label, 3, 64, 5, FMDY, N_("to:"), 0, 0, 0, 0, XV_WLAY_BELOWOF,"to"}, + { quick_checkbox, 37, 64, 4, FMDY, N_("&Using shell patterns"), 0, 0, + 0/* &source_easy_patterns */, 0, XV_WLAY_BELOWCLOSE, "using-shell" }, + { quick_input, 3, 64, 3, FMDY, "", 58, + 0, 0, 0, XV_WLAY_BELOWCLOSE, "input-def" }, +#ifndef HAVE_XVIEW +#define FMDI1 4 +#define FMDI2 5 +#define FMDC 3 + { quick_input, 3, 64, 6, FMDY, "", 58, 0, + 0, 0, XV_WLAY_BELOWCLOSE, "input2" }, +#endif +#define FMDI0 6 + { quick_label, 3, 64, 2, FMDY, "", 0, 0, 0, 0, XV_WLAY_DONTCARE, "ql" }, +#define FMBRGT 7 + { quick_button, 42, 64, 9, FMDY, N_("&Cancel"), 0, B_CANCEL, 0, 0, XV_WLAY_DONTCARE, + "cancel" }, +#undef SKIP +#ifdef WITH_BACKGROUND +# define SKIP 5 +# define FMCB21 11 +# define FMCB22 10 +# define FMBLFT 9 +# define FMBMID 8 + { quick_button, 25, 64, 9, FMDY, N_("&Background"), 0, B_USER, 0, 0, XV_WLAY_DONTCARE, "back" }, +#else /* WITH_BACKGROUND */ +# define SKIP 4 +# define FMCB21 10 +# define FMCB22 9 +# define FMBLFT 8 +# undef FMBMID +#endif + { quick_button, 14, 64, 9, FMDY, N_("&Ok"), 0, B_ENTER, 0, 0, XV_WLAY_NEXTROW, "ok" }, + { quick_checkbox, 42, 64, 8, FMDY, N_("&Stable Symlinks"), 0, 0, + &stable_symlinks, 0, XV_WLAY_BELOWCLOSE, "stab-sym" }, + { quick_checkbox, 31, 64, 7, FMDY, N_("&Dive into subdir if exists"), 0, 0, + &dive_into_subdirs, 0, XV_WLAY_BELOWOF, "dive" }, + { 0 } }; + +void +fmd_init_i18n() +{ +#ifdef ENABLE_NLS + + register int i; + int len; + + for (i = sizeof (op_names) / sizeof (op_names[0]); i--;) + op_names [i] = _(op_names [i]); + + i = sizeof (fmd_widgets) / sizeof (fmd_widgets [0]) - 1; + while (i--) + if (fmd_widgets [i].text[0] != '\0') + fmd_widgets [i].text = _(fmd_widgets [i].text); + + len = strlen (fmd_widgets [FMCB11].text) + + strlen (fmd_widgets [FMCB21].text) + 15; + fmd_xlen = max (fmd_xlen, len); + + len = strlen (fmd_widgets [FMCB12].text) + + strlen (fmd_widgets [FMCB22].text) + 15; + fmd_xlen = max (fmd_xlen, len); + + len = strlen (fmd_widgets [FMBRGT].text) + + strlen (fmd_widgets [FMBLFT].text) + 11; + +#ifdef FMBMID + len += strlen (fmd_widgets [FMBMID].text) + 6; +#endif + + fmd_xlen = max (fmd_xlen, len + 4); + + len = (fmd_xlen - (len + 6)) / 2; + i = fmd_widgets [FMBLFT].relative_x = len + 3; + i += strlen (fmd_widgets [FMBLFT].text) + 8; + +#ifdef FMBMID + fmd_widgets [FMBMID].relative_x = i; + i += strlen (fmd_widgets [FMBMID].text) + 6; +#endif + + fmd_widgets [FMBRGT].relative_x = i; + +#define chkbox_xpos(i) \ + fmd_widgets [i].relative_x = fmd_xlen - strlen (fmd_widgets [i].text) - 6 + + chkbox_xpos(FMCB0); + chkbox_xpos(FMCB21); + chkbox_xpos(FMCB22); + + if (fmd_xlen != FMD_XLEN) + { + i = sizeof (fmd_widgets) / sizeof (fmd_widgets [0]) - 1; + while (i--) + fmd_widgets [i].x_divisions = fmd_xlen; + + fmd_widgets [FMDI1].hotkey_pos = + fmd_widgets [FMDI2].hotkey_pos = fmd_xlen - 6; + } +#undef chkbox_xpos +#endif /* ENABLE_NLS */ + + fmd_i18n_flag = 1; +} + +char * +file_mask_dialog (int operation, char *text, char *def_text, int only_one, int *do_background) +{ + int source_easy_patterns = easy_patterns; + char *source_mask, *orig_mask, *dest_dir; + const char *error; + struct stat buf; + int val; + + QuickDialog Quick_input; + + if (!fmd_i18n_flag) + fmd_init_i18n(); + + stable_symlinks = 0; + fmd_widgets [FMDC].result = &source_easy_patterns; + fmd_widgets [FMDI1].text = easy_patterns ? "*" : "^\\(.*\\)$"; + Quick_input.xlen = fmd_xlen; + Quick_input.xpos = -1; + Quick_input.title = op_names [operation]; + Quick_input.help = "[Mask Copy/Rename]"; + Quick_input.ylen = FMDY; + Quick_input.i18n = 1; + + if (operation == OP_COPY) { + Quick_input.class = "quick_file_mask_copy"; + Quick_input.widgets = fmd_widgets; + } else { /* operation == OP_MOVE */ + Quick_input.class = "quick_file_mask_move"; + Quick_input.widgets = fmd_widgets + 2; + } + fmd_widgets [FMDI0].text = text; + fmd_widgets [FMDI2].text = def_text; + fmd_widgets [FMDI2].str_result = &dest_dir; + fmd_widgets [FMDI1].str_result = &source_mask; + + *do_background = 0; +ask_file_mask: + + if ((val = quick_dialog_skip (&Quick_input, SKIP)) == B_CANCEL) + return 0; + + if (op_follow_links && operation != OP_MOVE) + xstat = mc_stat; + else + xstat = mc_lstat; + + if (op_preserve || operation == OP_MOVE) { + preserve = 1; + umask_kill = 0777777; + preserve_uidgid = (geteuid () == 0) ? 1 : 0; + } + else { + int i; + preserve = preserve_uidgid = 0; + i = umask (0); + umask (i); + umask_kill = i ^ 0777777; + } + + orig_mask = source_mask; + if (!dest_dir || !*dest_dir) { + if (source_mask) + free (source_mask); + return dest_dir; + } + if (source_easy_patterns) { + source_easy_patterns = easy_patterns; + easy_patterns = 1; + source_mask = convert_pattern (source_mask, match_file, 1); + easy_patterns = source_easy_patterns; + error = re_compile_pattern (source_mask, strlen (source_mask), &rx); + free (source_mask); + } else + error = re_compile_pattern (source_mask, strlen (source_mask), &rx); + + if (error) { + message_3s (1, MSG_ERROR, _("Invalid source pattern `%s' \n %s "), + orig_mask, error); + if (orig_mask) + free (orig_mask); + goto ask_file_mask; + } + if (orig_mask) + free (orig_mask); + dest_mask = strrchr (dest_dir, PATH_SEP); + if (dest_mask == NULL) + dest_mask = dest_dir; + else + dest_mask++; + orig_mask = dest_mask; + if (!*dest_mask || (!dive_into_subdirs && !is_wildcarded (dest_mask) && + (!only_one || (!mc_stat (dest_dir, &buf) && S_ISDIR (buf.st_mode)))) || + (dive_into_subdirs && ((!only_one && !is_wildcarded (dest_mask)) || + (only_one && !mc_stat (dest_dir, &buf) && S_ISDIR (buf.st_mode))))) + dest_mask = strdup ("*"); + else { + dest_mask = strdup (dest_mask); + *orig_mask = 0; + } + if (!*dest_dir) { + free (dest_dir); + dest_dir = strdup ("./"); + } + if (val == B_USER) + *do_background = 1; + return dest_dir; +} + +/* + * This array introduced to avoid translation problems. The former (op_names) + * is assumed to be nouns, suitable in dialog box titles; this one should + * contain whatever is used in prompt itself (i.e. in russian, it's verb). + * Notice first symbol - it is to fool gettext and force these strings to + * be different for it. First symbol is skipped while building a prompt. + * (I don't use spaces around the words, because someday they could be + * dropped, when widgets get smarter) + */ +static char *op_names1 [] = { N_("1Copy"), N_("1Move"), N_("1Delete") }; + +/* + * These are formats for building a prompt. Parts encoded as follows: + * %o - operation from op_names1 + * %f - file/files or files/directories, as appropriate + * %m - "with source mask" or question mark for delete + * %s - source name (truncated) + * %d - number of marked files + */ +static char* one_format = N_("%o %f \"%s\"%m"); +static char* many_format = N_("%o %d %f%m"); + +static char* prompt_parts [] = +{ + N_("file"), N_("files"), N_("directory"), N_("directories"), + N_("files/directories"), N_(" with source mask:") +}; + +static char* +generate_prompt(char* cmd_buf, WPanel* panel, int operation, int only_one, + struct stat* src_stat) +{ + register char *sp, *cp; + register int i; + char format_string [200]; + char *dp = format_string; + char* source = NULL; + +#ifdef ENABLE_NLS + static int i18n_flag = 0; + if (!i18n_flag) + { + if (!fmd_i18n_flag) + fmd_init_i18n(); /* to get proper fmd_xlen */ + + for (i = sizeof (op_names1) / sizeof (op_names1 [0]); i--;) + op_names1 [i] = _(op_names1 [i]); + + for (i = sizeof (prompt_parts) / sizeof (prompt_parts [0]); i--;) + prompt_parts [i] = _(prompt_parts [i]); + + one_format = _(one_format); + many_format = _(many_format); + i18n_flag = 1; + } +#endif /* ENABLE_NLS */ + + sp = only_one ? one_format : many_format; + + if (only_one) + source = get_file (panel, src_stat); + + while (*sp) + { + switch (*sp) + { + case '%': + cp = NULL; + switch (sp[1]) + { + case 'o': + cp = op_names1 [operation] + 1; + break; + case 'm': + cp = operation == OP_DELETE ? "?" : prompt_parts [5]; + break; + case 'f': + if (only_one) + { + cp = S_ISDIR (src_stat->st_mode) ? + prompt_parts [2] : prompt_parts [0]; + } + else + { + cp = (panel->marked == panel->dirs_marked) + ? prompt_parts [3] + : (panel->dirs_marked ? prompt_parts [4] + : prompt_parts [1]); + } + break; + default: + *dp++ = *sp++; + } + if (cp) + { + sp += 2; + while (*cp) + *dp++ = *cp++; + } + break; + default: + *dp++ = *sp++; + } + } + *dp = '\0'; + + if (only_one) + { + i = fmd_xlen - strlen(format_string) - 4; + sprintf (cmd_buf, format_string, name_trunc (source, i)); + } + else + { + sprintf (cmd_buf, format_string, panel->marked); + i = strlen (cmd_buf) + 6 - fmd_xlen; + if (i > 0) + { + fmd_xlen += i; + fmd_init_i18n(); /* to recalculate positions of child widgets */ + } + } + + return source; +} + + +/* Returns 1 if did change the directory structure, + Returns 0 if user aborted */ +int +panel_operate (void *source_panel, int operation, char *thedefault) +{ + WPanel *panel = source_panel; +#ifdef WITH_FULL_PATHS + char *source_with_path = NULL; +#else +# define source_with_path source +#endif + char *source = NULL; + char *dest = NULL; + char *temp = NULL; + int only_one = (get_current_type () == view_tree) || (panel->marked <= 1); + struct stat src_stat, dst_stat; + int i, value; + long marked, total; + long count = 0, bytes = 0; + int dst_result; + int do_bg; /* do background operation? */ + + do_bg = 0; + rx.buffer = NULL; + free_linklist (&linklist); + free_linklist (&dest_dirs); + if (get_current_type () == view_listing) + if (!panel->marked && !strcmp (selection (panel)->fname, "..")){ + message (1, MSG_ERROR, _(" Can't operate on \"..\"! ")); + return 0; + } + + if (operation < OP_COPY || operation > OP_DELETE) + return 0; + + /* Generate confirmation prompt */ + source = generate_prompt(cmd_buf, panel, operation, only_one, &src_stat); + + /* Show confirmation dialog */ + if (operation == OP_DELETE && confirm_delete){ + if (know_not_what_am_i_doing) + query_set_sel (1); + i = query_dialog (_(op_names [operation]), cmd_buf, + D_ERROR, 2, _("&Yes"), _("&No")); + if (i != 0) + return 0; + } else if (operation != OP_DELETE) { + char *dest_dir; + + if (thedefault != NULL) + dest_dir = thedefault; + else if (get_other_type () == view_listing) + dest_dir = opanel->cwd; + else + dest_dir = panel->cwd; + + rx.buffer = (char *) xmalloc (MC_MAXPATHLEN, "mask copying"); + rx.allocated = MC_MAXPATHLEN; + rx.translate = 0; + dest = file_mask_dialog (operation, cmd_buf, dest_dir, only_one, &do_bg); + if (!dest) { + free (rx.buffer); + return 0; + } + if (!*dest){ + free (rx.buffer); + free (dest); + return 0; + } + } + +#ifdef WITH_BACKGROUND + /* Did the user select to do a background operation? */ + if (do_bg){ + int v; + + v = do_background (copy_strings (operation_names [operation], ": ", panel->cwd, 0)); + if (v == -1){ + message (1, MSG_ERROR, _(" Sorry, I could not put the job in background ")); + } + + /* If we are the parent */ + if (v == 1){ + vfs_force_expire (panel->cwd); + vfs_force_expire (dest); + return 0; + } + } +#endif + /* Initialize things */ + /* We turn on ETA display if the source is an ftp file system */ + create_op_win (operation, vfs_file_is_ftp (panel->cwd)); + ftpfs_hint_reread (0); + + /* Now, let's do the job */ + /* This code is only called by the tree and panel code */ + if (only_one){ + /* One file: FIXME mc_chdir will take user out of any vfs */ + if (operation != OP_COPY && get_current_type () == view_tree) + mc_chdir (PATH_SEP_STR); + + /* The source and src_stat variables have been initialized before */ +#ifdef WITH_FULL_PATHS + source_with_path = concat_dir_and_file (panel->cwd, source); +#endif + + if (operation == OP_DELETE){ + /* Delete operation */ + if (S_ISDIR (src_stat.st_mode)) + value = erase_dir (source_with_path); + else + value = erase_file (source_with_path); + } else { + /* Copy or move operation */ + temp = transform_source (source_with_path); + if (temp == NULL) { + value = transform_error; + } else { + temp = get_full_name (dest, temp); + free (dest); + dest = temp; + temp = 0; + + switch (operation){ + case OP_COPY: + /* we use op_follow_links only with OP_COPY, + */ + (*xstat) (source_with_path, &src_stat); + if (S_ISDIR (src_stat.st_mode)) + value = copy_dir_dir (source_with_path, dest, 1, 0, 0, 0); + else + value = copy_file_file (source_with_path, dest, 1); + break; + case OP_MOVE: + if (S_ISDIR (src_stat.st_mode)) + value = move_dir_dir (source_with_path, dest); + else + value = move_file_file (source_with_path, dest); + break; + default: + value = FILE_CONT; + message_1s (1, _(" Internal failure "), _(" Unknown file operation ")); + } + } + } /* Copy or move operation */ + + if (value == FILE_CONT) + unmark_files (panel); + + } else { + /* Many files */ + + if (operation != OP_DELETE){ + /* Check destination for copy or move operation */ + retry_many_dst_stat: + dst_result = mc_stat (dest, &dst_stat); + if (dst_result == 0 && !S_ISDIR (dst_stat.st_mode)){ + if (file_error (_(" Destination \"%s\" must be a directory \n %s "), dest) == FILE_RETRY) + goto retry_many_dst_stat; + goto clean_up; + } + } + + /* Initialize variables for progress bars */ + marked = panel->marked; + total = panel->total; + + /* Loop for every file */ + for (i = 0; i < panel->count; i++){ + if (!panel->dir.list [i].f.marked) + continue; /* Skip the unmarked ones */ + source = panel->dir.list [i].fname; + src_stat = panel->dir.list [i].buf; /* Inefficient, should we use pointers? */ +#ifdef WITH_FULL_PATHS + if (source_with_path) + free (source_with_path); + source_with_path = concat_dir_and_file (panel->cwd, source); +#endif + if (operation == OP_DELETE){ + /* Delete operation */ + if (S_ISDIR (src_stat.st_mode)) + value = erase_dir (source_with_path); + else + value = erase_file (source_with_path); + } else { + /* Copy or move operation */ + if (temp) + free (temp); + temp = transform_source (source_with_path); + if (temp == NULL) { + value = transform_error; + } else { + temp = get_full_name (dest, temp); + switch (operation){ + case OP_COPY: + /* we use op_follow_links only with OP_COPY, + */ + (*xstat) (source_with_path, &src_stat); + if (S_ISDIR (src_stat.st_mode)) + value = copy_dir_dir (source_with_path, temp, 1, 0, 0, 0); + else + value = copy_file_file (source_with_path, temp, 1); + free_linklist (&dest_dirs); + break; + case OP_MOVE: + if (S_ISDIR (src_stat.st_mode)) + value = move_dir_dir (source_with_path, temp); + else + value = move_file_file (source_with_path, temp); + break; + default: + message_1s (1, _(" Internal failure "), + _(" Unknown file operation ")); + goto clean_up; + } + } + } /* Copy or move operation */ + + if (value == FILE_ABORT) + goto clean_up; + if (value == FILE_CONT){ + do_file_mark (panel, i, 0); + } + count ++; + if (show_count_progress (count, marked) == FILE_ABORT) + goto clean_up; + bytes += src_stat.st_size; + if (verbose && + show_bytes_progress (bytes, total) == FILE_ABORT) + goto clean_up; + if (operation != OP_DELETE && verbose + && show_file_progress (0, 0) == FILE_ABORT) + goto clean_up; + mc_refresh (); + } /* Loop for every file */ + } /* Many files */ + + clean_up: + /* Clean up */ + destroy_op_win (); + ftpfs_hint_reread (1); + free_linklist (&linklist); + free_linklist (&dest_dirs); +#if WITH_FULL_PATHS + if (source_with_path) + free (source_with_path); +#endif + if (dest) + free (dest); + if (temp) + free (temp); + if (rx.buffer) { + free (rx.buffer); + rx.buffer = NULL; + } + if (dest_mask) { + free (dest_mask); + dest_mask = NULL; + } + +#ifdef WITH_BACKGROUND + /* Let our parent know we are saying bye bye */ + if (we_are_background){ + vfs_shut (); + tell_parent (MSG_CHILD_EXITING); + exit (1); + } +#endif + return 1; +} + +/* }}} */ + +/* {{{ Query/status report routines */ + +static int +real_do_file_error (enum OperationMode mode, char *error) +{ + int result; + char *msg; + + msg = mode == Foreground ? MSG_ERROR : _(" Background process error "); + result = query_dialog (msg, error, D_ERROR, 3, _("&Skip"), _("&Retry"), _("&Abort")); + + switch (result){ + case 0: + do_refresh (); + return FILE_SKIP; + case 1: + do_refresh (); + return FILE_RETRY; + case 2: + default: + return FILE_ABORT; + } +} + +/* Report error with one file */ +int +file_error (char *format, char *file) +{ + sprintf (cmd_buf, format, + name_trunc (file, 30), unix_error_string (errno)); + return do_file_error (cmd_buf); +} + +/* Report error with two files */ +int +files_error (char *format, char *file1, char *file2) +{ + char nfile1 [16]; + char nfile2 [16]; + + strcpy (nfile1, name_trunc (file1, 15)); + strcpy (nfile2, name_trunc (file2, 15)); + + sprintf (cmd_buf, format, nfile1, nfile2, unix_error_string (errno)); + return do_file_error (cmd_buf); +} + +static char *format = N_("Target file \"%s\" already exists!"); +static int +replace_callback (struct Dlg_head *h, int Id, int Msg) +{ +#ifndef HAVE_X + + switch (Msg){ + case DLG_DRAW: + dialog_repaint (h, ERROR_COLOR, ERROR_COLOR); + break; + } +#endif + return 0; +} + +#ifdef HAVE_X +#define X_TRUNC 128 +#else +#define X_TRUNC 52 +#endif + +/* + * FIXME: probably it is better to replace this with quick dialog machinery, + * but actually I'm not familiar with it and have not much time :( + * alex + */ +static struct +{ + char* text; + int ypos, xpos; + int value; /* 0 for labels */ + char* tkname; + WLay layout; +} +rd_widgets [] = +{ + {N_("Target file \"%s\" already exists!"), + 3, 4, 0, "target-e", XV_WLAY_CENTERROW}, + {N_("&Abort"), BY + 3, 25, REPLACE_ABORT, "abort", XV_WLAY_CENTERROW}, + {N_("if &Size differs"), + BY + 1, 28, REPLACE_SIZE, "if-size", XV_WLAY_RIGHTOF}, + {N_("non&E"), BY, 47, REPLACE_NEVER, "none", XV_WLAY_RIGHTOF}, + {N_("&Update"), BY, 36, REPLACE_UPDATE, "update", XV_WLAY_RIGHTOF}, + {N_("al&L"), BY, 28, REPLACE_ALWAYS, "all", XV_WLAY_RIGHTOF}, + {N_("Overwrite all targets?"), + BY, 4, 0, "over-label", XV_WLAY_CENTERROW}, + {N_("&Reget"), BY - 1, 28, REPLACE_REGET, "reget", XV_WLAY_RIGHTOF}, + {N_("ap&Pend"), BY - 2, 45, REPLACE_APPEND, "append", XV_WLAY_RIGHTOF}, + {N_("&No"), BY - 2, 37, REPLACE_NO, "no", XV_WLAY_RIGHTOF}, + {N_("&Yes"), BY - 2, 28, REPLACE_YES, "yes", XV_WLAY_RIGHTOF}, + {N_("Overwrite this target?"), + BY - 2, 4, 0, "overlab", XV_WLAY_CENTERROW}, + {N_("Target date: %s, size %d"), + 6, 4, 0, "target-date",XV_WLAY_CENTERROW}, + {N_("Source date: %s, size %d"), + 5, 4, 0, "source-date",XV_WLAY_CENTERROW} +}; + +#define ADD_RD_BUTTON(i)\ + add_widgetl (replace_dlg,\ + button_new (rd_widgets [i].ypos, rd_widgets [i].xpos, rd_widgets [i].value,\ + NORMAL_BUTTON, rd_widgets [i].text, 0, 0, rd_widgets [i].tkname), \ + rd_widgets [i].layout) + +#define ADD_RD_LABEL(i,p1,p2)\ + sprintf (buffer, rd_widgets [i].text, p1, p2);\ + add_widgetl (replace_dlg,\ + label_new (rd_widgets [i].ypos, rd_widgets [i].xpos, buffer, rd_widgets [i].tkname),\ + rd_widgets [i].layout) + +static void +init_replace (enum OperationMode mode) +{ + char buffer [128]; + static int rd_xlen = 60, rd_trunc = X_TRUNC; + +#ifdef ENABLE_NLS + static int i18n_flag; + if (!i18n_flag) + { + int l1, l2, l, row; + register int i = sizeof (rd_widgets) / sizeof (rd_widgets [0]); + while (i--) + rd_widgets [i].text = _(rd_widgets [i].text); + + /* + *longest of "Overwrite..." labels + * (assume "Target date..." are short enough) + */ + l1 = max (strlen (rd_widgets [6].text), strlen (rd_widgets [11].text)); + + /* longest of button rows */ + i = sizeof (rd_widgets) / sizeof (rd_widgets [0]); + for (row = l = l2 = 0; i--;) + { + if (rd_widgets [i].value != 0) + { + if (row != rd_widgets [i].ypos) + { + row = rd_widgets [i].ypos; + l2 = max (l2, l); + l = 0; + } + l += strlen (rd_widgets [i].text) + 4; + } + } + l2 = max (l2, l); /* last row */ + rd_xlen = max (rd_xlen, l1 + l2 + 8); + rd_trunc = rd_xlen - 6; + + /* Now place buttons */ + l1 += 5; /* start of first button in the row */ + i = sizeof (rd_widgets) / sizeof (rd_widgets [0]); + + for (l = l1, row = 0; --i > 1;) + { + if (rd_widgets [i].value != 0) + { + if (row != rd_widgets [i].ypos) + { + row = rd_widgets [i].ypos; + l = l1; + } + rd_widgets [i].xpos = l; + l += strlen (rd_widgets [i].text) + 4; + } + } + /* Abort button is centered */ + rd_widgets [1].xpos = (rd_xlen - strlen (rd_widgets [1].text) - 3) / 2; + + } +#endif /* ENABLE_NLS */ + + replace_colors [0] = ERROR_COLOR; + replace_colors [1] = COLOR_NORMAL; + replace_colors [2] = ERROR_COLOR; + replace_colors [3] = COLOR_NORMAL; + + replace_dlg = create_dlg (0, 0, 16, rd_xlen, replace_colors, replace_callback, + "[ Replace ]", "replace", DLG_CENTER); + + x_set_dialog_title (replace_dlg, + mode == Foreground ? _(" File exists ") : _(" Background process: File exists ")); + + + ADD_RD_LABEL(0, name_trunc (replace_filename, rd_trunc - strlen (rd_widgets [0].text)), 0 ); + ADD_RD_BUTTON(1); + + tk_new_frame (replace_dlg, "a."); + + ADD_RD_BUTTON(2); + ADD_RD_BUTTON(3); + ADD_RD_BUTTON(4); + ADD_RD_BUTTON(5); + ADD_RD_LABEL(6,0,0); + + /* "this target..." widgets */ + tk_new_frame (replace_dlg, "p."); + if (!S_ISDIR (d_stat->st_mode)){ + if ((do_reget == -1 && d_stat->st_size && s_stat->st_size > d_stat->st_size)) + ADD_RD_BUTTON(7); + + ADD_RD_BUTTON(8); + } + ADD_RD_BUTTON(9); + ADD_RD_BUTTON(10); + ADD_RD_LABEL(11,0,0); + + tk_new_frame (replace_dlg, "i."); + ADD_RD_LABEL(12, file_date (d_stat->st_mtime), (int) d_stat->st_size); + ADD_RD_LABEL(13, file_date (s_stat->st_mtime), (int) s_stat->st_size); + tk_end_frame (); +} + +static int +real_query_replace (enum OperationMode mode, char *destname, struct stat *_s_stat, + struct stat *_d_stat) +{ + if (replace_result < REPLACE_ALWAYS){ + replace_filename = destname; + s_stat = _s_stat; + d_stat = _d_stat; + init_replace (mode); + run_dlg (replace_dlg); + replace_result = replace_dlg->ret_value; + if (replace_result == B_CANCEL) + replace_result = REPLACE_ABORT; + destroy_dlg (replace_dlg); + } + + switch (replace_result){ + case REPLACE_UPDATE: + do_refresh (); + if (_s_stat->st_mtime > _d_stat->st_mtime) + return FILE_CONT; + else + return FILE_SKIP; + + case REPLACE_SIZE: + do_refresh (); + if (_s_stat->st_size == _d_stat->st_size) + return FILE_SKIP; + else + return FILE_CONT; + + case REPLACE_REGET: + do_reget = _d_stat->st_size; + + case REPLACE_APPEND: + do_append = 1; + + case REPLACE_YES: + case REPLACE_ALWAYS: + do_refresh (); + return FILE_CONT; + case REPLACE_NO: + case REPLACE_NEVER: + do_refresh (); + return FILE_SKIP; + case REPLACE_ABORT: + default: + return FILE_ABORT; + } +} + +int +real_query_recursive (enum OperationMode mode, char *s) +{ + char *confirm, *text; + + if (recursive_result < RECURSIVE_ALWAYS){ + char *msg = + mode == Foreground ? _("\n Directory not empty. \n Delete it recursively? ") + : _("\n Background process: Directory not empty \n Delete it recursively? "); + text = copy_strings (" Delete: ", name_trunc (s, 30), " ", 0); + + if (know_not_what_am_i_doing) + query_set_sel (1); + recursive_result = query_dialog (text, msg, D_ERROR, 5, + _("&Yes"), _("&No"), _("a&ll"), _("non&E"), _("&Abort")); + + + if (recursive_result != RECURSIVE_ABORT) + do_refresh (); + free (text); + if (know_not_what_am_i_doing && (recursive_result == RECURSIVE_YES + || recursive_result == RECURSIVE_ALWAYS)){ + text = copy_strings (_(" Type 'yes' if you REALLY want to delete "), + recursive_result == RECURSIVE_YES + ? name_trunc (s, 19) : _("all the directories "), " ", 0); + confirm = input_dialog (mode == Foreground ? _(" Recursive Delete ") + : _(" Background process: Recursive Delete "), + text, "no"); + do_refresh (); + if (!confirm || strcmp (confirm, "yes")) + recursive_result = RECURSIVE_NEVER; + free (confirm); + free (text); + } + } + switch (recursive_result){ + case RECURSIVE_YES: + case RECURSIVE_ALWAYS: + return FILE_CONT; + case RECURSIVE_NO: + case RECURSIVE_NEVER: + return FILE_SKIP; + case RECURSIVE_ABORT: + default: + return FILE_ABORT; + } +} + +#ifdef WITH_BACKGROUND +int +do_file_error (char *str) +{ + return call_1s (real_do_file_error, str); +} + +int +query_recursive (char *s) +{ + return call_1s (real_query_recursive, s); +} + +int +query_replace (char *destname, struct stat *_s_stat, struct stat *_d_stat) +{ + if (we_are_background) + return parent_call ((void *)real_query_replace, 3, strlen(destname), destname, + sizeof (struct stat), _s_stat, sizeof(struct stat), _d_stat); + else + return real_query_replace (Foreground, destname, _s_stat, _d_stat); +} + +#else +do_file_error (char *str) +{ + return real_do_file_error (Foreground, str); +} + +int +query_recursive (char *s) +{ + return real_query_recursive (Foreground, s); +} + +int +query_replace (char *destname, struct stat *_s_stat, struct stat *_d_stat) +{ + return real_query_replace (Foreground, destname, _s_stat, _d_stat); +} + +#endif + +/* + Cause emacs to enter folding mode for this file: + Local variables: + end: +*/ diff --git a/rosapps/mc/src/file.h b/rosapps/mc/src/file.h new file mode 100644 index 00000000000..c2730c52007 --- /dev/null +++ b/rosapps/mc/src/file.h @@ -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 index 00000000000..84ae4b1ada2 --- /dev/null +++ b/rosapps/mc/src/find.c @@ -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 +#include "tty.h" +#include +#include +#ifdef OS2_NT +# include +#endif +#include "fs.h" +#include /* For free() */ +#include +#include +#include +#include +#include +#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 index 00000000000..5ebc50a76fe --- /dev/null +++ b/rosapps/mc/src/find.h @@ -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 index 00000000000..db3fa65d4ed --- /dev/null +++ b/rosapps/mc/src/fixhlp.c @@ -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 +#include +#include +#include +#include +#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 \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 index 00000000000..5f1085b1b55 --- /dev/null +++ b/rosapps/mc/src/fs.h @@ -0,0 +1,46 @@ +/* Include file to use opendir/closedir/readdir */ + +#ifndef __FS_H +#define __FS_H +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#ifndef OS2_NT +#include +#endif +#include + +#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 +# 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 +# endif /* HAVE_SYS_NDIR_H */ + +# ifdef HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ + +# ifdef HAVE_NDIR_H +# include +# 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 index 00000000000..b8a3ab05222 --- /dev/null +++ b/rosapps/mc/src/fsusage.c @@ -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 +#endif +#if !defined(NO_INFOMOUNT) || defined(__QNX__) + +#if defined(__QNX__) +#define STAT_STATFS4 +#endif + +#include + +#include "fsusage.h" + +int statfs (); /* We leave the type ambiguous intentionally here */ + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_MOUNT_H +#include +#endif + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#ifdef HAVE_SYS_FILSYS_H +#include /* SVR2. */ +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SYS_STATFS_H +#include +#endif + +#ifdef HAVE_DUSTAT_H /* AIX PS/2. */ +#include +#endif + +#ifdef HAVE_SYS_STATVFS_H /* SVR4. */ +#include +#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 index 00000000000..dd23ea062b9 --- /dev/null +++ b/rosapps/mc/src/fsusage.h @@ -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 index 00000000000..77999ee0edd --- /dev/null +++ b/rosapps/mc/src/gindex.pl @@ -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 index 00000000000..c91d5a54aff --- /dev/null +++ b/rosapps/mc/src/global.h @@ -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 index 00000000000..343cf628a8b --- /dev/null +++ b/rosapps/mc/src/help.c @@ -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 +#include "tty.h" +#include +#include +#include +#include +#include +#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 index 00000000000..db856907c88 --- /dev/null +++ b/rosapps/mc/src/help.h @@ -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 index 00000000000..45f0eaad415 --- /dev/null +++ b/rosapps/mc/src/hotlist.c @@ -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 +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include /* For malloc() */ +#include +#include +#include +#include +#ifdef SCO_FLAVOR +# include /* alex: for struct timeb, used in time.h */ +#endif /* SCO_FLAVOR */ +#include +#ifndef OS2_NT +# include +# include +#else +# include +#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 index 00000000000..fefe49f0629 --- /dev/null +++ b/rosapps/mc/src/hotlist.h @@ -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 index 00000000000..4a561c4c7e9 --- /dev/null +++ b/rosapps/mc/src/i18n.h @@ -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 index 00000000000..ead75e3f33d --- /dev/null +++ b/rosapps/mc/src/info.c @@ -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 +#include +#include "tty.h" +#include +#include +#include +#include +#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 index 00000000000..35c8328b91e --- /dev/null +++ b/rosapps/mc/src/info.h @@ -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 index 00000000000..e803eeda0e7 --- /dev/null +++ b/rosapps/mc/src/key.c @@ -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 +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +# include +#endif +#include /* FD_ZERO et al */ +#ifndef SCO_FLAVOR + /* alex: sys/select.h defines struct timeval */ +# include /* struct timeval */ +#endif /* SCO_FLAVOR */ +#if HAVE_SYS_SELECT_H +# include +#endif +#include "tty.h" +#include +#include +#include +#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 /* This is needed for TIOCLINUX */ +# else +# include +# endif +# include +#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 index 00000000000..db2492f06bd --- /dev/null +++ b/rosapps/mc/src/key.h @@ -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 index 00000000000..055552c769f --- /dev/null +++ b/rosapps/mc/src/keyxdef.c @@ -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 +#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 +#else + #include +#endif +#include /* 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 index 00000000000..767eb37d02f --- /dev/null +++ b/rosapps/mc/src/layout.c @@ -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 +#include +#include +#include +#include +#include /* Required by tree.h */ +#include +#include +#if (!defined(__IBMC__) && !defined(__IBMCPP__)) && !defined(OS2_NT) +# include + /* + * If TIOCGWINSZ supported, make it available here, because window- + * resizing code depends on it... + */ +# ifdef __QNX__ /* Maybe not only QNX-specific... */ +# include +# endif +#endif +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#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 index 00000000000..22a59235d1b --- /dev/null +++ b/rosapps/mc/src/layout.h @@ -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 index 00000000000..76a7663a7ac --- /dev/null +++ b/rosapps/mc/src/learn.c @@ -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 +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include /* For malloc() */ +#include +#include +#include +#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 index 00000000000..5188e16b7d1 --- /dev/null +++ b/rosapps/mc/src/learn.h @@ -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 index 00000000000..42b469374e6 --- /dev/null +++ b/rosapps/mc/src/listmode.c @@ -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 +#ifdef HAVE_UNISTD_H +# include +#endif +#include +#include +#include /* For malloc() */ +#include +#include +#include +#ifndef OS2_NT +# include +# include +#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 index 00000000000..d9abc7f9d7d --- /dev/null +++ b/rosapps/mc/src/listmode.h @@ -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 index 00000000000..d89ae91b6f3 --- /dev/null +++ b/rosapps/mc/src/mad.c @@ -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 +#include "mad.h" +#undef malloc +#undef calloc +#undef realloc +#undef xmalloc +#undef strdup +#undef free +#include +#include +#include +#include /* For kill() */ +#ifdef HAVE_UNISTD_H +# include /* 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 index 00000000000..0119e1c74ae --- /dev/null +++ b/rosapps/mc/src/mad.h @@ -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 index 00000000000..ec6f87c7295 --- /dev/null +++ b/rosapps/mc/src/main.c @@ -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 +#include + +#ifdef _OS_NT +# include +#endif + +#ifdef __os2__ +# define INCL_DOS +# define INCL_DOSFILEMGR +# define INCL_DOSERRORS +# include +#endif + +#include "tty.h" +#include +#include +#include +#include +#include + +#include + +#ifdef HAVE_UNISTD_H +# include +#endif + +/* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */ +#if defined(HAVE_DIRENT_H) || defined(_POSIX_VERSION) +# include +# define NLENGTH(dirent) (strlen ((dirent)->d_name)) +#else +# define dirent direct +# define NLENGTH(dirent) ((dirent)->d_namlen) + +# ifdef HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ + +# ifdef HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ + +# ifdef HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +#endif /* not (HAVE_DIRENT_H or _POSIX_VERSION) */ + +#if HAVE_SYS_WAIT_H +# include /* For waitpid() */ +#endif + +#include +#ifndef OS2_NT +# include +#endif +#include +#include /* For O_RDWR */ +#include + +/* 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 +# include +#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 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 index 00000000000..f4d4ddc0b93 --- /dev/null +++ b/rosapps/mc/src/main.h @@ -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 index 00000000000..d68ad6d0d6c --- /dev/null +++ b/rosapps/mc/src/makefile.in @@ -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 index 00000000000..d216c2995da --- /dev/null +++ b/rosapps/mc/src/man2hlp.c @@ -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 +#include +#include +#include +#include +#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 ("

%s

", 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, "
    "); + } else { + for (i = heading_level; i < old_heading_level; i += 2) + fprintf (index_file, "
"); + } + old_heading_level = heading_level; + printf_string ("%s", + heading_level / 2 + 2, buffer + heading_level, + buffer + heading_level, heading_level / 2 + 2); + newline (); + fprintf (index_file, "
  • %s\n", + buffer + heading_level, buffer + heading_level); + } else { + for (i = 0; i < old_heading_level; i += 2) + fprintf (index_file, ""); + old_heading_level = 0; + fprintf (index_file, "

      \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 ("

      "); + 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 ("

      ");
      +	    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", 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 ("

      "); + } + 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 ("%s", 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 ("%s", 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 \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, "Midnight Commander manual\n"); + fprintf (index_file, "

      \""

      Manual

      \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.

      \n", + VERSION, __DATE__); + fprintf (index_file, "


      Contents

        \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 ("
      "); /* 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 ("
      "); + newline (); + for (i = 0; i < old_heading_level; i += 2) + fprintf (index_file, "
    "); + old_heading_level = 0; + fprintf (index_file, "
    \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 index 00000000000..7709836f82d --- /dev/null +++ b/rosapps/mc/src/mc.hlp @@ -0,0 +1,3193 @@ +[Contents] +Topics: + +  DESCRIPTION DESCRIPTION +  OPTIONS OPTIONS +  Overview Overview +  Mouse Support Mouse Support + +  Keys Keys +  Miscellaneous Keys Miscellaneous Keys +  Directory Panels Directory Panels +  Shell Command Line Shell Command Line +  General Movement Keys General Movement Keys +  Input Line Keys Input Line Keys + +  Menu Bar Menu Bar +  Left and Right Menus Left and Right Menus +  Listing Mode... Listing Mode... +  Sort Order... Sort Order... +  Filter... Filter... +  Reread Reread +  File Menu File Menu +  Quick cd Quick cd +  Command Menu Command Menu +  Directory Tree Directory Tree +  Find File Find File +  External panelize External panelize +  Hotlist Hotlist +  Extension File Edit Extension File Edit +  Background jobs Background jobs +  Menu File Edit Menu File Edit +  Options Menu Options Menu +  Configuration Configuration +  Display bits Display bits +  Confirmation Confirmation +  Learn keys Learn keys +  Virtual FS Virtual FS +  Layout Layout +  Save Setup Save Setup + +  Executing operating system commands Executing operating system commands +  The cd internal command The cd internal command +  Macro Substitution Macro Substitution +  The subshell support The subshell support +  Controlling Midnight Commander Controlling Midnight Commander +  Chmod Chmod +  Chown Chown +  File Operations File Operations +  Mask Copy/Rename Mask Copy/Rename +  Internal File Viewer Internal File Viewer +  Internal File Editor Internal File Editor +  Completion Completion +  Virtual File System Virtual File System +  FTP File System FTP File System +  Tar File System Tar File System +  Network File System Network File System +  Undelete File System Undelete File System +  Colors Colors +  Special Settings Special Settings +  Terminal databases Terminal databases + +  FILES FILES +  AVAILABILITY AVAILABILITY +  SEE ALSO SEE ALSO +  AUTHORS AUTHORS +  BUGS BUGS +  License License +  QueryBox QueryBox +  How to use help How to use help +[DESCRIPTION] +DESCRIPTION + +The Midnight Commander is a directory browser/file manager +for Unix-like operating systems.[OPTIONS] +OPTIONS + + +"-a" Disables the usage of graphic characters for line +drawing. + +"-b" Forces black and white display. + +"-c" Force color mode, please check the section ColorsColors for +more information. + +"-C arg" Used to specify a different color set in the +command line. The format of arg is documented in the +ColorsColors section. + +"-d" Disables mouse support. + +"-f" Displays the compiled-in search paths for Midnight +Commander files. + +"-k" Reset softkeys to their default from the +termcap/terminfo database. Only useful on HP terminals +when the function keys don't work. + +"-l file" Save the ftpfs dialog with the server in file. + +"-P" 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. + +"-s" Turns on the slow terminal mode, in this mode the +program will not draw expensive line drawing characters +and will toggle verbose mode off. + +"-t" Used only if the code was compiled with Slang and +terminfo: it makes the Midnight Commander use the value of +the TERMCAP variable for the terminal information instead +of the information on the system wide terminal database + +"-u" Disables the use of a concurrent shell (only makes +sense if the Midnight Commander has been built with +concurrent shell support). + +"-U" 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). + +"-v file" Enters the internal viewer to view the file +specified. + +"-V" Displays the version of the program. + +"-x" 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. + +[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 menu bar line.Menu Bar 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 Directory +Panels,Directory Panels the Left and Right MenusLeft and Right Menus and the File Menu.File Menu + +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 Shell Command LineShell Command Line and Input Line KeysInput Line Keys +sections to learn more about the command line. + +[Mouse Support] +Mouse Support + +The Midnight Commander comes with mouse support. It is +activated whenever you are running on an xterm(1) 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 gpm 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 extension fileExtension File +Edithas 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 Help ViewerHelp and the Directory +Tree.Directory Tree + +The default auto repeat rate for the mouse buttons is 400 +milliseconds. This may be changed to other values by +editing the ~/.mc/iniSave Setup file and changing the +mouse_repeat_rate 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.[] + + +[Keys] +Keys + +Some commands in the Midnight Commander involve the use of +the Control (sometimes labeled CTRL or CTL) and the Meta +(sometimes labeled ALT or even Compose) keys. In this +manual we will use the following abbreviations: + +C- means hold the Control key while typing the +character . Thus C-f would be: hold the Control key +and type f. + +M- means hold the Meta or Alt key down while typing +. If there is no Meta or Alt key, type ESC, release +it, then type the character . + +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 File MenuFile Menu 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 Directory PanelsDirectory Panels 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 Shell Command LineShell Command Line 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. + +Input Line KeysInput Line Keys are used for editing input lines. This +means both the command line and the input lines in the +query dialogs. + +[Miscellaneous Keys] +Miscellaneous Keys + +Here are some keys which don't fall into any of the other +categories: + +Enter. 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 chdir(2) 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 extensions fileExtension File Edit then the corresponding +command is executed. + +C-l. Repaint all the information in the Midnight +Commander. + +C-x c. Run the ChmodChmod command on a file or on the tagged +files. + +C-x o. Run the ChownChown command on the current file or on the +tagged files. + +C-x l. Run the link command. + +C-x s. Run the symbolic link command. + +C-x i. Set the other panel display mode to information. + +C-x q. Set the other panel display mode to quick view. + +C-x !. Execute the External panelizeExternal panelize command. + +C-x h Run the add directory to hotlistHotlist command. + +M-!, Executes the Filtered view command, described in the +view command.Internal File Viewer + +M-?, Executes the Find fileFind File command. + +M-c, Pops up the quick cdQuick cd dialog. + +C-o, 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. + +[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 Left and Right +Menus.Left and Right Menus + +Tab, C-i. 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. + +Insert, C-t. 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. + +M-g, M-h (or M-r), M-j. Used to select the top file in a +panel, the middle file and the bottom one, respectively. + +C-s, M-s. 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 "Show mini-status" 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 "backspace" or DEL keys can be used to +correct typing mistakes. If C-s is pressed again, the next +match is searched for. + +M-t 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. + +C-\\ (control-backslash). Show the directory hotlistHotlist and +change to the selected directory. + ++ (plus). This is used to select (tag) a group of files. +The Midnight Commander will prompt for a regular +expression describing the group. When Shell Patterns 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 Shell +Patterns 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. + +\\ (backslash). Use the "\" key to unselect a group of +files. This is the opposite of the Plus key. + +up-key, C-p. Move the selection bar to the previous entry +in the panel. + +down-key, C-n. Move the selection bar to the next entry in +the panel. + +home, a1, M-<. Move the selection bar to the first entry +in the panel. + +end, c1, M->. Move the selection bar to the last entry in +the panel. + +next-page, C-v. Move the selection bar one page down. + +prev-page, M-v. Move the selection bar one page up. + +M-o, 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. + +C-PageUp, C-PageDown Only when ran on the Linux console: +does a chdir to ".." and to the currently selected +directory respectively. + +[Shell Command Line] +Shell Command Line + +This section lists keys which are useful to avoid +excessive typing when entering shell commands. + +M-Enter. Copy the currently selected file name to the +command line. + +C-Enter. Same a M-Enter, this one only works on the Linux +console. + +M-Tab. Does the filename, command, variable, username and +hostname completionCompletion for you. + +C-x t, C-x C-t. 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. + +C-x p, C-x C-p. 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. + +C-q. The quote command can be used to insert characters +that are otherwise interpreted by the Midnight Commander +(like the '+' symbol) + +M-p, M-n. 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. + +M-h. Displays the history for the current input line. + +[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. + +Up, C-p. Moves one line backward. + +Down, C-n. Moves one line forward. + +Prev Page, Page Up, M-v. Moves one pageful backward. + +Next Page, Page Down, C-v. Moves one pageful forward. + +Home, A1. Moves to the beginning. + +End, C1. Move to the end. + +The help viewer and the file viewer accept the following +keys in addition the to ones mentioned above: + +b, C-b, C-h, Backspace, Delete. Moves one pageful +backward. + +Space bar. Moves one pageful forward. + +u, d. Moves one half of a page backward or forward. + +g, G. Moves to the beginning or to the end. + +[Input Line Keys] +Input Line Keys + +The input lines (they are used for the command lineShell Command Line and +for the query dialogs in the program) accept these keys: + +C-a puts the cursor at the beginning of line. + +C-e puts the cursor at the end of the line. + +C-b, move-left move the cursor one position left. + +C-f, move-right move the cursor one position right. + +M-f moves one word forward. + +M-b moves one word backward. + +C-h, backspace delete the previous character. + +C-d, Delete delete the character in the point (over the +cursor). + +C-@ sets the mark for cutting. + +C-w copies the text between the cursor and the mark to a +kill buffer and removes the text from the input line. + +M-w copies the text between the cursor and the mark to a +kill buffer. + +C-y yanks back the contents of the kill buffer. + +C-k kills the text from the cursor to the end of the line. + +M-p, M-n 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. + +M-C-h, M-Backspace delete one word backward. + +M-Tab does the filename, command, variable, username and +hostname completionCompletion for you. + +[] + + +[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 Left and Right MenusLeft and Right Menus allow you to modify the +appearance of the left and right directory panels. + +The File MenuFile Menu lists the actions you can perform on the +currently selected file or the tagged files. + +The Command MenuCommand Menu lists the actions which are more general +and bear no relation to the currently selected file or the +tagged files. + +[Left and Right Menus] +Left and Right Menus + +The outlook of the directory panels can be changed from +the "Left" and "Right" menus. + +[Listing Mode...] +Listing Mode... + +The listing mode view is used to display a listing of +files, there are four different listing modes available: +Full, Brief, Long, and User. 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 "ls -l" +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: + +name, displays the file name. + +size, displays the file size. + +bsize, is an alternative form of the