pax_global_header00006660000000000000000000000064150110252150014502gustar00rootroot0000000000000052 comment=87b2a2a6aba26756caa6699976c222b395cee8fa jove-4.17.5.5/000077500000000000000000000000001501102521500127065ustar00rootroot00000000000000jove-4.17.5.5/ChangeLog000066400000000000000000003004121501102521500144600ustar00rootroot00000000000000Author: Mark Moraes Date: Thu Feb 27 08:50:25 2025 -0500 4.17.5.5: restore mode-line indicator for show-match-mode, rename all strings to provide clue to the command to turn them off. update to debian Brazilian translation https://github.com/jonmacs/jove/issues/25 NOARGS macro for functions with no arguments replace bool with jbool for c23 (bool is a keyword) jmake.sh: ask for c89 (hopefully avoids complaints re: old-style protos). Search for gcc on SunOS to address https://github.com/jonmacs/jove/issues/23 add tmux terminal to builtin jtc fix some github actions bitrot Author: Mark Moraes Date: Thu Nov 30 02:48:10 2023 -0500 4.17.5.4 continued: get rid of ubuntu containers since docker pull fails, not sure why. fix workflows typos and skip ctags for Rocky even more elaborate hackery to fixup apt sources.list for archived debians like 8 and 9. add rockylinux:9 removal of sys/stat inclusion in recover.c broke mingw (and probably DOS) fixed it (in scandir.c) to work in both (probably also now works for the not-tested-in-years classic Mac port) testbuild: debian 9 regression no longer gets all the security repos, so continue if apt update fails Author: Mark Moraes Date: Tue Nov 28 22:52:00 2023 -0500 4.17.5.4 made jove compile and run on a BSD4.3 image running under simh. A few modernisms had crept in, but one bug (trying to use sg[].t_susp instead of ls[].t_susp in kbd_sig, send_oxc in iproc.c) seems to date back to 4.16beta! Fun things I had forgotten: * mkdir -p, test -d did not exist * ! and type did not exist in the shell * UL suffix did not exist for constants * ternary cannot have two different pointer types (void * vs char *) * include files are not protected against double inclusion * did not have S_ISDIR(x), use (x * S_IFMT) == S_IFDIR) * recover.c used strerror Author: Mark Moraes Date: Sun Mar 19 16:58:00 2023 -0500 4.17.5.3 put qref and example.rc in DDOCDIR (e.g /usr/share/doc/jove), update README to mention docs. Author: Mark Moraes Date: Sun Feb 26 17:31:00 2023 -0500 4.17.5.2 fix https://github.com/jonmacs/jove/issues/15 macros in joverc run immediately after the execute-macro command is processed (disallow macros from sourcing joverc to avoid a corner case that seems of low value), added doc/test*.rc to test rc handling. fix https://github.com/jonmacs/jove/issues/20 trims trailing whitespace off empty lines between paragraphs in comments per @C0RD for Debian conventions (probably other Linux too), Makefile now installs jove.man.pdf and jove.man.txt to DOCDIR, defined as $JOVEHOME/share/doc/jove by default (instead of SHAREDIR), fixed pkg/deb/debian/jove.docs to match. Added a few NOTREACHED after complain() and finish(). Author: Mark Moraes Date: Thu Feb 23 16:56:50 2023 -0500 4.17.5.1 remove doc/jem.rc, add doc/test.rc (some regression tests for joverc processing) fix https://github.com/jonmacs/jove/issues/17 and https://github.com/jonmacs/jove/issues/18 (often fails to fill last word in para) by reverting one change from 4.16.0.74. remove keychart. (causes trouble on Windows/DOS, not needed) rename *.doc to *.txt since everything expects .doc to be Microsoft Word files. Delete generated file before copying new one over it. remove cleanall target, added distclean synonym for clobber. install teach-jove and jove.qref with cmds.doc target for simplicity. generate jove.man.pdf rather than jove.man.ps. rename jove.man to jove.man.txt for consistency (redhat pkg did this already) Author: Mark Moraes Date: Mon Feb 20 19:19:35 2023 -0500 4.17.5.0 continued: forgot to put Beginner_Help call in jove.rc.in, (renamed jem1.txt to jem.text, and removed jem1.hlp, since new teach-jove command can replace about-jove mini-description). No real need for full jem.rc (those function key bindings clash with others, which would be confusing, and don't work in modern window systems anyway, since many of those function keys are intercepted by the desktop!) install jove.qref and jem.txt in SHAREDIR lower threshold to move objects from near to far in Makefile.wat so we can raise stack DOS build from 11000 to 18000 (since 11000 caused a stack overflow at least once -- 11500 did not, but seems worth some headroom; still handles about 35000 lines in a 200K executable) fix jexecpath bugs on NetBSD, FreeBSD (typos, stdbool clash), OpenIndiana (need getCWD before fixrelpath is called) Author: Mark Moraes Date: Mon Feb 20 13:55:43 2023 -0500 4.17.5.0 continued: WIN64 (x86_64-w64-mingw32) should build and work (JRWSIZE_T definition, avoid couple of ptr->unsigned long casts in debug printf) avoid "Unexpected" or "malformed" complaint when "else" or "endif" is followed by whitespace in joverc remove couple of dups in jove.qref fix typo ('0' should be '\0' in getvar(), fixes ifvar) adopt Debian jem* files if no .joverc or env var JOVENOHELP is not set to 1 Author: Mark Moraes Date: Wed Jan 25 00:16:41 2023 -0500 4.17.5.0 continued: If SHAREDIR or LIBDIR are relative paths, interpret them as relative to the directory from which the jove binary was run (i.e. BINDIR) which makes more sense in most situations, does not get confused if one uses cd or pushd, and allows us to create relocatable/portable Jove installations (particularly useful on Windows or DOS) increase 9 to 15 for MAXBASENAMELEN so that .exe and teach-jove fit. ensure that SyncRec is called after a buffer is unmodified (usually because it was saved) to avoid being asked to recover buffers with contents older than the saved version after a system or jove crash/kill. Use jamstrcat instead of jamstrsub for features, also use jamstr* to check some string ops in PathParse (though they are probably ok) Update teach-jove tutorial somewhat. Remove redundant install and DESTDIR in Debian pkg sample, since dh_auto_install adds those anyway. Some tweaks to sysdep.h and tune.h i686-w64-mingw and alpine static in testbuild use relative SHAREDIR & LIBDIR so those can be copied and run anywhere without installation. JMAKE_RELATIVE=1 env var causes jmake.sh to set DESTDIR, JBINDIR, JSHAREDIR, JLIBDIR appropriately to exploit relative SHAREDIR, LIBDIR Added mingw and musl-static builds to jmake.sh (both use relative) and simplified testbuild.sh Copy ChangeLog to DOS zip as changelg.txt, and doc/teach-jove as teachjov.txt teach-jove and relative features mean slightly smaller stack for DOS Updated README.dos and README.win Tried to make WIN64 (x86_64-w64-mingw32) build work, still does not work. some cleanup reported by pedantic on win32.c, proc.c, Author: Mark Moraes Date: Mon Jan 9 22:34:02 2023 -0500 4.17.5.0 unnoticed bugfix to joverc, just build and test tweaks Makefile tweak so nothing is written to pwd on install target if the all target was already run with the same variables by generating files in tmp before copying if different. created pkg/rpm and pkg/deb dirs, moved jspec.in to pkg/rpm added a sample derived from Cord's debian packaging info to pkg/deb along with a testdeb.sh script that runs pbuilder to generate pkgs for amd64, arm64 and armhf as a test of cross-build. Add pkg to tgz, plus some other .filelist cleanup (include jove.spec) updated some of the test environments in github actions to more recent ones. put old/ back into github automatic release tarballs since it is mentioned in README as a source for info about older sysdep. testbuild.sh: try to put human-friendly distro name and ver in output. automate sudo guesswork and provide env var SUDO override, no need for --sudo-preinstall option. add --force-yes in addition to -y to avoid interaction for apt install of prereqs. Invoke pbuilder if available to generate deb pkgs (but we do not add it automatically as a prereq, pretty expensive, plus seems unhappy inside container) use gzip instead of bzip2 since latter is sometimes missing on some platforms. joverc handling (commands.*, vars.*, keys.txt) Backed out of bsearch that I tried in 35dc21ae 4.17.3.2 since it does not provide the first-unambiguous-match behaviour. But now generate cmdidx and varidx in setmaps for a little less code in Jove. added teach-jove command and -T option to Jove to invoke it, removed standalone teachjove executable which was a nuisance (relied on cp so did not work on Windows/DOS). replaced teachjove.c with teachjove shell script for compatibility, but wonder if we can just get rid of those, less namespace pollution. removed duplicate/obsolete config from pkg/deb/debian/jove.rc (which goes in /etc/jove/jove.rc on Debian) Author: Mark Moraes Date: Sun Dec 18 02:52:09 2022 -0500 4.17.4.9 screen.c remove vestigial unused variable 'col' (causes complaints on FreeBSD 13.1) Author: Mark Moraes Date: Sun Dec 11 16:27:21 2022 -0500 4.17.4.8 jmake.sh: pass CC through, accept JMAKE_UNAME as override for uname. only use CC=gcc for Linux reverted a bit of da9018786dcb2e4a30f3f63ecd5081fc710d50e1 to use SYSDEFS instead of CPPFLAGS, because FreeBSD does not have the latter as part of .c.o, sigh. So we're back to SYSDEFS for -D or -I and OPTFLAGS for -O or other oddball compiler flags. default to gcc-style optflags, only change that for SunOS or unknown. testbuild.sh --preinstallonly or --sudo-preinstallonly exits after prereq package install without building, useful for updating containers. make rpm more robust for old containers that may have an previously installed jove, use TB_MACH instead of hardwired x86_64 Author: Mark Moraes Date: Fri Dec 4 20:20:45 2022 -0500 4.17.4.7 recover.c: changed copystr to copystrs in to avoid sprintf to fixed size buffer that generated many complaints. setbuf on pipe seems unnecessary on modern machines/libc. missing space in error message testbuild.sh: for apt case, use OPTFLAGS from Cord debian hardening Author: Mark Moraes Date: Fri Jul 8 03:39:05 2022 -0400 4.17.4.6 ifdef jove-{compiled,linked}-with variables for UNIX or MINGW in vars.tab, to match jove.h (the variables get defined by lines appended by the Unix Makefile to keys.c) fix missing case where long line did not set the error flag and therefore did not rename the buffer to a temporary name (same issue noted by Adam Sjøgren, partly fixed in commit 2a256983c9d4026c5745f4ea333d9140f9a6c24a, Mar 14, 2020) clean removes */*.tmp files jmake.sh looks for pkgconf before pkg-config since it's the new cool thing... some /etc/*-release are symlinks, testbuild.sh was skipping those. Author: Mark Moraes Date: Tue Jul 8 00:38:41 2022 -0400 4.17.4.5 apt case in testbuild installs bzip2 and dpkg-dev Replace buildflags.sh complexity with jmake.sh Makefile uses modern CPPFLAGS, CFLAGS, LDLIBS convention instead of SYSDEFS, OPTFLAGS and TERMCAPLIB, EXTRALIBS (though the latter should still work if the former aren't used). Changed from repeated invocation of buildflags.sh to a single jmake.sh wrapper (also easier to bypass completely), jmake.sh will invoke dpkg-buildflags if it exists, per https://github.com/jonmacs/jove/issues/11 and https://wiki.debian.org/HardeningWalkthrough Added jove-compiled-with and jove-linked-with variables to make it a bit easier to find out post-facto what the flags and libraries and compiler/linker options were. Fix spurious uninitialized-variable complaint in io.c Ensure initial modeline update on Windows Author: Mark Moraes Date: Sun Jun 5 20:19:02 2022 -0400 4.17.4.4 incorrect regexp in doc/jove.rc add documentation for insert-variable remove the -ms docs from the all: target since many Linux do not install -ms macros with groff, and those are only needed for formatted manuals, not the online help. fdocs target will build them. commit 6482cdc0d5cb7ee6e50fb18b8cf0369be769c33d Author: Mark Moraes Date: Sun Jun 5 20:19:02 2022 -0400 4.17.4.3 fix testbuild.sh to run on Debian Hurd. commit 71fe53cf1a864ce0a60120a7a3d06f583ce4fc81 Author: Mark Moraes Date: Sun Jun 5 19:33:42 2022 -0400 4.17.4.2 move preinstall from testbuild.yml to testbuild.sh to reduce duplicate code generate binaries and docs in DIST artifacts from github actions as part of all test builds move more old platform comments (Xenix, OSF/1 etc) for other compiler and link flags from Makefile to README for consistency. use only spaces in version.h to make it simpler for BSD sed (no \t, did not want to put literal TAB in Makefile, something might eat or munge it) update buildflags for Debian Hurd commit b36f587cf4990a266812d48a38ae73bbdb3ef12a Author: Mark Moraes Date: Mon May 30 01:51:27 2022 -0400 4.17.4.1 fixed sysdep.h, buildflags.h and jspec.in so Linux now uses GLIBCPTY (aka OPENPTY, BSDPOSIX_STDC rather than SYSVR4) since modern Linux (Debian 10 on, Alpine 3.13) seem to hit the issue reported in https://github.com/jonmacs/jove/issues/6 where the exit of interactive shells (when they see an EOF) confuses Jove. Added CentOS, Fedora, Alpine to the github actions build matrix. commit bba72938670cc350c45adc47222827382a5ea4a2 Author: Mark Moraes Date: Sat May 28 17:05:45 2022 -0400 4.17.4.0 fix nasty bug I introduced to recover in 4.17.2.8, forgot to pass buflist to erealloc, resulted in uniitalized memory references, would mess up badly on recovery files after the first set. Now passes valgrind cleanly. Also simplified option parsing a bit, added -r to also override the RecDir from cmdline, accept double-dash options as well, produce Usage for any unknown option, heuristic to detect missing argument. Use emalloc in place of malloc in a few places. commit 716ee39f1503f162aa2add7b387da0cfb7596867 Author: Mark Moraes Date: Mon Dec 6 00:00:59 2021 -0500 4.17.3.9 ignore switch "--" on command-line so that visudo works https://github.com/jonmacs/jove/issues/7 commit 89aa22d940cbc72386b59599ce403e96a64830ee Author: Mark Moraes Date: Tue Jul 6 22:51:29 2021 -0400 fix build on precise commit a155b00139e1c6ca7da676a2dccf8548b93ae3a8 Author: Mark Moraes Date: Fri Mar 19 23:51:37 2021 -0400 4.17.3.8 Added ChangeLog and LICENSE to MISC so 'make tgz' gets them Skip old/* for github autogeneration Mark *.ico binary commit 1417da64acb0ba9c8a0232d854f6d9b467c688cd Author: Mark Moraes Date: Mon Mar 15 00:50:16 2021 -0400 4.17.3.8 Do not fail build if ctags is missing. Improve error message from MakeTemp failure to show what caused it. MINGW needs NO_MKSTEMP because Windows mkstemp unlinks the filename, which is needed for filter-*. Fix two long-standing bug in Windows: shell-command used to crash on Win10 with code c0000005 because close(0) seemed to mess up input events, and filter-region did not work because InFName was not being being honored in the WIN32 ifdef. Tried to fix problem where Win10 waits for first event to update mode line. Helped sometimes, but still does not work consistently. commit b969d8967ebefb678131dcfc4f70cfe054b31bb2 Author: Mark Moraes Date: Mon Feb 22 20:05:50 2021 -0500 4.17.3.8 in-progress remove update flag for travis homebrew to see if that's fixed, should speed up Mac builds a lot. commit 043aaab5c8d4e71d4f40449a062dc870cf360e1c Author: Mark Moraes Date: Fri Feb 12 19:10:59 2021 -0500 4.17.3.8 in-progress Fix buildflags.sh for SunOS aka OpenIndiana. Add +e to end of script so internal travis errors do not cause regression to fail. commit 71b074fdf0dbfeede6b4b79323ef9d40f65a3b2f Author: Mark Moraes Date: Fri Feb 12 18:52:49 2021 -0500 4.17.3.8 in-progress Updated Makefile to support 7z or other zip/archiver commands for 'make zip' Improved buildflags pkg-config test slightly Updated README to describe package prereqs on many distros, clarify that buildflags defaults to/fallsback to JTC in many cases. commit 4b549fd67ba113afc14a89217b21dc483b377ce8 Author: Mark Moraes Date: Fri Feb 12 02:03:29 2021 -0500 4.17.3.8 in-progress fix mention of README.w32 -> README.win in README remove s390x from test platforms, seems to take a very long time and has never yet exposed a problem that other platforms didn't also expose. commit 81f448aab8899b05ca6d8921e344f434ce3a9986 Author: Mark Moraes Date: Thu Feb 11 22:59:07 2021 -0500 4.17.3.8 in-progress travis ubuntu precise seems to fail (though log shows it succeed?!), works on docker of 12.04, so switching to trusty for old ubuntu and add focal for newest. commit a9985e2bf0a62eb3c7cbb1a7e95872a954c40f28 Author: Mark Moraes Date: Thu Feb 11 01:52:24 2021 -0500 4.17.3.8 in-progress remove tabs from .travis.yml commit 0b927d2ac1158889c02cc904c5095994b80bab25 Author: Mark Moraes Date: Thu Feb 11 01:45:17 2021 -0500 4.17.3.8 in-progress Rename PPchar in setmaps to PPkey to avoid duplicate in tags. Add testmailer.sh to test recover -syscrash, also added support for JOVERECDIR to override default recover -syscrash destination (and code to mkdir it if needed). Other recover cleanup for error messages. commit ed750ba32e364e2dde0cf889f466a6e216938f86 Author: Mark Moraes Date: Thu Feb 11 01:40:07 2021 -0500 4.17.3.8 in-progress Added buildflags.sh utility script to intuit typical SYSDEFS (via --cflags) and TERMCAPLIB (via --libs) for most modern systems (*BSD, Linux, Solaris, MacOS X). The small overhead on each compile line seems well worth the ability for most people to not have to read the build docs. Updated .travis.yml Renamed README.w32 to README.win (clearer), moved README.cyg to old (normal README is fine for modern Cygwin) Removed EXPERIMENTAL comment on JTC, I've been happy with it for a year on a few systems (mainly Linux). Other documentation touch-ups. commit a6b7300941c02d75da4df3ed12aa81e58bfb0e20 Author: Mark Moraes Date: Thu Feb 11 01:35:34 2021 -0500 4.17.3.8 in-progress updated comment to indicate mac.c historical status moved README.mac to old to avoid confusing modern Mac users. commit 9eee27ae206ff8fc0960fc923d85e4d02f795455 Author: Mark Moraes Date: Fri Jan 29 11:30:14 2021 -0500 4.17.3.8 in-progress fixed branch name for travis commit ffaffa2acfd837a985aa2a1f5bed538d5d8fa551 Author: Mark Moraes Date: Fri Jan 29 00:59:47 2021 -0500 4.17.3.8 Jove now cross-compiles with MinGW (mingw-w64 4.0.4-2 on Ubuntu 16.04) for WIN32. Native WIN32 still seems to work. Fixed a bug in setmaps build that probably messed up most cross-compiles (setmaps must have exactly the same feature defines enabled when it includes commands.tab for local compile as will be used for the cross-compilation target platform) commit dcc4ffd4578e0a1513a1f9e287720bd307d6e0c9 Author: Mark Moraes Date: Fri Jan 29 00:12:27 2021 -0500 4.17.3.8 in-progress switched order of EXTRALIBS so that can link with -lasan -lubsan for address sanitizers which must be the first libraries. renamed SSIZE_T to JSSIZE_T to avoid MSVC clash, removes some ugliness from sysdep.h and removes problem building with mingw (work in progress) win32/mingw: add len arg to win32.c getcwd call fix signature for scandir jscandir in WIN32 branch remove couple of complaints when building with MSVC vcvars64 (in MSVC read/write 3rd arg remains unsigned int, not size_t for both vcvars32 and vcvars64). fprintf format complaint in recover.c, spawnve complaint in proc.c lowercase jjove.ico works for both native and mingw cross. commit 0ff14839ed1d4550d8441afa09e5e73820328fd2 Author: Mark Moraes Date: Sun Apr 5 14:17:37 2020 -0400 4.17.3.7 added left-right scroll to the minibuf. this is somewhat different logic than normal lines (does not use the Scroll* variables) because, well, so much about the minibuf is already so different from regular lines. Once it needs to scroll, tries to give the prompt no more than half the width (things like query-replace-search can have big prompts) and keeps the curchar at approx 3/4 of the width. Seems to look reasonable on both tiny and large screens. Also fixed a couple of code indentation weirdnesses I noticed in disp and reapp. commit 796bdcc55214740db5fc77becf744b1bff45f074 Author: Mark Moraes Date: Tue Mar 31 00:54:19 2020 -0400 4.17.3.6 put a '*' after the 6 digits of line number (if number-lines-in-window is on) if buffer has more than a million lines. Avoid recursion when formatting numbers. calculate percentage without risk of overflow. Add note that we avoid unsigned long because of ancient C compiler, be nice if we could format it since we can then use it for byte count, dot, etc (currently, io_chars e.g. as displayed in the message after writing a file goes negative on 32bit machines once one crosses 2GB of text, which can happen on modern machines, though unlikely in files one normally edits) commit b69684e31644db2c092337e5c233d5e0f37ff490 Author: Mark Moraes Date: Wed Mar 18 00:14:15 2020 -0400 4.17.3.5 fix type promotion bug in my bno_to_seek_off macro, results in bogus recovery and also some tmp file corruption above 32K lines for short daddr (i.e. only on DOS or pdp11) move DOS/WIN process.h inclusions to sysprocs.h and io.h to externs.h for simplification (removes a warning) Use EXIT macro everywhere that matters, defined as exit or _exit based on USE_EXIT. Updated README.{dos,w32} to proposed binary distributions joveNNN{s,w,m,l}.zip commit 8f16e4ec6ee90b36cda27815aab5db5b2dc6305c Author: Mark Moraes Date: Tue Mar 17 23:21:28 2020 -0400 deleted tbsearch.c, was a one-time test. commit d9b7034bb91bc5a52ef3f2c6a52d6f468c3c3424 Author: Mark Moraes Date: Tue Mar 17 23:20:55 2020 -0400 added test program for jbsearch for historical record commit 0e3d0f56f35f47deafc1316157c22427eb87db97 Author: Mark Moraes Date: Sun Mar 15 00:58:48 2020 -0400 Make jove -r work on Windows (better to exec/spawn it before we mess with the terminal; plus windows wants P_WAIT, for some reason P_OVERLAY does not work) Added jamstrcat (strcat with size check, and safe for overlap) utility function. commit 4012090145ad5778fdf4c42927c6292cd7daf582 Author: Mark Moraes Date: Sun Mar 15 00:56:40 2020 -0400 Fix to earlier 2a256983c9d4026c5745f4ea333d9140f9a6c24a commit, to leave buffers with null file names (e.g. Main) alone during read. Added proto decls for callbacks that MSVC seems to need (and fix one from ptrproto to proto) commit 3423a19158769f6fa5b167b45e101469a953e0c7 Author: Mark Moraes Date: Sat Mar 14 16:46:13 2020 -0400 Cord has been using LG_JBUFSIZ of 14 for Debian for a while anyway, seems a good time to bump this default to 15 (i.e. 32K, so max linesize is now that). It's 2020, VM on machines with >1GB of DRAM is the norm, I think a 2MB b_cache footprint for Jove is now quite acceptable. (Non-VM machines almost certainly need to use JSMALL anyway, or can override this). commit ba7736ce73911589c541f85afd067ac5876646f9 Author: Mark Moraes Date: Sat Mar 14 16:44:39 2020 -0400 removed the S_ISREG(m) macro hack and replaced with the underlying (m&S_IFMT) == S_IFREG idiom since that is in other jove code already. commit 2a256983c9d4026c5745f4ea333d9140f9a6c24a Author: Mark Moraes Date: Sat Mar 14 15:55:13 2020 -0400 4.17.3.4 Fixed issue noted by Adam Sjøgren, that a buffer with truncated lines can still be saved to the original file, which seems bad (fairly sure I've made that mistake at least once, accidentally starting a compile-it and saving files with truncated long lines that I had not noticed, or hadn't yet fixed). This change puts a temporary filename #FILENAME+~ on the buffer and marks it as SCRATCH (if new) till the read successfully finishes, switches the read to bail out on a Long line. insert-file changes the name but but does not mark the buffer scratch. shell processes stop at the long line as they used to (arguably also a bug that should be fixed, but that would require folding or truncating the lines -- I vaguely remember a fix that did that, anyone recall?) commit b09a9a05b0aa49d187cc0a7e993e7b6734755acb Author: Mark Moraes Date: Sat Mar 14 15:48:43 2020 -0400 may be gratuitous, but seemed pretty low-cost to protect truncstrsub from overlapping copies, for safety/consistency with jamstrsub. (One day, I'd really like to change all strcpy to jamstrsub, maybe rename it to jstrcpy, since copying to fixed-size buffers without size checks just creeps me out, I don't feel at all confident we can always get them just right by reasoning about them) commit 35dc21ae366f128e54a610af38e6d4af110b1c3b Author: Mark Moraes Date: Sat Mar 14 01:53:30 2020 -0400 4.17.3.2 Build recover on Win32, couple of tweaks to make it work. Fix Makefile.wat setmaps target that I broke in previous commit Use bsearch for commands instead of the single character hash, should be fewer steps for most common commands, since distribution is not even by character. Also use it for vars (has jbsearch for older systems) Added jove-features (read-only) variable with a colon-separated list of feature tokens, and an ifvar directive for joverc to use that, so can keep the same jove.rc file and not get errors on different platforms. probably useful for bug reports too. commit 222bda4921ded2795124ea9c2f4e74aa51a27e2a Author: Mark Moraes Date: Sun Mar 8 00:27:02 2020 -0500 removed negative line number bug from README commit ec656ce154f0994296368499687fa33b6511c2b3 Author: Mark Moraes Date: Sun Mar 8 00:06:47 2020 -0500 4.17.3.1 annotated error and len_error as NEVER_RETURNS too added /* NOTREACHED */ comment after those and a bunch of complain calls commit fa51970657fd31496f7c9f934d410da49c38478c Author: Mark Moraes Date: Sat Mar 7 23:15:45 2020 -0500 4.17.3.0 better version of NULLPROC/cmdproc_t initialization from Hugh Found and fixed couple more such complaints (from resetsighandler) Fixed couple of innocuous gcc complaints about uninitialized value (only if chr_to_* complains) commit 0966d6f4c750e618f7baf31759b5e560951125eb Author: Mark Moraes Date: Wed Mar 4 16:23:34 2020 -0500 recover.c: some machines off_t is long long, so cast correctly for debug printf wind.c: downcast long arg_val to int for grow/shrink, should be safe (int can hold the increment we plan to grow/shrink a window by) commit 8b93a409a987e553d584e53cc85bad8b44f08780 Merge: 3f0c245 d76b939 Author: Mark Moraes Date: Tue Mar 3 22:32:43 2020 -0500 Merge branch 'long-line-num' into moraes commit d76b9390c0f790b417ebbe81ebcd85150cb92b44 Author: Mark Moraes Date: Fri Feb 21 00:49:31 2020 -0500 4.17.2.9 try to use long for line numbers, so we do not see negative line numbers on platforms where int is 16bit, and can use arg > 32K to move forward, backward lines/chars/words, or goto line numbers. JLGBUFSIZ is now LG_JBUFSIZ to match other LG* constant names. Simplified blkio indirection and check lseek in tmp file for error. Improve tmp file too large message to show some numbers to help with understanding. Move a few constants from sysdep.h to jove.h to be with similar things, and vice-versa (so most JSMALL settings are in one block in sysdep.h). Rename CHAR_BITS to CHAR_BIT so we use the standard manifest if avail. commit 8601ea19036fd3dc8b54589c4cc4fb71eca7907e Author: Mark Moraes Date: Sun Mar 1 19:16:23 2020 -0500 4.17.2.8 DOS + recover cleanup rename SMALL manifest to JSMALL to reduce confusion with DOS memory mode. make MAXCOLS small (132) if JSMALL is defined recover cleanup: record JLGBUFSIZ and LG_CHUNK_SIZES to in header. compiles on DOS with OWC, some int -> long and other related fixes to make it work. tmpfile names now 8 chars. handle short reads of tmpfile more gracefully because there are some bogus daddrs in recfile when we reach out of memory (bug in rec or insert.c code, perhaps?) make recover header a bit more portable/robust across different configs of jove by storing more info in RECMAGIC and using only long rather than a mix of types. In principle, this opens the door to restoring rec files from any config of jove with the same program. move -D earlier in jove main so we can emit debug in functions called earlier. Add -D to recover so we can debug it more easily. define FULL_UNISTD for OWCDOS, it seems well-prototyped mention jove-users at freelists commit 3f0c24580ceda849cf2607f7a281c7cf76884681 Author: Mark Moraes Date: Sun Mar 1 19:16:23 2020 -0500 4.17.1.8 DOS + recover cleanup rename SMALL manifest to JSMALL to reduce confusion with DOS memory mode. make MAXCOLS small (132) if JSMALL is defined recover cleanup: record JLGBUFSIZ and LG_CHUNK_SIZES to in header. compiles on DOS with OWC, some int -> long and other related fixes to make it work. tmpfile names now 8 chars. handle short reads of tmpfile more gracefully because there are some bogus daddrs in recfile when we reach out of memory (bug in rec or insert.c code, perhaps?) make recover header a bit more portable/robust across different configs of jove by storing more info in RECMAGIC and using only long rather than a mix of types. In principle, this opens the door to restoring rec files from any config of jove with the same program. move -D earlier in jove main so we can emit debug in functions called earlier. Add -D to recover so we can debug it more easily. define FULL_UNISTD for OWCDOS, it seems well-prototyped mention jove-users at freelists commit 0a5e0ff4649c5fa9bcbea54873bcdcfbc90c6206 Author: Mark Moraes Date: Thu Feb 27 16:57:52 2020 -0500 distrib target becomes tgz, jovedos.zip becomes zip and makes joveVVVs.zip, distrib now makes both tgz and zip, clean does not remove tgz, clobber removes tgz and zip commit 3be5eb0f05f1caf2276a85e5b37bedde163f3e08 Author: Mark Moraes Date: Tue Feb 25 00:59:14 2020 -0500 4.17.2.7 Since -DLinux is default in Makefile, make TERMCAPLIB be -lncurses to match. That's a better default for most modern systems. Fix Makefile.wat to have bigger stacksize, needed for -ml. Added -os for default (which shrinks code slightly, but still not enough for -ms to work, sorry) Tried to skip failures for jove.rc on commands that might not exist. Use -D command-line option rather than JOVEDEBUG env var for debug filename, avoids security hazard. Hugh cleanup of jdprintf. Add some missing newlines. Put F_LOCKED on debug file so it doesn't get trashed. Print pid as long. Some cleanup of portsrv (takes --kbd as arg 1 to make it easier to run from shell for testing, fix signal handling for linux so kbd restarts correctly) Add RETRY_ERRNO macro to simplify (and not miss) all the places the retry-after-syscall is needed. jtc needs select, just make it non-conditional to help me build it under travis on more architectures. commit b1d6aac94aefba38b07460161ac3a45ab270e7de Author: Mark Moraes Date: Sun Feb 23 12:42:46 2020 -0500 per Hugh, missing space before opening paren commit f89cde8132df58dbbe61947cd5a658568cb0b33a Author: Mark Moraes Date: Sat Feb 22 01:27:08 2020 -0500 looks like all homebrew invocations need the update first, till https://github.com/travis-ci/packer-templates-mac/pull/13 makes it to production. simplified getconf logic to reduce chance it gets forgotten or copy/pasted. commit 67b24b81c5dc6dd83064d174e8f9b79e6dd6c258 Author: Mark Moraes Date: Sat Feb 22 01:13:59 2020 -0500 travis (well, yaml) does not like tabs, sigh commit d95f12d65ea36386199c4322c8f842602fe24b3d Author: Mark Moraes Date: Sat Feb 22 01:08:55 2020 -0500 fix travis indentation for homebrew, added flag that Darwin needs commit c27bb4b3b1055926376a1b63bfc5db21f3a7b21f Author: Mark Moraes Date: Sat Feb 22 00:52:52 2020 -0500 4.17.2.6 doc cleanup, removed email addresses in favor of github more travis cleanup, re-tested on alpine, fedora, gentoo, openindiana, *BSD rearranged test builds a bit Makefile quiet zip chatter OpenIndiana/Solaris compiler does not like promotion from void* to pointer-to-function, so added some typedefs and *NULLPROC definitions to quiet it down in commands.tab, disp.*, screen.*, setmaps ttystate.h simplified an ancient SUNOS4* ifdef commit 93b835ea412fd100c98e82765aa728a1dd6bb73b Author: Mark Moraes Date: Fri Feb 21 19:31:05 2020 -0500 odd "Error: Unknown command: bundle" error from homebrew, trying workaround proposed in https://travis-ci.community/t/macos-build-fails-because-of-homebrew-bundle-unknown-command/7296/13 commit 9524fec978b38167b252c2dd7973a56ac422431f Author: Mark Moraes Date: Fri Feb 21 17:30:55 2020 -0500 still fixing .travis.yml! commit 335f3e2e02efcfb778752e0b3c12c108a78f069d Author: Mark Moraes Date: Fri Feb 21 17:12:35 2020 -0500 .travis.yml fix mktemp portability quirk for old xcode, specify apts for jobs.include linuxes commit d5df0cf29d58f17cfa65290444077c74ff3b0792 Author: Mark Moraes Date: Fri Feb 21 16:44:46 2020 -0500 forgot to change one Makefile name commit 502392783dcde9f9ade4c87d8722eb9516515956 Author: Mark Moraes Date: Fri Feb 21 16:40:20 2020 -0500 Makefile: fix install dependencies so that -j works correctly. .travis.yml: try real gcc on osx, plus newer and older linux/osx images. Makefile.wat, sysdep.h and README.dos: describe medium vs large executables commit 00f751a50ab23c565a860d56e0702fcc4a2b6b4d Author: Mark Moraes Date: Fri Feb 21 00:53:06 2020 -0500 4.17.2.5: Use long for buffer-position line calculation, so can show more than 32K lines correctly on OWCDOS. This is a small localized change, and does not resolve the bigger issue that Jove uses int for line number calculations, which goes wrong in OWCDOS, which uses 16bit ints, so after 32K lines, number-lines-in-window starts showing negative line numbers. Fixing that, and goto-line (or arg-count) is a more extensive patch, debatable whether it is worth the change (large files are rare anyway, particularly on DOS, and does JOVE have enough usage on DOS to make this worth it?). With medium model, Jove can handle about 48K lines (around a 2.1MB file), and is pretty slow at that point. With large model, it handles only 31K lines (about a 1.4MB file), because we give more data space to the Jove buffer cache for increased speed. default UNIX to USE_GETWD if nothing else defined. commit 7ec53195363f98499340502a1b8a94add264a293 Author: Mark Moraes Date: Fri Feb 21 00:51:38 2020 -0500 per Hugh comment, Changed WATCOMC define OWCDOS so it is clearer that it is our symbol and only for DOS, not a compiler pre-def. commit 7a73b8d45fe6836ef0e273bf3e8979f848fc1cff Author: Mark Moraes Date: Fri Feb 21 00:13:00 2020 -0500 added note about memory models to Makefile.wat use FAR_LINES for all models in sysdep.h even if SMALL is not defined. commit f6a63db7f0dc1bfacb8cd593082afd17c0f2dd3f Author: Mark Moraes Date: Fri Feb 21 00:06:17 2020 -0500 fix Hugh comment re: SunOS, so this will complain on SunOS4 (who runs it now?!), and automatically add -DGRANTPT_BUG on SunOS5.0 (who ran it for more than a few minutes after SunOS5.1 came out?! Yes, I remember both SunOS4.0 nd 5.0 quite well, I still get nightmares about them...!) Add comment re: /usr/gnu/bin/install for modern Solaris/OpenIndiana commit 8769d7664ae167645ba0dd6a666924879cd79b00 Author: Mark Moraes Date: Wed Feb 19 20:58:34 2020 -0500 body on next line of if, per Hugh commit 6791a128dbc329b7f00b92890c445d4fa6f32593 Author: Mark Moraes Date: Tue Feb 18 23:16:57 2020 -0500 4.17.2.4 removed tags from all target, only needed for distrib and jovedoss.zip commit 02ca8173d987be68fababc748a33b721e35bcf60 Author: Mark Moraes Date: Tue Feb 18 00:35:17 2020 -0500 make travis now works on OpenIndiana (which really needs REALSTDC to work) commit f3c70d3c43dc91d5f1558473b72c53f8cfd087ba Author: Mark Moraes Date: Tue Feb 18 00:16:04 2020 -0500 further travis script fix (trying to see if 'make travis' works on platforms other than those available on travis-ci to make my virtualbox/docker testing easier commit 7058d46080e60cfcacd8ae4f3d53f1e4d0b9dd33 Author: Mark Moraes Date: Tue Feb 18 00:13:13 2020 -0500 further travis tweaks commit 9ffbacd3e03e95e4850ab8fa0237ab24c830d593 Author: Mark Moraes Date: Mon Feb 17 22:28:17 2020 -0500 another travis tweak commit 8f2d6dc0d2d3af17d7b5498e661564a670fa55be Author: Mark Moraes Date: Mon Feb 17 22:06:36 2020 -0500 have to turn set -u back on, since travis post-script functions break, sigh commit 6a45834003d06f9a7e30f5f196ea4733028ef011 Author: Mark Moraes Date: Mon Feb 17 21:44:48 2020 -0500 4.17.2.3 fix -DSMALL daddr/s_id ugliness, plus minor tweaks exposed by some of the new travis variants. travis: no need to use gcc+clang (they are the same thing on OS X by default, so rely on OSX for clang coverage, and Linux for gcc coverage, reduces build matrix) test some variants only on Linux for coverage (GLIBCPTY which mimics CYGWIN, and BSDPOSIX) Added 'make travis' target to try the travis script on local machine. commit 5b998c89d148fe1282dd7372eaeb78310b03702b Author: Mark Moraes Date: Mon Feb 17 12:56:51 2020 -0500 added .version, *.zip and some patterns for typical debris to .gitignore updated Makefile with 'make depend' updated .travis.yml to build a couple more variants, made it multiline so easier to read check Makefile works right without cmp commit f57a5d8da644abe1fab04a9a08a29268f257a435 Author: Mark Moraes Date: Mon Feb 17 02:07:00 2020 -0500 added ctags dependency to .travis.yml commit 18366d49bada3cc242928eef22267188df78ffc0 Author: Mark Moraes Date: Mon Feb 17 02:00:59 2020 -0500 4.17.2.2 builds on dosbox with Open Watcom 1.9.0 OW is fussy about char declarations for old-style function params, switched those to DAPchar (only a handful, gcc seems ok with this) ifdef out environ declaration (conflict with type) and exec* (usual confusion with consts not matching our interpretation of POSIX) Much fiddling with Makefile and Makefile.wat and Makefile.msc. Moved sysdepo.h to old/sysdep.h and Makefile.{bcc,zor} to old/ renamed paragraph.[ch] to para.[ch] to get rid of 8.3 hackery Made WIN32=1 default for Makefile.msc (it does not build for DOS, and I don't have the energy to figure out if that's even possible, it blows a type size assertion in the Windows headers. Updated README.dos to reflect current state. Cleaner X_OK hackery (define J_X_OK rather than redefining X_OK) Keep tags for PC jovedoss.zip, helpful when looking at src there (reduces need for distribs to have ctags). tags cleanup moved to clobber target. commit 72a05b6423a59651635e4b9e1669a29af457bc52 Author: Mark Moraes Date: Sun Feb 16 18:10:47 2020 -0500 4.17.2.1 addition: switched default Makefile OPTFLAGS back to -O so this does not blow up on non-gcc/clang platforms avoid fc31 gcc complaint re: ambiguous else. update jove.rc.in to avoid colors in i-shell busybox (e.g. alpine) commit 7eb35f8dda8af2dd0fafccfde7f8dded9fe767d1 Author: Mark Moraes Date: Sun Feb 16 18:01:16 2020 -0500 4.17.2.1 now works on openindiana (solaris) hipster x86_64 2019.11 (tested on the console in virtualbox) define NULL to 0 to avoid OpenIndiana (and likely other Solaris) complaints from initializing with their own NULL which is defined to (void *)0. cleanup of child iproc debug improve the logic for dup and close of slvptyfd I was clearly over-enthusiastic about CLOEXECs, since dup2 (on Solaris) copies the flag (Linux seems not to?) so I undid some that seem wrong in hindsight. important for OpenIndiana (likely many Solaris or SunOS5 or SYSVR4): ioctl TIOCSCTTY fails with ENOTTY, so cannot exit the child on that error, have to ignore it (this check was added 4.16.0.31, used to 'correctly' ignore that error return before .31, sigh! It's 2020 and ptys are still a portability nightmare) commit ff064e0dbad9a00c59e3e83c01747234b9423752 Author: Mark Moraes Date: Thu Feb 13 14:46:33 2020 -0500 4.17.2.0: found and fixed the causes of shell-command crashes on WIN32; one is that access(file, X_OK) with X_OK == 1 (the traditional/historical value) crashes. Set X_OK to F_OK for MS platforms. After that, the close/dup sequence to restore fds crashes (no idea why, just switched them to dup2 and it worked), switched spawnv to spawnve while I was at it so proc-env vars get passed through. commit cc795b7c76b01b4fc7759c87eb050f00a9151af2 Author: Mark Moraes Date: Thu Feb 13 14:42:13 2020 -0500 remove old files before redirecting onto them so that CYGWIN bug on vbox shared folders does not bite. commit cbcb072c900e7efd22e52fd2ed88130ac75ec679 Author: Mark Moraes Date: Wed Feb 12 23:25:11 2020 -0500 4.17.1.11: to catch .gitattributes (deleted pre-release 4.17.1.10) commit 6d3d348a53bad852c81acb7458b5cdf5c7652a08 Author: Mark Moraes Date: Wed Feb 12 23:21:32 2020 -0500 added .gitattibutes to exclude stuff from the github tarball commit 60a9cff1fb98c460fae513fdca96dbcd42e34eb7 Author: Mark Moraes Date: Wed Feb 12 22:42:19 2020 -0500 4.17.1.10 Removed afxres.h and resource.h and references to them from jjove.rc, they do not seem to be needed by Visual Studio 2019. MSVC also complains about exec* prototypes, like the comment said for Zortech and Borland, added _MSC_VER to that ifdef. Now builds cleanly on WIN32, but still crashes on subshell (push-shell works) Fixed weird and severe problem with Cygwin and VirtualBox saving files: open(...O_TRUNC) does *not* truncate a file that is on a VirtualBox shared folder (which is where I build jove src), so saving a file after deleting a few chars/lines results in old debris since it still stays the original size. open(O_TRUNC) works as expected on local disk. Windows open(O_TRUNC) works fine on both local disk and file in vbox shared folder. ftruncate works on both too, so added a redundant ftruncate after open(O_TRUNC) with an O_TRUNC_BROKEN manifest. (I have a test program to reproduce, will file a Cygwin bug report, not clear if this affects all network folders or just vbox, I suspect the latter else others would have noticed) Hit an infinite busy wait on pty a couple of times (EIO on IO_NEW pty ad nauseum in jdbg output), seems bad to have that risk (which the comment points out), added the pty creation time to the struct process, and eof after a few seconds. commit 301d3978f6b62de2c4f3885ba6763fc4d5b7f47b Author: Mark Moraes Date: Tue Feb 11 09:31:16 2020 -0500 added check that my new spell-command-format only contains one %s and no other % specifiers, so user error will not trash memory or crash jove. commit 9bef4a1b44ea03f286b276cb9f87355d128822cd Author: Mark Moraes Date: Mon Feb 10 22:03:18 2020 -0500 4.17.1.9 move aspell to FreeBSD, since NetBSD and OpenBSD have spell. Also enable aspell for CYGWIN. commit 8aa57e59b52ac5705dd96205b46537801b3db534 Author: Mark Moraes Date: Mon Feb 10 21:44:42 2020 -0500 *BSD also has aspell, added to XBSD definition commit 6ed0fbdb7b2da2680ab0b8e41c14798373bf3b8e Author: Mark Moraes Date: Mon Feb 10 21:32:58 2020 -0500 4.17.1.8: move various doc/jove.rc defauls (process-prompt, allow-^S-and-^Q, mode-line, disable-biff, pause-jove binding to ^[s ) to the code, they've been in doc/jove.rc for so long they can now be considered official, it reduces the number of weird differences when one just starts up the binary without SHAREDIR installed or for test. also leave allow-^S-and-^Q on for vt100. I refuse to believe any such real terminals are operational and used for Jove, but far more terminal emulators (e.g. NetBSD console!) claim to be vt100. update ModeFmt and MAX_TYPEOUT to new MAXCOLS to support the sort of wide-terminal that I suspect most of us now use. I think jove can afford the couple of hundred extra bytes (and when ported back to the PDP-11, MAXCOLS can be set lower, we can accept that fix when it is tested) commit 3bd5eafa75b6407a8930116b705392919d2c9a96 Author: Mark Moraes Date: Mon Feb 10 21:12:54 2020 -0500 Created spell-command-format variable, define it as aspell on Linux and *BSD, switch the SPELL manifest to the default value, documented. Seems to work. AFAIK, the old spell compatibility wrapper hasn't been shipped on most modern platforms. (Admittedly, it's been a very long time since I used spell to check my thesis, but felt bad it wasn't working when I tried it) commit e8d6b5690ff603d1c0b2efa6a7b88019ede38f2f Author: Mark Moraes Date: Mon Feb 10 21:09:05 2020 -0500 address-sanitize reported another overlapping strcpy, seems safest to make jamstrsub work for overlapping copies by calling memmove (it already has the string size), used byte_move() macro for portability and got rid of the ifdef around memmove in disp.c by making that a byte_move as well. Left mac.c alone, that already has memcpy and probably isn't going to ever be compiled again (please feel free to prove me wrong) #1 0x42cc7d in strcpy /usr/include/x86_64-linux-gnu/bits/string3.h:110 #2 0x42cc7d in jamstrsub /home/moraes/src/jove/github-jonmacs/jove/util.c:698 #3 0x44ca1f in setsearch /home/moraes/src/jove/github-jonmacs/jove/reapp.c:45 #4 0x44ca7d in search /home/moraes/src/jove/github-jonmacs/jove/reapp.c:64 #5 0x44ea6b in ForSearch /home/moraes/src/jove/github-jonmacs/jove/reapp.c:82 commit 314dc659b3db18d1ae8a332d576e1bb96010b3e1 Author: Mark Moraes Date: Mon Feb 10 21:02:43 2020 -0500 Fix memory leak in recover.c reported by leak-sanitizer commit db8e23cdcafa29f022f035f61008a0ce3030f110 Author: Mark Moraes Date: Mon Feb 10 20:56:50 2020 -0500 Only remove formatted docs, generated jove.spec and jove.rc to on clobber, not clean. That ensures that a tree sent via distrib to a PC/Windows won't result in missing docs when one does 'make clean'. Fixed mis-documentation re: PORTSRVINST. commit 4624e456a187afe169824704ec34e4d20bb70ac8 Author: Mark Moraes Date: Mon Feb 10 20:54:22 2020 -0500 setting DEBUGCRASH had the unfortunate side-effect of causing ^] to exit jove immediately (SIGINT), and I hit that sometimes when going for ^\ (since I grew up on a terminal where ^S was XON!) Since the main reason for DEBUGCRASH is to catch SEGV, BUS, etc, seems like HUP, INT, TERM should always be honored, moved those outside the ifdef. commit 045b93977330a93513dd483d2b56f63ed8e9b257 Author: Mark Moraes Date: Sun Feb 9 12:50:30 2020 -0500 4.17.1.7: removed redundant ifdef in proc.c since no real in the signal handling code for vfork and fork anymore (who knows if it's correct anyway), moved comment to vfork invocation. Ensure that environ is not changed in child (which might/will affect parent in the vfork case). Tested USE_VFORK briefly with Linux, seems to work for minimal testing. Added define for FreeBSD and OpenBSD in sysdep.h to save typing build flags, juse use make SYSDEFS=$(uname) Moved all historical definitions that are not currently tested to sysdepo.h (not included or used anywhere) Updated notes in Makefile, sysdep.doc, sysdep.h commit 8ed270b1e3125ab87bc0dc63f660d3e73bef1a1e Author: Mark Moraes Date: Fri Feb 7 19:33:59 2020 -0500 4.17.1.6 add TIOCGPTPEER for newer Linux (e.g. Alpine 3.9.4) which does not correctly set up pty (or ends up with wrong/bogus slvptyfd) without it! commit 8f28956f7eb6f4041471f215d0967a90d0d0e3ea Author: Mark Moraes Date: Thu Feb 6 09:12:04 2020 -0500 4.17.1.5: cleanup of portsrv so that echo ls | ./portsrv.exe /bin/sh sh -is and echo ls | ./portsrv.exe kbd seem to work rather than hang. pipeprocs still does not fully work on cygwin (neither does ptyprocs, TBD) tweaks to test pipeprocs on linux and *bsd as well, as a fallback option if (when?!) ptys fail, or just to keep an eye on portability to ancient systems. added a long-needed (IMHO) optional debug trace to jove in fmt.h, the jdprintf function and jdbg macro. JOVEDEBUG environment variable as a filename activates the debug logging -- at the moment, produces a trace of twisty little maze of ifdefs for pty/iproc handling (a mind-boggling portability horror show), which finally uncovered for me that NetBSD (7.2, 8.1 at least) TIOCREMOTE does not work as Jove expects (can I just say broken!), unlike other BSD siblings. Added NETBSD define to sysdep.h with the helpful NO_TIOCREMOTE, thanks to whichever kind soul (Hugh?) documented the breakage so clearly in iproc.c. Added CLOEXEC (attempt at robustness for modern systems after fork), has portabiity #define that should work on ancient ones. Use slvptyfd returned by openpty, seems better than relying on opening the ttyname, though the latter did seem to work fine in *BSD. Maybe this will help cygwin or netbsd, not sure. Clarify 'Out of ptys' message so it will be easier to tell which branch of code is failing. separated currently tested SYSDEFS from uh, historical artifacts in Makefile update .gitignore with generated formatted docs commit 98e7cba8e312fc7f40a3edcb0342e8d58b56e745 Author: Mark Moraes Date: Sun Feb 2 01:25:44 2020 -0500 4.17.1.4 Makefile.msc clean works, WIN32 has own getcwd. builds on MSVC 2019 Community Edition, but shell-command still crashes. PIPEPROCS compiles on Cygwin but crashes jove on startup. PTYPROCS compiles on Cygwin but hangs in openpty, sigh. commit 35905957a4d1763037ff014e32a014dee2017926 Author: Mark Moraes Date: Sat Feb 1 23:59:37 2020 -0500 4.17.1.3 fix typo in sysdep.h XBSD for Darwin Mac OS X move popd ahead in doc/jove.rc.in build doc/jove.rc for all commit 0b9729e6bdbd9983c16e04fd1782f84f05084041 Author: Mark Moraes Date: Sat Feb 1 23:17:36 2020 -0500 4.17.1.2: rename README.c32 to README.cyg and update for latest Cygwin (generally works on both CYGWIN64 and CYGWIN32), update README*. Move DispDefFs outside F_COMPLETION ifdef to match vars.tab, -DBAREBONES now compiles make extern declaration of getcwd unconditional, should be safe, and removes a complaint when building -DBAREBONES fix portsrv to detach from controlling terminal, so it works on Linux (for testing PIPEPROCS; the machines that one needed portsrv for presumably never had job control or controlling terminals?) added a matching RECOVER ifdef in jove.c to get rid of another complaint when -DBAREBONES ifdef to protect WIFSTOPPED in sysprocs.h, avoids complaints when -DBAREBONES remove jjoveico.uue and check in jjove.ico since git can handle binary files, unlike RCS, simplified Makefile to not need uudecode. Save formatted docs in distrib commit c404593b9eb6c1323e3f11296483e29310c524ab Author: Mark Moraes Date: Thu Jan 30 15:08:54 2020 -0500 4.7.1.1 tested on Cygwin 3.1.2, updated docs. commit 42a4eb3489e4c99b32d1cc97883243a3e97c6b86 Author: Mark Moraes Date: Thu Jan 30 14:38:27 2020 -0500 4.7.1.0 changes to build on Windows with MSVC 10.x. builds and mostly works (attempt to run shell command crashes) rename min, max to jmin, jmax, ReadOnly to BReadOnly, and undef CR before including windows.h to avoid clashes with MS macros or field names, sigh! move back to putting jversion in version.h (simpler for DOS/Windows) remove attempt at using git describe remove all targets and doc mentions of zoo format since zip is now ubiquitous use wsprintf instead of sprintf in win32 (MSVC libc apparently no longer provides sprintf by default) commit e409235d03eb1da27b9e93635d76338425c5a165 Author: Mark Moraes Date: Tue Jan 28 09:28:10 2020 -0500 4.17.0.9: fix stropts for latest Fedora/Arch, /etc/jove/jove.rc Cord requested a per-host jove.rc (jove already had a jove.local in sharedir, but that could be system-wide). Moved doc/jove.rc to doc/jove.rc.in, substituted ETCDIR (which defaults to /etc/jove), updated rpm package. Tested rpm on latest Fedora Docker image I could find (FC31), and discovered that it (and latest ArchLinux docker image) don't have stropts.h and do not define _XOPEN_STREAMS so added an if defined() check, now builds clean. Makefile fix to handle the situation of building in a brand new docker (i.e. no ~/rpmbuild directory to copy src into until one runs rpmbuild, chicken-v-egg) While at it, prefixed the DESTDIR variants of (SHARE|LIB|BIN|...)DIR with D to detect avoid mistakes from using old command lines. rpm built and installed and worked in Fedora FC31 smoothly. I'll see if I have the energy/patience to produce a PKGBUILD for Arch pacman... commit 8d22ba1d8e1b0d8a7b915b8de271f71512af9e99 Author: Mark Moraes Date: Mon Jan 27 13:19:26 2020 -0500 4.17.0.8 fix a small irritation - if one runs (with compile-it or shell-command) a script that one is editing, jove wants to overwrite the scrpt source (it prompts, but only offers the option to overwrite the src buffer). So put asterisks around names of process-output buffers, to match *minibuf* and *shell* to reduce the chance of a collision commit 440b451af0b71cce78dcd7e6090749199b647229 Author: Mark Moraes Date: Mon Jan 27 13:18:09 2020 -0500 4.17.0.7 typo in TMPDIR when renaming, so empty string in paths.h, fixed. commit 88aacef72465a2ea78282336f9a4a87505ee0829 Author: Mark Moraes Date: Sat Jan 25 22:04:02 2020 -0500 travis homebrew update seems to take a long time, try without it commit b5b09391d96b50afe227ab72602126c82bb61569 Author: Mark Moraes Date: Sat Jan 25 22:00:23 2020 -0500 need groff for some travis environments commit 586ead6202ef045ebcf00cf18e6505b7ae700dd1 Author: Mark Moraes Date: Sat Jan 25 21:57:47 2020 -0500 fixing travis script commit a24407f72cb94e8d1aa317927d645b0ce80517f9 Author: Mark Moraes Date: Sat Jan 25 21:39:59 2020 -0500 added .travis.yml to try some continuous-integration test builds. commit 99665b8e7fbdaded198efb5fbb40258a6eb670c1 Author: Mark Moraes Date: Sat Jan 25 18:57:41 2020 -0500 4.17.0.6: can now use make rpm to build an rpm package, tested on CentOS7.4 (other Fedora or RedHat testing needed) commit 33f1658f55419833bd56a49d44cea30a8a4fa8cb Author: Mark Moraes Date: Sat Jan 25 16:34:45 2020 -0500 4.17.0.5 fix version code to not duplicate version if that is the git tag commit b55bde96f77fc95a976fd9f7c00cbe2f4d31a374 Author: Mark Moraes Date: Sat Jan 25 15:53:44 2020 -0500 added jtc.c to C_SRC in Makefile commit e194676383e3e9fde8b2c457643239caa710833f Author: Mark Moraes Date: Fri Jan 24 22:34:06 2020 -0500 4.17.0.4: fixed -Wformat-overflow in teachjove.c, made exit status positive numbers, errors to stderr. commit de380c334a3348f72427d874af12d7a844ddcf30 Author: Mark Moraes Date: Fri Jan 24 21:53:05 2020 -0500 4.17.0.3: use -Wall -pedantic in default OPTFLAGS (clang and gcc support it; time to recognize that those are the dominant two compilers) Added LOCALEXTRALIBS variable and use it for setmaps (so I could specify EXTRALIBS=-lasan -lubsan and test with -fsanitize=address -fsanitize=memory) Added XEXT to setmaps for consistency (how did this ever work on DOS -- did we just ship keys.c?) typo in sysdep.h. (Note that -DXBSD probably covers all modern *BSD and Darwin, and -DXLINUX should probably cover all modern Linux, no need for the longer -DSYSVR...) fix sprintf buffer sizes so gcc 8.3 -Wall -pedantic (actually -Wformat-overflow) stops complaining (now builds on alpine with musl with clang 5 and gcc 8.3; also tested with clang 8 on CentOS7, and gcc 5 on Ubuntu 16.04) include errno.h (and optionally, stdio.h) in jove.h, to solve an include ordering fiasco in recover and setmaps, need tune.h to come first, so sysdep.h can specify _XOPEN_* or other features, before including any system includes. Adopt many of Cord's proposed changes from Debian package: DESTDIR prefix for all paths xjove/jovetool manuals not installed by default create and set permissions on missing *DIR install dirs switch to /var/tmp, it is not removed on reboot by FHS convention so recover -syscrash is not really needed. switch to groff options by default, who remembers ditroff! typo in doc/jove.nr commit 06e2a1d91a60d7cb7fcaa5889f7fe04d3545a486 Author: Mark Moraes Date: Fri Jan 24 10:51:40 2020 -0500 4.17.0.2 Back out of the reset-tabs sequence in jtc, does not work well on xterm and st (and konsole, per Paul Vixie) Fix all -Wall -pedantic complaints from gcc 5.5.0 (Ubuntu 16.04) declare dummy var in jtc so no complaints re: empty translation unit remove unused env_malloced variable from util.c (probably leftover, the real flag is in the Env struct) check setuid return in recover.c avoid sprintf in setmaps.c for trivial character formatting (still need to avoid sprintf in recover.c and teachjove.c, per clang complaints reported by Paul Vixie) Author: Mark Moraes Date: Thu Jan 23 23:01:00 2020 -0500 4.17.0.1: Cursory update for README, tweaked XBSD and XLINUX in sysdep.h commit aecc4dc618e68a39d9e53da0e68cb1dd15a3170a Author: Mark Moraes Date: Wed Jan 22 21:16:34 2020 -0500 4.17.0.0 candidate Some automatic version generation machinery in Makefile, uses git --describe. Remove version.h, only place version is specified is now Makefile, which generates jove.spec from jspec.in, and puts jversion and jversion_lnum in paths.h, which was already auto-generated, and can be used by jjove.rc instead of version.h Added LICENSE for general conformance/convenience (same as boilerplate header for src) and moved version.h history to ChangeLog, also more conventional Updated jove.spec to github make clean removes the xjove/.filelist and distrib created by make distrib Removed bogus reference and docs for non-existent IPROC_TERM jtc.c resets tabs on VTALT, avoids nastiness of some kinds if terminal gets borked (Jove really likes using phystab of 8) Updated .gitignore 5Acommit 41c658c11eedfbf2fc09f6559c03215f1e60aa98 Author: Mark Moraes Date: Thu Jan 23 22:25:51 2020 -0500 Updated jove.spec to github Clean removes the xjove/.filelist and distrib created by make distrib Removed bogus reference and docs for non-existent IPROC_TERM jtc.c resets tabs on VTALT, avoids nastiness of some kinds if terminal gets borked (Jove really likes using phystab of 8) commit 6d62c645b543bf2b7aebd85c62d001fa3dfba077 Author: Mark Moraes Date: Wed Jan 22 21:16:34 2020 -0500 Some automatic version generation machinery in Makefile, uses git --describe. Remove version.h, only place version is specified is now Makefile, which generates jove.spec from jspec.in, and puts jversion and jversion_lnum in paths.h, which was already auto-generated, and can be used by jjove.rc instead of version.h Added LICENSE for general conformance/convenience (same as boilerplate header for src) and moved version.h history to ChangeLog, also more conventional commit 586003424679800d75e78b534ef2bbcb61a705bd Author: Mark Moraes Date: Wed Jan 22 08:32:26 2020 -0500 ensure tune.h is first (move setjmp.h later) in jove.h (which is first everywhere else) so that system header features don't get defined, so we can now set _XOPEN_SOURCE or other features in sysdep.h or tune.h add XBSD and XLINUX to sysdep.h, for convenience on the two most common platforms around today (Darwin and Linux) commit 1c6e9a713069e190701307e661d464eb67d1d983 Author: Mark Moraes Date: Thu Jan 16 17:38:22 2020 -0500 tparm argument order seems wrong, needs to be l, c, since the definition for cm is %p1%d;%p2%d. tgoto is opposite and is c, l, presumably historical weirdness. commit 1de95ea776dd242f5d3acab8a0395388b609350c Author: Mark Moraes Date: Thu Jan 16 17:36:28 2020 -0500 UNIX may as well have MALLOC_CACHE set to 1, reduces apparent bss size. commit 5fbadda38f3b85ce71fb1acbc0c877d27e90d2a6 Author: Mark Moraes Date: Thu Jan 16 17:16:50 2020 -0500 fix delay code and add flushscreen for vb to avoid calling SitFor commit 996592ed7947c985538a187bdba75ab6c19d443e Author: Mark Moraes Date: Mon Jan 13 14:46:12 2020 -0500 switch from putpad to putstr since it is putting explicit escape sequences with no use of tputs syntax. commit 91eec94450bcb591ec88de8b4d1d857386debd6b Author: Mark Moraes Date: Sun Jan 12 12:45:08 2020 -0500 vb contains padding delays like $<100/> on most modern terminals (vt220, xterm) between the switch to reverse video and back, so it needs to be output by putpad (i.e. tputs), not putstr. On gnome-terminal (Ubuntu 16.04), set visible-bell on and hit ^G, and jove will produce $<100/> on the screen rather than a visual bell flash. commit 972f056a2ddc0d523c12fa2f3b9b585046476ac9 Author: Mark Moraes Date: Sun Jan 12 12:41:30 2020 -0500 Increase MAXCOLS from 256 to 512 (I get 300+ column maximized xterms on my new 4K monitor) commit 0ed38a00d06e4fb643bdfbcda9b963b291ac4f92 Author: Mark Moraes Date: Sat Jan 11 00:21:24 2020 -0500 added jtc, which provides all the termcap/terminfo functionality that Jove needs but is limited to ANSI X.3/VT[1-5]xx/xterm/rxvt/... (does anyone run anything else now) This avoids the small annoyance of the termcap/terminfo/curses/ncurses/ncursesw external dependency. commit 2fa2236ea50b22abc63e64b7532e0cc7e82db8a1 Author: Mark Moraes Date: Sat Jan 4 22:55:04 2020 -0500 increase size of tspace, xterm pretty close to edge, and some terms are over. commit e8390bd82e0305174c53e924a3de99193ff2e04f Author: Mark Moraes Date: Sat Jan 4 14:11:52 2020 -0500 correct TERM from emacs to dumb in README and mention {,i}proc-env* mention ncursesw and Alpine/docker note Changed jovehacks to jovedev email commit 3934215398c6cead35d23bc181adf13934bd0886 Author: Mark Moraes Date: Wed Nov 18 14:31:30 2015 -0500 added proc-env-{export,show,unset} to match iproc. changed jenvinit to more meaningful jenvdata. Fixed Makefile to use LANG=C for nroff etc so that it does not try smart hyphens (which break jove search) commit 88fb4b035946c6c3f141b532181801378e17baa9 Author: Mark Moraes Date: Wed Nov 18 02:37:28 2015 -0500 added iproc-env-{export,show,unset} commands to allow setting or unsetting env vars before interactive processes are started. Moved most code from set_process_env() to doc/jove.rc and added a few from jovedev email thread. commit f5a5f9122946e9bddd803a7178bfba6b0883e9f4 Author: Mark Moraes Date: Wed Nov 18 00:08:47 2015 -0500 Moved j{put,unsetenv}env from iproc.c to util.c, made them externally visible, declared in util.h, generalized them to take a ptr to an Env struct instead of modifying global state, keep one of those Env structs as iproc_env in iproc.c (preparatory to maintaining a separate one for proc.c) commit dbd3fe96fad7f3e3b77f763949b725e6930cdd5b Author: Paul Vixie Date: Sat Mar 2 06:38:36 2019 +0000 patch from github jonmacs/jove strcpy branch commit 2a6b24db99aa78351335583e133d1a970eeff583 very light strcpy audit, mostly to fix casey leedom report [the strcpy in proc.c:344 is also reported by valgrind ==27906== Source and destination overlap in strcpy(0x63e540, 0x63e540) MakeName (proc.c:344) ShellCom (proc.c:490) ExecCmd (commands.c:164) dispatch (keymaps.c:926) DoKeys (jove.c:1465) main (jove.c:1777) - moraes] commit 7f9e5d2b59ebfff8e4bfd5bb9b187c53465ba6c6 Author: paul vixie Date: Sat Mar 9 12:48:51 2019 -0800 use "do {}" rather than "do ;", for -pedantic (#5) commit e2d5e98fbf0b2d303f1f1cb7383e25ccc3ca990b Author: Mark Moraes Date: Sun Mar 10 23:25:45 2019 -0400 4.16.0.74: experimental release by Hugh on 2015-10-21 16:38 ftp.cs.toronto.edu:/pub/hugh/jove-dev/experimental/jove4.16.0.74.tgz tarball sha256sum 168084a021c38058d01e2de30d22b198836b12077647bd1e98dc8a9be416dbbf unfortunately same version in version.h further cleanup on fill (new_kill function for common code) Note about OpenSuSE TERMCAPLIB commit b8cb69213ee0c4f3200a203eda7aec39cfa4004f Author: Mark Moraes Date: Sun Mar 10 23:25:08 2019 -0400 4.16.0.74-old1: experimental release by Hugh on 2015-10-15 14:30 (email Oct 15, 2015 at 7:19 PM) ftp.cs.toronto.edu:/pub/hugh/jove-dev/experimental/jove4.16.0.74-old1.tgz tarball sha256sum ca679b63c38b424eed3e16d3a2ab40e4463c70bbc16e83164ae4ad692de26da3 Changes: - minor portability improvements - new jove.spec for Fedora and EPEL - fill-comment now handles paragraphs - fill-region can be undone via yank-pop - support for xterm-256color (same as xterm Revision 1.423 2010/07/11 15:29:31 hugh 4.16.0.73: - added NROFF="nroff -Tascii" to Makefile and jove.spec to force groff to use ASCII - spelling corrections [Cord Beermann] - remove -lolgx from xjove link [Cord Beermann] - improve recover's email Subject [Cord Beermann] Revision 1.422 2010/05/25 03:39:54 hugh 4.16.0.72: - eliminate strcpy and byte_copy calls with overlapping source and destination - fix setmaps.c misuse of fprintf Revision 1.421 2010/05/17 02:38:38 hugh - add new variable display-default-filenames (Casey Leedom) - eliminate most GCC warnings; improve handling of some errors - allow for Linux/glibc elimination of I_PUSH (pseudo TTY STREAMS) - improve jove.spec for Red Hat packaging - delete obsolete command process-dbx-output - delete obsolete variables allow-bad-filenames, display-bad-filenames, internal-tabstop - add bindings for more xterm function key variants Revision 1.420 2006/04/30 21:51:40 hugh don't crash when filename completion list is wider than screen Revision 1.419 2005/10/01 00:34:41 hugh 4.16.0.69: fix minor errors introduced in 4.16.0.67 Revision 1.418 2005/09/28 18:41:49 hugh Work around an xterm / termcap / terminfo bug involving SR. Revision 1.417 2005/05/14 20:29:03 hugh Generalize tags code to handle bizarre the mutations of tagfile format. Contributed by Mark Moraes; "improved" by DHR. Revision 1.416 2005/05/14 17:46:43 hugh rpmbuild now requires "License" tag in place of "Copyright" tag in .spec Revision 1.415 2004/07/11 20:04:32 hugh - dodge yet another xterm bug in hilite mode - set default buffer size to 4kB (ups line length limit to same) - tweak documentation Revision 1.414 2004/02/01 19:27:03 hugh - introduce sysdef BSDPOSIX_STDC - update README Revision 1.413 2003/05/05 01:37:05 hugh refine modified flag in list-buffers output Revision 1.412 2003/03/09 23:49:55 hugh 4.16.0.62: fix for WIN32; note tested environments [Jim Patterson] Revision 1.411 2003/02/01 02:02:08 hugh 4.16.0.61: increase MESG_SIZE to support wider terminals Revision 1.410 2003/01/31 22:15:33 hugh 4.16.0.60: fix screen update bug involving scrolling region Surprise: cursor location undefined after setting scrolling region Revision 1.409 2003/01/31 22:01:40 hugh 4.16.0.59: add "distrib" and "signeddistrib" Makefile targets tar file will now unpack into jove directory Revision 1.408 2003/01/09 02:07:15 hugh adjust jove.spec for yet another new rpmbuild requirement Revision 1.407 2002/12/13 01:52:47 hugh - allow $TERM for iprocs to be configured - adjust types of parameters of truncstrsub and jamstrsub (lint) - refine jove.spec (for RPM building); iproc TERM=vanilla Revision 1.406 2002/03/21 07:06:04 hugh update Copyright to satisfy Debian Revision 1.405 2002/02/12 20:14:08 hugh - add style.doc to describe some coding conventions - add a Makefile target to support Exuberant Ctags more conveniently - add a note about overflow in calculating percentage in buffer-position - change TERM and TERMCAP environment variables in iproc Revision 1.404 2001/12/20 21:07:25 hugh - fix Makefile problems with openpty configuration - factor LIBS into TERMCAPLIB and EXTRALIBS Revision 1.403 2001/12/17 22:24:14 hugh - fix a few buffer overruns - add "Quick summary" to README - use "jmode_t" where mode_t is appropriate (old systems must define as int) - use uid_t; hope this is portable - added GCC_LINT to make it more pleasant to use gcc warning options Revision 1.402 2001/07/15 19:14:23 hugh improve jove.spec (for Redhat Package Manager) Revision 1.401 2001/03/22 07:17:26 hugh 4.16.0.51: improve portability; use openpty on *BSD Revision 1.400 2001/02/04 21:01:50 hugh 4.16.0.50 support groff; fix jove.spec for RPM creation Revision 1.399 2000/11/10 07:58:22 hugh [BET+DHR] support installation into a playpen; exploit when building RPM Revision 1.398 2000/07/12 16:13:01 hugh 4.16.0.48: use SVR4_PTYS (AKA UNIX98 PTYS) for LINUX Revision 1.397 1999/10/22 14:16:39 hugh 4.16.0.47: get file creation mode right; predelete backup file Thanks to Rob McMahon Revision 1.396 1999/08/29 18:44:49 hugh 4.16.0.46: add save-on-exit [Rob.McMahon@warwick.ac.uk] Revision 1.395 1999/08/25 19:47:30 hugh 4.16.0.45: detect and report file close errors [Rob.McMahon@warwick.ac.uk] Revision 1.394 1999/08/19 02:14:13 hugh 4.16.0.44: add .spec for RPM creation Revision 1.393 1999/08/18 23:17:20 hugh 4.16.0.43: make mkstemp code less brittle (Moraes) Revision 1.392 1999/08/18 21:56:21 hugh make USE_CTYPE implicit in BSDPOSIX (except for __convex__!) Revision 1.391 1999/08/15 02:24:48 hugh Support for Cygwin32 environment on MS Win32 (from Arlindo da Silva and Dave Curry) Revision 1.390 1999/08/15 00:50:48 hugh 4.16.0.40: fix horrible umask security hole Revision 1.389 1999/08/13 14:43:05 hugh 4.16.0.39: reflect Jim's (Jim.Patterson@Cognos.COM) work on Win32 and HPUX Revision 1.388 1999/08/12 21:21:38 hugh 4.16.0.37: update Makefile and README to reflect modern systems Revision 1.387 1999/08/12 19:14:11 hugh 4.16.0.37: scatter "const"; update copyright; tidy comments Revision 1.386 1999/08/10 15:08:03 hugh 4.16.0.36: switch to safe creation of tempfiles. Note: mode_t isn't used because argument promotion rules mess things up. Some additional tidying. Tested on MSDOS, SunOS 4.0, Solaris 2.6, RedHat5.2. Revision 1.385 1999/08/09 05:50:51 hugh 4.16.0.35: fix nits in documentation Revision 1.384 1999/08/06 19:02:27 hugh 4.16.0.34: fixed a bug that caused justification of the following line to hang JOVE. set right-margin 70. Note whitespace at end. Revision 1.383 1999/08/06 16:47:20 hugh make xterm mouse code dodge metakey kludge (needed for xterms wider than 95) Revision 1.382 1999/02/11 18:41:51 hugh fix indented #ifdef: would confuse old compilers Revision 1.381 1998/09/22 21:10:44 hugh Rename SCO to SCO_ODT3 to be more specific. Fix typo in SCO_ODT3 settings (cannot test!). Thanks, Mark Moraes Revision 1.380 1998/09/22 03:47:03 hugh glibc-2 (the GNU C library, used in some LINUX systems) has a a unique (but probably not wrong) feature: stat, when it fails, scribbles over the stat buffer. This change lets JOVE deal with this feature. Thanks to Steve Thompson . Revision 1.379 1998/09/21 21:19:05 hugh Verify that other end of PTY can be opened before accepting it. This is needed apparently needed under LINUX. The test doesn't work on old versions of BSDI/386, so BSDI_PTY_BUG will suppress. Revision 1.378 1998/09/21 17:57:12 hugh fix error message construction [originally done 1998 March 29] Revision 1.377 1998/09/21 17:52:15 hugh avoid freeing already freed name list [originally done 1998 January 25] Revision 1.376 1998/09/21 17:48:10 hugh Change xterm-bug-workaround to avoid changes made for XFree 3.2. Without this change, mouse usage under the xterm of XFree 3.2 will leave mysterious blanks on the screen. The relevant change to XFree 3.2's xterm is that the sequence ESC X is now meaningful. We had counted on this to be ignored. Now we will count on ESC DEL being ignored. [originally done 1997 Sept 21] Revision 1.375 1997/07/10 06:06:30 hugh Add support for different meaning if im and ic with ncurses' termcap (used with LINUX and other free systems). Revision 1.374 1997/01/17 01:59:28 hugh 4.16.0.24: little touches - allow var internal-tabstop to be set to 0 (tab-width already could) - notes for porting to Digital UNIX - spelling improvement Revision 1.373 1997/01/16 22:08:26 hugh 4.16.0.23: handle symlinks in path canonicalization (PathParse) Revision 1.372 1996/10/10 06:59:26 hugh 4.16.0.22: more pr_name static buffer bugs Revision 1.371 1996/10/06 20:57:51 hugh 4.16.0.21: port to Digital UNIX V4.0 -- one JOVE bug, one OS bug Revision 1.370 1996/09/19 02:09:39 hugh 4.16.0.20: fix bug in window resizing by mouse To demonstrate bug: - split a window that is viewing a non-empty buffer - make upper window have a different dot. - enlarge the upper window by dragging its mode line down (button 2) The upper window's dot will be a copy of the lower window's. Revision 1.369 1996/09/09 06:29:43 hugh 4.16.0.19: eliminate tricky aliasing bug in Source/ask_ford/PathParse The bug to be fixed is the interaction of the following: - PathParse must not have aliased args - if ask_ford is called with def and buf aliased AND pr_name(def, YES) yields a pointer into def AND the user defaults the file name THEN PathParse will be called with aliased args - Source calls ask_ford with def and buf aliased To demonstrate: - set environment variable HOME to "" or "/" - run jove in some other directory - issue "source" command and hit return to default the file name - jove will attempt to source the file named "" The fix: since pr_name sometimes returns a pointer to its static buffer, the simplest change is to make it always return a pointer to its static buffer. At the same time, sprinkle a few comments about aliasing in the relevant routines. Incidental improvements: - pr_name now complains about too-long file names - pr_name will now choose to use ~ over cwd-relative naming if the resulting name is shorter The apology: static buffers are evil (wasteful and error-prone) and should be eliminated. Unfortunately, this would require changes to every use of pr_name. Revision 1.368 1996/08/19 21:05:09 hugh 4.16.0.18: make dbx a minor mode (simplify, generalize) Revision 1.367 1996/07/11 05:09:06 hugh 4.16.0.17: make jjove.rc use version.h Revision 1.366 1996/07/07 22:18:22 hugh 4.16.0.16: fix bugs in commandline arg processing There were several odd cases where the current buffer would not be tied to the current window. >> As a minor enhancement, the alternat buffer will now be set to the last file not assigned a window. Revision 1.365 1996/07/02 00:15:13 hugh 4.16.0.15: fix subtle screen maintenance bug Without this, filename/command/etc completion would get truncated when process windows were updated. Revision 1.364 1996/06/16 15:56:45 hugh 4.16.0.14: fix MatchDir usage Revision 1.363 1996/06/13 06:19:29 hugh 4.16.0.13: rename basename => jbasename (name taken by SVR4) Revision 1.362 1996/05/23 03:08:41 hugh 4.16.0.12: fix nits in teach-jove Revision 1.361 1996/05/20 01:57:36 hugh 4.16.0.11: in Makefile: use LDCC in appropriate places Revision 1.360 1996/05/09 02:40:21 hugh 4.16.0.10: improve READMEs for DOS and WIN32 Revision 1.359 1996/05/08 18:15:13 hugh 4.16.0.9: support ConvexOS, istrip problems and all Revision 1.358 1996/05/08 03:44:25 hugh 4.16.0.8: restore Zortech compatibility Zortech 3.0 doesn't define EINTR; I don't think any MSDOS runtime would generate it for a write(). (The code already reflects this understanding for read().) Revision 1.357 1996/05/07 04:28:18 hugh 4.16.0.7: fix backup-files code for MSFILESYSTEM Revision 1.356 1996/04/22 06:49:45 hugh 4.16.0.6: remove unwarranted bug warning The bug was caused by a virus on the test system. Revision 1.355 1996/03/30 00:59:29 hugh 4.16.0.5: fix justification nits Revision 1.354 1996/03/21 19:14:48 hugh 4.16.0.4: improve concatenation of pathname components This change is needed to avoid accidental references to network files under some Microsoft systems. Took this oportunity to delete some obliquely related nonsense code in scandir.c. Revision 1.353 1996/03/21 17:02:10 hugh 4.16.0.3: correct case of OS in Makefile.msc Revision 1.352 1996/03/20 08:00:59 hugh 4.16.0.2: Fix strange font usages in xjove (Charles) Revision 1.351 1996/03/20 07:40:19 hugh 4.16.0.1: fix and use lint Makefile target commit 702706df4025029f580bc2962b9fc407bd2ddc58 version 4.16 released on ftp.cs.toronto.edu on 1996/03/30 PC, Win32 and Un*x-specific code factored into ibmpcdos.c, win32.c and unix.c respectively. Retested on lots of platforms, this was the last major Jove release formally tested by all jove developers. The release announcement/README was: 4.16 has been widely ported, it features LOTS of changes, fixes, improvements. Among other things, it should compile and work out of the box on most widely used Un*x and Posix variants, including AIX, BSDI, DGUX, HP-UX, Irix, Linux, OSF/1, QNX, SCO, Solaris, SunOS, SVR4, Ultrix. Considerable work has gone into making it easier to port (functional ifdefs rather than system specific ones). It now has simple mouse support under xterms, the documentation has been re-worked. This version of Jove also works under DOS, Win32 and the Mac with almost the same functionality as the Un*x version. commit 6cf695fea5f3980fe41a2ce423122ef376446709 version 4.16beta released on ftp.cs.toronto.edu on 1994/11/23 many fixes, more portability, xjove, xterm mouse handling and jovetool appear courtesy Charles Lindsey. doc/jove.[123] become doc/intro.nr doc/jove.[45] become doc/cmds.nr doc/system.rc becomes doc/jove.rc* Readme.* become README.* Makefile.dos becomes Makefile.{bcc,msc,wat,zor} for various PC compilers tune.template is gone, those defines are set in Makefile commit aab347b0f618ecd19dce73efbe2ea44101cae20f version 4.14.10 released on ftp.cs.toronto.edu on 1993/06/19 Many bugfixes from Hugh Redelmeier who took on primary maintenance and Mark Moraes who did much of the portability revamp and testing on a wide range of Un*x variants available at UToronto at the time (MIPS, SGI Irix, SUNOS[34], BSD, Ultrix). sysdep.h makes an appearance and the ifdef maze is now feature-based rather than ad-hoc. Much de-lintingh as a side-effect of testing with full-warnings on as many nit-picky compilers as possible. a few files renames appear as delete+new because of conversion: in particular, version.c now becomes version.h commit 44a942827c9c2766d161668389d3edaea1a9dd8a revision 4.14 date: 1989/10/17 10:20:31; author: jpayne; state: Exp; lines: +1 -1 Quick check-in for hugh and mark. commit ba38dd8858356ade98ff351f46bdc0d7690ea5d4 revision 4.12 date: 1989/02/13 09:46:15; author: jpayne; state: Exp; lines: +3 -1 Ansi C-ified. Also minor addition to scroll-region-{left,right} now uses numeric argument if one is supplied to figure out how far to indent. commit 1028d6ba06536d582d289ab009748309853cfc59 revision 4.11 date: 1989/01/18 15:11:10; author: jpayne; state: Exp; lines: +1 -1 new c-mode, shift-region-{left,right}, dbx-mode, deleted find-files-read-only variable, uses getpwent to look up home directories. commit ad842c38e45fbd09ba81e8cda51f73f92e8283c7 revision 4.10 date: 1988/10/21 14:22:54; author: jpayne; state: Exp; lines: +1 -1 added function proto-typing {f,s,}printf => {f,s,}writef numeric argument functions are macros now real keymaps now added RE_block structure for RE's. new mail checking algorithm better handling of modeline with SG's changed meaning of %e in modeline deleted ansi-codes read-only mode new pipeprocs mechanism cleaned up white space added C-X 4 C-T commit a392c927e39e298e5298fccac90b752ac30dea4f revision 4.9 date: 1988/03/14 19:13:38; author: jpayne; state: Exp; lines: +7 -7 -runs on the macintosh! -new variables display-bad-filenames, scroll-all-lines, error-format-string -new commands scroll-left, scroll-right, shell-command-no-buffer shell-command-with-typeout -deleted parse-special-errors (see error-format-string) -disable redisplay during screen Typeout -%w in modeline displays '>' if window is scrolled -unbind-key really works -tabs are inserted if at end of line in lisp mode -jove -tTagname works -jove windows are resized in proportion to the system window resize commit 08e9e8903b0862b8f0c353fdb1fa6e0c62361a98 revision 4.8.1.1 date: 1988/01/18 13:12:48; author: jpayne; state: Exp; lines: +1 -1 Version 4.8b of JOVE, to be combined with the changes of Karl and Tim for PC jove. See 4.9 entry for diff listing. commit d547430ed201f1a5e614cf1359c55f7616f9a70c revision 4.8 date: 1987/10/16 15:53:08; author: jpayne; state: Exp; lines: +1 -1 branches: 4.8.1; New text macros!!! IBM PC/MSDOS compatible!!! commit 002e27a0a9fbe902043dd9a2b1bb0c8f4e392283 revision 4.7 date: 1987/07/16 11:11:47; author: jpayne; state: Exp; lines: +7 -9 -Changed arg count. -Added environment variable support. -Changed CTL() macro to conform to ansi C. -Changed file commands to use path relative form to speed up accesses. -Reverted to old fill-paragraph. -Added BL and NL (with stripped padding) termcap support. -Added %p on modeline (display process status). -Changed buffer-position. -Fixed fmt.c for BSD4.3 ctime(); cleaned up code. -Combinded ^U and ESC correctly. -find_tag uses binary search. -Changed rec file format. -Fixed load average for SUNS. commit 64dff0fa821665f05019f064b187313f34ea9343 revision 4.6.1.5 date: 1987/04/18 12:22:56; author: jpayne; state: Exp; lines: +1 -1 -kill buffer doesn't delete any windows -fixed simple recursive keymap displaying bug -buffer-position doesn't die on 0 length buffers -added goto-window-with-buffer -fixed .joverc weirdness with 'P' vs. 'p', etc. -fixed iproc's dieing - now insert message AT END OF BUFFER -combined ^U and ESC # at last -fixed dosub \\\ bug -find tag works in wrap-search mode -fixed structure name conflicts -SysV vs. SysVRel2 commit 669c46e98fe44a691cbfcf58ecb410673c45acbe revision 4.6.1.4 date: 1987/01/21 19:06:27; author: jpayne; state: Exp; lines: +1 -1 %m is changed on mode-line changed DoJustify to really use the right-margin commit b819657159a742fd3f9e6968c27f5ce812a5a7b4 revision 4.6.1.3 date: 1986/12/22 14:29:26; author: jpayne; state: Exp; lines: +1 -1 Few bug fixes. commit fa64b7627c24a9050cba5c044fb98c75e19c8624 revision 4.6.1.2 date: 1986/09/24 10:50:01; author: jpayne; state: Exp; lines: +7 -9 This is the version sent out to mod.sources. Contains a few minor differences from the previous version, some of Hugh's bug fixes, couple new variables, etc. commit f0263179fc74ce8a8c7f939aa51e204fdb8f9dc5 revision 4.6.1.1 date: 1986/08/26 19:20:49; author: jpayne; state: Exp; lines: +1 -1 -recover is no longer a top level command; use jove -r instead. -the jove tmp file is created upon demand now. -new variable type V_FILENAME, and new variable "tmp-file-path." -fixed typing C-V before initial file read is complete. -new command "add-lisp-special." -yes/no questions don't wait for return. -chk_mtime is called whenever a file is reselected. -the NORMC char code is followed by a # which is the # of NORMC's. commit d225bd8f9c48a5ca79ada5cc68aaf4921581e177 revision 4.6 date: 1986/07/24 12:57:08; author: jpayne; state: Exp; lines: +1 -1 branches: 4.6.1; Fixed serious text munging bug (getblock() in IO.C). Made case independent search as fast as normal search. Fixed bug that caused JOVE to keep trying to write files even after an error. ESC 1 2 3 and ESC 1 ESC 2 ESC 3 do the same thing now. So meta-key really works. Added some lisp commands. commit f4ae519828d94f99bdb58ab304be6d1bf9e6871c revision 4.5 date: 1986/03/27 20:40:14; author: payne; state: Exp; lines: +1 -1 This version has the new tmp file format. Lines are don't go over block bounderies anymore to make things faster. The search code is lots faster and the paren matching code is more accurate and MUCH faster. commit ecfd7acb0074e7efd778999306ad3e27c0ca86ed revision 4.4.2.1 locked by: payne; date: 1986/03/18 00:08:32; author: payne; state: Exp; lines: +1 -1 This version has new paren flash code, several bug fixes. commit 660c8ad206ba229a7988b804fcc8f066e34be601 no longer relies on sprintf returning char* revision 4.4.2.0 date: 1986/02/28 17:00:49; author: payne; state: Exp; lines: +1 -1 This version has a fix for the sun problem. On suns the C library version of malloc is used instead of the pdp11 version. commit ef3be7a4243bd913aeca7614d3a4ab2b45c3997f tiny change to a complaint revision 4.4.1.2 date: 1986/02/18 23:06:57; author: payne; state: Exp; lines: +1 -1 commit 194b87c042a1d87e92068292d15f60cc05678984 key bindings and setmaps revision 4.4.1.2 date: 1986/02/18 23:06:57; author: payne; state: Exp; lines: +1 -1 commit bd817796ebb8d403a2ed4fa54b3157bd2cb3f78d 4.4.1.1 seems the rest of the fixes described in the 4.4 log message revision 4.4 date: 1986/02/13 02:09:39; author: payne; state: Exp; lines: +1 -1 branches: 4.4.1; 4.4.2; Has file I/O enhancements. Basically rewritten from scratch. Some bug fixes. Code to automatically convert macros in the old format to the new format. ---------------------------- revision 4.4.1.1 date: 1986/02/14 20:09:52; author: payne; state: Exp; lines: +1 -1 New version 4.4.1.1 ---------------------------- commit 6011c1bbe8dc2472e907bd5b418115acf77d3898 version.c updated to 4.3.1.1 but fixes seem to match branch 4.4 revision 4.4 date: 1986/02/13 02:09:39; author: payne; state: Exp; lines: +1 -1 branches: 4.4.1; 4.4.2; Has file I/O enhancements. Basically rewritten from scratch. Some bug fixes. Code to automatically convert macros in the old format to the new format. commit 0ae3c568851d6990665f5e1dbdbea67a63374c0c JOVE is Jonathan's Own Version of EMACS Written by Jonathan Payne circa 1982, originally at the Lincoln-Sudbury Regional High School, MA, USA. This version history (from an RCS archive) starts in 1986 when Jonathan was finishing his CS undergrad at University of Rochester. Version 4.3 was included in the BSD 4.3 distribution (the hardcopy manual is part of the User Software Distribution; USD17) Supposedly, an earlier version was included in a 1984 USENIX software tape along with Jay Fenlason's HACK. A later version 4.6.1.4 was posted to comp.sources.unix (mod.sources at the time?) in late-1986 or early-1987. Version 4.8 was ported to the IBM PC. Version 4.12 was available from cs.rochester.edu for a while. Hugh Redelmeier and Mark Moraes took over releases in 1989, circa jove 4.14, which eventually resulted in a long-lived 4.16 release in 1996. Many subsequent dot releases were never released formally, though they were available from ftp.cs.toronto.edu:/pub/hugh/ and some made their way into various Linux/BSD distributions. This git history reconstructed by Mark Moraes from an RCS archive that Jonathan sent and starts with: revision 4.3 date: 1986/02/13 01:54:59; author: payne; state: Exp; As distributed with 4.3 BSD. https://groups.google.com/forum/#!msg/net.unix-wizards/9bPrVuHYlo8/s5Wm4N2-6KQJ (likely from Henry Spencer's archives, judging by the utzoo path entry) Message-ID: Newsgroups: net.unix-wizards Path: utzoo!decvax!decwrl!sun!megatest!fortune!hpda!hplabs!sri-unix!jpayne@BBN-UNIX From: jpayne@BBN-UNIX Date: Tue Apr 19 03:33:03 1983 Subject: Weird file names and ... Posted: Mon Apr 4 07:14:46 1983 Received: Tue Apr 19 03:33:03 1983 At Lincoln-Sudbury High School, here in massachusetts, we are running 2.81bsd UNIX. My friends and I (high school students/graduates), recently had a lot of fun deleting a file with the character \240 in it. The file name was so weird that ls couldn't even stat the file. ... Jonathan Payne P.S. Anyone out there interested in an EMACS style editor for the PDP11. Unfortunately it doesn't fit on non-split ID machines. Some of its features include, multiple buffers and windows (as many that can fit in both cases), key binding (similar to Gosling's), output from shell commands to buffer, filter-region (so you can sort your files or beatify your C), parse C/LINT/fgrep type error messages, spell-buffer (like error parsing), MACRO in the singular (haven't gotten around to making it more general). I almost forgot to mention that it has optimized redisplay (NOT as good as Gosling's, but close), works on any reasonable display terminal (TERMCAP), has super/hyper/meta optimized cursor motion (I believe it does the best thing EVERY time with good response time) and aborts redisplay if you support the right ioctl. It limitations are 512 characters per line (it stores the file on the disk in a way similar to that of ed(1) and VI), about a total of 6500 lines at any time buffers. I believe it hardly ever crashes i.e. it hasn't happened to anyone yet. There is 10k of I space left and is, in my opinion, well written and easy to read, so you can modify it easily. It's called JOVE which stands for Jonathan's Own Version of Emacs... If you are interested you can reach me at jpayne@bbng or jpayne@bbn-unix Be seeing you... Newsgroups: comp.emacs,comp.sys.mac.programmer.tools,comp.unix.bsd.freebsd.announce Subject: Announcing JOVE version 4.16 (EMACS-like text editor) Keywords: EMACS, editor, JOVE References: <1996Apr13.021821.26744@jarvis.cs.toronto.edu> Jove (Jonathan's Own Version of Emacs) is an Emacs-like editor without Lisp. It is comfortable to use, small, fast and portable. It has been available for about a dozen years, and has been included in several BSD releases. 4.16 (1996 Mar 19) is the latest released version. The previous release was 4.16beta (1994 Nov 23) and before that, 4.14.10. 4.16 has been widely ported, it features LOTS of changes, fixes, improvements. Among other things, it should compile and work out of the box on most widely used Un*x and Posix variants, including AIX, BSDI, DGUX, HP-UX, Irix, Linux, OSF/1, QNX, SCO, Solaris, SunOS, SVR4, Ultrix. Considerable work has gone into making it easier to port (functional ifdefs rather than system specific ones). It now has simple mouse support under xterms, the documentation has been re-worked. This version of Jove also works under MSDOS, Win32 (Windows NT and Windows 95) and the Macintosh with almost the same functionality as the Un*x version. The official source location for Jove is github.com/jonmacs/jove (newest code in the moraes branch) The ftp location for Jove is ftp.cs.toronto.edu:/pub/moraes/jove/ The file jove.README describes the contents of this directory. Source is provided for all platforms, as are pre-compiled versions for MSDOS, MSWin32, and the Macintosh. Jove is supported by a group of users. We can be reached on the github.com/jonmacs/jove bug tracker. We welcome bug reports. We also welcome reports on porting Jove. We are even interested in suggestions for new features, but we are conservative in adopting them. Mark Moraes, Hugh Redelmeier (for Jovehacks) jove-4.17.5.5/LICENSE000066400000000000000000000004141501102521500137120ustar00rootroot00000000000000This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is provided by Jonathan and Jovehacks without charge and without warranty. You may copy, modify, and/or distribute JOVE, provided that this notice is included in all the source files and documentation. jove-4.17.5.5/Makefile000066400000000000000000000761431501102521500143610ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## # SHELL for this Makefile (csh won't work!) SHELL = /bin/sh # If the system has no cmp, not a big deal, minor optimization to prevent # a few needless rebuilds CMP = cmp # JOVEHOME is the directory in which pieces of JOVE are kept. It is only used # in the default definitions of JSHAREDIR, JLIBDIR, JBINDIR, and JMANDIR. # JSHAREDIR is for online documentation, and the distributed standard system-wide # jove.rc file with some common # JLIBDIR is for the PORTSRV and RECOVER programs. # JBINDIR is where to put the executables JOVE and TEACHJOVE. # XEXT is the extension for executables (empty for UNIX; .exe for CYGWIN) # JMANDIR is where the manual pages go for JOVE, RECOVER and TEACHJOVE. # MANEXT is the extension for the man pages, e.g., jove.1 or jove.l or jove.m. # Must not be "nr". # JTEACHBASE is the basename of the installed teach-jove tutorial file, # which will be teachjov.txt on MSFILESYSTEM (and the zip file), # but teach-jove on Unix/Linux installs. # # If they don't exist, this makefile will try to create all *DIR directories # (prefixed with $DESTDIR, as most packaging systems desire; DESTDIR must # end with a slash) All others must already exist. # # Hack for relocatable installs: set JSHAREDIR and JLIBDIR and JBINDIR to relative # paths, set JOVEHOME to an empty directory, and DESTDIR to the install # destination with a trailing slash (or to just /, and copy the jove and recover # binaries, and the doc subdirectory by hand) JOVEHOME = /usr/local JSHAREDIR = $(JOVEHOME)/share/jove DSHAREDIR = $(DESTDIR)$(JSHAREDIR) JLIBDIR = $(JOVEHOME)/lib/jove DLIBDIR = $(DESTDIR)$(JLIBDIR) JBINDIR = $(JOVEHOME)/bin DBINDIR = $(DESTDIR)$(JBINDIR) XEXT= JMANDIR = $(JOVEHOME)/man/man$(MANEXT) DMANDIR = $(DESTDIR)$(JMANDIR) MANEXT = 1 JTEACHBASE = teach-jove TEACHDOC = $(DSHAREDIR)/$(JTEACHBASE) JDOCDIR = $(JOVEHOME)/share/doc/jove DDOCDIR = $(DESTDIR)$(JDOCDIR) REFDOC = $(DDOCDIR)/jove.qref EGRC = $(DDOCDIR)/example.rc # Install permission for SHAREDIR, LIBDIR, BINDIR DPERM = 755 # JTMPDIR is where the tmp files get stored, usually /tmp, /var/tmp, or # /usr/tmp. If you wish to be able to recover buffers after a system # crash, this needs to be a directory that isn't cleaned out on reboot. # You would probably want to clean out that directory periodically with # /etc/cron. # JRECDIR is the directory in which RECOVER looks for JOVE's tempfiles # (in case the system startup salvages tempfiles by moving them, # which is probably a good idea). JETCDIR = /etc/jove DETCDIR = $(DESTDIR)$(JETCDIR) JTMPDIR = /var/tmp JRECDIR = /var/lib/jove/preserve DRECDIR = $(DESTDIR)$(JRECDIR) # Install permission for DRECDIR RECPERM = 1777 # place to copy source tarball for rpmbuild RPMHOME = $(HOME)/rpmbuild/SOURCES # DFLTSHELL is the default shell invoked by JOVE. DFLTSHELL = /bin/sh # The install commands of BSD and System V differ in unpleasant ways: # -c: copy (BSD); -c dir: destination directory (SysV) # -s: strip (BSD); -s: suppress messages (SysV) # Also, the destination specification is very different. # The result is that the System V install command must not be used. # If you know that /bin/install is the BSD program, you can use it. # "cp" will work reasonably well, but be aware that any links continue # referencing the old file with new contents. INSTALLFLAGS = # -g bin -o root # XINSTALL to install executable files, prefer install since it is independent # of user umask # Linux/modern BSD/CYGWIN XINSTALL=install $(INSTALLFLAGS) -m 755 TINSTALL=install $(INSTALLFLAGS) -m 444 # old mkdir (4BSD and older Unix) did not have -p option, so will # need to set MKDIRP=mkdir and create top dirs by hand (or write a script # to emulate mkdir -p; 4BSD has basename but not dirname) MKDIRP=mkdir -p # WHICH shoiuld be a command that succeeds if the argument is found in the path # WHICH=which # for BSD WHICH=type # for sufficiently POSIX shells, not sure if Research Unix has this # These should all just be right if the above ones are. # You will confuse JOVE if you move anything from LIBDIR or SHAREDIR. JOVE = $(DBINDIR)/jove$(XEXT) TEACHJOVE = $(DBINDIR)/teachjove RECOVER = $(DLIBDIR)/recover$(XEXT) PORTSRV = $(DLIBDIR)/portsrv$(XEXT) JOVERC = $(DSHAREDIR)/jove.rc TERMSDIR = $(DSHAREDIR) CMDSDOC = $(DSHAREDIR)/cmds.txt JOVEM = $(DMANDIR)/jove.$(MANEXT) TEACHJOVEM = $(DMANDIR)/teachjove.$(MANEXT) XJOVEM = $(DMANDIR)/xjove.$(MANEXT) JOVETOOLM = $(DMANDIR)/jovetool.$(MANEXT) # We set CFLAGS to SYSDEFS and OPTFLAGS, so we can set # the definitions in SYSDEFS (needed for the local compiler # of keys.c, and the target compiler for the rest, in order # to make this work for cross-compilation) # SYSDEFS: specify system characteristics to the C preprocessor using -D options # The default is the system uname, which should work for many # popular modern systems like Linux, *BSD, OpenIndiana. # If sysdep.h does not define a block for your system, or uname produces # an illegal symbol on your platform (Cygwin, GNU Hurd), use jmake # or see README, sysdep.h, sysdep.txt. # XXX Among modern systems, FreeBSD does not put CPPFLAGS in the default # .c.o make build rules, so we put it in SYSDEFS, which we then add # to CFLAGS. This means the contents of CPPFLAGS will likely # appear twice in cc invocations on non-FreeBSD (i.e. OpenBSD, NetBSD, Linux) # so best to avoid setting it (the default value is empty anyway) SYSDEFS = -D`uname` -DJTC $(CPPFLAGS) # OPTFLAGS: compiler flags that are passed to both the compiling & linking steps # e.g. -g for debugging, -O for optimization. OPTFLAGS = -O # CFLAGS (i.e compile flags for the target compiler) are OPTFLAGS and SYSDEFS, # DO NOT OVERRIDE CFLAGS = $(OPTFLAGS) $(SYSDEFS) # For making dependencies under BSD systems DEPENDFLAG = -M # or, using the official Sun ANSI C compiler # DEPENDFLAG = -xM # Flags for Libraries to provide termcap and pty functions. # Some modern open-source systems have dropped termcap, or ship it # as part of the ncurses or tinfo packages. # For systems without dynamic libraries, termcap or terminfo are smaller, # and preferable to the bulkier curses library. # Jove comes with a simplified termcap substitute that only supports # ANSI X.3/VT[1-5]xx or compatible terminal emulators like xterm, rxvt, etc, # which is almost certainly all that is necessary on modern machines. # To use it, define -DJTC and leave TERMCAPLIB unset TERMCAPLIB = # for compatibility with old packagers, deprecated, use LDLIBS EXTRALIBS = -lutil # for compatibility with old packagers, deprecated, use LDLIBS LDLIBS = $(TERMCAPLIB) $(EXTRALIBS) # linker flags (LDFLAGS) not needed for most systems LDFLAGS = # LDCC can be used for link-time alternatives to CC. Also useful # for purify or similar link-time processing. LDCC = $(CC) # For cross compiling Jove, set CC to the cross compiler, and LOCALCC # to the local C compiler. LOCALCC will be used for compiling setmaps, # which is run as part of the compilation to generate the keymaps. # Set LOCALCFLAGS and LOCALLDFLAGS to anything extra (other than SYSDEFS, # which must be the same for local and cross, so that setmaps generates # the correct key bindings), though no optimization or debug or special # flags are usually needed (other than Xenix?!), since setmaps is # run just once, so use whatever compiles fastest. LOCALCC = $(CC) LOCALCFLAGS = # nothing really needed for setmaps LOCALLDFLAGS = $(LDFLAGS) LOCALEXTRALIBS = # nothing really needed for setmaps LOCALEXT = # default is a Un*x-style machine, not Windows # Objects are grouped into overlays for the benefit of (at least) 2.xBSD. BASESEG = commands.o keys.o argcount.o ask.o buf.o jctype.o delete.o \ disp.o insert.o io.o jove.o marks.o misc.o re.o \ screen.o termcap.o unix.o util.o vars.o list.o keymaps.o \ mouse.o jtc.o OVLAY1 = abbrev.o rec.o para.o fmt.o OVLAY2 = c.o wind.o fp.o move.o OVLAY3 = extend.o macros.o OVLAY4 = iproc.o reapp.o OVLAY5 = proc.o scandir.o term.o case.o OBJECTS = $(BASESEG) $(OVLAY1) $(OVLAY2) $(OVLAY3) $(OVLAY4) $(OVLAY5) # win32.o when cross-compiling with mingw for Win32 EXTRAOBJS = # jjove.coff for cross-compiling with mingw for Win32 ICON = WINDRES = windres # probably needs i686-w64-mingw32- prefix or similar ZIP=zip ZIPEXT=zip ZIPOPTS=-q -k # common options for both binary and code files ZIPTXTOPT=-l -r # options for recursively adding code files TAR=tar # These NROFF, TROFF and TROFFPOST settings work with groff. # Classic Unix and derivatives used to have ditroff, for which use: # NROFF = nroff # TROFF = troff # TDEV = ps or TDEV = psc # TROFFPOST = |/usr/lib/lp/postscript/dpost - # or TROFFPOST = |psc NROFF = nroff TROFF = troff TDEV = pdf TROFFPOST = |gro$(TDEV) # installed man pages MANUALS = $(JOVEM) $(TEACHJOVEM) C_SRC = commands.c commands.tab abbrev.c argcount.c ask.c buf.c c.c case.c jctype.c \ delete.c disp.c extend.c fp.c fmt.c insert.c io.c iproc.c \ jove.c jtc.c list.c macros.c marks.c misc.c move.c para.c \ proc.c re.c reapp.c rec.c scandir.c screen.c term.c termcap.c unix.c \ util.c vars.c vars.tab wind.c msgetch.c mac.c keymaps.c ibmpcdos.c \ mouse.c win32.c SOURCES = $(C_SRC) portsrv.c recover.c setmaps.c HEADERS = abbrev.h argcount.h ask.h buf.h c.h case.h chars.h commands.h \ jctype.h dataobj.h delete.h disp.h extend.h externs.h \ fmt.h fp.h insert.h io.h iproc.h jove.h \ keymaps.h list.h mac.h macros.h marks.h \ misc.h mouse.h move.h para.h proc.h \ re.h reapp.h rec.h recover.h scandir.h screen.h \ select.h sysdep.h sysprocs.h temp.h term.h ttystate.h \ tune.h util.h vars.h version.h wind.h DOCTERMS = doc/jove.rc.sun doc/keychart.sun \ doc/jove.rc.sun-cmd doc/keychart.sun-cmd \ doc/jove.rc.vt100 doc/keychart.vt100 \ doc/jove.rc.wyse doc/keychart.wyse \ doc/jove.rc.xterm doc/keychart.xterm \ doc/jove.rc.xterm-256color doc/keychart.xterm-256color \ doc/jove.rc.z29 doc/keychart.z29 \ doc/jove.rc.3022 doc/keychart.3022 \ doc/XTermresource # formatted docs, we ship these in the distrib to avoid groff dependency # and for non-Unix/Linux platforms. NOTE: These will be removed by clobber. # Also note that jove.man.* require the ms macros # (tmac.s or s.tmac) which many systems do not install with base groff. # By default, generate & install doc/jove.man.$(TDEV) FREFDOCS = doc/jove.man.txt doc/jove.man.$(TDEV) FDOCS = doc/cmds.txt $(FREFDOCS) # files we generate that we also ship in distrib for platforms sans sed # NOTE: these will be removed by clobber. GEN = doc/jove.rc doc/jove.$(MANEXT) \ doc/teachjove.$(MANEXT) doc/jovetool.$(MANEXT) DOSDOCS = doc/README doc/teach-jove doc/jove.qref doc/example.rc doc/jem.txt \ doc/jove.txt DOCS = doc/intro.nr doc/cmds.macros.nr doc/cmds.nr doc/contents.nr \ doc/jove.nr doc/teachjove.nr doc/xjove.nr doc/jovetool.nr \ doc/jove.rc.in $(DOSDOCS) $(DOCTERMS) $(FDOCS) $(GEN) MISC = Makefile Makefile.msc Makefile.wat \ README README.dos README.win ChangeLog LICENSE \ sysdep.txt tune.txt style.txt jmake.sh \ testbuild.sh testmailer.sh SUPPORT = recover.c setmaps.c portsrv.c keys.txt \ menumaps.txt mjovers.Hqx jjove.ico jjove.rc teachjove BACKUPS = $(HEADERS) $(C_SRC) $(SUPPORT) $(MISC) # all: default target. # Builds everything that "install" needs. all: jjove$(XEXT) recover$(XEXT) portsrv$(XEXT) $(FDOCS) $(GEN) jjove$(XEXT): $(OBJECTS) $(EXTRAOBJS) $(ICON) $(LDCC) $(LDFLAGS) $(CFLAGS) -o jjove$(XEXT) $(OBJECTS) $(EXTRAOBJS) $(ICON) $(LDLIBS) @-size jjove$(XEXT) # For mingw icon jjove.coff: jjove.rc version.h $(WINDRES) -r jjove.rc -fo jjove.coff # For 2.xBSD: link jove as a set of overlays. Not tested recently. ovjove: $(OBJECTS) ld $(LDFLAGS) $(OPTFLAGS) -X /lib/crt0.o \ -Z $(OVLAY1) \ -Z $(OVLAY2) \ -Z $(OVLAY3) \ -Z $(OVLAY4) \ -Z $(OVLAY5) \ -Y $(BASESEG) \ -o jjove$(XEXT) $(EXTRALIBS) $(TERMCAPLIB) -lc @-size jjove$(XEXT) # portsrv is only needed if IPROCS are implemented using PIPEPROCS # (modern systems use PTYPROCS). To install portsrv, set # PORTSRVINST=1 PORTSRVINST= portsrv$(XEXT): portsrv.o $(LDCC) $(LDFLAGS) $(CFLAGS) -o portsrv$(XEXT) portsrv.o $(LDLIBS) recover$(XEXT): recover.o $(LDCC) $(LDFLAGS) $(CFLAGS) -o recover$(XEXT) recover.o $(LDLIBS) # no need to optimize setmaps since it is run once during build, so faster # compile is better than faster executable (also urban legend that # optimization produced bad code for setmaps!) setmaps$(LOCALEXT): setmaps.o $(LOCALCC) $(LOCALLDFLAGS) $(LOCALCFLAGS) -o setmaps$(LOCALEXT) setmaps.o $(LOCALEXTRALIBS) # Critical that setmaps be compiled with same SYSDEFS setmaps.o: setmaps.c $(LOCALCC) $(LOCALCFLAGS) $(SYSDEFS) -c setmaps.c # create a temporary directory to hold some temporary intermediate files that the # Makefile generates, as a precaution against security hole via races (mktemp would be # better, but we try to keep this Makefile working on old Unix, pre-POSIX, sigh) TDIR=$(JTMPDIR)/jbuild$$$$ TFILE=$(TDIR)/temp keys.c: setmaps$(LOCALEXT) keys.txt Makefile .ALWAYS @mkdir $(TDIR) && \ ./setmaps$(LOCALEXT) < keys.txt > $(TFILE) && \ echo 'char JoveCompiled[sizeof(JoveCompiled)] = "'$(CC) $(CFLAGS)'";' >> $(TFILE) && \ echo 'char JoveLinked[sizeof(JoveLinked)] = "'$(LDCC) $(LDFLAGS) $(CFLAGS) $(EXTRAOBJS) $(LDLIBS)'";' >> $(TFILE) && \ if $(CMP) -s $(TFILE) keys.c 2> /dev/null; then rm $(TFILE); else rm -f keys.c; mv $(TFILE) keys.c; fi; rmdir $(TDIR) keys.o: keys.c tune.h sysdep.h jove.h keymaps.h dataobj.h commands.h .ALWAYS: # BSD sed cannot handle \t, and having tabs in the whitespace feels fragile. .version: .ALWAYS @mkdir $(TDIR) && \ sed -n 's/# *define *jversion *"\([0-9\\.]*\)".*/\1/p' version.h > $(TFILE); \ if $(CMP) -s $(TFILE) .version 2> /dev/null; then rm $(TFILE); else rm -f .version; mv $(TFILE) .version; fi; rmdir $(TDIR) jove.spec: .version @mkdir $(TDIR) && \ v=`sed 's/_.*//' .version`; sed "s,__VERSION__,$$v,g" pkg/rpm/jspec.in > $(TFILE); \ if $(CMP) -s $(TFILE) jove.spec 2> /dev/null; then rm $(TFILE); else rm -f jove.spec; mv $(TFILE) jove.spec; fi; rmdir $(TDIR) paths.h: .ALWAYS @mkdir $(TDIR) && \ (echo "/* Changes should be made in Makefile, not to this file! */" ; \ echo ""; \ echo \#define TMPDIR \"$(JTMPDIR)\"; \ echo \#define RECDIR \"$(JRECDIR)\"; \ echo \#define LIBDIR \"$(JLIBDIR)\"; \ echo \#define SHAREDIR \"$(JSHAREDIR)\"; \ echo \#define TEACHJOVE \"$(JTEACHBASE)\"; \ echo \#define DFLTSHELL \"$(DFLTSHELL)\";) > $(TFILE); \ if $(CMP) -s $(TFILE) paths.h 2> /dev/null; then rm $(TFILE); else rm -f paths.h; mv $(TFILE) paths.h; fi; rmdir $(TDIR) makexjove: ( cd xjove ; make CC="$(CC)" OPTFLAGS="$(OPTFLAGS)" SYSDEFS="$(SYSDEFS)" $(TOOLMAKEEXTRAS) xjove ) installxjove: $(XJOVEM) ( cd xjove ; make CC="$(CC)" OPTFLAGS="$(OPTFLAGS)" SYSDEFS="$(SYSDEFS)" XINSTALL="$(XINSTALL)" BINDIR="$(DBINDIR)" INSTALLFLAGS="$(INSTALLFLAGS)" $(TOOLMAKEEXTRAS) installxjove ) makejovetool: ( cd xjove ; make CC="$(CC)" OPTFLAGS="$(OPTFLAGS)" SYSDEFS="$(SYSDEFS)" DEFINES=-DSUNVIEW $(TOOLMAKEEXTRAS) jovetool ) installjovetool: $(JOVETOOLM) ( cd xjove ; make CC="$(CC)" OPTFLAGS="$(OPTFLAGS)" SYSDEFS="$(SYSDEFS)" DEFINES=-DSUNVIEW XINSTALL="$(XINSTALL)" BINDIR="$(DBINDIR)" INSTALLFLAGS="$(INSTALLFLAGS)" $(TOOLMAKEEXTRAS) installjovetool ) # Note: everything needed by "install" should be built by "all". # Thus, if "all" is done first, "install" can be invoked with # JOVEHOME pointing at a playpen where files are to be marshalled. # This property is fragile. install: $(DRECDIR) $(DETCDIR) $(DDOCDIR) $(CMDSDOC) $(TEACHDOC) $(JOVERC) \ $(PORTSRV) $(RECOVER) $(JOVE) $(TEACHJOVE) $(REFDOC) $(MANUALS) @echo See the README about changes to /etc/rc or /etc/rc.local @echo so that the system recovers jove files on reboot after a crash $(DBINDIR):: if test ! -d $(DBINDIR); then $(MKDIRP) $(DBINDIR) && chmod $(DPERM) $(DBINDIR); else :; fi $(DLIBDIR):: if test ! -d $(DLIBDIR); then $(MKDIRP) $(DLIBDIR) && chmod $(DPERM) $(DLIBDIR); else :; fi $(DSHAREDIR):: if test ! -d $(DSHAREDIR); then $(MKDIRP) $(DSHAREDIR) && chmod $(DPERM) $(DSHAREDIR); else :; fi $(DDOCDIR):: if test ! -d $(DDOCDIR); then $(MKDIRP) $(DDOCDIR) && chmod $(DPERM) $(DDOCDIR); else :; fi $(DETCDIR):: -if test ! -d $(DETCDIR); then $(MKDIRP) $(DETCDIR) && chmod $(DPERM) $(DETCDIR); fi $(DMANDIR):: if test ! -d $(DMANDIR); then $(MKDIRP) $(DMANDIR) && chmod $(DPERM) $(DMANDIR); else :; fi $(DRECDIR):: -if test ! -d $(DRECDIR); then $(MKDIRP) $(DRECDIR) && chmod $(RECPERM) $(DRECDIR); fi # first run of rpmbuild will mkdir other sibling directories in RPMHOME, but # we need this before we run rpmbuild, so RPMHOME might not even exist. $(RPMHOME):: if test ! -d $(RPMHOME); then mkdir -p $(RPMHOME) && chmod $(DPERM) $(RPMHOME); fi doc/cmds.txt: doc/cmds.macros.nr doc/cmds.nr @mkdir $(TDIR) && \ LANG=C $(NROFF) doc/cmds.macros.nr doc/cmds.nr > $(TFILE); \ if $(CMP) -s $(TFILE) doc/cmds.txt 2> /dev/null; then rm $(TFILE); else rm -f doc/cmds.txt; mv $(TFILE) doc/cmds.txt; fi; rmdir $(TDIR) doc/jove.man.txt: doc/intro.nr doc/cmds.nr @-if $(WHICH) $(NROFF) > /dev/null; then mkdir $(TDIR) && \ LANG=C; export LANG; cd doc && tbl intro.nr | $(NROFF) -ms - cmds.nr > $(TFILE); \ if $(CMP) -s $(TFILE) jove.man.txt 2> /dev/null; then rm $(TFILE); else rm -f jove.man.txt; mv $(TFILE) jove.man.txt; fi; rmdir $(TDIR); fi doc/jove.man.$(TDEV): doc/intro.nr doc/cmds.nr doc/contents.nr @-if $(WHICH) $(TROFF) > /dev/null; then mkdir $(TDIR) && \ LANG=C; export LANG; cd doc && tbl intro.nr | $(TROFF) -T$(TDEV) -ms - cmds.nr contents.nr $(TROFFPOST) > $(TFILE); \ if $(CMP) -s $(TFILE) jove.man.$(TDEV) 2> /dev/null; then rm $(TFILE); else rm -f jove.man.$(TDEV); mv $(TFILE) jove.man.$(TDEV); fi; rmdir $(TDIR); fi # might not have been formatted if there is no nroff or troff $(CMDSDOC): $(DSHAREDIR) doc/cmds.txt doc/teach-jove -$(TINSTALL) doc/cmds.txt $(CMDSDOC) $(TEACHDOC): $(DSHAREDIR) doc/teach-jove $(TINSTALL) doc/teach-jove $(TEACHDOC) $(REFDOC): $(DDOCDIR) doc/jove.qref doc/example.rc $(FREFDOCS) $(TINSTALL) README doc/jove.qref doc/example.rc $(FREFDOCS) $(DDOCDIR) doc/jove.rc: doc/jove.rc.in @mkdir $(TDIR) && \ sed "s,__ETCDIR__,$(JETCDIR)," doc/jove.rc.in > $(TFILE); \ if $(CMP) -s $(TFILE) doc/jove.rc 2> /dev/null; then rm $(TFILE); else rm -f doc/jove.rc; mv $(TFILE) doc/jove.rc; fi; rmdir $(TDIR) $(JOVERC): $(DSHAREDIR) doc/jove.rc $(TERMSDIR) $(DOCTERMS) $(TINSTALL) doc/jove.rc doc/jem* $(DOCTERMS) $(DSHAREDIR) $(PORTSRV): $(DLIBDIR) portsrv$(XEXT) case "$(PORTSRVINST)" in 1|y) $(XINSTALL) portsrv$(XEXT) $(PORTSRV);; esac $(RECOVER): $(DLIBDIR) recover$(XEXT) $(XINSTALL) recover$(XEXT) $(RECOVER) $(JOVE): $(DBINDIR) jjove$(XEXT) $(XINSTALL) jjove$(XEXT) $(JOVE) $(TEACHJOVE): $(DBINDIR) $(XINSTALL) teachjove $(TEACHJOVE) doc/jove.$(MANEXT): doc/jove.nr @mkdir $(TDIR) && \ sed -e 's;;$(JTMPDIR);' \ -e 's;;$(JLIBDIR);' \ -e 's;;$(JSHAREDIR);' \ -e 's;;$(DFLTSHELL);' doc/jove.nr > $(TFILE); \ if $(CMP) -s $(TFILE) doc/jove.$(MANEXT) 2> /dev/null; then rm $(TFILE); else rm -f doc.jove.$(MANEXT); mv $(TFILE) doc/jove.$(MANEXT); fi; rmdir $(TDIR) $(JOVEM): $(DMANDIR) doc/jove.$(MANEXT) $(TINSTALL) doc/jove.$(MANEXT) $(JOVEM) # doc/jove.txt is the formatted manpage (for Windows and DOS src zip) # Building it should be like building $(JOVEM) except that we # don't know what to substitute for etc. because they # will be presumably set later by the person who downloads and # installs the src zip, but we must do the formatting to prepare the zip # since Windows/DOS will not have NROFF. doc/jove.txt: doc/jove.nr @mkdir $(TDIR) && \ LANG=C $(NROFF) -man doc/jove.nr > $(TFILE) && \ if $(CMP) -s $(TFILE) doc/jove.txt 2> /dev/null; then rm $(TFILE); else rm -f doc/jove.txt; mv $(TFILE) doc/jove.txt; fi; rmdir $(TDIR) doc/teachjove.$(MANEXT): doc/teachjove.nr @mkdir $(TDIR) && \ sed -e 's;;$(JTMPDIR);' \ -e 's;;$(JLIBDIR);' \ -e 's;;$(JSHAREDIR);' \ -e 's;;$(DFLTSHELL);' doc/teachjove.nr > $(TFILE); \ if $(CMP) -s $(TFILE) doc/teachjove.$(MANTXT) 2> /dev/null; then rm $(TFILE); else rm -f doc/teachjove.$(MANEXT); mv $(TFILE) doc/teachjove.$(MANEXT); fi; rmdir $(TDIR) $(TEACHJOVEM): $(DMANDIR) doc/teachjove.$(MANEXT) $(TINSTALL) doc/teachjove.$(MANEXT) $(TEACHJOVEM) $(XJOVEM): $(DMANDIR) doc/xjove.nr $(TINSTALL) doc/xjove.nr $(XJOVEM) doc/jovetool.$(MANEXT): doc/jovetool.nr @mkdir $(TDIR) && \ sed -e 's;;$(MANDIR);' \ -e 's;;$(MANEXT);' doc/jovetool.nr > $(TFILE); \ if $(CMP) -s $(TFILE) doc/jovetool.$(MANTXT) 2> /dev/null; then rm $(TFILE); else rm -f doc/jovetool.$(MANEXT); mv $(TFILE) doc/jovetool.$(MANEXT); fi; rmdir $(TDIR) $(JOVETOOLM): $(DMANDIR) doc/jovetool.$(MANEXT) $(TINSTALL) doc/jovetool.$(MANEXT) $(JOVETOOLM) fdocs: $(FDOCS) echo: @echo $(SOURCES) $(HEADERS) # note: $(C_SRC) contains commands.tab and vars.tab # These should not be linted, but they will probably be ignored. lint: keys.c lint $(SYSDEFS) $(C_SRC) keys.c lint $(SYSDEFS) portsrv.c lint $(SYSDEFS) recover.c lint $(SYSDEFS) setmaps.c @echo Done # CTAGSFLAGS = -N --format=1 # fishy options required for Exuberant Ctags # since this is inconvenient to specify, you can use target extags instead. CTAGSFLAGS = -w tags: $(C_SRC) $(HEADERS) -rm -f tags && ctags $(CTAGSFLAGS) $(C_SRC) $(HEADERS) extags: $(C_SRC) $(HEADERS) -rm -f tags && ctags -N --format=1 $(C_SRC) $(HEADERS) # .filelist is a trick to get around a make limit: # the list of files is too long to fit in a command generated by make # The actual contents of the file depend only on Makefile, but by # adding extra dependencies, dependants of .filelist can have shorter # dependency lists. Note: since we have no list of xjove files, # we alway force a make of xjove/.filelist. This forces .filelist # to be rebuilt every time it is needed. .filelist: $(BACKUPS) $(DOCS) tags @mkdir $(TDIR) && \ if test -f tags; then ls tags; fi > $(TFILE) && \ ls $(BACKUPS) >> $(TFILE) && \ ls $(DOCS) >> $(TFILE) && \ find pkg old -print >> $(TFILE) && \ (cd xjove ; make FLIST=$(TFILE).xj $(TFILE).xj) && \ sed -e 's=^=xjove/=' $(TFILE).xj >> $(TFILE); \ if $(CMP) -s $(TFILE) .filelist 2> /dev/null; then rm $(TFILE); else rm -f .filelist; mv $(TFILE) .filelist; fi; rm -f $(TFILE).xj; rmdir $(TDIR) # Build a distribution: a gzipped tar file with a name "jove-.tgz" # The tar will unpack into a directory with the name jove- # Beware: old files with these names will be blown away. tgz: .version .filelist Makefile jove.spec set -u ; set -e ; \ BN=jove-`cat .version` ; \ rm -rf $$BN $$BN.tgz* ; \ mkdir $$BN ; \ $(TAR) cf - jove.spec `cat .filelist` | ( cd $$BN ; $(TAR) xf - ) ; \ $(TAR) czf $$BN.tgz $$BN ; \ rm -rf $$BN ; \ ls -l $$BN.tgz distrib: tgz zip rpm: jove.spec .version tgz $(RPMHOME) # rpmbuild really wants the source tarball to have # the basename of Source0 in the rpm spec, and be # in the rpmbuild SOURCES directory. rpmsrc=`sed -n '/Source0/s,.*/,,p' jove.spec`; \ BN=jove-`cat .version` ; \ cp $$BN.tgz $(RPMHOME)/$$rpmsrc; \ rpmbuild -ta $(RPMHOME)/$$rpmsrc # requires pbuilder to be installed, which uses chroot so needs to be run as root. deb: .version tgz BN=`pwd`/jove-`cat .version`.tgz && cd pkg/deb && ./testdeb.sh $$BN # create a distribution and a separate GPG signature for it signed: .version tgz BN=jove-`cat .version` ; \ gpg -sba $$BN.tgz; \ chmod a+r $$BN.tgz.asc # MSDOS isn't a full-fledged development environment. # Preparing a distribution for MSDOS involves discarding some things # and pre-building others. All should have \n converted to CR LF. # From SUPPORT: setmaps.c, keys.txt, recover.c # From MISC: all but Makefile and README.mac # Preformatted documentation. [would like a joverc] # tags DOSSRC = $(HEADERS) $(C_SRC) setmaps.c recover.c keys.txt \ Makefile.msc Makefile.wat ChangeLog \ README README.dos README.win sysdep.txt tune.txt style.txt \ jjove.rc $(FDOCS) tags doc/jove.rc $(DOSDOCS) zip: .version $(DOSSRC) jjove.ico Makefile set -u ; set -e ; \ V=`sed 's/\.//g;s/^\(...\).*/\1/' .version` && \ BN=jove$${V}s && \ rm -rf $$BN && \ mkdir $$BN && \ $(TAR) cf - jjove.ico $(DOSSRC) | ( cd $$BN ; $(TAR) xf - ) && \ $(ZIP) $(ZIPOPTS) jovetmp$$$$.$(ZIPEXT) $$BN/jjove.ico && \ rm -f $$BN/jjove.ico && \ mv $$BN/doc/jove.man.txt $$BN/doc/joveman.txt && \ mv $$BN/doc/jove.man.pdf $$BN/doc/joveman.pdf && \ mv $$BN/doc/teach-jove $$BN/doc/teachjov.txt && \ mv $$BN/ChangeLog $$BN/changelg.txt && \ $(ZIP) $(ZIPOPTS) jovetmp$$$$.$(ZIPEXT) $(ZIPTXTOPT) $$BN/* && \ rm -f jove$${V}s.$(ZIPEXT) && \ mv jovetmp$$$$.$(ZIPEXT) jove$${V}s.$(ZIPEXT) && \ rm -rf $$BN ; \ ls -l jove$${V}s.$(ZIPEXT) touch: touch $(OBJECTS) clean: rm -f a.out core *.o keys.c jjove$(XEXT) portsrv$(XEXT) recover$(XEXT) \ setmaps$(XEXT) make.log *.map \#* *~ *.tmp \ jjove.pure_* ID *.exe jjove.coff */*.tmp \ .filelist xjove/.filelist .version ( cd xjove ; make clean ) # NOTE: deletes distrib (tgz, zip), formatted docs clobber: clean rm -f paths.h jove.spec $(FDOCS) $(GEN) tags *.tgz *.$(ZIPEXT) *.orig *.rej distclean: clobber # This version only works under 4.3BSD dependbsd: @echo '"make depend" only works under 4.3BSD' @-rm -f Makefile.new sed -e '/^# DO NOT DELETE THIS LINE/q' Makefile >Makefile.new for i in ${SOURCES} ; do \ $(CC) ${CFLAGS} ${DEPENDFLAG} $$i | \ awk ' /[/]usr[/]include/ { next } \ { if ($$1 != prev) \ { if (rec != "") print rec; rec = $$0; prev = $$1; } \ else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \ else rec = rec " " $$2 } } \ END { print rec } ' >>Makefile.new; \ done echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile.new echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile.new echo '# see "make depend" above' >>Makefile.new @echo 'New makefile is in "Makefile.new". Move it to "Makefile".' # This version should work with any UNIX # It records all dependencies, including ones that are #ifdef'ed out. # It assumes that only jove.h and tune.h include other headers depend: @sed -e '/^# DO NOT DELETE THIS LINE/q' Makefile >Makefile.new for i in tune.h jove.h ${SOURCES} ; do \ ( ( echo "$$i:"; sed -n -e 's/^#[ ]*include[ ]*"\([^"]*\)".*/\1/p' $$i ) | \ sed -e 's/^jove\.h$$/$$(JOVE_H)/' -e 's/^tune\.h$$/$$(TUNE_H)/' \ -e 's/^jove\.h:$$/JOVE_H = jove.h/' -e 's/^tune\.h:$$/TUNE_H = tune.h/' \ -e 's/\.c:$$/.o:/' | \ tr "\012" "\040" ; echo ) | sed -e 's/ $$//' -e '/:$$/d' >>Makefile.new ; \ done @echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile.new @echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile.new @echo '# see "make depend" above' >>Makefile.new @if $(CMP) -s Makefile Makefile.new 2> /dev/null; \ then echo '*** Makefile is already up to date' ; rm -f Makefile.new; \ else echo '*** New makefile is in "Makefile.new". Move it to "Makefile".' ; \ fi # DO NOT DELETE THIS LINE -- "make depend" uses it TUNE_H = tune.h sysdep.h JOVE_H = jove.h $(TUNE_H) buf.h io.h dataobj.h keymaps.h argcount.h util.h externs.h commands.o: $(JOVE_H) jctype.h extend.h macros.h mouse.h abbrev.h c.h case.h commands.h delete.h disp.h insert.h sysprocs.h iproc.h marks.h misc.h move.h para.h proc.h reapp.h wind.h commands.tab abbrev.o: $(JOVE_H) fp.h jctype.h abbrev.h ask.h commands.h delete.h insert.h disp.h fmt.h move.h wind.h argcount.o: $(JOVE_H) jctype.h ask.o: $(JOVE_H) jctype.h chars.h disp.h fp.h scandir.h screen.h ask.h delete.h insert.h extend.h fmt.h marks.h move.h wind.h mac.h buf.o: $(JOVE_H) jctype.h disp.h ask.h extend.h fmt.h insert.h macros.h marks.h move.h sysprocs.h proc.h wind.h fp.h iproc.h mac.h c.o: $(JOVE_H) re.h c.h jctype.h disp.h delete.h insert.h fmt.h marks.h misc.h move.h para.h case.o: $(JOVE_H) disp.h case.h jctype.h marks.h move.h jctype.o: $(JOVE_H) jctype.h delete.o: $(JOVE_H) jctype.h disp.h delete.h insert.h marks.h move.h disp.o: $(JOVE_H) jctype.h chars.h fp.h disp.h ask.h extend.h fmt.h insert.h sysprocs.h iproc.h move.h macros.h screen.h term.h wind.h mac.h extend.o: $(JOVE_H) fp.h jctype.h chars.h commands.h disp.h re.h ask.h extend.h fmt.h insert.h move.h sysprocs.h proc.h vars.h mac.h fp.o: $(JOVE_H) fp.h jctype.h disp.h fmt.h mac.h fmt.o: $(JOVE_H) chars.h fp.h jctype.h disp.h extend.h fmt.h mac.h insert.o: $(JOVE_H) jctype.h list.h chars.h disp.h abbrev.h ask.h c.h delete.h insert.h fmt.h macros.h marks.h misc.h move.h para.h screen.h sysprocs.h proc.h wind.h re.h io.o: $(JOVE_H) list.h fp.h jctype.h disp.h ask.h fmt.h insert.h marks.h sysprocs.h proc.h wind.h rec.h mac.h re.h temp.h iproc.o: $(JOVE_H) re.h jctype.h disp.h fp.h sysprocs.h iproc.h ask.h extend.h fmt.h insert.h marks.h move.h proc.h wind.h ttystate.h select.h jove.o: $(JOVE_H) fp.h jctype.h chars.h disp.h re.h reapp.h sysprocs.h rec.h ask.h extend.h fmt.h macros.h marks.h mouse.h paths.h proc.h screen.h term.h version.h wind.h iproc.h select.h mac.h jtc.o: $(JOVE_H) jctype.h fmt.h fp.h select.h list.o: $(JOVE_H) list.h macros.o: $(JOVE_H) jctype.h fp.h chars.h disp.h ask.h commands.h macros.h extend.h fmt.h marks.o: $(JOVE_H) fmt.h marks.h disp.h misc.o: $(JOVE_H) jctype.h disp.h ask.h c.h delete.h insert.h extend.h fmt.h marks.h misc.h move.h para.h move.o: $(JOVE_H) re.h chars.h jctype.h disp.h move.h screen.h para.o: $(JOVE_H) jctype.h disp.h delete.h insert.h fmt.h marks.h misc.h move.h para.h re.h proc.o: $(JOVE_H) jctype.h fp.h re.h disp.h sysprocs.h ask.h delete.h extend.h fmt.h insert.h iproc.h marks.h misc.h move.h proc.h wind.h re.o: $(JOVE_H) re.h jctype.h ask.h disp.h fmt.h marks.h reapp.o: $(JOVE_H) fp.h re.h jctype.h chars.h disp.h ask.h extend.h fmt.h marks.h reapp.h wind.h mac.h rec.o: $(JOVE_H) fp.h sysprocs.h rec.h fmt.h recover.h scandir.o: $(JOVE_H) scandir.h screen.o: $(JOVE_H) fp.h chars.h jctype.h disp.h extend.h fmt.h term.h mac.h screen.h wind.h term.o: $(JOVE_H) term.h fp.h termcap.o: $(JOVE_H) term.h disp.h fmt.h fp.h jctype.h screen.h unix.o: $(JOVE_H) fp.h chars.h term.h ttystate.h util.o: $(JOVE_H) jctype.h disp.h fp.h ask.h chars.h fmt.h insert.h macros.h marks.h move.h rec.h mac.h vars.o: $(JOVE_H) extend.h vars.h abbrev.h ask.h c.h jctype.h disp.h insert.h sysprocs.h iproc.h mac.h mouse.h para.h proc.h re.h reapp.h rec.h screen.h term.h ttystate.h wind.h vars.tab wind.o: $(JOVE_H) chars.h disp.h ask.h extend.h commands.h mac.h reapp.h wind.h screen.h msgetch.o: $(JOVE_H) chars.h disp.h mac.o: $(TUNE_H) $(JOVE_H) mac.h ask.h chars.h disp.h extend.h fp.h commands.h fmt.h marks.h misc.h move.h screen.h scandir.h term.h vars.h version.h wind.h keymaps.o: $(JOVE_H) list.h fp.h jctype.h chars.h disp.h re.h ask.h commands.h macros.h extend.h fmt.h screen.h vars.h sysprocs.h iproc.h ibmpcdos.o: $(JOVE_H) fp.h chars.h screen.h term.h mouse.o: $(JOVE_H) commands.h disp.h misc.h ask.h chars.h delete.h fmt.h insert.h marks.h move.h wind.h term.h fp.h jctype.h mouse.h xjove/mousemsg.h win32.o: $(JOVE_H) fp.h chars.h screen.h disp.h portsrv.o: $(JOVE_H) sysprocs.h iproc.h recover.o: $(JOVE_H) sysprocs.h rec.h paths.h recover.h scandir.c jctype.h setmaps.o: $(JOVE_H) chars.h commands.h vars.h commands.tab vars.tab # DEPENDENCIES MUST END AT END OF FILE # IF YOU PUT STUFF HERE IT WILL GO AWAY # see "make depend" above jove-4.17.5.5/Makefile.msc000066400000000000000000000121211501102521500151240ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## # Makefile for Microsoft C version 8.0 (Visual C) # should also work with earlier versions # Once worked for MS VisualC++ 5.0 and MS VisualStudio 97 # Not recently tested (Windows and DOS packages now built with # mingw and Open Watcom C respectively). # # - supported targets: # + jjove.exe (build JOVE, but don't install it) # + jovedosx.zip (build executable JOVE kit for DOS) # + jovew32x.zip (build executable JOVE kit for Win32) # + clean # # - to install, do the following: # + copy jjove.exe where you wish # + copy doc/cmds.txt to /cmds.txt # + optional: copy some jove rc (none supplied) file to /jove.rc # Options (specify on MAKE command line with -D) # DEBUG=1 : enable debugging, disable optimizations # ARCH=0|2|3 : compile for 086/286/386 (-G option). Still 16-bit though. # Visual Studio 2019 only works for Win32, Dos is part of the past. # For DOS, use the Open Watcom compiler, see Makefile.wat. WIN32=1 !if "$(DEBUG)" != "" DEB = -Gs -Od -Zi -DDEBUG !else DEB = -Ox -D_NDEBUG DEBLDFLAGS= !endif !IF "$(WIN32)" == "1" SYSCFLAGS = -DWIN32 SYSLDFLAGS = /SUBSYSTEM:Console SYSOBJS = win32.obj LIBS = /DEFAULTLIB:USER32 /DEFAULTLIB:KERNEL32 /DEFAULTLIB:COMDLG32 OS = w32 !if "$(DEBUG)" != "" DEBLDFLAGS= /DEBUG !else DEBLDFLAGS= !endif !ELSE # Not WIN32 - 16-bit DOS !IF "$(ARCH)" == "" ARCH = 0 # Default to 8086 !ENDIF OS = dos MEM = L # M for medium or L for large SYSCFLAGS = -A$(MEM) -J -Zp -G$(ARCH) SYSLDFLAGS = /PACKC/NOE/NOI/MAP/E/STACK:0x2000 SYSOBJS = msgetch.obj ibmpcdos.obj !if "$(DEBUG)" != "" DEBLDFLAGS=/CO/F/B !endif !ENDIF # WIN32 !IF "$(BROWSE)" != "" BROWSE_FLG = -FR BROWSE_TGT = jjove.bsc !ENDIF CFLAGS = $(SYSCFLAGS) $(BROWSE_FLG) -nologo $(DEB) # # linker flags: for debugging use /NOE/NOI/F/B/PAC/CO/STACK:0x2000 # LDFLAGS = $(SYSLDFLAGS) $(DEBLDFLAGS) # # set VPATH as below if you have sources in SRC # # SRC = . # VPATH = .;.. # should read .;$(SRC) - but doesn't work # Other utilities used in build - defined here so they can be overridden # Used to generate archives for redistributing JOVE executables and docs. ZIP = pkzip TMPDIR = c:/tmp RECDIR = c:/tmp # BINDIR = c:/jove # LIBDIR and SHAREDIR are relative to BINDIR LIBDIR = SHAREDIR = doc DFLTSHELL = command OBJECTS = keys.obj commands.obj abbrev.obj ask.obj buf.obj c.obj \ case.obj jctype.obj delete.obj extend.obj argcount.obj \ insert.obj io.obj jove.obj macros.obj marks.obj misc.obj mouse.obj move.obj \ para.obj proc.obj re.obj reapp.obj rec.obj scandir.obj \ list.obj keymaps.obj util.obj vars.obj wind.obj \ fmt.obj disp.obj term.obj fp.obj screen.obj \ $(SYSOBJS) HEADERS = abbrev.h argcount.h ask.h buf.h c.h case.h chars.h commands.h \ jctype.h dataobj.h delete.h disp.h extend.h externs.h \ fmt.h fp.h insert.h io.h iproc.h jove.h \ keymaps.h list.h mac.h macros.h marks.h \ misc.h mouse.h move.h para.h proc.h \ re.h reapp.h rec.h scandir.h screen.h \ sysdep.h sysprocs.h temp.h term.h ttystate.h \ tune.h util.h vars.h version.h wind.h !IF "$(WIN32)" != "" RESOURCE = jjove.res !ENDIF all: jjove.exe recover.exe $(BROWSE_TGT) jjove.exe: $(OBJECTS) $(HEADERS) $(RESOURCE) !IF "$(WIN32)" != "" link /OUT:jjove.exe /MAP $(LIBS) @< keys.c keys.obj: keys.c jove.h $(CC) $(CFLAGS) -c keys.c clean: -del *.obj setmaps.exe keys.c *.bak *.map *.pdb *.vcp jove.lnk jove-4.17.5.5/Makefile.wat000066400000000000000000000167151501102521500151520ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## # wmake -f makefile.wat [] # Makefile for Watcom C 10.0 # # - supported targets: # + jjove.exe (build JOVE, but don't install it) # + jovedosx.zip (build executable JOVE kit) # + clean # # - to install, do the following: # + copy jjove.exe where you wish # + copy doc/cmds.txt to /cmds.txt # + optional: copy some jove rc (none supplied) file to /jove.rc # Watcom Quirks: # - "&" is used instead of "\" as the continuation character # - .SYMBOLIC is needed it a rule doesn't create the target (eg. "clean") # - .AUTODEPEND picks up dependencies recorded in .obj files # - stack size is specified using -k # - "*" at the start of a command will work around >128 char args. # For some reason, I couldn't get this to work, so I used *.obj # in the link step -- a bit fragile! # - To get wild-card processing of command-line args, we must # link in wildargv.obj (which we must build -- see below). # =================================================================== # Jove configuration: default JOVE paths. # Note that all these can be set from environment variables as well; # see README.DOS for details. # # TMPDIR is where the tmp files get stored, usually /tmp or /usr/tmp. # RECDIR is the directory in which RECOVER looks for JOVE's tempfiles. # LIBDIR is for the PORTSRV and RECOVER programs. # SHAREDIR is for online documentation, and the system-wide jove.rc file. ## BINDIR is where to put the executables JOVE # DFLTSHELL is the default shell invoked by JOVE. TMPDIR = c:/tmp RECDIR = c:/tmp # BINDIR = c:/jove # LIBDIR and SHAREDIR are relative to executable directory LIBDIR = SHAREDIR = doc DFLTSHELL = command # Compiler: CC = wcc # Watcom Compiler Flags: # # -d2 full symbolic debugging information # -fo= set object or preprocessor output file name # -i= another include directory # -m{s,m,c,l,h} memory model (Small,Medium,Compact,Large,Huge) # -w set warning level number # -wx generate all warnings # -zq operate quietly (diagnostics are not suppressed) # -zt put objects greater than bytes in far segments # -os optimize for size over speed # -ot optimize for speed over size # -s do not add stack overflow check code # # Same as UNIX: # -d[=text] precompilation #define name [text] # NOTE: quotes around the macro body in a -D are actually taken as part # of that body!! # -ms (small mode) cannot be used (Jove is about 15K over the 64K code limit, # even with -DBAREBONES, and OPTFLAGS="-os -s") # -mm (medium mode) builds with very few I/O buffers, and 512-byte max line # length. Might run out of tmp file space or heap memory if editing many # files. # -ml (large mode) is recommended, has more buffers (so should be faster # for normal use), 2K max line length, takes advantage of all heap memory # so can keep a very large number of files open. # 640K ought to be enough for anyone! MODEL = -ml OPTFLAGS = -os # optimize for size over speed CFLAGS = $(MODEL) $(OPTFLAGS) -wx -zq -zt200 -dOWCDOS=1 # Linker: LD = wcl # Watcom wcl (Watcom Compile/Link) Link Flags: # # -fe= set .exec output file name # -fm generate .map file # -kN allocate N bytes for stack # -x make case of names significant # N for stack may need to be lowered if linking complains that # DGROUP is too large (reduce it by the number of bytes in the # complaint). Alternatively, maybe decrease CFLAGS zt (moves # more objects to far, presumably a tad slower, bigger code footprint?) # https://open-watcom.github.io/open-watcom-v2-wikidocs/pguide.html#What_does__size_of_DGROUP_exceeds_64K__mean_for_16Mbit_applications_ STACKSIZE = 18000 LDFLAGS = $(CFLAGS) -x -k$(STACKSIZE) # =================================================================== # Implicit rules. .c.obj: .AUTODEPEND $(CC) $(CFLAGS) $< .obj.exe: $(LD) $(LDFLAGS) $< OBJECTS = keys.obj commands.obj abbrev.obj ask.obj buf.obj c.obj & case.obj jctype.obj delete.obj extend.obj argcount.obj insert.obj & io.obj jove.obj macros.obj marks.obj misc.obj mouse.obj move.obj & para.obj proc.obj re.obj reapp.obj rec.obj scandir.obj list.obj & keymaps.obj util.obj vars.obj wind.obj fmt.obj disp.obj term.obj & fp.obj screen.obj msgetch.obj ibmpcdos.obj HEADERS = abbrev.h argcount.h ask.h buf.h c.h case.h chars.h commands.h & jctype.h dataobj.h delete.h disp.h extend.h externs.h & fmt.h fp.h insert.h io.h iproc.h jove.h & keymaps.h list.h mac.h macros.h marks.h & misc.h mouse.h move.h para.h proc.h & re.h reapp.h rec.h scandir.h screen.h & sysdep.h sysprocs.h temp.h term.h ttystate.h & tune.h util.h vars.h version.h wind.h all: jjove.exe recover.exe # # For this reason, we can only force the building of paths.h # by adding it to the dependencies for explicit targets. # In the hope that it is built soon enough, we put it at the front. # To avoid over-long cmd line, we use *.obj for jjove link, # which means we have to ensure recover or setmaps use one-step # compile-and-link and do not leave .obj lying around. # * $(LD) $(LDFLAGS) -fe=$* $(OBJECTS) jjove.exe: paths.h $(OBJECTS) wildargv.obj -del recover.obj -del setmaps.obj $(LD) $(LDFLAGS) -fm -fe=$* *.obj recover.exe: recover.c wcl $(CFLAGS) $(LDFLAGS) $< -fe=$@ $< # Complains about an overly long command # $(OBJECTS): $(HEADERS) jovedosx.zip: paths.h jjove.exe -del jovedosx.zip -del jove.exe rename jjove.exe jove.exe pkzip -aP jovedosx.zip jove.exe recover.exe doc\*.* paths.h README.dos changelg.txt # Note that quotes are not stripped by the shell that will # execute the recipe for paths.h paths.h: Makefile.wat @echo Making < keys.c # Note: it may be necessary to manually copy the source file from # the distribution CDROM to the installation. On the CDROM, the # file's path is \watcom\src\startup\wildargv.c. # Or you can get it from # http://perforce.openwatcom.org:4000/@md=d&cd=//depot/openwatcom/bld/clib/startup/c/&c=WFs@//depot/openwatcom/bld/clib/startup/c/wildargv.c?ac=22 # (e.g. version 3 seems to compile with OpenWatcom 1.9) # The latest versions at github need newer compilers than 1.9.0 # https://github.com/open-watcom/open-watcom-v2/master/bld/clib/startup/c/wildargv.c # At least with some versions (fixed in the github version), wildargv.c does not accept tabs as # argument delimiters. This should be fixed. # Change line 82 from: # while( *p == ' ' ) ++p; /* skip over blanks */ # to: # while( *p == ' ' || *p == '\t' ) ++p; /* skip over blanks */ # Change line 103 from: # if( *p == ' ' ) break; # to: # if( *p == ' ' || *p == '\t' ) break; #WILDSRC=$(%WATCOM)\src\startup\wildargv.c WILDSRC=wildargv.c wildargv.obj: $(WILDSRC) $(CC) $(CFLAGS) $(WILDSRC) clean: .SYMBOLIC -del *.obj -del *.exe -del *.bak -del *.map -del keys.c jove-4.17.5.5/README000066400000000000000000001011131501102521500135630ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## [Updated in 2023 Nov] JOVE on UNIX/Linux/MacOS X/*BSD/CygWin Systems ---------------------------------------------- Getting JOVE ------------ JOVE releases are available at http://github.com/jonmacs/jove/ in various source (github's automatically packed tar.gz, or a manually packed .tgz which are essentialy identical, as well as a manually packed .zip or .exe for MS-DOS), and some binary forms for various OS architectures (Linux, DOS, Windows). All distributions include formatted manuals (PDF, text) -- in the doc/ subdirectory for source and some binary, or in share/doc/jove, share/jove or man/man1 (relative to a top-level installation directory, such as /usr or /usr/local) For information about other systems, see the other README files in the source, zip or exe distributions: README.dos for MS-DOS README.win for MS Win32 Quick Summary of Installation ----------------------------- Unpack the tar file somewhere convenient and cd into it: tar xzf jove-VERSION.tgz cd jove-VERSION For old Unix, gunzip this the file on a modern platform, them copy the tar over and use tar xf jove-VERSION.tgz Ensure you have the tools required to build Jove. You need a C compiler (classic Unix cc, gcc or clang should work), the make utility, and basic headers for libc, which may require extra packages on some Linux distributions. Debian, Ubuntu, Mint: apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends gcc make ncurses-dev pkg-config exuberant-ctags Alpine: apk update && apk add gcc make musl-dev ncurses-dev pkgconfig ctags MacOSX/Darwin: brew install make ncurses Nix: nix-shell -p gnumake Arch: pacman -Sy gcc make # pkgconf ncurses Gentoo: # comes with gcc and make and headers by default! For many modern systems (Linux, various BSDs, MacOSX/Darwin, Solaris, OpenIndiana), an auxiliary script called jmake.sh is provided that auto-detects what the SYSDEFS and EXTRALIBS should be, and then invokes 'make' without any manual configuration needed: just specify JOVEHOME to change where you want jove installed (default JOVEHOME is /usr/local, which puts the binaries in $JOVEHOME/bin, manuals in $JOVEHOME/man/man1, other documents and help and config in $JOVEHOME/share/jove, helper programs in $JOVEHOME/lib/jove e.g. to put jove in /opt/jove/{bin,share,...} ./jmake.sh JOVEHOME=/opt/jove # to build ./jmake.sh JOVEHOME=/opt/jove install # to install To build a relocatable version of Jove (i.e. an install directory that can be copied or moved freely to other paths) in /foo ./jmake.sh DESTDIR=/foo/ JOVEHOME= JBINDIR= JSHAREDIR=doc JLIBDIR= clean install If jmake.sh does not work, please do file a bug, indicating your system. One can also pass SYSDEFS, TERMCAPLIB and EXTRALIBS (and other variables in the Makefile) by hand. modern (Net|Open|Free)BSD/Darwin/Mac OS X: use the first of the following that works: make install make SYSDEFS=-DXBSD install make SYSDEFS="-DBSDPOSIX_STDC -DUSE_OPENPTY -DHAS_LIBUTILS_H" LDLIBS=-lutil install make SYSDEFS="-DBSDPOSIX_STDC" install make SYSDEFS="-DBSDPOSIX" install classic BSD4.[0123]: make SYDEFS=-DBSD4 JTMPDIR=/usr/tmp JRECDIR=/usr/preserve MKDIRP=mkdir LDLIBS=-ltermcap install Linux: Using RPM (if sufficiently close to Red Hat; make sure RPMHOME is correct in the Makefile, that you have the rpm-build package, a compiler and and use: make rpm and them install the resulting rpm from $HOME/rpmbuild/RPMS with "rpm -i" To compile and install from source, set JOVEHOME appropriately. By default, Jove has internal support for ansi/vt[1234]xx terminals that are emulated by every modern desktop environment (i.e xterm, rxvt, st, vte, konsole, {gnome,mate}-terminal, ...), so unless you have some very special terminal, you should not need a general purpose terminal handling library like termcap or curses. But if you need one, the packages go by different names on various Linux. If you install pkgconf (for the pkg-config program) and the ncurses (which sometimes goes by names like ncursesw, ncurses-base, ncurses-dev, ncurses-devel, libncurses-dev, libtinfo-dev, sys-libs), that should be enough on most Linux systems. Otherwise, you can explicitly ask for it is using something like make SYSDEFS=-D`uname` LDLIBS=-lncursesw If you link with one of the general terminal handling libraries rather than using Jove's builtin handling, then you will also need to ensure you have terminal descriptions, which are sometimes in separate packages (e.g. called ncurses-terminfo-base or ncurses-base or ncurses-term) Older Linux may need either SYSDEFS=-DXLINUX or SYSDEFS=-DBSDPOSIX_STDC (but do test how interactive-shell works once built; the main issues are pty-handling, even if they seem to compile without error) Solaris 5.1 or newer: make install Other systems: Read comments about SYSDEFS settings below, check sysdep.h for recently tested system settings or old/sysdep.h for once-working but currently untested settings that will need to be copied into sysdep.h, or just set on the command-line with SYSDEFS="-D...", LDLIBS if needed. Cross-Compiling: If your cross-compiler for some target FOO is FOO-gcc, then you can probably cross-compile with env JMAKE_UNAME=FOO-gcc ./jmake.sh e.g. env JMAKE_UNAME=i686-w64-mingw32 ./jmake.sh or env JMAKE_UNAME=i486-linux-musl ./jmake.sh More generally, the Jove Makefile has some support for cross-compiling. You need to set CC to the cross-compiler, but please do not override CFLAGS, which consists of SYSDEFS, (for any -I or -D cross-compiler options) and OPTFLAGS (for any optimizer flags or special cross-compiler options e.g. target arch). For linking, you can set LDFLAGS (e.g. -L) or LDLIBS for the cross-linker for the target system, while you can set LOCALCC, LOCALCFLAGS, LOCALLDFLAGS, LOCALEXTRALIBS and LOCALEXT for the local host machine compiler and linker (usually none other than LOCALCC are needed, since they are used when locally building the setmaps program on the host, which is run to generate keys.c, which will then be cross-compiled for the target) e.g. make CC=/cross/bin/cc-armv7 SYSDEFS="-DLinux -DJTC" OPTFLAGS=-O2 LDFLAGS="-L/cross/lib" LDLIBS="-lutil" LOCALCC=cc For another example, see README.win for cross-compiling using MinGW for a Windows target. Please help us keep up with new systems. If your system isn't covered in jmake.sh or on in the SYSDEFS section of Makefile, tell us what works. If your system is covered, but the documented procedure doesn't work, tell us by filing a bug on http://github.com/jonmacs/jove Full Story of Installation -------------------------- JOVE does not use any automatic configuring mechanism other than the very simple jmake.sh script, which only works on modern Linux/*BSD/MacOSX/Darwin/Solaris. System-specific configuring is done by defining specific symbols from sysdep.h in SYSDEFS in the Makefile (in most situations it is handier to override definitions by supplying them on the make command line rather than the classic technique of editing the Makefile). JOVE has been around for a *long* time, and a lot of care has been taken to make it work on many systems, new and old. For current systems, less configuring is require -- hurray for standards! Makefile specifies paths for installing JOVE components (JOVEHOME, JSHAREDIR, JLIBDIR, JBINDIR, JMANDIR, MANEXT), tempfiles (JTMPDIR, JRECDIR), and the default shell (DFLTSHELL). Although the defaults are reasonable, you may wish to change them. For many systems, you will need to change the definition of SYSDEFS. to the symbol that identifies your system's characteristics, using the notation for a macro-setting flag to the C compiler. For modern systems, that symbol is often the output of the uname command. For example, on a machine running NetBSD, use "SYSDEFS=-DNetBSD". The Makefile describes suitable settings of SYSDEFS for many configurations. If yours isn't mentioned, use "grep System: sysdep.h" to find all currently supported system configurations. If there is no canned configuration for your system, you will have to define a new symbol and edit sysdep.h suitably. See "sysdep.txt" for the possible set of system-dependent aspects that you can select/tune. On some systems, you may need to change the flags passed to the compiler (SYSDEFS, OPTFLAGS) or the linker (LDFLAGS, LDLIBS). [These supersede the older Jove-specific conventions of defining OPTFLAGS, SYSDEFS, TERMCAPLIB, EXTRALIBS, which should still work] Systems on which 4.17 was tested include the following (and their SYSDEFS and LDLIBS will usually be correctly set by the jmake.sh script that can be used to to invoke make with auto-guessed values) The following explicit settings also work and may provide a guide to customization. # Cygwin 3.1.2 SYSDEFS=-DCYGWIN LDLIBS= # builtin vt100/xterm/rxvt etc support, no need for curses dependency # Darwin aka MacOS X onwards SYSDEFS=-DDarwin LDLIBS=-ltermcap # FreeBSD 12.1 SYSDEFS=-DFreeBSD LDLIBS="-ltermcap -lutil" # Linux (modern, glibc pty.h) SYSDEFS=-DLinux LDLIBS="-lncursesw -lutil" # Linux (recent, UNIX98 PTYS) SYSDEFS=-DXLINUX LDLIBS=-lncursesw # Linux (old, BSD PTYS) SYSDEFS=-DBSDPOSIX_STDC LDLIBS=-lncurses # NetBSD 8.1 SYSDEFS=-DNetBSD LDLIBS="-ltermcap -lutil" # OpenBSD 6.6 SYSDEFS=-DOpenBSD LDLIBS="-ltermcap -lutil" # SunOS5.1 onwards (Solaris/OpenIndiana/Illumos/Joyent) SYSDEFS=-DSunOS LDLIBS=-ltermcap # Debian Hurd 0.9 SYSDEFS="-DGNU -DJTC" LDLIBS=-lutil # LDLIBS="-lncursesw -lutil" might work, did not try Next you may edit "tune.h" to select the compile time features you care about. See "tune.txt" for a description of all the compile time options. The default options are quite reasonable so, in most cases, you should leave them alone. If you are really short on space, or are porting JOVE to a new system, you may want to define -DBAREBONES in SYSDEFS to avoid some of the less-portable features of JOVE initially. You can type "make" to compile "jjove", "portsrv" (this is compiled on every system, but is only used if JOVE is compiled with the PIPEPROCS feature selection, typically on UNIX systems without pseudo ttys), "recover" and "teachjove". Test jjove to see if it works (remember that it won't be able to access its subsidiary files until they are installed, so you will need to call it with "./jjove -l . -s doc ..." -- assuming you are in the main JOVE directory). If it works, type "make install" to install everything where it belongs. Here are some things to consider when choosing a definition for JTMPDIR, the directory where JOVE puts temporary files. The obvious place is /tmp, but many systems delete all files in /tmp when they are rebooting. If you hope to recover buffers from a system crash, TMPDIR lets you specify a safer place. If your system does not remove subdirectories of /tmp on reboot (lots do remove them these days) then it makes sense to make TMPDIR be /tmp/jove; otherwise, /var/tmp may be better. But if you use /tmp and want to recover buffers on system crashes, you should put the lines: (echo preserving JOVE files) >/dev/console (cd /tmp; /usr/local/lib/jovelib/recover -syscrash) >/dev/console in the /etc/rc file BEFORE /tmp is cleared, so that you can recover files after reboots (hint: look for the equivalent code to preserve vi tempfiles). You should then create a crontab entry to clear out old files in /usr/preserve. If you plan on using JOVE with a xterm, look at doc/XTermresource. This file contains resource declarations that allow JOVE to respond to more function keys and mouse gestures. For RPM-based Linux, jspec.in specifies how an RPM should be created. On most modern Red Hat Linux (Fedora, CentOS, etc), "make rpm" will build source and binary RPMs -- rpm looks inside the .tgz to find jove.spec. (Need to 'yum install rpm-build groff' or similar first) It is possible to build a widely portable Linux binary using static compilation, perhaps using the musl library to keep size small. E.g., using the small Alpine Linux docker image, with srcdir set to a directory with the unpacked Jove source code, one can use: docker pull alpine docker run -v $srcdir:/src --rm -it alpine apk add gcc musl-dev make cd /src make 'CC=gcc --static' The resulting jjove can be run standalone pretty-much anywhere, though the doc/jove.rc file might also be useful. Some features. -------------- "doc/jove.rc" and "doc/example.rc" are JOVE initialization files. "jove.rc" is the recommended "system" rc file (until you are ready to roll your own, that is). It gets read every time JOVE starts up FOR EVERYONE ("make install" should copy it to the right place automatically). After that JOVE reads the initialization file .joverc in the user's home directory. "example.rc" is taken from a personal .joverc. The files intro.nr and cmds.nr in the doc directory are the official JOVE manual. Jonathan got permission from Richard Stallman to use his manual for the original EMACS, modifying it where necessary for JOVE. Lots of work was done by Brian Harvey on this manual. When formatted, these are usually in some system doc directory, typically /usr/share/doc/jove/ or /usr/local/share/doc/jove, as a PDF and a text form. There is also a quick-reference card with most JOVE key-bindings, commands and variables, best printed in landscape mode. There are Unix-style manual pages for jove and teachjove. Teachjove is an interactive tutorial for people who have never used EMACS style editors -- it can be started from within JOVE as the "teach-jove" command, usually bound to ESC t or historically, using the special Unix command "teachjove". It is THE tutorial written by Stallman for the original EMACS, only slightly modified for JOVE in the appropriate places. The manual pages are hopefully up to date. Optionally, if you want to use Jove to work with C source code, and know/like tags, you will need ctags or etags on your system so that you can generate tags files to use with jove -t or Jove's find-tag command (bound to the keys "^X t"). If you use Jove to work with text documents, and use the built-in spell-check support (i.e. Jove's spell-buffer command), you will need to install spell-checker program (spell on classic Unix, aspell on Linux/BSD). Optionally, if you want to modify, rebuild or reformat the documents, you will need a troff-style formatter (the package called groff on modern Linux/*BSD. You will also need the "ms" macros, should be included with most modern groff, though not in the scaled-down groff-base packages) Optionally, if you want to use 'make zip' to build a source archive suited to DOS/Windows, you will need the zip program (generally, a package called zip on most Linux/*BSD) Older, once-working systems ---------------------------- For the pdp11 version there was once the Ovmakefile, which had only been tested on 2.9bsd once upon a very long ago. It supposedly worked. and it was possible to turn on all the compile time options with that version. Maybe someone will try a PDP-11 emulator one day with 2.11BSD and report back?! The following used to work circa Jove 4.16 in the 1990s and have probably not been tested in the 21st century, so their definitions were deleted from sysdep.h, copies are still in old/sysdep.h. They may still build but some of this ancient support may be deleted from Jove at some point, we welcome any recent success stories from jove builders/packagers to refresh or maintain these. Pretty please! (e.g. a 2023 test with simh emulating a vax running 4.3BSD produced the fixes in 4.17.5.4) Most need LDLIBS=-ltermcap, but if you get link errors for tputs or tparm, try LDLIBS=-lcurses # Apple A/UX on macIIs SYSDEFS=-DA_UX # BSD4.1 SYSDEFS=-DBSD4 LDLIBS="-ljobs -ltermcap" # BSDI, 386BSD, BSD4.4 SYSDEFS=-DBSDPOSIX # Consensys V4 SYSDEFS="-DSYSVR4 -DGRANTPT_BUG" # Compaq Tru64 UNIX V4.0g, 5.1 SYSDEFS=-DSYSVR4 # DEC OSF R1.3MK SYSDEFS=-DSYSVR4 # DEC OSF/1 V1.3 SYSDEFS="-DBSDPOSIX -DNO_TIOCREMOTE -DNO_TIOCSIGNAL" # DEC OSF/1 V2.0 and later SYSDEFS=-DSYSVR4 # DEC Ultrix 4.2 SYSDEFS=-DBSDPOSIX # DEC Ultrix 4.3 SYSDEFS="-DBSDPOSIX -DJVDISABLE=255" # Digital UNIX V4.0 and later SYSDEFS="-DSYSVR4 -DGRANTPT_BUG" # DG AViiON 5.3R4 SYSDEFS="-DSYSVR4 -DBSD_SIGS" # HP/UX 8 or 9 SYSDEFS="-DHPUX -Ac" # HP/UX 11 (-Ac redundant) SYSDEFS=-DHPUX # IBM AIX 3.2 SYSDEFS=-DAIX3_2 # IBM AIX 4.2, 5.2 SYSDEFS="-DAIX4_2" LDLIBS="-lcurses -ltermcap -ls" # Irix 3.3-4.0.5 SYSDEFS="-DIRIX -DIRIX4" # Irix 5.0 onwards SYSDEFS="-DIRIX -prototypes" # Linux (ancient e.g. RedHat 4,5) SYSDEFS=-DBSDPOSIX # MIPS RiscOS4.x SYSDEFS="-systype bsd43 -DBSD4" # SCO Unix SYSDEFS=-DSCO LDLIBS=-lcurses # SunOS3.x SYSDEFS=-DSUNOS3 # SunOS4.0* SYSDEFS=-DSUNOS40 # SunOS4.1* SYSDEFS=-DSUNOS41 # SunOS5.0 (Solaris 2.0) SYSDEFS="-DSYSVR4 -DGRANTPT_BUG" # Sys III, Sys V R 2,3 SYSDEFS=-DSYSV PORTSRVINST='$(PORTSRV)' LDLIBS=-lcurses # Sys V Release 4.0 SYSDEFS="-DSYSVR4 -DGRANTPT_BUG" LDLIBS=-lcurses # Sys V Release 4.x SYSDEFS=-DSYSVR4 LDLIBS=-lcurses # Some systems based on System V release 4 have a bug affecting interactive processes. This bug can be worked around by defining GRANTPT_BUG. Read the explanation of GRANTPT_BUG in sysdep.txt. Notes for invoking make: # For SYSVR4 (/usr/ucb/cc will NOT work because of setjmp.h): # CC = /usr/bin/cc # To use the SunPro compiler under SunOS 4.n: # CC = acc # To use the official Sun compiler under Solaris 2.n: # CC = /opt/SUNWspro/bin/cc # For DG AViiON, expect compile errors unless you use the GNU C compiler: # CC=gcc LDCC is the load invocation of CC which can be changed to invoke link-time tools e.g. to use Purify(TM), try: LDCC = purify $(CC) Systems that used to need LDFLAGS # SysV Rel. 2: LDFLAGS = -Ml # SCO Xenix: LDFLAGS = -Ml -F 3000 # AIX Unix: LDFLAGS = -bloadmap:$@.map # only if loadmap # # To optimize the use of the address spaces, add to the LDFLAGS: # PDP-11 with separate I&D: -i # PDP-11 without separate I&D: -n For SCO Xenix, this might need to be set # LOCALCFLAGS = -Mle # OPTFLAGS = -LARGE -O -F 3000 -K -Mle (say -Mle2 for an 80286) For compiler OPTFLAGS set in the Makefile: # On the official Sun ANSI C compiler and the standard System V Release 4 # compiler, adding -Xa -v will increase compiler checking. # On DEC OSF/1 and Digital UNIX VV4.0, add -std1 to enable ANSI C features # and perhaps -g3 for more debugging info with optimization. # Some old versions of the HPUX C compiler have a bug in handling forward # struct tag declarations. Using the -Ac flag in place of -Ae will avoid # this problem (and reduce the compiler's error checking, unfortunately). # For install on 4BSD, SunOS #XINSTALL=/usr/ucb/install $(INSTALLFLAGS) -c -m 755 # -s #TINSTALL=/usr/ucb/install $(INSTALLFLAGS) -c -m 644 # newer Solaris 2.x aka SunOS 5.x #XINSTALL=/usr/gnu/bin/install $(INSTALLFLAGS) -m 755 #TINSTALL=/usr/gnu/bin/install $(INSTALLFLAGS) -m 444 # SysV-derivatives, or non-BSD Unix (V7, etc) #XINSTALL=cp #TINSTALL=cp Some acknowledgments. --------------------- Thanks to Jay (hack) Fenlason for writing the original pty code. Thanks to Dave Curry at Purdue for putting in tons of time and effort into getting JOVE ready. It just wouldn't be working without his help. Thanks to Jeff Mc Carrell at Berkeley for finding bugs and adding features, in particular, the comment formatter. Thanks to Karl Gegenfurtner for making the PC version. Thanks to Ken Mitchum for the Macintosh version. Thanks to Hugh Redelmeier for his input, his experience, countless bug fixes, and ... that's it, I guess. Thanks to Arlindo da Silva and Dave Curry for the original Cygwin ports. Thanks to Ken Mitchum for the original Mac port. (Thanks to Brian Harvey for teaching me about linked lists ...) Good luck, have fun. Jonathan Payne (once jpayne@starwave.com, sun.com, marimba.com :-) Thanks to Charles Lindsey for the xjove/jovetool and xterm mouse support. Thanks to Jim Patterson for the Win 32 port. Thanks to the other JoveHacks for testing and for contributing numerous fixes, portability enhancements, and pieces of sage advice. D. Hugh Redelmeier Thanks to Cord Beermann for Debian packaging, Peter Cock for conda packaging, Paul Vixie for FreeBSD packaging and many fixes. Mark Moraes Changes in 4.17.* ----------------- - github - Portability fixes, mainly removal of overlapping strcpy for Linux, *BSD, Darwin/MacOS, but also Windows and MinGW fixes, FreeDOS (!), OpenIndiana. 4.3BSD tested again! - Much build cleanup/revamp. Remove some ancient systems from sysdep.h since there seems no hope of testing them. - Use aspell if available on Linux - Handle terminals wider than 256 chars! - Handle line-numbering correctly if >1M lines! - Default line length max to 32K now - Fast/simple code to directly handle 99.9% of all currently used terminals (vt100+ derivatives) without needing termcap/terminfo/curses. - Do not allow writeback of files if lines were too long, and thus truncated, do not conflate shell output windows with files of the same name. - Horizontal scroll of the minibuffer. Changes in 4.16.* ------------------ - Portability fixes. Most important: work around a never-to-be-fixed bug in ncurses (the freely redistributable termcap/terminfo database). - Various minor bug fixes. Highlights: + use mkstemp to avoid a security loophole + avoid bad interaction between metakey and xterm mouse support in windows wider than 95 characters + handle symlinks better + obscure bug in text justification that could hang JOVE + misuse of stat that only misbehaved on LINUX Changes since 4.16beta ---------------------- - Added the variable paragraph-delimiter-pattern to customize paragraph recognition. - Ported to Win 32 (but not Win 32s) - Several variables have been renamed to more clearly indicate their function. The old name will still work, but eventually it will be eliminated. allow-bad-filenames => allow-bad-characters-in-filenames display-bad-filenames => display-filenames-with-bad-extensions internal-tabstop => tab-width - Several minor bugs fixed. Several portability improvements. + MSDOS: avoid date rollover problem + Borland C: support version 4 + Borland and Microsoft C: enable HIGHLIGHTING + NetBSD: dodge ssize_t redefinition + SCO UNIX: use + SunOS + Solaris: make charp effective + generic: Ensure screen is maintained during non-interactive processes, even if the user has typed ahead - The xterm mousing interface has been completely revamped. Some small ancillary consequences of this are + A next-line (prev-line) landing in the middle of a Tab selects the Tab character (rather than the following one) + A yank-pop is no longer permitted to follow a copy-region. Changes since version 4.14.6. ----------------------------- JOVE now works on many newer systems. For example, it compiles under Solaris 2.n (SYSDEFS=-DSYSVR4). The uninstalled binary in the JOVE directory is jjove instead of xjove (xjove is now something else). The new command line flag -J inhibits the reading of the global jove.rc file. Similarly, -j inhibits ~/.joverc. JOVE's auxiliary files are kept in two directories (actually, they can be the same directory). The sharedir holds the system jove.rc and cmds.txt, the data used to implement the describe-command and describe-variable commands; these files are meant to be machine-independent. The libdir holds portsrv and recover; these are compiled programs, and are machine-dependent. There are three ways JOVE uses to determine each of the directories, two of them new. If JOVE was invoked with -l dirname, dirname is taken as the LibDir; otherwise, if the environment contains JOVELIB, its value is taken as the LibDir; otherwise, the value of the make variable $(LIBDIR) when JOVE was compiled is used as LibDir. Similarly, -s dirname, JOVESHARE, and $(SHAREDIR) specify ShareDir. As a shortcut, -ls dirname specifies both directories. Now, a good way to test an uninstalled version of JOVE is to say, within the JOVE directory, jjove -s doc -l . other_parameters A new command "pushlibd" effectively does a pushd command with ShareDir as the operand. This is for use within startup files such as jove.rc. The global startup file is now in doc/jove.rc (was doc/system.rc), so the -s flag can find it as above. It contains lots of goodies (you might not want all of them), including an ability to call up additional TERMinal specific startup files depending on the $TERM environment variable. Among other things, these provide support for the many wacky keys that terminal makers provide. See doc/README. The old make-keymap and bind-keymap-to-key commands are no longer needed. Instead, bind-to-key can accept character strings of any length (they had better not be a prefix of any other binding). This enables, among other things, binding commands to the function keys on Sun keyboards. Buffer- specific bindings are now supported (local-bind-* commands). All system dependencies are now gathered together in the file sysdep.h, to make it easier to select the bits of code which should or should not be included for various flavors of UNIX. The position of the mark is now indicated by underlining it (the position of point is, of course, indicated by the cursor, so the extent of the region is now easily seen). The bad news is that, although this works well on terminals, underlining is broken in some environments (notably SunView and the versions of OpenWindows with SUNOS4.1.x and Solaris 2.0 -- Solaris 2.1+ is OK). For the broken OpenWindows versions, you can include the following in your .Xdefaults file term.boldStyle: Offset_X_and_Y term.underlineStyle: Same_as_Bold The stock X11 terminfo entry for xterm was broken until X11R6 in a way that will cause the screen to be scrambled when JOVE tries to use underlining. The following fixes to the entry solve this problem and more: replace "blink=@," with "blink@," replace "rs2=@" with "rs2@," [note the added comma!] add "kf1=\EOP," [if not already be present] delete "smul@," and "rmul@," [if present] add "smul=\E[4m, rmul=\E[m," [xterm does support underlining] The portion of the buffer visible in the window is now indicated by "uninverting" a part of the modeline in proportion. This feature is really intended for use with "xjove" (described next), and there is a variable "scroll-bar" to enable it. xjove is a complete front-end for JOVE which will be found in the directory xjove (see the README there). It enables setting of point and mark with the mouse, cutting and pasting of text via the region, and scrolling by pointing into the modeline. It is written using the XView library (supplied with Suns, or with the X-distribution from MIT); there is also a version for Sunview known as jovetool. See its man entry in doc/xjove.nr. An alternative way of using the mouse is provided in the form of commands designed to recognize the mouse events coded by Xterm. These facilities are not nearly as extensive or convenient as those provided via xjove or jovetool. Within SHELL windows, the TERM environment variable is now set to "dumb", mainly to discourage running programs which might have depended on something else. Some shells (tcsh, for example) might prefer the emacs terminal type; JOVE also sets the INSIDE_JOVE variable, which can be used to set things up for shells, as well as the proc-env-export, and proc-env-unset commands for subshells and corresponding iproc-env-export and iproc-env-unset commands for interactive processes. By default, commands requiring a "y" or "n" response require a Return as well. When variable "one-key-confirmation" is set "on", a single character "y" or "n" is expected. Some features have been removed. Marks always float, so the variable "marks-should-float" is gone. The IBMPC-specific commands scroll-*-page are gone. JOVE is now 8-bit clean (the old behavior can be retained by setting NCHARS to 128 in sysdep.h, but no known system requires this setting). In operating systems with the necessary support (USE_CTYPE set in sysdep.h) it is possible to set the environment variable LC_CTYPE (or the JOVE variable lc-ctype) to a "locale" such as "iso_8859_1", whereupon characters with the 8th bit set sent from the keyboard (using the Alt Graph key, or the Compose key, or the Meta key, or whatever the particular hardware provides) will be displayed correctly, and will be treated as upper/lower case, etc in the correct manner. The default locale is "C", which reverts to 7-bit ASCII with the top 128 characters being displayed in octal. The format of the "jrec" file (now "jr*" ) has changed. This means that previous versions of recover cannot deal with the files left by crashes of the new JOVE, and vice versa. 4.17+ recover will realize this. Here is a list of reasons why your .joverc might no longer work. JOVE places diagnostics about the user and system .joverc files in the buffer "RC errors". - JOVE no longer ignores extra stuff on the end of binding commands. - All keymap creation is implicit. You no longer can or need to create new keymaps explicitly. - auto-execute-command no longer magically supplies a numeric argument for its command. If the command is intended to set a mode, you should supply the argument. If you don't set the numeric argument, the mode will be flipped. Here is an example from the system jove.rc: 1 auto-execute-command c-mode .*\.[chy]$ - Within regular expressions, alternatives are separated by "\|". Previously, alternatives within braces were separated by ",". For example, "/tmp/\{Re,article,rnmail,pn\}" must be changed to "/tmp/\{Re\|article\|rnmail\|pn\}". - auto-execute-command and auto-execute-macro both require explicit patterns. Previously, the pattern would default to match every filename. - Certain commands and variables have been eliminated or renamed: bind-keymap-to-key, make-keymap, process-bind-keymap-to-key -- no longer needed unbind-key -- bind the "unbound" command instead marks-should-float -- they always do now physical-tabstop -- now picked up from termcap scroll-next-page, scroll-previous-page -- IBM PC only, and useless background-color => background-attribute -- IBM PC only foreground-color => foreground-attribute mode-line-color => mode-line-attribute - On the IBM PC, the Delete key now generates the ASCII DEL character; Control-@ and Control-Space now generate the ASCII NUL character. Known problems -------------- In an interactive process buffer, JOVE sometimes fails to receive an end-of-file through the pseudo-tty, reporting "[Process i-shell: Exited 0; not EOFed]" rather than "[Process i-shell: Done]". In this case, the process window will not be considered done, even though the child and all its ancestors are dead. The only consequences are that the status display continues to report that the process is not done and that another process may not be started up in that buffer. This only happens on certain systems, not sure why. For example, this worked fine upto Debian 9, and broke in Debian 10 (using SYSVR4 ptys), and is fixed by switching to GLIBCPTY. e.g. https://github.com/jonmacs/jove/issues/6 If a window-find command is issued while the current window's lines are numbered, the numbering may become wrong temporarily. We are working on this bug. JOVE can not handle lines longer than JBUFSIZ characters (usually 4096, but 512 on some small systems). Eliminating this limit is not easy. JBUFSIZ is 2^LG_JBUFSIZ, which can be raised; JOVE keeps NBUF such buffers in memory and reads/writes these from/to a temporary file, and lines may not exceed a buffer, so making LG_JBUFSIZ larger increases the max line length. However, it increases memory consumption, though that only matters on machines in the sub-megabyte range. JOVE can not handle NUL characters in the buffer. In most cases, they are discarded silently, another dubious feature. JOVE does not handle Unicode (aka UTF-8), it silently ignores LANG, locale etc. Fixing this limitation is not easy. Bug Reports and Maintenance. ---------------------------- Jonathan Payne no longer works on JOVE. A group of JOVE maintainers supports the github.com/jonmacs/jove releases and welcomes: - help or success reports or issues with porting for additional systems - bug reports (we may already have an explanation or fix) - suggestions for and implementations of improvements or additional features (we do try to keep JOVE small) See https://github.com/jonmacs/jove for JOVE updates. A mailing list for discussions and mutual help amongst JOVE users exists at jove-users _at_ freelists _DOT_ org jove-4.17.5.5/README.dos000066400000000000000000000364571501102521500143710ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## [Updated in February 2023] HOW TO GET STARTED WITH JOVE: ============================= JOVE for MSDOS is distributed in two forms. The source code version allows you to easily understand and modify JOVE. The executable version allows you to easily install JOVE without using a C compiler. Neither requires the other. Each distribution may be in the form of a .zip archive (smaller) or a .sfx archive (self-extracting executable zip, larger, may be disallowed by various security tools, though that may also be true for .zip). You can create a suitable archive (source on Un*x, executable on DOS/Windows) using make zip if you have a zip command installed. If you use pkunzip to unpack, be sure to use the -d flag to get it to correctly place files in subdirectories. If you need/prefer to use 7-zip, something like make ZIP=7z ZIPOPTS=a zip ZIPEXT=7z should work (though 7z does not make filenames DOS-friendly 8.3, probably does not matter for modern Windows machines) The source distribution for MSDOS (and WIN32 -- Windows/95 or later) is an archive called joveNNNs.zip, where NNN is a version number (for example, jove417s.zip for 4.17). The source archive contains all the source files needed to compile JOVE on an MSDOS or WIN32 machine. It differs in three ways from the generic JOVE source distribution. First, it is distributed in a conventional MSDOS format, rather than as a tar file. Second, certain files are left out because they are of no use under MSDOS (for example, the X Window System support) and may not fit the 8.3 naming straitjacket. Third, a few files are pre-built on UNIX and included because the tools to build them are not generally available under MSDOS (for example, the formatted documentation). The source distribution for MSDOS can be built from the generic distribution on UNIX with the command "make zip". The executable distribution for MSDOS on the IBM PC is an archive called joveNNNd.zip where NNN is a version number (e.g. 417 for 4.17). The archive contains all the files needed to use jove: the executables and the documentation. The executables are built for large model (maximum line length of 2048 bytes, can usually go upto 32K total lines across many buffers). Jove can also be compiled for medium model (slightly smaller memory footprint, maximum line lengths of 512 bytes, but likely to run out of memory or hit a temp file limit when editing lots of files at the same time, so not recommended, not recently tested) jove.exe JOVE editor executable. recover.exe This is the recover program to pull data back out of the temporary working file if JOVE or the PC previously crashed while editing. It is invoked by the JOVE -r option. May need to set the JOVELIB environment variable, or use the -l option to locate it if stored in a different location than the compiled-in default (lib-dir-pathname variable in JOVE, LIBDIR in paths.h, empty means same dir as jove.exe) doc\cmds.txt contains text for the describe-command and describe- variable command. If the compiled-in default does not work, then may need to set the JOVESHARE environment variable or use -s JOVE option doc\jove.man the complete JOVE manual doc\jove.txt the "manpage" for JOVE: describes how to run JOVE doc\jove.qre a plain text quick reference card with JOVE commands/variables doc\joveman.ps PostScript version of the JOVE manual for printing doc\jove.rc a system-default startuup file, see JOVESHARE doc\teachjov.txt Jove tutorial for -T option or teach-jove command, see JOVESHARE doc\example.rc other example startup configuration paths.h This file shows what the default directories JOVE was compiled with. The file itself is not used to run JOVE. README.dos This file. ENVIRONMENT VARIABLES USED BY JOVE: =================================== COMSPEC This variable is used to specify the default program to run as the SHELL. It can be overridden by the JOVE variable "shell". TMPDIR (or TEMP) JOVE uses the value of TMPDIR, or if that is not set, TEMP to determine the directory where it should put its temporary file. The default is c:\tmp (set by TMPDIR in the makefile when JOVE was compiled), and this is probably not what you want. In general editing is faster, if TEMP points to a ramdisk, like "set temp=d:". You have to know however that the temporary file can grow quite big when editing many big files at once. So please make sure that you have enough space available on your ramdisk. If JOVE runs out of space on the device which holds the temporary file, you have to leave the editor immediately. You can save your work without any trouble, but you have to start over. Please note also that the Large Model version of JOVE has a big cache for the temporary file in memory, which makes it quite fast even if you don't have a ramdisk. It is an MSDOS convention to use TEMP; use TMPDIR if you intend that the directory is solely for JOVE. Remember to create the temporary directory, since JOVE does not do that automatically (newer DOS versions usually have a temporary directory and set TEMP) JOVESHARE This variable specifies the path to the directory in which the documentation and support files for JOVE can be found (1) cmds.txt (the file of command and variable descriptions used by the describe-command and desribe-variable commands) and (2) the system-wide jove.rc (the first file that is sourced (executed) by JOVE when it starts up) and (3) the TEACHJOV.TXT tutorial that can be accessed with the "teach-jove" command within JOVE, or by starting JOVE with the -T option (different from -t; unlikes typical DOS programs, JOVE options are case-sensitive) If this is a relative path, JOVE will interpret it as relative to the directory containing the JOVE executable. The default is "doc" (set by SHAREDIR in the makefile when JOVE was compiled), which works if you either run a compiled JJOVE executable out of the source directory, or from the ZIP or (self-extracting) EXE file with the JOVE DOS binaries. JOVELIB This variable specifies the path to the directory in which the RECOVER.EXE program can be found, needed when JOVE is invoked with the -r option. As with JOVESHARE, a relative directory will be interpreted as relative to the same directory as the JOVE executable was found. The default is the empty string, which means the same directory as the JOVE executable, which works for either a source directory that was just compiled, or the pre-packaged ZIP or self-extracting EXE binary distributions. HOME The directory which is to be considered the user's home (as in UNIX). The default is the current directory on the current disk when JOVE was started. JOVE looks in this directory for the user's jove.rc startup file (this will be sourced after the system-wide jove.rc, unless HOME and JOVESHARE are the same). In filenames, an initial ~/ denotes the home directory. METAKEY If this environment variable is set, JOVE turns on its meta-key variable. DIFFERENCES BETWEEN JOVE UNDER MSDOS AND UNIX JOVE: =================================================== The MSDOS version of JOVE currently supports all of the features that are possible to implement under MSDOS in a reasonable way. The things that are missing under MSDOS are: spell-buffer (obsolete under MSDOS) interactive shells in a window (not possible) There are however some features added, which are specific to the PC version: Variables: text-attribute specifies the background and foreground colors of the screen. The default value is 0x07, which stands for white on black. The attribute used for writing to the screen is formed by (bg&7)<<4 & (fg&7). Mode-line-attribute specifies the background and foreground colors of the modeline. Its default value is 0, and in that case it is drawn in reverse video. If it has any other value, this value is used as the attribute in Bios calls. (note that on a monochrome monitor the best thing is to leave the default colors - anything else can lead to blank screens very easily) General: JOVE on the IBM PC supports the whole 8 bit character set of the IBM PC. You can use all the line drawing characters in your files. It also knows about some special foreign characters (Umlaute), which are treated correctly as part of words and in case conversions. It knows about and has special bindings for most of the non-ASCII keys (such as the function keys and the ALT shift key). VIDEO MODES ON THE IBM PC UNDER DOS: ==================================== When JOVE is started, it automatically checks which video mode is currently used, and adjusts itself correspondingly. This means that JOVE will work correctly even in 40x25 mode. If you have an EGA or VGA card, and want to use a special mode with 25, 28, 43, or 50 lines, set the environment variable TERM to the value EGAn. This will tell JOVE to set the screen in 80xn mode. The regular 80x25 mode is restored upon exit. On a color monitor, you can change the screen colors by using the commands mentioned above. SPECIAL KEYS ON THE IBM PC UNDER DOS AND WIN32: =============================================== JOVE checks to see if an enhanced AT-style keyboard is available and if so it will recognize use of the F11 and F12 keys plus numerous Alt/Shift/Control keys that cannot be generated with the basic keyboard BIOS. This check can be overridden by setting the enhanced-keyboard variable in the jove.rc file. JOVE turns Ctrl-Space into NUL. This makes the keyboard match most others, and makes it easy to invoke the set-mark command. JOVE turns a Delete keystroke into a DEL character. Surprisingly, this isn't done by the BIOS. DEL is also generated by Ctrl-BackSpace, so a distinction is lost. If you are used to IBM PC conventions, you may wish to bind DEL to delete-next-character (its standard binding is to delete-previous-character). JOVE maps the shifted arrow, Insert, Delete, Home, End, PgUp, and PgDn keys to codes distinct from the unshifted keys. This allows them to be bound differently. If the meta-key variable is on, the ALT key acts like a META key -- any key typed while it is depressed generates an ESC before the normal code. Otherwise, any key typed while ALT is depressed generates a special PCNONASCII code and the scan code for the key. JOVE supplies a keymap for the PCNONASCII code. COMPILING JOVE UNDER MSDOS: =========================== If JOVE is compiled using "Large Model", it can freely use all of the available portion of the normal 640kB memory. If it is compiled using "Medium Model", all of its data (except for line descriptors) must fit in 64kB; one consequence is that JOVE's tempfile cache is severely reduced. The advantage of Medium Model is that JOVE's object code is somewhat smaller. JOVE has been compiled (2023 February) for DOS with the Open Watcom 1.9.0 compiler (which was downloaded circa 2020 from http://ftp.openwatcom.org/install/open-watcom-c-dos-1.9.exe), tested under FreeDOS 1.2 and the dosbox emulator (0.74-4.2+deb9u2build0.16.04.1 on Ubuntu 16.04) using wmake -f Makefile.wat in the source unpacked from jove417s.zip (made on a Unix/Linux machine) Since this is not a primary platform for current JOVE maintainers, new testers (and bug reports/patches) are welcome. The following AUTOEXEC.BAT was used: PATH C:\WATCOM\BINW;%PATH% SET INCLUDE=C:\WATCOM\H SET WATCOM=C:\WATCOM SET EDPATH=C:\WATCOM\EDDAT SET WIPFC=C:\WATCOM\WIPFC The following CONFIG.SYS was used: FILES=20 A wildargv.c file was downloaded from https://tinyurl.com/ow-wildargv a.k.a http://perforce.openwatcom.org:4000/@md=d&cd=//depot/openwatcom/bld/clib/startup/c/&cdf=//depot/openwatcom/bld/clib/startup/c/wildargv.c&sr=28826&c=7po@//depot/openwatcom/bld/clib/startup/c/wildargv.c though that link may not work after varioius acquisitions. JOVE was once compiled with version 8.0 of the Microsoft C compiler a.k.a. Visual C. It might have also compiled with versions 6 or 7 but that was never confirmed. The makefile called Makefile.msc might be adaptable to this, patches are welcome. Try nmake /f Makefile.msc WIN32=0 JOVE was once compiled (1994 July) with version 3.1 of Borland's C compiler. Extract relevant files/definitions from old/Makefile.bcc and old/sysdep.h, which will likely require some tweaking in order to be brought uptodate. Patches are welcome. Without newer build validation and test, this support is likely to be deleted from future versions of JOVE. JOVE was once compiled (1996 May) with version 3.0 of Zortech's C compiler. If that is desired again, try old/Makefile.zor and definitions from old/sysdep.h, patches are welcome. Without newer build validation and test, this support is likely to be deleted from future versions of JOVE. JOVE once supported MSDOS on hardware that is not IBM PC compatible. In particular, use -DRAINBOW for the DEC Rainbow computer (this series hasn't been manufactured since the mid 1980s). This hasn't been tested recently. JOVE was once ported to TOS on the Atari ST, which is much like MSDOS but not at all like the IBM PC. Without newer build validation and test, this support is likely to be deleted from future versions of JOVE. MSDOS ON MACHINES NOT COMPATIBLE WITH THE IBM PC ================================================ JOVE was once ported to MSDOS machines that were not IBM PC clones. One example for which there is special code is the DEC Rainbow. Another was the Atari ST (although the specific code for it is not included in our current source). Still others were generic MSDOS machines such as the Nabu 1600. Although the source code still has provisions for these, it has not been tested for a very long time and so is probably no longer quite right. The next two variables are not used by the IBM PC version, and have to do with specifying the type of terminal in use on a generic MSDOS computer. TERM This variable should specify the name of the terminal you are using. For example, if you have a DEC vt-100 terminal attached to your MSDOS computer, you should give the command "set TERM=vt100" prior to starting JOVE. TERMCAP This environment variable holds the name of a database with descriptions of different terminal types. If you are familiar with the UNIX operating system, you probably know about TERMCAP. For each terminal type, specified by TERM, the TERMCAP database holds an entry, which describes how to set the cursor, how to scroll, and many other things, for that particular terminal. A small example TERMCAP file comes with JOVE. If your terminal is not included there, you should ask a local UNIX guru for help. If you don't have one, you can ask github.com/jonmacs/jove The original port of JOVE to the IBM PC was done by Karl Gegenfurtner (karl@hipl.psych.nyu.edu). Karl's port was modified for Zortech C by D. Hugh Redelmeier). Joe Smith (jes@mbio.med.upenn.edu) ported to Borland C. Several others, including Jim Patterson (jimp@cognos.com) and Gary Puckering (garyp@cognos.com) updated the Microsoft port. Mark Moraes re-ported to Win32 and DOS in in Feb 2020 and continues to test sporadically on those platforms. jove-4.17.5.5/README.win000066400000000000000000000327421501102521500143720ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## [Updated in Feb 2023] Jove for WIN32 ============== While Windows (or DOS) are not primary platforms for the JOVE developers, some effort is been made to test JOVE on both. Jove can be built for WIN32 (that is, Windows versions after Windows/95) natively with Microsoft Visual C (MSVC), or cross-compiled with {i686,x86-64}-w64-mingw32 on Linux. The MSDOS source distribution zip may be preferable for MSVC builds because it contains pre-built documentation files which must be created on a UNIX system, and excludes some things only of use on UNIX (for example, X Window System support). The filename of the MSDOS source distribution is a name that includes the version number joveNNNs.zip (for example, jove417s.zip for version 4.17), created by running 'make zip' on a Unix/Linux/*BSD system, make zip A pre-compiled (via MINGW) and ready-to-run copy of JOVE for WIN32 is distributed in archives with the names jove-N.N.N.N-x86_64-w64-mingw32.zip (64bit binaries, 4.17.0.5 on), jove-N.N.N.N-i686-w64-mingw32.zip (32bit binaries). Older distributions (4.16, early 4.17) used joveNNNw.zip (for example, jove416w.zip for version 4.16). Jove for WIN32 has usually been lightly tested on the Win7 platform, but is expected to work on older versions like Windows/95, 98, NT, 2000, XP, etc, and might work on newer versions like Win8 and Win10. Test and bug reports are welcome, though the Jove developers are primarily from Unix-land. Jove for WIN32 does not function under the WIN32s environment (which is a special subsystem of Windows 3.1). The primary reason is that WIN32s doesn't support the WIN32 Console API, which Jove for WIN32 depends on in order to display text on the screen and accept and interpret keystrokes. For such environments, use the MSDOS version. The original port of Jove to WIN32 was performed by Jim Patterson (Jim.Patterson@Cognos.COM) with the help and advice of D. Hugh Redelmeier as well as early testing and feedback by Gary Puckering (Gary.Puckering@Cognos.COM). Building Jove for WIN32 ======================= To build for WIN32 natively using Microsoft Visual C++ (2.0 or later), unpack a source distribution, setup the Visual C environment (typically, by running vcvars32.bat or starting a Developer Command window from Visual Studio), and use nmake /f Makefile.msc To cross-compile on a Unix/Linux machine with MinGW installed (e.g. on a modern Debian/Ubuntu/Mint, try "apt install mingw-w64"), and then use JMAKE_UNAME=i686-w64-mingw32 ./jmake.sh (DESTDIR=/none is a hack to avoid some Makefile complaints, it does not get used otherwise) Advantages of WIN32 version (over DOS) ====================================== Since Windows/NT and Windows/95 support native DOS applications like Jove, using the 16-bit version of JOVE is a perfectly acceptable alternative to using the WIN32 version. However, the WIN32 version does provide several advantages, as follows: 1. Long filenames. Windows/NT and Windows/95 allow filenames that go beyond DOS's 8.3 naming limitations. Jove for WIN32 uses long filenames by default, whereas Jove for DOS can only see the 8.3 versions of filenames. Jove for WIN32 is also able to directly access files in UNC format, i.e. with an explicit network name. Jove for DOS can only access network files via an associated drive letter. 2. Window sizing. WIN32 consoles can be dynamically resized. When running a 16-bit application like JOVE, resizing is disabled. However, Jove for WIN32 responds to resizing events and reconfigures its display, just like it does under UNIX when it receives a SIGWINCH signal. 3. 32-bit limits. Jove for WIN32 is a 32-bit application, and so is less prone to size constraints than its 16-bit DOS cousin (though through clever coding even 16-bit DOS Jove is able to handle a lot files of a considerable size). It is hoped that Jove works on 64bit Windows as well. 4. 32-bit Performance. Jove for WIN32 should perform, and behave, better than Jove for DOS on a suitable platform for several reasons. - Flat address space (no segment register loading). - Poll-free operation. Jove for DOS uses a polling loop as it waits for input if it needs to display the time on the mode line or wait for a delayed refresh. Jove for WIN32 can use WIN32 Wait... functions to do this, which permit it to cooperate with other tasks more effectively. 5. Its own Icon. Since Jove for WIN32 is a Windows executable, it can have its own icon. No more hunting around in MORICONS.DLL for something suitable. (If you don't like my planet icon, feel free to craft another; I'm not an artist)! 6. Non-Intel platforms, in theory. Jove for WIN32 might port easily to other WIN32 platforms e.g. Alpha and PowerPC (though it hasn't actually been built on any of these). The performance advantage of having native applications might be considerable, since these platforms must use software emulation to run 16-bit DOS applications. (If anyone has such a platform, and wants to use JOVE on it, please open a github issue, would love to hear about the port) One functional difference is that under Windows/95 there is apparently no way to dynamically resize the console window as there is under Windows/NT. There is no code specifically to support Windows/95, though some design decisions were based on the need to support it. ENVIRONMENT VARIABLES USED BY JOVE: =================================== COMSPEC This variable is used to specify the default program to run as the SHELL. It can be overridden by the JOVE variable "shell" or by the SHELL environment variable. TMPDIR (or TEMP) JOVE uses the value of TMPDIR, or if that is not set, TEMP to determine the directory where it should put its temporary file. The default is c:\tmp (set by TMPDIR in the makefile when JOVE was compiled), and this is probably not what you want. In general editing is faster, if TEMP points to a ramdisk, like "set temp=d:". You have to know however that the temporary file can grow quite big when editing many big files at once. So please make sure that you have enough space available on your ramdisk. If JOVE runs out of space on the device which holds the temporary file, you have to leave the editor immediately. You can save your work without any trouble, but you have to start over. Please note also that the Large Model version of JOVE has a big cache for the temporary file in memory, which makes it quite fast even if you don't have a ramdisk. It is an MSDOS convention to use TEMP; use TMPDIR if you intend that the directory is solely for JOVE. JOVESHARE This variable specifies the path to the directory that contains (1) cmds.txt (the file of command and variable descriptions used by the describe-command and describe-variable commands) (2) the system-wide jove.rc (the first file that is sourced (executed) by JOVE when it starts up) and (3) The teach-jove tutorial, which can be loaded by either starting JOVE with the -T option (case-sensitive options) or by invoking the teach-jove command within JOVE. A relative path will be interpreted as relative to the location of the JOVE executable binary. The default is "doc" (set by JSHAREDIR in the Makefile when JOVE was compiled), which is fine for either running JJOVE.EXE from the source directory, or JOVE.EXE from the binary distributions. JOVELIB This variable specifies the path to the directory that contains RECOVER.EXE, needed for the JOVE -r option, to recover any data after a machine or JOVE crash (hopefully rare). Default is empty, which means the same directory as the JOVE executable (same relative interpretation as JOVESHARE) HOME The directory which is to be considered the user's home (as in UNIX). The default is the current directory on the current disk when JOVE was started. JOVE looks in this directory for the user's jove.rc startup file (this will be sourced after the system-wide jove.rc, unless HOME and JOVESHARE are the same). In filenames, an initial ~/ denotes the home directory. HOMEDRIVE, HOMEPATH These variables are used together, or not at all. If HOME is not set but HOMEDRIVE and HOMEPATH are, then the home directory is taken to be the concatenation of their values. HOMEDRIVE and HOMEPATH are part of the default Windows NT user environment. They are not typically set on a Windows 95 system (but Jove will use them as described if they are). SHELL This defines an alternate shell for JOVE to use when running commands with shell-command. It overrides COMSPEC if provided. Managing the console for Jove ============================= In many (but not all) respects, WIN32 Consoles are more flexible than DOS shell windows. Here are a few tricks for setting up a Jove console the way you like it. - Jove will set up its screen to match the current Window. This is often the same size as the current "console buffer" but the window may be smaller in size in which case scroll bars will appear. When the screen buffer changes size, Jove will resize its screen buffer. However, Jove can't always tell if the window size changes. Use a clear-and-redraw (typically bound to ESC ^L) to force Jove to resize its screen. - You can use a MODE command to interactively cause Jove to resize its window if you want to do this, say, from a jove.rc file. For example, this sets up a 40 line 100 column window: shell-command-no-buffer mode con lines=40 cols=100 - A better way to set up the screen size under NT is to use the window properties. If you choose to save these settings, they will then apply whenever you run that application. - You can set up a "file association" for Jove under NT, and set up the Jove as the program to handle a file. It's not immediately obvious how to change the default screen size. The problem is that with an association, the file you launch is what the settings are tied to; each different file gets its own file settings. To get around this, use this as the command line instead: start jove %1 This works because the window settings are associated with the window title, not the application. When started this way the window title is always "Jove", so settings can be used for all files launched with that association. This has an unfortunate size effect of obscuring the Jove window, however. If someone finds a better setup, please broadcast it! Development Notes: ================== Since Jove was originally developed on Unix, and is still primarily developed/tested in the Linux/Unix/*BSD world, it is still an awkward fit for Windows, unfortunately. Jove for WIN32 and Jove for DOS share some code, but also have considerable OS-specific code. The following manifests are used to flag code for the MS-DOS and/or WIN32 versions of Jove (they are explained more fully in sysdep.txt) IBMPCDOS - flags features specific to IBM PC hardware running DOS. MSDOS - describes code that is specific to the 16-bit DOS version of Jove. WIN32 - describes code specific to the 32-bit Windows version of Jove. MSFILESYSTEM - enables aspects of Jove to support Microsoft file systems. MSDOS_PROCS - enables use of the spawn series of APIs that replace fork/exec. DIRECTORY_ADD_SLASH indicates that file browsing will flag directories. TEXTFILE_ADD_CR instructs Jove to strip/add CRs from lines of text files. FILENAME_CASEINSENSITIVE indicates that case is not significant for filenames. Most of the support code for Jove for WIN32 resides in the file win32.c. The MSDOS files MSDOS.C and PCSCR.C are not used for Jove for WIN32. TO DO ===== There are some opportunities for additional work to make Jove for WIN32 more useable and functional. 1. Add IPROC support. WIN32 supports pipes, which mean that it's conceptually possible to support IPROCs using methods similar to that of the UNIX PIPEPROC support. In fact, WIN32 IPROC should be somewhat cleaner than PIPEPROCs because the API avoids the need for a third process. However, the reality of WIN32 pipes seems to be somewhat different, and my own attempts to get them to work have so far failed (though the single direction pipes used for a simple SUBSHELL do seem to function okay). 2. Add MOUSE support. The current input model for WIN32 could easily be extended to support mouse events. It's just necessary to enable the mouse in the SetConsoleMode call, and then process the mouse events as they arrive. The main obstacle is in coming up with a good command model. There are two different mouse command models supported by Jove right now, one for X and one for SunView; no doubt there are reasons that neither one is totally appropriate in the Windows world. Known Bugs: ========== - Under Windows 95, the CAPS LOCK key also shifts non-alpha keys (e.g. numerics and []). This seems to be a bug in the Windows 95 Console API implementation: the Event.KeyEvent.uChar.AsciiChar field for the keyboard event is set incorrectly. - The much touted icon doesn't appear under Windows 95. Once Windows 95 sees that it's not a "real Windows application", it assumes that a standard console icon is good enough. - Occasionally, when Jove is started under Windows 95, it does not display anything until a key is pressed. We haven't tracked down what circumstances cause this; it seems to happen more often with certain machine configurations. jove-4.17.5.5/abbrev.c000066400000000000000000000144041501102521500143160ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #ifdef ABBREV /* the body is the rest of this file */ #include "fp.h" #include "jctype.h" #include "abbrev.h" #include "ask.h" #include "commands.h" /* for ExecCmd() */ #include "delete.h" #include "insert.h" #include "disp.h" #include "fmt.h" #include "move.h" #include "wind.h" #define HASHSIZE 20 struct abbrev { unsigned int a_hash; char *a_abbrev, *a_phrase; struct abbrev *a_next; const data_obj *a_cmdhook; }; private void define proto((struct abbrev **, char *, char *)); #define GLOBAL NMAJORS private struct abbrev *A_tables[NMAJORS + 1][HASHSIZE]; /* Must be zeroed! */ jbool AutoCaseAbbrev = YES; /* VAR: automatically do case on abbreviations */ private unsigned int hash(a) register const char *a; { register unsigned int hashval = 0; register char c; while ((c = *a++) != '\0') hashval = (hashval << 2) + c; return hashval; } private void def_abbrev(table) struct abbrev *table[HASHSIZE]; { char abbrev[100], phrase[100]; jamstr(abbrev, ask((char *)NULL, "abbrev: ")); jamstr(phrase, ask((char *)NULL, "abbrev: %s phrase: ", abbrev)); define(table, abbrev, phrase); } private struct abbrev * lookup_abbrev(table, abbrev) register struct abbrev *table[HASHSIZE]; register const char *abbrev; { register struct abbrev *ap; unsigned int h; h = hash(abbrev); for (ap = table[h % HASHSIZE]; ap; ap = ap->a_next) if (ap->a_hash == h && strcmp(ap->a_abbrev, abbrev) == 0) break; return ap; } private void define(table, abbrev, phrase) register struct abbrev *table[HASHSIZE]; char *abbrev, *phrase; { register struct abbrev *ap; ap = lookup_abbrev(table, abbrev); if (ap == NULL) { register unsigned int h = hash(abbrev); ap = (struct abbrev *) emalloc(sizeof *ap); ap->a_hash = h; ap->a_abbrev = copystr(abbrev); h %= HASHSIZE; ap->a_next = table[h]; ap->a_cmdhook = NULL; table[h] = ap; } else free((UnivPtr) ap->a_phrase); ap->a_phrase = copystr(phrase); } void AbbrevExpand() { char wordbuf[100]; register char *wp = wordbuf, *cp; int col; register char c; int UC_count = 0; struct abbrev *ap; col = curchar; while (col != 0 && jisident(linebuf[col - 1])) col -= 1; if (curchar-col >= (int)sizeof(wordbuf)) return; /* too long for us -- ignore it */ while (col < curchar) { c = linebuf[col]; if (AutoCaseAbbrev && jisupper(c)) { UC_count += 1; c = CharDowncase(c); } *wp++ = c; col += 1; } *wp = '\0'; if ((ap = lookup_abbrev(A_tables[curbuf->b_major], wordbuf)) != NULL || (ap = lookup_abbrev(A_tables[GLOBAL], wordbuf)) != NULL) { del_char(BACKWARD, (int)(wp - wordbuf), NO); for (cp = ap->a_phrase; (c = *cp) != '\0'; ) { if (UC_count > 0 && jislower(c) && (cp == ap->a_phrase || (UC_count > 1 && (jiswhite(cp[-1]) || cp[-1] == '-')))) c = CharUpcase(c); insert_c(c, 1); cp += 1; } if (ap->a_cmdhook != NULL) ExecCmd(ap->a_cmdhook); } } private const char *const mode_names[NMAJORS + 1] = { "Fundamental Mode", "Text Mode", "C Mode", #ifdef LISP "Lisp Mode", #endif "Global" }; private void save_abbrevs(file) char *file; { File *fp; struct abbrev *ap, **tp; char buf[LBSIZE]; int i, count = 0; fp = open_file(file, buf, F_WRITE, YES); for (i = 0; i <= GLOBAL; i++) { fwritef(fp, "------%s abbrevs------\n", mode_names[i]); for (tp = A_tables[i]; tp < &A_tables[i][HASHSIZE]; tp++) for (ap = *tp; ap; ap = ap->a_next) { fwritef(fp, "%s:%s\n", ap->a_abbrev, ap->a_phrase); count += 1; } } f_close(fp); add_mess(" %d written.", count); } private void rest_abbrevs(file) char *file; { int mode = -1, /* Should be ++'d immediately */ lnum = 0; char *phrase_p; File *fp; char buf[LBSIZE]; fp = open_file(file, buf, F_READ, YES); while (mode<=GLOBAL && !f_gets(fp, genbuf, (size_t) LBSIZE) && genbuf[0] != '\0') { static const char sep[] = "------"; lnum += 1; if (strncmp(genbuf, sep, sizeof(sep)-1) == 0) { mode += 1; } else if (mode == -1 || (phrase_p = strchr(genbuf, ':')) == NULL) { complain("Abbrev. format error, line %d.", file, lnum); /* NOTREACHED */ } else { *phrase_p++ = '\0'; /* Null terminate the abbrev. */ define(A_tables[mode], genbuf, phrase_p); } } f_close(fp); message(NullStr); } void DefGAbbrev() { def_abbrev(A_tables[GLOBAL]); } void DefMAbbrev() { def_abbrev(A_tables[curbuf->b_major]); } void SaveAbbrevs() { char filebuf[FILESIZE]; save_abbrevs(ask_file((char *)NULL, (char *)NULL, filebuf)); } void RestAbbrevs() { char filebuf[FILESIZE]; rest_abbrevs(ask_file((char *)NULL, (char *)NULL, filebuf)); } void EditAbbrevs() { char tname[128]; static const char EditName[] = "Abbreviation Edit"; Buffer *obuf = curbuf, *ebuf; if ((ebuf = buf_exists(EditName)) != NULL) { if (ebuf->b_type != B_SCRATCH) confirm("Over-write buffer %b? ", ebuf); } SetBuf(ebuf = do_select(curwind, EditName)); ebuf->b_type = B_SCRATCH; buf_clear(ebuf); /* Empty buffer. Save the definitions to a tmp file * and read them into this buffer so we can edit them. */ PathCat(tname, sizeof(tname), TmpDir, #ifdef MAC ".jabbXXX" /* must match string in mac.c:Ffilter() */ #else "jaXXXXXX" #endif ); /* do a safe form of mktemp */ close(MakeTemp(tname, "abbrevs")); save_abbrevs(tname); setfname(ebuf, tname); read_file(tname, NO); message("[Edit definitions and then type ^X ^C]"); Recur(); /* We edit them ... now */ if (IsModified(ebuf)) { file_write(tname, NO); rest_abbrevs(tname); } (void) unlink(tname); if (valid_bp(obuf)) SetBuf(do_select(curwind, obuf->b_name)); } void BindMtoW() { struct abbrev *ap; const char *word = ask((char *)NULL, "Word: "); if ((ap = lookup_abbrev(A_tables[curbuf->b_major], word)) == NULL && (ap = lookup_abbrev(A_tables[GLOBAL], word)) == NULL) { complain("%s: unknown abbrev.", word); /* NOTREACHED */ } ap->a_cmdhook = findmac("Macro: "); } #endif /* ABBREV */ jove-4.17.5.5/abbrev.h000066400000000000000000000015411501102521500143210ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef ABBREV /* the body is the rest of this file */ extern void AbbrevExpand proto((void)); /* Variables: */ extern jbool AutoCaseAbbrev; /* VAR: automatically do case on abbreviations */ /* Commands: */ extern void BindMtoW proto((void)), DefMAbbrev proto((void)), DefGAbbrev proto((void)), SaveAbbrevs proto((void)), RestAbbrevs proto((void)), EditAbbrevs proto((void)); #endif /* ABBREV */ jove-4.17.5.5/argcount.c000066400000000000000000000052421501102521500146770ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" int arg_state = AS_NONE; long arg_count; void negate_arg() { if (arg_count < 0) { arg_count = -arg_count; if (arg_count < 0) { complain("arg count overflow"); /* NOTREACHED */ } } else { arg_count = -arg_count; } } private void gather_argument(ns, nc) int ns, /* new state */ nc; /* new count */ { for (;;) { ZXchar c; jbool neg = NO; if (arg_count < 0) { neg = YES; negate_arg(); } if (ns != arg_state) { /* First time in this state */ arg_state = ns; arg_count = nc; /* ignore previous value (but remember sign) */ } else { /* Continuing in this state. */ long t = arg_count; switch (ns) { case AS_NUMERIC: t = t*10 + nc; /* add a digit to previous value */ break; case AS_NEGSIGN: neg = !neg; /* change previous sign */ break; case AS_TIMES: t *= nc; /* multiply by factor */ break; } if (t < arg_count) { complain("arg count overflow"); /* NOTREACHED */ } arg_count = t; } if (neg) negate_arg(); /* Treat a following digit as AS_NUMERIC. * If in AS_TIMES, accept a '-'. */ c = waitchar(); if (jisdigit(c)) { ns = AS_NUMERIC; nc = c - '0'; } else if (arg_state==AS_TIMES && c=='-') { ns = AS_NEGSIGN; /* forget multiplication */ nc = -1; } else { Ungetc(c); break; } } this_cmd = ARG_CMD; } void TimesFour() { gather_argument(AS_TIMES, 4); } void Digit() { if (LastKeyStruck == '-') { gather_argument(AS_NEGSIGN, -1); } else if (jisdigit(LastKeyStruck)) { gather_argument(AS_NUMERIC, LastKeyStruck - '0'); } else { complain((char *)NULL); /* NOTREACHED */ } } void Digit0() { gather_argument(AS_NUMERIC, 0); } void Digit1() { gather_argument(AS_NUMERIC, 1); } void Digit2() { gather_argument(AS_NUMERIC, 2); } void Digit3() { gather_argument(AS_NUMERIC, 3); } void Digit4() { gather_argument(AS_NUMERIC, 4); } void Digit5() { gather_argument(AS_NUMERIC, 5); } void Digit6() { gather_argument(AS_NUMERIC, 6); } void Digit7() { gather_argument(AS_NUMERIC, 7); } void Digit8() { gather_argument(AS_NUMERIC, 8); } void Digit9() { gather_argument(AS_NUMERIC, 9); } void DigitMinus() { gather_argument(AS_NEGSIGN, -1); } jove-4.17.5.5/argcount.h000066400000000000000000000031741501102521500147060ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* macros for getting at and setting the current argument count */ #define arg_value() arg_count #define arg_or_default(x) (is_an_arg()? arg_count : (x)) #define set_arg_value(n) { arg_state = AS_NUMERIC; arg_count = (n); } #define clr_arg_value() { arg_state = AS_NONE; arg_count = 1; } #define is_an_arg() (arg_state != AS_NONE) #define is_non_minus_arg() (arg_state != AS_NONE && arg_state != AS_NEGSIGN) #define save_arg(as,ac) { (ac) = arg_count; (as) = arg_state; } #define restore_arg(as,ac) { arg_count = (ac); arg_state = (as); } extern void negate_arg proto((void)); /* Commands: */ extern void Digit proto((void)), DigitMinus proto((void)), Digit0 proto((void)), Digit1 proto((void)), Digit2 proto((void)), Digit3 proto((void)), Digit4 proto((void)), Digit5 proto((void)), Digit6 proto((void)), Digit7 proto((void)), Digit8 proto((void)), Digit9 proto((void)), TimesFour proto((void)); /* private to macros */ extern int arg_state; /* NO, YES, or YES_NODIGIT */ extern long arg_count; #define AS_NONE 0 /* no arg */ #define AS_NUMERIC 1 /* numeric arg supplied */ #define AS_NEGSIGN 2 /* only minus sign supplied */ #define AS_TIMES 3 /* multiplicative request */ jove-4.17.5.5/ask.c000066400000000000000000000406011501102521500136310ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "chars.h" #include "disp.h" #include "fp.h" #include "scandir.h" #include "screen.h" /* for Placur */ #include "ask.h" #include "delete.h" #include "insert.h" #include "extend.h" #include "fmt.h" #include "marks.h" #include "move.h" #include "wind.h" #ifdef MAC # include "mac.h" #else /* !MAC */ # ifdef F_COMPLETION # include # endif #endif /* !MAC */ ZXchar AbortChar = CTL('G'); /* VAR: cancels command input */ jbool DispDefFs = YES; /* VAR: display default filenames in prompt? */ jbool Asking = NO; int AskingWidth; char Minibuf[LBSIZE]; private LinePtr CurAskPtr = NULL; /* points at some line in mini-buffer */ private Buffer *AskBuffer = NULL; /* Askbuffer points to actual structure */ /* The way the mini-buffer works is this: The first line of the mini-buffer * is where the user does his stuff. The rest of the buffer contains * strings that the user often wants to use, for instance, file names, or * common search strings, etc. If he types ^N or ^P while in ask(), we * bump the point up or down a line and extract the contents (we make sure * is somewhere in the mini-buffer). */ private Buffer * get_minibuf() { if (AskBuffer) { /* make sure it still exists */ register Buffer *b; for (b = world; b != NULL; b = b->b_next) if (b == AskBuffer) return b; } AskBuffer = do_select((Window *)NULL, "*minibuf*"); AskBuffer->b_type = B_SCRATCH; return AskBuffer; } /* Add a string to the mini-buffer. */ void minib_add(str, movedown) char *str; jbool movedown; { register Buffer *saveb = curbuf; SetBuf(get_minibuf()); LineInsert(1); ins_str(str); if (movedown) CurAskPtr = curline; SetBuf(saveb); } jbool InRealAsk = NO; private const char * real_ask(delim, d_proc, def, prompt) const char *delim, *def, *prompt; jbool (*d_proc) ptrproto((ZXchar)); { jmp_buf savejmp; ZXchar c; int prompt_len, prompt_off = 0, line_off = 0; const char *prompt_leftchar = "", *line_leftchar = ""; Buffer *saveb = curbuf; volatile jbool aborted = NO; jbool no_typed = NO; const data_obj *push_cmd = LastCmd; int saved_as, saved_ac; #ifdef MAC menus_off(); #endif if (InRealAsk) { complain((char *) NULL); /* NOTREACHED */ } save_arg(saved_as, saved_ac); push_env(savejmp); InRealAsk = YES; SetBuf(get_minibuf()); if (!inlist(AskBuffer->b_first, CurAskPtr)) CurAskPtr = curline; prompt_len = strlen(prompt); ToFirst(); /* Beginning of buffer. */ linebuf[0] = '\0'; modify(); makedirty(curline); if (setjmp(mainjmp)) { if (InJoverc) { /* this is a kludge */ aborted = YES; goto cleanup; } } this_cmd = OTHER_CMD; /* probably redundant */ for (;;) { int COMAX = CO - 3, nw; cmd_sync(); jdbg("prompt=\"%s\" plen=%d poff=%d cc=%d loff=%d linebuf=\"%s\"\n", prompt, prompt_len, prompt_off, curchar, line_off, linebuf); if (line_off > 0 && curchar < line_off) { /* might need to scroll right, just force recalc */ line_off = 0; line_leftchar = ""; prompt_off = 0; prompt_leftchar = ""; } #define PRWIDTH (prompt_len - prompt_off + SIWIDTH(prompt_off)) #define ASKWIDTH (PRWIDTH + curchar - line_off + SIWIDTH(line_off)) nw = ASKWIDTH; if (nw > COMAX) { int COMID = COMAX/2; if (prompt_len > COMID) { /* offset into prompt so it ends at center */ prompt_off = prompt_len - COMID + 1; prompt_leftchar = "!"; } else { prompt_off = 0; prompt_leftchar = ""; } nw = ASKWIDTH; if (nw > COMAX) { /* scroll buf left */ line_off = PRWIDTH + curchar - COMID - COMID/2; line_leftchar = "!"; } else { line_off = 0; line_leftchar = ""; } nw = ASKWIDTH; } jdbg("prompt=\"%s\" plen=%d poff=%d cc=%d loff=%d nw=%d linebuf=\"%s\"\n", prompt, prompt_len, prompt_off, curchar, line_off, nw, linebuf); if (!InJoverc) s_mess("%s%s%s%s", prompt_leftchar, &prompt[prompt_off], line_leftchar, &linebuf[line_off]); Asking = YES; AskingWidth = nw; c = getch(); if (c != '\0' && strchr(delim, c) != NULL) { if (d_proc == NULL_ASK_EXT || !(*d_proc)(c)) break; } else if (c == AbortChar) { message("[Aborted]"); aborted = YES; break; } else switch (c) { case CTL('N'): case CTL('P'): if (CurAskPtr != NULL) { long n = (c == CTL('P') ? -arg_value() : arg_value()); CurAskPtr = next_line(CurAskPtr, n); if (CurAskPtr == curbuf->b_first && CurAskPtr->l_next != NULL) CurAskPtr = CurAskPtr->l_next; (void) ltobuf(CurAskPtr, linebuf); modify(); makedirty(curline); Eol(); this_cmd = OTHER_CMD; } break; case CTL('R'): if (def != NULL) ins_str(def); else rbell(); break; default: dispatch(c); break; } if (curbuf != AskBuffer) SetBuf(AskBuffer); if (curline != curbuf->b_first) { CurAskPtr = curline; curline = curbuf->b_first; /* with whatever is in linebuf */ } } cleanup: pop_env(savejmp); LastCmd = push_cmd; restore_arg(saved_as, saved_ac); no_typed = (linebuf[0] == '\0'); strcpy(Minibuf, linebuf); SetBuf(saveb); InRealAsk = Asking = Interactive = NO; if (!aborted) { if (!PreEmptOutput()) { Placur(ILI, 0); flushscreen(); } if (no_typed) return NULL; } else { complain((char *)NULL); /* NOTREACHED */ } return Minibuf; } #ifdef STDARGS const char * ask(const char *def, const char *fmt, ...) #else /*VARARGS2*/ const char * ask(def, fmt, va_alist) const char *def; const char *fmt; va_dcl #endif { char prompt[128]; const char *ans; va_list ap; va_init(ap, fmt); format(prompt, sizeof prompt, fmt, ap); va_end(ap); ans = real_ask("\r\n", NULL_ASK_EXT, def, prompt); if (ans == NULL) { /* Typed nothing. */ if (def == NULL) { complain("[No default]"); /* NOTREACHED */ } ans = def; } return ans; } #ifdef STDARGS const char * do_ask(const char *delim, jbool (*d_proc) ptrproto((ZXchar)), const char *def, const char *fmt, ...) #else /*VARARGS4*/ const char * do_ask(delim, d_proc, def, fmt, va_alist) const char *delim; jbool (*d_proc) ptrproto((ZXchar)); const char *def; const char *fmt; va_dcl #endif { char prompt[128]; va_list ap; va_init(ap, fmt); format(prompt, sizeof prompt, fmt, ap); va_end(ap); return real_ask(delim, d_proc, def, prompt); } jbool OneKeyConfirmation = NO; /* VAR: single y or n keystroke sufficient? */ #ifdef STDARGS jbool yes_or_no_p(const char *fmt, ...) #else /*VARARGS1*/ jbool yes_or_no_p(fmt, va_alist) const char *fmt; va_dcl #endif { char prompt[128]; va_list ap; va_init(ap, fmt); format(prompt, sizeof prompt, fmt, ap); va_end(ap); for (;;) { if (OneKeyConfirmation) { ZXchar c; message(prompt); Asking = YES; /* so redisplay works */ AskingWidth = strlen(prompt); c = getch(); Asking = NO; if (c == AbortChar) { complain("[Aborted]"); /* NOTREACHED */ } switch (CharUpcase(c)) { case 'Y': return YES; case 'N': return NO; default: add_mess("[Type Y or N]"); Asking = YES; /* so cursor sits on question */ SitFor(10); break; } } else { const char *ans = ask((char *) NULL, prompt); if (caseeqn(ans, "yes", strlen(ans))) return YES; if (caseeqn(ans, "no", strlen(ans))) return NO; rbell(); } } /* NOTREACHED */ } #ifdef F_COMPLETION /* look for any substrings of the form $foo in linebuf, and expand * them according to their value in the environment (if possible) - * this munges all over curchar and linebuf without giving it a second * thought (I must be getting lazy in my old age) */ # ifndef MAC /* no environment in MacOS */ jbool DoEVexpand = YES; /* VAR: should we expand evironment variables? */ private void EVexpand() { register char c; register char *lp = linebuf, *ep; char varname[128], *vp, *lp_start; Mark *m = MakeMark(curline, curchar); while ((c = *lp++) != '\0') { if (c == '$') { lp_start = lp - 1; /* the $ */ vp = varname; /* Pick up env. variable name ([a-zA-Z0-9_]*) */ while (('a' <= (c = *lp++) && c <= 'z') || ('A' <= c && c <= 'Z') || ('0' <= c && c <= '9') || c == '_') *vp++ = c; *vp = '\0'; /* if we find an env. variable with the right * name, we insert it in linebuf, and then delete * the variable name that we're replacing - and * then we continue in case there are others ... */ if ((ep = getenv(varname)) != NULL) { curchar = lp_start - linebuf; ins_str(ep); del_char(FORWARD, (int)strlen(varname) + 1, NO); lp = linebuf + curchar; } } } ToMark(m); DelMark(m); } # endif /* !MAC */ private char *fc_filebase; jbool DispBadFs = YES; /* VAR: display filenames with bad extensions? */ char BadExtensions[sizeof(BadExtensions)] = /* VAR: extensions to ignore */ # ifndef MSFILESYSTEM /* .o: object code format * .Z .gz: compressed formats * .tar .zip .zoo: archive formats * .gif .jpg .jpeg .mpg .mpeg .tif .tiff .rgb: graphics formats * .dvi: TeX or ditroff output * .elc: compiled GNU EMACS code */ ".o .Z .gz .tar .zip .zoo .gif .jpg .jpeg .mpg .mpeg .tif .tiff .rgb .dvi .elc"; # else /* MSFILESYSTEM */ /* .obj .lib .exe .com .dll: object code files * .arc .zip .zoo: archive formats * .bmp .gif .jpg .mpg .tif .pcx: graphics formats * .wks .wk1 .xls: spreadsheet formats */ ".obj .lib .exe .com .dll .arc .zip .zoo .bmp .gif .jpg .mpg .tif .pcx .wks .wk1 .xls"; # endif /* MSFILESYSTEM */ private jbool bad_extension(name) char *name; { char *ip, *bads; size_t namelen = strlen(name), ext_len; # if defined(UNIX) || defined(MSFILESYSTEM) # ifdef DIRECTORY_ADD_SLASH if (strcmp(name, "./")==0 || strcmp(name, "../")==0) return YES; # else if (strcmp(name, ".")==0 || strcmp(name, "..")==0) return YES; # endif /* DIRECTORY_ADD_SLASH */ # endif /* UNIX || MSFILESYSTEM */ for (ip=bads=BadExtensions; *ip!='\0'; bads = ip+1) { if ((ip = strchr(bads, ' ')) == NULL) ip = bads + strlen(bads); ext_len = ip - bads; if (ext_len != 0 && ext_len < namelen # ifdef FILENAME_CASEINSENSITIVE && caseeqn(&name[namelen - ext_len], bads, ext_len)) # else && strncmp(&name[namelen - ext_len], bads, ext_len) == 0) # endif return YES; } return NO; } private jbool f_match proto((char* file)); /* needed to comfort MS Visual C */ private jbool f_match(file) char *file; { size_t len = strlen(fc_filebase); if (!DispBadFs && bad_extension(file)) return NO; return len == 0 # ifdef FILENAME_CASEINSENSITIVE || caseeqn(file, fc_filebase, len); # else || strncmp(file, fc_filebase, len) == 0; # endif } # ifndef DIRECTORY_ADD_SLASH private jbool isdir(name) char *name; { (void) do_stat(name, (Buffer *) NULL, DS_DIR); return was_dir; } # endif /* !DIRECTORY_ADD_SLASH */ private void fill_in(dir_vec, n) register char **dir_vec; int n; { jbool filter; for (filter = DispBadFs; ; filter = NO) { int minmatch = 0, numfound = 0, lastmatch = -1, i; for (i = 0; i < n; i++) { /* If filter is NO, we accept all entries * (either DispBadFs is NO, in which case filtering * was done when dir_vec was built, or DispBadFs * is YES, but we are trying again, after finding * no files passed the filter. */ if (!filter || !bad_extension(dir_vec[i])) { minmatch = numfound == 0 ? (int)strlen(dir_vec[i]) #ifdef FILENAME_CASEINSENSITIVE : jmin(minmatch, numcompcase(dir_vec[lastmatch], dir_vec[i])); #else : jmin(minmatch, numcomp(dir_vec[lastmatch], dir_vec[i])); #endif lastmatch = i; numfound += 1; } } if (numfound == 0) { if (!filter) { /* hopeless: complain and give up */ rbell(); break; } } else { jbool the_same = YES; /* After filling in, are we the same as when we were called? */ if (minmatch > (int)strlen(fc_filebase)) { if (minmatch >= LBSIZE - (fc_filebase - linebuf)) { len_error(JMP_COMPLAIN); /* NOTREACHED */ } the_same = NO; null_ncpy(fc_filebase, dir_vec[lastmatch], (size_t) minmatch); modify(); makedirty(curline); } Eol(); # ifndef DIRECTORY_ADD_SLASH if (numfound == 1 && fc_filebase[0] != '\0' && isdir(linebuf)) { the_same = NO; insert_c('/', 1); } # endif if (the_same) { add_mess(" [%s%s]", !filter && DispBadFs? "!" : NullStr, numfound == 1? "Unique" : "Ambiguous"); SitFor(7); } break; /* we're done */ } } } /* called from do_ask() when one of "\r\n ?" is typed. Does the right * thing, depending on which. */ private jbool f_complete(c) ZXchar c; { char dir[FILESIZE], **dir_vec; int nentries; # ifndef MAC /* no environment in MacOS */ if (DoEVexpand) EVexpand(); # endif if (c == CR || c == LF) return NO; /* tells ask to return now */ fc_filebase = strrchr(linebuf, '/'); # ifdef MSFILESYSTEM { char *p = strrchr(fc_filebase == NULL? linebuf : fc_filebase, '\\'); if (p != NULL) fc_filebase = p; if (fc_filebase == NULL) fc_filebase = strrchr(linebuf, ':'); } # endif /* MSFILESYSTEM */ if (fc_filebase != NULL) { char tmp[FILESIZE]; fc_filebase += 1; if ((size_t) (fc_filebase - linebuf) >= sizeof(tmp)) { len_error(JMP_COMPLAIN); /* NOTREACHED */ } null_ncpy(tmp, linebuf, (size_t) (fc_filebase - linebuf)); if (tmp[0] == '\0') strcpy(tmp, "/"); PathParse(tmp, dir); } else { fc_filebase = linebuf; strcpy(dir, "."); } if ((nentries = jscandir(dir, &dir_vec, f_match, fnamecomp)) == -1) { add_mess(" [Unknown directory: %s]", dir); SitFor(7); return YES; } if (nentries == 0) { add_mess(" [No match]"); SitFor(7); } else if (jiswhite(c)) { fill_in(dir_vec, nentries); } else { /* we're a '?' */ const int towidth = jmin((CO - 2), MAX_TYPEOUT); int i, maxlen = 0, ncols, line, entriespercol; TOstart("Completion"); Typeout("(! means file will not be chosen unless typed explicitly)"); Typeout("Possible completions (in %s):", dir); for (i = 0; i < nentries; i++) maxlen = jmax((int)strlen(dir_vec[i]), maxlen); maxlen += 4; /* pad each column with at least 4 spaces */ if (maxlen > towidth) maxlen = towidth; ncols = towidth / maxlen; entriespercol = (nentries + ncols - 1) / ncols; for (line = 0; line < entriespercol; line++) { int col, which = line, bufcol = 0; char buf[MAX_TYPEOUT + 1]; for (col = 0; col < ncols; col++) { if (which < nentries) { jbool isbad = DispBadFs && bad_extension(dir_vec[which]); swritef(buf+bufcol, sizeof(buf) - bufcol, "%s%-*s", isbad ? "!" : NullStr, maxlen - isbad, dir_vec[which]); } which += entriespercol; bufcol += maxlen; } Typeout("%s", buf); } TOstop(); } freedir(&dir_vec, nentries); return YES; } #endif /* F_COMPLETION */ /* ask for file or directory * * These are only different under MSFILESYSTEM. * Note: def and buf may be equal. */ #ifdef MSFILESYSTEM private #endif char * ask_ford(prmt, def, buf) const char *prmt; char *def, *buf; { /* Note: pr_name yields a pointer into its static buffer so * pretty_name will not be a pointer into def. This allows * us to accept *def and *buf being aliases. Otherwise we * could end up calling PathParse with aliases. (Yes, you * are looking at a battle scar.) */ char *pretty_name = pr_name(def, YES), prompt[128]; const char *ans; if (prmt == NULL) swritef(prompt, sizeof(prompt), ProcFmt); else jamstr(prompt, prmt); if (DispDefFs && def != NULL && *def != '\0') { size_t pl = strlen(prompt); swritef(prompt + pl, sizeof(prompt)-pl, "(default %s) ", pretty_name); if ((int)strlen(prompt) * 2 >= CO) prompt[pl] = '\0'; } #ifdef F_COMPLETION ans = real_ask("\r\n \t?", f_complete, pretty_name, prompt); /* note: *pretty_name may have been overwritten -- we can't use it */ if (ans == NULL && (ans = pr_name(def, YES)) == NULL) { complain("[No default file name]"); /* NOTREACHED */ } #else ans = ask(pretty_name, prompt); #endif PathParse(ans, buf); return buf; } #ifdef MSFILESYSTEM char * ask_file(prmt, def, buf) const char *prmt; char *def, *buf; { MatchDir = NO; return ask_ford(prmt, def, buf); } char * ask_dir(prmt, def, buf) const char *prmt; char *def, *buf; { MatchDir = YES; return ask_ford(prmt, def, buf); } #endif jove-4.17.5.5/ask.h000066400000000000000000000036651501102521500136470ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern jbool Asking, /* are we on read a string from the terminal? */ InRealAsk; /* are we currently executing real_ask()? */ extern int AskingWidth; /* width of question being asked */ extern char Minibuf[LBSIZE]; #define NULL_ASK_EXT ((jbool (*) ptrproto((ZXchar))) NULL) /* ask for file or directory (only different under MSFILESYSTEM) */ #ifdef MSFILESYSTEM extern char *ask_file proto((const char *prmt, char *def, char *buf)), *ask_dir proto((const char *prmt, char *def, char *buf)); #else extern char *ask_ford proto((const char *prmt, char *def, char *buf)); # define ask_file(prmt, def, buf) ask_ford(prmt, def, buf) # define ask_dir(prmt, def, buf) ask_ford(prmt, def, buf) #endif extern const char *ask proto((const char *, const char *, ...)), *do_ask proto((const char *, jbool (*) ptrproto((ZXchar)), const char *, const char *, ...)); extern jbool yes_or_no_p proto((const char *, ...)); extern void minib_add proto((char *str, jbool movedown)); /* Variables: */ extern ZXchar AbortChar; /* VAR: cancels command input */ extern jbool DispDefFs; /* VAR: display default filenames in prompt? */ #ifdef F_COMPLETION extern jbool DispBadFs; /* VAR: display filenames with bad extensions? */ extern char BadExtensions[128]; /* VAR: extensions (e.g. ".o") to ignore */ # ifndef MAC /* no environment in MacOS */ extern jbool DoEVexpand; /* VAR: should we expand evironment variables? */ # endif #endif extern jbool OneKeyConfirmation; /* VAR: single y or n keystroke sufficient? */ jove-4.17.5.5/buf.c000066400000000000000000000442721501102521500136370ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Contains commands that deal with creating, selecting, killing and * listing buffers, and buffer modes, and find-file, etc. */ #include "jove.h" #include "jctype.h" #include "disp.h" #include "ask.h" #include "extend.h" #include "fmt.h" #include "insert.h" #include "marks.h" #include "move.h" #include "sysprocs.h" #include "proc.h" #include "wind.h" #ifdef IPROCS # include "fp.h" # include "iproc.h" #endif #ifdef MAC # include "mac.h" #else # include #endif #ifdef AUTO_BUFS char *iobuff, *genbuf, *linebuf; #else char iobuff[LBSIZE], genbuf[LBSIZE], linebuf[LBSIZE]; #endif private void setbname proto((Buffer *, const char *)); private const char Mainbuf[] = "Main", NoName[] = "Sans un nom!"; Buffer *world = NULL, /* First in the list */ *curbuf = NULL, /* pointer into world for current buffer */ *lastbuf = NULL, /* Last buffer we were in so we have a default buffer during a select buffer. */ *perr_buf = NULL; /* Buffer with error messages */ /* Toggle BIT in the current buffer's minor mode flags. If argument is * supplied, a positive one always turns on the mode and zero argument * always turns it off. */ void TogMinor(bit) int bit; { if (is_an_arg()) { if (arg_value() == 0) curbuf->b_minor &= ~bit; else curbuf->b_minor |= bit; } else curbuf->b_minor ^= bit; UpdModLine = YES; } /* Creates a new buffer, links it at the end of the buffer chain, and * returns it. */ private Buffer *free_bufs = NULL; private Buffer * buf_alloc() { register Buffer *b, *lastbp; lastbp = NULL; for (b = world; b != NULL; b = b->b_next) lastbp = b; if (free_bufs != NULL) { b = free_bufs; free_bufs = b->b_next; } else { b = (Buffer *) emalloc(sizeof (Buffer)); } if (lastbp) lastbp->b_next = b; else world = b; b->b_first = NULL; b->b_next = NULL; #ifdef MAC b->Type = BUFFER; /* kludge, but simplifies menu handlers */ b->Name = NULL; #endif return b; } /* Make a buffer and initialize it. */ private Buffer * mak_buf() { register Buffer *newb; register int i; newb = buf_alloc(); newb->b_fname = NULL; newb->b_name = NoName; newb->b_marks = NULL; newb->b_themark = 0; /* Index into markring */ /* No marks yet */ for (i = 0; i < NMARKS; i++) newb->b_markring[i] = NULL; newb->b_modified = newb->b_diverged = NO; newb->b_type = B_FILE; /* File until proven SCRATCH */ newb->b_minor = 0; newb->b_major = TEXTMODE; newb->b_first = NULL; newb->b_map = NULL; #ifdef IPROCS newb->b_process = NULL; #endif buf_clear(newb); #ifdef MAC Bufchange = YES; #endif return newb; } void ReNamBuf() { setbname(curbuf, ask_buf((Buffer *)NULL, ALLOW_NEW)); } void FindFile() { char fnamebuf[FILESIZE]; (void) ask_file((char *)NULL, curbuf->b_fname, fnamebuf); SetABuf(curbuf); SetBuf(do_find(curwind, fnamebuf, YES, NO)); if (curbuf->b_diverged) rbell(); /* slight hint of divergence */ } private void mkbuflist(bnamp, ebnamp) register const char **bnamp; const char **ebnamp; { register Buffer *b; for (b = world; b != NULL; b = b->b_next) { if (b->b_name != NULL) { *bnamp++ = b->b_name; if (bnamp >= ebnamp) { complain("too many buffers to list"); /* NOTREACHED */ } } } *bnamp = NULL; } const char * ask_buf(def, flags) Buffer *def; int flags; { const char *defname = def != NULL? def->b_name : (char *)NULL; const char *bnames[200]; register const char *bname; register int offset; char prompt[100]; /* The test for % in the next definition is a kludge to prevent * the default buffer name in the prompt string from provoking * unintended formatting. Ugh! The name will still be the default. */ if (defname != NULL && strchr(defname, '%') == NULL) swritef(prompt, sizeof(prompt), ": %%f (default %s) ", defname); else jamstr(prompt, ProcFmt); mkbuflist(bnames, &bnames[elemsof(bnames)]); /* Secret bonus: if there is no default, ^R will insert curbuf's name. */ offset = complete(bnames, defname==NULL? curbuf->b_name : defname, prompt, flags | (defname == NULL? 0 : ALLOW_EMPTY)); if (offset < 0) bname = *Minibuf == '\0' && defname != NULL? defname : Minibuf; else bname = bnames[offset]; return bname; } void BufSelect() { register const char *bname; bname = ask_buf(lastbuf, ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW); SetABuf(curbuf); SetBuf(do_select(curwind, bname)); } private void BufNSelect(n) int n; { register Buffer *b; for (b = world; b != NULL; b = b->b_next) { if (b->b_name != NULL) { n -= 1; if (n == 0) { SetABuf(curbuf); SetBuf(do_select(curwind, b->b_name)); return; } } } complain("[No such buffer]"); /* NOTREACHED */ } void Buf1Select() { BufNSelect(1); } void Buf2Select() { BufNSelect(2); } void Buf3Select() { BufNSelect(3); } void Buf4Select() { BufNSelect(4); } void Buf5Select() { BufNSelect(5); } void Buf6Select() { BufNSelect(6); } void Buf7Select() { BufNSelect(7); } void Buf8Select() { BufNSelect(8); } void Buf9Select() { BufNSelect(9); } void Buf10Select() { BufNSelect(10); } private void delb_wind(b) register Buffer *b; { register Window *w = fwind; const char *alt = lastbuf != NULL && lastbuf != b? lastbuf->b_name : b->b_next != NULL? b->b_next->b_name : Mainbuf; do { Window *next = w->w_next; if (w->w_bufp == b) { if (one_windp() || alt != Mainbuf) (void) do_select(w, alt); else del_wind(w); } w = next; } while (w != fwind || w->w_bufp == b); } private Buffer * getNMbuf() { register Buffer *delbuf = buf_exists(ask_buf(curbuf, ALLOW_OLD | ALLOW_INDEX)); if (delbuf->b_modified) confirm("%s modified, are you sure? ", delbuf->b_name); return delbuf; } void BufErase() { register Buffer *delbuf = getNMbuf(); buf_clear(delbuf); } /* Free a buffer structure. * The actual struct is preserved to reduce the damage * from dangling references to it. They seem to be pervasive. * We try to reset enough that a dangling reference will be useless. */ private void kill_buf(delbuf) register Buffer *delbuf; { #ifdef IPROCS untieDeadProcess(delbuf); /* check for lingering processes */ #endif /* Clean up windows associated with this buffer * before it becomes invalid. */ delb_wind(delbuf); /* Resetting curbuf must be done after delb_wind since it can * have a side-effect of setting curbuf to delbuf. For the same * reason, delbuf must not be unlinked until after delb_wind. */ if (curbuf == delbuf) curbuf = NULL; if (lastbuf == delbuf) lastbuf = curbuf; /* even if NULL */ if (curbuf == NULL) SetBuf(curwind->w_bufp); /* unlink the buffer */ if (world == delbuf) { world = delbuf->b_next; } else { register Buffer *b; for (b = world; b->b_next != delbuf; b = b->b_next) ; b->b_next = delbuf->b_next; } if (perr_buf == delbuf) { ErrFree(); perr_buf = NULL; } lfreelist(delbuf->b_first); delbuf->b_first = delbuf->b_dot = delbuf->b_last = NULL; if (delbuf->b_name != NULL) { free((UnivPtr) delbuf->b_name); delbuf->b_name = NULL; } if (delbuf->b_fname != NULL) { free((UnivPtr) delbuf->b_fname); delbuf->b_fname = NULL; } flush_marks(delbuf); delbuf->b_marks = NULL; DelObjRef((data_obj *)delbuf->b_map); delbuf->b_map = NULL; delbuf->b_next = free_bufs; free_bufs = delbuf; #ifdef MAC Bufchange = YES; delbuf->Name = NULL; /* ??? this cannot legitimately matter */ #endif } /* offer to kill some buffers */ void KillSome() { register Buffer *b, *next; for (b = world; b != NULL; b = next) { next = b->b_next; if (!yes_or_no_p(IsModified(b)? "Kill %s [modified]? " : "Kill %s? ", b->b_name)) continue; if (IsModified(b) && yes_or_no_p("%s modified; should I save it? ", b->b_name)) { Buffer *oldb = curbuf; SetBuf(b); SaveFile(); SetBuf(oldb); } kill_buf(b); } } void BufKill() { kill_buf(getNMbuf()); } private const char *const TypeNames[] = { NULL, "Scratch", "File", "Process", }; void BufList() { register const char *fmt = "%2s %5s %-8s %-1s%-1s %-*s %-s"; register Buffer *b; int bcount = 1, /* To give each buffer a number */ buf_width = 11; jbool any_needsaving = NO, any_tempmodified = NO, any_ntbf = NO, any_diverged = NO; for (b = world; b != NULL; b = b->b_next) { buf_width = jmax(buf_width, (int)strlen(b->b_name)); if (b->b_type == B_FILE) any_needsaving |= IsModified(b); else any_tempmodified |= IsModified(b); any_ntbf |= b->b_ntbf; any_diverged |= b->b_diverged; } TOstart("Buffer list"); if (any_needsaving) Typeout("(* means buffer needs saving)"); if (any_tempmodified) Typeout("(+ means temporary buffer has been modified)"); if (any_ntbf) Typeout("(- means file hasn't been read yet)"); if (any_diverged) Typeout("(# means file has been changed since buffer was read or written)"); if (any_needsaving | any_tempmodified | any_ntbf | any_diverged) Typeout(NullStr); Typeout(fmt, "NO", "Lines", "Type", NullStr, NullStr, buf_width, "Name", "File"); Typeout(fmt, "--", "-----", "----", NullStr, NullStr, buf_width, "----", "----"); for (b = world; b != NULL; b = b->b_next) { char bnostr[10], linestr[10]; swritef(bnostr, sizeof(bnostr), "%d", bcount++); if (b->b_ntbf) strcpy(linestr, "?"); else swritef(linestr, sizeof(linestr), "%d", LinesTo(b->b_first, (LinePtr)NULL)); Typeout(fmt, bnostr, linestr, TypeNames[b->b_type], b->b_diverged ? "#" : NullStr, IsModified(b) ? (b->b_type==B_FILE? "*" : "+") : b->b_ntbf ? "-" : NullStr, buf_width, /* For the * (variable length field) */ b->b_name, filename(b)); if (TOabort) break; } TOstop(); } private void bufname(b) register Buffer *b; { char tmp[100]; const char *cp; int try = 1; if (b->b_fname == NULL) { complain("[No file name]"); /* NOTREACHED */ } cp = jbasename(b->b_fname); jamstr(tmp, cp); while (buf_exists(tmp)) { swritef(tmp, sizeof(tmp), "%s.%d", cp, try); try += 1; } setbname(b, tmp); } void buf_clear(b) register Buffer *b; { lfreelist(b->b_first); b->b_first = b->b_dot = b->b_last = NULL; (void) listput(b, b->b_first); SavLine(b->b_dot, NullStr); b->b_char = 0; AllMarkReset(b, b->b_dot); if (b == curbuf) getDOT(); diverge(b, NO); if (b->b_modified) UpdModLine = YES; b->b_ntbf = b->b_modified = NO; #ifdef USE_INO b->b_dev = 0; b->b_ino = 0; #endif b->b_mtime = 0; } /* Returns pointer to buffer with name NAME, or if NAME is a string of digits * returns the buffer whose number equals those digits. Otherwise, returns * NULL. */ Buffer * buf_exists(name) register const char *name; { register Buffer *bp; if (name == NULL) return NULL; for (bp = world; bp != NULL; bp = bp->b_next) if (strcmp(bp->b_name, name) == 0) return bp; return NULL; } /* Returns buffer pointer with a file name NAME, if one is found. * If target is NULL, all buffers are searched; otherwise, only * target is examined. Match is by inode (to catch links) or * canonical name. * * Divergence is diligently searched for. In particular, all * buffers are examined to see if they match the specified file, * in name or inode. If they do, divergence is checked (i.e. loss * of underlying file, change in inode number, or modification * time different from last visit). * * DS_REUSE can be used to avoid redundant stat calls. Use it * with care! */ jbool was_dir, /* do_stat found a directory */ was_file; /* do_stat found a (plain) file */ Buffer * do_stat(name, target, flags) register const char *name; Buffer *target; int flags; { register Buffer *b = NULL; Buffer *result = NULL; char fnamebuf[FILESIZE]; static struct stat stbuf; PathParse(name, fnamebuf); if ((flags & DS_REUSE) == 0) { if (stat(fnamebuf, &stbuf) < 0) { stbuf.st_mode = S_IFREG; #ifdef USE_INO stbuf.st_ino = 0; /* impossible number */ stbuf.st_dev = 0; #endif stbuf.st_mtime = 0; } was_dir = (stbuf.st_mode & S_IFMT) == S_IFDIR; was_file = stbuf.st_ino != 0 && (stbuf.st_mode & S_IFMT) == S_IFREG; } if ((flags & DS_DIR) == 0 && was_dir) { complain("[%s is a directory]", fnamebuf); /* NOTREACHED */ } if (flags & DS_SET) { if ((stbuf.st_mode & S_IFMT) == S_IFREG) { #ifdef USE_INO target->b_dev = stbuf.st_dev; target->b_ino = stbuf.st_ino; #endif target->b_mtime = stbuf.st_mtime; } else { #ifdef USE_INO target->b_dev = 0; target->b_ino = 0; #endif target->b_mtime = 0; } diverge(target, NO); } for (b = world; b != NULL; b = b->b_next) { #ifdef USE_INO if(b->b_ino != 0 && b->b_ino == stbuf.st_ino && b->b_dev != 0 && b->b_dev == stbuf.st_dev) { /* A buffer's inode got a match; check divergence: * - name is different & can't stat buffer's fname * - name is different & stat yields a different inode * - inode now refers to a non-file */ struct stat stbchk; if ((strcmp(b->b_fname, fnamebuf) != 0 && (stat(b->b_fname, &stbchk) == -1 || b->b_ino != stbchk.st_ino || b->b_dev != stbchk.st_dev)) || (stbuf.st_mode & S_IFMT) != S_IFREG) { /* false match: buffer's file has lost its inode */ b->b_ino = 0; b->b_dev = 0; diverge(b, YES); continue; /* try again */ } /* true match -- check times */ if (b->b_mtime != stbuf.st_mtime) diverge(b, YES); if (target == NULL || target == b) result = b; } else if (b->b_fname != NULL && strcmp(b->b_fname, fnamebuf) == 0) { /* a name (but not inode) match */ if (b->b_ino != stbuf.st_ino || (stbuf.st_mode & S_IFMT) != S_IFREG) { /* one or the other has an inode */ b->b_ino = 0; b->b_dev = 0; diverge(b, YES); } if (target == NULL || target == b) result = b; } #else if (b->b_fname != NULL && strcmp(b->b_fname, fnamebuf) == 0) { /* a name match -- check times */ if (stbuf.st_mtime != b->b_mtime) diverge(b, YES); if (target == NULL || target == b) result = b; } #endif } return result; } private void setbname(b, name) register Buffer *b; register const char *name; { UpdModLine = YES; /* Kludge ... but speeds things up considerably */ if (name != NULL) { if (b->b_name == NoName) b->b_name = NULL; b->b_name = strcpy((char *)freealloc( (UnivPtr) b->b_name, strlen(name) + 1), name); } else { b->b_name = NULL; } #ifdef MAC Bufchange = YES; #endif } void setfname(b, name) register Buffer *b; register const char *name; { char wholename[FILESIZE], oldname[FILESIZE], *oldptr = NULL; Buffer *save = curbuf; SetBuf(b); UpdModLine = YES; /* Kludge ... but speeds things up considerably */ if (b->b_fname != NULL) { oldptr = strcpy(oldname, b->b_fname); free((UnivPtr) b->b_fname); b->b_fname = NULL; } if (name != NULL) { PathParse(name, wholename); curbuf->b_fname = copystr(wholename); } DoAutoExec(curbuf->b_fname, oldptr); /* until they're known, zero these */ #ifdef USE_INO curbuf->b_dev = 0; curbuf->b_ino = 0; #endif curbuf->b_mtime = 0; diverge(curbuf, NO); SetBuf(save); #ifdef MAC Bufchange = YES; #endif } /* Find the file `fname' into buf and put in in window `w' */ Buffer * do_find(w, fname, force, do_macros) register Window *w; register char *fname; jbool force; jbool do_macros; { register Buffer *b; Buffer *oldb = curbuf; b = do_stat(fname, (Buffer *)NULL, DS_NONE); if (b == NULL) { b = mak_buf(); setfname(b, fname); bufname(b); (void) do_stat(b->b_fname, b, DS_SET | DS_REUSE); b->b_ntbf = force; SetBuf(b); /* force => load the file */ if (w) tiewind(w, b); /* We now execute all pending macro text, on the * unwarranted presumption that it must have come * from an auto-execute-macro. If we didn't do this * here, it would get delayed until the current * command was finished, which may be too late in the * case of UNIX_cmdline, watch_input, find_tag, or * ErrParse. * * There are some SetBuf(b) calls within the dispatch, * but they do not cause reading of the file * because b->b_ntbf will be false at this point. * One consequence will be that the macro will be executed * on the unfilled buffer -- somewhat surprising! */ if (do_macros) dispatch_macros(); /* ??? At this point, we make the rash assumption * that buffer oldb still exists, even though * the macro text could have deleted it. */ b->b_ntbf = !force; /* * the file will be read when the user next mentions Buffer b */ SetBuf(oldb); } else { if (force) { SetBuf(b); /* b->b_ntbf => load the file */ SetBuf(oldb); } if (w) tiewind(w, b); } return b; } /* set alternate buffer */ void SetABuf(b) Buffer *b; { if (b != NULL) lastbuf = b; } /* check to see if BP is a valid buffer pointer */ jbool valid_bp(bp) register Buffer *bp; { register Buffer *b; for (b = world; b != NULL; b = b->b_next) if (b == bp) return YES; return NO; } void SetBuf(newbuf) register Buffer *newbuf; { if (newbuf == curbuf || newbuf == NULL) return; if (!valid_bp(newbuf)) { complain("Internal error: (0x%x) is not a valid buffer pointer!", newbuf); /* NOTREACHED */ } lsave(); curbuf = newbuf; getDOT(); /* do the read now ... */ if (curbuf->b_ntbf) read_file(curbuf->b_fname, NO); #ifdef MAC Modechange = YES; #endif } Buffer * do_select(w, name) register Window *w; register const char *name; { register Buffer *new; if ((new = buf_exists(name)) == NULL) { new = mak_buf(); setfname(new, (char *)NULL); setbname(new, name); } if (w != NULL) tiewind(w, new); return new; } void buf_init() { SetBuf(do_select(curwind, Mainbuf)); } LinePtr lastline(lp) register LinePtr lp; { register LinePtr next; while ((next = lp->l_next) != NULL) lp = next; return lp; } LinePtr next_line(line, num) register LinePtr line; register long num; { if (num < 0) return prev_line(line, -num); if (line != NULL) while (--num >= 0 && line->l_next != NULL) line = line->l_next; return line; } LinePtr prev_line(line, num) register LinePtr line; register long num; { if (num < 0) return next_line(line, -num); if (line != NULL) while (--num >= 0 && line->l_prev != NULL) line = line->l_prev; return line; } jove-4.17.5.5/buf.h000066400000000000000000000136041501102521500136370ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* maximum length of a line (including '\0'). Currently cannot * be larger than a logical disk block. */ #define LBSIZE JBUFSIZ /* buffer types */ #define B_SCRATCH 1 /* for internal things, e.g. minibuffer ... */ #define B_FILE 2 /* normal file (we auto-save these.) */ #define B_PROCESS 3 /* unix process output in this buffer */ /* major modes (order must match entries in disp.c:majname[]) */ #define FUNDAMENTAL 0 /* Fundamental mode */ #define TEXTMODE 1 /* Text mode */ #define CMODE 2 /* C mode */ #ifdef LISP # define LISPMODE 3 /* Lisp mode */ # define NMAJORS 4 #else # define NMAJORS 3 #endif #define MajorMode(x) (curbuf->b_major == (x)) #define SetMajor(x) { curbuf->b_major = (x); UpdModLine = YES; } /* minor modes (order must match entries in disp.c:minname[]) */ #define Fill (1 << 0) /* text fill mode */ #define Abbrev (1 << 1) /* abbrev mode */ #define OverWrite (1 << 2) /* over write mode */ #define Indent (1 << 3) /* indent same as previous line after return */ #define BReadOnly (1 << 4) /* buffer is read only */ #define ShowMatch (1 << 5) /* paren flash mode */ #ifdef IPROCS /* buffer is running DBX process -- track source references */ # define DbxMode (1 << 6) #endif #define BufMinorMode(b, x) (((b)->b_minor & (x)) != 0) #define MinorMode(x) BufMinorMode(curbuf, (x)) /* global line scratch buffers */ #ifdef AUTO_BUFS extern char *genbuf, /* scratch pad points at s_genbuf (see main()) */ *linebuf, /* points at s_linebuf */ *iobuff; /* for file reading ... points at s_iobuff */ #else extern char genbuf[LBSIZE], linebuf[LBSIZE], iobuff[LBSIZE]; #endif /* typedef struct line *LinePtr in jove.h */ struct line { LinePtr l_prev, /* pointer to prev */ l_next; /* pointer to next */ daddr l_dline; /* pointer to disk location */ }; /* typedef struct mark Mark in jove.h */ struct mark { LinePtr m_line; int m_char; jbool m_big_delete; /* mark was within the range of a multi-line delete */ Mark *m_next; /* list of marks */ }; /* typedef struct buffer Buffer in jove.h */ struct buffer { #ifdef MAC int Type; /* kludge... to look like a data_obj */ char *Name; /* Name will not be used */ #endif Buffer *b_next; /* next buffer in chain */ const char *b_name; /* buffer name */ char *b_fname; /* file name associated with buffer */ #ifdef USE_INO /* unique identification of file */ dev_t b_dev; /* device of file name. */ ino_t b_ino; /* inode of file name */ #endif time_t b_mtime; /* last modify time ... to detect two people writing to the same file */ LinePtr b_first, /* pointer to first line in list */ b_dot, /* current line */ b_last; /* last line in list */ int b_char; /* current character in line */ #define NMARKS 8 /* number of marks in the ring */ Mark *b_markring[NMARKS], /* new marks are pushed here */ #define b_curmark(b) ((b)->b_markring[(b)->b_themark]) #define curmark b_curmark(curbuf) *b_marks; /* all the marks for this buffer */ int b_themark, /* current mark (in b_markring) */ b_type; /* file, scratch, process, iprocess */ char b_ntbf, /* (jbool) needs to be found when we first select? */ b_modified, /* (jbool) is the buffer modified? */ b_diverged; /* (jbool) has the underlying file been changed behind our back? */ int b_major; /* major mode */ unsigned b_minor; /* and minor mode */ struct keymap *b_map; /* local bindings (if any) */ #ifdef IPROCS struct process *b_process; /* process we're attached to */ #endif }; extern Buffer *world, /* first buffer */ *curbuf, /* pointer into world for current buffer */ *lastbuf, /* Last buffer we were in so we have a default buffer during a select buffer. */ *perr_buf; /* Buffer with error messages */ #define curline (curbuf->b_dot) #define curchar (curbuf->b_char) /* typedef struct position Bufpos in jove.h */ struct position { LinePtr p_line; int p_char; }; extern jbool valid_bp proto((Buffer *bp)); extern Buffer *buf_exists proto((const char *name)), *do_find proto((Window *w, char *fname, jbool force, jbool do_macros)), *do_select proto((Window *w, const char *name)), *do_stat proto((const char *name, Buffer *target, int flags)); /* flags to do_stat */ #define DS_NONE 0 #define DS_SET 1 /* set target buffers stat fields */ #define DS_REUSE 2 /* reuse result of last stat */ #define DS_DIR 4 /* directory OK as result */ extern jbool was_dir, /* do_stat found a directory */ was_file; /* do_stat found a (plain) file */ extern const char *ask_buf proto((Buffer *def, int flags)); #ifdef USE_PROTOTYPES struct macro; /* forward declaration preventing prototype scoping */ #endif /* USE_PROTOTYPES */ extern void TogMinor proto((int bit)), buf_clear proto((Buffer *b)), setfname proto((Buffer *b, const char *name)), SetABuf proto((Buffer *b)), SetBuf proto((Buffer *newbuf)), buf_init proto((void)); extern LinePtr lastline proto((LinePtr lp)), listput proto((Buffer *buf, LinePtr after)), next_line proto((LinePtr line, long num)), prev_line proto((LinePtr line, long num)); /* Commands: */ extern void BufErase proto((void)), BufKill proto((void)), BufList proto((void)), BufSelect proto((void)), FindFile proto((void)), KillSome proto((void)), ReNamBuf proto((void)); extern void Buf1Select proto((void)), Buf2Select proto((void)), Buf3Select proto((void)), Buf4Select proto((void)), Buf5Select proto((void)), Buf6Select proto((void)), Buf7Select proto((void)), Buf8Select proto((void)), Buf9Select proto((void)), Buf10Select proto((void)); jove-4.17.5.5/c.c000066400000000000000000000453721501102521500133070ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Contains commands for C mode. Paren matching routines are in here. */ #include "jove.h" #include "re.h" #include "c.h" #include "jctype.h" #include "disp.h" #include "delete.h" #include "insert.h" #include "fmt.h" #include "marks.h" #include "misc.h" #include "move.h" #include "para.h" private void FindMatch proto((int)); private jbool backslashed(lp, cpos) register char *lp; register int cpos; { register int cnt = 0; while (cpos > 0 && lp[--cpos] == '\\') cnt += 1; return (cnt % 2) != 0; } private const char p_types[] = "(){}[]"; private int mp_kind; #define MP_OKAY 0 #define MP_MISMATCH 1 #define MP_UNBALANCED 2 #define MP_INCOMMENT 3 void mp_error() { switch (mp_kind) { case MP_MISMATCH: message("[Mismatched parentheses]"); break; case MP_UNBALANCED: message("[Unbalanced parenthesis]"); break; case MP_INCOMMENT: message("[Inside a comment]"); break; case MP_OKAY: default: return; } rbell(); } /* Search from the current position for the paren that matches p_type. * Search in the direction dir. If can_mismatch is YES then it is okay * to have mismatched parens. If stop_early is YES then when an open * paren is found at the beginning of a line, it is assumed that there * is no point in backing up further. This is so when you hit tab or * LineFeed outside, in-between procedure/function definitions, it won't * sit there searching all the way to the beginning of the file for a * match that doesn't exist. {forward,backward}-s-expression are the * only ones that insist on getting the "true" story. */ Bufpos * m_paren(p_type, dir, can_mismatch, can_stop) DAPchar p_type; register int dir; jbool can_mismatch; jbool can_stop; { static Bufpos ret; Bufpos savedot; struct RE_block re_blk; int count = 0; register char c = '\0'; /* avoid uninitialized complaint from gcc -W */ char p_match, /* kind of paren matching p_type */ quote_c = '\0'; register int c_char; int in_comment = -1; /* -1, YES, or NO */ jbool stopped = NO; REcompile(MajorMode(CMODE)? "[(){}[\\]/\"']" : "[(){}[\\]\"]", YES, &re_blk); { char *cp = strchr(p_types, p_type); if (cp == NULL) { complain("[Cannot match %c's]", p_type); /* NOTREACHED */ } p_match = cp[dir]; } DOTsave(&savedot); /* To make things a little faster I avoid copying lines into * linebuf by setting curline and curchar by hand. Warning: * this is slightly to very risky. When I did this there were * lots of problems with procedures that expect the contents of * curline to be in linebuf. */ do { Bufpos *sp = docompiled(dir, &re_blk); register char *lp; if (sp == NULL) break; lp = lbptr(sp->p_line); curline = sp->p_line; curchar = sp->p_char; /* here's where I cheat */ c_char = curchar; if (dir == FORWARD) c_char -= 1; if (backslashed(lp, c_char)) continue; c = lp[c_char]; /* check if this is a comment (if we're not inside quotes) */ if (quote_c == '\0' && c == '/') { int new_ic = in_comment; /* -1, YES, or NO */ /* close comment */ if ((c_char != 0) && lp[c_char - 1] == '*') { new_ic = (dir == FORWARD) ? NO : YES; if (new_ic == NO && in_comment == -1) { count = 0; quote_c = '\0'; } } else if (lp[c_char + 1] == '*') { new_ic = (dir == FORWARD) ? YES : NO; if (new_ic == NO && in_comment == -1) { count = 0; quote_c = '\0'; } } in_comment = new_ic; } if (in_comment == YES) continue; if (c == '"' || c == '\'') { if (quote_c == c) quote_c = '\0'; else if (quote_c == '\0') quote_c = c; } if (quote_c != '\0') continue; if (jisopenp(c)) { count += dir; if (c_char == 0 && can_stop && count >= 0) { stopped = YES; break; } } else if (jisclosep(c)) { count -= dir; } } while (count >= 0); ret.p_line = curline; ret.p_char = curchar; curline = savedot.p_line; curchar = savedot.p_char; /* here's where I undo it */ if (count >= 0) mp_kind = MP_UNBALANCED; else if (c != p_match) mp_kind = MP_MISMATCH; else mp_kind = MP_OKAY; /* If we stopped (which means we were allowed to stop) and there * was an error, we clear the error so no error message is printed. * An error should be printed ONLY when we are sure about the fact, * namely we didn't stop prematurely HOPING that it was the right * answer. */ if (stopped && mp_kind != MP_OKAY) { mp_kind = MP_OKAY; return NULL; } if (mp_kind == MP_OKAY || (mp_kind == MP_MISMATCH && can_mismatch)) return &ret; return NULL; } private void do_expr(dir, skip_words) register int dir; jbool skip_words; { register char syntax = (dir == FORWARD) ? C_BRA : C_KET; if (dir == BACKWARD) b_char(1); for (;;) { char c = linebuf[curchar]; if (!skip_words && jisident(c)) { for (;;) { if (dir == FORWARD? c == '\0' : bolp()) break; curchar += dir; if (!jisident(linebuf[curchar])) { if (dir == BACKWARD) curchar += 1; break; } } break; } /* * BUG ALERT! The following test ought not to recognise brackets inside * comments or quotes */ if (has_syntax(c, syntax)) { FindMatch(dir); break; } f_char(dir); if (eobp() || bobp()) return; } } void FSexpr() { register int num = arg_value(); if (num < 0) { negate_arg(); BSexpr(); } while (--num >= 0) do_expr(FORWARD, NO); } void FList() { register int num = arg_value(); if (num < 0) { negate_arg(); BList(); } while (--num >= 0) do_expr(FORWARD, YES); } void BSexpr() { register int num = arg_value(); if (num < 0) { negate_arg(); FSexpr(); } while (--num >= 0) do_expr(BACKWARD, NO); } void BList() { register int num = arg_value(); if (num < 0) { negate_arg(); FList(); } while (--num >= 0) do_expr(BACKWARD, YES); } void BUpList() { register int num = arg_value(); Bufpos *mp; if (num < 0) { negate_arg(); FDownList(); } while (--num >= 0) { mp = m_paren(')', BACKWARD, YES, YES); if (mp == NULL) mp_error(); else SetDot(mp); } } void FDownList() { register int num = arg_value(); Bufpos *sp; static const char sstr[] = "[{([\\])}]"; if (num < 0) { negate_arg(); BUpList(); } while (--num >= 0) { /* * BUG ALERT! The following test ought not to recognise brackets inside * comments or quotes */ sp = dosearch(sstr, FORWARD, YES); if (sp == NULL || jisclosep(lcontents(sp->p_line)[sp->p_char - 1])) { complain("[No contained expression]"); /* NOTREACHED */ } SetDot(sp); } } /* Move to the matching brace or paren depending on the current position * in the buffer. */ private void FindMatch(dir) int dir; { register Bufpos *bp; register char c = linebuf[curchar]; if (strchr(p_types, c) == NULL || backslashed(linebuf, curchar)) { complain((char *)NULL); /* NOTREACHED */ } if (dir == FORWARD) f_char(1); bp = m_paren(c, dir, YES, NO); if (dir == FORWARD) b_char(1); if (bp != NULL) SetDot(bp); mp_error(); /* if there is an error the user wants to know about it */ } #define ALIGN_ARGS (-1) /* If CArgIndent == ALIGN_ARGS then the indentation routine will * indent a continued line by lining it up with the first argument. * Otherwise, it will indent CArgIndent characters past the indent * of the first line of the procedure call. */ int CArgIndent = ALIGN_ARGS; /* VAR: how to indent arguments to C functions */ /* indent for C code */ Bufpos * c_indent(brace) jbool brace; { Bufpos *bp; int new_indent = 0, current_indent, increment = brace? 0 : CIndIncrmt; /* Find matching paren, which may be a mismatch now. If it * is not a matching curly brace then it is a paren (most likely). * In that case we try to line up the arguments to a procedure * or inside an of statement. */ if ((bp = m_paren('}', BACKWARD, YES, YES)) != NULL) { Bufpos save; int matching_indent; DOTsave(&save); SetDot(bp); /* go to matching paren */ ToIndent(); matching_indent = calc_pos(linebuf, curchar); SetDot(bp); switch (linebuf[curchar]) { case '{': new_indent = matching_indent; if (!bolp()) { b_char(1); /* If we're not within the indent then we * can assume that there is either a C keyword * line DO on the line before the brace, or * there is a parenthesized expression. If * that's the case we want to go backward * over that to the beginning of the expression * so that we can get the correct indent for * this matching brace. This handles wrapped * if statements, etc. */ if (!within_indent()) { Bufpos savematch; savematch = *bp; do_expr(BACKWARD, NO); ToIndent(); new_indent = calc_pos(linebuf, curchar); /* do_expr() calls b_paren, which * returns a pointer to a structure, * and that pointer is in BP so we * have to save away the matching * paren and restore it in the * following line ... sigh */ *bp = savematch; } } if (!brace) new_indent += (increment - (new_indent % increment)); break; case '(': if (CArgIndent == ALIGN_ARGS) { f_char(1); new_indent = calc_pos(linebuf, curchar); } else new_indent = matching_indent + CArgIndent; break; } SetDot(&save); } /* new_indent is the "correct" place to indent. Now we check to * see if what we consider as the correct place to indent is to * the LEFT of where we already are. If it is, and we are NOT * handling a brace, then we assume that the person wants to tab * in further than what we think is right (for some reason) and * so we allow that. */ ToIndent(); current_indent = calc_pos(linebuf, curchar); if (!brace && new_indent <= current_indent) new_indent = current_indent + (increment - (current_indent % increment)); Bol(); DelWtSpace(); /* nice uniform Tabs*Space* */ n_indent(new_indent); return bp; } private void re_indent(incr) int incr; { LinePtr l1, l2, lp; int c1, c2; Mark *m = CurMark(); Bufpos savedot; DOTsave(&savedot); l1 = curline; c1 = curchar; l2 = m->m_line; c2 = m->m_char; (void) fixorder(&l1, &c1, &l2, &c2); for (lp = l1; lp != l2->l_next; lp = lp->l_next) { int indent; SetLine(lp); ToIndent(); indent = calc_pos(linebuf, curchar); if (indent != 0 || linebuf[0] != '\0') n_indent(indent + incr); } SetDot(&savedot); } void LRShift() { re_indent(-arg_or_default(CIndIncrmt)); } void RRShift() { re_indent(arg_or_default(CIndIncrmt)); } #ifdef CMT_FMT char CmtFmt[80] = "/*%n%! * %c%!%n */"; /* VAR: comment format */ /* Strip leading and trailing white space. Skip over any imbedded '\n's. */ private void strip_c(from, to) char *from, *to; { register char *fr_p = from, *to_p = to, c; while ((c = *fr_p) == '\n' || jiswhite(c)) fr_p += 1; while ((c = *fr_p) != '\0') { if (c != '\n') *to_p++ = c; fr_p += 1; } while (to_p > to && jiswhite(to_p[-1])) to_p -= 1; *to_p = '\0'; } # define CMT_STR_BOUND 20 private char open_c[CMT_STR_BOUND], /* the open comment format string */ open_pat[CMT_STR_BOUND], /* the search pattern for open comment */ l_header[CMT_STR_BOUND], /* the prefix for each comment line */ l_trailer[CMT_STR_BOUND], /* the suffix ... */ close_c[CMT_STR_BOUND], close_pat[CMT_STR_BOUND]; private jbool nl_in_close_c; /* Fill in the data structures above from the format string. Don't return * if there's trouble. */ private void parse_cmt_fmt() { static char *const component[] = { open_c, l_header, l_trailer, close_c }; register char *fmtp = CmtFmt; register char *const *c_body = component, *body_p = *c_body, *body_limit = body_p + CMT_STR_BOUND - 1; char c; int comp_no = 0; /* pick apart the comment string */ nl_in_close_c = NO; while ((c = *fmtp++) != '\0') { if (c == '%') { switch(c = *fmtp++) { case 'n': switch (comp_no) { case 0: break; case 3: nl_in_close_c = YES; break; default: complain("%%n not allowed in line header or trailer: %s", fmtp - 2); /* NOTREACHED */ } c = '\n'; break; case 't': c = '\t'; break; case '%': break; case '!': case 'c': if (++comp_no == elemsof(component)) { complain("too many components"); /* NOTREACHED */ } if ((c=='c') != (comp_no==2)) { complain("wrong separator: %%%c", c); /* NOTREACHED */ } *body_p++ = '\0'; body_p = *++c_body; body_limit = body_p + CMT_STR_BOUND - 1; continue; default: complain("[Unknown comment escape: %%%c]", c); /*NOTREACHED*/ } } if (body_p >= body_limit) { complain("component too long"); /* NOTREACHED */ } *body_p++ = c; } *body_p = '\0'; while (++comp_no != elemsof(component)) **++c_body = '\0'; /* make search patterns */ strip_c(open_c, open_pat); strip_c(close_c, close_pat); } void FillComment() { int saveRMargin, indent_pos; jbool found_close; char *trimmed_header; /* l_header without leading spaces */ int trimmed_header_len, /* length without leading or trailing spaces */ trailer_len; register char *cp; Bufpos open_c_pt, close_c_pt, tmp_bp, *match_o, *match_c; Mark *close_c_mark, /* end of comment (we may terminate it) */ *open_c_mark, /* start of comment (reference to curmark) */ *savedot; parse_cmt_fmt(); /* Figure out if we're "inside" a comment. * First look back for opening comment symbol. */ if ((match_o = dosearch(open_pat, BACKWARD, NO)) == NULL) { complain("No opening %s to match to.", open_pat); /* NOTREACHED */ } open_c_pt = *match_o; if ((match_c = dosearch(close_pat, BACKWARD, NO)) != NULL && inorder(open_c_pt.p_line, open_c_pt.p_char, match_c->p_line, match_c->p_char)) { complain("[Must be between %s and %s to re-format]", open_pat, close_pat); /* NOTREACHED */ } /* Now look forward for closing comment symbol. * This involves looking forward for the next opening too. */ if ((match_o = dosearch(open_pat, FORWARD, NO)) != NULL) { tmp_bp = *match_o; match_o = &tmp_bp; } match_c = dosearch(close_pat, FORWARD, NO); /* If we found the right close comment symbol, we format * up to it; otherwise we format up to dot. We have found the * close if we found (looking forward) a close not preceded by * an open. */ found_close = match_c != NULL && (match_o == NULL || inorder(match_c->p_line, match_c->p_char, match_o->p_line, match_o->p_char)); if (found_close) { close_c_pt = *match_c; } else { close_c_pt.p_line = curline; close_c_pt.p_char = curchar; } SetDot(&open_c_pt); set_mark(); /* user visible mark! */ open_c_mark = curmark; indent_pos = calc_pos(linebuf, curchar); /* move to end; delete close if it exists */ SetDot(&close_c_pt); CopyRegion(); /* enable yank-pop for undo */ if (found_close) { del_char(BACKWARD, (int)strlen(close_pat), NO); DelWtSpace(); if (bolp()) del_char(BACKWARD, 1, NO); } close_c_mark = MakeMark(curline, curchar); /* Separate the comment body from anything preceeding it. * Delete separator later. */ ToMark(open_c_mark); LineInsert(1); DelWtSpace(); Bol(); /* insert comment open string */ for (cp = open_c; *cp!='\0'; cp++) { if (*cp == '\n') { if (!eolp()) LineInsert(1); else line_move(FORWARD, 1, NO); } else if (jiswhite(*cp)) { if (linebuf[curchar] != *cp) insert_c(*cp, 1); } else { /* Since we matched the open comment string * on this line, we don't need to worry about * crossing line boundaries. */ curchar += 1; } } savedot = MakeMark(curline, curchar); /* We need to strip the line header pattern of leading * white space since we need to match the line after all of * its leading whitespace is gone. We also need to note * how long that string is without counting trailing whitespace. */ for (cp = l_header; jiswhite(*cp); cp++) ; trimmed_header = cp; for (trimmed_header_len = strlen(cp) ; trimmed_header_len > 0 && jiswhite(cp[trimmed_header_len - 1]) ; trimmed_header_len--) ; trailer_len = strlen(l_trailer); /* Strip each comment line of the open and close comment line strings * before reformatting it. * Any whitespace at the end of the open line string is optional. * This allows empty comment lines (paragraph separators) without * trailing whitespace. */ for (;;) { Bol(); DelWtSpace(); if (trimmed_header_len) { int hmw = numcomp(linebuf, trimmed_header); if (hmw >= trimmed_header_len) del_char(FORWARD, hmw, NO); } if (trailer_len) { Eol(); if (curchar > trailer_len && strncmp(&linebuf[curchar - trailer_len], l_trailer, (size_t)trailer_len)==0) del_char(BACKWARD, trailer_len, NO); } if (curline == close_c_mark->m_line) break; line_move(FORWARD, 1, NO); } /* Now that comment decoration is gone, use normal fill * routine to format body. * Adjust RMargin to allow for decoration to be added back, * but always allow at least 10 characters (arbitrary). */ do_set_mark(savedot->m_line, savedot->m_char); /* user visible mark! */ DelMark(savedot); ToMark(close_c_mark); saveRMargin = RMargin; RMargin = jmax(10, saveRMargin - (int)strlen(l_header) - trailer_len - indent_pos + 2); do_rfill(NO); /* justify from mark through point */ RMargin = saveRMargin; PopMark(); /* get back to the start of the comment; discard mark */ /* redecorate newly filled comment text */ for (;;) { if (curline != open_c_mark->m_line->l_next) { /* Not first line: insert line header. * Slightly tricky: preserve interesting leading * whitespace in line (n_indent would eat it). */ Bol(); ins_str(trimmed_header); Bol(); n_indent(indent_pos + (int)(trimmed_header - l_header)); } Eol(); if (trailer_len == 0) DelWtSpace(); if (curline == close_c_mark->m_line) break; /* not last line: insert line trailer */ ins_str(l_trailer); line_move(FORWARD, 1, NO); } if (nl_in_close_c) { /* since NewLine is included in comment close, * add line trailer first */ ins_str(l_trailer); } /* handle the close comment symbol */ DelMark(close_c_mark); DelWtSpace(); /* if the addition of the close symbol would cause the line * to be too long, put the close symbol on the next line. */ if (!nl_in_close_c && (int)strlen(close_c) + calc_pos(linebuf, curchar) > RMargin) { LineInsert(1); n_indent(indent_pos); } for (cp = close_c; *cp; cp++) { if (*cp == '\n') { LineInsert(1); n_indent(indent_pos); } else { insert_c(*cp, 1); } } ExchPtMark(); Eol(); del_char(FORWARD, 1, NO); /* Delete separator added earlier */ this_cmd = UNDOABLECMD; /* allow yank-pop to undo */ } #endif /* CMT_FMT */ jove-4.17.5.5/c.h000066400000000000000000000020371501102521500133030ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern Bufpos *c_indent proto((jbool brace)), *m_paren proto((DAPchar p_type, int dir, jbool can_mismatch, jbool can_stop)); extern void mp_error proto((void)); /* Variables: */ extern int CArgIndent; /* VAR: how to indent arguments to C functions */ #ifdef CMT_FMT extern char CmtFmt[80]; /* VAR: comment format */ #endif /* Commands: */ extern void BList proto((void)), BSexpr proto((void)), BUpList proto((void)), #ifdef CMT_FMT FillComment proto((void)), #endif FDownList proto((void)), FList proto((void)), FSexpr proto((void)), LRShift proto((void)), RRShift proto((void)); jove-4.17.5.5/case.c000066400000000000000000000061251501102521500137710ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "disp.h" #include "case.h" #include "jctype.h" #include "marks.h" #include "move.h" /* Commands: * CapChar * CapWord * CasRegLower * CasRegUpper * LowWord * UppWord */ private jbool lower proto((char *)), upper proto((char *)); private void CaseReg proto((jbool up)), case_reg proto((LinePtr line1,int char1,LinePtr line2,int char2,jbool up)); void CapChar() { register int num; jbool restore = NO; Bufpos b; DOTsave(&b); num = arg_value(); if (num < 0) { restore = YES; num = -num; b_char(num); /* Cap previous EXP chars */ } while (num--) { if (upper(&linebuf[curchar])) { modify(); makedirty(curline); } if (eolp()) { if (curline->l_next == NULL) break; SetLine(curline->l_next); } else curchar += 1; } if (restore) SetDot(&b); } void CapWord() { register int num, restore = NO; Bufpos b; DOTsave(&b); num = arg_value(); if (num < 0) { restore = YES; f_word(num); /* Cap previous EXP words */ num = -num; } while (num--) { to_word(FORWARD); /* Go to the beginning of the next word. */ if (eobp()) break; if (upper(&linebuf[curchar])) { modify(); makedirty(curline); } curchar += 1; while (!eolp() && jisword(linebuf[curchar])) { if (lower(&linebuf[curchar])) { modify(); makedirty(curline); } curchar += 1; } } if (restore) SetDot(&b); } private void case_word(up) jbool up; { Bufpos before; DOTsave(&before); ForWord(); /* this'll go backward if negative argument */ case_reg(before.p_line, before.p_char, curline, curchar, up); } /* Convert *p to upper case. Return YES iff it was changed. */ private jbool upper(p) register char *p; { if (jislower(*p)) { *p = CharUpcase(*p); return YES; } return NO; } /* Convert *p to lower case. Return YES iff it was changed. */ private jbool lower(p) char *p; { char c = *p; if (jisupper(c)) { *p = CharDowncase(c); return YES; } return NO; } private void case_reg(line1, char1, line2, char2, up) LinePtr line1, line2; int char1, char2; jbool up; { (void) fixorder(&line1, &char1, &line2, &char2); DotTo(line1, char1); for (;;) { if (curline == line2 && curchar == char2) break; if (!eolp()) if ((up) ? upper(&linebuf[curchar]) : lower(&linebuf[curchar])) { makedirty(curline); modify(); } f_char(1); } } void CasRegLower() { CaseReg(NO); } void CasRegUpper() { CaseReg(YES); } private void CaseReg(up) jbool up; { register Mark *mp = CurMark(); Bufpos savedot; DOTsave(&savedot); case_reg(curline, curchar, mp->m_line, mp->m_char, up); SetDot(&savedot); } void UppWord() { case_word(YES); } void LowWord() { case_word(NO); } jove-4.17.5.5/case.h000066400000000000000000000011771501102521500140000ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Commands: */ extern void CasRegLower proto((void)), CasRegUpper proto((void)), CapChar proto((void)), CapWord proto((void)), LowWord proto((void)), UppWord proto((void)); jove-4.17.5.5/chars.h000066400000000000000000000011431501102521500141560ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #define CTL(c) ((c) & 037) #define METABIT 0200 #define DEL '\177' #define LF CTL('J') #define CR CTL('M') #define BS CTL('H') #define ESC '\033' jove-4.17.5.5/commands.c000066400000000000000000000076441501102521500146660ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "extend.h" #include "macros.h" #include "mouse.h" /* included for command routine declarationss */ #include "abbrev.h" /* #include "argcount.h */ /* #include "buf.h" */ #include "c.h" #include "case.h" #include "commands.h" #include "delete.h" #include "disp.h" /* #include "extend.h" */ #include "fmt.h" #include "insert.h" /* #include "io.h" */ #include "sysprocs.h" /* needed for iproc.h */ #include "iproc.h" /* #include "jove.h" */ /* #include "keymaps.h" */ /* #include "macros.h" */ #include "marks.h" #include "misc.h" #include "move.h" #include "para.h" #include "proc.h" #include "reapp.h" #include "wind.h" #define PROC(p) (p) #include "commands.tab" const data_obj *LastCmd; const char *ProcFmt = ": %f "; const data_obj * findcom(prompt) const char *prompt; { if (InJoverc) { /* For faster rc file processing on startup, read until a space * or a tab or a newline character is reached, and then do a * semi-indexedlookup on that string. This should be much faster * than minibuffer completion for each line. */ char cmdbuf[128]; register const struct cmd *cmd; register char *cp = cmdbuf; register ZXchar c; const struct cmd *which = NULL; size_t cmdlen; int ic; #ifdef MAC /* ??? Is this necessary? The input is comming from a file! */ menus_off(); /* Block menu choices during input */ #endif /* gather the cmd name */ while (jisprint(c = getch()) && c != ' ') { *cp++ = CharDowncase(c); if (cp == &cmdbuf[sizeof(cmdbuf)]) { complain("command too long"); /* NOTREACHED */ } } *cp = '\0'; cmdlen = cp - cmdbuf; jdbg("findcom lookup \"%s\"\n", cmdbuf); /* look it up (in the reduced search space) */ c = ZXC(cmdbuf[0]); ic = IDX(c); if (ic >= 0 && ic <= IDXSZ && (cmd = cmdidx[ic]) != NULL) { for (; cmd->Name != NULL && cmd->Name[0] == cmdbuf[0]; cmd++) { if (strncmp(cmd->Name, cmdbuf, cmdlen) == 0) { if (cmd->Name[cmdlen] == '\0') return (data_obj *) cmd; if (which != NULL) { complain("[cmd \"%s\" ambiguous]", cmdbuf); /* NOTREACHED */ } which = cmd; } } } if (which == NULL) { complain("[\"%s\" unknown]", cmdbuf); /* NOTREACHED */ } return (data_obj *) which; } else { static const char *strings[elemsof(commands)]; static int last = -1; if (strings[0] == NULL) { register const char **strs = strings; register const struct cmd *c = commands; do {} while ((*strs++ = (*c++).Name) != NULL); } last = complete(strings, last >= 0? strings[last] : (char *)NULL, prompt, CASEIND | ALLOW_OLD); return (data_obj *) &commands[last]; } } const struct cmd * FindCmd(proc) register cmdproc_t proc; { register const struct cmd *cp; for (cp = commands; cp->Name; cp++) if (cp->c_proc == proc) return cp; return NULL; } void ExecCmd(cp) register const data_obj *cp; { LastCmd = cp; jdprintf("ExecCmd \"%s\" 0x%x\n", cp->Name?cp->Name:"(NULL)", cp->Type); if (cp->Type & MAJOR_MODE) { SetMajor((cp->Type >> MAJOR_SHIFT)); } else if (cp->Type & MINOR_MODE) { TogMinor((cp->Type >> MAJOR_SHIFT)); } else switch (cp->Type&TYPEMASK) { case MACRO: do_macro((struct macro *) cp); break; case COMMAND: { register struct cmd *cmd = (struct cmd *) cp; if (cmd->c_proc != NULL) { if ((cmd->Type & MODIFIER) && BufMinorMode(curbuf, BReadOnly)) { rbell(); message("[Buffer is read-only]"); } else { (*cmd->c_proc)(); } } } break; } } jove-4.17.5.5/commands.h000066400000000000000000000016261501102521500146650ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ typedef void(*cmdproc_t) ptrproto((void)); struct cmd { /* Type and Name must match data_obj */ int Type; const char *Name; const cmdproc_t c_proc; #ifdef MAC char c_map; /* prefix map for About Jove... */ char c_key; /* key binding for About Jove... */ #endif }; extern const struct cmd commands[]; extern const struct cmd *cmdidx[IDXSZ]; extern const struct cmd *FindCmd proto((cmdproc_t)); extern void ExecCmd proto((const data_obj *cp)); jove-4.17.5.5/commands.tab000066400000000000000000000347071501102521500152120ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* This file is #included by commands.c and setmaps.c * Each defines PROC differently! */ #ifdef MAC # define WIRED_CMD(c) PROC(c),'\0','\0' /* for About Jove... */ #else # define WIRED_CMD(c) PROC(c) #endif /* MAC */ #define NULLCMD WIRED_CMD((cmdproc_t)0) /* Table of commands * * Note: must be kept in alphabetical order (setmaps does a check). */ const struct cmd commands[] = { #ifdef LISP { COMMAND, "add-lisp-special", WIRED_CMD(AddSpecial) }, #endif { COMMAND, "append-region", WIRED_CMD(AppReg) }, { COMMAND, "apropos", WIRED_CMD(Apropos) }, { COMMAND, "auto-execute-command", WIRED_CMD(CAutoExec) }, { COMMAND, "auto-execute-macro", WIRED_CMD(MAutoExec) }, { DefMinor(Fill), "auto-fill-mode", NULLCMD }, { DefMinor(Indent), "auto-indent-mode", NULLCMD }, { COMMAND, "backward-character", WIRED_CMD(BackChar) }, { COMMAND, "backward-list", WIRED_CMD(BList) }, { COMMAND, "backward-paragraph", WIRED_CMD(BackPara) }, { COMMAND, "backward-s-expression", WIRED_CMD(BSexpr) }, { COMMAND, "backward-sentence", WIRED_CMD(Bos) }, { COMMAND, "backward-up-list", WIRED_CMD(BUpList) }, { COMMAND, "backward-word", WIRED_CMD(BackWord) }, { COMMAND, "begin-kbd-macro", WIRED_CMD(Remember) }, { COMMAND, "beginning-of-file", WIRED_CMD(Bof) }, { COMMAND, "beginning-of-line", WIRED_CMD(Bol) }, { COMMAND, "beginning-of-window", WIRED_CMD(Bow) }, { COMMAND, "bind-keymap-to-key", WIRED_CMD(BindMap) }, { COMMAND, "bind-macro-to-key", WIRED_CMD(BindMac) }, #ifdef ABBREV { COMMAND, "bind-macro-to-word-abbrev", WIRED_CMD(BindMtoW) }, #endif { COMMAND, "bind-to-key", WIRED_CMD(BindAKey) }, { COMMAND, "buffer-position", WIRED_CMD(BufPos) }, { DefMajor(CMODE), "c-mode", NULLCMD }, { MODCMD, "case-character-capitalize", WIRED_CMD(CapChar) }, { MODCMD, "case-region-lower", WIRED_CMD(CasRegLower) }, { MODCMD, "case-region-upper", WIRED_CMD(CasRegUpper) }, { MODCMD, "case-word-capitalize", WIRED_CMD(CapWord) }, { MODCMD, "case-word-lower", WIRED_CMD(LowWord) }, { MODCMD, "case-word-upper", WIRED_CMD(UppWord) }, { COMMAND, "cd", WIRED_CMD(Chdir) }, { MODCMD, "character-to-octal-insert", WIRED_CMD(ChrToOct) }, { COMMAND, "clear-and-redraw", WIRED_CMD(ClAndRedraw) }, #ifdef SUBSHELL { COMMAND, "compile-it", WIRED_CMD(MakeErrors) }, #endif #ifdef PTYPROCS { COMMAND, "continue-process", WIRED_CMD(ProcCont) }, #endif { COMMAND, "copy-region", WIRED_CMD(CopyRegion) }, { COMMAND, "current-error", WIRED_CMD(ShowErr) }, { COMMAND, "date", WIRED_CMD(prCTIME) }, #ifdef IPROCS { DefMinor(DbxMode), "dbx-mode", NULLCMD }, #endif #ifdef ABBREV { COMMAND, "define-global-word-abbrev", WIRED_CMD(DefGAbbrev) }, #endif { COMMAND, "define-macro", WIRED_CMD(DefKBDMac) }, #ifdef ABBREV { COMMAND, "define-mode-word-abbrev", WIRED_CMD(DefMAbbrev) }, #endif { MODCMD, "delete-blank-lines", WIRED_CMD(DelBlnkLines) }, { COMMAND, "delete-buffer", WIRED_CMD(BufKill) }, { COMMAND, "delete-current-window", WIRED_CMD(DelCurWindow) }, { MODCMD, "delete-next-character", WIRED_CMD(DelNChar) }, { COMMAND, "delete-other-windows", WIRED_CMD(OneWindow) }, { MODCMD, "delete-previous-character", WIRED_CMD(DelPChar) }, { MODCMD, "delete-white-space", WIRED_CMD(DelWtSpace) }, { COMMAND, "describe-bindings", WIRED_CMD(DescBindings) }, { COMMAND, "describe-command", WIRED_CMD(DescCom) }, { COMMAND, "describe-key", WIRED_CMD(KeyDesc) }, { COMMAND, "describe-variable", WIRED_CMD(DescVar) }, { COMMAND, "digit", WIRED_CMD(Digit) }, { COMMAND, "digit-0", WIRED_CMD(Digit0) }, { COMMAND, "digit-1", WIRED_CMD(Digit1) }, { COMMAND, "digit-2", WIRED_CMD(Digit2) }, { COMMAND, "digit-3", WIRED_CMD(Digit3) }, { COMMAND, "digit-4", WIRED_CMD(Digit4) }, { COMMAND, "digit-5", WIRED_CMD(Digit5) }, { COMMAND, "digit-6", WIRED_CMD(Digit6) }, { COMMAND, "digit-7", WIRED_CMD(Digit7) }, { COMMAND, "digit-8", WIRED_CMD(Digit8) }, { COMMAND, "digit-9", WIRED_CMD(Digit9) }, { COMMAND, "digit-minus", WIRED_CMD(DigitMinus) }, { COMMAND, "dirs", WIRED_CMD(prDIRS) }, { COMMAND, "down-list", WIRED_CMD(FDownList) }, #ifdef PTYPROCS { COMMAND, "dstop-process", WIRED_CMD(ProcDStop) }, #endif #ifdef ABBREV { COMMAND, "edit-word-abbrevs", WIRED_CMD(EditAbbrevs) }, #endif { COMMAND, "end-kbd-macro", WIRED_CMD(Forget) }, { COMMAND, "end-of-file", WIRED_CMD(Eof) }, { COMMAND, "end-of-line", WIRED_CMD(Eol) }, { COMMAND, "end-of-window", WIRED_CMD(Eow) }, #ifdef PTYPROCS { COMMAND, "eof-process", WIRED_CMD(ProcEof) }, #endif { COMMAND, "erase-buffer", WIRED_CMD(BufErase) }, { COMMAND, "exchange-point-and-mark", WIRED_CMD(ExchPtMark) }, { COMMAND, "execute-kbd-macro", WIRED_CMD(ExecMacro) }, { COMMAND, "execute-macro", WIRED_CMD(RunMacro) }, { COMMAND, "execute-named-command", WIRED_CMD(Extend) }, { COMMAND, "exit-jove", WIRED_CMD(Leave) }, #ifdef CMT_FMT { MODCMD, "fill-comment", WIRED_CMD(FillComment) }, #endif /* CMT_FMT */ { MODCMD, "fill-paragraph", WIRED_CMD(FillParagraph) }, { MODCMD, "fill-region", WIRED_CMD(FillRegion) }, #ifdef SUBSHELL { MODCMD, "filter-region", WIRED_CMD(FilterRegion) }, #endif { COMMAND, "find-file", WIRED_CMD(FindFile) }, { COMMAND, "find-tag", WIRED_CMD(FindTag) }, { COMMAND, "find-tag-at-point", WIRED_CMD(FDotTag) }, { COMMAND, "first-non-blank", WIRED_CMD(ToIndent) }, { COMMAND, "forward-character", WIRED_CMD(ForChar) }, { COMMAND, "forward-list", WIRED_CMD(FList) }, { COMMAND, "forward-paragraph", WIRED_CMD(ForPara) }, { COMMAND, "forward-s-expression", WIRED_CMD(FSexpr) }, { COMMAND, "forward-sentence", WIRED_CMD(Eos) }, { COMMAND, "forward-word", WIRED_CMD(ForWord) }, { DefMajor(FUNDAMENTAL), "fundamental-mode", NULLCMD }, { COMMAND, "gather-numeric-argument", WIRED_CMD(TimesFour) }, { COMMAND, "goto-line", WIRED_CMD(GoLine) }, { COMMAND, "goto-window-with-buffer", WIRED_CMD(GotoWind) }, #ifdef LISP { MODCMD, "grind-s-expr", WIRED_CMD(GSexpr) }, #endif { COMMAND, "grow-window", WIRED_CMD(GrowWindowCmd) }, { MODCMD, "handle-tab", WIRED_CMD(Tab) }, { COMMAND, "i-search-forward", WIRED_CMD(IncFSearch) }, { COMMAND, "i-search-reverse", WIRED_CMD(IncRSearch) }, #ifdef IPROCS { COMMAND, "i-shell-command", WIRED_CMD(Iprocess) }, #endif { MODCMD, "insert-file", WIRED_CMD(InsFile) }, { MODCMD, "insert-variable", WIRED_CMD(InsVar) }, #ifdef IPROCS { COMMAND, "interrupt-process", WIRED_CMD(ProcInt) }, { COMMAND, "iproc-env-export", WIRED_CMD(IprocEnvExport) }, { COMMAND, "iproc-env-show", WIRED_CMD(IprocEnvShow) }, { COMMAND, "iproc-env-unset", WIRED_CMD(IprocEnvUnset) }, #endif { MODCMD, "kill-next-word", WIRED_CMD(DelNWord) }, { MODCMD, "kill-previous-word", WIRED_CMD(DelPWord) }, #ifdef IPROCS { COMMAND, "kill-process", WIRED_CMD(ProcKill) }, #endif { MODCMD, "kill-region", WIRED_CMD(DelReg) }, { MODCMD, "kill-s-expression", WIRED_CMD(KillExpr) }, { COMMAND, "kill-some-buffers", WIRED_CMD(KillSome) }, { MODCMD, "kill-to-beginning-of-sentence", WIRED_CMD(KillBos) }, { MODCMD, "kill-to-end-of-line", WIRED_CMD(KillEOL) }, { MODCMD, "kill-to-end-of-sentence", WIRED_CMD(KillEos) }, { COMMAND, "left-margin-here", WIRED_CMD(SetLMargin) }, #ifdef LISP { DefMajor(LISPMODE), "lisp-mode", NULLCMD }, #endif { COMMAND, "list-buffers", WIRED_CMD(BufList) }, #ifdef IPROCS { COMMAND, "list-processes", WIRED_CMD(ProcList) }, #endif { COMMAND, "local-bind-keymap-to-key", WIRED_CMD(LBindMap) }, { COMMAND, "local-bind-macro-to-key", WIRED_CMD(LBindMac) }, { COMMAND, "local-bind-to-key", WIRED_CMD(LBindAKey) }, { COMMAND, "make-buffer-unmodified", WIRED_CMD(NotModified) }, { COMMAND, "make-macro-interactive", WIRED_CMD(MacInter) }, { COMMAND, "name-kbd-macro", WIRED_CMD(NameMac) }, { MODCMD, "newline", WIRED_CMD(Newline) }, { MODCMD, "newline-and-backup", WIRED_CMD(OpenLine) }, { MODCMD, "newline-and-indent", WIRED_CMD(LineAI) }, { COMMAND, "next-error", WIRED_CMD(NextError) }, { COMMAND, "next-line", WIRED_CMD(NextLine) }, { COMMAND, "next-page", WIRED_CMD(NextPage) }, { COMMAND, "next-window", WIRED_CMD(NextWindow) }, { COMMAND, "number-lines-in-window", WIRED_CMD(WNumLines) }, { DefMinor(OverWrite), "over-write-mode", NULLCMD }, { COMMAND, "page-next-window", WIRED_CMD(PageNWind) }, { MODCMD, "paren-flash", WIRED_CMD(DoParen) }, { COMMAND, "parse-errors", WIRED_CMD(ErrParse) }, #ifdef SPELL { COMMAND, "parse-spelling-errors-in-buffer", WIRED_CMD(SpelWords) }, #endif #ifdef JOB_CONTROL { COMMAND, "pause-jove", WIRED_CMD(PauseJove) }, #else # ifdef SUBSHELL { COMMAND, "pause-jove", WIRED_CMD(Push) }, # endif #endif { COMMAND, "pop-mark", WIRED_CMD(PopMark) }, { COMMAND, "popd", WIRED_CMD(Popd) }, { COMMAND, "previous-error", WIRED_CMD(PrevError) }, { COMMAND, "previous-line", WIRED_CMD(PrevLine) }, { COMMAND, "previous-page", WIRED_CMD(PrevPage) }, { COMMAND, "previous-window", WIRED_CMD(PrevWindow) }, { COMMAND, "print", WIRED_CMD(PrVar) }, #ifdef SUBSHELL { COMMAND, "proc-env-export", WIRED_CMD(ProcEnvExport) }, { COMMAND, "proc-env-show", WIRED_CMD(ProcEnvShow) }, { COMMAND, "proc-env-unset", WIRED_CMD(ProcEnvUnset) }, #endif #ifdef IPROCS { COMMAND, "process-bind-keymap-to-key", WIRED_CMD(PBindMap) }, { COMMAND, "process-bind-macro-to-key", WIRED_CMD(PBindMac) }, { COMMAND, "process-bind-to-key", WIRED_CMD(PBindAKey) }, { MODCMD, "process-newline", WIRED_CMD(ProcNewline) }, { COMMAND, "process-send-data-no-return", WIRED_CMD(ProcSendData) }, #endif #ifdef SUBSHELL { COMMAND, "push-shell", WIRED_CMD(Push) }, #endif { COMMAND, "pushd", WIRED_CMD(Pushd) }, { COMMAND, "pushlibd", WIRED_CMD(Pushlibd) }, { COMMAND, "pwd", WIRED_CMD(prCWD) }, { MODCMD, "query-replace-string", WIRED_CMD(QRepSearch) }, #ifdef IPROCS { COMMAND, "quit-process", WIRED_CMD(ProcQuit) }, #endif { MODCMD, "quoted-insert", WIRED_CMD(QuotChar) }, { DefMinor(BReadOnly), "read-only-mode", NULLCMD }, #ifdef ABBREV { COMMAND, "read-word-abbrev-file", WIRED_CMD(RestAbbrevs) }, #endif { COMMAND, "recursive-edit", WIRED_CMD(Recur) }, { COMMAND, "redraw-display", WIRED_CMD(RedrawDisplay) }, { COMMAND, "rename-buffer", WIRED_CMD(ReNamBuf) }, { MODCMD, "replace-in-region", WIRED_CMD(RegReplace) }, { MODCMD, "replace-string", WIRED_CMD(RepSearch) }, { COMMAND, "right-margin-here", WIRED_CMD(SetRMargin) }, { COMMAND, "save-file", WIRED_CMD(SaveFile) }, { COMMAND, "scroll-down", WIRED_CMD(DownScroll) }, { COMMAND, "scroll-left", WIRED_CMD(ScrollLeft) }, { COMMAND, "scroll-right", WIRED_CMD(ScrollRight) }, { COMMAND, "scroll-up", WIRED_CMD(UpScroll) }, { COMMAND, "search-forward", WIRED_CMD(ForSearch) }, { COMMAND, "search-forward-nd", WIRED_CMD(FSrchND) }, { COMMAND, "search-reverse", WIRED_CMD(RevSearch) }, { COMMAND, "search-reverse-nd", WIRED_CMD(RSrchND) }, { COMMAND, "select-buffer", WIRED_CMD(BufSelect) }, { COMMAND, "select-buffer-1", WIRED_CMD(Buf1Select) }, { COMMAND, "select-buffer-10", WIRED_CMD(Buf10Select) }, { COMMAND, "select-buffer-2", WIRED_CMD(Buf2Select) }, { COMMAND, "select-buffer-3", WIRED_CMD(Buf3Select) }, { COMMAND, "select-buffer-4", WIRED_CMD(Buf4Select) }, { COMMAND, "select-buffer-5", WIRED_CMD(Buf5Select) }, { COMMAND, "select-buffer-6", WIRED_CMD(Buf6Select) }, { COMMAND, "select-buffer-7", WIRED_CMD(Buf7Select) }, { COMMAND, "select-buffer-8", WIRED_CMD(Buf8Select) }, { COMMAND, "select-buffer-9", WIRED_CMD(Buf9Select) }, { MODCMD, "self-insert", WIRED_CMD(SelfInsert) }, { COMMAND, "set", WIRED_CMD(SetVar) }, { COMMAND, "set-mark", WIRED_CMD(SetMark) }, #ifdef IPROCS /* for GNU compatibility */ { COMMAND, "shell", WIRED_CMD(ShellProc) }, #endif #ifdef SUBSHELL { COMMAND, "shell-command", WIRED_CMD(ShellCom) }, { COMMAND, "shell-command-no-buffer", WIRED_CMD(ShNoBuf) }, { COMMAND, "shell-command-to-buffer", WIRED_CMD(ShToBuf) }, { COMMAND, "shell-command-with-typeout", WIRED_CMD(Shtypeout) }, #endif { MODCMD, "shift-region-left", WIRED_CMD(LRShift) }, { MODCMD, "shift-region-right", WIRED_CMD(RRShift) }, { DefMinor(ShowMatch), "show-match-mode", NULLCMD }, { COMMAND, "shrink-window", WIRED_CMD(ShrWindow) }, { COMMAND, "source", WIRED_CMD(Source) }, #ifdef SPELL { COMMAND, "spell-buffer", WIRED_CMD(SpelBuffer) }, #endif { COMMAND, "split-current-window", WIRED_CMD(SplitWind) }, { COMMAND, "start-remembering", WIRED_CMD(Remember) }, #ifdef PTYPROCS { COMMAND, "stop-process", WIRED_CMD(ProcStop) }, #endif { COMMAND, "stop-remembering", WIRED_CMD(Forget) }, { COMMAND, "string-length", WIRED_CMD(StrLength) }, #ifdef JOB_CONTROL { COMMAND, "suspend-jove", WIRED_CMD(PauseJove) }, #endif { COMMAND, "teach-jove", WIRED_CMD(TeachJove) }, { DefMajor(TEXTMODE), "text-mode", NULLCMD }, { MODCMD, "transpose-characters", WIRED_CMD(TransChar) }, { MODCMD, "transpose-lines", WIRED_CMD(TransLines) }, { COMMAND, "unbound", WIRED_CMD(Unbound) }, { COMMAND, "version", WIRED_CMD(ShowVersion) }, { COMMAND, "visible-spaces-in-window", WIRED_CMD(WVisSpace) }, { COMMAND, "visit-file", WIRED_CMD(JReadFile) }, { COMMAND, "window-find", WIRED_CMD(WindFind) }, #ifdef ABBREV { DefMinor(Abbrev), "word-abbrev-mode", NULLCMD }, #endif { COMMAND, "write-file", WIRED_CMD(JWriteFile) }, { COMMAND, "write-macros-to-file", WIRED_CMD(WriteMacs) }, { COMMAND, "write-modified-files", WIRED_CMD(WtModBuf) }, { COMMAND, "write-region", WIRED_CMD(WrtReg) }, #ifdef ABBREV { COMMAND, "write-word-abbrev-file", WIRED_CMD(SaveAbbrevs) }, #endif #ifdef MOUSE { COMMAND, "xj-mouse-copy-cut", WIRED_CMD(xjMouseCopyCut) }, { COMMAND, "xj-mouse-line", WIRED_CMD(xjMouseLine) }, { COMMAND, "xj-mouse-mark", WIRED_CMD(xjMouseMark) }, { COMMAND, "xj-mouse-point", WIRED_CMD(xjMousePoint) }, { COMMAND, "xj-mouse-word", WIRED_CMD(xjMouseWord) }, { COMMAND, "xj-mouse-yank", WIRED_CMD(xjMouseYank) }, { COMMAND, "xt-mouse-cut-point-yank", WIRED_CMD(xtMouseCutPointYank) }, { COMMAND, "xt-mouse-extend", WIRED_CMD(xtMouseExtend) }, { COMMAND, "xt-mouse-mark", WIRED_CMD(xtMouseMark) }, { COMMAND, "xt-mouse-mark-drag-point-copy", WIRED_CMD(xtMouseMarkDragPointCopy) }, { COMMAND, "xt-mouse-null", WIRED_CMD(xtMouseNull) }, { COMMAND, "xt-mouse-point", WIRED_CMD(xtMousePoint) }, { COMMAND, "xt-mouse-point-yank", WIRED_CMD(xtMousePointYank) }, { COMMAND, "xt-mouse-yank", WIRED_CMD(xtMouseYank) }, #endif { MODCMD, "yank", WIRED_CMD(Yank) }, { MODCMD, "yank-pop", WIRED_CMD(YankPop) }, { COMMAND, NULL, NULLCMD }, }; jove-4.17.5.5/dataobj.h000066400000000000000000000025601501102521500144660ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #define COMMAND 1 #define VARIABLE 2 #define MACRO 3 #define FULL_KEYMAP 4 #define SPARSE_KEYMAP 5 #ifdef MAC # define BUFFER 6 /* menus can point to buffers, too */ # define STRING 7 /* a menu string or divider */ #endif #define TYPEMASK 07 #define obj_type(o) ((o)->Type & TYPEMASK) #define MAJOR_MODE 010 #define MINOR_MODE 020 #define MODIFIER 040 #define MODCMD (COMMAND|MODIFIER) #define MAJOR_SHIFT 8 #define DefMajor(x) (COMMAND|MAJOR_MODE|((x) << MAJOR_SHIFT)) #define DefMinor(x) (COMMAND|MINOR_MODE|((x) << MAJOR_SHIFT)) /* prefix of cmd, macro, keymap, variable, and sometimes buffer structs */ typedef struct { int Type; const char *Name; } data_obj; extern const data_obj *LastCmd; /* last command invoked */ extern const char *ProcFmt; /* ": %f " -- name of LastCmd */ extern const data_obj *findcom proto((const char *prompt)), *findmac proto((const char *prompt)), *findvar proto((const char *prompt)); jove-4.17.5.5/delete.c000066400000000000000000000201071501102521500143140ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Routines to perform all kinds of deletion. */ #include "jove.h" #include "jctype.h" #include "disp.h" #include "delete.h" #include "insert.h" #include "marks.h" #include "move.h" /* Assumes that either line1 or line2 is actually the current line, so it can * put its result into linebuf. */ private void patchup(line1, char1, line2, char2) LinePtr line1, line2; register int char1, char2; { if (line1 != line2) ChkWindows(line1, line2); DotTo(line1, char1); modify(); linecopy(linebuf, curchar, lcontents(line2) + char2); /* The following is a redisplay optimization. */ if (line1 != line2 && (char1 == 0 && char2 == 0)) line1->l_dline = line2->l_dline; DFixMarks(line1, char1, line2, char2); makedirty(curline); } /* Deletes the region by unlinking the lines in the middle, * and patching things up. The unlinked lines are still in * order. */ LinePtr reg_delete(line1, char1, line2, char2) LinePtr line1, line2; int char1, char2; { register LinePtr retline; if ((line1 == line2 && char1 == char2) || line2 == NULL) { complain((char *)NULL); /* NOTREACHED */ } (void) fixorder(&line1, &char1, &line2, &char2); retline = nbufline(); /* New buffer line */ (void) ltobuf(line1, genbuf); if (line1 == line2) genbuf[char2] = '\0'; retline->l_prev = NULL; retline->l_dline = jputline(&genbuf[char1]); patchup(line1, char1, line2, char2); if (line1 == line2) retline->l_next = NULL; else { retline->l_next = line1->l_next; (void) ltobuf(line2, genbuf); genbuf[char2] = '\0'; line2->l_dline = jputline(genbuf); /* Shorten this line */ } if (line1 != line2) { line1->l_next = line2->l_next; if (line1->l_next) line1->l_next->l_prev = line1; else curbuf->b_last = line1; line2->l_next = NULL; } return retline; } private void lremove(line1, line2) register LinePtr line1, line2; { LinePtr next = line1->l_next; if (line1 == line2) return; line1->l_next = line2->l_next; if (line1->l_next) line1->l_next->l_prev = line1; else curbuf->b_last = line1; lfreereg(next, line2); /* Put region at end of free line list. */ } /* delete character forward */ void DelNChar() { del_char(FORWARD, arg_value(), YES); } /* Delete character backward */ void DelPChar() { if (MinorMode(OverWrite) && !eolp()) { /* Overwrite with spaces. * Some care is exercised to overwrite tabs reasonably, * but control characters displayed as two are not handled. */ int rightcol = calc_pos(linebuf, curchar); int charcount = jmin(arg_value(), curchar); int colcount = rightcol - calc_pos(linebuf, curchar-charcount); b_char(charcount); overwrite(' ', colcount); b_char(colcount); } else { del_char(BACKWARD, arg_value(), YES); } } /* Delete some characters. If deleting forward then call for_char * to the final position otherwise call back_char. Then delete the * region between the two with patchup(). */ void del_char(dir, num, OK_kill) int dir, num; jbool OK_kill; { Bufpos before, after; jbool killp = (OK_kill && (abs(num) > 1)); DOTsave(&before); if (dir == FORWARD) f_char(num); else b_char(num); if (before.p_line == curline && before.p_char == curchar) { complain((char *)NULL); /* NOTREACHED */ } if (killp) reg_kill(before.p_line, before.p_char, YES); else { DOTsave(&after); (void) fixorder(&before.p_line, &before.p_char, &after.p_line, &after.p_char); patchup(before.p_line, before.p_char, after.p_line, after.p_char); lremove(before.p_line, after.p_line); } } /* The kill ring. * Newest entry is at killptr; second newest is at killptr-1, etc. * All empty slots are at the end of the array. */ LinePtr killbuf[NUMKILLS]; int killptr = 0; /* index of newest entry (if any) */ void DelKillRing() /* delete newest entry */ { int i; lfreelist(killbuf[killptr]); /* free entry */ /* move space to end */ for (i = killptr; i != NUMKILLS-1; i++) killbuf[i] = killbuf[i+1]; killbuf[i] = NULL; /* make killptr index predecessor (if any) */ killptr = (killptr + NUMKILLS - 1) % NUMKILLS; while (killbuf[killptr] == NULL && killptr != 0) killptr -= 1; } private void AddKillRing(text) /* add a new entry */ LinePtr text; { if (killbuf[killptr] != NULL) { killptr = (killptr +1) % NUMKILLS; if (killbuf[NUMKILLS-1] == NULL) { /* there is space: move one slot here */ int i; for (i = NUMKILLS-1; i != killptr; i--) killbuf[i] = killbuf[i-1]; } else { /* no free slots: delete oldest element */ lfreelist(killbuf[killptr]); } } killbuf[killptr] = text; } /* This kills a region between point, and line1/char1 and puts it on * the kill-ring. If the last command was one of the kill commands, * the region is appended (prepended if backwards) to the last entry. */ void reg_kill(line2, char2, dot_moved) LinePtr line2; int char2; jbool dot_moved; { LinePtr nl, line1 = curline; int char1 = curchar; jbool backwards; backwards = !fixorder(&line1, &char1, &line2, &char2); /* This is a kludge! But it possible for commands that don't * know which direction they are deleting in (e.g., delete * previous word could have been called with a negative argument * in which case, it wouldn't know that it really deleted * forward. */ if (!dot_moved) backwards = !backwards; DotTo(line1, char1); nl = reg_delete(line1, char1, line2, char2); if (last_cmd != KILLCMD) { AddKillRing(nl); } else { LinePtr lastln = lastline(nl); if (backwards) { (void) DoYank(nl, 0, lastln, length(lastln), killbuf[killptr], 0, (Buffer *)NULL); } else { LinePtr olastln = lastline(killbuf[killptr]); (void) DoYank(nl, 0, lastln, length(lastln), olastln, length(olastln), (Buffer *)NULL); } } this_cmd = KILLCMD; } void DelReg() { register Mark *mp = CurMark(); reg_kill(mp->m_line, mp->m_char, NO); } /* get a new line buffer and add it to the kill ring */ LinePtr new_kill() { register LinePtr nl = nbufline(); AddKillRing(nl); SavLine(nl, NullStr); nl->l_next = nl->l_prev = NULL; return nl; } /* Save a region. A pretend kill. */ void CopyRegion() { register LinePtr nl; register Mark *mp; register int status; mp = CurMark(); if (mp->m_line == curline && mp->m_char == curchar) { complain((char *)NULL); /* NOTREACHED */ } nl = new_kill(); status = inorder(mp->m_line, mp->m_char, curline, curchar); if (status == -1) return; if (status) (void) DoYank(mp->m_line, mp->m_char, curline, curchar, nl, 0, (Buffer *)NULL); else (void) DoYank(curline, curchar, mp->m_line, mp->m_char, nl, 0, (Buffer *)NULL); } void DelWtSpace() { register char *ep = &linebuf[curchar], *sp = &linebuf[curchar]; while (jiswhite(*ep)) ep += 1; while (sp > linebuf && jiswhite(sp[-1])) sp -= 1; if (sp != ep) { curchar = sp - linebuf; DFixMarks(curline, curchar, curline, curchar + (int)(ep - sp)); /* Shift the remaining characters left in the buffer to close the gap. * strcpy(sp, ep) won't do because the destination overlaps the source. */ do {} while ((*sp++ = *ep++) != '\0'); makedirty(curline); modify(); } } void DelBlnkLines() { register Mark *dot; jbool all; if (!blnkp(&linebuf[curchar])) return; dot = MakeMark(curline, curchar); all = !blnkp(linebuf); while (blnkp(linebuf) && curline->l_prev) SetLine(curline->l_prev); all |= firstp(curline); Eol(); DelWtSpace(); line_move(FORWARD, 1, NO); while (blnkp(linebuf) && !eobp()) { DelWtSpace(); del_char(FORWARD, 1, NO); } if (!all && !eobp()) open_lines(1); ToMark(dot); DelMark(dot); } private void dword(forward) jbool forward; { Bufpos savedot; DOTsave(&savedot); if (forward) ForWord(); else BackWord(); reg_kill(savedot.p_line, savedot.p_char, YES); } void DelNWord() { dword(YES); } void DelPWord() { dword(NO); } jove-4.17.5.5/delete.h000066400000000000000000000022231501102521500143200ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern void del_char proto((int dir,int num,jbool OK_kill)), reg_kill proto((LinePtr line2, int char2, jbool dot_moved)); extern LinePtr reg_delete proto((LinePtr line1,int char1,LinePtr line2,int char2)), new_kill proto((void)); /* kill buffer */ #define NUMKILLS 16 /* number of kills saved in the kill ring */ extern LinePtr killbuf[NUMKILLS]; extern int killptr; /* index of newest entry (if any) */ extern void DelKillRing proto((void)); /* delete newest entry */ /* Commands: */ extern void CopyRegion proto((void)), DelBlnkLines proto((void)), DelNChar proto((void)), DelNWord proto((void)), DelPChar proto((void)), DelPWord proto((void)), DelReg proto((void)), DelWtSpace proto((void)); jove-4.17.5.5/disp.c000066400000000000000000001105471501102521500140210ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "chars.h" #include "fp.h" #include "disp.h" #include "ask.h" #include "extend.h" #include "fmt.h" #include "insert.h" /* #include "io.h" */ /* for pwd() */ #ifdef IPROCS # include "sysprocs.h" # include "iproc.h" #endif #include "move.h" #include "macros.h" #include "screen.h" #include "term.h" #include "wind.h" #ifdef MAC # include "mac.h" #else # include #endif /* define a couple of unique daddrs */ #define NOWHERE_DADDR (~NULL_DADDR | DDIRTY) /* not in tmp file */ #define UNSAVED_CURLINE_DADDR ((NOWHERE_DADDR - 1) | DDIRTY) /* not yet in tmp file */ struct screenline *Screen = NULL, /* the screen (a bunch of screenline) */ *Curline = NULL; /* current line */ private void DeTab proto((char *, int, char *, char *, jbool)), DoIDline proto((int)), do_cl_eol proto((int)), ModeLine proto((Window *, char *, int)), GotoDot proto((void)), UpdLine proto((int)), UpdWindow proto((Window *, int)); #ifdef ID_CHAR private void DelChar proto((int, int, int)), InsChar proto((int, int, int, char *)); private jbool IDchar proto ((char *, int)), OkayDelete proto ((int, int, jbool)), OkayInsert proto ((int, int)); private int NumSimilar proto ((char *, char *, int)), IDcomp proto ((char *, char *, int)); #endif /* ID_CHAR */ private jbool AddLines proto((int, int)), DelLines proto((int, int)); jbool DisabledRedisplay = NO; /* Kludge windows gets called by the routines that delete lines from the * buffer. If the w->w_line or w->w_top are deleted and this procedure * is not called, the redisplay routine will barf. */ void ChkWindows(line1, line2) LinePtr line1, line2; { register Window *w = fwind; register LinePtr lp, lend = line2->l_next; do { if (w->w_bufp == curbuf) { for (lp = line1->l_next; lp != lend; lp = lp->l_next) { if (lp == w->w_top) w->w_flags |= W_TOPGONE; if (lp == w->w_line) w->w_flags |= W_CURGONE; } } w = w->w_next; } while (w != fwind); } #ifdef WINRESIZE volatile jbool ResizePending = NO; /* asynch request for screen resize */ private void resize() { jbool oldDisabledRedisplay = DisabledRedisplay; int oldILI = ILI, oldCO = CO; DisabledRedisplay = YES; /* prevent tragedy */ ResizePending = NO; /* early & safe */ ttsize(); /* update line (LI and ILI) and col (CO) info. */ if (oldILI != ILI || oldCO != CO) { register int total; register Window *wp; /* Go through the window list, changing each window size in * proportion to the resize. If the window would become too * small, we delete it. * * Actually, we must do the deletion in * a separate pass because del_wind donates the space to either * neighbouring window. We test the windows in a funny order: * top-most, then bottom-up. Although it isn't necessary * for correctness, it means that we consider any donated * space, cutting down the number of windows we decide to delete. * Loop termination is tricky: fwind may have changed due to a * del_wind. As a simple fix, we start over whenever we * delete a window. Although this is O(n**2), it can't * really be expensive. * * After scaling all the windows, we * give any space remaining to the current window (which would * have changed if the old current window had been deleted). * * This seems fairer than just resizing the current window. */ wp = fwind; for (;;) { int newsize = ILI * wp->w_height / oldILI; if (newsize < 2) { del_wind(wp); wp = fwind; } else { wp = wp->w_prev; if (wp == fwind) break; } } total = 0; do { int newsize = ILI * wp->w_height / oldILI; wp->w_height = newsize; total += newsize; wp = wp->w_next; } while (wp != fwind); curwind->w_height += ILI - total; /* Make a new screen structure */ make_scr(); /* Do a 'hard' update on the screen - clear and redraw */ ClAndRedraw(); #ifdef WIN32 ResizeWindow(); #endif } DisabledRedisplay = oldDisabledRedisplay; } #endif /* WINRESIZE */ private jbool RingBell; /* So if we have a lot of errors ... ring the bell only ONCE */ void redisplay() { if (DisabledRedisplay) return; #ifdef WINRESIZE do #endif { register Window *w; int lineno, i; jbool done_ID = NO, old_UpdModLine; register struct scrimage *des_p, *phys_p; #ifdef WINRESIZE if (ResizePending) resize(); #endif curwind->w_line = curwind->w_bufp->b_dot; curwind->w_char = curwind->w_bufp->b_char; #ifdef MAC /* To avoid calling redisplay() recursively, * we must avoid calling CheckEvent(), * so we must avoid calling charp(). */ InputPending = NO; #else if (PreEmptOutput()) return; #endif if (RingBell) { dobell(1); RingBell = NO; } AbortCnt = ScrBufSize; /* initialize this now */ if (UpdMesg) DrawMesg(YES); for (lineno = 0, w = fwind; lineno < ILI; w = w->w_next) { UpdWindow(w, lineno); lineno += w->w_height; } /* Now that we've called update window, we can * assume that the modeline will be updated. But * if while redrawing the modeline the user types * a character, ModeLine() is free to set this on * again so that the modeline will be fully drawn * at the next redisplay. Furthermore, if output * is preempted, we'll restore the old value because * we can't be sure that the updating has happened. */ old_UpdModLine = UpdModLine; UpdModLine = NO; des_p = DesiredScreen; phys_p = PhysScreen; for (i = 0; i < ILI; i++, des_p++, phys_p++) { if (!done_ID && (des_p->s_id != phys_p->s_id)) { DoIDline(i); done_ID = YES; } if ((des_p->s_flags & (s_DIRTY | s_L_MOD)) || des_p->s_id != phys_p->s_id || des_p->s_vln != phys_p->s_vln || des_p->s_offset != phys_p->s_offset) UpdLine(i); if (CheapPreEmptOutput()) { if (old_UpdModLine) UpdModLine = YES; goto suppress; } } if (Asking) { int p = calc_pos(mesgbuf, AskingWidth); jdbg("redisplay CO=%d aw=%d p=%d \"%s\"\n", CO, AskingWidth, p, mesgbuf); Placur(ILI, jmin(CO - 2, p)); /* Nice kludge */ flushscreen(); } else { GotoDot(); } suppress: ; } #ifdef WINRESIZE /**/ while (ResizePending); #endif #ifdef MAC if (Windchange) docontrols(); #endif } /* find_pos() returns the position on the line, that C_CHAR represents * in LINE */ private int find_pos(line, c_char) LinePtr line; int c_char; { return calc_pos(lcontents(line), c_char); } /* calc_pos calculates the screen column of character c_char. * * Note: the calc_pos, how_far, and DeTab must be in synch -- * each thinks it knows how characters are displayed. */ int calc_pos(lp, c_char) register char *lp; register int c_char; { register int pos = 0; register ZXchar c; while ((--c_char >= 0) && (c = ZXC(*lp++)) != 0) { if (c == '\t' && tabstop != 0) { pos += TABDIST(pos); } else if (jisprint(c)) { pos += 1; } else { if (c <= DEL) pos += 2; else pos += 4; } } return pos; } volatile jbool UpdModLine = NO; jbool UpdMesg = NO; private void DoIDline(start) int start; { register struct scrimage *des_p = &DesiredScreen[start]; struct scrimage *phys_p = &PhysScreen[start]; register int i, j; /* Some changes have been made. Try for insert or delete lines. * If either case has happened, Addlines and/or DelLines will do * necessary scrolling, also CONVERTING PhysScreen to account for the * physical changes. The comparison continues from where the * insertion/deletion takes place; this doesn't happen very often, * usually it happens with more than one window with the same * buffer. */ #ifdef TERMCAP if (!CanScroll) return; /* We should never have been called! */ #endif for (i = start; i < ILI; i++, des_p++, phys_p++) if (des_p->s_id != phys_p->s_id) break; for (; i < ILI; i++) { for (j = i + 1; j < ILI; j++) { des_p = &DesiredScreen[j]; phys_p = &PhysScreen[j]; if (des_p->s_id != NULL_DADDR && des_p->s_id == phys_p->s_id) break; if (des_p->s_id == PhysScreen[i].s_id) { if (des_p->s_id == NULL_DADDR) continue; if (AddLines(i, j - i)) { DoIDline(j); return; } break; } if ((des_p = &DesiredScreen[i])->s_id == phys_p->s_id) { if (des_p->s_id == NULL_DADDR) continue; if (DelLines(i, j - i)) { DoIDline(i); return; } break; } } } } /* Make DesiredScreen reflect what the screen should look like when we are done * with the redisplay. This deals with horizontal scrolling. Also makes * sure the current line of the Window is in the window. */ jbool ScrollAll = NO; /* VAR: when current line scrolls, scroll whole window? */ int ScrollWidth = 10; /* VAR: unit of horizontal scrolling */ private void UpdWindow(w, start) register Window *w; int start; { LinePtr lp; long i, upper, /* top of window */ lower; /* bottom of window */ int strt_col, /* starting print column of current line */ ntries = 0; /* # of tries at updating window */ register struct scrimage *des_p, *phys_p; Buffer *bp = w->w_bufp; do { if (w->w_flags & W_CURGONE) { w->w_line = bp->b_dot; w->w_char = bp->b_char; } if (w->w_flags & W_TOPGONE) CentWind(w); /* reset topline of screen */ w->w_flags &= ~(W_CURGONE | W_TOPGONE); /* make sure that the current line is in the window */ upper = start; lower = upper + WSIZE(w); for (i = upper, lp = w->w_top; ; lp = lp->l_next, i++) { if (i == lower || lp == NULL) { /* we've run out of window without finding dot */ ntries += 1; if (ntries == 1) { CalcWind(w); } else if (ntries == 2) { w->w_top = w->w_line = w->w_bufp->b_first; writef("\rERROR in redisplay: I got hopelessly lost!"); dobell(2); } else { writef("\n\rOops, still lost, quitting ...\r\n"); finish(-1); /* die! */ /*NOTREACHED*/ } break; } if (lp == w->w_line) { ntries = 0; /* happiness: dot is in window */ break; } } } while (ntries != 0); /* first do some calculations for the current line */ { int nw = W_NUMWIDTH(w), dot_col, end_col; strt_col = ScrollAll? w->w_LRscroll : PhysScreen[i].s_offset; end_col = strt_col + (CO - 1) - (nw + SIWIDTH(strt_col)); /* Right now we are displaying from strt_col to * end_col of the buffer line. These are PRINT * columns, not actual characters. */ dot_col = w->w_dotcol = find_pos(w->w_line, w->w_char); /* if the new dotcol is out of range, reselect * a horizontal window */ if (PhysScreen[i].s_offset == -1 || !(strt_col <= dot_col && dot_col < end_col)) { /* If dot_col is within first step left of screen, step left. * Otherwise, if ditto for right. * Otherwise, if it is in first screenwidth, start from begining. * Otherwise, center dot_col. * Fudge: if a scroll left would work except for the necessary * appearance of an ! on the left, we scroll an extra column. */ int step = jmin(ScrollWidth, end_col - strt_col); strt_col = strt_col > dot_col && strt_col - step <= dot_col ? jmax(strt_col - step, 0) : dot_col >= end_col && dot_col < end_col + step ? jmin(strt_col + step + (strt_col == 0 && dot_col == end_col + step - 1? 1 : 0) , dot_col) : dot_col < ((CO - 1) - nw) ? 0 : dot_col - ((CO - nw) / 2); if (ScrollAll) { if (w->w_LRscroll != strt_col) UpdModLine = YES; w->w_LRscroll = strt_col; } } w->w_dotline = i; w->w_dotcol = dot_col + nw + SIWIDTH(strt_col); } lp = w->w_top; des_p = &DesiredScreen[upper]; phys_p = &PhysScreen[upper]; for (i = upper; i < lower; i++, des_p++, phys_p++) { if (lp != NULL) { des_p->s_offset = (lp == w->w_line)? strt_col : w->w_LRscroll; des_p->s_flags = isdirty(lp) ? s_L_MOD : 0; des_p->s_vln = (w->w_flags & W_NUMLINES)? w->w_topnum + (i - upper) : 0; des_p->s_id = (lp == curline && DOLsave)? UNSAVED_CURLINE_DADDR : lp->l_dline & ~DDIRTY; des_p->s_lp = lp; lp = lp->l_next; } else { /* display line beyond end of buffer */ static const struct scrimage clean_plate = { 0, 0, 0, NULL_DADDR, NULL, NULL }; *des_p = clean_plate; if (phys_p->s_id != NULL_DADDR) des_p->s_flags = s_DIRTY; } des_p->s_window = w; } /* mode line: */ /* ??? The following assignment to des_p->s_id is tricky: * * We count on the cast pointer value being distinct from * any other daddr, but equal to itself. Turning * the "DDIRTY" bit on should ensure that it is distinct * from legitimate daddr values (except for NOWHERE_DADDR * and UNSAVED_CURLINE_DADDR). * If sizeof(Buffer *)>sizeof(daddr), nothing ensures that * these pointers are even distinct from each other. * * There also seems to be an assumption that every modeline * for a particular buffer will be the same. This is not * always the case: the last modeline on the screen is usually * different from any other modeline, even for the same buffer. * Currently, I think that only very contrived cases could cause * problems (probably involving window resizing). * Further problems will arise if JOVE is changed so that there are * other ways in which a modeline can reflect the window state * (instead of just the buffer state). * * -- DHR */ des_p->s_window = w; des_p->s_id = (jwid_t) w->w_bufp | DDIRTY; des_p->s_flags = (des_p->s_id != phys_p->s_id || UpdModLine)? s_MODELINE | s_DIRTY : 0; des_p->s_offset = 0; des_p->s_vln = 0; des_p->s_lp = NULL; #ifdef MAC if (UpdModLine) Modechange = YES; if (w == curwind && w->w_control != NULL) SetScrollBar(w); #endif } /* Write whatever is in mesgbuf (maybe we are Asking, or just printed * a message). Turns off the UpdateMesg line flag. */ void DrawMesg(abortable) jbool abortable; { char outbuf[MAXCOLS + PPWIDTH]; /* assert(CO <= MAXCOLS); */ #ifndef MAC /* same reason as in redisplay() */ if (PreEmptOutput()) return; #endif i_set(ILI, 0); jdbg("DrawMesg aw=%d \"%s\"\n", AskingWidth, mesgbuf); DeTab(mesgbuf, 0, outbuf, outbuf + CO, NO); if (swrite(outbuf, NOEFFECT, abortable)) { cl_eol(); UpdMesg = NO; } flushscreen(); } /* Goto the current position in the current window. Presumably redisplay() * has already been called, and curwind->{w_dotline,w_dotcol} have been set * correctly. */ private void GotoDot() { if (!CheapPreEmptOutput()) { Placur(curwind->w_dotline, curwind->w_dotcol - PhysScreen[curwind->w_dotline].s_offset); flushscreen(); } } private int UntilEqual(start) register int start; { register struct scrimage *des_p = &DesiredScreen[start], *phys_p = &PhysScreen[start]; while ((start < ILI) && (des_p->s_id != phys_p->s_id)) { des_p += 1; phys_p += 1; start += 1; } return start; } /* Calls the routine to do the physical changes, and changes PhysScreen to * reflect those changes. */ private jbool AddLines(at, num) register int at, num; { register int i; int bottom = UntilEqual(at + num); if (num == 0 || num >= ((bottom - 1) - at)) return NO; /* we did nothing */ v_ins_line(num, at, bottom - 1); /* Now change PhysScreen to account for the physical change. */ for (i = bottom - 1; i - num >= at; i--) PhysScreen[i] = PhysScreen[i - num]; for (i = 0; i < num; i++) PhysScreen[at + i].s_id = NULL_DADDR; return YES; /* we did something */ } private jbool DelLines(at, num) register int at, num; { register int i; int bottom = UntilEqual(at + num); if (num == 0 || num >= ((bottom - 1) - at)) return NO; v_del_line(num, at, bottom - 1); for (i = at; num + i < bottom; i++) PhysScreen[i] = PhysScreen[num + i]; for (i = bottom - num; i < bottom; i++) PhysScreen[i].s_id = NULL_DADDR; return YES; } jbool MarkHighlighting = YES; /* VAR: highlight mark when visible */ /* Update line linenum in window w. Only set PhysScreen to DesiredScreen * if the swrite or cl_eol works, that is nothing is interrupted by * characters typed. */ private void UpdLine(linenum) register int linenum; { register struct scrimage *des_p = &DesiredScreen[linenum]; register Window *w = des_p->s_window; char outbuf[MAXCOLS + PPWIDTH]; /* assert(CO <= MAXCOLS); */ i_set(linenum, 0); if (des_p->s_flags & s_MODELINE) { ModeLine(w, outbuf, linenum); } else if (des_p->s_id != NULL_DADDR) { char *lptr; int fromcol = W_NUMWIDTH(w); #ifdef HIGHLIGHTING static struct LErange lr = {0, 0, LENULLPROC, US_effect}; Mark *mark = b_curmark(w->w_bufp); jbool marked_line = (MarkHighlighting # ifdef TERMCAP && US != NULL # endif && mark != NULL && mark->m_line == des_p->s_lp); #endif /* HIGHLIGHTING */ des_p->s_lp->l_dline &= ~DDIRTY; des_p->s_flags &= ~(s_DIRTY | s_L_MOD); if (w->w_flags & W_NUMLINES) { outbuf[fromcol-2] = ' '; swritef(outbuf, sizeof(outbuf), "%6D ", des_p->s_vln); if (outbuf[fromcol-2] != ' ') { outbuf[fromcol-2] = '*'; outbuf[fromcol-1] = ' '; } } if (des_p->s_offset != 0) { outbuf[fromcol++] = '!'; outbuf[fromcol] = '\0'; } lptr = lcontents(des_p->s_lp); DeTab(lptr, des_p->s_offset, outbuf + fromcol, outbuf + CO, (w->w_flags & W_VISSPACE) != 0); #ifdef HIGHLIGHTING if (marked_line) { lr.start = calc_pos(lptr, mark->m_char) - des_p->s_offset + fromcol; lr.width = 1; if (lr.start < sizeof(outbuf) - 1 && outbuf[lr.start] == '\0') { outbuf[lr.start] = ' '; outbuf[lr.start + 1] = '\0'; } } #endif /* HIGHLIGHTING */ #ifdef ID_CHAR /* REMIND: This code, along with the rest of the * ID_CHAR, belongs in the screen driver for * termcap based systems. mac and pc's and other * window-based drivers don't give a hoot about * ID_CHAR. */ /* attempt to exploit insert or delete character capability * but only if not highlighting some part of the line */ if (UseIC && Curline->s_effects == NOEFFECT # ifdef HIGHLIGHTING && !marked_line # endif /* HIGHLIGHTING */ ) { if (IDchar(outbuf, linenum)) { /* success: clean up and go home */ PhysScreen[linenum] = *des_p; return; } /* failure: re-initialize various cursors */ i_set(linenum, 0); } #endif /* ID_CHAR */ if (swrite(outbuf, #ifdef HIGHLIGHTING marked_line ? &lr : NOEFFECT, #else NOEFFECT, #endif YES)) { do_cl_eol(linenum); } else { /* interrupted: mark indeterminate state */ PhysScreen[linenum].s_id = NOWHERE_DADDR; } } else if (PhysScreen[linenum].s_id != NULL_DADDR) { /* not the same ... make sure */ do_cl_eol(linenum); } } private void do_cl_eol(linenum) register int linenum; { cl_eol(); PhysScreen[linenum] = DesiredScreen[linenum]; } /* Expand tabs (and other funny characters) of a section of "buf" * into "outbuf". * * Note: outbuf must allow for at least PPWIDTH extra characters. * This is sufficient room for one extra character to be displayed, * streamlining the code. * * Note: the calc_pos, how_far, and DeTab must be in synch -- * each thinks it knows how characters are displayed. */ private void DeTab(src, start_offset, dst, dst_limit, visspace) char *src; int start_offset; char *dst; char *dst_limit; jbool visspace; { ZXchar c; int offset = start_offset; /* At any time, the number of characters we've output is * start_offset - offset. This is needed to correctly * calculate TABDIST() without having to add another * variable (pos) to be incremented for each call to addc. */ #define addc(ch) { if (--offset < 0) *dst++ = (ch); } while ((c = ZXC(*src++)) != '\0') { if (c == '\t' && tabstop != 0) { int nchars = TABDIST(start_offset - offset); c = visspace? '>' : ' '; while (--nchars > 0 && dst < dst_limit) { addc(c); c = ' '; } } else if (jisprint(c)) { if (visspace && c == ' ') c = '_'; } else { char buf[PPWIDTH]; char *p; PPchar(c, buf); /* assert(buf[0] != '\0'); */ for (p = buf; (c = *p++), *p != '\0'; ) addc(c); } if (--offset < 0) { *dst++ = c; if (dst >= dst_limit) { /* we've run out of real estate: truncate and flag it */ dst = dst_limit-1; *dst++ = '!'; break; } } } #undef addc *dst = '\0'; } #ifdef ID_CHAR /* From here to the end of the file is code that tries to utilize the * insert/delete character feature on some terminals. It is very confusing * and not so well written code, AND there is a lot of it. You may want * to use the space for something else. */ jbool IN_INSmode = NO; void INSmode(on) jbool on; { if (on != IN_INSmode) { putpad(on? IM : EI, 1); IN_INSmode = on; } } /* ID character routines full of special cases and other fun stuff like that. * It actually works though ... * * Returns Non-Zero if you are finished (no differences left). */ private jbool IDchar(new, lineno) register char *new; int lineno; { register int col = 0; struct screenline *sline = &Screen[lineno]; register char *old = sline->s_line; int newlen = strlen(new); for (;;) { int oldlen = sline->s_roof - old; int i; for (; ; col++) { if (col == oldlen || col == newlen) return oldlen == newlen; /* one ended; happy if both ended */ if (old[col] != new[col]) break; } /* col now is first difference, and not the end of either */ /* see if an insertion will help */ for (i = col + 1; i < newlen; i++) { if (new[i] == old[col]) { /* The number of saved characters is (roughly) * the number of characters we can retain after * the insertion, minus the number that we * could have salvaged without moving them. */ int NumSaved = IDcomp(new + i, old + col, oldlen-col) - NumSimilar(new + col, old + col, jmin(i, oldlen)-col); if (OkayInsert(NumSaved, i - col)) { InsChar(lineno, col, i - col, new); col = i; break; } } } if (i != newlen) continue; /* see if a deletion will help */ for (i = col + 1; i < oldlen; i++) { if (new[col] == old[i]) { int NumSaved = IDcomp(new + col, old + i, oldlen - i); if (OkayDelete(NumSaved, i - col, newlen == oldlen)) { DelChar(lineno, col, i - col); break; } } } if (i != oldlen) continue; return NO; } } private int NumSimilar(s, t, n) register char *s, *t; int n; { register int num = 0; while (n--) if (*s++ == *t++) num += 1; return num; } private int IDcomp(s, t, len) register char *s, /* NUL terminated */ *t; /* len chars */ int len; { register int i; int num = 0, nonspace = 0; for (i = 0; i < len; i++) { char c = *s++; if (c == '\0' || c != *t++) break; if (c != ' ') nonspace = 1; num += nonspace; } return num; } private jbool OkayDelete(Saved, num, samelength) int Saved, num; jbool samelength; { /* If the old and the new have different lengths, then the competition * will have to clear to end of line. We take that into consideration. * Note: we must avoid multiplying by INFINITY. */ return Saved + (samelength ? 0 : CElen) > jmin(MDClen, DC != NULL? DClen * num : INFINITY); } private jbool OkayInsert(Saved, num) int Saved, num; { # ifdef NCURSES_BUG /* Note: with the ncurses version of termcap/terminfo, we must use * any one of insert mode, insert character, or multiple insert character. */ register int n = INFINITY; if (IC != NULL) /* Per character prefixes */ n = num * IClen; n = jmin(n, MIClen); n = jmin(n, IMEIlen); # else /* !NCURSES_BUG */ /* Note: the way termcap/terminfo is defined, we must use *both* * IC and IM to insert, but normally only one will be defined. * See terminfo(5), under the heading "Insert/Delete Character". */ register int n = 0; if (IC != NULL) /* Per character prefixes */ n = jmin(num * IClen, MIClen); if (!IN_INSmode) n += IMEIlen; # endif /* !NCURSES_BUG */ n += num; /* The characters themselves */ return Saved > n; } private void DelChar(lineno, col, num) int lineno, col, num; { struct screenline *sp = (&Screen[lineno]); Placur(lineno, col); putmulti(DC, M_DC, num, 1); /* Shift the remaining characters left in the buffer to close the gap. * byte_copy cannot be used since the destination overlaps the source. */ { register char *to = sp->s_line + col, *from = to + num; register size_t len = sp->s_roof - from; byte_move(from, to, len); } clrline(sp->s_roof - num, sp->s_roof); sp->s_roof -= num; } private void InsChar(lineno, col, num, new) int lineno, col, num; char *new; { register char *sp1, *sp2, /* To push over the array. */ *sp3; /* Last character to push over. */ int i; i_set(lineno, 0); sp2 = Curline->s_roof + num; if (sp2 > cursend) { i_set(lineno, CO - num - 1); cl_eol(); sp2 = cursend; } Curline->s_roof = sp2; sp1 = sp2 - num; sp3 = Curline->s_line + col; while (sp1 > sp3) *--sp2 = *--sp1; new += col; byte_copy(new, sp3, (size_t) num); /* The internal screen is correct, and now we have to do * the physical stuff. */ Placur(lineno, col); # ifdef NCURSES_BUG /* Note: with the ncurses version of termcap/terminfo, we must use * any one of insert mode, insert character, or multiple insert character. */ if (IN_INSmode || ((IC == NULL || IMEIlen < num * IClen) && IMEIlen < MIClen)) INSmode(YES); else putmulti(IC, M_IC, num, 1); # else /* !NCURSES_BUG */ /* Note: the way termcap/terminfo is defined, we must use *both* * IC and IM, but normally only one will be defined. * See terminfo(5), under the heading "Insert/Delete Character". */ if (IC != NULL) putmulti(IC, M_IC, num, 1); if (IM != NULL) INSmode(YES); # endif /* !NCURSES_BUG */ for (i = 0; i < num; i++) { scr_putchar(new[i]); if (IN_INSmode) putpad(IP, 1); } CapCol += num; } #endif /* ID_CHAR */ #ifdef UNIX /* obviously ... no mail today if not Unix*/ /* chkmail() returns YES if there is new mail since the * last time we checked. */ char Mailbox[FILESIZE]; /* VAR: mailbox name */ int MailInt = 60; /* VAR: mail check interval (seconds) */ jbool chkmail(force) jbool force; { time_t now; static jbool state = NO; /* assume unknown */ static time_t last_chk = 0, mbox_time = 0; struct stat stbuf; if (MailInt == 0 || Mailbox[0] == '\0') return NO; time(&now); if ((force == NO) && (now < last_chk + MailInt)) return state; last_chk = now; if (stat(Mailbox, &stbuf) < 0) { state = NO; /* no mail */ return NO; } if ((stbuf.st_atime > stbuf.st_mtime && stbuf.st_atime > mbox_time) || stbuf.st_size == 0) { mbox_time = stbuf.st_atime; state = NO; } else if (stbuf.st_mtime > mbox_time) { if (mbox_time > 0) dobell(2); /* announce the change */ mbox_time = stbuf.st_mtime; state = YES; } return state; } #endif /* UNIX */ /* Print the mode line. */ private char *mode_p, *mend_p; jbool BriteMode = YES; /* VAR: make the mode line inverse? */ private void mode_app(str) register const char *str; { ZXchar c; while (mode_p < mend_p && (c = ZXC(*str++)) != '\0') { /* don't expand tabs: treat them as suspects */ if (jisprint(c)) { *mode_p++ = c; } else { char buf[PPWIDTH]; PPchar(c, buf); mode_app(buf); } } } /* VAR: mode line format string */ char ModeFmt[MAXCOLS] = "%[Jove%]%w%w%c(%M)%3c[%b:%n]%2c\"%f\"%c%i# %m*-%2c%p%2s%(%d%e(%t)%)"; private void ModeLine(w, line, linenum) register Window *w; char *line; /* scratch space of at least CO chars */ int linenum; { int n, glue = 0; jbool ign_some = NO; jbool td = NO; /* is time (kludge: or mail status) displayed? */ char *fmt = ModeFmt, fillc, c; register Buffer *thisbuf = w->w_bufp; register Buffer *bp; LineEffects highlighting; mode_p = line; mend_p = &line[CO - 1]; #ifdef TERMCAP if (SO == NULL) BriteMode = NO; /* we can't do it */ #endif /* ??? On Mac, perhaps '_' looks better than '-' */ fillc = BriteMode? ' ' : '-'; while ((c = *fmt++)!='\0' && mode_p= '0' && c <= '9') { n = 0; while (c >= '0' && c <= '9') { n = n * 10 + (c - '0'); c = *fmt++; } if (c == '\0') break; } switch (c) { case '%': mode_app("%"); break; case '(': if (w->w_next != fwind) /* Not bottom window. */ ign_some = YES; break; case ')': ign_some = NO; break; case '[': case ']': for (n=RecDepth; n>0 && mode_pb_minor; const char *const *p; mode_app(majname[thisbuf->b_major]); for (p = minname; minors != 0; p++) { if (minors & 01) mode_app(*p); minors >>= 1; } if (InMacDefine) mode_app(" Def"); break; } case 'c': while (--n>=0 && mode_pb_name); break; case 'f': case 'F': if (thisbuf->b_fname == NULL) mode_app("[No file]"); else { if (c == 'f') mode_app(pr_name(thisbuf->b_fname, YES)); else mode_app(jbasename(thisbuf->b_fname)); } break; case 'i': { char yea = (*fmt == '\0') ? '#' : *fmt++; char nay = (*fmt == '\0') ? ' ' : *fmt++; *mode_p++ = w->w_bufp->b_diverged ? yea : nay; break; } case 'm': { char yea = (*fmt == '\0') ? '*' : *fmt++; char nay = (*fmt == '\0') ? ' ' : *fmt++; *mode_p++ = IsModified(w->w_bufp) ? yea : nay; break; } case 'n': { char tmp[16]; for (bp = world, n = 1; bp != NULL; bp = bp->b_next, n++) if (bp == thisbuf) break; swritef(tmp, sizeof(tmp), "%d", n); mode_app(tmp); break; } case 'p': #ifdef IPROCS if (thisbuf->b_type == B_PROCESS) { char tmp[40]; swritef(tmp, sizeof(tmp), "(%s)", pstate(thisbuf->b_process)); mode_app(tmp); } #endif break; case 's': if (mode_p[-1] != ' ') *mode_p++ = ' '; break; case 't': { char timestr[12]; td = YES; mode_app(get_time((time_t *)NULL, timestr, 11, 16)); break; } case 'w': if (w->w_LRscroll > 0) mode_app(">"); break; default: mode_app("?"); break; } } /* Glue (Knuth's term) is a field that expands to fill * any leftover space. Multiple glue fields compete * on an equal basis. This is a generalization of a * mechanism to allow centring and right-justification. * The original meaning of %e (fill the rest of the * line) has also been generalized. %e can now * meaningfully be used 0 or more times. */ if (glue) { /* 1 space unused, plus padding for magic cookies */ register char *to = &line[CO - 1 - (4 * SG)], *from = mode_p; if (to < from) to = from; mode_p = to; while (from != line) { if ((*--to = *--from) == '\0') { register int portion = (to-from) / glue; glue--; *to = fillc; while (--portion >= 0) *--to = fillc; } } } else { while (mode_p < &line[CO - 1 - (4 * SG)]) *mode_p++ = fillc; } *mode_p = '\0'; /* Highlight mode line. */ highlighting = NOEFFECT; if (BriteMode) { highlighting = WindowRange(w); #ifdef HIGHLIGHTING { char *p = &line[highlighting->start], *e = p + highlighting->width; for (; p != e; p++) if (*p == ' ') *p = '-'; } #endif } if (w->w_next == fwind && TimeDisplayed != td) { TimeDisplayed = td; #ifdef UNIX SetClockAlarm(YES); #endif } #ifdef ID_CHAR INSmode(NO); #endif if (swrite(line, highlighting, YES)) do_cl_eol(linenum); else UpdModLine = YES; } /* This tries to place the current line of the current window in the * center of the window, OR to place it at the arg'th line of the window. * This also causes the horizontal position of the line to be centered, * if the line needs scrolling, or moved all the way back to the left, * if that's possible. */ void RedrawDisplay() { int line; LinePtr newtop = prev_line((curwind->w_line = curline), arg_or_default(WSIZE(curwind)/2)); if ((line = in_window(curwind, curwind->w_line)) != -1) PhysScreen[line].s_offset = -1; if (newtop == curwind->w_top) ClAndRedraw(); else SetTop(curwind, newtop); } void ClAndRedraw() { cl_scr(YES); } void NextPage() { LinePtr newline; if (Asking) { /* don't do it */ } else if (arg_value() < 0) { negate_arg(); PrevPage(); } else if (is_non_minus_arg()) { UpScroll(); } else { if (in_window(curwind, curwind->w_bufp->b_last) != -1) { rbell(); return; } newline = next_line(curwind->w_top, jmax(1, WSIZE(curwind) - 1)); SetTop(curwind, curwind->w_line = newline); if (curwind->w_bufp == curbuf) SetLine(newline); } } void PrevPage() { LinePtr newline; if (Asking) { /* don't do it */ } else if (arg_value() < 0) { negate_arg(); NextPage(); } else if (is_non_minus_arg()) { DownScroll(); } else { newline = prev_line(curwind->w_top, jmax(1, WSIZE(curwind) - 1)); SetTop(curwind, curwind->w_line = newline); if (curwind->w_bufp == curbuf) SetLine(newline); } } void UpScroll() { SetTop(curwind, next_line(curwind->w_top, arg_value())); if (curwind->w_bufp == curbuf && in_window(curwind, curline) == -1) SetLine(curwind->w_top); } void DownScroll() { SetTop(curwind, prev_line(curwind->w_top, arg_value())); if (curwind->w_bufp == curbuf && in_window(curwind, curline) == -1) SetLine(curwind->w_top); } jbool VisBell = NO; /* VAR: use visible bell (if possible) */ void rbell() { RingBell = YES; } /* Message prints the null terminated string onto the bottom line of the * terminal. */ void message(str) const char *str; { if (InJoverc) return; UpdMesg = YES; stickymsg = NO; if (str != mesgbuf) truncstr(mesgbuf, str); } /* End of Window */ void Eow() { if (Asking) return; SetLine(next_line(curwind->w_top, WSIZE(curwind) - 1 - jmin(WSIZE(curwind) - 1, arg_value() - 1))); if (!is_an_arg()) Eol(); } /* Beginning of Window */ void Bow() { if (Asking) return; SetLine(next_line(curwind->w_top, jmin(WSIZE(curwind) - 1, arg_value() - 1))); } /* Typeout Mechanism */ jbool UseBuffers = NO, /* VAR: use buffers with Typeout() */ TOabort = NO; private int LineNo; /* screen line for Typeout (if not UseBuffers) */ private Window *old_wind; /* curwind before preempted by typeout to buffer */ /* This initializes the typeout. If send-typeout-to-buffers is set * the buffer NAME is created (emptied if it already exists) and output * goes to the buffer. Otherwise output is drawn on the screen and * erased by TOstop() */ void TOstart(name) const char *name; { if (UseBuffers) { old_wind = curwind; pop_wind(name, YES, B_SCRATCH); } else DisabledRedisplay = YES; TOabort = NO; LineNo = 0; } private void TOlineFits(s) char *s; { i_set(LineNo, 0); (void) swrite(s, NOEFFECT, NO); PhysScreen[LineNo].s_id = NOWHERE_DADDR; cl_eol(); flushscreen(); } private void TOprompt(s) char *s; { if (!TOabort) { register ZXchar c; TOlineFits(s); c = kbd_getch(); TOlineFits(""); if (c != ' ') { TOabort = YES; if (c != AbortChar) kbd_ungetch(c); } } } #ifdef STDARGS void Typeout(const char *fmt, ...) #else /*VARARGS1*/ void Typeout(fmt, va_alist) const char *fmt; va_dcl #endif { char string[MAX_TYPEOUT+1]; va_list ap; va_init(ap, fmt); format(string, sizeof string, fmt, ap); va_end(ap); if (UseBuffers) { ins_str(string); ins_str("\n"); } else { char outbuf[MAXCOLS + PPWIDTH]; /* assert(CO <= MAXCOLS); */ if (LineNo == ILI - 2) { TOprompt("--more--"); LineNo = 0; } if (!TOabort) { DeTab(string, 0, outbuf, outbuf + CO, NO); TOlineFits(outbuf); LineNo += 1; } } } void TOstop() { if (UseBuffers) { ToFirst(); SetWind(old_wind); } else { TOprompt("--end--"); DisabledRedisplay = NO; } } jove-4.17.5.5/disp.h000066400000000000000000000057061501102521500140260ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #define makedirty(line) { (line)->l_dline |= DDIRTY; } #define isdirty(line) ((line)->l_dline & DDIRTY) typedef DADDR jwid_t; /* DADDR must be >= max(sizeof(daddr),sizeof(Buffer *)) */ struct scrimage { int s_offset, /* offset to start printing at */ s_flags; /* various flags */ long s_vln; /* Visible Line Number */ jwid_t s_id; /* unique identifier for line */ LinePtr s_lp; /* line to display (if any) */ Window *s_window; /* window that contains this line */ }; /* s_flags flags */ #define s_DIRTY 01 /* buffer line changed since last displayed */ #define s_MODELINE 02 /* this is a modeline */ #define s_L_MOD 04 /* line has been modified internally */ extern struct scrimage *DesiredScreen, /* what we want */ *PhysScreen; /* what we got */ extern jbool UpdMesg; /* update the message line */ extern jbool chkmail proto((jbool force)); extern int calc_pos proto((char *lp,int c_char)); #define MAX_TYPEOUT MAXCOLS /* maximum width of typout (in chars) */ extern void ChkWindows proto((LinePtr line1,LinePtr line2)), ChkWinLines proto((void)), DrawMesg proto((jbool abortable)), message proto((const char *)), TOstart proto((const char *name)), TOstop proto((void)), Typeout proto((const char *, ...)), rbell proto((void)), redisplay proto((void)); #ifdef WINRESIZE extern volatile jbool ResizePending; /* asynch request for screen resize */ # ifdef WIN32 extern void ResizeWindow proto((void)); # endif #endif extern jbool DisabledRedisplay; #ifdef ID_CHAR extern jbool IN_INSmode; extern void INSmode proto((jbool)); #endif /* ID_CHAR */ /* Variables: */ extern jbool BriteMode; /* VAR: make the mode line inverse? */ #ifdef UNIX extern int MailInt; /* VAR: mail check interval */ extern char Mailbox[FILESIZE]; /* VAR: mailbox name */ #endif /* UNIX */ extern char ModeFmt[MAXCOLS]; /* VAR: mode line format string */ extern jbool ScrollAll; /* VAR: when current line scrolls, scroll whole window? */ extern int ScrollWidth; /* VAR: unit of horizontal scrolling */ extern jbool UseBuffers; /* VAR: use buffers with Typeout() */ #ifdef ID_CHAR extern jbool UseIC; /* VAR: whether or not to use i/d char processesing */ #endif extern jbool VisBell; /* VAR: use visible bell (if possible) */ extern jbool MarkHighlighting; /* VAR: highlight mark when visible */ /* Commands: */ extern void Bow proto((void)), ClAndRedraw proto((void)), DownScroll proto((void)), Eow proto((void)), NextPage proto((void)), PrevPage proto((void)), RedrawDisplay proto((void)), UpScroll proto((void)); jove-4.17.5.5/doc/000077500000000000000000000000001501102521500134535ustar00rootroot00000000000000jove-4.17.5.5/doc/README000066400000000000000000000101361501102521500143340ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## README this file cmds.macros.nr nroff macros used to format cmds.nr to produce cmds.doc intro.nr introductory part of JOVE manual; combined with cmds.nr to produce complete manual (nroff input) cmds.nr descriptions of JOVE commands (and variables) (nroff input) jove.nr JOVE manpage (nroff input) teachjove.nr teachjove manpage (nroff input) jovetool.nr jovetool manpage (nroff input) xjove.nr xjove manpage (nroff input) jove.qref JOVE quick reference documentation teach-jove text used by teachjove program example.rc sample user .joverc (startup file) jove.rc standard system startup file jem.txt Jove Beginner Easy Menu help text file jove.rc.3022 startup files for specific terminals jove.rc.sun jove.rc.sun-cmd jove.rc.vt100 jove.rc.wyse jove.rc.xterm jove.rc.xterm-256color jove.rc.z29 test*.rc these are tests for JOVE's joverc code, developer use only keychart.3022 keyboard binding descriptions for specific terminals keychart.sun keychart.sun-cmd keychart.vt100 keychart.wyse keychart.xterm keychart.xterm-256color keychart.z29 XTermresource X Window System resource file to improve the codes generated by XTerm. See comments in the file. The Makefile in the parent directory contains recipes for building and installing documentation and for installing the various startup files. The file jove.rc is intended to be 'source'd before each run of jove (except when the -J flag is given). This file contains various initializations, some of which are pretty well essential and some of which are suggestions for sysadmins to experiment with. See the comments in this file. Note that if you hack this file, you must take precautions to avoid your changes being lost if you upgrade Jove. See jove-local.rc and /etc/jove/jove.rc below for alternatives for performing local customizations that should not be lost on new installs. jem.txt is a simple startup help window that is displayed (from jove.rc) if (on Un*x systems) the user does not have a.joverc file. It can also be suppressed by setting the environment JOVENOHELP=1 (useful for non-Un*x). A files jove.rc.$TERM, where $TERM is the value of the TERM environment variable, is 'source'd near the end the generic jove.rc, and provides suggested bindings for the function keys on the various terminals. The selection of terminals given is somewhat arcane, and suggestions for bindings for other terminals would be welcomed. See the comments in these files. After jove.rc.$TERM is source'd, a file jove-local.rc is source'd if it exists. Local settings can be placed in this file that will add to or override previous settings from jove.rc and/or jove.rc.TERM files. jove-local.rc may contain terminal bindings but is not terminal specific; if a site does a lot of terminal key binding customization for multiple terminal types, it should likely create a local terminal file and source it from this file (see jove.rc for an example of how to do this). Finally, if a file called /etc/jove/jove.rc is found, it is sourced. That file is expected to contain per-host or per-distro settings. The user's $HOME/.joverc will be 'source'd after jove.rc.$TERM and jove-local.rc . User preferences belong in this file. The files keychart.TERM, where TERM is the value of the $TERM environment variable, are intended to display a map of the Function Keys on the particular keyboard showing what they are bound to. This file will be displayed when the user gives the 'keychart' macro (which should usually be bound to the Help key, if there is one). Some of these files also contain setup information for the terminal. We welcome contributions to our collection of terminal support files. We don't have the resources to create more than a few ourselves. jove-4.17.5.5/doc/XTermresource000066400000000000000000000123061501102521500162070ustar00rootroot00000000000000! This file contains keybindings for xterm to ensure that every key on the ! keyboard (including all function keys, keypad keys, and freestanding arrow ! keys etc.) produces some key sequence that may be recognised by Jove. The ! file jove.rc.xterm then provides suggested translations from those key ! sequences to Jove commands. Note: these resources are to be installed ! on the X server and affect its keyboard and mouse. ! ! On Suns, xterm provides a choice of keybindings for the funcion keys, to ! match the usual Sun bindings if XTerm*sunFunctionKeys is true and to match ! VT220-like bindings otherwise. This file supports both modes. ! ! For keys which are not customarily bound at all in xterm, we have chosen ! bindings in the Sun style, to minimise the possibility of accidentally ! producing sequences that might be meaningful to some program. Thus it is ! expected that existing applications using xterm will not be affected by ! these bindings. ! ! This file may be incorporated in your .Xdefaults file, or kept as a separate ! file to be invoked by xrdb (probably from within your .xinitrc). In either ! case, the call of xrdb must be in the form ! xrdb -merge -DSUN -DSUNKEYS -DJOVE -DXTERM=xjoveterm $HOME/.Xdefaults ! where you should include ! -DSUN on any Sun machine (to cope with the strange Sun bindings of ! F11 and F12). ! -DSUNKEYS to define the sunFunctionKeys resource and adjust other ! bindings so that Sun keyboard sequences are generated ! instead of the "standard" sequences. See xterm(1). ! -DJOVE if you want full Jove mouse operations ! (tells xterm to pass Ctrl-modified mouse events through) ! -DXTERM=xjoveterm if the effects are only required when xterm is called by ! the name 'xjoveterm' (or whatever), where 'xjoveterm' might be a ! soft link to xterm. The combination of this facility with -DJOVE ! is recommended. ! ! Alternatively, this file may be included in your XFILESEARCHPATH ! or XUSERFILESEARCHPATH, or in the XENVIRONMENT variable, in which case it ! must first be passed through cpp with -DSUN etc. as appropriate. ! ! If SUN is #defined, the CLIPBOARD is used for xterm-style cutting and ! pasting, thus permitting cutting and pasting from cmdtool and textedit ! windows. This may be overridden by #defining BUFFER (e.g. to CUT_BUFFER0). #ifndef XTERM #define XTERM XTerm #endif #ifndef BUFFER #ifdef SUN #define BUFFER CLIPBOARD #else #define BUFFER CUT_BUFFER0 #endif #endif #ifdef JOVE #define MOUSE_SPECIFIC \ !Ctrl : ignore()\n \ !Ctrl : ignore()\n \ ~Ctrl ~Meta : insert-selection(PRIMARY,BUFFER)\n \ : select-end(PRIMARY,BUFFER)\n #else #define MOUSE_SPECIFIC \ ~Ctrl ~Meta : insert-selection(PRIMARY,BUFFER)\n \ : select-end(PRIMARY,BUFFER)\n #endif #ifdef SUN #define SUNSPECIFIC \ L1: string(0x1B)string("[192z")\n \ L2: string(0x1B)string("[193z")\n \ Pause: string(0x1B)string("[208z")\n \ Print: string(0x1B)string("[209z")\n \ Scroll_Lock: string(0x1B)string("[210z")\n #else #define SUNSPECIFIC #endif #ifndef SUNKEYS XTERM*sunFunctionKeys: false #define SUNKEYS_SPECIFIC \ ~@Num_LockKP_Equal: string(0x1B)string("[211z")\n \ ~@Num_LockKP_Divide: string(0x1B)string("[212z")\n \ ~@Num_LockKP_Multiply: string(0x1B)string("[213z")\n \ ~@Num_LockKP_5: string(0x1B)string("[218z")\n #define SUNKEYS_KP_SPECIFIC \ Prior: string(0x1B)string("[5~")\n \ Next: string(0x1B)string("[6~")\n \ Insert: string(0x1B)string("[2~")\n \ Find: string(0x1B)string("[1~")\n #else XTERM*sunFunctionKeys: true #define SUNKEYS_SPECIFIC #define SUNKEYS_KP_SPECIFIC \ Prior: string(0x1B)string("[216z")\n \ Next: string(0x1B)string("[222z")\n \ Insert: string(0x1B)string("[2~")\n #endif XTERM.VT100.Translations: #override \ SunF36: string(0x1B)string("[234z")\n \ SunF37: string(0x1B)string("[235z")\n \ SUNSPECIFIC \ SUNKEYS_SPECIFIC \ ~@Num_LockKP_Decimal: string(0x1B)string("[249z")\n \ ~@Num_LockKP_Enter: string(0x1B)string("[250z")\n \ ~@Num_LockKP_Add: string(0x1B)string("[253z")\n \ ~@Num_LockKP_Subtract: string(0x1B)string("[254z")\n \ ~@Num_LockKP_Insert: string(0x1B)string("[2~")\n \ @Num_LockKP_0: string(0)\n \ @Num_LockKP_1: string(1)\n \ @Num_LockKP_2: string(2)\n \ @Num_LockKP_3: string(3)\n \ @Num_LockKP_4: string(4)\n \ @Num_LockKP_5: string(5)\n \ @Num_LockKP_6: string(6)\n \ @Num_LockKP_7: string(7)\n \ @Num_LockKP_8: string(8)\n \ @Num_LockKP_9: string(9)\n \ @Num_LockKP_Decimal: string(.)\n \ @Num_LockKP_Enter: string(0x0D)\n \ @Num_LockKP_Add: string(+)\n \ @Num_LockKP_Subtract: string(-)\n \ @Num_LockKP_Multiply: string(*)\n \ @Num_LockKP_Divide: string(/)\n \ @Num_LockKP_Equal: string(=)\n \ Help: string(0x1B)string("[202z")\n \ Left: string(0x1B)string("[D")\n \ Right: string(0x1B)string("[C")\n \ Up: string(0x1B)string("[A")\n \ Down: string(0x1B)string("[B")\n \ Home: string(0x1B)string("[214z")\n \ End: string(0x1B)string("[220z")\n \ SUNKEYS_KP_SPECIFIC \ MOUSE_SPECIFIC jove-4.17.5.5/doc/cmds.macros.nr000066400000000000000000000013201501102521500162210ustar00rootroot00000000000000.\" Macros for formatting cmds.nr to produce cmds.doc . .\" define strings for left and right double-quotes (same as -ms) .if n .ds Q "" .if n .ds U "" .if t .ds Q `` .if t .ds U '' . .de IQ \" italics (in manual) or quote (here, in describe-command) "\\$1"\\$2 .. .de BQ \" bold (in manual) or quote (here, in describe-command) "\\$1"\\$2 .. .de dc .sp 1 :entry "\\$1" .if '\\$2'(variable)' "Variable" .if !'\\$2'(variable)' "Command" .br .. .de ID .sp 1 .in +5 .. .de DE .fi .sp 1 .in -5 .. .de DS .nf .sp 1 .in +5 .. .de UX UNIX\\$1 .. .ll 7i .na \" No Adjust: ragged right looks best on fixed-pitch screen .nh \" No Hyphenation: best with ragged .pl 1 \" page length 1 line: avoid filling last page with blank lines jove-4.17.5.5/doc/cmds.nr000066400000000000000000003355501501102521500147550ustar00rootroot00000000000000.\"########################################################################## .\"# This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # .\"# provided by Jonathan and Jovehacks without charge and without # .\"# warranty. You may copy, modify, and/or distribute JOVE, provided that # .\"# this notice is included in all the source files and documentation. # .\"########################################################################## .\" .\" cmds.nr: descriptions of each JOVE command and variable. .\" .\" This nroff/troff text is used for two purposes: .\" it is the second portion of the JOVE manual (combine with intro.nr), and .\" it is used to produce cmds.doc, the text used by the describe-command .\" and describe-variable commands. .\" Take note of the .IQ and .BQ macros used in this file to put text in .\" italic or bold, and that their effect when producing cmds.doc is to .\" enclose the relevant text within quotes. Do not use any other means of .\" italicising or emboldening in this file. . .dc "abort-char" "(variable)" This variable defines \s-2JOVE\s0'S abort character. When JOVE reads this character from the keyboard, it stops what it is doing (unless the character is quoted in some way). Unfortunately, JOVE won't notice the character until it reads from the keyboard. The default value is ^G. See also .IQ interrupt-character . .dc "add-lisp-special" "Not Bound" This command is to tell \s-2JOVE\s0 what identifiers require special indentation in lisp mode. Lisp functions like .IQ defun and .IQ let are two of the default functions that get treated specially. This is just a kludge to define some of your own. It prompts for the function name. .dc "allow-^S-and-^Q" "(variable)" This variable, when set, tells \s-2JOVE\s0 that your terminal will not need to use the characters ^S and ^Q for flow control, in which case \s-2JOVE\s0 will instruct the system's tty driver to pass them through as normal characters. Otherwise, if the tty driver was already using these characters for flow control, it will continue to do so. Certain terminals and communications systems require that this variable be set .IQ off ; in other circumstances it is better set .IQ on . .dc "allow-bad-characters-in-filenames" "(variable)" If set, this variable permits the creation of filenames which contain \*Qbad\*U characters such as those from the set \(**&%!"`[]{}. These files are harder to deal with, because the characters mean something to the shell. The default value is .IQ off . .dc "append-region" "Not Bound" This appends the region to a specified file. If the file does not already exist it is created. .dc "apropos" "Not Bound" This types out each command, variable and macro with the specified string in its name (\*Q?\*U matches every name). For each command and macro that contains the string, the key sequence that can be used to execute the command or macro is printed; with variables, the current value is printed. So, to find all the commands that are related to windows, you type .DS : apropos window . .DE .dc "auto-case-abbrev" "(variable)" When this variable is .IQ on (the default), word abbreviations are adjusted for case automatically. If the abbreviation is typed with no uppercase letter, the expansion is not changed; if it is typed with one or more uppercase letters, the first character in the expansion is capitalized; additionally, if the abbreviation is typed with more than one uppercase letter, each letter in the expansion immediately preceded by whitespace or \- is capitalized. For example, if \*Qjove\*U were the abbreviation for \*Qjonathan's own version of EMACS\*U, the following table shows how the abbreviation would be expanded. .DS I .ta \w'JOVE111'u jove jonathan's own version of EMACS Jove Jonathan's own version of EMACS JOVE Jonathan's Own Version Of EMACS JoVe Jonathan's Own Version Of EMACS .DE When this variable is .IQ off , upper and lower case are distinguished when looking for the abbreviation, i.e., in the example above, \*QJOVE\*U and \*QJove\*U would not be expanded unless they were defined separately. See also the .IQ word-abbrev-mode command. .dc "auto-execute-command" "Not Bound" This tells \s-2JOVE\s0 to execute a command automatically when a file whose name matches a specified pattern is read. The first argument is the command you wish to have executed. The second argument is the pattern, a regular expression that is matched against the start of the file name. If you wish to match a suffix, start the pattern with \*Q.\(**\*U; to match every file, use that as the whole pattern. Any numeric argument will be passed on to the command when it is executed (this is useful when combined with commands that adjust a minor mode). For example, if you want to be in .IQ show-match-mode when you edit C source files (that is, files that end with .BQ .c or .BQ .h ) you can type .DS : auto-execute-command show-match-mode .\(**\^\e\^.[ch]$ .DE Actually, this command toggles the Show Match minor mode, but since it is initially off, it will have the desired effect. For more certain control, give the .IQ auto-execute-command a non-zero numeric argument: this will be passed on to the .IQ show-match-mode . .dc "auto-execute-macro" "Not Bound" This is like .IQ auto-execute-command except you use it to execute macros automatically instead of built-in commands. .dc "auto-fill-mode" "Not Bound" This turns on or off the Auto Fill minor mode in the selected buffer. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. When \s-2JOVE\s0 is in Auto Fill mode it automatically breaks lines for you when you reach the right margin so you don't have to remember to hit Return. \s-2JOVE\s0 uses 78 as the right margin but you can change that by setting the variable .IQ right-margin to another value. .dc "auto-indent-mode" "Not Bound" This turns on or off Auto Indent minor mode in the selected buffer. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. When \s-2JOVE\s0 is in Auto Indent mode, the .IQ newline command (which is normally bound to Return) acts identically to .IQ newline-and-indent : the new line is indented to the same position as the line you were just on. This is useful for lining up C code (or any other language (but what else is there besides C?)). Furthermore, if a line is broken because of Auto Fill mode, and Auto Indent mode is on, the new line will be indented as the old line was. .dc "backward-character" "^B" This moves point backward over a single character or line-separator. Thus if point is at the beginning of the line it moves to the end of the previous line. .dc "backward-list" "ESC\ ^P" This moves point backward over a list, which is any text between properly matching (\^...\^), [\^...\^] or {\^...\^}. It first searches backward for a \*Q)\*U and then moves to the matching \*Q(\*U. This is useful when you are trying to find unmatched parentheses in a program. Arguments are accepted, and negative arguments search forwards. See also .IQ backward-s-expression . .dc "backward-paragraph" "Usually Not Bound" This moves point backward to the beginning of the current or previous paragraph. Paragraphs are bounded by lines that match .IQ paragraph-delimiter-pattern (by default, those that are empty or look like troff or TeX commands). A change in indentation may also signal a break between paragraphs, except that \s-2JOVE\s0 allows the first line of a paragraph to be indented differently from the other lines. Arguments are accepted, and negative arguments search forwards. .dc "backward-s-expression" "ESC\ ^B" This moves point backward over an s-expression, that is over a Lisp atom or a C identifier (depending on the major mode) ignoring punctuation and whitespace; or, if the nearest preceding significant character is one of \*Q)]}\*U, over a list as in .IQ backward-list . Arguments are accepted, and negative arguments search forwards. .dc "backward-sentence" "ESC\ A" This moves point backward to the beginning of the current or previous sentence. \s-2JOVE\s0 considers the end of a sentence to be the characters \*Q.\*U, \*Q!\*U or \*Q?\*U followed by a Return or by one or more spaces. Arguments are accepted, and negative arguments search forwards. .dc "backward-up-list" "ESC\ ^U" This is similar to .IQ backward-list except it backs up and OUT of the enclosing list. In other words, it moves backward to whichever of \*Q([{\*U would match one of \*Q)]}\*U if you were to type it right then. Arguments are accepted, and negative arguments search forwards as in .IQ down-list . .dc "backward-word" "ESC\ B" This moves point backward to the beginning of the current or previous word. Arguments are accepted, and negative arguments search forwards. .dc "bad-filename-extensions" "(variable)" This contains a list of words separated by spaces which are to be considered bad filename extensions, and so will not be included in filename completion. The default contains, amongst much else, .BQ .o so if you have .BQ jove.c and .BQ jove.o in the same directory, the filename completion will not complain of an ambiguity because it will ignore .BQ jove.o . .dc "begin-kbd-macro" "^X\ (" This starts defining the keyboard macro by remembering all your key strokes until you execute .IQ end-kbd-macro , by typing \*Q^X\ )\*U. Because of a bug in \s-2JOVE\s0 you shouldn't terminate the macro by typing \*QESC\ X end-kbd-macro\*U; .IQ end-kbd-macro must be bound to \*Q^X\ )\*U in order to make things work correctly. The .IQ execute-kbd-macro command will execute the remembered key strokes. Sometimes you may want a macro to accept different input each time it runs. To see how to do this, see the .IQ make-macro-interactive command. .dc "beginning-of-file" "ESC\ <" This moves point backward to the beginning of the buffer. This sometimes prints the \*Q[Point pushed]\*U message to indicate that \s-2JOVE\s0 has set the mark so you can go back to where you were if you want. See also the variable .IQ mark-threshold . .dc "beginning-of-line" "^A" This moves point to the beginning of the current line. .dc "beginning-of-window" "ESC\ ," This moves point to the beginning of the active window. If there is a numeric argument, point moves that many lines below the top line. With the default bindings, the sequence \*QESC\ ,\*U is the same as \*QESC\ <\*U (\c .IQ beginning-of-file ) but without the shift key on the \*Q<\*U, and can thus easily be remembered. .dc "bind-keymap-to-key" "Not Bound" This is like .IQ bind-to-key except that you use it to attach a key sequence to a named keymap. The only reasonable use is to bind some extra key to .IQ ESC-map for keyboards that make typing ESC painful. .dc "bind-macro-to-key" "Not Bound" This is like .IQ bind-to-key except you use it to attach a key sequence to a named macro. .dc "bind-macro-to-word-abbrev" "Not Bound" This command allows you to bind a macro to a previously defined word abbreviation. Whenever you type the abbreviation, it will first be expanded as an abbreviation (which could be empty, of course), and then the macro will be executed. Note that if the macro moves point around, you should first .IQ set-mark and then .IQ exchange-point-and-mark . .dc "bind-to-key" "Not Bound" This attaches a key sequence to an internal \s-2JOVE\s0 command so that future hits on that key sequence invoke that command. This is called a global binding, as compared to local bindings and process bindings. Any previous global binding of this key sequence is discarded. For example, to make \*Q^W\*U erase the previous word, you type .DS : bind-to-key kill-previous-word ^W . .DE It isn't possible to have two globally bound key sequences where one is a prefix of the other: \s-2JOVE\s0 wouldn't know whether to obey the shorter sequence or wait for the longer sequence. Normally, when the .IQ bind-to-key command is issued interactively, the key sequence is taken to end one keystroke after the longest sequence matching any proper prefix of another binding (thus no new prefix can be created). If the command is given a numeric argument, the key sequence is taken up to the next Return keystroke (kludge!); bindings to any prefix of the sequence are discarded. When the command is issued from a .IQ source d file, the key sequence is taken up to the end of the line (it is also processed so that control characters can and should be entered using the ^A notation). Note that neither process nor local bindings are changed by this command, although they can be eclipsed. Given a choice between bindings, the shortest is executed; if there is still a choice, a process binding is preferred to a local binding, and a local binding is preferred to a global binding. .dc "buffer-position" "Not Bound" This displays the current file name, current line number, total number of lines, current character number, total number of characters, percentage of the way through the file, and the position of the cursor in the current line. .dc "c-argument-indentation" "(variable)" This variable describes how to indent lines which are part of nested expressions in C. The default is \-1, which means to indent a continued line by lining it up with the first argument of the current expression. Otherwise, the line will be indented by .IQ c-argument-indentation characters past the indent of the first line of the expression. For example, the default value produces: .DS .nr TY \w'Typeout(' Typeout(fmt, itoa(bcount++), line_cnt(b, nbuf), \h'\n(TYu'TypeNames[b->b_type], \h'\n(TYu'IsModified(b) ? "\(**" : b->b_ntbf ? "+" : NullStr, \h'\n(TYu'buf_width, b->b_name, filename(b)); .DE .dc "c-indentation-increment" "(variable)" This defines a set of tabstops independent of the value of .IQ tab-width . This value will be used in C mode, and \s-2JOVE\s0 will insert the correct number of Spaces and Tabs to get the right behavior. For programmers that like to indent with 4 spaces, set this value to 4. Some people prefer to set this to 4 and leave tab-width set to 8. This will create files whose indentation steps in 4-space increments, and which look the same anywhere that tabs are expanded to 8 spaces (i.e. in most settings). Others prefer to have one tab character per indentation level, then fiddle the tab expansion width to get the appearance they like. They should set both .IQ c-indentation-increment and .IQ tab-width to 4. Whenever using a non-standard tab width (\c .IQ tab-width ) you should only use tabs for indentation, and use spaces for all columnar alignment later in the lines. .dc "c-mode" "Not Bound" This turns on the C major mode in the currently selected buffer. When in C or Lisp mode, Tab, \*Q}\*U, and \*Q)\*U behave a little differently from usual: They are indented to the \*Qright\*U place for C (or Lisp) programs. In \s-2JOVE\s0, the \*Qright\*U place is simply the way the author likes it (but I've got good taste). .dc "case-character-capitalize" "Not Bound" This capitalizes the character after point, i.e., the character under the cursor. If a negative argument is supplied that many characters before point are upper cased. .dc "case-ignore-search" "(variable)" This variable, when .IQ on , tells \s-2JOVE\s0 to treat upper and lower case the same when searching. Thus \*Qjove\*U would match \*QJOVE\*U, and \*QJoVe\*U would match either. The default value of this variable is .IQ off . .dc "case-region-lower" "Not Bound" This changes all the upper case letters in the region to their lower case equivalents. .dc "case-region-upper" "Not Bound" This changes all the lower case letters in the region to their upper case equivalents. .dc "case-word-capitalize" "ESC\ C" This capitalizes the current word by making the current letter upper case and making the rest of the word lower case. Point is moved to the end of the word. If point is not positioned on a word it is first moved forward to the beginning of the next word. If a negative argument is supplied that many words before point are capitalized. This is useful for correcting the word just typed without having to move point to the beginning of the word yourself. .dc "case-word-lower" "ESC\ L" This lower-cases the current word and leaves point at the end of it. If point is in the middle of a word the rest of the word is converted. If point is not in a word it is first moved forward to the beginning of the next word. If a negative argument is supplied that many words before point are converted to lower case. This is useful for correcting the word just typed without having to move point to the beginning of the word yourself. .dc "case-word-upper" "ESC\ U" This upper-cases the current word and leaves point at the end of it. If point is in the middle of a word the rest of the word is converted. If point is not in a word it is first moved forward to the beginning of the next word. If a negative argument is supplied that many words before point are converted to upper case. This is useful for correcting the word just typed without having to move point to the beginning of the word yourself. .dc "cd" "Not Bound" This changes the current directory. .dc "character-to-octal-insert" "Not Bound" This inserts a Back-slash followed by the ascii value of the next character typed. For example, \*Q^G\*U inserts the string \*Q\^\e\^007\*U. .dc "clear-and-redraw" "ESC\ ^L" This clears the entire screen and redraws all the windows. Use this when \s-2JOVE\s0 gets confused about what's on the screen, or when the screen gets filled with garbage characters or output from another program. .dc "comment-format" "(variable)" This variable tells \s-2JOVE\s0 how to format your comments when you run the command .IQ fill-comment . Its format is this: .ID %!%c%! .DE The %!, %c, and %! must appear in the format; everything else is optional. A newline (represented by %n) may appear in the open or close patterns. %% is the representation for %. The default comment format is for C comments. See .IQ fill-comment for more details. .dc "compile-it" "^X\ ^E" This compiles your program by running the .UX command .IQ make into a buffer, and automatically parsing the error messages that are created (if any). See the .IQ parse-errors command. If .IQ compile-it is given a numeric argument, it will prompt for a command to run in place of the plain make and the command you enter will become the new default. See also .IQ error-format-string which makes it possible to parse errors of a different format and see also the variable .IQ error-window-size . .dc "continue-process" "Not Bound" This sends the signal SIGCONT to the interactive process in the current buffer, IF the process is currently stopped. .dc "copy-region" "ESC\ W" This takes all the text in the region and copies it onto the kill ring buffer. This is just like running .IQ kill-region followed by the .IQ yank command. See the .IQ kill-region and .IQ yank commands. .dc "current-error" "Not Bound" This moves to the current error in the list of parsed errors. See the .IQ next-error and .IQ previous-error commands for more detailed information. .dc "date" "Not Bound" This prints the date on the message line. .dc "dbx-format-string" "(variable)" This is the default regular-expression search string used by \s-2JOVE\s0 to parse output from .IQ dbx running in a shell process (see the .IQ dbx-mode command). You shouldn't have to change this unless you are using something other than .IQ DBX . .dc "dbx-mode" "Not Bound" This turns on or off the DBX minor mode in the selected buffer. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. This mode only makes sense in a buffer running an interactive shell process. If you are running .IQ dbx in a window and and the buffer is in DBX minor mode, \s-2JOVE\s0 will automatically track the source location in another window. Whenever you type \*Qwhere\*U or while you're stepping through a program, or when you reach a breakpoint, \s-2JOVE\s0 will present the source file in another window and move to the line that is being referenced. See also the variable .IQ dbx-format-string . .dc "define-global-word-abbrev" "Not Bound" This defines a global abbreviation. See the .IQ word-abbrev-mode command. .dc "define-macro" "Not Bound" This provides a different mechanism for defining keyboard macros. Instead of gathering keystrokes and storing them into the \*Qkeyboard-macro\*U (which is how .IQ begin-kbd-macro works), .IQ define-macro prompts for a macro name (terminated with Space, or Newline) and then for the actual macro body. If you wish to specify control characters in the macro, you may simply insert them (using the .IQ quoted-insert command) or by inserting the character '^' followed by the appropriate letter for that character (e.g., ^A would be the two characters '^' followed by 'A'). You may use Back-slash to prevent the '^' from being interpreted as part of a control character when you really wish to insert one (e.g., a macro body \*Q\^\e\^^foo\*U would insert the string \*Q^foo\*U into the buffer, whereas the body \*Q^foo\*U would be the same as typing ^F and then inserting the string \*Qoo\*U). See .IQ write-macros-to-file to see how to save macros. .dc "define-mode-word-abbrev" "Not Bound" This defines a mode-specific abbreviation. See the .IQ word-abbrev-mode command. .dc "delete-blank-lines" "^X\ ^O" This deletes all the blank lines around point. This is useful when you previously opened many lines with the .IQ newline-and-backup command and now wish to delete the unused ones. .dc "delete-buffer" "^X\ K" This deletes a buffer and frees up all the memory associated with it. Be careful(!) - once a buffer has been deleted it is gone forever. \s-2JOVE\s0 will ask you to confirm if you try to delete a buffer that needs saving. This command is useful for when \s-2JOVE\s0 runs out of space to store new buffers. See also the .IQ erase-buffer command and the .IQ kill-some-buffers command. .dc "delete-current-window" "^X\ D)" This deletes the active window and moves point into one of the remaining ones. It is an error to try to delete the only remaining window. .dc "delete-next-character" "^D" This deletes the character that's just after point (that is, the character under the cursor). If point is at the end of a line, the line-separator is deleted and the next line is joined with the current one. If an argument is given, that many characters are deleted and placed on the kill ring. If the argument is negative the deletion is forwards. .dc "delete-other-windows" "^X\ 1" This deletes all the other windows except the current one. This can be thought of as going back into One Window mode. .dc "delete-previous-character" "DEL and ^H" This deletes the character that's just before point (that is, the character before the cursor). If point is at the beginning of the line, the line separator is deleted and that line is joined with the previous one. If an argument is given, that many characters are deleted and placed on the kill ring. If the argument is negative the deletion is backwards. .dc "delete-white-space" "ESC\ \e\^" This deletes all the Tabs and Spaces around point. .dc "describe-bindings" "Not Bound" This types out a list containing each bound key and the command that gets invoked every time that key is typed. To make a wall chart of \s-2JOVE\s0 commands, set .IQ send-typeout-to-buffer to .IQ on and \s-2JOVE\s0 will store the key bindings in a buffer which you can save to a file and then print. .dc "describe-command" "ESC\ ?" This waits for you to type a command and then prints an explanation of that command, together with its current bindings. .dc "describe-key" "^X\ ?" This waits for you to type a key and then tells the name of the command that gets invoked every time that key is hit. Once you have the name of the command you can use the .IQ describe-command command to find out exactly what it does. .dc "describe-variable" "Not Bound" This prints an explanation of a specified variable. .dc "digit" "ESC\ 0 through ESC\ 9" Starts or continues the entry of a numeric argument with the digit typed. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. .dc "digit-0" "Not Bound" Starts or continues the entry of a numeric argument with the digit 0. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 0 key on the numeric keypad. .dc "digit-1" "Not Bound" Starts or continues the entry of a numeric argument with the digit 1. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 1 key on the numeric keypad. .dc "digit-2" "Not Bound" Starts or continues the entry of a numeric argument with the digit 2. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 2 key on the numeric keypad. .dc "digit-3" "Not Bound" Starts or continues the entry of a numeric argument with the digit 3. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 3 key on the numeric keypad. .dc "digit-4" "Not Bound" Starts or continues the entry of a numeric argument with the digit 4. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 4 key on the numeric keypad. .dc "digit-5" "Not Bound" Starts or continues the entry of a numeric argument with the digit 5. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 5 key on the numeric keypad. .dc "digit-6" "Not Bound" Starts or continues the entry of a numeric argument with the digit 6. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 6 key on the numeric keypad. .dc "digit-7" "Not Bound" Starts or continues the entry of a numeric argument with the digit 7. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 7 key on the numeric keypad. .dc "digit-8" "Not Bound" Starts or continues the entry of a numeric argument with the digit 8. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 8 key on the numeric keypad. .dc "digit-9" "Not Bound" Starts or continues the entry of a numeric argument with the digit 9. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the 9 key on the numeric keypad. .dc "digit-minus" "ESC\ \-" Starts the entry of a numeric argument with a minus sign. It continues reading digits until you type some other command. Then that command is executed with the numeric argument you specified. Sometimes it is handy to bind this to the \- key on a numeric keypad. In the absence of further digits and unless otherwise stated (e.g. .IQ next-page ")," the argument \-1 is assumed. .dc "dirs" "Not Bound" This prints out the directory stack. See the .IQ cd , .IQ pushd , .IQ pushlibd and .IQ popd commands for more information. .dc "disable-biff" "(variable)" When this is set, \s-2JOVE\s0 disables biff when you're editing and enables it again when you get out of \s-2JOVE\s0, or when you pause to the parent shell or push to a new shell. (This means arrival of new mail will not be immediately apparent but will not cause indiscriminate writing on the display). The default is .IQ off , although it is always safe to set it .IQ on , even on systems that do not provide the biff facility. Note that the variable .IQ mode-line can be set up to announce the arrival of new mail during a \s-2JOVE\s0 session. .dc "display-default-filenames" "(variable)" If this is set when \s-2JOVE\s0 asks for a filename, it will display the default (unless that would take too much of the prompt line). .dc "display-filenames-with-bad-extensions" "(variable)" This variable affects only filename completion, in particular, what happens when \*Q?\*U is typed while prompting for a file. When this variable is .IQ on , any files that end with one of the extensions defined by the variable .IQ bad-filename-extensions will be displayed with an \*Q!\*U in front of their names. When .IQ display-filenames-with-bad-extensions is .IQ off the files will not be displayed at all. The default value is .IQ on . .dc "down-list" "ESC\ ^D" This is the opposite of .IQ backward-up-list . It enters the next list. In other words, it moves forward to whichever of \*Q([{\*U it first encounters. Arguments are accepted, and negative arguments search backwards as in .IQ backward-up-list . .dc "dstop-process" "Proc: ^C\ ^Y" Send the signal SIGTSTP to the interactive process in the selected buffer when next it tries to read input. This is equivalent to sending the \*Qdsusp\*U character (which most people have set to ^Y) to the process. This only works if you are in a buffer bound to an interactive process. .dc "edit-word-abbrevs" "Not Bound" This creates (if necessary) a buffer with a list of each abbreviation and the phrase it expands into, and enters a recursive edit to let you change the abbreviations or add some more. The format of this list is \*Qabbreviation:phrase\*U so if you add some more you should follow that format. It's probably simplest just to copy some already existing abbreviations and edit them. Use the .IQ exit-jove command to exit the recursive edit. .dc "end-kbd-macro" "^X\ )" This stops the definition of the keyboard macro. Because of a bug in \s-2JOVE\s0, this must be bound to \*Q^X\ )\*U, or some key sequence which is one or two characters long. Anything else will not work properly. See .IQ begin-kbd-macro for more details. .dc "end-of-file" "ESC\ >" This moves point forward to the end of the buffer. This sometimes prints the \*Q[Point pushed]\*U message to indicate that \s-2JOVE\s0 has set the mark so you can go back to where you were if you want. See also the variable .IQ mark-threshold . .dc "end-of-line" "^E" This moves point to the end of the current line. If the line is too long to fit on the screen, it will be scrolled horizontally. This is described with the variables .IQ scroll-width and .IQ scroll-all-lines . .dc "end-of-window" "ESC\ ." This moves point to the last character in the active window. If there is a numeric argument, the point moves that many lines above the bottom line. With the default bindings, the sequence \*QESC\ .\*U is the same as \*QESC\ >\*U (\c .IQ end-of-file ) but without the shift key on the \*Q>\*U, and can thus easily be remembered. .dc "enhanced-keyboard" "(variable)" (IBM PC version only) This is a boolean variable which can be set to enable the enhanced AT-style keyboard. The enhanced keyboard contains function keys and key combinations that are not supported on the original IBM PCs and XTs. The default value is determined by a bit in the BIOS data area, but this method apparently does not work with a few BIOS implementations. WARNING: setting enhanced-keyboard .IQ on on systems without an enhanced keyboard will lock up your system and require you to reboot. .dc "eof-process" "^C\ ^D" Sends EOF to the current interactive process. This only works on versions of \s-2JOVE\s0 running under versions of .UX with pty's. .dc "erase-buffer" "Not Bound" This erases the contents of the specified buffer. This is like .IQ delete-buffer except it only erases the contents of the buffer, not the buffer itself. If you try to erase a buffer that needs saving you will be asked to confirm it. .dc "error-format-string" "(variable)" This is the error format string that is used by .IQ parse-errors to find the error messages in a buffer. The way it works is by using this string as a \s-2JOVE\s0 regular expression search string, where the \e\^(\^...\^\e) regular expression feature is used to pick out the file name and line number from the line containing an error message. For instance, a typical error message might look like this: .sp 1 "file.c", line 540: missing semi-colon .sp 1 For strings of this format, an appropriate value for .IQ error-format-string would be something like this: .sp 1 ^"\^\e\^([^"]\(**\^\e)", line \e\^([0-9]\(**\^\e): .sp 1 What this means is, to find an error message, search for a line beginning with a double-quote. Then it says that all the following characters up to another double-quote should be remembered as one unit, namely the filename that the error is in (that is why the first set of parentheses is surrounding it). Then it says that after the filename there will be the string \*Q, line \*U followed by a line number, which should be remembered as a single unit (which is why the second set of parentheses is around that). The only constraint on the error messages is that the file name and line number appear on the same line. Most compilers seem to do this anyway, so this is not an unreasonable restriction. .sp 1 If you do not know how to use regular expressions then this variable will be hard for you to use. Also note that you can look at the default value of this variable by printing it out, but it is a really complicated string because it is trying to accommodate the outputs of more than one compiler. .dc "error-window-size" "(variable)" This is the percentage of the screen to use for the error-window on the screen. When you execute .IQ compile-it or .IQ spell-buffer , .IQ error-window-size percent of the screen will go to the error window. If the window already exists and is a different size, it is made to be this size. The default value is 20%. .dc "exchange-point-and-mark" "^X\ ^X" This moves point to mark and makes mark the old point. This is for quickly moving from one end of the region to the other. .dc "execute-kbd-macro" "^X\ E" This executes the keyboard macro. If you supply a numeric argument the macro is executed that many times. See the .IQ begin-kbd-macro command for more details. .dc "execute-macro" "Not Bound" This executes a specified macro. If you supply a numeric argument the macro is executed that many times. .dc "execute-named-command" "ESC\ X" This is the way to execute a command that isn't bound to any key. When you are prompted with \*Q:\ \*U you can type the name of the command. You don't have to type the entire name. After typing a few characters, Tab will fill in as many more as it can (as will Space, but that will also obey the command if it is now unambiguous). If you are not sure of the name of the command, type \*Q?\*U and \s-2JOVE\s0 will print a list of all the commands that you could possibly match given what you've already typed. Once the command is unambiguous, typing Return will cause it to be obeyed. If you don't have any idea what the command's name is but you know it has something to do with windows (for example), you can do \*QESC\ X apropos window\*U and \s-2JOVE\s0 will print a list of all the commands that are related to windows. If you find yourself constantly executing the same commands this way you probably want to bind them to keys so that you can execute them more quickly. See the .IQ bind-to-key command. .dc "exit-jove" "^X\ ^C" This exits \s-2JOVE\s0. If any buffers need saving \s-2JOVE\s0 will print a warning message and ask for confirmation. If you leave without saving your buffers all your work will be lost. If you made a mistake and really do want to exit then you can. If there are any interactive processes running, \s-2JOVE\s0 will also ask whether they should be terminated. If you are in a recursive editing level .IQ exit-jove will return you from that. The selected buffer will be set back to the buffer that was current when the recursive edit was entered. Normally, point will be returned to its position at the time of entry, but if the .IQ exit-jove command is given a numeric argument, point is left at its most recent position within that buffer. .dc "expand-environment-variables" "(variable)" When this variable is .IQ on \s-2JOVE\s0 will try to expand any strings of the form \*Q$var\*U into the value of the environment variable \*Qvar\*U when asking for a filename. For example, if you type .BQ $HOME/.joverc , \*Q$HOME\*U will be replaced with your home directory. The default value is .IQ on . .dc "file-creation-mode" "(variable)" This variable has an octal value. It contains the mode (see .IQ chmod (1)) with which files should be created. This mode gets modified by your current umask setting (see .IQ umask (1)). The default value is usually 0666 or 0644. .dc "files-should-end-with-newline" "(variable)" This variable indicates that all files should always have a newline at the end. This is often necessary for line printers and the like. When set, if \s-2JOVE\s0 is writing a file whose last character is not a newline, it will add one automatically. The default value is .IQ on . .dc "fill-comment" "Not Bound" This command fills in your C comments to make them pretty and readable. This filling is done according the variable .IQ comment-format . .DS /\(** \(** the default format makes comments like this. \(**/ .DE This can be changed by changing the .IQ comment-format variable. Other languages may be supported by changing the format variable appropriately. The formatter looks backwards from point for an open comment symbol. If found, all indentation is done relative to the position of the first character of the open symbol. If there is a matching close symbol, the entire comment is formatted. If not, the region between the open symbol and point is reformatted. The original text is saved in the kill ring; a .IQ yank-pop command will undo the formatting. .dc "fill-paragraph" "ESC\ J" This rearranges words between lines so that all the lines in the current paragraph extend as close to the right margin as possible, ensuring that none of the lines will be greater than the right margin. The default value for .IQ right-margin is 78, but can be changed with the .IQ set and .IQ right-margin-here commands. The rearrangement may cause an end of line to be replaced by whitespace. Normally, this whitespace is a single space character. If the variable .IQ space-sentence-2 is .IQ on , and the end of the line was apparently the end of a sentence or the line ended with a colon, two spaces will be used. However, a sentence or colon followed by a single space already within a line will not be altered. \s-2JOVE\s0 has a complicated algorithm for determining the beginning and end of the paragraph. In the normal case \s-2JOVE\s0 will give all the lines the same indent as they currently have, but if you wish to force a new indent you can supply a numeric argument to .IQ fill-paragraph and \s-2JOVE\s0 will indent each line to the column specified by the .IQ left-margin variable. See also the .IQ left-margin variable and .IQ left-margin-here command. Filling a paragraph can do something that you didn't intend. For that reason the original text is saved on the kill ring and can be yanked back. Deleting the rubble is up to you. .dc "fill-region" "Not Bound" This is like .IQ fill-paragraph , except it operates on a region instead of just a paragraph. .dc "filter-region" "Not Bound" This sends the text in the region to a .UX command, and replaces the region with the output from that command. For example, if you are lazy and don't like to take the time to write properly indented C code, you can put the region around your C file and .IQ filter-region it through .IQ cb , the .UX C beautifier. If you have a file that contains a bunch of lines that need to be sorted you can do that from inside \s-2JOVE\s0 too, by filtering the region through the .UX .IQ sort command. Before output from the command replaces the region \s-2JOVE\s0 stores the old text in the kill ring. If you are unhappy with the results a .IQ yank-pop command will get back the old text. .dc "find-file" "^X\ ^F" This reads a specified file into its own buffer and then selects that buffer. If you've already read this file into a buffer, that buffer is simply selected. If the file doesn't yet exist, \s-2JOVE\s0 will print \*Q(New file)\*U so that you know. If possible, the buffer is named after the filename (ignoring any directory part). .dc "find-tag" "^X\ T" This finds the file that contains the specified tag. \s-2JOVE\s0 looks up tags by default in the .BQ tags file in the current directory, as created by the .UX command .IQ ctags(1) . You can change the default tag name by setting the .IQ tag-file variable to another name. If you specify a numeric argument to this command, you will be prompted for a tag file. This is a good way to specify another tag file without changing the default. .dc "find-tag-at-point" "Not Bound" This finds the file that contains the tag that point is currently in. See .IQ find-tag . .dc "first-non-blank" "ESC\ M" This moves point (backwards or forwards) to the indent of the current line. .dc "forward-character" "^F" This moves point forward over a single character or line-separator. Thus if point is at the end of the line it moves to the beginning of the next one. .dc "forward-list" "ESC\ ^N" This moves point forward over a list, which is any text between properly matching (\^...\^), [\^...\^] or {\^...\^}. It first searches forward for a \*Q(\*U and then moves to the matching \*Q)\*U. This is useful when you are trying to find unmatched parentheses in a program. Arguments are accepted, and negative arguments search backwards. See also .IQ forward-s-expression . .dc "forward-paragraph" "ESC\ ]" This moves point forward to the end of the current or next paragraph. Paragraphs are bounded by lines that match .IQ paragraph-delimiter-pattern (by default, those that are empty or look like troff or TeX commands). A change in indentation may also signal a break between paragraphs, except that \s-2JOVE\s0 allows the first line of a paragraph to be indented differently from the other lines. Arguments are accepted, and negative arguments search backwards. .dc "forward-s-expression" "ESC\ ^F" This moves point forward over an s-expression, that is over a Lisp atom or a C identifier (depending on the major mode) ignoring punctuation and whitespace; or, if the nearest succeeding significant character is one of \*Q([{\*U, over a list as in .IQ forward-list . Arguments are accepted, and negative arguments search backwards. .dc "forward-sentence" "ESC\ E" This moves point forward to the end of the current or next sentence. \s-2JOVE\s0 considers the end of a sentence to be the characters \*Q.\*U, \*Q!\*U or \*Q?\*U, followed possibly by \*Q'\*U, \*Q''\*U, or \*Q"\*U, followed by a Return or whitespace. Arguments are accepted, and negative arguments search backwards. .dc "forward-word" "ESC\ F" This moves point forward to the end of the current or next word. .dc "fundamental-mode" "Not Bound" This sets the major mode to Fundamental. Fundamental mode is the mode of the Minibuf, and hence of anything typed in the message line. .dc "gather-numeric-argument" "^U" This command is one of two ways to specify a numeric argument to a command. Typing this command once means, Do the next command 4 times. Typing it twice will do the next command 16 times, and so on. If at any point you type a number, then that number will be used instead of 4. For instance, ^U 3 5 means do the next command 35 times (assuming .IQ gather-numeric-argument is bound to ^U). .dc "goto-line" "ESC\ G" If a positive numeric argument is supplied, point moves to the beginning of that line. If the argument is negative, it indicates how many lines from the end of the buffer to move point to. If no argument is supplied one is prompted for. .dc "goto-window-with-buffer" "Not Bound" This command prompts for a buffer name and then selects that buffer. If the buffer is currently being displayed in one of the windows, that window is selected instead. .dc "grind-s-expr" "Not Bound" When point is positioned on a \*Q(\*U, this re-indents that LISP expression. .dc "grow-window" "^X\ ^\^" This makes the active window one line bigger. This only works when there is more than one window and provided there is room to change the size. See also .IQ shrink-window . .dc "handle-tab" "Tab" This handles indenting to the \*Qright\*U place in C and Lisp mode, and just inserts itself in Text mode. .dc "highlight-attribute" "(variable)" (IBM PC version only) This specifies how the attribute (color) of a character is to be changed when it is highlighted. Highlighting is indicated by exclusive oring this value with the normal attribute for the character. The default is 16. .dc "highlight-mark" "(variable)" When this is on, jove will highlight the mark if currently visible. The mark is highlighted with an underscore. .dc "i-search-forward" "Not Bound" Incremental search. Like search-forward except that instead of prompting for a string and searching for that string all at once, it accepts the string one character at a time. After each character you type as part of the search string, it searches for the entire string so far. When you like what it found, type Return to finish the search. You can take back a character with DEL and the search will back up to the position before that character was typed. ^G aborts the search. .dc "i-search-reverse" "Not Bound" Incremental search. Like search-reverse except that instead of prompting for a string and searching for that string all at once, it accepts the string one character at a time. After each character you type as part of the search string, it searches for the entire string so far. When you like what it found, type Return to finish the search. You can take back a character with DEL and the search will back up to the position before that character was typed. ^G aborts the search. .dc "i-shell-command" "Not Bound" This is like .IQ shell-command except that it launches an interactive process and so lets you continue with your editing while the command is running. This is really useful for long running commands with sporadic output. See also the variable .IQ wrap-process-lines . .dc "insert-file" "^X\ ^I" This inserts a specified file into the selected buffer at point. Point is positioned at the beginning of the inserted file. .dc "interrupt-character" "(variable)" This specifies what character should be used as the operating system's tty driver interrupt character. When this character is typed, the tty driver generates SIGINT signal. This will interrupt a non-interactive process. If no such process is running, \s-2JOVE'S\s0 will offer you the option of continuing, or crashing \s-2JOVE'S\s0 (trying to save your work). This is a crude and desperate way to stop \s-2JOVE'S\s0. Unfortunately there is no way to turn off the interrupt character. The default is ^]. See also .IQ abort-char . .dc "insert-variable" "Not Bound" This inserts the value of the specified variable at the current point in the current buffer. .dc "interrupt-process" "Proc: ^C\ ^C" This sends the signal SIGINT to the interactive process in the selected buffer. This only works if you are inside a buffer bound to an interactive process. .dc "iproc-env-export" "Not Bound" This takes an argument of the form VARNAME=VALUE and replaces or sets VARNAME to that VALUE in the list of environment variables that are passed to interactive shell commands i.e. .IQ shell and .IQ i-shell-command . .dc "iproc-env-show" "Not Bound" This shows (as temporary screen output or in a buffer, depending on the variable .IQ send-typeout-to-buffer ) the environment that will be exported to interactive processes. .dc "iproc-env-unset" "Not Bound" This takes an argument that is the name of an environment variable and removes it from the list of environment variables that will be passed to interactive processes. .dc "jove-compiled-with" "(variable)" This is a special, read-only variable, containing the compiler, flags and options used to build Jove (on Unix-style machines) .dc "jove-features" "(variable)" This is a special, read-only variable, set with a colon-delimited list of all the optional capabilities compiled into \s-2JOVE\s0. The value will be something like .br .IQ :unix:abbr:bak:biff:cmtfmt:fcomp:iproc:pty:lisp:proc:spell:rec:job:idchar:hl:tcap:ctype: .br .IQ unix specifies a variety of traditional UNIX/POSIX capabilities (case-sensitive filenames, a Unix-style filesystem), as opposed to .br .IQ msdos or .IQ win32 which have case-insensitive filesystems, for example. The platform .IQ ibmpcdos indicates specialization for the IBM-PC platform, which in reality, is the only MS-DOS form remaining in existence (other non-IBM-PC platforms, like Heath/Zenith, DEC Rainbow, etc probably do not exist anymore, as is probably the case for the pre-OSX classic .IQ mac platform). Other tokens are .br .IQ abbr (abbrev-mode exists), .br .IQ bak (backup-files can be created), .br .IQ biff (ability to disable screen-disruptions from old Unix-style mail notification), .br .IQ cmtfmt (format C comments), .br .IQ fcomp (filename completion), .br .IQ iproc (interactive shell processes), .br .IQ pipe (indicating that .IQ iproc is implemented using pipes and the .IQ portsrv helper program ), or .br .IQ pty (indicating that .IQ iproc is implemented using pseudo-terminals, available on any modern post-4.2BSD platform), .br .IQ lisp (lisp mode is available), .br .IQ proc (the ability to run non-interactive subshell processes with output to buffers, or switch entirely from \s-2JOVE\s0 to a child shell via .IQ push-shell and then return to \s-2JOVE\s0 when that child shell exits), .br .IQ spell (the ability to run a spell checker on the contents of a buffer, parse and modify the checker output and then step through any misspelled words in the original buffer with ^X^N and ^X^P) .br .IQ rec (periodically generate a recovery file so that one can restore unsaved changes from \s-2JOVE\s0 editors after a machine or program crash) .br .IQ job (BSD job control is supported, so one can suspend \s-2JOVE\s0 with the pause-jove command and return to the shell that \s-2JOVE\s0 was started from, and later resume \s-2JOVE\s0 using a shell command like .IQ fg ), .br .IQ jsmall (\s-2JOVE\s0 was built with smaller limits on the number of lines it can support, probably only 32000) .br .IQ idchar (\s-2JOVE\s0 will attempt to optimize screen display using insert/delete character modes and terminal control sequences), .IQ hl (enable highlight-mark capabiltiy to display a small underscore for the position of the mark, and enable the scroll-bar capability in the buffer mode line), .br .IQ jtc (uses builtin ANSI/VT1xx/XTERM driver rather than .IQ termcap/terminfo/curses ), .br .IQ tcap (termcap database code is enabled) .br .IQ tinfo (uses SystemV-style terminfo rather than BSD-style termcap calls), .br .IQ ctype (uses the system ctype character classification rather than \s-2JOVE\s0 builtin capability) .br .IQ iso88591 (uses builtin \s-2JOVE\s0 tables for ISO-8859-1 character classification rather than the system ctype capability). .dc "jove-linked-with" "(variable)" This is a special, read-only variable, containing the linker, flags and libraries used to build Jove (on Unix-style machines) .dc "kill-next-word" "ESC\ D" This kills the text from point to the end of the current or next word. .IQ The killed text is sent to the kill ring. .dc "kill-previous-word" "ESC\ DEL" This kills the text from point to the beginning of the current or previous word. The killed text is sent to the kill ring. .dc "kill-process" "Not Bound" This command prompts for a buffer name or buffer number (just as .IQ select-buffer does) and then sends the process in that buffer the signal SIGKILL. .dc "kill-region" "^W" This deletes the text in the region and saves it on the kill ring. Commands that delete text but save it on the kill ring all have the word \*Qkill\*U in their names. Use the .IQ yank command to get back the most recent kill. .dc "kill-s-expression" "ESC\ ^K" This kills the text from point to the end of the current or next s-expression. The killed text is sent to the kill ring. .dc "kill-some-buffers" "Not Bound" This goes through all the existing buffers and asks whether or not to delete each one. If you decide to delete a buffer, and it turns out that the buffer is modified, \s-2JOVE\s0 will offer to save it first. This is useful for when \s-2JOVE\s0 runs out of memory to store lines (this only happens on PDP-11's) and you have lots of buffers that you are no longer using. See also the .IQ delete-buffer command. .dc "kill-to-beginning-of-sentence" "^X\ DEL" This kills from point to the beginning of the current or previous sentence. If a negative numeric argument is supplied it kills from point to the end of the current or next sentence. The killed text is sent to the kill ring. .dc "kill-to-end-of-line" "^K" This kills from point to the end of the current line. When point is at the end of the line (discounting any white space) the line-separator is also deleted and the next line is joined with current one. If a numeric argument is supplied that many lines are killed; if the argument is negative that many lines before point are killed; if the argument is zero the text from point to the beginning of the line is killed. The killed text is sent to the kill ring. .dc "kill-to-end-of-sentence" "ESC\ K" This kills from point to the end of the current or next sentence. If a negative numeric argument is supplied it kills from point to the beginning of the current or previous sentence. The killed text is sent to the kill ring. .dc "lc-ctype" "(variable)" This string variable determines how non-ASCII characters are displayed, and which characters are to be considered as upper-case, lower-case, printable, etc. The default is the implementation-defined native environment; under POSIX, it is determined by whichever of the environment variables LC_ALL, LC_CTYPE or LANG is first found to be set, and is otherwise "C". Some useful values of .IQ lc-ctype might be: .DS .ta \w'"iso_8859_111" 'u "" Default: the native environment. "C" Strict ASCII. All other characters greater than \e\^177 rendered in octal. "iso_8859_1" Latin-1 alphabet. .DE .dc "left-margin" "(variable)" This is how far lines should be indented when Auto Indent mode is on, or when the .IQ newline-and-indent command is run (usually by typing Linefeed). It is also used by .IQ fill-paragraph and Auto Fill mode. If the value is zero (the default) then the left margin is determined from the surrounding lines. .dc "left-margin-here" "Not Bound" This sets the .IQ left-margin variable to the current position of point. This is an easy way to say, \*QMake the left margin begin here,\*U without having to count the number of spaces over it actually is. .dc "lib-dir-pathname" "(variable)" This tells JOVE where to find the machine-dependent helper programs: the .IQ recover program, run when .IQ "jove -r" is run after a crash to try to recover unsaved files, and on some older machines without pseudo-terminal support, the .IQ portsrv program, which handles multiplexed communication with the keyboard and interactive shells (if JOVE is compiled with SUBSHELL and PIPEPROCS configured) .dc "lisp-mode" "Not Bound" This turns on the Lisp major mode. In Lisp mode, the characters Tab and \*Q)\*U are treated specially, similar to the way they are treated in C mode. Also, Auto Indent mode is affected, and handled specially. See also the .IQ c-mode command. .dc "list-buffers" "^X\ ^B" This types out a list containing various information about each buffer. The list looks like this: .DS .ta \w'NO111'u +\w'Lines1'u +\w'Scratch111'u +\w'\(**1'u +\w'commands.doc111'u \ (\(** means the buffer needs saving) \ NO Lines Type Name File \ -- ----- ---- ---- ---- \ 1 1 File Main [No file] \ 2 1 Scratch \(** Minibuf [No file] \ 3 519 File \(** commands.doc commands.doc .DE The first column lists the buffer's number. When \s-2JOVE\s0 prompts for a buffer name you can either type in the full name, or you can simply type the buffer's number. The second column is the number of lines in the buffer. The third says what type of buffer. There are four types: File, Scratch, Process and I-Process. \*QFile\*U is simply a buffer that holds a file; \*QScratch\*U is for buffers that \s-2JOVE\s0 uses internally; \*QProcess\*U is one that holds the output from a .UX command; \*QI-Process\*U is one that has an interactive process attached to it. The next column contains the name of the buffer. And the last column is the name of the file that's attached to the buffer. In this case, both Minibuf and commands.doc have been changed but not yet saved. In fact Minibuf won't be saved since it's a Scratch buffer. .dc "list-processes" "Not Bound" This makes a list somewhat like \*Qlist-buffers\*U does, except its list consists of the current interactive processes. The list looks like this: .DS .ta \w'shell-111111111111'u +\w'Running1111111111'u +\w'1851211111'u \ Buffer Status Pid Command \ ------ ------ --- ------- \ \(**shell\(** Running 18415 shell \ fgrep Done 18512 fgrep -n Buffer \(**.c .DE The first column has the name of the buffer to which the process is attached. The second has the status of the process; if a process has exited normally the status is \*QDone\*U as in fgrep; if the process exited with an error the status is \*QExit N\*U where N is the value of the exit code; if the process was killed by some signal the status is the name of the signal that was used; otherwise the process is running. The last column is the name of the command that is being run. .dc "local-bind-keymap-to-key" "Not Bound" This is like .IQ local-bind-to-key except that you use it to attach a key sequence to a named keymap. The only reasonable use is to bind some extra key to .IQ ESC-map for keyboards that make typing ESC painful. .dc "local-bind-macro-to-key" "Not Bound" This is like .IQ local-bind-to-key except you use it to attach a key sequence to a named macro. .dc "local-bind-to-key" "Not Bound" This is like .IQ bind-to-key , except that the binding is only enabled when the selected buffer is the buffer that was current when the command was executed. In other words, the binding only applies to the selected buffer. .dc "macify" "(variable)" (Mac version only) When this variable is on, \s-2JOVE\s0 will use the standard Macintosh file-selector dialog in place of the traditional \s-2JOVE\s0 Minibuffer. .dc "mail-check-frequency" "(variable)" This is how often (in seconds) \s-2JOVE\s0 should check your mailbox for incoming mail. If you set this to zero \s-2JOVE\s0 won't check for new mail. See also the .IQ mode-line , .IQ mailbox and .IQ disable-biff variables. The default is 60. .dc "mailbox" "(variable)" Set this to the full pathname of your mailbox. \s-2JOVE\s0 will look here to decide whether or not you have any unread mail. This defaults to .BQ /usr/spool/mail/$USER , where \*Q$USER\*U is set to your login name. .dc "make-backup-files" "(variable)" If this variable is set, then whenever \s-2JOVE\s0 writes out a file, it will move the previous version of the file (if there was one) to \*Q#filename~\*U. This is often convenient if you save a file by accident. The default value of this variable is .IQ off . .dc "make-buffer-unmodified" "ESC\ ~\^" This makes \s-2JOVE\s0 think the selected buffer hasn't been changed even if it has. Use this when you accidentally change the buffer but don't want it considered changed. Watch the mode line to see the \(** disappear when you use this command. .dc "make-macro-interactive" "ESC\ I" This command is meaningful only while you are defining a keyboard macro, and when you are expecting input in the message line. Ordinarily, when a command in a macro definition requires a trailing text argument (file name, search string, etc.), the argument you supply becomes part of the macro definition. If you want to be able to supply a different argument each time the macro is used, then while you are defining it, you should give the .IQ make-macro-interactive command just before typing the argument which will be used during the definition process. Note: you must bind this command to a key in order to use it; you can't say \*QESC\ X make-macro-interactive\*U. .dc "mark-threshold" "(variable)" This variable contains the number of lines point may move by before the mark is set. If, in a search or some other command that may move point, point moves by more than this many lines, the mark is set so that you may return easily. The default value of this variable is 22 (one screenful, on most terminals). See also the commands .IQ search-forward , .IQ search-reverse , .IQ beginning-of-file and .IQ end-of-file . .dc "match-regular-expressions" "(variable)" When set, \s-2JOVE\s0 will match regular expressions in search patterns. This makes special the characters ., \(**, [ and ]. See the \s-2JOVE\s0 Manual for a full discussion of regular-expressions. .dc "meta-key" "(variable)" You should set this variable to .IQ on if your terminal has a real Meta key which forces the 8th bit of each character. If your terminal has such a key, then a key sequence like ESC\ Y can be entered by holding down Meta and typing Y. On the IBM PC, this variable affects how ALT is interpreted. On the Macintosh, it affects how Option is interpreted. NOTE: In some older .UX systems, \s-2JOVE\s0 must switch the tty to raw mode to accept the 8-bit characters generated by a meta key. Unfortunately, the .IQ interrupt-character does not generate an interrupt in raw mode. .dc "mode-line" "(variable)" The format of the mode line can be determined by setting this variable. The items in the line are specified using a format similar to that used by .IQ printf(3) , with the special things being marked as \*Q%x\*U. Digits may be used between the '%' and the 'x' to mean repeat that many times. \&'x' may be: .DS I .ta .5i 1i 1.5i C checks for new mail, and displays \*Q[New mail]\*U if there is any (see also the \c .IQ mail-check-frequency " \c" and \c .IQ mailbox " \c" variables) F the current file name, with leading path stripped M the current list of major and minor modes b the selected buffer name c the fill character (-) d the current directory e extra space in mode line is distributed evenly among the places %e is used (used for justifying, separating, or centering parts of the mode line) f the current file name ixy x, when the buffer's file has been changed behind JOVE's back, y, when not mxy x, when the buffer is modified or y, when not n the selected buffer number p interactive process status for process windows s space, but only if previous character is not a space t the current time (updated automatically) w a '>' for windows which are scrolled left [ ] the square brackets printed when in a recursive edit ( ) items enclosed in %( ... %) will only be printed on the bottom mode line, rather than copied when the window is split .DE In addition, any other character is simply copied into the mode line. Characters may be escaped with a backslash. To get a feel for all this, try typing \*QESC\ X print mode-line\*U and compare the result with your current mode line. .dc "mode-line-attribute" "(variable)" (IBM PC version only) This specifies the screen attribute (color) for characters in the mode line. The default is 112 (black on white). .dc "mode-line-should-standout" "(variable)" If set, the mode line will be printed in reverse video, if your terminal supports it. The default for this variable is .IQ on . .dc "name-kbd-macro" "Not Bound" This copies the keyboard macro and gives it a name freeing up the keyboard macro so you can define some more. Keyboard macros with their own names can be bound to keys just like built in commands can. See the .IQ define-macro , .IQ source and .IQ write-macros-to-file commands. .dc "newline" "Return" This divides the current line at point moving all the text to the right of point down onto the newly created line. Point moves down to the beginning of the new line. In Auto Indent mode, the new line will be indented to match the old line. .dc "newline-and-backup" "^O" This divides the current line at point moving all the text to the right of point down onto the newly created line. The difference between this and .IQ newline is that point does not move down to the beginning of the new line. .dc "newline-and-indent" "Linefeed" This behaves in any mode the same way as .IQ newline does in Auto Indent mode. .dc "next-error" "^X\ ^N" This moves to the next error in the list of errors that were parsed with .IQ parse-errors . In one window the list of errors is shown with the current one always at the top. If the file that contains the error is not already in a buffer, it is read in. Its buffer is displayed in another window and point is positioned in this window on the line where the error occurred. .dc "next-line" "^N" This moves point down to the corresponding position on the next line (or the end of that line if it does not extend so far). .dc "next-page" "^V" This displays the next page of the selected buffer by taking the bottom line of the window and redrawing the window with it at the top. If there isn't another page in the buffer \s-2JOVE\s0 rings the bell. If a numeric argument of only \- (with no digits) is supplied, the previous page is displayed. Otherwise, if a numeric argument is supplied the screen is scrolled up that many lines, exactly as in the .IQ scroll-up command; if the argument is negative the screen is scrolled down. .dc "next-window" "^X\ N" This moves into the next window. Windows live in a circular list so when you're in the bottom window and you try to move to the next one you are moved to the top window. It is an error to use this command with only one window. .dc "number-lines-in-window" "Not Bound" This displays the line numbers for each line in the buffer being displayed. The number isn't actually part of the text; it's just printed before the actual buffer line is. To turn this off you run the command again; it toggles. .dc "one-key-confirmation" "(variable)" If this variable is set, a single keystroke of y or n is expected in answer to yes/no questions. Normally, a yes/no question must be answered with any non-empty prefix of yes or no, followed by a Return .dc "over-write-mode" "Not Bound" This turns Over Write minor mode on in the selected buffer. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. When on, this mode changes the way the self-inserting characters work. Instead of inserting themselves and pushing the rest of the line over to the right, they replace or over-write the existing character. Also, DEL replaces the character before point with a space instead of deleting it. When Over Write mode is on \*QOvrWt\*U is displayed in the mode line. .dc "page-next-window" "ESC\ ^V" This displays the next page in the next window. It switches to the next window, performs a .IQ next-page command (with any numeric argument), and switches back to the original window. Note that an argument of just \*Q\-\*U will thus display the previous page. .dc "paren-flash" "\^) } ]\^" This command causes the characters bound to it to be inserted, and then to partake in C mode curly brace indentation, Lisp mode parenthesis indentation, and the Show Match mode paren/curly-brace/square-bracket flashing. .dc "paragraph-delimiter-pattern" "(variable)" When \s-2JOVE\s0 is searching for a paragraph boundary, if this pattern (a regular expression) matches the start of a line, that line is treated as a paragraph delimiter. The default pattern recognizes blank lines, troff control lines, and lines starting with a TeX control sequence. There is a special provision for TeX: if a line is matched by the pattern, and the match is of exactly an initial \e, that line is only treated as a delimiter if the next line also starts with \e. .dc "paren-flash-delay" "(variable)" How long, in tenths of a second, \s-2JOVE\s0 should pause on a matching parenthesis in Show Match mode. The default is 5. .dc "parse-errors" "Not Bound" This takes the list of C compilation errors (or the output from another program in an acceptable format) in the selected buffer and parses them for use with the .IQ next-error , .IQ previous-error and .IQ current-error commands. This is a very useful tool and helps with compiling C programs or, when used in conjunction with the .UX .IQ grep command, with making changes to a bunch of files. \s-2JOVE\s0 finds each file that has an error and remembers each line that contains an error. It doesn't matter if later you insert or delete some lines in the buffers containing errors; \s-2JOVE\s0 remembers where they are regardless. .IQ current-error is automatically executed after one of the parse commands, so you end up at the first error. The variable .IQ error-format-string specifies, by means of regular-expressions, the format of errors to be recognized. Its default value can handle messages from .IQ cc , .IQ cpp , .IQ lint and .IQ "grep\ \-n" . .dc "parse-spelling-errors-in-buffer" "Not Bound" This parses a list of words in the selected buffer and looks them up in another buffer that you specify. It is invoked automatically by the .IQ spell-buffer command. .dc "pause-jove" "ESC\ S" This stops \s-2JOVE\s0 and returns control to the parent shell. This only works on systems that have the job control facility. To return to \s-2JOVE\s0 you type \*Qfg\*U to the shell. .dc "pop-mark" "Not Bound" \s-2JOVE\s0 remembers the last eight marks and you use .IQ pop-mark to go backward through the ring of marks. If you execute .IQ pop-mark enough times you will eventually get back to where you started. This command is also executed when you run .IQ set-mark with a numeric argument. .dc "popd" "Not Bound" This pops one entry off the directory stack. Entries are pushed with the .IQ pushd or .IQ pushlibd commands. The names were stolen from the C-shell and the behavior is the same. .dc "previous-error" "^X\ ^P" This is the same as .IQ next-error except it goes to the previous error. See .IQ next-error for documentation. .dc "previous-line" "^P" This moves point up to the corresponding position on the previous line (or the end of that line if it does not extend so far). .dc "previous-page" "ESC\ V" This displays the previous page of the selected buffer by taking the top line and redrawing the window with it at the bottom. If a numeric argument of only \- (with no digits) is supplied, the next page is displayed. Otherwise, if a numeric argument is supplied the screen is scrolled down that many lines, exactly as in the .IQ scroll-down command; if the argument is negative the screen is scrolled up. .dc "previous-window" "^X\ P or ^X\ O" This moves into the previous window. Windows live in a circular list so when you're in the top window and you try to move to the previous one you are moved to the bottom window. It is an error to use this command with only one window. .dc "print" "Not Bound" This displays the value of a \s-2JOVE\s0 variable in the message line. .dc "proc-env-export" "Not Bound" This takes an argument of the form VARNAME=VALUE and replaces or sets VARNAME to that VALUE in the list of environment variables that are passed to subshell commands i.e. .IQ shell-command , .IQ compile-it , .IQ spell-buffer , etc. .dc "proc-env-show" "Not Bound" This shows (as temporary screen output or in a buffer, depending on the variable .IQ send-typeout-to-buffer ) the environment that will be exported to subshell commands. .dc "proc-env-unset" "Not Bound" This takes an argument that is the name of an environment variable and removes it from the list of environment variables that will be passed to subshell commands. .dc "process-bind-keymap-to-key" "Not Bound" This is like .IQ process-bind-to-key except that you use it to attach a key sequence to named keymap. The only reasonable use is to bind some extra key to .IQ ESC-map for keyboards that make typing ESC\ painful. .dc "process-bind-macro-to-key" "Not Bound" This is like .IQ process-bind-to-key except you use it to attach a key sequence to a named macro. .dc "process-bind-to-key" "Not Bound" This command is identical to .IQ bind-to-key , except that it only affects your bindings when you are in a buffer attached to an interactive process. When you enter the process buffer, any keys bound with this command will automatically take their new values. When you switch to a non-process buffer, the old bindings for those keys will be restored. For example, you might want to execute .DS I process-bind-to-key stop-process ^C\ ^Z process-bind-to-key interrupt-process ^C\ ^C .DE Then, when you start up an interactive process and switch into that buffer, ^C\ ^Z will execute .IQ stop-process and ^C\ ^C will execute .IQ interrupt-process . Bindings effective only in process windows are shown with a \*QProc:\*U prefix in this manual and by the .IQ apropos and .IQ describe-bindings commands. .dc "process-newline" "Proc: Return" This command is normally bound to Return as if by a .IQ process-bind-to-key so that it will only be bound in a process window. \s-2JOVE\s0 does two different things depending on where you are when you hit Return. When you're in the last line of the interactive process buffer, point moves to the end of the line, the line is terminated, and the line is made available as input to the process. When point is positioned in some other line, that line is copied to the end of the buffer (with the prompt stripped) and point is moved there with it, so you can then edit that line before sending it to the process. This command must be bound to the key you usually use to enter shell commands (Return), or else you won't be able to enter any. See the variable .IQ process-prompt . .dc "process-prompt" (variable) What a prompt looks like from the .IQ shell and .IQ i-shell-command processes. The default is \*Q% \*U, the default C-shell prompt. This is actually a regular expression search string. So you can set it to be more than one thing at once using the \e| operator. For instance, for LISP hackers, the prompt can be .DS "% \e|-> \e|<[0-9]>: ". .DE .dc "process-send-data-no-return" "Not Bound" This is like .IQ process-newline except it sends everything to the process without the newline. Normally, when you type return in a process buffer it sends everything you typed including the Return. This command just provides a way to send data to the process without having to send a newline as well. .dc "push-shell" "Not Bound" This spawns a child shell and relinquishes control to it. Within this shell, $1 can be used to refer to the filename (if any) of the selected buffer. This works on any version of .UX , but this isn't as good as .IQ pause-jove because it takes time to start up the new shell and you get a brand new environment every time. To return to \s-2JOVE\s0, simply exit the shell. .dc "pushd" "Not Bound" This pushes a directory onto the directory stack and cd's into it. It asks for the directory name but if you don't specify one it switches the top two entries on the stack. It purposely behaves the same as C-shell's .IQ pushd . .dc "pushlibd" "Not Bound" Performs same function as .IQ pushd except that it pushes the Jove sharable library directory. This directory holds the system-wide .BQ jove.rc and the text used by the .IQ describe-command and .IQ describe-variable commands. It is mainly intended for use with the .BQ jove.rc file. .dc "pwd" "Not Bound" This prints the pathname of the working directory, as in the .UX .IQ pwd command. .dc "query-replace-string" "ESC\ Q" This replaces strings matching a specified regular-expression with a specified replacement string. When a match is found, point is moved to it and then \s-2JOVE\s0 asks what to do. The options are: .DS I .ta \w'DEL, BS, or N or n11'u Space or Y or y to replace this match and go on to the next one. Period to replace this match and then stop. DEL, BS, or N or n to skip this match and go on to the next one. ^R or R or r to enter a recursive edit. This lets you temporarily suspend the replace, do some editing, and then return to continue where you left off. To continue with the \c .IQ query-replace-string ,\c use the \c .IQ exit-jove " command." ^W to delete the match and then enter a recursive edit. ^U or U or u to undo all changes to the last modified line and continue the search from the start of that line. ! or P or p to go ahead and replace the remaining matches without asking, as in \c .IQ replace-string . Return or Q or q to stop the \c .IQ query-replace-string . ^L to redraw the screen .DE It is often useful to include a piece of the matched string in the replacement, especially if the piece was not matched by literal text. To select which part of the matched string is to be used, the corresponding part of the pattern is bracketed with \e\^( and \e). More than one set of brackets may be used, as long as they are properly nested. The matching substring is selected in the replacement string using \e followed by a digit: \e1 for the first, \e\^2 for the second, and so on. Conveniently, \e\^0 always stands for the complete matched string, as if the whole regular expression were bracketed. For example, the following command will reverse pairs of comma-separated numbers: .ID : query-replace-string \e\^([0-9]\(**\^\e),\e\^([0-9]\(**\^\e) with \e\^2,\e1 .DE The search for a match starts at point and goes to the end of the buffer, so to replace in the entire buffer you must first go to the beginning. Each subsequent search starts at the position after the previous match; if the previous match was an empty string, the search is first advanced one character to prevent unbounded repetition. .dc "quit-process" "Proc: ^C\ ^\^\e\^" Send the signal SIGQUIT to the interactive process in the selected buffer. This is equivalent to sending the \*Qquit\*U character (which most people have bound to ^\^\e) to the process. This only works if you are in a buffer bound to an interactive process. .dc "quoted-insert" "^Q or ^^\^" This lets you insert characters that normally would be executed as other \s-2JOVE\s0 commands. For example, to insert \*Q^F\*U you type \*Q^Q ^F\*U (assuming .IQ quoted-insert is bound to ^Q). NUL cannot be represented in the buffer, so .IQ quoted-insert will insert \*Q^@\*U in its stead. On the IBM PC under DOS, non-ASCII keystrokes are seen by \s-2JOVE\s0 as a hex FF character followed by another character; .IQ quoted-insert will quote both characters. .dc "read-only-mode" "Not Bound" This turns on or off the Read-only minor mode. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. When a buffer is in Read-only mode, any attempt to modify the buffer will fail. When a file is found, and it's not got write permission, \s-2JOVE\s0 automatically puts the buffer in read-only mode. This is very helpful when you are in environments which use source control programs like RCS and SCCS. It prevents accidents like making a bunch of changes and only THEN discovering that you haven't checked the file out for making changes. .dc "read-word-abbrev-file" "Not Bound" This reads a specified file that contains a bunch of abbreviation definitions, and makes those abbreviations available. See the .IQ word-abbrev-mode command. .dc "recursive-edit" "Not Bound" This enters a recursive editing level. This isn't really very useful. I don't know why it's available for public use. I think I'll delete it some day. .dc "redraw-display" "^L" This vertically centers the line containing point within the window. If that line is already in place, the screen is first cleared and then redrawn. If a numeric argument is supplied, the line is positioned at that offset from the top of the window. For example, \*QESC\ 0 ^L\*U positions the line containing point at the top of the window (assuming .IQ redraw-display is bound to ^L). .dc "rename-buffer" "Not Bound" This lets you rename the selected buffer. .dc "replace-in-region" "Not Bound" This is the same as .IQ replace-string except that it is restricted to occurrences between point and the mark. .dc "replace-string" "ESC\ R" This replaces all occurrences of a specified string with a specified replacement string. This is just like .IQ query-replace-string except that it replaces without asking. .dc "right-margin" "(variable)" Where the right margin is for Auto Fill mode and the .IQ fill-paragraph and .IQ fill-region commands. The default is 78. .dc "right-margin-here" "Not Bound" This sets the .IQ right-margin variable to the current position of point. This is an easy way to say, \*QMake the right margin begin here,\*U without having to count the number of spaces over it actually is. .dc "save-file" "^X\ ^S or ^X\ S or ^X\ \e\^" This saves the selected buffer to the associated file. This makes your changes permanent so you should be sure you really want to do it. If the buffer has not been modified .IQ save-file refuses to do the save. If you really do want to write the file you must use .IQ write-file . .dc "save-on-exit" "(variable)" If this is .IQ on when \s-2JOVE\s0 is about to exit, it will ask, for each modified buffer, whether you wish it to be saved. See .IQ write-modified-files . .dc "scroll-all-lines" "(variable)" When this is .IQ off , (the default) horizontal scrolling will only affect the line containing point. When it is .IQ on , horizontal scrolling will affect the whole window. See also the .IQ scroll-width variable. .dc "scroll-bar" "(variable)" When this is turned .IQ on , a section of the mode line at the foot of each window is left in not-reverse-video, to show the position of the window relative to the whole of the file represented by that buffer (however, if the whole of the buffer is within the window, the whole mode line remains inverted). .dc "scroll-down" "ESC\ Z" This scrolls the screen one line down. If the line containing point moves past the bottom of the window, point is moved up to the top of the window. If a numeric argument is supplied that many lines are scrolled; if the argument is negative the screen is scrolled up instead. See the .IQ previous-page command. .dc "scroll-left" "Not Bound" This scrolls the text in the active window to the left. If a numeric argument is specified then the text is scrolled that number of columns. Otherwise, the text is scrolled by the number of columns specified by the variable .IQ scroll-width . If the variable .IQ scroll-all-lines is ON then .IQ scroll-left may actually do nothing if the scrolling would cause point not to be visible. A negative argument scrolls right. If the .IQ mode-line variable is suitably set, an indication that the text is scrolled will be given in the mode line. .dc "scroll-right" "Not Bound" This scrolls the text in the active window to the right. If a numeric argument is specified then the text is scrolled that number of columns. Otherwise, the text is scrolled by the number of columns specified by the variable .IQ scroll-width . If the variable .IQ scroll-all-lines is ON then .IQ scroll-right may actually do nothing if the scrolling would cause point not to be visible. A negative argument scrolls left. .dc "scroll-step" "(variable)" How many lines should be scrolled if the .IQ previous-line or .IQ next-line commands move you off the top or bottom of the screen. You may wish to decrease this variable if you are on a slow terminal. The default value is 0, which means to center the current line in the window. If the value is negative, the behavior is slightly different. If you move off the top of the window, and .IQ scroll-step is, say, \-5 then the new line will be displayed 5 lines from the bottom of the window. If you move off the bottom of the window, the new line will be positioned 5 lines from the top of the window. .dc "scroll-up" "^Z" This scrolls the screen one line up. If the line containing point moves past the top of the window, point is moved down to the top of the window. If a numeric argument is supplied that many lines are scrolled; if the argument is negative the screen is scrolled down instead. See also the .IQ next-page command. .dc "scroll-width" "(variable)" Just as a buffer may be too long to be completely displayed in a window, a line may be too wide. \s-2JOVE\s0 handles wide lines through horizontal scrolling, displaying only a portion of the line. This variable affects horizontal scrolling. If point is outside the displayed portion of its line, but is within the specified number of columns beyond either side, the line is scrolled that much. Otherwise, the line will be scrolled to center point. The default value is 10. If the variable is 0, centering will always be used. See also the .IQ scroll-all-lines variable. .dc "search-exit-char" "(variable)" Set this to the character you want to use to exit incremental search. The default is Newline, which makes .IQ i-search commands compatible with normal string search. .dc "search-forward" "^S or ^\^\e\^" This searches forward for a specified search string and positions point at the end of the string if it's found. If the string is not found point remains unchanged. This searches from point to the end of the buffer, so any matches before point will be missed. If point is moved by more than the variable .IQ mark-threshold , the old point will be pushed. .dc "search-forward-nd" "Not Bound" This is just like .IQ search-forward except that it doesn't assume a default search string, and it doesn't set the default search string. This is useful for defining macros, when you want to search for something, but you don't want it to affect the current default search string. .dc "search-reverse" "^R" This searches backward for a specified search string and positions point at the beginning if the string if it's found. If the string is not found point remains unchanged. This searches from point to the beginning of the buffer, so any matches after point will be missed. If point is moved by more than the variable .IQ mark-threshold , the old point will be pushed. .dc "search-reverse-nd" "Not Bound" This is just like .IQ search-reverse except that it doesn't assume a default search string, and it doesn't set the default search string. This is useful for defining macros, when you want to search for something, but you don't want it to affect the current default search string. .dc "select-buffer" "^X\ B" This selects a new or already existing buffer making it the current one. You can type either the buffer name or number. If you type in the name you need only type the name until it is unambiguous, at which point typing Tab or Space will complete it for you. If you want to create a new buffer you can type Return instead of Space, and a new empty buffer will be created. .dc "select-buffer-1" "Not Bound" This selects buffer number 1, if it exists. .dc "select-buffer-10" "Not Bound" This selects buffer number 10, if it exists. .dc "select-buffer-2" "Not Bound" This selects buffer number 2, if it exists. .dc "select-buffer-3" "Not Bound" This selects buffer number 3, if it exists. .dc "select-buffer-4" "Not Bound" This selects buffer number 4, if it exists. .dc "select-buffer-5" "Not Bound" This selects buffer number 5, if it exists. .dc "select-buffer-6" "Not Bound" This selects buffer number 6, if it exists. .dc "select-buffer-7" "Not Bound" This selects buffer number 7, if it exists. .dc "select-buffer-8" "Not Bound" This selects buffer number 8, if it exists. .dc "select-buffer-9" "Not Bound" This selects buffer number 9, if it exists. .dc "self-insert" "Most Printing Characters" This inserts the character that invoked it into the buffer at point. Initially all but a few of the printing characters are bound to .IQ self-insert . See also .IQ paren-flash . .dc "send-typeout-to-buffer" "(variable)" When this is .IQ on \s-2JOVE\s0 will send output that normally overwrites the screen (temporarily) to a buffer instead. This affects commands like .IQ list-buffers , .IQ list-processes , .IQ shell-command-with-typeout , and commands that use completion. The default value is .IQ off . .dc "set" "Not Bound" This sets a specified variable to a new value. .dc "set-mark" "^@" This sets the mark at the current position in the buffer. It prints the message \*Q[Point pushed]\*U on the message line. It says that instead of \*Q[Mark set]\*U because when you set the mark the previous mark is still remembered on a ring of eight marks. So \*Q[Point pushed]\*U means point is pushed onto the ring of marks and becomes the value of \*Qthe mark\*U. To go through the ring of marks, use the .IQ pop-mark command. If you type this enough times you will get back to where you started. If a .IQ set-mark command is given a numeric argument, it acts like a .IQ pop-mark command. .dc "share-dir-pathname" "(variable)" This tells JOVE where to find the machine-independent configuration files that it uses, typically some system-wide .IQ jove.rc configuration files read on startup, the formatted help information for the .IQ describe-* commands and the tutorial. There is usually a compiled-in path that should be correct if Jove was properly installed. This path can also be overridden with the .IQ -s command-line option. .dc "shell" "(variable)" The shell to be used with all the shell-\(** commands command. If your SHELL environment variable is set, it is used as the default value of .IQ shell ; otherwise \*Q/bin/csh\*U is the default. See also the description of the .IQ shell-flags variable to see how to change the flags passed to this shell. .dc "shell" "Not Bound" This starts up an interactive shell in a window; if there is already an interactive shell, it just selects that buffer. \s-2JOVE\s0 uses \*Q\(**shell-n\(**\*U (where .BQ n is the argument of the command) as the name of the buffer in which the interacting takes place. Thus different argument values refer to different interactive shells. See the \s-2JOVE\s0 manual for information on how to use interactive processes. See also the variable .IQ wrap-process-lines . .dc "shell-command" "^X\ !" This runs a .UX command and places the output from that command in a buffer. Within the command, $1 can be used to refer the the filename (if any) of the selected buffer. \s-2JOVE\s0 creates a buffer that matches the name of the command you specify and then attaches that buffer to a window. So, when you have only one window running, this command will cause \s-2JOVE\s0 to split the window and attach the new buffer to that window. Otherwise, \s-2JOVE\s0 finds the most convenient of the available windows and uses that one instead. If the buffer already exists it is first emptied (unless a numeric argument is specified). If it's already holding a file, not some output from a previous command, \s-2JOVE\s0 asks permission before emptying the buffer. Beware that if you go ahead, not only do you lose any unsaved changes that you made to the buffer, but the buffer's file name remains set, making it easy to later accidentally overwrite the original file. See also the variable .IQ wrap-process-lines . .dc "shell-command-no-buffer" "Not Bound" This is just like .IQ shell-command except it just runs the command without saving the output to any buffer. It will report the success of the command in the usual way. .dc "shell-command-to-buffer" "Not Bound" This is just like .IQ shell-command except it lets you specify the buffer to use. .dc "shell-command-with-typeout" "Not Bound" This is just like .IQ shell-command except that instead of saving the output to a buffer, and displaying it in a window, this just types out the output in the same way that .IQ list-buffers does. Actually, how this behaves depends on the value of the variable .IQ send-typeout-to-buffer . If it is .IQ on then .IQ shell-command-with-typeout will behave just like .IQ shell-command . If a numeric argument is given, the \*Qcompleted successfully\*U message at the end is suppressed. .dc "shell-flags" "(variable)" This specifies a flag argument that directs the shell to take the next argument as a command to be executed. The default is \*Q\-c\*U (suitable for all known .UX shells). Under MSDOS, the default is \*Q/c\*U (suitable for command.com and similar MSDOS shells). Other MSDOS shells, such as MKS KSH require that this be changed to \*Q\-c\*U. Under MSDOS, \s-2JOVE\s0 puts quotes around the command argument if .IQ shell-flags starts with \*Q\-\*U. See the .IQ shell variable to change the default shell. .dc "shift-region-left" "Not Bound" This shifts the region left by .IQ c-indentation-increment OR by the numeric argument, if one is supplied. If a negative argument is supplied the region is shifted the other way. .dc "shift-region-right" "Not Bound" This shifts the region right by .IQ c-indentation-increment OR by the numeric argument, if one is supplied. If a negative argument is supplied the region is shifted the other way. .dc "show-match-mode" "Not Bound" This turns on or off the Show Match minor mode in the selected buffer. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. This mode changes \*Q}\*U, \*Q)\*U and \*Q]\*U so that when they are typed they are inserted as usual, and then the cursor flashes back to the matching \*Q{\*U, \*Q(\*U or \*Q[\*U (depending on what was typed) for about half a second, and then goes back to just after the \*Q}\*U, \*Q)\*U or \*Q]\*U that invoked the command. This is useful for typing in complicated expressions in a program. You can change how long the cursor sits on the matching parenthesis by setting the .IQ paren-flash-delay variable in tenths of a second. If the matching \*Q{\*U, \*Q(\*U or \*Q[\*U isn't visible, the line containing the match is displayed on the message line. .dc "shrink-window" "Not Bound" This makes the active window one line shorter, if possible. Windows must be at least 2 lines high, one for the text and the other for the mode line. See also .IQ grow-window . .dc "source" "Not Bound" This reads a bunch of \s-2JOVE\s0 commands from a file. If a numeric argument is supplied to the .IQ source command, it will quietly do nothing if it cannot read the file. The format of the file is the same as that in the .BQ jove.rc file, or your private .BQ \&.joverc in your home directory. There should be one command per line and it should be as though you were responding to an .IQ execute-named-command command while in \s-2JOVE\s0. A command can be optionally preceded by a numeric argument. Lines commencing with a # are treated as comments. Control characters such as ^R may be represented as themselves, or as \*Q^\*U followed by \*QR\*U. ESC should be represented by ^[. Sometimes it is useful to do different things in different circumstances. To make this possible, there are three conditional commands: .IQ if , .IQ ifenv , and .IQ ifvar . The .IQ if command takes as an operand a shell command, which it runs. If the command succeeds, the commands after the .IQ if , until a line containing .IQ else or .IQ endif , are performed. Otherwise, these commands are suppressed and the commands after any .IQ else , up until an .IQ endif , are executed. Conditionals nest in the normal way. The .IQ ifenv command takes as operands the name of an environment variable and a pattern. If the environment variable is defined and its value matches the pattern, the .IQ ifenv succeeds. Note that patterns are anchored matches from the left. The .IQ ifvar command takes as operands the name of a \s-2JOVE\s0 variable and a pattern. If the \s-2JOVE\s0 variable is defined and its value matches the pattern, the .IQ ifvar succeeds. For example, here are some lines from the file .BQ jove.rc . .DS I bind-to-key pause-jove ^[S bind-to-key pause-jove ^[s set process-prompt ^[^%$#]*[%$#] # source any TERMinal-specific rc file 1 source jove.rc.$TERM ifvar jove-features .*:iproc: process-bind-to-key interrupt-process ^C^C endif .DE What they do is to provide two alternative key bindings for .IQ pause-jove , set the variable .IQ process-prompt , and attempt to call the .IQ source command on the file .BQ jove.rc.$TERM . Because of the numeric argument 1, there will be no complaint if this file cannot be found. If \s-2JOVE\s0 was compiled with interactive-processes enabled (in which case the string .IQ :iproc: will be part of the read-only \s-2JOVE\s0 variable .IQ jove-features ), the .iQ process-bind-to-key command binds the key sequence Control-C Control-C to the .IQ interrupt-process command, which sends the SIGINT signal to interactive shell. .dc "space-sentence-2" (variable) If set .IQ on , two spaces are left after each sentence by commands such as .IQ fill-paragraph ; otherwise, one space is left. The default is .IQ on . .dc "spell-command-format" "(variable)" This is the format specification string for a command which will run a spell checker on a specified file and produce a list of misspelled words on the output. This variable (and related .IQ spell-buffer capability) is only available if Jove is built with support for subshells. The string must contain one instance of the specifier %s which will be replaced with the pathname of the file to be checked. .dc "spell-buffer" "Not Bound" This saves the current buffer and runs it through the .UX .IQ spell command (specified by the variable .IQ spell-command-format ) and places the output in buffer \*QSpell\*U. Then \s-2JOVE\s0 lets you edit the list of words, expecting you to delete the ones that you don't care about, i.e., the ones you know are spelled correctly. Then the .IQ parse-spelling-errors-in-buffer command comes along and finds all the misspelled words and sets things up so the error commands .IQ next-error , .IQ previous-error and .IQ current-error work. See also the variable .IQ error-window-size . .dc "split-current-window" "^X\ 2" This splits the active window into two equal parts (providing the resulting windows would be big enough) and displays the selected buffer in both windows. Use .IQ delete-other-windows to go back to 1 window mode. If a numeric argument is supplied, the window is split \*Qevenly\*U that many times (when possible). .dc "start-remembering" "Not Bound" This is just another name for the .IQ begin-kbd-macro command. It is included for backward compatibility. .dc "stop-process" "Not Bound" Send the signal SIGTSTP to the interactive process in the selected buffer. This is equivalent to sending the \*Qstop\*U character (which most people have bound to ^Z) to the process. This only works if you are in a buffer bound to an interactive process. .dc "stop-remembering" "Not Bound" This is just another name for the .IQ end-kbd-macro command. It is included for backward compatibility. .dc "string-length" "Not Bound" This prints the number of characters in the string that point sits in. Strings are surrounded by double quotes. \s-2JOVE\s0 knows that \*Q\^\e\^007\*U is considered a single character, namely \*Q^G\*U, and also knows about other common ones, like \*Q\^\e\^r\*U (Return) and \*Q\^\e\^n\*U (Linefeed). This is mostly useful only for C programmers. .dc "suspend-jove" "Not Bound" This is a synonym for .IQ pause-jove . .dc "sync-frequency" "(variable)" The temporary files used by \s-2JOVE\s0 are forced out to disk every .IQ sync-frequency modifications. The default is 50, which really makes good sense. Unless your system is very unstable, you probably shouldn't fool with this. .dc "tab-width" "(variable)" When \s-2JOVE\s0 displays a Tab character, it moves point forward to the next multiple of this variable. If the value is 0, tab is displayed as ^I, not whitespace. The default value is 8. .dc "tag-file" "(variable)" This is the name of the file in which \s-2JOVE\s0 should look up tag definitions. The default value is \*Q.\^/tags\*U. .dc "text-attribute" "(variable)" (IBM PC version only) This specifies the screen attribute (color) for normal text characters. The default is 7 (white on black). .dc "teach-jove" "Not Bound" This loads the Jove tutorial from from the .BQ ~/teach-jove file if it was already saved there, else it loads the reference copy from .BQ SHAREDIR/teach-jove into a buffer that will save to .BQ ~/teach-jove, replacing the old standalone .I teachjove command. The .IQ -T option, if given to JOVE on the command line, will start JOVE up with the tutorial loaded. .dc "text-mode" "Not Bound" This sets the major mode to Text. This affects what \s-2JOVE\s0 considers as characters that make up words. For instance, Single-quote is not part of a word in Fundamental mode, but is in Text mode. .dc "tmp-file-pathname" "(variable)" This tells \s-2JOVE\s0 where to put the tmp files, which is where \s-2JOVE\s0 stores buffers internally. The default is in .BQ /tmp , or as set up when your system was compiled, but if you want to store them somewhere else, you can set this variable. If your system crashes a lot it might be a good idea to set this variable to somewhere other than .BQ /tmp because the system removes all the files in .BQ /tmp upon reboot, and so you would not be able to recover editor buffers using the .IQ "jove -r" command. NOTE: In order for this to work correctly you must set this variable BEFORE \s-2JOVE\s0 creates the tmp file. You can set this in your .BQ \&.joverc (the closer to the beginning the better), or as soon as you start up \s-2JOVE\s0 before you read any files. .dc "transpose-characters" "^T" This switches the character before point with the one after point, and then moves forward one. This doesn't work at the beginning of the line, and at the end of the line it switches the two characters before point. Since point is moved forward, so that the character that was before point is still before point, you can use .IQ transpose-characters to drag a character down the length of a line. .dc "transpose-lines" "^X\ ^T" This switches the current line with the one above it, and then moves down one so that the line that was above point is still above point. This, like .IQ transpose-characters , can be used to drag a line down a page. .dc "unbound" "Not Bound" This command acts as if an unbound key sequence were typed. In fact, that is its use: if you wish to unbind a key sequence, simply bind it to this command. .dc "update-time-frequency" "(variable)" How often the mode line is updated (and thus the time). The default is 30 seconds. .dc "use-i/d-char" "(variable)" If your terminal has insert/delete character capability you can tell \s-2JOVE\s0 not to use it by setting this to .IQ off . In my opinion it is only worth using insert/delete character at low baud rates. WARNING: if you set this to .IQ on when your terminal doesn't have insert/delete character capability, you will get weird (perhaps fatal) results. .dc "version" "Not Bound" Displays the version number of this \s-2JOVE\s0. .dc "visible-bell" "(variable)" If the terminal has a visible bell, use it instead of beeping. .dc "visible-spaces-in-window" "Not Bound" This displays an underscore character instead of each Space in the window and displays a greater-than followed by spaces for each Tab in the window. The actual text in the buffer is not changed; only the screen display is affected. To turn this off you run the command again; it toggles. .dc "visit-file" "^X\ ^V or ^X\ ^R" This reads a specified file into the selected buffer replacing the old text. If the buffer needs saving \s-2JOVE\s0 will offer to save it for you. Sometimes you use this to start over, say if you make lots of changes and then change your mind. If that's the case you don't want \s-2JOVE\s0 to save your buffer and you answer \*QNO\*U to the question. .dc "window-find" "^X\ 4" This lets you select another buffer in another window three different ways. This waits for another character which can be one of the following: .DS I .ta .5i 1i 1.5i T Finds a tag in the other window. ^T Finds the tag at point in the other window F Finds a file in the other window. B Selects a buffer in the other window. .DE This is just a convenient short hand for .IQ split-current-window (or .IQ previous-window if there are already two windows) followed by the appropriate sequence for invoking each command. With this, though, there isn't the extra overhead of having to redisplay. In addition, you don't have to decide whether to use .IQ split-current-window or .IQ previous-window since .IQ window-find does the right thing. .dc "word-abbrev-mode" "Not Bound" This turns on or off Word Abbrev minor mode in the selected buffer. Without a numeric argument, the command toggles the mode; with a zero argument, the mode is turned off; with a non-zero argument, the mode is turned on. Word Abbrev mode lets you specify a word (an abbreviation) and a phrase with which \s-2JOVE\s0 should substitute the abbreviation. You can use this to define words to expand into long phrases, e.g., \*Qjove\*U can expand into \*QJonathan's Own Version of Emacs\*U; another common use is defining words that you often misspell in the same way, e.g., \*Qthier\*U => \*Qtheir\*U or \*Qteh\*U => \*Qthe\*U. See the information on the .IQ auto-case-abbrev variable. .sp 1 There are two kinds of abbreviations: mode specific and global. If you define a Mode specific abbreviation in C mode, it will expand only in buffers that are in C mode. This is so you can have the same abbreviation expand to different things depending on your context. Global abbreviations expand regardless of the major mode of the buffer. The way it works is this: \s-2JOVE\s0 looks first in the mode specific table, and then in the global table. Whichever it finds it in first is the one that's used in the expansion. If it doesn't find the word it is left untouched. \s-2JOVE\s0 tries to expand words when you type a punctuation character or Space or Return. If you are in Auto Fill mode the expansion will be filled as if you typed it yourself. .dc "wrap-process-lines" "(variable)" If this variable is .IQ on , the process output that is captured in a buffer is wrapped just before the line would have as many characters as there are columns on the screen. This introduces extra newlines, but it makes the output more readable. Note that the folding does not take into account that some characters (notably tabs) occupy more than one column of the display. The output of the .IQ filter-region command is not processed in this way because the extra newlines are presumed to be undesired in this case. .dc "wrap-search" "(variable)" If set, searches will \*Qwrap around\*U the ends of the buffer instead of stopping at the bottom or top. The default is .IQ off . .dc "write-file" "^X\ ^W" This saves the selected buffer to a specified file, and then makes that file the default file name for this buffer. If you specify a file that already exists you are asked to confirm over-writing it. .dc "write-files-on-make" "(variable)" When set, all modified files will be written out before calling make when the .IQ compile-it command is executed. The default is .IQ on . .dc "write-macros-to-file" "Not Bound" This writes the currently defined macros to a specified file in a format appropriate for reading them back in with the .IQ source command. The purpose of this command is to allow you to define macros once and use them in other instances of \s-2JOVE\s0. See also the .IQ define-macro command. .dc "write-modified-files" "^X\ ^M" This saves all the buffers that need saving. If you supply a numeric argument it asks, for each buffer, whether you really want to save it. .dc "write-region" "Not Bound" This writes the text in the region to a specified file. If the file already exists you are asked to confirm over-writing it. .dc "write-word-abbrev-file" "Not Bound" This writes the currently defined abbreviations to a specified file. They can be read back in and automatically defined with .IQ read-word-abbrev-file . .dc "xj-mouse-commands" "^X\ m\(**" Programs such as XJove and JoveTool generate these commands whenever a mouse button is pressed or released, or the mouse is moved while the button is pressed. They are followed by parameters giving parameters for the button pressed, the coordinates of the mouse, etc. They are not intended for direct use by the normal user. .sp 1 The individual commands will now be described. .dc "xj-mouse-copy-cut" "^X\ m8" Performs a .IQ copy-region if the CTRL key was down, or a .IQ kill-region if both CTRL and SHIFT were down. This command is normally bound to the release of button 2. .dc "xj-mouse-line" "^X\ m7" Sets the region to be the whole line containing the cursor. This command is normally bound to a triple down click of button 2, and the presumed effects of the preceding double click are first undone. .dc "xj-mouse-mark" "^X\ m5" Both point and mark are set to the cursor. This command is normally bound to the pressing of button 2. .dc "xj-mouse-point" "^X\ m[01249]" Point is set to the cursor. This command is normally bound to the single, double, and triple down-click and the dragging of button 1; also the dragging of button 2. .dc "xj-mouse-word" "^X\ m6" Sets the region to be the word (or the gap between two words) containing the cursor. This command is normally bound to a double down click of button 2, and the presumed effects of the preceding single click are first undone. .dc "xj-mouse-yank" "^X\ m3" Performs a .IQ yank if the CTRL key was down. This command is normally bound to the release of button 1. .dc "xt-mouse" "(variable)" When set, \s-2JOVE\s0 sends XTerm escape sequences to enable and disable the mouse messages at appropriate times. Warning: due to the way XTerm encodes mouse events, if .IQ meta-key is set, mouse actions beyond column 95 or row 95 will be misunderstood; in any case, mouse actions beyond column 223 or row 223 will be misunderstood. .dc "xt-mouse-commands" "ESC\ [ M\(**" Programs such as XTerm generate these commands whenever a mouse button is pressed or released. XTerm does not give the user as much power as XJove. They are followed by parameters specifying the button pressed, the coordinates of the mouse, etc. They are not intended for direct use by the normal user. Set the variable .IQ xt-mouse on to enable XTerm mouse mode. .sp 1 The individual commands will now be described. .dc "xt-mouse-mark" "^X\ m5" Both point and mark are set to the cursor. This command is normally bound to the pressing of button 2. .dc "xt-mouse-point" "^X\ m[01249]" Point is set to the cursor. This command is normally bound to the down-click of button 1. .dc "xt-mouse-up" "^X\ m6" As the name implies, this command is normally bound to the release of any button (XTerm does not specify which button was released). Note that a normally configured XTerm will not pass on mouse events if the CTRL or SHIFT keys are pressed. Point is set to the cursor. If the most recently pressed button was button 1 and the CTRL key was down (and not the SHIFT key), this command performs a .IQ yank . If the most recently pressed button was button 2 and the CTRL key was down, this command performs a .IQ copy-region . If the most recently pressed button was button 2 and the CTRL and SHIFT keys were down, this command performs a .IQ kill-region . .dc "yank" "^Y" This inserts the text at the front of the kill ring (as set by an earlier .IQ copy-region , .IQ kill-region , etc.) at point. When you do multiple kill commands in a row, they are merged so that the .IQ yank command yanks back all of them. .dc "yank-pop" "ESC\ Y" \s-2JOVE\s0 has a kill ring on which the last sixteen kills are stored. This command yanks back previous texts from the kill ring. .IQ yank yanks a copy of the text at the front of the ring. If you want one of the last sixteen kills you then use .IQ yank-pop which rotates the ring so another different entry is now at the front. You can use .IQ yank-pop only immediately following a .IQ yank or another .IQ yank-pop . If you supply a negative numeric argument the ring is rotated the other way. If you use this command enough times in a row you will eventually get back to where you started. jove-4.17.5.5/doc/contents.nr000066400000000000000000000001201501102521500156420ustar00rootroot00000000000000.EH '\s-2%\s0'JOVE User Manual'' .OH ''JOVE User Manual'\s-2%\s0' .pn 1 .bp .PX jove-4.17.5.5/doc/example.rc000066400000000000000000000013141501102521500154330ustar00rootroot00000000000000if /ua/jonathan/src/jove/lib/isttytype iq120 bind-to-key Prefix-1 \\ bind-to-key set-mark ^[ set allow-^S-and-^Q on endif if /ua/jonathan/src/jove/lib/modemp set mode-line -%n %m "%f" %((%t%s%C%s%l)%) else set mode-line -%n- %["%f" %m [%b] %]%s%((%t%s%C%s%l)%)%s(%M) %e endif 1 auto-execute-command show-match .*\.[ch]$ set comment-format /* %! %c%! */ set disable-biff on set match-regular-expressions on set use-i/d-char off bind-to-key backward-paragraph ^[[ bind-to-key current-error ^X^C bind-to-key exit-jove ^X^Z bind-to-key find-tag-at-point ^[^T bind-to-key grow-window ^Xg bind-to-key kill-s-expression ^[^K bind-to-key list-processes ^X^L bind-to-key scroll-down ^C bind-to-key shrink-window ^Xs jove-4.17.5.5/doc/intro.nr000066400000000000000000004175171501102521500151660ustar00rootroot00000000000000.\" ditroff -ms .\"########################################################################## .\"# This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # .\"# provided by Jonathan and Jovehacks without charge and without # .\"# warranty. You may copy, modify, and/or distribute JOVE, provided that # .\"# this notice is included in all the source files and documentation. # .\"########################################################################## . .\" intro.nr: the first half of the JOVE manual (not manpage!). .\" .\" To produce the whole manual, .\" tbl intro.nr | [nt]roff -ms - cmds.nr contents.nr . .\" In troff, `\` tends to overlap the characters to its left or right. In .\" this text, therefore, it is usually preceded and followed by '\' (a thin .\" space, ignored in nroff). Exceptions are where it it adjacent to .\" whitespace, and the specific cases '\"', '\|', '\1', '\)' and '\}' which .\" appear better left alone. . .de IQ \" italics (here, in manual) or quote (in describe-command) \&\\fI\\$1\\fP\\$2 .. .de BQ \" bold (here, in manual) or quote (in describe-command) \&\\fB\\$1\\fP\\$2 .. .de dc .NH 2 \\$1 .if '\\$2'(variable)' (variable) .if !'\\$2'(variable)' (\\$2) .XS \\n(PN 5n \\*(SN \\$1 .if '\\$2'(variable)' (variable) .XE .LP .. .de HH .nr Op \\n(PS .RT .ne 4.1 .if \\$1=1 .nr PS +4 .if \\$1=2 .nr PS +2 .NH \\$1 \\$2 .if \\$1=1 .XS .if \\$1=2 .XS \\n(PN 5n .if \\$1=3 .XS \\n(PN 10n .if \\$1=4 .XS \\n(PN 15n .ps 10 \\*(SN \\$2 .XE .nr PS \\n(Op .ps \\n(PS .. . .\" Change the extra vertical spacing around .DS/.DE .\" Does not work with groff's version of MS (GS is 1 iff groff MS) .if !\n(GS .if n .nr DD 0v .if !\n(GS .if t .nr DD \n(PD/2u . .nr LL 6.5i .nr LT 6.5i .nr Ww (\n(LL-30n-4n)/1n .EH '%'JOVE User Manual'' .OH ''JOVE User Manual'%' .TL JOVE User Manual .br Version 4.17 .AU Jonathan Payne (with revisions by Doug Kingston, Mark Seiden, D. Hugh Redelmeieir, Mark Moraes and Charles Lindsey) .AI .AB no .AE .HH 1 "Introduction" .LP \s-2JOVE\s0* .FS *\s-2JOVE\s0 stands for Jonathan's Own Version of \s-2EMACS\s0. .FE is an advanced, self-documenting, customizable, display editor. It (and this tutorial introduction) are based on the original \s-2EMACS\s0 editor and user manual written at M.I.T. by Richard Stallman\(dg. .FS \(dgAlthough \s-2JOVE\s0 is meant to be compatible with \s-2EMACS\s0, and indeed many of the basic commands are very similar, there are some major differences between the two editors, and you should not rely on their behaving identically. .FE .LP \s-2JOVE\s0 is considered a display editor because normally the text being edited is visible on the screen and is updated automatically as you type your commands. What You See Is What You Get. .KS .LP \s-2JOVE\s0 provides many facilities that go beyond simple insertion and deletion. Some of the more advanced features are: .DS cut and paste (or kill and yank in our terminology); search and replace using regular-expressions; multiple files, buffers and windows available simultaneously; filling of text, both on demand and as you type; manipulation of words, lines, sentences and paragraphs; automatic indentation of programs; automatic location of procedure definitions; executing programs, capturing their output in buffers; automatic location of spelling and compilation errors; parenthesis matching. .DE .KE .LP \s-2JOVE\s0 is self-documenting insofar as you can call up descriptions of commands, variables and key bindings. .KS .LP \s-2JOVE\s0 is customizable insofar as you can .DS change its behavior by changing appropriate variables; change its behavior by setting appropriate modes; automatically set the modes for a buffer from its filename; define macros to perform complex tasks; change the key bindings to match features of the particular keyboard. .DE .KE All of these options can be exercised by the system administrator, or by the user at startup, or even in the middle of a job. .LP Finally, mouse support is available (on screens which support the X-Windows package from M.I.T.) using the front end program \fIxjove\fP (or alternatively via the mouse-reporting facilities of the terminal emulator \fIxterm\fP). .KS .HH 1 "The Organization of the Screen" .LP \s-2JOVE\s0 divides the screen into several sections. .TS center; = || L1 || L . #include void main() { \ \ \ \ printf("Hello world!\^\e\^n"); \ \ \ \ return 0; <\ the Window } _ \fBJOVE\ (C OvrWt)\ \ \ [Main:1]\ \ "hello.c"\ \ \(**\ \ /home/foo\fP <\ the Mode Line _ : write-file (default hello.c) aloha.c\^\(sq <\ the Message Line = .TE .KE .HH 2 "The Window" .LP The Window section is used to display the text you are editing. The terminal's cursor shows the position of \fIpoint\fP, the location at which editing takes place. While the cursor appears to point \fIat\fP a character, point should be thought of as between characters; it points \fIbefore\fP the character that the cursor appears to be on top of. Terminals have only one cursor, and when output is in progress it must appear where the typing is being done. This doesn't mean that point is moving; it is only that \s-2JOVE\s0 has no way of showing you the location of point except when the terminal is idle. In the example, the user is in the middle of issuing a \fIwrite-file\fP command, so the cursor is at the end of the message line. .HH 3 "Typeout" .LP The lines of the window are usually available for displaying text but sometimes are pre-empted by typeout from certain commands (such as a listing of all the buffers). You can always recognize such \fItypeout\fP because it is terminated by either an \fB--end--\fP line or a \fB--more--\fP line. Most of the time, output from commands like these is only desired for a short period of time, usually just long enough to glance at it. When you have finished looking at the output, you can type Space to make the text reappear (usually a Space that you type inserts itself, but when there is typeout in the window, it does nothing but get rid of that). Any other command executes normally, .I after redrawing your text. .LP You will see \fB--more--\fP on the line above the last mode line when typeout from a command is too long to fit on the screen. It means that if you type a Space the next screenful of typeout will be printed. If you are not interested, typing ^G will cause the rest of the output to be discarded. Typing any other key will discard the rest of the output and that key will be taken as the next keyboard input. Similarly, \fB--end--\fP signifies that typeout is complete; the same responses are accepted. .LP Sometimes you may wish to keep a permanent record of the typeout from these commands. To do this, set the variable \fIsend-typeout-to-buffer\fP to \fIon\fP. The typeout will then be put into a newly-created buffer, which you can arrange to save to a permanent file. .HH 2 "The Mode Line" .LP The Mode Line gives information about the window above it. There is a variable \fImode-line\fP which determines the layout of the mode line. For the example above, this was set as described in the section on customizing \s-2JOVE\s0. .LP \fB(C OvrWt)\fP shows that \fBC\fP is the name of the current \fImajor mode\fP and that the Over Write \fIminor mode\fP is turned on. .LP At any time, \s-2JOVE\s0 can be in only one major mode. Currently there are four major modes: \fIFundamental\fP, \fIText\fP, \fILisp\fP and \fIC\fP. New ones may be added in the future. .KS .LP The words which indicate which minor modes are turned on are: .DS \fBAbbrev\fP meaning that \fIWord Abbrev\fP mode is on; \fBAI\fP meaning that \fIAuto Indent\fP mode is on; \fBFill\fP meaning that \fIAuto Fill\fP mode is on; \fBOvrWt\fP meaning that \fIOver Write\fP mode is on; \fBRO\fP meaning that \fIRead Only\fP mode is on. \fBDBX\fP meaning that \fIDBX\fP mode is on. \fBDef\fP meaning that you are in the process of defining a keyboard macro. This is not really a mode, but it's useful to be reminded about it. .DE .KE The meanings of these modes are described later in this document. .LP \fB[Main:1]\fP shows that the name of the currently selected \fIbuffer\fP is \fBMain\fP and its number is \fB1\fP. Each buffer has its own name and holds a file being edited, which is how \s-2JOVE\s0 can hold several files at once. But at any given time you are editing only one of them, the \fIselected\fP buffer. When we speak of what some command does to \*Qthe buffer\*U, we are talking about the currently selected buffer. Multiple buffers make it easy to switch around between several files, and then it is very useful that the mode line tells you which one you are editing at any time. .LP \fB"hello.c"\fP shows the name of the file being edited in buffer \fBMain\fP. This is also the default filename for commands that expect a filename as input, as can be seen in the message line which follows. .LP The \(** in the mode line means that there are changes in the buffer that have not been saved in the file. If the buffer had not been changed since it was read in or last saved, there would be a minus instead. .LP Sometimes a file is changed ``behind \s-2JOVE\s0's back'': something changes the file (not the buffer) after it has been loaded into or saved from a buffer. This can be quite dangerous, so \s-2JOVE\s0 tests for this when it reads, writes, or finds the file. \s-2JOVE\s0 indicates the problem by displaying a # before the change indicator. It also asks for confirmation before performing the read or write. .LP \fB/home/foo\fP shows the name of the current directory. .LP \fB15.23\fP shows the time. .HH 2 "The Message Line" .LP The Message Line is reserved for printing messages and for accepting input from the user, such as filenames or search strings. When \s-2JOVE\s0 prompts for input, the cursor will temporarily appear on the bottom line, waiting for you to type a string. When you have finished typing your input, you can type a Return to send it to \s-2JOVE\s0. If you change your mind about running the command that is waiting for input, you can type ^G to abort, and you can then continue with your editing. .LP The message line and the list of filenames from the shell command that invoked \s-2JOVE\s0 are kept in a special buffer called \fIMinibuf\fP that can be edited like any other buffer. It is instructive to view the Minibuf in a window and to observe how it changes as parameters to commands are typed, and as the ^N and ^P functions are invoked. .HH 2 "Multiple Windows" .LP The window area, described above, can in fact be split into several \fIwindows\fP, each showing a different \fIbuffer\fP, or possibly different parts of the same buffer. Each window has its own mode line beneath it. The methods of creating and destroying windows will be described presently. .HH 1 "Input Conventions" .LP .HH 2 "Keyboard Usage" .LP In this manual, \*QControl\*U characters (that is, characters that are typed with the Control key and some other key at the same time) are represented by a circumflex (^) followed by another character. Thus, ^A is the character you get when you type A with the Control key (sometimes labeled CTRL) held down. Control characters in the \s-2JOVE\s0 buffer are displayed with a caret; thus, ^A for Control-A. DEL is displayed as ^?, ESC as ^[. .LP If the keyboard has extra keys, such as Function keys, Arrow keys and the like, then \s-2JOVE\s0 can be customized to use them. .HH 2 "The Character Set" .LP \s-2JOVE\s0 normally accepts the ASCII character set, with its 95 printing characters, including Space, (which appear on the screen as themselves) and its 33 Control characters (which, except for TAB, appear on the screen as, e.g. \*Q\^^C\*U). There are, however, two characters that may not appear. One is the NL character (because it is always converted into a \fIline-separator\fP, which is not quite a character) and the other is the NUL character (^@) which is used internally within \s-2JOVE\s0 to delimit lines (lines also have a maximum length, which is 1023 in most systems). .LP However, \s-2JOVE\s0 is \*Q8-bit clean\*U, so if your keyboard is able to produce all 256 8-bit characters, the extra ones will appear in octal (e.g. \*Q\^\e\^277\*U). Moreover, if your .UX system supports the \fILocale\fP facility (as most modern ones do), you may set the variable \fIlc-ctype\fP to \*QC\*U (the default, which corresponds to pure ASCII), or to \*Qiso_8859_1\*U (which corresponds to the Latin-1 alphabet with a total of 192 printing characters, all of which \s-2JOVE\s0 should be able to display), or to any other \fILocale\fP available on your system. The initial value of \fIlc-ctype\fP is taken from your LC_CTYPE environment variable, and otherwise defaults to \*QC\*U. With each \fILocale\fP \s-2JOVE\s0 will know which of the extra characters are upper-case letters, lower-case letters, etc. .HH 2 "Name Completion" .LP \s-2JOVE\s0 knows the names of all sorts of objects, such as \s-2JOVE\s0 Commands, \s-2JOVE\s0 Variables, Macros, Keymaps, Buffers and even (with some help from the .UX directories) Files. Since names must be entered often, \s-2JOVE\s0 has features to make this easier. .LP For many names, \s-2JOVE\s0 is willing to supply a default if you enter an empty answer. For example, when you are telling .IQ select-buffer which buffer to select, it will default to the previous buffer. When the prompt mentions a default, this is the value that will be used in place of an empty answer. .LP If the default isn't the name you want, name completion can help you enter a name. When you are prompted for a name, you need type only enough letters to make it unambiguous. At any point in the course of typing the name, you can type question mark (?) to see a list of all the relevant names which begin with the characters you have already typed; you can type Tab to have \s-2JOVE\s0 supply as many characters as it can; or you can type Return to terminate your input, or you can type Space to do both (supply the characters and terminate). For example, you are typing a Command and you have so far typed the letters \*Q\fIau\fP\*U and you then type a question mark, you will see the list .DS I auto-execute-command auto-execute-macro auto-fill-mode auto-indent-mode .DE If you type a Return at this point, \s-2JOVE\s0 will complain by ringing the bell, because the letters you have typed do not unambiguously specify a single command. But if you type Tab or Space, \s-2JOVE\s0 will supply the characters \*Q\fIto-\fP\*U because all commands that begin \*Q\fIau\fP\*U also begin \*Q\fIauto-\fP\*U. You could then type the letter \*Qf\*U followed by either Space or Return, and \s-2JOVE\s0 would complete and obey the entire command. .LP There are in fact two cases that can arise. .IP 1. .B The name you are typing is supposed to exist already .R (Commands, Variables and Keymaps always, Macros and Buffers except when you are trying to create a new one). .br If you type Return and what you have typed is not an unambiguous prefix of any name of the right kind, you will hear the bell; otherwise, it will complete what you have typed and then use it. Tab will complete what it can (you can then type Return if it looks right). Space will complete what it can and use it if it then matches. .IP 2. .B The name you are typing may be a new one .R (Files always, Macros (including the Keyboard Macro) and Buffers if you are allowed to create or rename one at that point). .br If you type Return, and it does not match any name, then it will take exactly what you have typed as a new name. Tab and Space try to complete as before. .LP If you type ^R, it will insert a name that might be useful. Even if this name is not the one you wish to enter, it is often convenient to edit this name into the desired one. The inserted name will be the default (if there is one), or the current value (if there is one). When \s-2JOVE\s0 is asking for a command or variable name, ^R will insert the last one named. .LP Buffers, keymaps, and macros are also numbered (if you type \*Q?\*U when first prompted, you will see the numbers as well as the possible names), and the number may be used in place of the name. .HH 3 "Filename Completion" .LP Whenever \s-2JOVE\s0 is prompting you for a filename, say in the \fIfind-file\fP command, things happen as just described and Return always accepts the name just as it is (because you might be wanting to create a new file with a name similar to that of an existing one). The variable \fIbad-filename-extensions\fP contains a list of words separated by spaces which are to be considered bad filename extensions; any filename with one of these extensions will not be counted in filename completion. The default includes \*Q.o\*U so if you have jove.c and jove.o in the same directory, the filename completion will not complain of an ambiguity because it will ignore jove.o. .LP When \s-2JOVE\s0 is prompting for a \fIfilename\fP, it has the following extra functions: .IP "^N" Insert the next filename from the argument list in the Minibuf. .IP "^P" Insert the previous filename from the argument list in the Minibuf. .HH 1 "Commands and Variables" .HH 2 "Commands" .LP \s-2JOVE\s0 uses \fIcommands\fP which have long names such as \fInext-line\fP. Then \fIkeys\fP such as ^N are connected to commands through the \fIcommand dispatch table\fP. When we say that ^N moves the cursor down a line, we are glossing over a distinction which is unimportant for ordinary use, but essential for simple customization: it is the command \fInext-line\fP which knows how to move down a line, and ^N moves down a line because it is connected to that command. The name for this connection is a \fIbinding\fP; we say that the key ^N \fIis bound to\fP the command \fInext-line\fP (or vice versa). \s-2JOVE\s0 has many bindings already \fIbuilt-in\fP, but you (or your system administrator) may also add your own, e.g. to make full use of any Function Keys provided on your particular keyboard. .LP Thus there may be three ways to refer to a command \(em by its full name, or by its standard (built-in) binding, or by your customized binding. Throughout this manual, we shall always use the standard bindings, followed by the full name (in italics). The standard bindings are designed to work on any ASCII keyboard, and can always be used so long as you (or your system administrator) have not actually changed them. But they are hard to remember, so you may well prefer to use your own, particularly if you always use the same terminal. See the section on Customization for more details. .LP Some terminals and modems cannot accept characters flat out at a reasonable baud rate, and therefore require the use of a flow control protocol using the characters ^S and ^Q (see the variable \fIallow-^S-and-^Q\fP). These characters cannot, therefore, be typed by the user. It has therefore been arranged that whenever a standard binding requires ^S (^Q) to be typed, a spare standard binding for that facility is also provided in which ^\^\e (^^) can be typed in its place. .LP Not all commands are bound to keys. To invoke a command that isn't bound to a key, you can type the sequence ESC\ X, which is bound to the command \fIexecute-named-command\fP. You will then be able to type the name of whatever command you want to execute on the message line. .HH 2 "Prefix Characters" .LP Because there are more command names than keys, \s-2JOVE\s0 allows a sequence of keystrokes to be bound to a command. Usually, the first character of the sequence will be one of the two \fIprefix characters\fP ^X or ESC. When you type such a prefix character \s-2JOVE\s0 will wait for the next character before deciding what to do. If you wait more than a second or so, \s-2JOVE\s0 will print the prefix character on the message line as a reminder and leave the cursor down there while you type the rest of the sequence. Many \s-2JOVE\s0 commands are bound to a 2-stroke sequence starting with ^X or ESC. How the next character is interpreted depends on which of them you typed. For example, if you type ESC followed by B you will run \fIbackward-word\fP, but if you type ^X followed by B you will run \fIselect-buffer\fP. .HH 2 "Variables" .LP Sometimes the description of a command will say \*Qto change this, set the variable \fImumble-foo\fP\*U. A variable is a name used to remember a value. \s-2JOVE\s0 contains variables which are there so that you can change them if you want to customize. The variable's value may be examined by some command, and changing that value makes the command behave differently. However, the facilities provided are pretty limited: you cannot invent new variables, or use them for other than their built-in purposes, and their values apply globally to all buffers irrespective of mode settings. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . set Sets the value of a variable. print Displays the current value of a variable. .TE .LP To set or change the value of a variable, type ESC\ X \fIset\fP . Values may be \fIon\fP of \fIoff\fP (for Boolean variables) or numbers (numeric variables) or strings (string variables). To inspect the current value of a variable, type ESC\ X print . .HH 2 "Giving Numeric Arguments to \s-2JOVE\s0 Commands" .LP Many \s-2JOVE\s0 commands can be given a \fInumeric argument\fP. Many commands interpret the argument as a repetition count (possibly negative). For example, giving an argument of ten to the ^F command (\fIforward-character\fP) moves forward ten characters. With these commands, no argument is equivalent to an argument of 1. .LP Some commands use the value of the argument, or even just its presence or absence, in highly idiosyncratic ways. For example, the commands which change the minor modes (such as \fIauto-fill-mode\fP) toggle the mode if there is no argument, but turn the more off with a zero argument, and on with any other argument. .LP The fundamental way of specifying an argument is to use ESC followed by the digits of the argument, for example, ESC\ 123 ESC\ G to go to line 123. Negative arguments are allowed, although not all commands know what to do with them. Unless otherwise stated, ESC\ Minus\ ... is equivalent to ESC\ Minus\ 1\ ...\ . Note that when giving arguments to \fIsourced\fP commands (described later under Customization) different rules apply. .LP Typing ^U means \*Qsupply an argument of 4\*U. Two such ^U's supply sixteen. Thus, ^U ^U ^F moves forward sixteen characters. This is a good way to move forward quickly, since it moves about 1/4 of a line on most terminals. Other useful combinations are: ^U ^U ^N (move down a good fraction of the screen), and ^U ^U ^O (make \*Qa lot\*U of blank lines). .LP There are other, terminal-dependent, ways of specifying arguments. They have the same effect but may be easier to type. If your terminal has a numeric keypad which sends something recognizably different from the ordinary digits, it is possible to customize \s-2JOVE\s0 to allow use of the numeric keypad for specifying arguments. .HH 2 "Help" .LP To get a list of keys and their associated commands, you type ESC\ X \fIdescribe-bindings\fP (warning: the list runs to many screenfuls; type Space to see the next one, or ^G when you have seen enough). If you want to describe a single key, ^X\ ? (\fIdescribe-key\fP) will work. A description of an individual command is available by using ESC\ ? (\fIdescribe-command\fP), and descriptions of variables by using ESC\ X \fIdescribe-variable\fP. If you can't remember the name of the thing you want to know about, ESC\ X \fIapropos\fP will tell you if a command or variable has a given string in its name. For example, ESC\ X \fIapropos describe\fP will list the names of the four describe commands just mentioned. .HH 1 "Basic Editing Commands" .LP .HH 2 "Inserting Text" .LP To insert printing characters into the text, just type them. All such printing characters you type are inserted into the text at the cursor (that is, at \fIpoint\fP), and the cursor moves forward. Any characters after the cursor move forward too. If the text in the buffer is FOOBAR, with the cursor before the B, then if you type XX you get FOOXXBAR, with the cursor still before the B. .LP To correct text you have just inserted, you can use DEL. DEL deletes the character \fIbefore\fP the cursor (not the one that the cursor is on top of or under; that is the character \fIafter\fP the cursor). The cursor and all characters after it move backwards. Therefore, if you typing a printing character and then type DEL, they cancel out. .LP To end a line and start typing a new one, type Return. Return operates by inserting a \fIline-separator\fP, so if you type Return in the middle of a line, you break the line in two. Because a line-separator behaves like a single character, you can type DEL at the beginning of a line to delete the line-separator and join it with the preceding line. Note that the line separator is \fBnot\fP a character (it is not the ASCII NL character, for example) so that you cannot include it in search or replace strings. .LP As a special case, if you type Return at the end of a line and there are two or more empty lines just below it, \s-2JOVE\s0 does not insert a line-separator but instead merely moves to the next (empty) line. This behavior is convenient when you want to add several lines of text in the middle of a buffer. You can use the ^O (\fInewline-and-backup\fP) command to \*Qopen\*U several empty lines at once; then you can insert the new text, filling up these empty lines. The advantage is that \s-2JOVE\s0 does not have to redraw the bottom part of the screen for each Return you type, as it would ordinarily. That \*Qredisplay\*U can be both slow and distracting. .LP If you add too many characters to one line, without breaking it with Return, the line will grow too long to display on one screen line. When this happens, \s-2JOVE\s0 puts an \*Q!\*U at the extreme right margin, and doesn't bother to display the rest of the line unless the cursor happens to be in it. The \*Q!\*U is not part of your text; conversely, even though you can't see the rest of your line, it is still there, and if you break the line, the \*Q!\*U will go away. .LP Direct insertion works for printing characters and space, but other characters act as editing commands and do not insert themselves. If you need to insert a control character, ESC, or DEL, you must first \fIquote\fP it by typing the ^Q command (\fIquoted-insert\fP) first, for example ^Q\ ^C to insert a genuine ^C. .HH 2 "Moving the Cursor" .LP To do more than insert characters, you have to know how to move the cursor. Here are the commands for doing that. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^A beginning-of-line Move to the beginning of the line. ^E end-of-line Move to the end of the line. ^F or \(-> forward-character Move forward over one character. ^B or \(<- backward-character Move backward over one character. ^N or \(da next-line T{ Move down one line, vertically. If you start in the middle of one line, you end in the middle of the next. T} ^P or \(ua previous-line Move up one line, vertically. ESC\ < beginning-of-file Move to the beginning of the entire buffer. ESC\ > end-of-file Move to the end of the entire buffer. ESC\ , beginning-of-window Move to the beginning of the visible window. ESC\ \fB.\fP end-of-window Move to the end of the visible window. ^Z scroll-up T{ Move the lines in the window upwards. If this brings the cursor outside of the window, it is automatically relocated. T} ESC\ Z scroll-down Move the lines in the window downwards. .TE Observe the use of the arrow keys (\(->, \(<-, \(da and \(ua) as alternatives for ^F, ^B, ^N and ^P. These should be available on just about any terminal. You (or your system administrator) may find it convenient to bind other Function Keys available on your keyboard to some of these commands, especially if those keys already have appropriate engravings on them. See the section on Customizing \s-2JOVE\s0. .HH 2 "Deleting Text" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . DEL delete-previous-character Delete the character before the cursor. ^D delete-next-character Delete the character after the cursor. ESC \e delete-white-space Delete spaces and tabs around point. ^X\ ^O delete-blank-lines Delete blank lines around the current line. .TE .LP You already know about the DEL command which deletes the character \fIbefore\fP the cursor. Another command, ^D, deletes the character \fIafter\fP the cursor, the one the cursor is \*Qon top of\*U or \*Qunderneath\*U, causing the rest of the text on the line to shift left. Line-separators act like normal characters when deleted, so if ^D is typed at the end of a line, that line and the next line are joined together. .LP The other delete commands are those which delete only formatting characters: spaces, tabs, and line-separators. ESC\ \e (\fIdelete-white-space\fP) deletes all the spaces and tab characters before and after point. ^X\ ^O (\fIdelete-blank-lines\fP) deletes all blank lines after the current line, and if the current line is blank deletes all the blank lines preceding the current line as well (leaving one blank line, the current line). .HH 2 "Files \(em Saving Your Work" .LP The commands above are sufficient for creating text in the \s-2JOVE\s0 buffer. The more advanced \s-2JOVE\s0 commands just make things easier. But to keep any text permanently you must put it into a \fIfile\fP. Files are the objects which .UX uses for storing data for a length of time. To tell \s-2JOVE\s0 to read text into a file, choose a filename, such as \fIfoo.bar\fP, and type ^X\ ^F\ \fIfoo.bar\fP (\fIfind-file\fP). This reads the file \fIfoo.bar\fP so that its contents appear in a new buffer on the screen for editing. Alternatively, type ^X\ ^R \fIfoo.bar\fP (\fIread-file\fP) to have the file appear in an existing buffer. You can make changes, and then save the file by typing ^X\ ^S (\fIsave-file\fP). This makes the changes permanent and actually changes the file \fIfoo.bar\fP. Until then, the changes are only inside \s-2JOVE\s0, and the file \fIfoo.bar\fP is not really changed. If the file \fIfoo.bar\fP does not exist, and you want to create it, read it as if it did exist. When you save your text with ^X\ ^S, the file will be created then. .HH 2 "Exiting and Pausing \(em Leaving \s-2JOVE\s0" .LP The command ^X\ ^C (\fIexit-jove\fP) will terminate the \s-2JOVE\s0 session and return to the shell. If there are modified but unsaved buffers, \s-2JOVE\s0 will ask you for confirmation, and you can abort the command, look at what buffers are modified but unsaved using ^X\ ^B (\fIlist-buffers\fP), save the valuable ones, and then exit. If what you want to do, on the other hand, is to \fIpreserve\fP the editing session but return to the shell temporarily you can (under most modern versions of .UX ) issue the command ESC\ S (\fIpause-jove\fP), do your .UX work within your shell, and then return to \s-2JOVE\s0 using the \fIfg\fP command to resume editing at the point where you paused. Alternatively, for this sort of situation, you might consider using an \fIinteractive shell\fP (that is, a shell in a \s-2JOVE\s0 window) which lets you use the editor to issue your .UX commands and manipulate their output, while never leaving the editor (the interactive shell feature is described later). .HH 1 "Kill and Yank (or Cut and Paste)" .LP Any editor needs a facility for dealing with large blocks of text \(em deleting them or moving them to other places. The usual terminology speaks of \*QCut\*U (to remove a block of text), \*QPaste\*U (to replace it somewhere else) and \*QCopy\*U (to copy it for subsequent pasting without removal from its original place). For historical reasons, editors based on \s-2EMACS\s0 use the terms Kill, Yank and Copy with essentially the same meanings, and we shall continue to do so in this manual. However, it may be sensible, if your keyboard has keys marked Cut, Paste and Copy, to bind appropriate Kill, Yank and Copy commands to them as part of your local customization. .HH 2 "The Mark and the Region" .LP In general, a command that processes an arbitrary part of the buffer must know where to start and where to stop. In \s-2JOVE\s0, such commands usually operate on the text between \fIpoint\fP and \fIthe mark\fP. On most terminals, the position of the mark is indicated by underlining. This body of text is called \fIthe region\fP. To specify a region, you set point at one end of it and mark at the other. It doesn't matter which one comes earlier in the text. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^@ set-mark Set the mark where point is. ^X\ ^X exchange-point-and-mark Interchange point and mark. pop-mark Move to the previous mark in the ring. .TE .LP The way to set the mark is with the ^@ command or (on some terminals) the ^Space command. They set the mark where point is. Then you can move point away, leaving the mark behind. When the mark is set, \*Q[Point pushed]\*U is printed on the message line. .LP For example, if you wish to convert part of the buffer to all upper-case, you can use the \fIcase-region-upper\fP command, which operates on the text in the region. You can first go to the beginning of the text to be capitalized, put the mark there, move to the other end, and then type ESC\ X \fIcase-region-upper\fP. Or, you can set the mark at the end of the text, move to the beginning, and then type the same thing. .LP On terminals with the requisite capabilities, the marked character is underlined. Otherwise, you have to remember where it is (the usual method is to set the mark and then use it soon). Alternatively, you can see where the mark is with the command ^X\ ^X which puts the mark where point was and point where the mark was. The extent of the region is unchanged, but the cursor and point are now at the previous location of the mark. .HH 2 "The Ring of Marks" .LP Aside from delimiting the region, the mark is also useful for remembering a spot that you may want to go back to. To make this feature more useful, \s-2JOVE\s0 remembers 16 previous locations of the mark. Most commands that set the mark push the old mark onto this stack. To return to a marked location, use ^U\ ^@ (equivalent to \fIpop-mark\fP). This moves point to where the mark was, and restores the mark from the stack of former marks. So repeated use of this command moves point to all of the old marks on the stack, one by one. Since the stack is actually a ring, enough uses of ^U\ ^@ bring point back to where it was originally. .LP Some commands whose primary purpose is to move point a great distance take advantage of the stack of marks to give you a way to undo the command. The best example is ESC\ < (\fIbeginning-of-file\fP), which moves to the beginning of the buffer. If there are more than 22 lines between the beginning of the buffer and point, ESC\ < sets the mark first, so that you can use ^U ^@ or ^X\ ^X to go back to where you were. You can change the number of lines from 22 since it is kept in the variable \fImark-threshold\fP. By setting it to 0, you can make these commands always set the mark and by setting it to a very large number you can make them never set it. If a command decides to set the mark, it prints the message [Point pushed]. .HH 2 "Killing and Moving Text" .LP The way of moving text with \s-2JOVE\s0 is to \fIkill\fP (cut) it, and \fIyank\fP (paste) it back again later in one or more places. This is very safe because the last several pieces of killed text are all remembered, and it is versatile because the many commands for killing syntactic units can also be used for moving those units. .HH 3 "Deletion and Killing" .LP Most commands which erase text from the buffer save it so that you can get it back if you change your mind, or you can copy it to other parts of the buffer (even to a different buffer). These commands are known as \fIkill\fP commands. The rest of the commands that erase text do not save it; they are known as \fIdelete\fP commands. The delete commands include ^D and DEL, which delete only one character at a time, and those commands that delete only spaces or line-separators. Commands that can destroy significant amounts of nontrivial data generally kill. A command's name and description will use the words \fIkill\fP or \fIdelete\fP to say which it does. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^D delete-next-character Delete next character. DEL delete-previous-character Delete previous character. ESC\ \e delete-white-space Delete spaces and tabs around point. ^X\ ^O delete-blank-lines Delete blank lines around the current line. ^K kill-to-end-of-line Kill rest of line or one or more lines. ^W kill-region Kill the region (from point to mark). ESC\ D kill-next-word Kill word. ESC\ DEL kill-previous-word Kill word backwards. ESC\ K kill-to-end-of-sentence Kill to end of sentence. ^X\ DEL kill-to-beginning-of-sentence Kill to beginning of sentence. ESC\ ^K kill-s-expression Kill from point to the end of an s-expression. .TE .HH 3 "Deletion" .LP The various delete commands have already been described. Actually, ^D and DEL aren't always \fIdelete\fP commands; if you give an argument, they \fIkill\fP instead. This prevents you from losing a great deal of text by typing a large argument to a ^D or DEL. .HH 3 "Killing (and Copying) the region, and Yanking it back again" .LP The commonest kill command is ^W (\fIkill-region\fP), which kills everything between point and the mark*. .FS *Often users switch this binding from ^W to ^X\ ^K because it is too easy to hit ^W accidentally. .FE With this command, you can kill and save contiguous characters, if you first set the mark at one end of them and then go to the other end. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^W kill-region Kill everything between point and mark. ESC\ W copy-region Save the region without killing. .TE .LP Yanking (un-killing) is getting back text which was killed. The usual way to move or copy text is to kill or copy it and then yank it one or more times. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^Y yank Yank (re-insert) the last killed text. ESC\ Y yank-pop Replace re-inserted killed text with the previously killed text. .TE .LP Killed text is pushed onto a \fIring buffer\fP called the \fIkill ring\fP that remembers the last sixteen blocks of text that were killed (why it is called a ring buffer will be explained below). The command ^Y (\fIyank\fP) reinserts the text of the most recent kill. The yanked text becomes the new region. Thus, a single ^Y undoes the ^W and vice versa. .LP If you wish to copy a block of text, you might want to use ESC\ W (\fIcopy-region\fP), which copies the region into the kill ring without removing it from the buffer. .LP There is only one kill ring shared among all the buffers. After reading a new file or selecting a new buffer, whatever was last killed in the previous file or buffer is still on top of the kill ring. This is important for moving text between buffers. .HH 3 "Other Kill commands" .LP Other syntactic units can be killed, too; words, with ESC\ DEL (\fIkill-previous-word\fP) and ESC\ D (\fIkill-next-word\fP); and sentences, with ESC\ K (\fIkill-to-end-of-sentence\fP) and ^X\ DEL (\fIkill-to-beginning-of-sentence\fP). .HH 3 "Killing by Lines" .LP Another kill command is the ^K command (\fIkill-to-end-of-line\fP). If issued at the beginning of a line, it kills all the text on the line, leaving it blank. If given in the middle of a line, it kills all the text up to the end of the line. If given on a line that is empty or contains only white space (blanks and tabs) the line disappears. If ^K is done at the end of a line, it joins that line and the next line. As a consequence, if you go to the front of a non-blank line and type two ^K's, the line disappears completely (but be careful, because one ^K is sufficient to remove an empty line). .LP In general, ^K kills from point up to the end of the line, unless it is at the end of a line, in which case it kills the line-separator following the line, thus merging the next line into the current one. Invisible spaces and tabs at the end of the line are ignored when deciding which case applies, so if point appears to be at the end of the line, you can be sure the line-separator will be killed. .LP ^K with an argument kills that many lines, including their line separators (whether the lines are empty or not). Without an argument, ^K behaves as described in the previous paragraph. ^U ^K kills four lines (but note that typing ^K four times would kill only 2 lines) .LP ^K with an argument of zero kills all the text before point on the current line. .HH 3 "Appending Kills" .LP Normally, each kill command pushes a new block onto the kill ring. However, two or more kill commands immediately in a row (without any other intervening commands) combine their text into a single entry on the ring, so that a single ^Y (\fIyank\fP) command gets it all back as it was before it was killed. This means that you don't have to kill all the text in one command; you can keep killing line after line, or word after word, until you have killed it all, and you can still get it all back at once. .LP Commands that kill forward from point add onto the end of the previously killed text. Commands that kill backward from point add onto the beginning. This way, any sequence of mixed forward and backward kill commands puts all the killed text into one entry without needing rearrangement. .LP Suppose, for example you have a line containing FOO\ BAR\ BAZ with the cursor at the start of BAR. Type ESC\ D (\fIkill-next-word\fP), then ESC\ DEL (\fIkill-previous-word\fP), then ESC\ F (\fIforward-word\fP) to put the cursor after BAZ, and Space to insert a space. Then type ^Y (\fIyank\fP) and your line will contain BAZ\ FOO\ BAR. .HH 2 "The Kill Ring" .LP To recover killed text that is no longer the most recent kill, you need the ESC\ Y (\fIyank-pop\fP) command. The ESC\ Y command can be used only immediately after a ^Y (\fIyank\fP) command or another ESC\ Y. It takes the yanked text inserted by the ^Y and replaces it with the text from an earlier kill. So, to recover the text of the next-to-the-last kill, you first use ^Y to recover the last kill, and then discard it by use of ESC\ Y to move back to the previous one. .LP You can think of all the last few kills as living on a ring. After a ^Y command, the text at the front of the ring is still present in the buffer. ESC\ Y \*Qrotates\*U the ring bringing the previous string of text to the front and this text replaces the other text in the buffer as well. Enough ESC\ Y commands can rotate any part of the ring to the front, so you can get at any killed text so long as it is recent enough to be still in the ring. Eventually the ring rotates all the way round and the most recently killed text comes to the front (and into the buffer) again. ESC\ Y with a negative argument rotates the ring backwards. .LP When the text you are looking for is brought into the buffer, you can stop doing ESC\ Y's and the text will stay there. It is really just a copy of what's at the front of the ring, so editing it does not change what's in the ring. And the ring, once rotated, stays rotated, so that doing another ^Y gets another copy of what you rotated to the front with ESC\ Y. .LP If you change your mind about yanking, ^W (\fIkill-region\fP) gets rid of the yanked text, even after any number of ESC\ Y's. .HH 1 "Searching and Replacing" .HH 2 "Searching" .LP The search commands are useful for finding and moving to arbitrary positions in the buffer in one swift motion. For example, if you just ran the spell program on a document and you want to correct some word, you can use the search commands to move directly to that word. There are two flavors of search: \fIstring search\fP and \fIincremental search\fP. The former is the default flavor \(em if you want to use incremental search you must rearrange the key bindings (see below). .HH 3 "Conventional Search" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^S or ^\^\e search-forward Search forward. ^R search-reverse Search backward. .TE .LP To search for the string \*QFOO\*U you type ^S\ FOO. If \s-2JOVE\s0 finds FOO it moves point to the end of it; otherwise \s-2JOVE\s0 prints an error message and leaves point unchanged. ^S searches forward from point so only occurrences of FOO after point are found. To search in the other direction use ^R. It is exactly the same as ^S except that it searches in the opposite direction, and if it finds the string it leaves point at the beginning of it, not at the end as in ^S. .LP While \s-2JOVE\s0 is searching it displays the search string on the message line. This is so you know what \s-2JOVE\s0 is doing. When the system is heavily loaded and editing in exceptionally large buffers, searches can take several (sometimes many) seconds. .LP \s-2JOVE\s0 remembers the last search string you used, so if you want to search for the same string again you can type ^S\ . If you mistyped the last search string, you can type ^S followed immediately by ^R (which is \fInot\fP the \fIsearch-reverse\fP command in this context) which inserts the default search string, and then you can fix it up. .LP Note that the precise interpretation of the search string is dependent on the variable \fImatch-regular-expressions\fP and is subject to the rules for \fIregular-expressions\fP to be described shortly. .HH 3 "Incremental Search" .LP This search command is unusual in that is is \fIincremental\fP; it begins to search before you have typed the complete search string. As you type in the search string, \s-2JOVE\s0 shows you where it would be found. When you have typed enough characters to identify the place you want, you can stop. Depending on what you will do next, you may or may not need to terminate the search explicitly with a Return. .LP To use the incremental searches, you first have to bind them to suitable keys, for example to ^S and ^R if you want all your searching to become incremental. To do this, type .IP .I ESC\ X bind-to-key i-search-forward ^S .br ESC\ X bind-to-key i-search-reverse ^R .R .LP The command to search is now ^S (\fIi-search-forward\fP). ^S reads in characters and positions the cursor at the first occurrence of the characters that you have typed so far. If you type ^S and then F, the cursor moves in the text just after the next \*QF\*U. Type an \*QO\*U, and see the cursor move to after the next \*QFO\*U. After another \*QO\*U, the cursor is after the next \*QFOO\*U. At the same time, \*QFOO\*U has echoed on the message line. .LP If you type a mistaken character, you can rub it out. After the FOO, typing a DEL makes the \*QO\*U disappear from the message line, leaving only \*QFO\*U. The cursor moves back in the buffer to the \*QFO\*U. Rubbing out the \*QO\*U and \*QF\*U moves the cursor back to where you started the search. .LP When you are satisfied with the place you have reached, you can type a Return, which stops searching, leaving the cursor where the search brought it. Also, any command not specially meaningful in searches stops the searching and is then executed. Thus, typing ^A would exit the search and then move to the beginning of the line. Return is necessary only if the next character you want to type is a printing character, DEL, Return, or another search command, since those are the characters that have special meanings inside the search. .LP Sometimes you search for \*QFOO\*U and find it, but not the one you hoped to find. Perhaps there is a second FOO after the one you just found. Then type another \*Q^S\*U and the cursor will find the next FOO. This can be done any number of times. If you overshoot, you can return to previous finds by rubbing out the \*Q^S\*Us. Note that, in this context, \*Q^S\*U (alternatively \*Q^\^\e\*U) is a built-in use of the ^S character and not another invocation of \fIi-search-forward\fP (which is why I have shown it in \*Qquotes\*U). .LP After you exit a search, you can search for the same string again by typing just ^S ^S: one ^S command to start the search and then another \*Q^S\*U to mean \*Qsearch again for the same string\*U. .LP If your string is not found at all, the message line says \*QFailing I-search\*U. The cursor is after the place where \s-2JOVE\s0 found as much of your string as it could. Thus, if you search for FOOT and there is no FOOT, you might see the cursor after the FOO in FOOL. At this point there are several things you can do. If your string was mistyped, you can rub some of it out and correct it. If you like the place you have found, you can type Return or some other \s-2JOVE\s0 command to \*Qaccept what the search offered\*U. Or you can type ^G, which undoes the search altogether and positions you back where you started the search. .LP You can also type ^R (\fIi-search-reverse\fP) at any time to start searching backwards. If a search fails because the place you started was too late in the file, you should do this. Repeated \*Q^R\*Us keep looking backward for more occurrences of the last search string. A \*Q^S\*U starts going forward again. \*Q^R\*Us can be rubbed out just like anything else. .LP Unlike conventional searching, incremental searching does not use the rules for regular-expressions. .HH 2 "Replacing" .LP In addition to the simple Replace operation which is like that found in most editors, there is a Query Replace operation which asks, for each occurrence of the pattern, whether to replace it or not. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ESC\ R replace-string T{ Replace every occurrence of the string from point to the end of the buffer. T} replace-in-region T{ Replace every occurrence of the string within the region. T} ESC\ Q query-replace-string T{ Replace occurrences of the string from point to the end of the buffer, but asking for confirmation before each replacement. T} .TE .HH 3 "Global replacement" .LP To replace every occurrence of FOO after point with BAR, you can do, ESC\ R FOOBAR (\fIreplace-string\fP). Replacement takes place only between point and the end of the buffer, so if you want to cover the whole buffer you must go to the beginning first. .LP Another alternative is to use \fIreplace-in-region\fP which is just like \fIreplace-string\fP except it searches only within the region. .HH 3 "Query Replace" .LP If you want to change only some of the occurrences of FOO, not all, then the global \fIreplace-string\fP is inappropriate; instead, use, e.g., ESC\ Q FOOBAR (\fIquery-replace-string\fP). This moves the cursor to each occurrence of FOO and waits for you to say whether to replace it with BAR. The things you can type when you are shown an occurrence of FOO are: .IP "Space or Y or y" "\w'DEL or BS or N or n11'u" to replace the FOO with BAR. .IP "Period" to replace this FOO and then stop. .IP "DEL or BS or N or n" to skip to the next FOO without replacing this one. .IP "^R\ or\ R\ or\ r" to enter a recursive editing level, in case the FOO needs to be edited rather than just replaced with a BAR. When you are done, exit the recursive editing level with ^X\ ^C (\fIexit-jove\fP) and the next FOO will be displayed. .IP "^W" to delete the FOO, and then start editing the buffer. When you are finished editing whatever is to replace the FOO, exit the recursive editing level with ^X\ ^C (\fIexit-jove\fP) and the \fIquery-replace\fP will continue at the next FOO. .IP "^U or U or u" move to the last replacement and undo all changes made on that line. .IP "! or P or p" to replace all remaining FOO's without asking, as in \fIreplace-string\fP. .IP "Return or Q or q" to stop without doing any more replacements. .IP "^L" redraw the screen. .HH 2 "Searching with Regular Expressions" .LP When we use the searching and replacement facilities described above, \s-2JOVE\s0 can search for patterns using \fIregular-expressions\fP. The handling of regular-expressions in \s-2JOVE\s0 is somewhat like that of \fIed(1)\fP or \fIvi(1)\fP, but with some notable additions. The precise behavior depends on the setting of the variable \fImatch-regular-expressions\fP. If this variable is \fIon\fP, we use true \fIregular-expressions\fP. If it is \fIoff\fP, we have just \fIsimple-expressions\fP. In what follows, the term \fIexpression\fP should be interpreted as simple-expression or regular-expression according to the state of that variable. .LP Another variable that affects searching is \fIcase-ignore-search\fP. If this variable is set to \fIon\fP then upper case and lower case letters are considered equal (except, of course, within regular-expressions such as [A\-Za\-z]). .LP Note that the rules which follow are complex, arbitrary, and different from those in other editors. Hence they may be changed significantly in future versions of \s-2JOVE\s0. .HH 3 "Simple Regular Expressions" .LP If the variable \fImatch-regular-expressions\fP is \fIoff\fP, the search pattern is interpreted as follows: .IP "^ (at the start of a pattern or sub-pattern) " 14n Matches the empty string at the beginning of a line. .IP "$ (at the end of a pattern or sub-pattern)" Matches the empty string at the end of a line. .IP "\e\^<" Matches the empty string at the beginning of a word. What makes up a word depends on the major mode of the buffer that you are searching in. In all modes a word is a contiguous sequence of characters which have some defined pattern, bounded by characters that don't fit that pattern or by the beginning or end of the line. The individual modes' word patterns are as follows: .RS .KS .IP "\fIFundamental\fP " 12n upper and lower case letters and digits. .IP "\fIText\fP" upper and lower case letters and digits plus apostrophe ('). .IP "\fIC\fP" upper and lower case letters and digits plus \*Q$\*U and \*Q_\*U (underscore). .IP "\fILisp\fP" upper and lower case letters and digits plus \*Q!\^$\^%\^&\^\(**\^+\^\-\^/\^:\^<\^=\^>\^?\^^\^_\^{\^|\^}\^\s+2~\s0\*U and Delete. .KE .RE .IP "\e\^> " 14n Matches the empty string at the end of a word. .IP "\e\^\fIc\fP" Matches the character \fIc\fP where \fIc\fP is not one of <, >, (, ), {, } or |. In particular, \e\^^, \e\^$ and \e\^\e match the characters ^, $ and \e\^. When full regular-expressions are in use, \e\^\fB.\fP, \e\^\(** and \e\^[ will also be required. .IP "\fIc\fP" Matches the character \fIc\fP where \fIc\fP is not \e or ^ (at the start of a pattern) or $ (at the end of a pattern) (plus a few further things if \fImatch-regular-expressions\fP is \fIon\fP). .IP "\e\^{\fIc1...cN\fP\^\e}" Matches whatever the sequence of regular-expressions \fIc1..cN\fP would have matched. Note that full regular-expression capability (even the \e| construct described below) is provided within \e\^{...\e} whatever the setting of the variable \fImatch-regular-expressions\fP. \e\^{...\e} provides a grouping construct like parentheses in algebraic expressions. Thus \*Qaa\^\e\^{xx\^\e|yy\e}bb\*U searches for \*Qaaxxbb\*U or \*Qaayybb\*U. .IP "\e\^(\fIc1..cN\fP\^\e)" Matches whatever the sequence of expressions \fIc1..cN\fP would have matched, where the expressions are any of those described above (and also the additional full regular-expressions if \fImatch-regular-expressions\fP is \fIon\fP). This is used to tag part of the search text for later reference via \e\^\fBn\fP (see below). \e\^(\fIc1..cN\fP\^\e) patterns may be nested. Observe that use of the \e| construct (see below) directly within a \e\^(...\e) is precluded. .IP "\e\^\fIn\fP" Matches the \fIn\fP'th \e\^(\fIc1..cN\fP\^\e) pattern where \fIn\fP is between 1 and 9. The \e\^(\fIc1..cN\fP\^\e) patterns are numbered by counting the \e\^( sequences starting from the beginning of the search pattern, resetting to 1 (or to the value at the start of an enclosing \e\^{...\e}) whenever a \e| is encountered. To avoid confusion in the counting, it is required that each alternative (separated by \e|) within a \e\^{...\e} should contain the same number of \e\^(...\e)s. For example, the search pattern \*Q^\^\e\^(\^\e\^{ab\^\e|cd\^\e}\^\e)\^\e1$\*U searches for all non-empty lines which contain just \*Qabab\*U or \*Qcdcd\*U (but not \*Qabcd\*U). It is an error in the search pattern to reference a \e\^(\fIc1..cN\fP\^\e) pattern that follows the occurrence of \e\^\fIn\fP. .IP "\fIc1..cN\fP" Matches the longest string matched by \fIc1\fP, followed by the longest string matched by \fIc2\fP, and so on. The expressions \fIc1..cN\fP are any of those described above (and also the additional full regular-expressions if \fImatch-regular-expressions\fP is \fIon\fP). .IP "\fIc1..cN\fP\^\e|\fId1..dN\fP" Matches the longest string matched by \fIc1..cN\fP, if any, and otherwise the longest string matched by \fId1..dN\fP. Multiple \e| sequences may be used to indicate more alternatives. The sequences \fIc1..cN\fP and \fId1..dN\fP are any of those described above, which means that \e| has lower precedence than any of the other operators. Each alternative must have the same number of \e\^(...\e) groups, as already explained. Thus, \*Q\^\e\^\*U matches any word beginning with \*Qfoo\*U, any occurrence of the string \*Qbar\*U, or any word ending in \*Qbaz\*U. .LP In the replacement string: .IP "\e\^\fIn\fP" 14n Is replaced with the characters matched by the \fIn\fP'th \e\^(\fIc1..cN\fP\^\e) in the search pattern where \fIn\fP is between 1 and 9. For example, one could replace \*Q\e\^<\^\e\^(\^\e\^{FOO\^\e|BAR\^\e|BAZ\^\e}\^\e)\^\e\^>\*U with \*Q[\^\e1]\*U to enclose every occurrence of the words FOO, BAR and BAZ within [...]. .IP "\e\^0" Is replaced with the characters matched by the entire search pattern. .IP "\e\^\fIc\fP" Inserts the character \fIc\fP where \fIc\fP is not a digit. .IP "\fIc\fP" Inserts the character \fIc\fP where \fIc\fP is not \e\^. .HH 3 "Full Regular Expressions" .LP If the variable \fImatch-regular-expressions\fP is \fIon\fP, the following additional special matching rules are used. Observe that special meanings now attach to the characters \fB.\fP, \(** and [, which can therefore no longer stand for themselves. .LP In the search pattern: .IP "\fIc\fP " 14n Matches the character \fIc\fP where \fIc\fP is not one of \fB.\fP\^, \(**, [, \e\^, ^ (at the start of a line) or $ (at the end of a line). .IP "\fB.\fP" Matches any character, but not a line-separator. .IP "[\fIc1..cN\fP]" Matches any of the characters in the sequence of characters \fIc1..cN\fP provided circumflex (^) is not the first character of the sequence (see below). The only special characters recognized while parsing the sequence are \*Q]\*U, \*Q\-\*U and \*Q\^\e\*U. All may be represented by escaping them with a backslash (\^\e\^): \*Q\^\e\^]\*U, \*Q\^\e\^\-\*U, \*Q\^\e\^\e\*U. Ranges of characters may be indicated by \fIa\fP\-\fIb\fP where \fIa\fP is the first character of the range and \fIb\fP is the last. The special meaning of \- is lost if it appears as the first or last character of the sequence. The special meaning of ] is lost if it appears as the first character of the sequence. .IP "[^\fIc1..cN\fP]" Matches any character except those contained in the sequence of characters \fIc1..cN\fP. The circumflex (^) is not special except immediately following the left bracket. .IP "\fIc\fP\(**" Matches zero or more occurrences of the expression \fIc\fP. The expression \fIc\fP may be any of the expressions covered above except for ^ and $ (which match null strings), \e\^(\fIc1..cN\fP\^\e) and \fIc1..cN\fP\^\e|\fId1..dN\fP (which would not work), and \e\^{\fIc1...cN\fP\^\e} (arbitrarily forbidden). .HH 1 "Commands for English Text" .LP \s-2JOVE\s0 has many commands that work on the basic units of English text: words, sentences and paragraphs. .HH 2 "Word Commands" .LP \s-2JOVE\s0 has commands for moving over or operating on words. By convention, they are all ESC commands. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ESC\ F forward-word Move Forward over a word. ESC\ B backward-word Move Backward over a word. ESC\ D kill-next-word Kill forward to the end of a word. ESC\ DEL kill-previous-word Kill backward to the beginning of a word. .TE .LP Notice how these commands form a group that parallels the character-based commands, ^F, ^B, ^D, and DEL. .LP The commands ESC\ F and ESC\ B move forward and backward over words. They are thus analogous to ^F and ^B, which move over single characters. Like their Control- analogues, ESC\ F and ESC\ B move over several words if given an argument (and in the opposite direction with negative arguments). Forward motion stops right after the last letter of the word; backward motion stops right before the first letter. .LP ESC\ D kills the word after point. To be precise, it kills everything from point to the place ESC\ F would move to. Thus, if point is in the middle of a word, only the part after point is killed. If some punctuation comes after point, and before the next word, it is killed along with the word. If you wish to kill only the next word but not the punctuation, simply do ESC\ F to get to the end, and kill the word backwards with ESC\ DEL. ESC\ D takes arguments just like ESC\ F. .LP ESC\ DEL kills the word before point. It kills everything from point back to where ESC\ B would move to. If point is after the space in \*QFOO, BAR\*U, then \*QFOO, \*U is killed. If you wish to kill just \*QFOO\*U, then do an ESC\ B and an ESC\ D instead of an ESC\ DEL. .LP Note that the term \*Qword\*U in all of these commands refers simply to a sequence of upper and lower case letters and digits. It is not dependent on the major mode of the buffer as was the case with regular-expressions involving \e\^< and \e\^>. Thus it will require two uses of ESC\ D to remove a word such as \*Qisn't\*U, even if the major mode is Text mode. .HH 2 "Sentence Commands" .LP The \s-2JOVE\s0 commands for manipulating sentences and paragraphs are mostly ESC commands, so as to resemble the word-handling commands. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ESC\ A backward-sentence Move back to the beginning of the sentence. ESC\ E forward-sentence Move forward to the end of the sentence. ESC\ K kill-to-end-of-sentence Kill forward to the end of the sentence. ^X\ DEL kill-to-beginning-of-sentence Kill back to the beginning of the sentence. .TE .LP The commands ESC\ A and ESC\ E move to the beginning and end of the current sentence, respectively. They were chosen to resemble ^A and ^E, which move to the beginning and end of a line. Unlike them, ESC\ A and ESC\ E if repeated or given numeric arguments move over successive sentences. \s-2JOVE\s0 considers a sentence to end wherever there is a \*Q.\*U, \*Q?\*U, or \*Q!\*U followed by the end of a line or by one or more spaces. Neither ESC\ A nor ESC\ E moves past the end of the line or the spaces which delimit the sentence. .LP Just as ^A and ^E have a kill command, ^K, to go with them, so ESC\ A and ESC\ E have a corresponding kill command ESC\ K which kills from point to the end of the sentence. With minus one as an argument it kills back to the beginning of the sentence. Positive arguments serve as a repeat count. .LP There is a special command ^X\ DEL for killing back to the beginning of a sentence, because this is useful when you change your mind in the middle of composing text. .HH 2 "Paragraph Commands" .LP The \s-2JOVE\s0 commands for handling paragraphs are .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . backward-paragraph Move back to the start of the previous paragraph. ESC\ ] forward-paragraph Move forward to the end of the next paragraph. .TE .LP Note that \*QESC\ [\*U is not bound to \fIbackward-paragraph\fP, as might have been expected, on most (i.e. ANSI-compliant) terminals because that sequence is used as a prefix for codes generated by the Function Keys. .LP \fIBackward-paragraph\fP moves to the beginning of the current or previous paragraph, while \fIforward-paragraph\fP moves to the end of the current or next paragraph. Paragraphs are delimited by lines of differing indent, or lines with text formatter commands, or blank lines. \s-2JOVE\s0 knows how to deal with most indented paragraphs correctly, although it can get confused by one- or two-line paragraphs delimited only by indentation. .HH 2 "Text Indentation Commands" .LP .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . Tab handle-tab Indent \*Qappropriately\*U in a mode-dependent fashion. Linefeed newline-and-indent T{ Is the same as Return, except it copies the indent of the line you just left. T} ESC\ M first-non-blank Moves to the line's first non-blank character. .TE .LP The way to request indentation is with the Tab command. Its precise effect depends on the major mode. In \fIText\fP mode, it indents to the next tab stop (as determined by the variable \fItab-width\fP, whose default value is 8). In \fIC\fP mode or \fILisp\fP mode, it indents to the \*Qright\*U position for those programs (see later). .LP To move over the indentation on a line, do ESC\ M (\fIfirst-non-blank\fP). This command, given anywhere on a line, positions the cursor at the first non-blank, non-tab character on the line. .HH 2 "Text Filling" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . auto-fill-mode Toggle the minor mode \fIauto fill\fP. ESC\ J fill-paragraph Refill the paragraph containing the cursor. fill-region Refill the region. fill-comment Refill a comment, depending on the major mode. left-margin-here Sets the variable \fIleft-margin\fP from point. right-margin-here Sets the variable \fIright-margin\fP from point. .TE .LP \fIAuto Fill\fP mode is a minor mode that causes text to be \fIfilled\fP (broken up into lines that fit in a specified width) automatically as you type it in. If you alter existing text so that it is no longer properly filled, \s-2JOVE\s0 can fill it again if you ask. .LP Entering \fIAuto Fill\fP mode is done with ESC\ X \fIauto-fill-mode\fP. From then on, lines are broken automatically at spaces when they get longer than the desired width. To leave \fIAuto Fill\fP mode, once again execute ESC\ X \fIauto-fill-mode\fP. When \fIAuto Fill\fP mode is in effect, the word \fBFill\fP appears in the mode line. .LP If you edit the middle of a paragraph, it may no longer be filled correctly. To refill a paragraph, use the command ESC\ J (\fIfill-paragraph\fP). It causes the paragraph that point is inside to be filled. All the line breaks are removed and new ones inserted where necessary. Similarly, \fIfill-region\fP may be used to refill a region other than a paragraph. The special command \fIfill-comment\fP is only meaningful in those major modes, currently C mode and Lisp mode, which support it. .LP The maximum line width for filling is in the variable \fIright-margin\fP. Both ESC\ J and auto-fill make sure that no line exceeds this width. The value of \fIright-margin\fP is initially 78. .LP Normally ESC\ J figures out the indent of the paragraph and uses that same indent when filling. If you want to force some other indent for a paragraph, you set \fIleft-margin\fP to the new position and type ^U\ ESC\ J, since \fIfill-paragraph\fP uses the value of \fIleft-margin\fP when supplied with a numeric argument. .LP If you know where you want to set the variable \fIright-margin\fP but you don't know the actual value, move to where you want to set the value and use the \fIright-margin-here\fP command. \fIleft-margin-here\fP does the same for the \fIleft-margin\fP variable. .HH 2 "Case Conversion Commands" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ESC\ L case-word-lower Convert the following word to lower case. ESC\ U case-word-upper Convert the following word to upper case. ESC\ C case-word-capitalize Capitalize the following word. case-character-capitalize Capitalize the character after point. case-region-lower Convert the region to lower case. case-region-upper Convert the region to upper case. .TE .LP The word conversion commands are most useful. ESC\ L converts the word after point to lower case, moving past it. Thus, successive ESC\ L's convert successive words. ESC\ U converts to all capitals instead, while ESC\ C puts the first letter of the word into upper case and the rest into lower case. All these commands convert several words at once if given an argument. They are especially convenient for converting a large amount of text from all upper case to mixed case, because you can move through the text using ESC\ L, ESC\ U or ESC\ C on each word as appropriate. .LP When given a negative argument, the word case conversion commands apply to the appropriate number of words before point, but do not move point. This is convenient when you have just typed a word in the wrong case. You can give the case conversion command and continue typing. .LP If a word case conversion command is given in the middle of a word, it applies only to the part of the word which follows the cursor, treating it as a whole word. .HH 2 "Commands for Fixing Typos" .LP In this section we summarize the commands that are especially useful for the times when you catch a mistake in your text just after you have made it, or you change your mind while composing text on a line. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . DEL delete-previous-character Delete last character. ESC\ DEL kill-previous-word Kill last word. ^X\ DEL kill-to-beginning-of-sentence Kill to beginning of sentence. ^T transpose-characters Transpose two characters. ^X\ ^T transpose-lines Transpose two lines. ESC\ Minus ESC\ L Convert last word to lower case. ESC\ Minus ESC\ U Convert last word to upper case. ESC\ Minus ESC\ C Convert last word to lower case with initial capital. .TE .LP .HH 3 "Killing Your Mistakes" .LP The DEL command is the most important correction command. When used among printing (self-inserting) characters, it can be thought of as canceling the last character typed. .LP When your mistake is longer than a couple of characters, it might be more convenient to use ESC\ DEL or ^X\ DEL. ^X\ DEL is particularly useful when you are thinking of what to write as you type it, in case you change your mind about phrasing. ESC\ DEL and ^X\ DEL save the killed text for subsequent yanking. .LP ESC\ DEL is often useful even when you have typed only a few characters wrong, if you know you are confused in your typing and aren't sure what you typed. At such a time, you cannot correct with DEL except by looking at the screen to see what you did. It requires less thought to kill the whole word and start over again. .HH 3 "Transposition" .LP The common error of transposing two characters can be fixed with the ^T (\fItranspose-characters\fP) command. Normally, ^T transposes the two characters on either side of the cursor and moves the cursor forward one character. Repeating the command several times \*Qdrags\*U a character to the right. When given at the end of a line, rather than switching the last character of the line with the line-separator, which would be useless, ^T transposes the last two characters on the line. So, if you catch your transposition error right away, you can fix it with just a ^T. If you don't catch it so quickly, you must move the cursor back to between the two characters. .LP To transpose two lines, use the ^X\ ^T (\fItranspose-lines\fP) command. The line containing the cursor is exchanged with the line above it; the cursor is left at the beginning of the line following its original position. .HH 2 "Checking and Correcting Spelling" .LP When you write a paper, you should correct its spelling at some point close to finishing it. To correct the entire buffer, do ESC\ X \fIspell-buffer\fP. This invokes the .UX .I spell program, which prints a list of all the misspelled words. \s-2JOVE\s0 catches the list and places it in a \s-2JOVE\s0 buffer called \fBSpell\fP. You now edit the \fBSpell\fP buffer (technically, you are in a recursive edit at this point) by deleting from that buffer any words that aren't really errors. Next, type ^X\ ^C (\fIexit-jove\fP) to escape from the recursive edit, and \s-2JOVE\s0 now positions you at the first misspelled word in the original buffer. Correct that mistake with the usual editor commands. Then you can go forward to each other misspelled word with ^X\ ^N (\fInext-error\fP) or backward with ^X\ ^P (\fIprevious-error\fP). If, in the course of editing a mistake, you get completely lost, the command \fIcurrent-error\fP will put you back at the error you were supposed to be correcting. .HH 1 "Buffers" .LP When we speak of \*Qthe buffer\*U, which contains the text you are editing, we may have given the impression that there is only one. In fact, there may be many of them, each with its own body of text. At any time only one buffer can be \fIcurrent\fP and available for editing, but it is easy to switch to a different one. Each buffer individually remembers which file it contains, what modes are in effect, and whether there are any changes that need saving. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ B select-buffer Select or create a buffer. ^X\ ^B list-buffers List the existing buffers. ^X\ K delete-buffer Delete the contents of a buffer and destroy it. erase-buffer Delete the contents of a buffer. kill-some-buffers Destroy unwanted buffers. rename-buffer Rename the selected buffer. buffer-position Report the position of point within the buffer. ESC\ \s+2~\s0 make-buffer-unmodified Tell \s-2JOVE\s0 to forget that the buffer has been changed. ^X\ ^F find-file Read a file into its own buffer. ^X\ ^S or ^X\ \e save-file Save the selected buffer. ^X\ ^M write-modified-files Save all modified buffers. .TE .LP Each buffer in \s-2JOVE\s0 has a single name which normally doesn't change. A buffer's name can be any length. The name of the currently selected buffer and the name of the file contained in it are visible in the mode line of any window displaying that buffer. A newly started \s-2JOVE\s0 has only one buffer, named \fBMain\fP, unless you specified files to edit in the shell command that started \s-2JOVE\s0. .HH 2 "Creating and Selecting Buffers" .LP To create a new buffer, you need only think of a name for it (say, FOO) and then type ^X\ B FOO (\fIselect-buffer\fP). This makes a new, empty buffer (if one by that name didn't exist previously) and selects it for editing. The new buffer does not contain any file, so if you try to save it you will be asked for the filename to use. Each buffer has its own major mode; the new buffer's major mode is Text mode by default. .LP To return to buffer FOO later after having switched to another, the same command ^X\ B FOO is used, since ^X\ B can tell whether a buffer named FOO exists already or not. Just ^X\ B reselects the previous buffer. Repeated ^X\ B's alternate between the last two buffers selected. .HH 2 "Using Existing Buffers" .LP To get a list of all the buffers that exist, type ^X\ ^B (\fIlist-buffers\fP). Each buffer's type, name, and contained filename is printed. An asterisk before the buffer name indicates that there are changes that have not yet been saved. The number that appears at the beginning of a line in a ^X\ ^B listing is that buffer's \fIbuffer number\fP. You can select a buffer by typing its number in place of its name. If a buffer with that number doesn't already exist, a new buffer is created with that number as its name. .LP If several buffers have modified text in them, you can save them with ^X\ ^M (\fIwrite-modified-files\fP). This finds all the buffers that need saving and then saves them. Saving the buffers this way is much easier and more efficient (but more dangerous) than selecting each one and typing ^X\ ^S (\fIsave-file\fP). If you give ^X\ ^M an argument, \s-2JOVE\s0 will ask for confirmation before saving each buffer. .LP ESC\ X \fIrename-buffer\fP changes the name of the selected buffer. .LP ESC\ X \fIerase-buffer\fP erases the contents of without destroying it entirely. .LP ESC\ X \fIbuffer-position\fP reports the position of point within the selected buffer, both as lines/total-lines, chars/total-chars, and as a percentage. .LP Sometimes you will change a buffer by accident. Even if you undo the effect of the change by editing, \s-2JOVE\s0 still knows that \*Qthe buffer has been changed\*U. You can tell \s-2JOVE\s0 to pretend that there have been no changes with the ESC\ \s+2~\s0 command (\fImake-buffer-unmodified\fP). This command simply clears the \*Qmodified\*U flag which says that the buffer contains changes which need to be saved. Even if the buffer really \fIis\fP changed \s-2JOVE\s0 will still act as if it were not. .HH 3 "Killing Buffers" .LP After you use a \s-2JOVE\s0 for a while, it may fill up with buffers which you no longer need. Eventually you can reach a point where trying to create any more results in an \*Qout of memory\*U or \*Qout of lines\*U error. When this happens you will want to destroy some buffers with the ^X\ K (\fIdelete-buffer\fP) command. You can destroy the buffer FOO by doing ^X\ K FOO. If you type ^X\ K \s-2JOVE\s0 will kill the previously selected buffer. If you try to kill a buffer that needs saving \s-2JOVE\s0 will ask you to confirm it. .LP If you need to kill several buffers, use the command \fIkill-some-buffers\fP. This prompts you with the name of each buffer and asks for confirmation before killing it. .HH 1 "File Handling" .LP The basic unit of stored data is the file. Each program, each document, lives usually in its own file. To edit a program or document, the file that contains it must first be brought into a buffer, either an existing one (\fIvisit-file\fP) or one created specifically for that file (\fIfind-file\fP). To make your changes to the file permanent on disk, you must \fIsave\fP the file. .HH 2 "Reading Files" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ ^F find-file Read a file into its own buffer. ^X\ ^V visit-file Visit a file. ^X\ ^R visit-file An alternative to ^X\ ^V. ^X\ ^I insert-file Insert a file at point. .TE .LP \s-2JOVE\s0 remembers the name of the file that is contained in each buffer (remember the ^X\ ^B (\fIlist-buffers\fP) command). The name of the buffer is visible in its mode line together with the name of its file. .LP You can read a file into its own newly created buffer by typing ^X\ ^F (\fIfind-file\fP), followed by the filename. The name of the new buffer will be the last element of the file's pathname. You can abort the command by typing ^G, or edit the filename with any of the standard \s-2JOVE\s0 commands (e.g., ^A, ^E, ^F, ESC\ F, ESC\ DEL). If the filename you wish to visit is similar to the filename in the current mode line (the default filename), you can type ^R to insert the default and then edit it. For more about this and other special methods of constructing filenames, see the sections on .IQ "The Message Line" and .IQ "Name Completion" earlier in this manual. When you are satisfied type Return, and the new file's text will appear on the screen, and its name in the mode line. .LP The ^F in ^X\ ^F stands for \*QFind\*U, because if the specified file already resides in some buffer, that buffer is simply reselected. So you need not remember whether you have brought the file in already or not. A buffer created by ^X\ ^F can be reselected later with ^X\ B or ^X\ ^F, whichever you find more convenient. .LP \fIVisiting\fP a file means copying its contents into an existing buffer so that you can edit them. To visit a file, use the command ^X\ ^V or ^X\ ^R (\fIvisit-file\fP), followed by the filename. The name of the new file will appear in the mode line but the name of the buffer will be unchanged. .LP If you alter one file and then visit another in the same buffer, \s-2JOVE\s0 offers to save the old one. If you answer YES (or y), the old file is saved; if you answer NO (or n), all the changes you have made to it since the last save are lost. You should not type ahead after a file visiting command, because your type-ahead might answer an unexpected question in a way that you would regret. .LP ^X\ ^I (\fIinsert-file\fP) followed by a filename reads the file and inserts it into the buffer at point, leaving point before the file contents and the mark at their end. .LP The changes you make with \s-2JOVE\s0 are made in a copy inside \s-2JOVE\s0. The file itself is not changed. The changed text is not permanent until you \fIsave\fP it in a file. The first time you change the text, an asterisk appears in the mode line; this indicates that the text contains fresh changes which will be lost unless you save them. .LP What if you want to create a file? Just read it with \fIfind-file\fP or \fIvisit-file\fP. \s-2JOVE\s0 prints \fI(New file)\fP but aside from that behaves as if you had read an existing empty file. If you make any changes and save them, the file is created then. If you read a nonexistent file unintentionally (because you typed the wrong filename), go ahead and read the file you meant. The unwanted file will not have been created. .HH 2 "Writing files" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ ^S or ^X\ ^\^\e save-file Save the file in the selected buffer. ^X\ ^W write-file Write the selected buffer to a different file. write-region Write the region to the specified file. append-region Append the region to the specified file. .TE .LP If you wish to save the file and make your changes permanent, type ^X\ ^S. After the save is finished, ^X\ ^S prints the filename and the number of characters and lines that it wrote to the file. If there are no changes to save (no asterisk in the mode line), the file is not saved; otherwise the changes are saved and the asterisk in the mode line disappears. .LP If \s-2JOVE\s0 is about to save a file and sees that the date of the version on disk does not match what \s-2JOVE\s0 last read or wrote, \s-2JOVE\s0 notifies you of this fact, and asks what to do, because this probably means that something is wrong. For example, somebody else may have been editing the same file. If this is so, there is a good chance that your work or his work will be lost if you don't take the proper steps. You should first find out exactly what is going on. If you determine that somebody else has modified the file, save your file under a different filename and then DIFF the two files to merge the two sets of changes. (The \*Qpatch\*U command is useful for applying the results of context diffs directly). Also get in touch with the other person so that the files don't diverge any further. .LP ^X\ ^W (\fIwrite-file\fP) writes the contents of the buffer into the file , changing the name of the file recorded in the mode line accordingly. It can be thought of as a way of \*Qchanging the name\*U of the file in the buffer. Unlike ^X\ ^S, \fIwrite-file\fP saves even if the buffer has not been changed. .LP ESC\ X \fIwrite-region\fP writes the region (the text between point and mark) to the specified file. It does not change the buffer's filename. .LP ESC\ X \fIappend-region\fP appends the region to . The text is added to the end of . .HH 2 "How to Undo Drastic Changes to a File" .LP If you have made several extensive changes to a file and then change your mind about them, and you haven't yet saved them, you can get rid of them by reading in the previous version of the file. You can do this with the ^X\ ^V (\fIvisit-file\fP) command, to visit the unsaved version of the file. Remember to tell it not to save your existing changes when it asks. .HH 1 "Windows .HH 2 "Multiple Windows" .LP \s-2JOVE\s0 allows you to split the screen into two or more \fIwindows\fP and use them to display parts of different buffers, or different parts of the same buffer. .KS .TS center; = || L1 || L . #define\ getchar()\ \ \ \ getc(stdin) #define\ putchar(x)\ \ \ putc((x), stdout) <\ first Window _ \fBJOVE\ (C RO)\ \ \ [stdio.h:1]\ \ "/usr/include/stdio.h"\ \ \-\-\fP <\ the Mode Line _ { \ \ \ \ printf("Hello world!\^\e\^n"); \ \ \ \ return 0; <\ second Window }\^\(sq _ \fBJOVE\ (C OvrWt)\ \ \ [Main:1]\ \ "aloha.c"\ \ \-\-\ \ /home/foo\fP <\ the Mode Line _ [Point pushed] <\ the Message Line = .TE .KE .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ 2 split-current-window Divide the active window into two smaller ones. ^X\ 1 delete-other-windows Delete all windows but the current one. ^X\ D delete-current-window Delete the active window. ^X\ N next-window Switch to the next window. ^X\ P previous-window Switch to the previous window. ^X\ O previous-window Same as ^X\ P. ^X\ ^ grow-window Make this window bigger. shrink-window Make this window smaller. ESC\ ^V page-next-window Scroll the other window. ^X\ 4 window-find Combination window command. .TE .LP When using \fImultiple window\fP mode, the window portion of the screen is divided into \fIwindows\fP, which can display different pieces of text. Each window can display different buffers, or different parts of the same buffer. Only one of the windows is \fIactive\fP, viz. the window which the cursor is in. Editing normally takes place in that window alone. To edit in another window, you would give a command to move the cursor to the other window, and then edit there. .LP Each window includes a mode line for the buffer it is displaying. This is useful to keep track of which window corresponds with which buffer and which file. In addition, the mode line serves as a separator between windows. Normally, the variable \fImode-line-should-standout\fP is \fIon\fP so that \s-2JOVE\s0 displays the mode-line in reverse video (assuming your particular terminal has the reverse video capability). However, if the variable .I scroll-bar is also \fIon\fP, a portion of the mode line is left clear to indicate how the window is located within the buffer. .LP The command ^X\ 2 (\fIsplit-current-window\fP) divides the active window into two. A new mode line appears across the middle of the original window, dividing its display area into two halves. Both windows contain the same buffer and display the same position in it, namely where point was at the time you issued the command. The cursor moves to the second window. .LP To return to viewing only one window, use the command ^X\ 1 (\fIdelete-other-windows\fP). The active window expands to fill the whole screen, and the other windows disappear until the next ^X\ 2. (The buffers and their contents are unaffected by any of the window operations). .LP While there is more than one window, you can use ^X\ N (\fInext-window\fP) to switch to the next window, and ^X\ P (\fIprevious-window\fP) to switch to the previous one. If you are in the bottom window and you type ^X\ N, you will be placed in the top window, and the opposite thing happens when you type ^X\ P in the top window. ^X\ O is the same as ^X\ P. It stands for \*Qother window\*U because, when there are only two windows, repeated use of this command will switch between them. .LP Often you will be editing one window while using the other just for reference. Then, the command ESC\ ^V (\fIpage-next-window\fP) is very useful. It scrolls the next window up, just as if you switched to the next window, typed ^V, and switched back. With a negative argument, ESC\ ^V will scroll down. .LP When a window splits, both halves are approximately the same size. You can redistribute the screen space between the windows with the ^X\ ^ (\fIgrow-window\fP) command. It makes the active window grow one line bigger, or as many lines as is specified with a numeric argument. Use ESC\ X \fIshrink-window\fP to make the active window smaller. .HH 2 "Multiple Buffers in Multiple Windows" .LP Buffers can be selected independently in each window. The ^X\ B (\fIselect-buffer\fP) command selects a different buffer in the active window (i.e. the one containing the cursor). Other windows' buffers do not change. Likewise, the ^X\ ^F (\fIfind-file\fP) command reads a new file into a new buffer in the active window. .LP You can view the same buffer in more than one window. Although the same buffer appears in both windows, they have different values of point, so you can move around in one window while the other window continues to show the same text. If you make changes in one window, and the same place in the buffer happens to be visible in the other window, your changes will appear simultaneously in both places. .LP If you have the same buffer in both windows, you must beware of trying to visit a different file in one of the windows with ^X\ ^V, because if you bring a new file into this buffer it will replace the old file in \fIboth\fP windows. To view different files in different windows, you must switch buffers in one of the windows first (with ^X\ B) or use ^X\ ^F (\fIfind-file\fP). .LP A convenient \*Qcombination\*U command for viewing something in another window is ^X\ 4 (\fIwindow-find\fP). With this command you can ask to see any specified buffer, file or tag in the other window. Follow the ^X\ 4 with either B and a buffer name, F and a filename, or T and a tag name. This switches to the other window and finds there what you specified. If you were previously in one-window mode, multiple-window mode is entered. ^X\ 4 B is similar to ^X\ 2 ^X\ B; ^X\ 4 F is similar to ^X\ 2 ^X\ ^F; ^X\ 4 T is similar to ^X\ 2 ^X\ T. The difference is one of efficiency, and also that ^X\ 4 works equally well if you are already using two windows. .HH 2 "Controlling the Display" .LP Since only part of a large file will fit in a window, \s-2JOVE\s0 tries to show the portion that is likely to be interesting. The display control commands allow you to bring a different portion of the buffer within the active window. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^L redraw-display T{ Reposition point at a specified vertical position, OR clear and redraw the window with point in the same place. T} ESC\ ^L clear-and-redraw Clear and redraw the entire screen. ^V next-page Scroll forwards (a page or a few lines). ESC\ V previous-page Scroll backwards. ^Z scroll-up Scroll forward some lines. ESC\ Z scroll-down Scroll backwards some lines. scroll-left Scroll the window to the left. scroll-right Scroll the window to the right. number-lines-in-window Number the lines in the window. .TE .LP A window is rarely large enough to display all of your file. If the whole buffer doesn't fit on the screen, \s-2JOVE\s0 shows a contiguous portion of it, containing point. It continues to show approximately the same portion until point moves outside of what is displayed; then \s-2JOVE\s0 chooses a new portion centered around a new point. This is \s-2JOVE\s0's guess as to what you are most interested in seeing, but if the guess is wrong, you can use the display control commands to see a different portion. .LP If the window holds only a part of the buffer, and if the variable .I scroll-bar is \fIon\fP, a clear patch in the (otherwise reverse-videoed) mode line indicates what proportion is visible. This is especially useful for mouse-based versions of the editor, such as .I xjove . .LP First we describe how \s-2JOVE\s0 chooses a new window position on its own. The goal is usually to place point half way down the window. This is controlled by the variable \fIscroll-step\fP, whose value is the number of lines above the bottom or below the top of the window that the line containing point is placed. A value of 0 (the initial value) means center point in the window. .LP The basic display control command is ^L (\fIredraw-display\fP). In its simplest form, with no argument, it tells \s-2JOVE\s0 to choose a new portion of the buffer, centering the existing point half way from the top as usual. ^L with a positive argument chooses a new portion so as to put point that many lines from the top. An argument of zero puts point on the very top line. Point does not move with respect to the text; rather, the text and point move rigidly on the screen. .LP If during the ^L command point stays on the same line, the window is first cleared and then redrawn. Thus, two ^L's in a row are guaranteed to clear and redraw the active window. ESC\ ^L (\fIclear-and-redraw\fP) will clear and redraw the entire screen. .LP The \fIscrolling\fP commands ^V, ESC\ V, ^Z, and ESC\ Z let you move the whole display up or down a few lines. In fact, with a numeric argument, ^V is identical to ^Z and ESC\ V to ESC\ Z. So ^V (\fInext-page\fP) or ^Z (\fIscroll-up\fP) with an argument shows you that many more lines at the bottom of the screen, moving the text and point up together as ^L might. ^V or ^Z with a negative argument shows you more lines at the top of the screen, as does ESC\ V (\fIprevious-page\fP) or ESC\ Z (\fIscroll-down\fP) with a positive argument. .LP ^V with no argument scrolls the buffer a window at a time. It takes the last line at the bottom of the window and puts it at the top, followed by nearly a whole window of lines not visible before. Point is put at the top of the window. Thus, each ^V shows the \*Qnext page of text\*U, except for one line of overlap to provide context. To move backward, use ESC\ V without an argument, which moves a whole window backwards (again with a line of overlap). .LP With no argument, ^Z and ESC\ Z scroll one line forward and one line backward, respectively. These are convenient for moving in units of one line without having to type a numeric argument. .LP The commands \fIscroll-left\fP and \fIscroll-right\fP scroll the entire window in the specified direction by the amount of the argument (or for 10 characters by default). The argument may be negative. .LP The command \fInumber-lines-in-window\fP causes each line displayed to be preceded by its line-number (and giving the command again restores the former state). Note that this state is a property of the window, not of the buffer. .HH 1 "Processes Under \s-2JOVE\s0" .LP An important feature of \s-2JOVE\s0 is its ability to interact with .UX . You can run .UX commands from \s-2JOVE\s0 and catch their output in \s-2JOVE\s0 buffers. Two mechanisms are provided, \fIinteractive processes\fP and \fInon-interactive processes\fP. .HH 2 "Interactive Processes" .LP With most modern .UX systems, \s-2JOVE\s0 has the capability of running interactive processes, accepting your input and capturing your output in a buffer. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . shell T{ Run a shell in an interactive process buffer. T} i-shell-command T{ Run a \s-1UNIX\s0 command in an interactive process buffer. T} .TE .HH 3 "How to Run a Shell in a Window" .LP Type ESC\ X \fIshell\fP to start up a shell. \s-2JOVE\s0 will create a buffer, called \fB\(**shell\(**\-1\fP, and choose a window for this new buffer. The shell process is now said to be attached to the buffer. The program that is now running in the buffer is that specified by the variable \fIshell\fP, which is itself initialized from your SHELL environment variable. The shell command is called with the flag \*Q-c\*U, or whatever else the variable \fIshell-flags\fP has been set to. .LP Use an argument (\fBn\fP) with the \fIshell\fP command to create other buffers (\fB\(**shell\(**\-n\fP) running independent shells. .LP Once an interactive process is running you can select another buffer into that window, or you can delete that window altogether. You can go off and do some other editing while the command is running. This is useful for commands that do sporadic output and run for fairly long periods of time. When you reselect that buffer later it will be up to date. That is, even though the buffer wasn't visible it was still receiving output from the process. You don't have to worry about missing anything when the buffer isn't visible. .HH 3 "How to Run a Command in a Window" .LP To run a .UX command interactively from \s-2JOVE\s0 type ESC\ X \fIi-shell-command\fP . For example, to run the desk calculator, you do: .DS ESC\ X i-shell-command dc .DE Then \s-2JOVE\s0 picks a buffer in which the output from the command will be placed, named after the command (\fIdc\fP in this case). Compare this command to the non-interactive \fIshell-command\fP to be described presently. .HH 3 "Facilities available in interactive windows" .LP What you type into an interactive process isn't seen immediately by the process; instead \s-2JOVE\s0 waits until you type an entire line before passing it on to the process to read. This means that before you type Return all of \s-2JOVE\s0's editing capabilities are available for fixing errors on your input line. If you discover an error at the beginning of the line, rather than erasing the whole line and starting over you can simply move to the error, correct it, move back, and continue typing. .LP In fact Return does different things depending on both your position in the buffer and on the state of the process. In the normal case, when point is in the last line of the buffer, Return does as already described: it inserts a line-separator and then sends the line to the process. If you are somewhere else in the buffer, possibly positioned at a previous command that you want to edit, Return will place a copy of that line at the end of the buffer and move you there (the prompt will be discarded if there is one \(em the variable \fIprocess-prompt\fP specifies what to discard) Then you can edit the line and type Return as in the normal case. If the process has died for some reason, Return does nothing. It doesn't even insert itself. If that happens unexpectedly, you should type ESC\ X \fIlist-processes\fP to get a list of each process and its state. If your process died abnormally, \fIlist-processes\fP may help you figure out why. .LP Another feature is that you have the entire history of your session in the \s-2JOVE\s0 buffer. You don't have to worry about output from a command moving past the top of the screen. If you missed some output you can move back through it with ESC\ V and other commands. In addition, you can save yourself retyping a command (or a similar one) by sending edited versions of previous commands, or edit the output of one command to become a list of commands to be executed (\*Qimmediate shell scripts\*U). .LP There are several special commands available only in interactive windows. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . Return process-newline Send a line to a process. process-send-data-no-return T{ Send a line to a process, but without the line-separator. T} ^C\ ^C interrupt-process Send SIGINT to the process. ^C\ \^\e quit-process Send SIGQUIT to the process. ^C\ ^Z stop-process Send SIGTSTP to the process. ^C\ ^Y dstop-process Send SIGTSTP when next the process tries to read input. continue-process Send SIGCONT to the process. kill-process Send SIGKILL to the process in a specified buffer. ^C\ ^D eof-process Send EOF to the process. .TE Although Return is automatically bound to \fIprocess-newline\fP, the various ^C\ ... must be explicitly bound in your (or your system administrator's) customization. The effects of Return (\fIprocess-newline\fP) in various circumstances have already been described above. The effects of ^C\ ^\fBx\fP for various \fBx\fP are equivalent to sending ^\fBx\fP to the shell, assuming the customary bindings as set up by \fIstty\fP. Observe that ^\fBx\fP without a preceding ^C will have some other effect in \s-2JOVE\s0 (for example, ^D is still bound to \fIdelete-next-character\fP). .HH 3 "DBX in interactive windows" .LP If the debugging program \fIdbx\fP is provided with your .UX system, you may of course run it in an interactive window. Before doing this, you should turn on the dbx minor mode. The effect of this is that, every time \fIdbx\fP halts with a message line specifying a filename and linenumber (at every breakpoint, for example), \fIfind-file\fP will automatically be called on that filename, it will appear in another window, and point will be moved to that line. Thus you may easily follow the progress of the program being debugged. .HH 2 "Non-interactive Processes" .LP The reason these are called non-interactive processes is that you can't type any input to them; you can't interact with them; they can't ask you questions because there is no way for you to answer. Remember that \s-2JOVE\s0 (not the process in the window) is listening to your keyboard, and \s-2JOVE\s0 waits until the process dies before it looks at what you type. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ ! shell-command Run a \s-1UNIX\s0 command in a buffer. shell-command-no-buffer Run a \s-1UNIX\s0 command without any buffer. shell-command-to-buffer Run a \s-1UNIX\s0 command in a named buffer. shell-command-with-typeout T{ Run a \s-1UNIX\s0 command sending output to the screen. T} .TE .LP To run a .UX command from \s-2JOVE\s0 just type ^X\ ! . For example, to get a list of all the users on the system, you do: .DS I ^X\ ! who .DE Then \s-2JOVE\s0 picks a buffer in which the output from the command will be placed, named after the command. E.g., \*Qwho\*U uses a buffer called \fBwho\fP; \*Qps alx\*U uses \fBps\fP; and \*Qegrep -n foo \(**.c\*U uses \fBegrep\fP. If \s-2JOVE\s0 wants to use a buffer that already exists it first erases the old contents. If the buffer it selects holds a file, not output from a previous shell command, you must first delete that buffer with ^X\ K (\fIdelete-buffer\fP). There are variants of the command where there is no buffer, where you can name your own buffer, and where the output is direct to the screen (see the section on typeout at the start of this manual). .LP Once \s-2JOVE\s0 has picked a buffer it puts that buffer in a window so you can see the command's output as it is running. If there is only one window \s-2JOVE\s0 will automatically make another one. Otherwise, \s-2JOVE\s0 tries to pick the most convenient window other than the current one. .LP It is not a good idea to type anything while the command is running because \s-2JOVE\s0 won't see the characters (and thus won't execute them) until the command finishes, so you may forget what you have typed. If you really want to carry on with other editing tasks while it is running, it is better to use the \fIi-shell-command\fP described previously. .LP If you want to interrupt the command for some reason (perhaps you mistyped it, or you changed your mind) you can type ^] (or whatever else has been put in the variable \fIinterrupt-character\fP). Typing this inside \s-2JOVE\s0 while a process is running is the same as typing ^C when you are outside \s-2JOVE\s0, namely the process is interrupted. .LP When the command finishes, \s-2JOVE\s0 puts you back in the window in which you started. Then it prints a message indicating whether or not the command completed successfully in its (the command's) opinion. That is, if the command had what it considers an error (or you interrupt it with ^]) \s-2JOVE\s0 will print an appropriate message. .HH 3 "Applications of Non-Interactive Processes" .LP ^X\ ! (\fIshell-command\fP) is useful for running commands that do some output and then exit. So you could type ^X\ ! spell and it would create a buffer \*Qspell\*U, fill it with all the spelling mistakes in and display it in a window. However, as we have already seen, there is a built-in \s-2JOVE\s0 command to do this job (and more) which, behind the scenes, issues exactly that \fIshell-command\fP. Thus, the built in usage of this facility by \s-2JOVE\s0 itself is as important as any use you might invent for yourself. .LP You could run a program through a compiler using \fIshell-command\fP, but again \s-2JOVE\s0 provides a special command for the job. This is the ^X\ ^E (\fIcompile-it\fP) command. If you run \fIcompile-it\fP with no argument it runs the .UX \fImake\fP program into a buffer. If you need a special command or want to pass arguments to \fImake\fP, run \fIcompile-it\fP with any argument (^U is good enough) and you will be prompted for the command to execute. If any error messages are produced, they are treated specially by \s-2JOVE\s0. That treatment is the subject of the next section. .LP Another useful example of using the \fIshell-command\fP would be to type ^X\ ! egrep\ -l \ \(**.c, to give you a list of all your .c files containing that . .HH 4 "Error Message Parsing" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . parse-errors Prepare to exhibit the errors listed in the buffer. parse-spelling-errors-in-buffer Prepare to exhibit the listed spelling errors. ^X\ ^N next-error Move to the next listed error. ^X\ ^P previous-error Move to the previous listed error. current-error Move to the current listed error. .TE .LP When you have your error messages in a buffer as produced by the \fIshell-command\fP, you run the \fIparse-errors\fP command (this happens automatically after a \fIcompile-it\fP). Each line in this buffer should specify a filename and a linenumber (\s-2JOVE\s0 knows how to interpret the error messages from many .UX commands; in particular from \fIcc\fP, \fIgrep\ -n\fP and \fIlint\fP). \fIParse-errors\fP then does a \fIfind-file\fP on the first such filename and a \fIgoto-line\fP on its linenumber. When you have dealt with the error on that line (perhaps editing lines elsewhere in your program in the process) you can type ^X\ ^N (\fInext-error\fP) to move to the next error (perhaps in a different file). Or you can type ^X\ ^P (\fIprevious-error\fP) or ESC\ X \fIcurrent-error\fP. The rules \s-2JOVE\s0 uses to interpret error message in a buffer are specified in the variable \fIerror-format-string\fP. .LP The action following the \s-2JOVE\s0 command \fIspell\fP is similar, except that it calls (automatically) the command \fIparse-spelling-errors-in-buffer\fP instead of \fIparse-errors\fP. .LP If you already have a file called \fIerrs\fP containing, say, C compiler messages then you can get \s-2JOVE\s0 to interpret the messages by invoking it as: .DS I .I % jove \-p errs .R .DE .HH 4 "Filtering" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . filter-region T{ Pass the region through a command and replace it with the output. T} .TE .LP Suppose your buffer contains a table. You make this table the region (put mark at the start of it and point at the end). Type ESC\ X \fIfilter-region\fP \fIsort\fP (or any other .UX command). Your table will be passed through the .UX \fIsort\fP command and be replaced by the sorted version of itself. The old version is placed in the kill ring, and you can restore the status quo by obeying the \fIyank-pop\fP command. .HH 1 "Directory Handling" .LP To save having to use absolute pathnames when you want to edit a nearby file \s-2JOVE\s0 maintains a \fIcurrent directory\fP and allows you to move around the .UX filesystem just as a shell would. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . cd \fRdir Change to the specified directory. pushd \fR[dir] T{ Like \fIcd\fP, but saves the old directory on the directory stack. With no directory argument, simply exchanges the top two directories on the stack and \fIcd\fPs to the new top. T} pushlibd T{ Does a \fIpushd\fP on the directory containing all of \s-2JOVE\s0's standard customization files. T} popd T{ Take the current directory off the stack and restore the previous one. T} dirs Display the contents of the directory stack. .TE .LP The names and behavior of these commands were chosen to mimic those in the c-shell. .HH 1 "Major and Minor Modes" .HH 2 "Major Modes" .LP To help with editing particular types of file, say a document or a C program, \s-2JOVE\s0 has several \fImajor modes\fP. Each mode defines rules as to which characters constitute a \*Qword\*U (for the purposes of regular-expressions, language identifiers, abbreviations, and double-clicking in \fIxjove\fP), how indentation is to be performed, and maybe other specialized services. These are currently as follows: .HH 3 "Fundamental Mode" .LP This is the simplest mode, with no frills, and is used when you are operating within the message line at the bottom of the screen (hence it is the mode of the Minibuf). .HH 3 "Text mode" .LP This is the default major mode. Nothing special is done beyond making apostrophe (') be a word character. .HH 3 "C mode" .LP In this mode, \*Q$\*U and \*Q_\*U are word characters, and there are special facilities for indentation. Using the \fIauto-execute-command\fP command, you can make \s-2JOVE\s0 enter \fIC Mode\fP whenever you edit a file whose name ends in \fI.c\fP. .HH 4 "Indentation Commands" .LP To save having to lay out C programs \*Qby hand\*U, \s-2JOVE\s0 has an idea of the correct indentation of a line, based on the surrounding context. When you are in C Mode, \s-2JOVE\s0 treats tabs specially \(em typing a Tab at the beginning of a new line means \*Qindent to the right place\*U (actually, it just goes back to the line containing the nearest unmatched \*Q{\*U, and indents 1 Tab more than that line). The indentation will be in multiples of the variable \fIc-indentation-increment\fP (which defaults to 8). Closing braces are also handled specially, and are indented to match the corresponding open brace. .LP If you Tab in the middle of a (\^...\^) (for example, you call a function whose actual-parameters stretch over many lines) then you have a choice depending on the variable \fIc-argument-indentation\fP. If its value is \-1, you will be aligned with the corresponding actual-parameter on the line above. Otherwise, \fIc-argument-indentation\fP gives the extra number of characters by which to indent this continuation line. .LP If you really want a Tab to mean a single Tab on some particular occasion, you can always precede it by a ^Q (\fIquoted-insert\fP). .HH 4 "Parenthesis and Brace Matching" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . show-match-mode Toggle the \fIShow Match\fP minor mode. ESC\ ^N forward-list Move forwards over a (\^...\^). ESC\ ^P backward-list Move backwards over a (\^...\^). ESC\ ^D down-list Move forward to just inside the next (\^...\^). ESC\ ^U backward-up-list T{ Move backwards to the start of the enclosing (\^...\^). T} .TE .LP To check that parentheses and braces match the way you think they do, turn on the \fIShow Match\fP minor mode (ESC\ X \fIshow-match-mode\fP). Then, whenever you type a close brace or parenthesis, the cursor moves momentarily to the matching opener, if it is currently visible. If it's not visible, \s-2JOVE\s0 displays the line containing the matching opener on the message line. .LP If your parenthesized expressions are already typed, then you may find ESC\ ^N and ESC\ ^P useful to find a closing parenthesis to match an opening one somewhere just after point, or a closing one to match an opening one somewhere just before point. Note that these commands handle all kinds of parentheses ((\^...\^), [\^...\^] and {\^...\^}) and properly matched internal pairs are skipped over. These two commands take arguments and go in the opposite direction if the argument is negative. Likewise, the commands ESC\ D (\fIdown-list\fP) and ESC\ U (\fIbackward-up-list\fP) may be used to find more or less (respectively) deeply nested parentheses. .HH 4 "C Tags" .LP Often when you are editing a C program, especially someone else's code, you see a function call and wonder what that function does. So you have to suspend the edit, \fIgrep\fP for the function-name in every .c file that might contain it, and finally visit the appropriate file. .LP To avoid this diversion or the need to remember which function is defined in which file, many .UX systems provide a program called \fIctags(1)\fP, which takes a set of source files and looks for function definitions, producing a file called \fItags\fP as its output. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ T find-tag Find the file/line where the specified tag is declared. find-tag-at-point Find the tag immediately following point. .TE .LP \s-2JOVE\s0 has a command called ^X\ T (\fIfind-tag\fP) that prompts you for the name of a function (a \fItag\fP), looks up the tag reference in the previously constructed \fItags\fP file, then performs a \fIfind-file\fP on the file containing that tag, with point positioned at the definition of the function. There is another version of this command, \fIfind-tag-at-point\fP, that uses the identifier at point. .LP So, when you've added new functions to a module, or moved some old ones around, run the \fIctags\fP program to regenerate the \fItags\fP file. \s-2JOVE\s0 looks in the file specified by the variable \fItag-file\fP. The default is \*Q\fB.\fP\^/\^tags\*U, i.e. the tag file in the current directory. If you wish to use an alternate tag file you use ^U\ ^X\ T and \s-2JOVE\s0 will prompt for a file name. .LP To begin an editing session looking for a particular tag, use the \fI\-t tag\fP command line option to \s-2JOVE\s0. For example, say you wanted to look at the file containing the tag \fISkipChar\fP, you would invoke \s-2JOVE\s0 as: .DS I .I % jove \-t SkipChar .R .DE .HH 3 "Lisp mode" .LP In this mode, any of the characters \*Q!\^$\^%\^&\^\(**\^+\^\-\^/\^:\^<\^=\^>\^?\^^\^_\^{\^|\^}\^\s+2~\s0\*U and Delete are word characters (in other words, \*Qwords\*U are Lisp atoms). The mode is analogous to \fIC Mode\fP, but performs the indentation needed to lay out Lisp programs properly. .HH 4 "Parenthesis Matching" .LP In addition to the parenthesis matching commands available under C mode, we have: .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ESC\ ^F forward-s-expression Move backward over an atom or list. ESC\ ^B backward-s-expression Move forward over an atom or a list. grind-s-expression Re-indent an s-expression. ESC\ ^K kill-s-expression Kill from point to the end of an s-expression. .TE .LP In fact the first two of these commands work in other modes also, but for \*Qatom\*Q read \*Qidentifier\*U. .HH 2 "Minor Modes" .LP In addition to the major modes, \s-2JOVE\s0 has a set of minor modes whose state is controlled by the following commands: .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . auto-indent-mode auto-fill-mode dbx-mode over-write-mode read-only-mode show-match-mode word-abbrev-mode .TE .LP With no argument, these commands toggle the mode. With a zero argument they turn it \fIoff\fP, and with any other argument they turn it \fIon\fP. .HH 3 "Auto Indent" .LP In this mode, \s-2JOVE\s0 indents each line the same way as that above it. That is, the Return key in this mode acts as the Linefeed key ordinarily does. This mode is only likely to be useful if you are afflicted with a keyboard without a Linefeed key. .HH 3 "Auto Fill" .LP In \fIAuto Fill\fP mode, a newline is automatically inserted when the line length exceeds the right margin. This way, you can type a whole paragraph without having to use the Return key. .HH 3 "DBX" .LP This mode is useful if dbx is being run in an interactive window. It is described in the section on interactive windows. .HH 3 "Over Write" .LP In this mode, any text typed in will replace the previous contents (the default is for new text to be inserted and \*Qpush\*U the old along). This is useful for editing an already-formatted diagram in which you want to change some things without moving other things around on the screen. .HH 3 "Read Only" .LP In this mode, modifying the buffer is inhibited. This mode is set automatically on any attempt to read a file for which you do not have write permission. .HH 3 "Show Match" .LP Move the cursor momentarily to the matching opening parenthesis when a closing parenthesis is typed. .HH 3 "Word Abbrev" .LP In this mode, every word you type is compared to a list of word abbreviations; whenever you type an abbreviation, it is replaced by the text that it abbreviates. This can save typing if a particular word or phrase must be entered many times. For example, your programming language might have reserved words that you customarily type in upper case (identifiers etc. being in lower case). So you might define B as an abbreviation for BEGIN, E for END, P for PROCEDURE, and so on. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . define-global-word-abbrev Define a new global abbreviation. define-word-abbrev T{ Define a new abbreviation within the current major mode. T} edit-word-abbrev Edit the list of abbreviations. write-word-abbrev-file Write the list of abbreviations to a file. read-word-abbrev-file Read a list of abbreviations from a file. .TE .LP The abbreviations and their expansions are held in a list that looks like: .DS I abbrev:phrase .DE for example .DS jove:jonathan's own version of EMACS .DE Use \fIdefine-global-word-abbrev\fP to add an entry that is to be effective in all buffers and \fIdefine-word-abbrev\fP for an entry that is to be effective only in buffers of the same major mode as the selected buffer. Use \fIedit-word-abbrev\fP to edit the list (it enters a recursive edit on a buffer containing the list \(em use ^X\ ^C (\fIexit jove\fP) when you are finished). Use \fIwrite-word-abbrev-file\fP to write the list to a file and \fIread-word-abbrev-file\fP to read it back again (this command might be used in your \fB.joverc\fP file) . .LP If the variable \fIauto-case-abbrev\fP is \fIon\fP, and the abbreviations in the list are all in lower case (as in the \*Qjove\*U example above) then, whenever you type \*Qjove\*U you will get .DS jonathan's own version of EMACS .DE but if you type \*QJove\*U you will get .DS Jonathan's own version of EMACS .DE and if you type \*QJOVE\*U (with at least 2 upper case letters) you will get .DS Jonathan's Own Version Of EMACS .DE .LP On the other hand, if the variable \fIauto-case-abbrev\fP is \fIoff\fP (as it should be for the reserved word example) the case of the abbreviation is significant and must be matched exactly. .HH 1 "Macros" .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . ^X\ ( begin-kbd-macro Start recording your commands. ^X\ ) end-kbd-macro Stop recording your commands. ESC\ I make-macro-interactive Call for a parameter to be typed at this point. ^X\ E execute-kbd-macro Replay the recording. name-kbd-macro Name the recording. define-macro Define a named macro. execute-macro Execute a named macro. write-macros-to-file Write all named macros to a file. bind-macro-to-key Bind named macro to a key-sequence. bind-macro-to-word-abbrev Bind named macro to an abbrev. .TE .LP Although \s-2JOVE\s0 has many powerful commands, you often find that you have a task that no individual command can do. \s-2JOVE\s0 allows you to define your own commands from sequences of existing ones. The easiest way to do this is \*Qby example\*U. .HH 2 "Keyboard Macros" .LP First you type ^X\ ( (\fIbegin-kbd-macro\fP). Next you \*Qperform\*U the commands which will constitute the body of the macro (they are executed as well as being remembered). Then you type ^X\ ) (\fIend-kbd-macro\fP). You now have a \fIkeyboard macro\fP. .LP To run this command sequence again, type ^X\ E (\fIexecute-keyboard-macro\fP). .LP If your macro needs a parameter (a filename to be opened, perhaps), include the command needing the parameter (e.g. ^X\ ^F) at the appropriate place in the macro followed immediately by ESC\ I (\fImake-macro-interactive\fP). When the macro is executed, you will be given an opportunity to type in the actual-parameter at this point. .HH 2 "Named Macros" .LP You may give the keyboard macro a name using the \fIname-keyboard-macro\fP command (or you may create a named macro from scratch using the \fIdefine-macro\fP command). We're still not finished because all this hard work will be lost if you leave \s-2JOVE\s0. What you do next is to save your macros into a file with the \fIwrite-macros-to-file\fP command. To retrieve your macros in the next editing session, you can simply execute the \fIsource\fP command on that file, or include that file in your personal \fB.joverc\fP file. .LP A named macro can be executed by typing ESC\ X \fIexecute-macro\fP . It is unfortunate that macro names are kept in a different name space than command names, so that you cannot type ESC\ X . This may well be changed in a future release. .HH 2 Binding Macros to Keys .LP Finally, if you find all this bothersome to type and re-type, there is a way to bind the macro to a key. The binding is made with the \fIbind-macro-to-key\fP command, or alternatively the \fIbind-macro-to-word-abbrev\fP command (in which case the macro will be executed upon typing the abbrev word you have specified \(em it will get expanded as well unless it was an abbreviation for nothing). .HH 1 "Customizing Jove" .HH 2 "The jove.rc and .joverc files" .LP \s-2JOVE\s0 is aware of a directory, the \fIsharedir\fP, in which system-wide customization files are kept. Chief amongst these is the file \fBjove.rc\fP which is read each time \s-2JOVE\s0 is started up (\fBjove.rc\fP may then initiate the reading of other files in the sharedir, such as initialization files for specific terminals). After that, \s-2JOVE\s0 reads your personal \fB.joverc\fP in your $HOME directory, if you have one. And if all that is not enough, you may at any time read other customization files using the \fIsource\fP command. .LP The \s-2JOVE\s0 distribution comes with a recommended \fBjove.rc\fP file together with specific \fBjove.rc.TERM\fP files for various terminals. It is up to system administrators to decide whether to use these as they stand or to modify them to accord with local conventions. Note that these files are well commented and worthy of study by those who decide to \*Qroll their own\*U. .LP There are command-line options that can be used when \s-2JOVE\s0 is started to substitute a different \fIsharedir\fP or to suppress reading of the \fBjove.rc\fP or \fB.joverc\fP files or both \(em see the Man page for \s-2JOVE\s0. Thus everything is ultimately under the control of the individual \s-2JOVE\s0 user. .HH 2 "The source Command" .LP Type ESC\ X \fIsource\fP to read and obey the commands in . If a numeric argument is supplied to \fIsource\fP, it will silently ignore a request for a non-existent file (otherwise an error message will be produced). The format of the \fIsource\fPd file, as of the \fBjove.rc\fP and \fB.joverc\fP files, is as follows. .LP Each line consists of a command name (no need to precede it with ESC\ X) followed by whatever parameters that command requires. To give a numeric argument to the command, simply precede the command name by a number. Thus it is possible to to do anything that the user could do while \s-2JOVE\s0 is running. .LP .KS But there is more than this. You can say .RS \fIif\fP .RS .br .RE \fIelse\fP .RS .br .RE \fIendif\fP .RE .KE The is run, and if it succeeds the first lot of s is obeyed, and otherwise the second lot (the \fIelse\fP part is optional). Another variant of this feature allows you to say, in place of \fIif\fP , \fIifenv\fP , which succeeds if exists and if its value matches the regular expression (an anchored match from the beginning of the variable value). There is a similar variant \fIifvar\fP , which succeeds if the specified \s-2JOVE\s0 variable exists and if its value matches . These conditional commands can be nested in the usual way; also indentation and empty lines have no effect. Finally, any line that starts with a \*Q#\*U is treated as a comment and is ignored by \s-2JOVE\s0. .LP Here are some examples taken from the provided \fBjove.rc\fP. .KS .RS pushlibd .sp .5n # This is for the shell window. Supports sh, csh and ksh. .br set process-prompt ^[\^^%$#]\(**[%$#] .sp .5n # Modern terminals do not need ^S/\^^Q for flow control. .br # The exceptions (e.g. vt100) should turn it off again in jove.rc.TERM. .br set allow-^S-and-^Q on .sp .5n # source any TERMinal-specific rc file .br 1 source jove.rc.$TERM .sp .5n popd .RE .KE .LP The \fIpushlibd\fP ensures that any files it tries to read will be taken from the \fIsharedir\fP (observe the matching \fIpopd\fP at the end). Then follow some settings of variables such as \fIprocess-prompt\fP (see the discussion of interactive processes earlier in this manual). Observe how environment variables such as $TERM are honored within parameters, and note how that \fIsource\fP command was given a numeric argument so that there would be no complaint if the file \fBjove.rc.$TERM\fP did not exist. .LP On the other hand, if \fBjove.rc.$TERM\fP does exist for the particular terminal specified in $TERM, that file will now be \fIsource\fPd. It will likely set many key bindings particular to that terminal, and then say .KS .RS define-macro keychart ^[xpushlibd\^^M .RS ^U\^^[Xshell-command-with-typeout cat keychart.$TERM\^^M .br ^[Xpopd\^^M .RE # except that should really have been all on one line .br bind-macro-to-key keychart ^[\^[\^\s+2~\s0 .RE .KE .LP Quite some mouthful! What it does is to define a macro \fIkeychart\fP (the hard way) and bind it to ESC\ [\ \s+2~\s0. In general, any terminal for which extensive key bindings are provided ought to define this macro and bind it to a suitable key (preferably the one inscribed \*QHelp\*U). When this key is pressed, it will cause the file \fBkeychart.$TERM\fP to be displayed on the screen in \fItypeout\fP style. This file should exhibit a map of the terminal's keyboard, showing what has been bound to each key. The \fIsharedir\fP contains several such keychart files. .LP Although Control characters may be stored as themselves in these files (as produced by the \fIquoted-insert\fP command, for example), it is better to store them using an explicit \*Q\^^\^\*U (e.g. as ^C), since this form is accepted by the \fIsource\fP command, and editing files in this form is much easier. .HH 2 "Key Re-binding" .LP Many of the commands built into \s-2JOVE\s0 are not bound to specific keys. You must type ESC\ X (\fIexecute-named-command\fP) in order to invoke these commands. Also, many of the keys to which commands \fIare\fP bound are hard to remember (although at least compatible across all terminals) whilst all sorts of interesting keys on the particular keyboard remain unused. For both these reasons, \s-2JOVE\s0 makes it possible to \fIbind\fP commands to keys. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . bind-to-key Bind a command to a key-sequence. bind-macro-to-key Bind a named macro to a key-sequence. bind-macro-to-word-abbrev Bind a named macro to an abbrev. bind-keymap-to-key Bind an extra key-sequence to a keymap. describe-bindings Exhibit all key bindings as a screen typeout. local-bind-to-key T{ As bind-to-key, for use in the selected buffer only. T} local-bind-macro-to-key T{ As bind-macro-to-key, for use in the selected buffer only. T} local-bind-keymap-to-key T{ As bind-keymap-to-key, for use in the selected buffer only. T} process-bind-to-key T{ Bind interactive process command to a key-sequence. T} process-bind-macro-to-key T{ Bind a macro within interactive processes only. T} process-bind-keymap-to-key T{ Bind a keymap within interactive processes only. T} .TE .LP Although these commands can be typed in by the user, they are mostly intended for use in \fIsource\fPd files. Here are some more examples from \fBjove.rc\fP. .KS .RS # if you have job control, this puts Jove out of the way temporarily. .br bind-to-key pause-jove ^[S .br bind-to-key pause-jove ^[s .sp .5n # The following apply to shell windows. Note the use of ^C\^^C, ^C\^^D etc., .br process-bind-to-key interrupt-process ^C\^^C .br process-bind-to-key eof-process ^C\^^D .sp .5n # This makes the arrow keys work on most terminals. .br bind-to-key previous-line ^[[A .br bind-to-key next-line ^[[B .RE .KE .LP When a command is \fIbound\fP to a key any future hits on that key will invoke that command. All the printing characters are initially bound to the command \fIself-insert\fP. Thus, typing any printing character causes it to be inserted into the text. To unbind a key, simply bind it to the fictitious command \fIunbound\fP. .LP Observe how key-sequences are often derived from common prefixes, such as ^X\ ..., ESC\ ... (to be typed as ^[\ ... in binding commands) and ESC\ [\ ... (or ^[\ [\ ...). Internally, \s-2JOVE\s0 creates tables for each prefix encountered, but it cannot create a new prefix from a manually entered \fIbind-\fP command (it does not know when you have finished your binding). To overcome this, give the \fIbind-\fP command an argument and terminate it with a Return (this applies automatically within \fIsource\fPd files). Obviously, you must not have two bindings where one is a prefix of the other. .LP Very rarely, you may want two prefixes to be regarded as equivalent for all commands (for example, you have a keyboard with no ESC key, and it would be tedious to have to rebind every command in the system with a different prefix). In this case, you can type ESC\ X \fIbind-keymap-to-key\fP . The only recognized s are \*QESC-map\*U and \*QCtlx-map\*U, and the customary replacement for ESC is \*Q`\*U. .LP For historical reasons, the Escape key is often referred to as \*QMeta\*U. Indeed, if your terminal has a Meta-key which forces the 8th-bit of a character, and if the variable \fImeta-key\fP is \fIon\fP, you may type Y whilst holding the Meta-key down to achieve the same effect as when typing ESC\ Y. .HH 3 "The Provided Terminal Bindings" .LP The terminals for which keybindings have been provided are a mixed bunch (we would welcome suggestions for other common terminals). However, there are certain principles which were followed in setting them up. .IP 1. Groupings of keys that are found in bindings for other terminals were adhered to so far as possible. Rather than saying that the F1 key always does so-and-so, groupings of Function Keys that are physically associated on the keyboard were mapped onto similar groupings on other keyboards, even though the engravings on them might be quite different. .IP 2 Keys which do related things should be close together. .IP 3 Keys which customarily do certain things under other editors normally used with that keyboard should do the same (or similar) things under \s-2JOVE\s0. .IP 4 Keys which have suggestive engravings on them should do what the engravings suggest. Sometimes, this necessitated the creation of a macro where no \s-2JOVE\s0 command existed to do precisely that job (for example, the macro \fIkill-line\fP). .HH 2 "Auto-execution of Commands" .LP It is useful, when a file is recognized as being in a particular programming language, for the appropriate major mode and other relevant facilities to be set up automatically in any buffer into which such a file is read. .TS L2w(10)fR L2w(20)fI Lw(\n(Ww)fR . auto-execute-command T{ Obey the given command for each filename matched by the given regular-expression. T} auto-execute-macro Obey the given macro likewise. .TE .LP Here is an example taken from \fBjove.rc\fP. .KS .RS # set various language modes. .br 1 auto-execute-command c-mode .\(**\.[chy]$ .br 1 auto-execute-command lisp-mode .\(**\.l$\|.\(**\.lisp$\|.\(**\.scm$ .br # all the languages need show-match-mode. .br 1 auto-execute-command show-match-mode .\(**\.[lchyfp]$\|.\(**\.lisp$\|.\(**\.scm$ .RE .KE .LP The effect of this is that whenever a filename matches the regular-expression \*Q.\(**\.[chy]$\*U the command \fIc-mode\fP is obeyed in the buffer into which the file is being read, and similarly for \fIlisp-mode\fP. An attempt is then made to set \fIshow-match-mode\fP for both C and Lisp programs. Observe that all the \fIauto-execute-command\fPs in this example have an argument of 1. This argument is passed on to the obeyed command so that, for example, it is ensured that \fIc-mode\fP is definitely set to be \fIon\fP, rather than merely being toggled. .HH 2 "Customizing the Mode Line" .LP The format of the mode line is controlled by the variable \fImode-line\fP. Here is a suggested setting. .DS %[Jove%]%w%w%c(%M)%3c[%b:%n]%2c"%f"%2c%m\(**-%m\(**-%2c%p%2s%(%d%e(%t)%) .DE .LP and here is what it all means. .IP %[\^...\^%] 12n Puts brackets around Jove when in a recursive edit. .IP %w%w Warns with >> if the window is scrolled left. .IP (%M) Gives the current major and minor modes. .IP [%b:%n] Shows the buffer name and number. .IP """%f""" Shows the filename. .IP %m\(**\-%m\(**\- Displays \(**\(** if the buffer is modified, \-\- if not. .IP %p In process windows only, shows the status of the process. .IP %d Shows the current directory. .IP (%t) Shows the time of day. .LP Everything else is layout. See the full description of the \fImode-line\fP variable for further details. .HH 1 "Xjove and Xterm" .LP If you run \s-2JOVE\s0 on a workstation equipped with the X-Windows system from M.I.T., then it is advised to run \s-2JOVE\s0 under one of the terminal emulators \fIxjove\fP or \fIxterm\fP. \fIXterm\fP is provided as a standard part of the X-Windows system, but the facilities provided are a small subset of those available with \fIxjove\fP, which was written especially to support \s-2JOVE\s0. However, \fIxjove\fP suffers from the disadvantage that it must be compiled under the XView Toolkit which, although available free from M.I.T., may not be available on your system. Note that, in either case, special keybindings must be provided (see the files \fBjove.rc.sun-cmd\fP and \fBjove.rc.xterm\fP). See the Man page for \fIxjove\fP for how to call it and the flags and options available. .HH 2 "Basic Mouse Operations" .LP When running under \fIxjove\fP or \fIxterm\fP you may click the LEFT mouse button in order to set the position of point, and the MIDDLE mouse button to set the position of point and mark. If you hold the MIDDLE button down, you may sweep it along, leaving mark where you started and point where you finished, thus defining the region. If you hold the Control key down while you are doing this, the region is copied to the kill ring, as with the \fIcopy-region\fP command, and if you hold both the Control and Shift keys down, the region is killed (and sent to the kill ring) as with the \fIkill-region\fP command. To have the killed text yanked at some other point, click the LEFT mouse button there, holding the Control key down at the same time. .LP To switch to a different window, simply click either button in the window you want to be in (note that this does not affect point or mark in that window \(em it takes two clicks to change windows and then change point). .LP To scroll rapidly to a different part of the buffer, simply click either mouse button in the mode line at a position corresponding to the percentage way down the file you want to be. It helps to have set the variable \fIscroll-bar\fP \fIon\fP so that you can see by the uninverted part of the mode line which part of the buffer is currently visible in the window. When you have finished, the mouse pointer should be exactly in the middle of the uninverted region. .HH 2 "Additional Xjove Features" .LP When running under \fIxjove\fP there are some additional facilities. Firstly, the setting when pointing into the mode line is more sensitive, because it notes the mouse position to the nearest pixel instead of the nearest character, and it is possible to hold the mouse button down and watch the window scrolling as you drag it (although this can consume considerable machine resources and it may have difficulty in keeping up). Also, it is possible to follow the position of point in real time as you drag the mouse around when delineating a region. .LP If you do a double click with the MIDDLE button in \fIxjove\fP, it will set the region spanning the word you were over (or spanning the gap if you were between words). Note that the definition of \*Qword\*U here follows the major mode. If you do a triple click, it will likewise select the whole line. These operations may be combined with the Control key, or the Control and Shift keys together, to obtain copying and killing as before. .LP If your keyboard has keys marked Paste and Cut, it is possible to bring text from another part of the buffer (even from a different window) without changing the position of point (this is useful if you are constructing text at some point, bringing in fragments from other places \(em you would prefer not to have to keep moving point to those other places to acquire some text for the kill ring, only to have to move it back again before yanking). To do this, with point where you want the text to be inserted, you hold the Paste key down while you select a region with the MIDDLE button (multi-clicking or dragging as usual). When you have finished, a copy of the region you selected will appear at point, with point moved beyond it (since it went via the kill ring, this text is also available for conventional yanking subsequently). If you change your mind in mid stream, let go of Paste before releasing MIDDLE. Likewise, if you do the same thing holding the Cut key down, the text will also be killed from its original position. .LP Finally, if you press the RIGHT mouse button, you will be offered a menu which enables you to issue any \s-2JOVE\s0 command or set any \s-2JOVE\s0 variable. Particularly useful if you need some obscure and rarely used command, and cannot remember exactly what it is called. .HH 1 "Recovering from system/editor crashes" .LP \s-2JOVE\s0 does not have an \fIAuto Save\fP mode, but it does provide a way to recover your work in the event of a system or editor crash. \s-2JOVE\s0 saves information about the files you are editing every \fIsync-frequency\fP changes to a special buffer, so as to make recovery possible. Since a relatively small amount of information is involved it is hardly even noticeable when \s-2JOVE\s0 does this. The variable \fIsync-frequency\fP says how often to save the necessary information, and the default is every 50 changes. 50 is a very reasonable number: if you are writing a paper you will not lose more than the last 50 characters you typed, which is less than the average length of a line. .LP If \s-2JOVE\s0, or the operating system, crashes, you may now use the \s-2JOVE\s0 \fIrecover\fP program to get back your files. You invoke this by running \s-2JOVE\s0 with the -r flag. See the Man page for \s-2JOVE\s0 for further details. .LP Another worthwhile precaution you can take is to set the variable \fImake-backup-files\fP \fIon\fP. Then, whenever you save a file with \fIsave-file\fP it will leave behind the original version of that file with the name \*Q#\fIfilename\fP\s+2~\s0\*U. .bp .HH 1 "Alphabetical List of Commands and Variables" .LP In this chapter, the standard binding is shown for each command which has one. Generally, these are the built-in bindings, but occasionally they are ones taken from the provided \fBjove.rc\fP file. jove-4.17.5.5/doc/jem.txt000066400000000000000000000004411501102521500147660ustar00rootroot00000000000000C-X means press Control and X together, ESC X means ESC key followed by X Exit: C-X C-C Save: C-X s Tutorial: ESC t Describe-Key: C-X ? Describe-Command: ESC ? Apropos(Command-Search): C-X a Hide this help: ^X 1 Disable this beginner help with 'touch ~/.joverc' jove-4.17.5.5/doc/jove.nr000066400000000000000000000413571501102521500147710ustar00rootroot00000000000000.\"########################################################################## .\"# This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # .\"# provided by Jonathan and Jovehacks without charge and without # .\"# warranty. You may copy, modify, and/or distribute JOVE, provided that # .\"# this notice is included in all the source files and documentation. # .\"########################################################################## .TH JOVE 1 "24 June 1993" .SH NAME jove \- an interactive display-oriented text editor .SH SYNOPSIS .B jove [ .BI \-d \ directory ] [ .BI \-D \ debugfile ] [ .BI \-l \ libdir ] [ .BI \-s \ sharedir ] [ .BI \-ls \ bothdir ] [ .B \-J ] [ .B \-j ] [ .BI \-w n ] [ .BI \-t \ tag ] [ .B \-T ] [ .BI + n\ file ] [ .BI +/ pattern\ file ] [ .BI \-p \ file ] [ .IR file .\|.\|. ] .br .B jove \-r .SH DESCRIPTION .hy 0 JOVE is Jonathan's Own Version of Emacs. It is based on the original EMACS editor written at MIT by Richard Stallman. Although JOVE is meant to be compatible with EMACS, there are some major differences between the two editors and you shouldn't rely on their behaving identically. .LP JOVE works on any reasonable display terminal that is described in the .I termcap file (see TERMCAP(5) for more details). When you start up JOVE, it checks to see whether you have your .I TERM environment variable set. On most systems that will automatically be set up for you, but if it's not JOVE will ask you what kind of terminal you are using. To avoid having to type this every time you run JOVE you can set your .I TERM environment variable yourself. How you do this depends on which shell you are running. If you are running the C Shell, as most of you are, you type .sp 1 % setenv TERM .I type .sp 1 and with the Bourne Shell, you type .sp 1 $ TERM= .I type ; export TERM .sp 1 where .I type is the name of the kind of terminal you are using (e.g., vt100). If neither of these works get somebody to help you. .SH INVOKING JOVE If you run JOVE with no arguments you will be placed in an empty buffer, called .I Main. Otherwise, any arguments you supply are considered file names and each is ``given'' its own buffer. Only the first file is actually read in \(em reading other files is deferred until you actually try to use the buffers they are attached to. This is for efficiency's sake: most of the time, when you run JOVE on a big list of files, you end up editing only a few of them. .LP The names of all of the files specified on the command line are saved in a buffer, called .I *minibuf*. The mini-buffer is a special JOVE buffer that is used when JOVE is prompting for some input to many commands (for example, when JOVE is prompting for a file name). When you are being prompted for a file name, you can type ^N (that's Control-N) and ^P to cycle through the list of files that were specified on the command line. The file name will be inserted where you are typing and then you can edit it as if you typed it in yourself. .LP JOVE recognizes the following switches: .TP .BI \-d \ dirname .I dirname is taken to be the name of the current directory. This is for systems that don't have a version of C shell that automatically maintains the .I CWD environment variable. If .B \-d is not specified on a system without a modified C shell, JOVE will have to figure out the current directory itself, and that can be slow. You can simulate the modified C shell by putting the following lines in your C shell initialization file (.cshrc): .nf .sp 1 alias cd 'cd \e!*; setenv CWD $cwd' alias popd 'popd \e!*; setenv CWD $cwd' alias pushd 'pushd \e!*; setenv CWD $cwd' .fi .BI \-D \ debugfile .I debugfile is created if missing, and some internal debug output is written to it. Only for developers (or filing with bug reports on interactive-shell misbehaviour) .TP .BI \-l \ libdir Allows the user to specify the directory in which supporting programs (recover, portsrv) required by JOVE can be found (default ). Within JOVE, this setting will be visible as the .I lib-dir-pathname variable. If JOVE was built to fit on machines with very little memory, without the features for post-crash recovery or interactive processes, then this option is not relevant. If .I libdir is a relative path, then the directory from which the running JOVE binary was started will be prepended to it. .TP .BI \-s \ sharedir Allows the user to specify the directory in which default initialization files, command help and primary JOVE tutorial can be found (default ). Within JOVE, this setting will be visible as the .I share-dir-pathname variable. If .I sharedir is a relative path, then the directory from which the running Jove binary was started will be prepended to it. .TP .BI \-ls \ bothdir Allows the user to specify the directory in which binary files and initialization files required by JOVE can be found. .B \-sl is an alias for this option. .TP .B \-J Inhibits reading of the system-wide initialization file (/jove.rc). .TP .B \-j Inhibits reading of the user's initialization file (~/.joverc). .TP .BI + n Reads the file designated by the following argument, and positions point at the .I n'th line instead of the (default) first line. This can be specified more than once but it doesn't make sense to use it twice on the same file; in that case the second one wins. If no numeric argument is given after the +, the point is positioned at the end of the file. .TP .BI +/ pattern Reads the file designated by the following argument, and positions point at the first match of the pattern. .TP .BI \-p \ file Parses the error messages in .IR file . The error messages are assumed to be in a format similar to the C compiler, LINT, or GREP output. .TP .BI \-t \ tag Runs the .I find-tag command on .I tag (see ctags(1)). .TP .B \-T starts JOVE in .I teach-jove mode, loading the JOVE tutorial into a buffer (unsaved) with the filename .IR ~/teach-jove . This replaces the old .B teachjove command. .TP .BI \-w n Divides the window into .I n windows (if .I n is omitted, it is taken to be 2). Subsequent files in the list are read in and displayed in succeeding windows. .SH "RECOVERING BUFFERS AFTER A CRASH" The .B \-r option of jove runs the JOVE recover program. Use this when the system crashes, or JOVE crashes, or you accidentally get logged out while in JOVE. If there are any buffers to be recovered, this will find them. .LP Recover looks for JOVE buffers that are left around and are owned by you. (You cannot recover other peoples' buffers, obviously.) If there were no buffers that were modified at the time of the crash or there were but recover can't get its hands on them, you will be informed with the message, ``There is nothing to recover.'' Otherwise, recover prints the date and time of the version of the buffers it has, and then waits for you type a command. .LP To get a list of the buffers recover knows about, use the .I list command. This will list all the buffers and the files and the number of lines associated with them. Next to each buffer is a number. When you want to recover a buffer, use the .I get command. The syntax is .I get buffer filename where .I buffer is either the buffer's name or the number at the beginning of the line. If you don't type the buffer name or the filename, recover will prompt you for them. .LP If there are a lot of buffers and you want to recover all of them, use the .I recover command. This will recover each buffer to the name of the buffer with ``.#'' prepended to the name (so that the original isn't over-written). It asks for each file and if you want to restore that buffer to that name you type ``yes''. If you want to recover the file but to a different name, just type the new name in. If you type ``no'' recover will skip that file and go on to the next one. .LP If you want to look at a buffer before deciding to recover it, use the .I print command. The syntax for this is .I print buffer where .I buffer again is either its name or the number. You can type ^C if you want to abort printing the file to the terminal, and recover will respond with an appropriate message. .LP When you're done and have all the buffers you want, type the .I quit command to leave. You will then be asked whether it's okay to delete the tmp files. Most of the time that's okay and you should type ``yes''. When you say that, JOVE removes all traces of those buffers and you won't be able to look at them again. (If you recovered some buffers they will still be around, so don't worry.) So, if you're not sure whether you've gotten all the buffers, you should answer ``no'' so that you'll be able to run recover again at a later time (presumably after you've figured out which ones you want to save). If there were more than one crashed JOVE session, .I quit will move you on to dealing with the next one instead of exiting. .LP If you type ^C at any time other than when you're printing a file to the terminal, recover will exit without a word. If you do this but wish you hadn't, just type ``jove \-r'' to the shell again, and you will be put back with no loss. .SH GETTING HELP Once in JOVE, there are several commands available to get help. To execute any JOVE command, you type `` X command-name'' followed by . To get a list of all the JOVE commands you type `` X'' followed by ``?''. The .I describe-bindings command can be used to get a list containing each key, and its associated command (that is, the command that gets executed when you type that key). If you want to save the list of bindings, you can set the jove variable .I send-typeout-to-buffer to ON (using the .I set command), and then execute the .I describe-bindings command. This will create a buffer and put in it the bindings list it normally would have printed on the screen. Then you can save that buffer to a file and print it to use as a quick reference card. (See VARIABLES below.) .LP Once you know the name of a command, you can find out what it does with the .I describe-command command, which you can invoke quickly by typing ``ESC ?''. The .I apropos command will give you a list of all the command with a specific string in their names. For example, if you want to know the names of all the commands that are concerned with windows, you can run ``apropos'' with the keyword .I window. .LP If the initialization file has provided specific keybindings for your terminal, it should also be possible to view the keyboard layout with the keychart macro. .LP If you're not familiar with the EMACS command set, it would be worth your while to use run TEACHJOVE. Do do that, just type ``teachjove'' to your shell and you will be placed in JOVE in a file which contains directions. I highly recommend this for beginners; you may save yourself a lot of time and headaches. .SH KEY BINDINGS and VARIABLES You can alter the key bindings in JOVE to fit your personal tastes. That is, you can change what a key does every time you strike it. For example, by default the ^N key is bound to the command .I next-line and so when you type it you move down a line. If you want to change a binding or add a new one, you use the .I bind-to-key command. The syntax is ``bind-to-key key''. .LP You can also change the way JOVE behaves in little ways by changing the value of some variables with the .I set command. The syntax is ``set value'', where value is a number or a string, or ``on'' or ``off'', depending on the context. For example, if you want JOVE to make backup files, you set the ``make-backup-files'' variable to ``on''. To see the value of a variable, use the ``print '' command. .SH INITIALIZATION JOVE first reads the system-wide initialization file (/jove.rc) which provides reasonable defaults for your installation and loads standard macros. It will normally observe your TERM environment variable in order to provide terminal-specific key bindings and a map of your keyboard (see the standard ``keychart'' macro). .LP JOVE then automatically reads further commands from the initialization file called ``.joverc'' (``jove.rc'' under MSDOS) in your HOME directory. In this file you can place commands that you would normally type in JOVE. If you like to rearrange the key bindings and set some variables every time you get into JOVE, you should put them in your initialization file. Here are a few lines from mine: .nf set match-regular-expressions on 1 auto-execute-command auto-fill /tmp/Re\e|.*drft bind-to-key i-search-forward ^\e bind-to-key i-search-reverse ^R bind-to-key find-tag-at-point ^[^T bind-to-key scroll-down ^C bind-to-key grow-window ^Xg bind-to-key shrink-window ^Xs .fi (Note that the Control Characters can be either two character sequences (e.g. ^ and C together as ^C) or the actual control character. If you want to use an ^ by itself you must BackSlash it (e.g., bind-to-key grow-window ^X\e^ binds grow-window to ``^X^''). .SH ENVIRONMENT .LP If the variable .SB "LC_CTYPE" (see .BR environ (5)) is not set in the environment, the operational behavior of JOVE for the .SB "LC_CTYPE" locale category is determined by the value of the .SB LANG environment variable. If .SB LC_ALL is set, its contents are used to override both the .SB LANG and the .SB "LC_CTYPE" variable. If none of the above variables is set in the environment, the "C" (U.S. style) locale determines how JOVE behaves. .TP .SB LC_CTYPE Determines how JOVE handles characters. When .SB LC_CTYPE is set to a valid value, JOVE can display and handle text and filenames containing valid characters for that locale. In particular, characters will be correctly recognised as upper or lower case and displayed if printable. However JOVE cannot display or handle Extended Unix Code (EUC) characters which are more than 1 byte wide. In the "C" locale, only characters from 7-bit ASCII are valid (all characters with the eighth bit set being displayed in octal). In the "iso_8859_1" locale (if supported by the OS), the full Latin-1 alphabet is available. The JOVE variable ``lc-ctype'' can be used to change the locale while JOVE is running. .SH SOME MINOR DETAILS You should type ^\e instead of ^S in many instances. For example, the way to search for a string is documented as being ``^S'' but in reality you should type ``^\e''. This is because ^S is the XOFF character (what gets sent when you type the NO SCROLL key), and clearly that won't work. The XON character is ``^Q'' (what gets sent when you type NO SCROLL again) which is documented as the way to do a quoted-insert. The alternate key for this is ``^^'' (typed as ``^`'' on vt100's and its look-alikes). If you want to enable ^S and ^Q and you know what you are doing, you can put the line: .nf set allow-^S-and-^Q on .fi in your initialization file. .LP If your terminal has a metakey and you turn on the ``meta-key'' variable, JOVE will use it to generate commands which would otherwise start with an ESC. JOVE will automatically turn on ``meta-key'' if the METAKEY environment variable exists. This is useful for if you have different terminals (e.g., one at home and one at work) and one has a metakey and the other doesn't. However, if a locale which recognises 8-bit characters is in force, a metakey may be better used to generate the extra characters (so leave the ``meta-key'' variable off). .SH FILES .nf /jove.rc \(em system-wide initialization file .sp 0 /jove.rc.$TERM \(em terminal-specific initialization file .sp 0 /keychart.$TERM \(em terminal-specific help file .sp 0 /macros \(em standard macros file .sp 0 ~/.joverc \(em personal initialization file .sp 0 \(em where temporary files are stored .sp 0 /teach-jove \(em the interactive tutorial .sp 0 /recover \(em the recovery program .sp 0 /portsrv \(em for running shells in windows (pdp11 only) .SH ENVIRONMENT VARIABLES .nf TERM \(em your terminal type .sp 0 METAKEY \(em if defined, sets the ``meta-key'' variable .sp 0 SHELL \(em the shell to be used by the ``shell'' and other commands .sp 0 COMSPEC \(em (on MSDOS) used if SHELL is not defined .sp 0 MAIL \(em to initialize the ``mailbox'' variable .sp 0 JOVELIB \(em overrides unless overridden by \-l or \-ls .sp 0 JOVESHARE \(em overrides unless overridden by \-s or \-ls .sp 0 TMPDIR \(em overrides as directory for temporary files .sp 0 LC_ALL, LC_CTYPE, LANG \(em to set the locale .fi .SH SEE ALSO .nf ctags(1) \(em to generate tags for the find-tag command and the \-t command-line option .sp 0 ed(1) \(em for a description of regular expressions .sp 0 teachjove(1) \(em for an interactive JOVE tutorial. .fi .SH DIAGNOSTICS JOVE diagnostics are meant to be self-explanatory, but you are advised to seek help whenever you are confused. You can easily lose a lot of work if you don't know EXACTLY what you are doing. .SH BUGS Lines can't be more than 1024 characters long. .sp 1 Searches can't cross line boundaries. .SH AUTHOR Jonathan Payne jove-4.17.5.5/doc/jove.qref000066400000000000000000000136371501102521500153070ustar00rootroot00000000000000 JOVE Command Quick Reference Guide --- HELP apropos describe-bindings describe-command ESC ? describe-key ^X ? describe-variable execute-named-command ESC X --- MOVING AROUND backward-character ^B backward-list ESC ^P backward-paragraph ESC [ backward-s-expression ESC ^B backward-sentence ESC A backward-up-list ESC ^U backward-word ESC B beginning-of-file ESC < beginning-of-line ^A beginning-of-window ESC , current-error down-list ESC ^D end-of-file ESC > end-of-line ^E end-of-window ESC . find-tag ^X T find-tag-at-point first-non-blank ESC M forward-character ^F forward-list ESC ^N forward-paragraph ESC ] forward-s-expression ESC ^F forward-sentence ESC E forward-word ESC F goto-line ESC G next-error ^X ^N next-line ^N next-page ^V previous-error ^X ^P previous-line ^P previous-page ESC V window-find-tag ^X 4 t --- INSERTING AND DELETING delete-blank-lines ^X ^O delete-next-char ^D delete-previous-char ^H (DEL) delete-white-space ESC \ erase-buffer handle-tab ^I (TAB) kill-next-word ESC D kill-next-word ESC d kill-previous-word ESC ^? kill-s-expression ESC ^K kill-to-beginning-of-se ^X ^? kill-to-end-of-line ^K kill-to-end-of-sentence ESC K newline ^M (RETURN) newline-and-backup ^O newline-and-indent ^J over-write-mode quoted-insert ^^ --- SEARCH AND REPLACE find-tag ^X T find-tag-at-point i-search-forward i-search-reverse query-replace-string ESC Q replace-in-region replace-string ESC R search-forward ^\ search-reverse ^R window-find-tag ^X 4 t --- MARKS AND REGIONS append-region case-region-lower case-region-upper copy-region ESC W exchange-point-and-mark ^X ^X filter-region kill-region ^W replace-in-region set-mark ^@ (^SPACE) write-region yank ^Y yank-pop ESC Y --- TEXT PROCESSING auto-fill-mode bind-macro-to-word-abbr case-character-capitali case-region-lower case-region-upper case-word-capitalize ESC C case-word-lower ESC L case-word-upper ESC U current-error define-global-word-abbr define-mode-word-abbrev edit-word-abbrevs fill-paragraph ESC J fill-region left-margin-here next-error ^X ^N over-write-mode parse-spelling-errors-i previous-error ^X ^P read-word-abbrev-file right-margin-here spell-buffer text-mode transpose-characters ^T transpose-lines ^X ^T visible-spaces-in-windo word-abbrev-mode write-word-abbrev-file --- DISPLAY AND WINDOWS clear-and-redraw ESC ^L delete-current-window ^X D delete-current-window ^X d delete-other-windows ^X 1 grow-window ^X ^ next-window ^X N number-lines-in-window page-next-window ESC ^V previous-window ^X P redraw-display ^L scroll-down ESC Z scroll-up ^Z shrink-window split-current-window ^X 2 window-find-buffer ^X 4 b window-find-file ^X 4 f window-find-tag ^X 4 t --- FILES AND BUFFERS append-region append-region buffer-position delete-buffer ^X K delete-buffer ^X k erase-buffer find-file ^X ^F insert-file ^X ^I kill-buffer ^X K list-buffers ^X ^B make-buffer-unmodified ESC ~ read-macros-from-file read-word-abbrev-file rename-buffer save-file ^X ^\ save-file ^X ^S select-buffer ^X B select-existing-buffer ^X B spell-buffer visit-file ^X ^V visit-file ^X ^R window-find-buffer ^X 4 b window-find-file ^X 4 f write-file ^X ^W write-macros-to-file write-modified-files ^X ^M write-region write-word-abbrev-file --- DIRECTORIES cd dirs popd pushd pwd --- PROGRAMMERS auto-indent-mode backward-s-expression ESC ^B c-mode compile-it(make) ^X ^E current-error fill-comment forward-s-expression ESC ^F grind-s-expr kill-s-expression ESC ^K lisp-mode next-error ^X ^N number-lines-in-window paren-flash ),],} parse-errors parse-special-errors previous-error ^X ^P show-match-mode string-length visible-spaces-in-windo --- REPEAT digit ESC - digit ESC [0-9] gather-numeric-argument ^U --- MACROS delete-macro execute-keyboard-macro ^X E make-macro-interactive ESC I read-macros-from-file begin-kbd-macro ^X ( end-kbd-macro ^X ) write-macros-to-file --- SHELL exit-jove ^X ^C i-shell-command pause-jove ESC S pause-jove ESC s push-shell shell shell-command ^X ! shell-command-to-buffer suspend-jove --- PROCESSES eof-process interrupt-process ^C kill-process list-processes process-bind-to-key process-newline ^M (RETURN) process-send-data-no-re quit-process stop-process --- MISCELLANEOUS auto-execute-command auto-execute-macro bind-macro-to-key bind-macro-to-word-abbr bind-to-key character-to-octal-inse date execute-extended-comman ESC X fundamental-mode print recursive-edit ring-the-bell(ABORT) ^G set source version --- VARIABLES abort-char allow-^S-and-^Q allow-bad-characters-in-filenames auto-case-abbrev bad-filename-extensions c-argument-indentation c-indentation-increment case-ignore-search comment-format dbx-format-string disable-biff display-default-filenames display-filenames-with-bad-extensions enhanced-keyboard error-format-string error-window-size expand-environment-variables file-creation-mode files-should-end-with-newline highlight-attribute highlight-mark interrupt-character jove-compiled-with jove-features jove-linked-with lc-ctype left-margin lib-dir-pathname macify mail-check-frequency mailbox make-backup-files mark-threshold match-regular-expression meta-key mode-line mode-line-attribute mode-line-should-standout one-key-confirmation paragraph-delimiter-pattern paren-flash-delay process-prompt right-margin save-on-exit scroll-all-lines scroll-bar scroll-step scroll-width search-exit-char send-typeout-to-buffer share-dir-pathname shell shell-flags space-sentence-2 spell-command-format sync-frequency tab-width tag-file text-attribute tmp-file-pathname update-time-frequency use-i/d-char visible-bell wrap-process-lines wrap-search write-files-on-make xt-mouse jove-4.17.5.5/doc/jove.rc.3022000066400000000000000000000043341501102521500153350ustar00rootroot00000000000000# The 3022 is a vt220 clone made by Newbury in England. If anyone would be # kind enough to check this out on a genuine vt220, that would be much # appreciated. # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # F keys bind-to-key beginning-of-line ^[[17~ bind-to-key beginning-of-file ^[[18~ bind-to-key shrink-window ^[[19~ bind-to-key split-current-window ^[[20~ bind-to-key next-window ^[[21~ bind-to-key delete-other-window ^[[23~ bind-to-key grow-window ^[[24~ bind-to-key end-of-file ^[[25~ bind-to-key end-of-line ^[[26~ bind-macro-to-key keychart ^[[28~ bind-to-key delete-next-character ^[[29~ bind-to-key backward-word ^[[31~ bind-to-key set-mark ^[[32~ bind-to-key exchange-point-and-mark ^[[33~ bind-to-key forward-word ^[[34~ # PF keys, for compatibility with vt100 bind-to-key beginning-of-line ^[OP bind-to-key backward-word ^[OQ bind-to-key forward-word ^[OR bind-to-key end-of-line ^[OS bind-to-key split-current-window ^[^[OP bind-to-key next-window ^[^[OQ bind-to-key grow-window ^[^[OR bind-to-key delete-other-window ^[^[OS # Arrow keys bind-to-key backward-character ^[[D bind-to-key previous-line ^[[A bind-to-key next-line ^[[B bind-to-key forward-character ^[[C bind-to-key backward-character ^[OD bind-to-key previous-line ^[OA bind-to-key next-line ^[OB bind-to-key forward-character ^[OC # Inscribed Function keys bind-to-key search-forward ^[[1~ bind-to-key newline-and-backup ^[[2~ bind-macro-to-key kill-line ^[[3~ bind-to-key search-reverse ^[[4~ bind-to-key scroll-down ^[[5~ bind-to-key scroll-up ^[[6~ # Numeric Keypad keys bind-to-key yank ^[Ow bind-to-key copy-region ^[Ox bind-to-key kill-region ^[Oy bind-to-key previous-page ^[Om bind-to-key spell-buffer ^[Ot bind-to-key fill-paragraph ^[Ou bind-to-key auto-fill-mode ^[Ov bind-to-key next-page ^[Ol bind-to-key list-buffers ^[Oq bind-to-key select-buffer ^[Or bind-to-key find-file ^[Os bind-to-key shell ^[OM bind-to-key execute-named-command ^[Op bind-to-key over-write-mode ^[On # ESC codes for vt100 compatibility bind-to-key set-mark ^[^[Ow bind-to-key exchange-point-and-mark ^[^[Oy bind-to-key newline-and-backup ^[^[Oq bind-macro-to-key kill-line ^[^[Os jove-4.17.5.5/doc/jove.rc.in000066400000000000000000000114341501102521500153540ustar00rootroot00000000000000# Make changes to jove.rc.in (and not jove.rc) # # This standard system-wide initialization file provides various # reasonable defaults. However, it is probably best seen as a starting # point, with examples of interesting possibilities, from which # sysadmins can hack their own versions. pushlibd # This macro deletes the line containing the cursor. # It is used in several of the jove.rc.TERM files and is intended # for binding to the delete-line key on terminals which have it. # It is placed in the kill ring for subsequent yanking. define-macro kill-line ^[xbeginning-of-line^M^[xset-mark^M^[xnext-line^M^[xkill-region^M^[xpop-mark^M # Set fill mode when Jove is fired up automatically by certain # mail/news readers. 1 auto-execute-command auto-fill-mode /tmp/\{Re\|article\|rnmail\|pn\} # The following is if you prefer fill-mode to be on for all # files except the ones you want it off for (but on the other hand it could # be argued that defaults in editors should be the "least surprising" # alternative). # Sets auto-fill-mode for every file and then turns it off as required. # 1 auto-execute-command auto-fill-mode .* # 0 auto-execute-command auto-fill-mode .*\.[lcChyfp]$\|.*\.lisp$\|.*\.scm$\|.*\.c++$ # set various language modes. 1 auto-execute-command c-mode .*\.[cChy]$\|.*\.c++$ 1 auto-execute-command lisp-mode .*\.l$\|.*\.lisp$\|.*\.scm$ # all the languages need show-match-mode. 1 auto-execute-command show-match-mode .*\.[lcChyfp]$\|.*\.lisp$\|.*\.scm$\|.*\.c++$ # The following apply to shell windows. Note the use of ^C^C, ^C^D etc., # thus leaving ^D available for delete-next-character. # This conforms to current emacs usage. ifvar jove-features .*:iproc: process-bind-to-key interrupt-process ^C^C process-bind-to-key eof-process ^C^D process-bind-to-key quit-process ^C^\ process-bind-to-key stop-process ^C^Z process-bind-to-key dstop-process ^C^Y # A plethora of programs now unilaterally try to color # their output using ANSI color sequences, and all # have different ways to turn that off, sigh. iproc-env-export INSIDE_JOVE=iproc iproc-env-export TERM=dumb iproc-env-unset COLORTERM iproc-env-export LS_COLORS=none iproc-env-unset CLICOLOR iproc-env-export GREP_COLOR=never iproc-env-unset GREP_COLORS iproc-env-export GCC_COLORS="" iproc-env-export SYSTEMD_LOG_COLOR=false endif # since proc do not have a pty, fewer # programs produce color, not sure # if all these are needed. ifvar jove-features .*:proc: proc-env-export INSIDE_JOVE=proc proc-env-export LS_COLORS=none proc-env-unset CLICOLOR proc-env-export GREP_COLOR=never proc-env-unset GREP_COLORS proc-env-export GCC_COLORS="" proc-env-export SYSTEMD_LOG_COLOR=false # Uncomment to set TERM you find any programs producing # unreadable output in subshells via pipes. # proc-env-export TERM=dumb # gcc error messages have Unicode quote chars # if LANG or LC* are set to utf*, which is # typical for modern Linux. That is hard to # read inside Jove compile-it output. # (similarly, nroff produces Unicode hyphens) # LANG=C seems a more readable, albeit constraining # default for Jove subshells (at least, # till Jove gets to understand Unicode) proc-env-export LANG=C endif # This makes the arrow keys work on most terminals. bind-to-key previous-line ^[[A bind-to-key next-line ^[[B bind-to-key forward-character ^[[C bind-to-key backward-character ^[[D bind-to-key previous-line ^[OA bind-to-key next-line ^[OB bind-to-key forward-character ^[OC bind-to-key backward-character ^[OD # This causes the previous file version to remain as '#filename~'. # set make-backup-files on # If a terminal needs ^S/^Q for flow control, set allow-^S-and-^Q off # in jove.rc.TERM. Note that many things claiming to be vt100 # are now terminal emulators (e.g. NetBSD console), so be careful # turning it off. # source any TERMinal-specific rc file 1 source jove.rc.$TERM # Beginner help window and bindings (adopted from Jove Einsteiger Menue # in Debian package, original by Gerold Meerkoetter) define-macro help-window ^[xselect-buffer *Beginner_Help*^M^[xpushlibd^M^[xinsert-file jem.txt^M^[xmake-buffer-unmodified^M^[xread-only-mode^M^[xwindow-find^Mb^M^[7^[xgrow-window^M^[xpopd^M auto-execute-command delete-other-windows .*/\{teach-jove\|teachjov.txt\} bind-to-key teach-jove ^[t bind-to-key apropos ^Xa ifenv JOVENOHELP 1 else ifvar jove-features .*:unix:.*:proc: if sh -c 'test ! -f $HOME/.joverc' execute-macro help-window endif else execute-macro help-window endif endif # source local custom rc file, if present # This might be convenient for system admins # making customizations across their entire domain 1 source jove-local.rc popd # source local host rc file, if present # This might be convenient for customizations for a specific # machine. 1 source __ETCDIR__/jove.rc jove-4.17.5.5/doc/jove.rc.sun000066400000000000000000000115431501102521500155540ustar00rootroot00000000000000# xjove (and JoveTool) mouse bindings: # # button 1: # down, double-click down, triple-click down, drag while 1 down: # xj-mouse-point [set point to mouse location] # up (any number of clicks): # xj-mouse-yank [set point to mouse location; yank if CTRL held] # button 2: # down, drag while 2 down: # xj-mouse-mark [set point and mark to mouse location] # double-click down: # xj-mouse-word [undo preceding mouse-copy-cut; set mark to end of # word designated by mouse; set point to start of word] # triple-click down: # xj-mouse-word [undo preceding mouse-copy-cut; set mark to end of # line designated by mouse; set point to start of line] # up (any number of clicks): # xj-mouse-copy-cut [copy region if CTRL pressed; # delete region if CTRL+SHIFT pressed] # button 3: # not available bind-to-key xj-mouse-point ^Xm0 bind-to-key xj-mouse-point ^Xm1 bind-to-key xj-mouse-point ^Xm2 bind-to-key xj-mouse-yank ^Xm3 bind-to-key xj-mouse-point ^Xm4 bind-to-key xj-mouse-mark ^Xm5 bind-to-key xj-mouse-word ^Xm6 bind-to-key xj-mouse-line ^Xm7 bind-to-key xj-mouse-copy-cut ^Xm8 bind-to-key xj-mouse-point ^Xm9 # The following bindings are designed for the Sun Type 4 Keyboard. # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # For the Type 5 keyboard it so happens that all the extra keys, under the # default xmodmap, are simply duplicates of other keys on the keyboard (except # that they still have their effects even when Num Lock is on). So my binding # still works sensibly, except for the missing KP_Subtract key. # Note that the files jove.rc.sun and jove.rc.sun-cmd should be identical, # and preferably hard-linked together. # The following general principles were followed in designing this binding: # 1. Groupings of keys that are found in bindings for other terminals # should be adhered to so far as possible. # 2. Keys which do related things should be close together. # 3. Keys which do certain things under Sun editors (notably textedit) # should do the same (or similar) things under jove. # 4. Keys which have suggestive engravings on them should do what the # engravings suggest. # Thus KP_0 ("Ins") and KP_Point ("Del") are used to insert and delete # lines. Since 9 of the 15 R keys were already associated with cursor # movement or scrolling, it seemed right to make the remaining 6 do # likewise. # However, having said all that, these bindings are only illustrative # suggestions, and local sysadmins may well wish to change them. # arrow keys, using their xjove bindings bind-to-key backward-character ^[[217z bind-to-key previous-line ^[[215z bind-to-key next-line ^[[221z bind-to-key forward-character ^[[219z # L keys bind-to-key over-write-mode ^[[192z bind-to-key auto-fill-mode ^[[193z bind-to-key set-mark ^[[194z bind-to-key exchange-point-and-mark ^[[195z bind-to-key copy-region ^[[197z bind-to-key yank ^[[199z bind-to-key search-forward ^[[200z bind-to-key search-reverse ^[^[[200z bind-to-key kill-region ^[[201z # Help key (xjove only) bind-macro-to-key keychart ^[[202z # F keys bind-to-key execute-named-command ^[[224z bind-to-key split-current-window ^[[225z bind-to-key next-window ^[[226z bind-to-key delete-other-window ^[[227z bind-to-key delete-current-window ^[[228z bind-to-key grow-window ^[[229z bind-to-key spell-buffer ^[[230z bind-to-key fill-comment ^[[231z bind-to-key fill-paragraph ^[[232z bind-to-key list-buffers ^[[233z bind-to-key select-buffer ^[[234z bind-to-key find-file ^[[235z # On the Type 4 keyboard the Backspace key is right below Delete and, in the # default Jove bindings these both do delete-previous-character. They would # make a fine pair with one to delete forward and one to delete backward. # For historical reasons, we leave them both as delete backward, but # recommend that the adventurous (or IBM PC acculturated) enable these. # bind-to-key delete-next-character ^? # bind-to-key kill-next-word ^[^? # R keys (these are all associated with cursor movement or scrolling) bind-to-key beginning-of-line ^[[208z bind-to-key backward-list ^[[209z bind-to-key backward-word ^[[210z bind-to-key end-of-line ^[[211z bind-to-key forward-list ^[[212z bind-to-key forward-word ^[[213z bind-to-key beginning-of-file ^[[214z bind-to-key previous-page ^[[216z # This moves the cursor to the start of the next line. define-macro newline-and-beginning ^A^N bind-macro-to-key newline-and-beginning ^[[218z bind-to-key end-of-file ^[[220z bind-to-key next-page ^[[222z # The following are only available with xjove. # KP_0 (engraved "Ins") bind-to-key newline-and-backup ^[[247z # KP_Point (engraved "Del") bind-macro-to-key kill-line ^[[249z # KP_Enter bind-to-key shell ^[[250z # KP_Add bind-to-key scroll-up ^[[253z # KP_Subtract bind-to-key scroll-down ^[[254z # It is presumed Sun users will normally use xjove. Hence: set scroll-bar on jove-4.17.5.5/doc/jove.rc.sun-cmd000066400000000000000000000115431501102521500163150ustar00rootroot00000000000000# xjove (and JoveTool) mouse bindings: # # button 1: # down, double-click down, triple-click down, drag while 1 down: # xj-mouse-point [set point to mouse location] # up (any number of clicks): # xj-mouse-yank [set point to mouse location; yank if CTRL held] # button 2: # down, drag while 2 down: # xj-mouse-mark [set point and mark to mouse location] # double-click down: # xj-mouse-word [undo preceding mouse-copy-cut; set mark to end of # word designated by mouse; set point to start of word] # triple-click down: # xj-mouse-word [undo preceding mouse-copy-cut; set mark to end of # line designated by mouse; set point to start of line] # up (any number of clicks): # xj-mouse-copy-cut [copy region if CTRL pressed; # delete region if CTRL+SHIFT pressed] # button 3: # not available bind-to-key xj-mouse-point ^Xm0 bind-to-key xj-mouse-point ^Xm1 bind-to-key xj-mouse-point ^Xm2 bind-to-key xj-mouse-yank ^Xm3 bind-to-key xj-mouse-point ^Xm4 bind-to-key xj-mouse-mark ^Xm5 bind-to-key xj-mouse-word ^Xm6 bind-to-key xj-mouse-line ^Xm7 bind-to-key xj-mouse-copy-cut ^Xm8 bind-to-key xj-mouse-point ^Xm9 # The following bindings are designed for the Sun Type 4 Keyboard. # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # For the Type 5 keyboard it so happens that all the extra keys, under the # default xmodmap, are simply duplicates of other keys on the keyboard (except # that they still have their effects even when Num Lock is on). So my binding # still works sensibly, except for the missing KP_Subtract key. # Note that the files jove.rc.sun and jove.rc.sun-cmd should be identical, # and preferably hard-linked together. # The following general principles were followed in designing this binding: # 1. Groupings of keys that are found in bindings for other terminals # should be adhered to so far as possible. # 2. Keys which do related things should be close together. # 3. Keys which do certain things under Sun editors (notably textedit) # should do the same (or similar) things under jove. # 4. Keys which have suggestive engravings on them should do what the # engravings suggest. # Thus KP_0 ("Ins") and KP_Point ("Del") are used to insert and delete # lines. Since 9 of the 15 R keys were already associated with cursor # movement or scrolling, it seemed right to make the remaining 6 do # likewise. # However, having said all that, these bindings are only illustrative # suggestions, and local sysadmins may well wish to change them. # arrow keys, using their xjove bindings bind-to-key backward-character ^[[217z bind-to-key previous-line ^[[215z bind-to-key next-line ^[[221z bind-to-key forward-character ^[[219z # L keys bind-to-key over-write-mode ^[[192z bind-to-key auto-fill-mode ^[[193z bind-to-key set-mark ^[[194z bind-to-key exchange-point-and-mark ^[[195z bind-to-key copy-region ^[[197z bind-to-key yank ^[[199z bind-to-key search-forward ^[[200z bind-to-key search-reverse ^[^[[200z bind-to-key kill-region ^[[201z # Help key (xjove only) bind-macro-to-key keychart ^[[202z # F keys bind-to-key execute-named-command ^[[224z bind-to-key split-current-window ^[[225z bind-to-key next-window ^[[226z bind-to-key delete-other-window ^[[227z bind-to-key delete-current-window ^[[228z bind-to-key grow-window ^[[229z bind-to-key spell-buffer ^[[230z bind-to-key fill-comment ^[[231z bind-to-key fill-paragraph ^[[232z bind-to-key list-buffers ^[[233z bind-to-key select-buffer ^[[234z bind-to-key find-file ^[[235z # On the Type 4 keyboard the Backspace key is right below Delete and, in the # default Jove bindings these both do delete-previous-character. They would # make a fine pair with one to delete forward and one to delete backward. # For historical reasons, we leave them both as delete backward, but # recommend that the adventurous (or IBM PC acculturated) enable these. # bind-to-key delete-next-character ^? # bind-to-key kill-next-word ^[^? # R keys (these are all associated with cursor movement or scrolling) bind-to-key beginning-of-line ^[[208z bind-to-key backward-list ^[[209z bind-to-key backward-word ^[[210z bind-to-key end-of-line ^[[211z bind-to-key forward-list ^[[212z bind-to-key forward-word ^[[213z bind-to-key beginning-of-file ^[[214z bind-to-key previous-page ^[[216z # This moves the cursor to the start of the next line. define-macro newline-and-beginning ^A^N bind-macro-to-key newline-and-beginning ^[[218z bind-to-key end-of-file ^[[220z bind-to-key next-page ^[[222z # The following are only available with xjove. # KP_0 (engraved "Ins") bind-to-key newline-and-backup ^[[247z # KP_Point (engraved "Del") bind-macro-to-key kill-line ^[[249z # KP_Enter bind-to-key shell ^[[250z # KP_Add bind-to-key scroll-up ^[[253z # KP_Subtract bind-to-key scroll-down ^[[254z # It is presumed Sun users will normally use xjove. Hence: set scroll-bar on jove-4.17.5.5/doc/jove.rc.vt100000066400000000000000000000025721501102521500156230ustar00rootroot00000000000000# This is the genuine, original, vt100 # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # PF keys bind-to-key backward-word ^[OP bind-to-key forward-word ^[OQ bind-to-key beginning-of-line ^[OR bind-to-key end-of-line ^[OS # ESCaped versions bind-to-key split-current-window ^[^[OP bind-to-key next-window ^[^[OQ bind-to-key delete-other-window ^[^[OR bind-to-key grow-window ^[^[OS # Arrow keys bind-to-key backward-character ^[OD bind-to-key previous-line ^[OA bind-to-key next-line ^[OB bind-to-key forward-character ^[OC # Numeric Keypad bind-to-key yank ^[Ow bind-to-key copy-region ^[Ox bind-to-key kill-region ^[Oy bind-to-key previous-page ^[Om bind-to-key spell-buffer ^[Ot bind-to-key fill-paragraph ^[Ou bind-to-key auto-fill-mode ^[Ov bind-to-key next-page ^[Ol bind-to-key list-buffers ^[Oq bind-to-key select-buffer ^[Or bind-to-key find-file ^[Os bind-to-key shell ^[OM bind-to-key execute-named-command ^[Op bind-to-key over-write-mode ^[On # ESCaped versions bind-to-key set-mark ^[^[Ow bind-to-key exchange-point-and-mark ^[^[Oy bind-to-key newline-and-backup ^[^[Oq bind-macro-to-key kill-line ^[^[Os # Real vt100 might have needed flow control to throttle # output from the computer, but unlikely to be needed # for any modern vt100-emulator. # set allow-^S-and-^Q off jove-4.17.5.5/doc/jove.rc.wyse000066400000000000000000000044701501102521500157370ustar00rootroot00000000000000# A vt220 clone made by Wyse # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # Note that the terminal has to be correctly configured before these bindings # will work. A string of characters to fire at the terminal to achieve this # is included at the end of the file keychart.wyse (also another string to # deconfigure it). It may be convenient to call 'jove' by means of a wrapper # shell script which automatically configures the terminal before calling jove # (and maybe deconfigues it after). # F keys bind-to-key beginning-of-line ^[OA bind-to-key beginning-of-file ^[OB bind-to-key shrink-window ^[OC bind-to-key split-current-window ^[OD bind-to-key next-window ^[OE bind-to-key delete-other-window ^[OF bind-to-key grow-window ^[OG bind-to-key end-of-file ^[OH bind-to-key end-of-line ^[OI bind-macro-to-key keychart ^[OJ bind-to-key backward-word ^[OT bind-to-key set-mark ^[OU bind-to-key exchange-point-and-mark ^[OV bind-to-key forward-word ^[OW # PF keys, for compatibility with vt100 bind-to-key beginning-of-line ^[OP bind-to-key backward-word ^[OQ bind-to-key forward-word ^[OR bind-to-key end-of-line ^[OS bind-to-key split-current-window ^[^[OP bind-to-key next-window ^[^[OQ bind-to-key grow-window ^[^[OR bind-to-key delete-other-window ^[^[OS # Arrow keys bind-to-key backward-character ^[[D bind-to-key previous-line ^[[A bind-to-key next-line ^[[B bind-to-key forward-character ^[[C # Inscribed Function keys bind-to-key search-forward ^[[1~ bind-to-key newline-and-backup ^[[2~ bind-macro-to-key kill-line ^[[3~ bind-to-key search-reverse ^[[4~ bind-to-key scroll-down ^[[5~ bind-to-key scroll-up ^[[6~ # Numeric Keypad keys bind-to-key yank ^[Ow bind-to-key copy-region ^[Ox bind-to-key kill-region ^[Oy bind-to-key previous-page ^[Om bind-to-key spell-buffer ^[Ot bind-to-key fill-paragraph ^[Ou bind-to-key auto-fill-mode ^[Ov bind-to-key next-page ^[Ol bind-to-key list-buffers ^[Oq bind-to-key select-buffer ^[Or bind-to-key find-file ^[Os bind-to-key shell ^[OM bind-to-key execute-named-command ^[Op bind-to-key over-write-mode ^[On # ESC codes for vt100 compatibility bind-to-key set-mark ^[^[Ow bind-to-key exchange-point-and-mark ^[^[Oy bind-to-key newline-and-backup ^[^[Oq bind-macro-to-key kill-line ^[^[Os jove-4.17.5.5/doc/jove.rc.xterm000066400000000000000000000172061501102521500161100ustar00rootroot00000000000000# The following bindings should work with most keyboards when used # with the 'xterm' terminal emulator. There are two sets of bindings of # function keys within 'xterm' that are commonly used on Suns, one emulating # the customary Sun bindings and the other being more vt220-like. The # following binding will work with either of them. Note: in the preceding, # "binding" means the characters sent by xterm to the program in response # to keystrokes. # # We try to accomodate the mutations of xterm in XFree86 and its successors. # F1-F3, Delete, Home, End, and the 5-key in the keyapad generate novel sequences. # Xterm Mouse Bindings # # If its program enables the mode, xterm will send the client character # sequences signifying certain mouse events. JOVE will enable this mode # while it is running if the xt-mouse variable is on. set xt-mouse on # JOVE decodes the resulting character sequences using its normal # key binding techiques. These bindings invoke certain commands designed # to process mouse events. Here we have two set of bindings: one # makes mouse actions behave analogously to those in xterm; the other # is more like OpenLook. One should be suppressed via commenting. # # Bindings to give other "looks and feels" are possible, except for # operations marked 'button 1 ONLY' below. Those operations involving # use of CTRL require the special translation table contained in the # file 'XTermresource'. # Xterm "Look and Feel" Bindings: # # button 1: # down with no modifiers: # xt-mouse-point [set point to mouse location] # down with CTRL held: # xt-mouse-mark [set point and mark to mouse location] # button 2: # down with no modifiers: # xt-mouse-point-yank [yank at mouse location] # [weaker but more xterm-like binding: xt-mouse-yank for yank at point] # down with CTRL held: # xt-mouse-cut-point-yank [delete region and yank at mouse location] # button 3: # down with no modifiers: # xt-mouse-extend [extend copied region and re-copy] # down with CTRL held: # xt-mouse-null # button up: # up after drag: [button 1 ONLY] # xt-mouse-mark-drag-point-copy [set region and copy] # other button up: # xt-mouse-null # button 1 down [note that the next line has a SPace at the end] bind-to-key xt-mouse-point ^[[M bind-to-key xt-mouse-mark ^[[M0 # button 2 down # less powerful but more xterm-like: bind-to-key xt-mouse-yank ^[[M! bind-to-key xt-mouse-point-yank ^[[M! bind-to-key xt-mouse-cut-point-yank ^[[M1 # button 3 down bind-to-key xt-mouse-extend ^[[M" bind-to-key xt-mouse-null ^[[M2 # button 1 up after drag and/or multiclick bind-to-key xt-mouse-mark-drag-point-copy ^[[T bind-to-key xt-mouse-mark-drag-point-copy ^[[t # other button releases bind-to-key xt-mouse-null ^[[M# bind-to-key xt-mouse-null ^[[M3 # End of xterm "look and feel" bindings. ## OpenLook "Look and Feel" Bindings: ## ## The differences are in buttons 2 and 3. ## ## button 1: ## down with no modifiers: ## xt-mouse-point [set point to mouse location] ## down with CTRL held: ## xt-mouse-mark [set point and mark to mouse location] ## button 2: ## down with no modifiers: ## xt-mouse-extend [extend copied region and re-copy] ## down with CTRL held: ## xt-mouse-point-yank [yank at mouse location] ## button 3: ## down with no modifiers: ## xt-mouse-null ## down with CTRL held: ## xt-mouse-cut-point-yank [delete region and yank at mouse location] ## button up: ## up after drag: [button 1 ONLY] ## xt-mouse-mark-drag-point-copy [set region and copy] ## other button up: ## xt-mouse-null # ## button 1 down [note that the next line has a SPace at the end] #bind-to-key xt-mouse-point ^[[M #bind-to-key xt-mouse-mark ^[[M0 # ## button 2 down #bind-to-key xt-mouse-extend ^[[M! #bind-to-key xt-mouse-point-yank ^[[M1 # ## button 3 down #bind-to-key xt-mouse-null ^[[M" #bind-to-key xt-mouse-cut-point-yank ^[[M2 # ## button 1 up after drag and/or multiclick #bind-to-key xt-mouse-mark-drag-point-copy ^[[T #bind-to-key xt-mouse-mark-drag-point-copy ^[[t # ## other button releases #bind-to-key xt-mouse-null ^[[M# #bind-to-key xt-mouse-null ^[[M3 # ## End of OpenLook "look and feel" bindings. # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # See the file jove.rc.sun(-cmd) for further details of this binding, and # for reasons why it is as it is. # Arrow keys bind-to-key backward-character ^[[D bind-to-key previous-line ^[[A bind-to-key next-line ^[[B bind-to-key forward-character ^[[C bind-to-key backward-character ^[OD bind-to-key previous-line ^[OA bind-to-key next-line ^[OB bind-to-key forward-character ^[OC # L keys bind-to-key over-write-mode ^[[192z bind-to-key auto-fill-mode ^[[193z bind-to-key set-mark ^[[194z bind-to-key set-mark ^[[25~ bind-to-key exchange-point-and-mark ^[[195z bind-to-key exchange-point-and-mark ^[[26~ bind-to-key copy-region ^[[197z bind-to-key copy-region ^[[29~ bind-to-key yank ^[[199z bind-to-key yank ^[[32~ bind-to-key search-forward ^[[200z bind-to-key search-forward ^[[33~ bind-to-key search-forward ^[[1~ bind-to-key search-reverse ^[^[[200z bind-to-key search-reverse ^[^[[33~ bind-to-key search-reverse ^[^[[1~ bind-to-key kill-region ^[[201z bind-to-key kill-region ^[[34~ # Help key bind-macro-to-key keychart ^[[202z # F keys bind-to-key execute-named-command ^[[224z bind-to-key execute-named-command ^[[11~ bind-to-key execute-named-command ^[OP bind-to-key split-current-window ^[[225z bind-to-key split-current-window ^[[12~ bind-to-key split-current-window ^[OQ bind-to-key next-window ^[[226z bind-to-key next-window ^[[13~ bind-to-key next-window ^[OR bind-to-key delete-other-window ^[[227z bind-to-key delete-other-window ^[[14~ bind-to-key delete-other-window ^[OS bind-to-key delete-current-window ^[[228z bind-to-key delete-current-window ^[[15~ bind-to-key grow-window ^[[229z bind-to-key grow-window ^[[17~ bind-to-key spell-buffer ^[[230z bind-to-key spell-buffer ^[[18~ bind-to-key fill-comment ^[[231z bind-to-key fill-comment ^[[19~ bind-to-key fill-paragraph ^[[232z bind-to-key fill-paragraph ^[[20~ bind-to-key list-buffers ^[[233z bind-to-key list-buffers ^[[21~ bind-to-key select-buffer ^[[234z bind-to-key select-buffer ^[[23~ bind-to-key find-file ^[[235z bind-to-key find-file ^[[24~ # On many keyboards the Backspace key is near Delete and, in the # default Jove bindings these both do delete-previous-character. They would # make a fine pair with one to delete forward and one to delete backward. # For historical reasons, we leave them both as delete backward, but # recommend that the adventurous (or IBM PC acculturated) enable these. # bind-to-key delete-next-character ^? # bind-to-key kill-next-word ^[^? bind-to-key delete-previous-character ^[[3~ # R keys (these are all associated with cursor movement or scrolling) bind-to-key unbound ^[[208z bind-to-key beginning-of-line ^[[209z bind-to-key beginning-of-file ^[OH bind-to-key end-of-line ^[[210z bind-to-key unbound ^[[211z bind-to-key backward-word ^[[212z bind-to-key forward-word ^[[213z bind-to-key beginning-of-file ^[[214z bind-to-key beginning-of-file ^[[41~ bind-to-key previous-page ^[[216z bind-to-key previous-page ^[[5~ # This moves the cursor to the start of the next line. define-macro newline-and-beginning ^A^N bind-macro-to-key newline-and-beginning ^[[218z bind-macro-to-key newline-and-beginning ^[OE bind-to-key end-of-file ^[[220z bind-to-key end-of-file ^[OF bind-to-key next-page ^[[222z bind-to-key next-page ^[[6~ # KP_0 (engraved "Ins") bind-to-key newline-and-backup ^[[2~ # KP_Point (engraved "Del") bind-macro-to-key kill-line ^[[249z # KP_Enter bind-to-key shell ^[[250z # KP_Add bind-to-key scroll-up ^[[253z # KP_Subtract bind-to-key scroll-down ^[[254z set scroll-bar on jove-4.17.5.5/doc/jove.rc.xterm-256color000066400000000000000000000145261501102521500174630ustar00rootroot00000000000000# The following bindings should work with most keyboards when used # with the 'xterm' terminal emulator. There are two sets of bindings of # function keys within 'xterm' that are commonly used on Suns, one emulating # the customary Sun bindings and the other being more vt220-like. The # following binding will work with either of them. Note: in the preceding, # "binding" means the characters sent by xterm to the program in response # to keystrokes. # # We try to accomodate the mutations of xterm in XFree86 and its successors. # F1-F3, Delete, Home, End, and the 5-key in the keyapad generate novel sequences. # Xterm Mouse Bindings # # If its program enables the mode, xterm will send the client character # sequences signifying certain mouse events. JOVE will enable this mode # while it is running if the xt-mouse variable is on. set xt-mouse on # JOVE decodes the resulting character sequences using its normal # key binding techiques. These bindings invoke certain commands designed # to process mouse events. Here we have two set of bindings: one # makes mouse actions behave analogously to those in xterm; the other # is more like OpenLook. One should be suppressed via commenting. # # Bindings to give other "looks and feels" are possible, except for # operations marked 'button 1 ONLY' below. Those operations involving # use of CTRL require the special translation table contained in the # file 'XTermresource'. # Xterm "Look and Feel" Bindings: # # button 1: # down with no modifiers: # xt-mouse-point [set point to mouse location] # down with CTRL held: # xt-mouse-mark [set point and mark to mouse location] # button 2: # down with no modifiers: # xt-mouse-point-yank [yank at mouse location] # [weaker but more xterm-like binding: xt-mouse-yank for yank at point] # down with CTRL held: # xt-mouse-cut-point-yank [delete region and yank at mouse location] # button 3: # down with no modifiers: # xt-mouse-extend [extend copied region and re-copy] # down with CTRL held: # xt-mouse-null # button up: # up after drag: [button 1 ONLY] # xt-mouse-mark-drag-point-copy [set region and copy] # other button up: # xt-mouse-null # button 1 down [note that the next line has a SPace at the end] bind-to-key xt-mouse-point ^[[M bind-to-key xt-mouse-mark ^[[M0 # button 2 down # less powerful but more xterm-like: bind-to-key xt-mouse-yank ^[[M! bind-to-key xt-mouse-point-yank ^[[M! bind-to-key xt-mouse-cut-point-yank ^[[M1 # button 3 down bind-to-key xt-mouse-extend ^[[M" bind-to-key xt-mouse-null ^[[M2 # button 1 up after drag and/or multiclick bind-to-key xt-mouse-mark-drag-point-copy ^[[T bind-to-key xt-mouse-mark-drag-point-copy ^[[t # other button releases bind-to-key xt-mouse-null ^[[M# bind-to-key xt-mouse-null ^[[M3 # End of xterm "look and feel" bindings. # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # See the file jove.rc.sun(-cmd) for further details of this binding, and # for reasons why it is as it is. # Arrow keys bind-to-key backward-character ^[[D bind-to-key previous-line ^[[A bind-to-key next-line ^[[B bind-to-key forward-character ^[[C bind-to-key backward-character ^[OD bind-to-key previous-line ^[OA bind-to-key next-line ^[OB bind-to-key forward-character ^[OC # L keys bind-to-key over-write-mode ^[[192z bind-to-key auto-fill-mode ^[[193z bind-to-key set-mark ^[[194z bind-to-key set-mark ^[[25~ bind-to-key exchange-point-and-mark ^[[195z bind-to-key exchange-point-and-mark ^[[26~ bind-to-key copy-region ^[[197z bind-to-key copy-region ^[[29~ bind-to-key yank ^[[199z bind-to-key yank ^[[32~ bind-to-key search-forward ^[[200z bind-to-key search-forward ^[[33~ bind-to-key search-forward ^[[1~ bind-to-key search-reverse ^[^[[200z bind-to-key search-reverse ^[^[[33~ bind-to-key search-reverse ^[^[[1~ bind-to-key kill-region ^[[201z bind-to-key kill-region ^[[34~ # Help key bind-macro-to-key keychart ^[[202z # F keys bind-to-key execute-named-command ^[[224z bind-to-key execute-named-command ^[[11~ bind-to-key execute-named-command ^[OP bind-to-key split-current-window ^[[225z bind-to-key split-current-window ^[[12~ bind-to-key split-current-window ^[OQ bind-to-key next-window ^[[226z bind-to-key next-window ^[[13~ bind-to-key next-window ^[OR bind-to-key delete-other-window ^[[227z bind-to-key delete-other-window ^[[14~ bind-to-key delete-other-window ^[OS bind-to-key delete-current-window ^[[228z bind-to-key delete-current-window ^[[15~ bind-to-key grow-window ^[[229z bind-to-key grow-window ^[[17~ bind-to-key spell-buffer ^[[230z bind-to-key spell-buffer ^[[18~ bind-to-key fill-comment ^[[231z bind-to-key fill-comment ^[[19~ bind-to-key fill-paragraph ^[[232z bind-to-key fill-paragraph ^[[20~ bind-to-key list-buffers ^[[233z bind-to-key list-buffers ^[[21~ bind-to-key select-buffer ^[[234z bind-to-key select-buffer ^[[23~ bind-to-key find-file ^[[235z bind-to-key find-file ^[[24~ # On many keyboards the Backspace key is near Delete and, in the # default Jove bindings these both do delete-previous-character. They would # make a fine pair with one to delete forward and one to delete backward. # For historical reasons, we leave them both as delete backward, but # recommend that the adventurous (or IBM PC acculturated) enable these. # bind-to-key delete-next-character ^? # bind-to-key kill-next-word ^[^? bind-to-key delete-previous-character ^[[3~ # R keys (these are all associated with cursor movement or scrolling) bind-to-key unbound ^[[208z bind-to-key beginning-of-line ^[[209z bind-to-key beginning-of-file ^[OH bind-to-key end-of-line ^[[210z bind-to-key unbound ^[[211z bind-to-key backward-word ^[[212z bind-to-key forward-word ^[[213z bind-to-key beginning-of-file ^[[214z bind-to-key beginning-of-file ^[[41~ bind-to-key previous-page ^[[216z bind-to-key previous-page ^[[5~ # This moves the cursor to the start of the next line. define-macro newline-and-beginning ^A^N bind-macro-to-key newline-and-beginning ^[[218z bind-macro-to-key newline-and-beginning ^[OE bind-to-key end-of-file ^[[220z bind-to-key end-of-file ^[OF bind-to-key next-page ^[[222z bind-to-key next-page ^[[6~ # KP_0 (engraved "Ins") bind-to-key newline-and-backup ^[[2~ # KP_Point (engraved "Del") bind-macro-to-key kill-line ^[[249z # KP_Enter bind-to-key shell ^[[250z # KP_Add bind-to-key scroll-up ^[[253z # KP_Subtract bind-to-key scroll-down ^[[254z set scroll-bar on jove-4.17.5.5/doc/jove.rc.z29000066400000000000000000000024361501102521500153740ustar00rootroot00000000000000# This is the Zenith z29 terminal # define macro to display TERMinal-specific keychart file define-macro keychart ^[xpushlibd^M^U^[xshell-command-with-typeout cat keychart.$TERM^M^[xpopd^M # F keys bind-to-key beginning-of-line ^[OS bind-to-key beginning-of-file ^[OT bind-to-key shrink-window ^[OU bind-to-key split-current-window ^[OV bind-to-key next-window ^[OW bind-to-key delete-other-window ^[OP bind-to-key grow-window ^[OQ bind-to-key end-of-file ^[OR bind-to-key end-of-line ^[OX bind-macro-to-key keychart ^[[~ bind-to-key backward-word ^[[H bind-to-key backward-character ^[[D bind-to-key previous-line ^[[A bind-to-key next-line ^[[B bind-to-key forward-character ^[[C bind-to-key forward-word ^[[J # Numeric Keypad bind-to-key yank ^[Ow bind-to-key copy-region ^[Ox bind-to-key kill-region ^[Oy bind-to-key previous-page ^[Om bind-to-key spell-buffer ^[Ot bind-to-key fill-paragraph ^[Ou bind-to-key auto-fill-mode ^[Ov bind-to-key next-page ^[Ol bind-to-key list-buffers ^[Oq bind-to-key select-buffer ^[Or bind-to-key find-file ^[Os bind-to-key shell ^[OM bind-to-key execute-named-command ^[Op bind-to-key over-write-mode ^[On # Numeric Keypad SHIFTED bind-to-key set-mark ^[[4h bind-to-key exchange-point-and-mark ^[[P bind-to-key newline-and-backup ^[[L bind-macro-to-key kill-line ^[[M jove-4.17.5.5/doc/jovetool.nr000066400000000000000000000000341501102521500156520ustar00rootroot00000000000000.so /xjove. jove-4.17.5.5/doc/keychart.3022000066400000000000000000000136761501102521500156120ustar00rootroot00000000000000 F6 F7 F8 F9 F10 F11 F12 F13 F14 Beg of Beg of Shrink Split Switch Kill Enlarge End of End of LINE FILE WINDOW WINDOW WINDOW Other WINDOW FILE LINE WINDOW Help Do F17 F18 F19 F20 HELP DELETE Left Set Exch Right Next Ch WORD MARK . & m WORD Find Insert Remove Select Prev Next SEARCH Insert Delete SEARCH SCROLL SCROLL Fwd LINE LINE Bwd Down Up Numeric pad: 7 8 9 - YANK COPY KILL Page Region Region DOWN 4 5 6 , SPELL FILL Fill-m Page Para Toggle UP 1 2 3 ENTER List Select Find | BUFFERs BUFFER FILE | SHELL --- 0 --- . | COMMAND OvrWT | Toggle The following are included solely for compatibility with vt100 and mac terminals. PF1 PF2 PF3 PF4 Beg of Left Right End of LINE WORD WORD LINE with ESC ---> Split Switch Enlarge Kill WINDOW WINDOW WINDOW Other WINDOW Numeric pad, with ESC ---> 7 (IC) ---- 9 (DC) ----- Set Exch MARK . & m ---- ---- ---- ----- 1 (IL) ---- 3 (DL) | Insert Delete | LINE LINE | | --------- ----- | LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D (delt-next-char) delt-curr-wind kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) forw-list O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) back-list Q quoted-insert query-repl-str R search-reverse visit-file repl-string S (search-forw) save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z (scroll-up) (scroll-down) CTRL ESC & CHARACTER ^\ (search-forw) ESC , begin-wind ^~ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < begin-file ESC > end-file ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro DEL delt-prev-char ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent TERMINAL SETUP Press SET UP Move cursor to 'Default' Press Enter (NOT Return) The terminal is now set up in its default state, but it will not work with UNIX this way. Move cursor to 'Comm' and Press Enter Move cursor to '8 Bits, No Parity' Press Enter until it reads '7 Bits, Even Parity, No check' Move cursor to 'XOFF at 64' Press Enter until it reads 'No XOFF' Move cursor to 'To Directory' and Press Enter Cursor should be on 'Display'; Press Enter Move cursor to 'Smooth Scroll' and Press Enter Move cursor to 'To Directory' and Press Enter Move cursor to 'Save' and Press Enter This saves all the settings in non-volatile memory, so you need never do SETUP again Press SET UP to get back to normal operation jove-4.17.5.5/doc/keychart.sun000066400000000000000000000122711501102521500160170ustar00rootroot00000000000000 F1 F2 F3 F4 F5 F6 F7 F8 F9 ___ Jove Split Next Delete Delete Enlarge Spell Fill Fill \ COMMAND WINDOW WINDOW Other Current WINDOW Buffer Comment Para ] WINDOWs WINDOW / <-----' F10 F11 F12 Delete BKsp List Select Find Delete Delete BUFFERs BUFFER FILE Prev Ch Prev Ch L1 L2 R1 R2 R3 (Toggle Toggle Beg of Left Left OvrWt) Fill-m LINE Paren WORD L3 L4 R4 R5 R6 - Set EXCH End of Right Right (Scroll MARK . & m LINE Paren WORD DOWN) L6 ) R7 R8 R9 + (COPY ) Beg of Up Page (Scroll Region) ) In FILE DOWN UP) ) L8 ) R10 R11 R12 | (YANK) ) XJove Left Beg Right | ) NEXT | ) LINE L9 L10 ) Only R13 R14 R15 ENTER (SEARCH (KILL ) End of Down Page | Forwd) Region) ) FILE UP | | -- Help -- --- 0 --- . | Show (Insert (Delete (SHELL) Keychart Line) Line) | In addition to the bindings shown, the following ESC combinations also work: ESC L9 search-reverse ESC DEL kill-previous-word Note that keys with commands shown in parentheses are only available with XJove. LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D (delt-next-char) (delt-curr-win) kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) (forw-list) O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) (back-list) Q quoted-insert query-repl-str R (search-reverse)visit-file repl-string S (search-forw) save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z (scroll-up) (scroll-down) CTRL ESC & CHARACTER ^\ (search-forw) ESC , begin-wind ^^ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < (begin-file) ESC > (end-file) ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro ESC ^@ set-mark ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent jove-4.17.5.5/doc/keychart.sun-cmd000066400000000000000000000122711501102521500165600ustar00rootroot00000000000000 F1 F2 F3 F4 F5 F6 F7 F8 F9 ___ Jove Split Next Delete Delete Enlarge Spell Fill Fill \ COMMAND WINDOW WINDOW Other Current WINDOW Buffer Comment Para ] WINDOWs WINDOW / <-----' F10 F11 F12 Delete BKsp List Select Find Delete Delete BUFFERs BUFFER FILE Prev Ch Prev Ch L1 L2 R1 R2 R3 (Toggle Toggle Beg of Left Left OvrWt) Fill-m LINE Paren WORD L3 L4 R4 R5 R6 - Set EXCH End of Right Right (Scroll MARK . & m LINE Paren WORD DOWN) L6 ) R7 R8 R9 + (COPY ) Beg of Up Page (Scroll Region) ) In FILE DOWN UP) ) L8 ) R10 R11 R12 | (YANK) ) XJove Left Beg Right | ) NEXT | ) LINE L9 L10 ) Only R13 R14 R15 ENTER (SEARCH (KILL ) End of Down Page | Forwd) Region) ) FILE UP | | -- Help -- --- 0 --- . | Show (Insert (Delete (SHELL) Keychart Line) Line) | In addition to the bindings shown, the following ESC combinations also work: ESC L9 search-reverse ESC DEL kill-previous-word Note that keys with commands shown in parentheses are only available with XJove. LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D (delt-next-char) (delt-curr-win) kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) (forw-list) O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) (back-list) Q quoted-insert query-repl-str R (search-reverse)visit-file repl-string S (search-forw) save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z (scroll-up) (scroll-down) CTRL ESC & CHARACTER ^\ (search-forw) ESC , begin-wind ^^ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < (begin-file) ESC > (end-file) ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro ESC ^@ set-mark ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent jove-4.17.5.5/doc/keychart.vt100000066400000000000000000000107321501102521500160640ustar00rootroot00000000000000 Up Down Left Right PF1 PF2 PF3 PF4 (as expected) Left Right Beg of End of WORD WORD LINE LINE with ESC ---> Split Switch Kill Enlarge WINDOW WINDOW Other W WINDOW Numeric pad: 7 8 9 - YANK COPY KILL Page Region Region DOWN 4 5 6 , SPELL FILL Fill-m Page Para Toggle UP 1 2 3 ENTER List Select Find | BUFFERs BUFFER FILE | SHELL --- 0 --- . | COMMAND OvrWT | Toggle Numeric pad, with ESC ---> 7 (IC) ---- 9 (DC) ----- Set Exch MARK . & m ---- ---- ---- ----- 1 (IL) ---- 3 (DL) | Insert Delete | LINE LINE | | --------- ----- | LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D delt-next-char delt-curr-wind kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) forw-list O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) back-list Q quoted-insert query-repl-str R search-reverse visit-file repl-string S search-forw save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z scroll-up scroll-down CTRL ESC & CHARACTER ^\ search-forw ESC , begin-wind ^~ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < begin-file ESC > end-file ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro DEL delt-prev-char ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent jove-4.17.5.5/doc/keychart.wyse000066400000000000000000000134271501102521500162050ustar00rootroot00000000000000N.B. Use 'Do' key in place of 'ESC' F6 F7 F8 F9 F10 F11 F12 F13 F14 Beg of Beg of Shrink Split Switch Kill Enlarge End of End of LINE FILE WINDOW WINDOW WINDOW Other WINDOW FILE LINE WINDOW Help Do F17 F18 F19 F20 HELP ESCAPE Left Set Exch Right key WORD MARK . & m WORD Find Insert Remove Select Prev Next SEARCH Insert Delete SEARCH SCROLL SCROLL Fwd LINE LINE Bwd Down Up Numeric pad: 7 8 9 - YANK COPY KILL Page Region Region DOWN 4 5 6 , SPELL FILL Fill-m Page Para Toggle UP 1 2 3 ENTER List Select Find | BUFFERs BUFFER FILE | SHELL --- 0 --- . | COMMAND OvrWT | Toggle The following are included mainly for compatibility with vt100 and mac terminals. PF1 PF2 PF3 PF4 Beg of Left Right End of LINE WORD WORD LINE with Do ---> Split Switch Enlarge Kill WINDOW WINDOW WINDOW Other WINDOW Numeric pad, with Do ---> 7 (IC) ---- 9 (DC) ----- Set Exch MARK . & m ---- ---- ---- ----- 1 (IL) ---- 3 (DL) | Insert Delete | LINE LINE | | --------- ----- | LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER Do & LETTER Do & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D delt-next-char delt-curr-wind(kill-next-word)down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) forw-list O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) back-list Q quoted-insert query-repl-str R search-reverse visit-file repl-string S (search-forw) save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z (scroll-up) (scroll-down) CTRL Do & CHARACTER ^\ (search-forw) Do , begin-wind ^~ quoted-insert Do - digit-minus ^@ (set-mark) Do . end-wind Do [0-9] digit ^X & CTRL Do < begin-file Do > end-file ^X ^\ save-file Do ? describe-command Do \ delt-white-space ^X & CHARACTER Do ] forw-paragraph Do ~ make-buffer-unmod ^X ! shell-command Do DEL kill-prev-word ^X ( begin-kbd-macro DEL delt-prev-char ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent CONFIGURATION The following string may be fired at the terminal in order to configure it correctly for use with this binding. P0;1|37/1b4f41;38/1b4f42;39/1b4f43;40/1b4f44;41/1b4f45;43/1b4f46;44/1b4f47;45/1b4f48;46/1b4f49;48/1b4f4a;49/1b;51/1b4f54;52/1b4f55;53/1b4f56;54/1b4f57;17/1b4f41;18/1b4f42;19/1b4f43;20/1b4f44;21/1b4f45;23/1b4f46;24/1b4f47;25/1b4f48;26/1b4f49;28/1b4f4a;29/1b;31/1b4f54;32/1b4f55;33/1b4f56;34/1b4f57\ The following restores the default configuration. P0;1|37/01;38/1b3c;39/0c;40/1b3e;41/05;43/1b;44/08;45/0a;49/1b\ jove-4.17.5.5/doc/keychart.xterm000066400000000000000000000121211501102521500163430ustar00rootroot00000000000000 F1 F2 F3 F4 F5 F6 F7 F8 F9 ___ Jove Split Next Delete Delete Grow Spell Fill Fill \ COMMAND WINDOW WINDOW Other Current WINDOW Buffer Comment Para ] WINDOWs WINDOW / <-----' F10 F11 F12 | PrSc Scroll-L Pause List Select Find | Beg of End of BUFFERs BUFFER FILE | LINE LINE SPARE L1 L2 | | NumLock / * - Toggle Toggle | | Left Right Scroll OvrWt Fill-m | | WORD WORD DOWN |----------------------------| L3 L4 | INSERT HOME PREV | 7 8 9 + Set EXCH | Insert Beg of Page | Beg of Up Page Scroll MARK . & m | Line FILE UP | FILE UP UP | | | L6 | DEL END NEXT | 4 5 6 | COPY | Delete End of Page | Left Beg Right | Region | Prev Ch FILE DOWN | NEXT | |----------------------------| LINE L8 | | 1 2 3 ENTER YANK | | End of Down Page | | | FILE DOWN | | | | L9 L10 | | ---- 0 ---- . | SEARCH KILL | | Insert Kill SHELL Forwd Region | | Line Line | | -- Help -- | Show | Keychart | In addition to the bindings shown, the following ESC combinations also work: ESC L9 search-reverse ESC DEL kill-previous-word LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D (delt-next-char) (delt-curr-win) kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) (forw-list) O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) (back-list) Q quoted-insert query-repl-str R (search-reverse)visit-file repl-string S (search-forw) save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z (scroll-up) (scroll-down) CTRL ESC & CHARACTER ^\ (search-forw) ESC , begin-wind ^^ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < (begin-file) ESC > (end-file) ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro ESC ^@ set-mark ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent jove-4.17.5.5/doc/keychart.xterm-256color000066400000000000000000000121211501102521500177140ustar00rootroot00000000000000 F1 F2 F3 F4 F5 F6 F7 F8 F9 ___ Jove Split Next Delete Delete Grow Spell Fill Fill \ COMMAND WINDOW WINDOW Other Current WINDOW Buffer Comment Para ] WINDOWs WINDOW / <-----' F10 F11 F12 | PrSc Scroll-L Pause List Select Find | Beg of End of BUFFERs BUFFER FILE | LINE LINE SPARE L1 L2 | | NumLock / * - Toggle Toggle | | Left Right Scroll OvrWt Fill-m | | WORD WORD DOWN |----------------------------| L3 L4 | INSERT HOME PREV | 7 8 9 + Set EXCH | Insert Beg of Page | Beg of Up Page Scroll MARK . & m | Line FILE UP | FILE UP UP | | | L6 | DEL END NEXT | 4 5 6 | COPY | Delete End of Page | Left Beg Right | Region | Prev Ch FILE DOWN | NEXT | |----------------------------| LINE L8 | | 1 2 3 ENTER YANK | | End of Down Page | | | FILE DOWN | | | | L9 L10 | | ---- 0 ---- . | SEARCH KILL | | Insert Kill SHELL Forwd Region | | Line Line | | -- Help -- | Show | Keychart | In addition to the bindings shown, the following ESC combinations also work: ESC L9 search-reverse ESC DEL kill-previous-word LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D (delt-next-char) (delt-curr-win) kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) (forw-list) O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) (back-list) Q quoted-insert query-repl-str R (search-reverse)visit-file repl-string S (search-forw) save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z (scroll-up) (scroll-down) CTRL ESC & CHARACTER ^\ (search-forw) ESC , begin-wind ^^ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < (begin-file) ESC > (end-file) ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro ESC ^@ set-mark ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent jove-4.17.5.5/doc/keychart.z29000066400000000000000000000112301501102521500156300ustar00rootroot00000000000000 F1 F2 F3 F4 F5 F6 F7 F8 F9 Beg of Beg of Shrink Split Switch Kill Enlarge End of End of LINE FILE WINDOW WINDOW WINDOW Other WINDOW FILE LINE WINDOW HELP HOME <-- ^ --> ERASE ERASE(shifted) HELP Left Left Up Right Right (spare) WORD WORD Numeric pad, UNSHIFTED: 7 8 9 - YANK COPY KILL Page Region Region DOWN 4 5 6 , SPELL FILL Fill-m Page Para Toggle UP 1 2 3 ENTER List Select Find | BUFFERs BUFFER FILE SHELL --- 0 --- . | Jove Toggle | COMMAND OVERWRITE Numeric pad SHIFTED: 7 (IC) 8 9 (DC) ----- Set Up EXCH MARK . & m 4 5 6 ----- Left Left Right WORD 1 (IL) 2 3 (DL) | Insert Down Delete | LINE LINE | | --------- ----- | LIST OF KEY BINDINGS (ones in parentheses are already bound to keys). CTRL ^X & CTRL ^X & LETTER ESC & LETTER ESC & CTRL A (begin-line) back-sent B (back-char) (list-buffers) (select-buffer)(back-word) back-s-expression C exit-jove case-capitalize D delt-next-char delt-curr-wind kill-next-word down-list E (end-line) compile-it exec-kbd-macro forw-sent F (forw-char) (find-file) (forw-word) forw-s-expression G ABORT COMMAND goto-line H (delt-prev-char) I (handle-tab) insert-file macro-interacti J (newline-&-inden) (fill-paragraph) K kill-end-line delt-buffer kill-end-sent kill-s-expression L redraw-display case-lower clear-&-redraw M (newline) write-mod-files first-non-blank N (next-line) next-error (next-wind) forw-list O (newline-&-back)delt-blank-lin(prev-wind) P (prev-line) prev-error (prev-wind) back-list Q quoted-insert query-repl-str R search-reverse visit-file repl-string S search-forw save-file save-file pause-jove T transp-chars transp-lines find-tag U *4-numeric-arg case-upper back-up-list V (next-page) visit-file (prev-page) page-next-wind W (kill-region) write-file (copy-region) X (exch-.-&-mark) (exec-command) Y (yank) yank-pop Z scroll-up scroll-down CTRL ESC & CHARACTER ^\ search-forw ESC , begin-wind ^^ quoted-insert ESC - digit-minus ^@ (set-mark) ESC . end-wind ESC [0-9] digit ^X & CTRL ESC < (begin-file) ESC > (end-file) ^X ^\ save-file ESC ? describe-command ESC \ delt-white-space ^X & CHARACTER ESC ] forw-paragraph ESC ~ make-buffer-unmod ^X ! shell-command ESC DEL kill-prev-word ^X ( begin-kbd-macro DEL delt-prev-char ^X ) end-kbd-macro ^X 1 (delt-other-winds) ^X 2 (split-curr-wind) ^X 4 wind-find ^X ? describe-key ^X ^ (grow-wind) ^X DEL kill-begin-sent jove-4.17.5.5/doc/teach-jove000066400000000000000000001160371501102521500154330ustar00rootroot00000000000000 J O V E T U T O R I A L Welcome to JOVE - an advanced, easy-to-use, user-friendly environment for editing text, programs or anything else you may like to type. JOVE is designed to be run from a "dumb terminal", so it does not use the capabilities and conventions of windowing systems (multiple windows, mice, multiple fonts and so on). JOVE can be run on such a system using a "terminal emulator" or "command window". JOVE commands generally involve the CONTROL key (sometimes labelled CTRL or CTL) or the META key (generally labelled ESCAPE). Rather than write out META or CONTROL each time we want you to prefix a character, we'll use the following abbreviations: ^ means hold the CONTROL key while typing the character Thus, ^F would be: hold the CONTROL key and type F. M- means type the META (ESCAPE) key and release it, then type the character . The can be upper or lower case and it will have the same meaning. Important note: if you must exit at some point, type ^X ^C. The characters ">>" at the left margin indicate directions for you to try using a command. For instance: >> Now type ^V (View next screen) to move to the next screen. (go ahead, do it by depressing the control key and V together). From now on, you'll be expected to do this whenever you finish reading the screen. Note that there is an overlap when going from screen to screen; this provides some continuity when moving through the file. The first thing that you need to know is how to move around from place to place in the file. You already know how to move forward a screen, with ^V. To move backwards a screen, type M-V (depress the META key and type V, or type V if you don't have a META or EDIT key). >> Try typing M-V and then ^V to move back and forth a few times. SUMMARY ------- The following commands are useful for viewing screenfuls: ^V Move forward one screenful M-V Move backward one screenful ^L Center the current line--clear screen and redisplay everything if current line is already at center. >> find the cursor and remember what text is near it. Then type a ^L. Find the cursor again and see what text is near it now. BASIC CURSOR CONTROL -------------------- Getting from screenful to screenful is useful, but how do you reposition yourself within a given screen to a specific place? There are several ways you can do this. One way (not the best, but the most basic) is to use the commands previous, backward, forward and next. As you can imagine these commands (which are given to JOVE as ^P, ^B, ^F, and ^N respectively) move the cursor from where it currently is to a new place in the given direction. Here, in a more graphical form are the commands: Previous line, ^P : : Backward, ^B .... Current cursor position .... Forward, ^F : : Next line, ^N You'll probably find it easy to think of these by letter. P for previous, N for next, B for backward and F for forward. These are the basic cursor positioning commands and you'll be using them ALL the time so it would be of great benefit if you learn them now. >> Do a few ^N's to bring the cursor down to this line. >> Move into the line with ^F's and then up with several ^P's. See what ^P does when the cursor is in the middle of the line. Lines are separated by a single Linefeed character, which is what Unix calls a Newline. >> Try to ^B at the beginning of a line. Do a few more ^B's. Then do ^F's back to the end of the line and beyond. When you go off the top or bottom of the screen, the text beyond the edge is shifted onto the screen so that your instructions can be carried out while keeping the cursor on the screen. >> Try to move the cursor off the bottom of the screen with ^N and see what happens. If moving by characters is too slow, you can move by words. M-F (Meta-F) moves forward a word and M-B moves back a word. >> Type a few M-F's and M-B's. Intersperse them with ^F's and ^B's. Notice the parallel between ^F and ^B on the one hand, and M-F and M-B on the other hand. Very often Meta characters are used for operations related to English text whereas Control characters operate on the basic textual units that are independent of what you are editing (characters, lines, etc). There is a similar parallel between lines and sentences: ^A and ^E move to the beginning or end of a line, and M-A and M-E move to the beginning or end of a sentence. >> Try a couple of ^A's, and then a couple of ^E's. Try a couple of M-A's, and then a couple of M-E's. See how repeated ^A's do nothing, but repeated M-A's keep moving farther. Do you think that this is right? Two other simple cursor motion commands are M-< (Meta Less-than), which moves to the beginning of the file, and M-> (Meta Greater-than), which moves to the end of the file. You probably don't need to try them, since finding this spot again will be boring. If you need the shift key to type a "<", then you must also use the shift key to type M-<. Otherwise, you would be typing M-, . The location of the cursor in the text is also called "point". To paraphrase, the cursor shows on the screen where point is located in the text. Here is a summary of simple moving operations including the word and sentence moving commands: ^F Move forward a character ^B Move backward a character M-F Move forward a word M-B Move backward a word ^N Move to next line ^P Move to previous line ^A Move to beginning of line ^E Move to end of line M-A Move back to beginning of sentence M-E Move forward to end of sentence M-< Go to beginning of file M-> Go to end of file >> Try all of these commands now a few times for practice. Since the last two will take you away from this screen, you can come back here with the command ^X ^X (which will be explained later). These are the most often used commands. Like all other commands in JOVE, these commands can be given arguments which cause them to be executed repeatedly. The way you give a command a repeat count is by typing META and then the digits before you type the command. (Remember META is ususally called ESCAPE) For instance, META 8 ^F moves forward eight characters. >> Try giving a suitable argument to ^N or ^P to come as close as you can to this line in one jump. The only apparent exception to this is the screen moving commands, ^V and M-V. When given an argument, they scroll the screen up or down by that many lines, rather than screenfuls. This proves to be much more useful. >> Try typing M-8 ^V now. Did it scroll the screen up by 8 lines? If you would like to scroll it down you can give an argument to M-V. THE UNIVERSAL ARGUMENT ---------------------- Almost every command in JOVE takes a so-called Universal Argument. This argument, although it is interpreted differently in some cases, usually means REPEAT. One important exception to this is with the screen moving commands. In this case, the number refers to the number of LINES to scroll, not the number of screens. The way you give a command a universal argument is by typing ESC and then the number. For example, ESC 10 ^F would move you forward ten characters. >>> Try giving a suitable argument to ^N or ^P to come as close as you can to this line in one jump. Then try giving the same command, except make the number negative. Another count-giving command is ^U. This command, when you first type it, gives you an argument of 4 (four). If you type ^U ^U, you will get an argument of 16. Each time ^U is typed, the argument is multiplied by four. >>> Try typing ESC 8 ^V now. THE GOTO COMMAND ---------------- Now that we've learned about the universal argument, we can introduce another cursor positioning command, the command to move to a specific line. This command is given by giving a line number via ESC, and then typing M-G. >>> Try using the M-< and M-> commands to move to the beginning and the end of the file. Then come back here using the M-G command (this is line 206, so you'd type ESC 206 M-G.) QUITTING FROM COMMANDS ---------------------- The character in JOVE used to quit out of all commands which request input is ^G. For example, you can use ^G to discard a numeric argument or the beginning of a command that you don't want to finish. >> Type M-100 to make a numeric arg of 100, then type ^G. Now type ^F. How many characters does it move? If you have typed an by mistake, you can get rid of it with a ^G. ERRORS ------ Sometimes you may do something which JOVE doesn't allow. If it is something simple, such as typing a control key sequence which is not associated with any command, JOVE will just beep at you. Otherwise, JOVE will also display an informative error message at the bottom of the screen. Some versions of JOVE do not have all the features described in this tutorial implemented yet. If you come across such an unimplemented feature, you may get an error message when you try to use it. Just proceed on to the next section of the tutorial. INSERTING AND DELETING ---------------------- If you want to type text, just do it. Characters which you can see, such as A, 7, *, etc. are taken by JOVE as text and inserted immediately. Type (the carriage-return key) to insert a line separator. You can delete the last character you typed by typing . is a key on the keyboard, which may be labeled "Rubout" instead of "Delete" on some terminals. More generally, deletes the character immediately before the current cursor position. >> Do this now, type a few characters and then delete them by typing a few times. Don't worry about this file being changed; you won't affect the master tutorial. This is just a copy of it. >> Now start typing text until you reach the right margin, and keep typing. When a line of text gets too big for one line on the screen, the line of text is "continued" off the edge of the screen The exclamation mark at the right margin indicates a line which has been continued. The line will slide over if you move off the edge on either side. >> The following line actually goes off the edge. Trying typing enough ^F's that you move off the right hand end of this line.... This is a long line of text that the JOVE editor extends to the right. >> Use s to delete the text until the line fits on one screen line again. The continuation "!" will go away. >> Move the cursor to the beginning of a line and type . This deletes the line separator before the line and merges the line onto the previous line. The resulting line may be too long to fit, in which case it has a continuation indication. >> Type to insert the separator again. Remember that most JOVE commands can be given a repeat count; Note that this includes characters which insert themselves. >> Try that now -- type META 8 * and see what happens. If you want to create a blank line in between two lines, move to the second of the two lines and type ^O. >> Try moving to a line and typing ^O now. You've now learned the most basic way of typing something in JOVE and correcting errors. You can delete by words or lines as well. Here is a summary of the delete operations: delete the character just before the cursor ^D delete the next character after the cursor M- kill the word immediately before the cursor M-D kill the next word after the cursor ^K kill from the cursor position to end of line M-K kill to the end of the current sentence Notice that and ^D vs M- and M-D extend the parallel started by ^F and M-F (well, isn't really a control character, but let's not worry about that). ^K and M-K are like ^E and M-E, sort of, in that lines are opposite sentences. Now suppose you kill something, and then you decide that you want to get it back? Well, whenever you kill something bigger than a character, JOVE saves it for you. To yank it back, use ^Y. Note that you don't have to be in the same place to do ^Y; This is a good way to move text around. Also note that the difference between "Killing" and "Deleting" something is that "Killed" things can be yanked back, and "Deleted" things cannot. Generally, the commands that can destroy a lot of text save it, while the ones that attack only one character, or nothing but blank lines and spaces, do not save. For instance, type ^N a couple times to postion the cursor at some line on this screen. >> Do this now, move the cursor and kill that line with ^K. Note that a single ^K kills the contents of the line, and a second ^K kills the line itself, and make all the other lines move up. If you give ^K a repeat count, it kills that many lines AND their contents. The text that has just disappeared is saved so that you can retrieve it. To retrieve the last killed text and put it where the cursor currently is, type ^Y. >> Try it; type ^Y to yank the text back. Think of ^Y as if you were yanking something back that someone took away from you. Notice that if you do several ^K's in a row the text that is killed is all saved together so that one ^Y will yank all of the lines. >> Do this now, type ^K several times. Now to retrieve that killed text: >> Type ^Y. Then move the cursor down a few lines and type ^Y again. You now see how to copy some text. What do you do if you have some text you want to yank back, and then you kill something else? ^Y would yank the more recent kill. But the previous text is not lost. You can get back to it using the M-Y command. After you have done ^Y to get the most recent kill, typing M-Y replaces that yanked text with the previous kill. Typing M-Y again and again brings in earlier and earlier kills. When you have reached the text you are looking for, you can just go away and leave it there. If you M-Y enough times, you come back to the starting point (the most recent kill). >> Kill a line, move around, kill another line. Then do ^Y to get back the second killed line. Then do M-Y and it will be replaced by the first killed line. Do more M-Y's and see what you get. Keep doing them until the second kill line comes back, and then a few more. If you like, you can try giving M-Y positive and negative arguments. FILES ----- In order to make the text you edit permanent, you must put it in a file. Otherwise, it will go away when your invocation of JOVE goes away. While you are editing a file in JOVE, your changes are actually being made to a private "scratch" copy of the file that JOVE holds in temporary memory. However, the changes still don't become permanent until you "save" the file. This is so you can have control to avoid leaving a half-changed file around when you don't want to. If you look near the botton of the screen you will see a line that looks like this: JOVE (Text) [teach-jove:3] "~/teach-jove" * "teach-jove" is the name of the file you are editing. This is the name of your own copy of the text of this JOVE tutorial, the file you are now editing. Whatever file you edit, that file's name will appear in that precise spot. The commands for finding (starting to edit) and saving files are a bit different from the commands you have learned so far, in that they consist of two characters. They both start with the character Control-X. There is a whole series of commands that start with Control-X; many of them have to do with files, buffers, and related things, and all of them consist of Control-X followed by some other character. As with M- the character interpreted the same regardless of case. To save any changes you have made to a file you are editing, type the command ^X ^S Save the file and your changes to will be saved to disk permanently. Go ahead, it's safe to try that now. (Note: on some old systems JOVE will not be able to process the key ^S. In place of ^S, you should type ^\. It is possible to make ^S work but ^\ is guaranteed always to work in place of ^S.) The old version of the file will be replaced. When the operation is finished, JOVE prints the name and number of lines and characters saved in the bottom line. Another thing about the command for finding a file in order to start editing it is that you have to say what file name you want. We say the command "reads an argument from the terminal" (in this case, the argument is the name of the file). After you type the command ^X ^F Find a file JOVE will ask you for the file name. You should end the name with the Return key. After this command, you will now see the contents of that file in your JOVE. You can edit the contents. When you wish to make the changes permanent, issue the command ^X ^S Save the file If you forget to save and then edit a different file, and then try to exit, JOVE will remind you that you made changes that have not been saved and then ask you whether you really want to quit. (If you don't save them, they will be thrown away. That might be what you want, but likely not!) You should answer with a "Y" to throw the changes away or "N" to abort quitting so you can then save the changes. To make a new file, just find it "as if" it already existed, JOVE will create an empty screen for you to start editing. Then start typing in the text. When you ask to "save" the file, JOVE will really create the file with the text that you have inserted. From then on, you can consider yourself to be editing an already existing file. It is not easy for you to try out editing a file and continue with the tutorial. But you can always come back into the tutorial by starting it over and skipping forward. So, when you feel ready, you should try editing a file named "FOO", putting some text in it, and saving it; then exit from JOVE and look at the file to be sure that it worked. CONCLUSION OF PART ONE ---------------------- This is the end of the first part of this tutorial. You now know enough to edit a file with JOVE, and save your work. The second part of this tutorial, which starts with the next section, discusses searching, replacing, word processing, and other modes of JOVE. You may wish to stop here and practice for awhile before you continue. EXTENDING THE COMMAND SET ------------------------- There are many, many more JOVE commands than could possibly be put on all the control and meta characters. JOVE gets around this with the X (eXtend) command. This comes in two flavors: ^X Character eXtend. Followed by one character. M-X Named command eXtend. Followed by a long name. These are commands that are generally useful but used less than the commands you have already learned about. You have already seen two of them: the file commands ^X ^F to Find and ^X ^S to Save. Another example is the command to tell JOVE that you'd like to stop editing. The command to do this is ^X ^C. There are many ^X commands. The ones you need immediately are: ^X ^V Visit file. ^X ^S Save file. ^X ^C Quit JOVE. This does not save your files auto- matically, though if your files have been modi- fied, JOVE asks if you really want to quit. The standard way to save and exit is ^X ^S ^X ^C. Named eXtended commands are commands which are used even less frequently, or commands which are used only in certain modes. These commands are usually called "commands". An example is the command "apropos", which prompts for a keyword and then gives the names of all the commands that apropos for that keyword. When you type M-X, JOVE prompts you at the bottom of the screen with ":" and you should type the name of the command you wish to call; in this case, "apropos". Just type "apr" and JOVE will complete the name. JOVE will ask you for a keyword or phrase and you type the string that you want ask about. >> Try typing M-X, followed by "apropos" or "apr" and then Return. Then try typing "file" followed by a Return. MODE LINE --------- If JOVE sees that you are typing commands slowly it shows them to you at the bottom of the screen in an area called the echo area. The echo area contains the bottom line of the screen. The line immediately above them is called the MODE LINE. The mode line says something like JOVE (Text) Buffer: [buffername] "filename" * This is a very useful "information" line. The buffername is the name JOVE gave to the buffer, and it is usually related to the filename. You already know what the filename means -- it is the file you have edited. The star means that you have made changes to the text. Right after you visit or save a file, there is no star. The part of the mode line inside the parentheses is to tell you what modes you are in. The default mode is Text which is what you are in now. It is an example of a "major mode". There are several major modes in JOVE for editing different languages and text, such as C mode, Lisp mode, Text mode, etc. At any time one and only one major mode is active, and its two-letter code can always be found in the mode line just where "Text" is now. Each major mode makes a few commands behave differently. For example, what JOVE considers as part of a valid expression or an identifier differs from one major mode to another, since each programming language has a different idea of what is a legal identifier. Major modes are called major because there are also minor modes. They are called minor because they aren't alternatives to the major modes, just minor modifications of them. Each minor mode can be turned on or off by itself, regardless of what major mode you are in, and regardless of the other minor modes. So you can use no minor modes, or one minor mode, or any combination of several minor modes. One minor mode which is very useful, especially for editing English text, is "Auto Fill" mode. When this mode is on, JOVE breaks the line in between words automatically whenever the line gets too long. You can turn this mode on by doing M-X auto-fill-mode. When the mode is on, you can turn it off by doing M-X auto-fill-mode-- it toggles. >> Type "M-X auto-fill-mode" now. Then insert a line with a bunch of words over again until you see it divide into two lines. You must put in spaces between them because Auto Fill breaks lines only at spaces. Notice that "Fill" (the code for Auto Fill) appears in the mode line after "Text" to indicate that you are in Text Fill mode. The margin is usually set at 78 characters, but you can change it with the set command. The margin is kept in a variable just like the mode values. >> Type "M-X set right-margin 20", then type in some text and see JOVE fill lines of 20 characters with it. Then set the margin back to 72 using M-X set again. SEARCHING --------- JOVE can do searches for strings (these are groups of contiguous characters or words) either forward through the file or backward through it. To search for the string means that you are trying to find that string somewhere in the file. Remember to use ^\ where it says ^S. >> Now type ^S to start a search. Type the word 'cursor', then Return. >> Type ^S Return to find the next occurrence of "cursor". The ^S starts a search that looks for any occurrence of the search string AFTER the current cursor position. But what if you want to search for something earlier in the text? To do this one should type ^R for reverse search. Everything that applies to ^S applies to ^R except that the direction of the search is reversed. REPLACING TEXT -------------- >> Move the cursor to the blank line two lines below this one. Then type M-r changedaltered. Notice how this line has changed: you've replaced the word c-h-a-n-g-e-d with "altered" wherever it occurs after the cursor. The more customary command for replacing strings is the interactive command query-replace-search, which has several options. In essence, it shows each occurrence of the first string and asks you if you want to replace it or not. You can also choose to edit around the string, or go on and replace all occurrences without asking further. This is invoked with M-Q.. When you start up a Query Replace, it will prompt you with "From" and "To", for what you want to change, and what you want to change it to. JOVE will then move to the first occurence of the "From", and wait for a character. You can type: Do the replacement, and move to next occurrence of the "From" string. Skip the current "From" string and move to the next one. RETURN Exit the Query Replace now. r Recursive Edit p Replace all further occurences of the "From" string, without asking. Recursive edit makes it possible to temporarily supend the Q-R-S, let the user go off and do something, and then return to the search after the he is done. The command exit-jove (^X ^C) returns from the recursive-edit. GETTING MORE HELP ----------------- In this tutorial we have tried to supply just enough information to get you started using JOVE. There is so much available in JOVE that it would be impossible to explain it all here. However, you may want to learn more about JOVE since it has numerous desirable features that you don't know about yet. JOVE has a some internal documentation. The most basic HELP feature is the describe-key command which is available by typing ^X ? and then a command character. JOVE prints one line line on the bottom of the screen tell what command is bound to that key. You can then get further information on that command using... The describe-command command M-? will prompt for the name of a command and print out the section from the manual about that command. When you are finished reading it, type a Space or a ^G (quit) to bring your text back on the screen. >> Type ^X ? Control-P. The message at the bottom of the screen should be something like "^P is bound to previous-line". Multi-character commands such as ^X ^C and V are also allowed after ^X ?. Now lets get more information about the previous-line command. >> Type M-? previous-line. When you are finished reading the output, type a Space. The "name of the command" is important for people who are customizing JOVE. It is what appears in the JOVE CHART as the documentation for the command character. One other form of help is the "apropos" command. We have already tried using this command in an earlier part of this tutorial, but it should be mentioned again here. Apropos prompts for a word or phrase and lists all the commands that contain that string. If you couldn't remember the name of a certain command to read file, you could run the apropos command with the keyword "file" and it would list all the commands that contain "file". To run apropos you would type M-X aprfile Finally, the full JOVE manual is included in the distribution. It is in NROFF/TROFF form and can be formatted into a form readable on the terminal or line-printer with the command: cd /local/src/jove make doc/jove.man.txt To get a typeset copy, use the make target jove.man.pdf (PDF format) or jove.man.ps (PostScript format). You will have to adjust the makefile for your local facilities for TROFF output. Besides, someone around you must have a printed version which you can borrow! There's also an old copy in the Berkeley Unix 4.3 manuals - in the User Supplementary Documents manual (the one with the green spine). There is also a chart of JOVE commands, sorted by function, which is handy as a quick reference. Ask your local Jove guru for a copy. CONCLUSION OF PART TWO ---------------------- This concludes section two of the JOVE tutorial. The rest of this tutorial describes some of the very advanced features of JOVE, such as editing more than one file at once, writing your own macros, windows, and initialization files. Unless you're already somewhat familiar with JOVE, you should probably wait a little while before starting the third section. MARKS AND REGIONS ----------------- In general, a command which processes an arbitrary part of the buffer must know where to start and where to stop. In JOVE, such commands usually operate on the text between point (where the cursor is now) and "the mark". This range of text is called "the region". To specify a region, you set point to one end of it and mark at the other. It doesn't matter which one is set first chronologically, or which one comes earlier in the text. Here are some commands for setting the mark: ^@ Set the mark where point is. ^ The same. ^X ^X Interchange mark and point. The most common way to set the mark is with the ^@ command or the ^ command. They set the mark where point is. Then you can move point away, leaving the mark behind. Since terminals have only one cursor, there is no way for JOVE to show you where the mark is located. You have to remember. The usual solution to this problem is to set the mark and then use it soon, before you forget where it is. But you can see where the mark is with the command ^X ^X which puts the mark where point was and point where the mark was. The extent of the region is unchanged, but the cursor and point are now at the previous location of the mark. There are many, many commands which use regions (the area between the point and the mark), which we have not mentioned here. They can be found in the Jove Quick Reference Card. BUFFERS ------- When editing a file, JOVE reads the file into a buffer. This is where the modifcations are done, and when you save the file with ^X ^S, the buffer is actually written out to the file. JOVE permits you to have up to 100 buffers, so, in essence, you can edit up to 100 files at the same time. If you want to list the buffers you have, use the ^X ^B command. This will display a list of the buffers, their numbers and names, and whether or not they've been modified. >>> Do this now, type ^X ^B. When you're done looking, type a . You probably noticed you have three buffers, named "Main", "*minibuf*", and "teach-jove". The "Main" buffer is always created by JOVE; you may use it if you wish. "*minibuf*" is a special reserved buffer which is described in the JOVE manual. "teach-jove" holds a working copy of the file of the same name. If you were editing more than one file, you would have even more buffers. There are two ways to edit more than one file. The first is to call JOVE with more than one file on the command line. For example, the shell command jove a b c would start JOVE with three buffers (named a, b, and c), each one containing one file. The other way is to use the ^X ^F command (called Find File). This command prompts you for a filename, and then reads that file into a new buffer, and puts you into the new buffer. To change buffers, use the ^X B command. JOVE will prompt you for a buffer name, and print a name in parentheses. If you just hit a carriage return without typing a buffer name, you will go to the buffer named in parentheses. Another way to change buffers is to give ^X B a NUMBER. This goes to the buffer NUMBER, rather than using the buffer name. >>> Get a piece of paper, and write down the following commands. Then run them, to get a feel for playing with buffers. BE SURE TO WRITE THEM DOWN! We don't want to get you lost! ^X ^B ^X ^F (type "/etc/motd" to the prompt) ^X ^B ^X B Well, wasn't that fun? Now you know how to get another file into another buffer, and then "bounce" back and forth. A nice feature about editing more than one file is that you can transfer text from one file to the other. Just kill it in one file, change buffers, and then put it back with ^Y. WINDOWS ------- What you see on your screen is a "window" into the buffer you are editing. JOVE allows you to have more than one window on your screen, and you can therefore look into two, or more buffers at once. You can also look at different parts of the same file. The command ^X 2 splits your screen into two windows, both looking into the same buffer. The command ^X 4 f will display a specified file in the other window, ^X 4 b will display a specified buffer in the other window, ^X n moves to the next window on the screen, while ^X p moves to the previous window. >>> Try the command ^X 2, which splits the screen into two windows, and displays the same buffer in both. You'll notice that you are in the new window. Try some commmands in this window, like ^V, or M-V, to move around in the file. Observe that the other window doesn't change its position relative to the buffer. This gives you a way of looking at two parts of the same file. >>> Now try to type some text, or change something. You will see the changes affecting the text in the other window as well. That is because both windows are displaying the same buffer, and therefor the same text. Changes in the contents of the buffer have to affect both windows. >>> Let's now try to edit another file in this window. Give the command ^X ^F and type the name of file as "/etc/motd". You now have two files on your screen at the same time. >>> Type the command M-^V (Meta followed by ^V) and watch the other window page downward. This is very convenient when doing a variety of tasks, like correcting errors in a file - edit the file, with the list of errors in the other window! >>> Finally, let's get back to the main window (with this document) by typing ^X p (or ^X n, since there are only two windows). Expand this window to fill the entire screen by typing ^X 1. Enjoyable, wasn't it! There are other commands for shrinking and growing windows, but one of the most useful when editing text like this is the command which invokes JOVE's interactive spelling checker. It's called spell-buffer. It runs the UNIX spell(1) command on the buffer, and puts the errors in another buffer in another window, and allows you to edit the list to remove the words you know are not errors. Then, type ^X ^C, which usually gets you out of JOVE but in this case only gets you out of the spell-edit mode. You can now go through the remaining spelling errors word-by-word, and you can correct them. The commands for this are ^X ^N (for next error) and ^X ^P (for previous error.) >>> Try the spell-buffer command now, by going M-X spel and watch. Delete a few errors, then type ^X ^C, and do a few ^X ^N's to find some errors in this document. We've left a few! (deliberately, of course!!!) MACROS ------ A "keyboard macro" is a command defined by the user to abbreviate a sequence of other commands. If you discover that you are about to type ^N ^D forty times, you can define a keyboard macro to do ^N ^D and call it with a repeat count of forty. The commands which deal with keyboard macros are: ^X ( Start defining a keyboard macro. ^X ) End the definition of a keyboard macro. ^X E Execute the most recent keyboard macro. You define a keyboard macro while executing the commands which are the definition. Put differently, as you are defining a keyboard macro, the definition is being executed for the first time. This way, you can see what the effects of your commands are, so that you don't have to figure them out in your head. When you are finished, the keyboard macro is defined and also has been, in effect, executed once. You can then do the whole thing over again by invoking the macro. To start defining a keyboard macro, type the ^X ( command. From then on, your commands continue to be executed, but also become part of the definition of the macro. "Def" appears in the mode line to remind you of what is going on. When you are finished, the ^X ) command terminates the definition (without becoming part of it!). The macro thus defined can be invoked again with the ^X E command which may be given a repeat count as a numeric argument to execute the macro many times. ^X ) can also be given a repeat count as an argument, in which case it repeats the macro that many times right after defining it, but defining the macro counts as the first repetition (since it is executed as you define it). So, giving ^X ) an argument of 2 executes the macro immediately one additional time. If you want to perform an operation on each line, then either you should start by positioning point on the line above the first one to be processed and then begin the macro definition with a ^N, or you should start on the proper line and end with a ^N. Either way, repeating the macro will operate on successive lines. >>> Place the cursor at the top of the screen and then enter the commands below. Note that after the first command, "Def" appears in the mode line. ^X ( ^A ***** M-F M-F M-F ----- ^N ^X ) >>> Notice that as you typed those commands in, they were executed. Now move the cursor down a couple of lines, but keep it near the top of the screen. Type the command ^U ^X E. This will execute your macro 4 times. Although not described here, it is possible to both name your macros, and to save and restore them from files. See the documentation for this. INITIALIZATION FILES -------------------- You can initialize JOVE just the way you like it by putting a file named ".joverc" in your home directory. To see what this file should look like, look at the one in the directory /usr/src/local/jove/doc. The file system.rc is one such file, the other example is example.rc. It should be noted that the commands in this file contain control characters, which may make it hard to read. Use the "cat -v" command for this. To insert control characters into a file with JOVE, you should use the ^Q command. Type ^Q where is the control character. Note that ^Q will not work on some terminals, because it, like ^S, is used for suspending and restoring the output to the terminal. In that case, use the command M-X quo . INTERACTIVE SHELLS ------------------ One of JOVE's very powerful features is the ability to start up shells within the editor, and then use shell commands within the screen editing environment. To execute a command again, just cursor-up to it, change it if you want with all the normal editing keys, and hit RETURN once to bring it down to your present command line, and again to execute it. We'll bow out here suggesting you consult the manual for hard details, or type M-X shell if you are the adventurous type! CONCLUSION ---------- Remember, to exit use ^X ^C. This tutorial is meant to be understandable to all new users, so if you found something unclear, don't sit and blame yourself - complain to one of the people listed at the end of this document! You'll probably find that if you use JOVE for a few days you won't be able to give it up. Initially it may give you trouble. But remember that this is the case with any editor, especially one that can do many, many things. And JOVE can do practically everything. Hopefully you have enjoyed this tutorial, and, more importantly, I hope you've learned something. If you use JOVE for about a week, and be patient, you will find that it is more convenient and friendly to use than any other editor you've used. I know. I did. --------------------------------------------------------------------------- This tutorial was originally written by Richard Stallman for EMACS and modified by Doug Kingston and Jonathan Payne for JOVE. The section on windows was added by Mark Moraes. Comments on this document should be sent to github.com/jonmacs/jove jove-4.17.5.5/doc/teachjove.nr000066400000000000000000000030571501102521500157710ustar00rootroot00000000000000.\"########################################################################## .\"# This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # .\"# provided by Jonathan and Jovehacks without charge and without # .\"# warranty. You may copy, modify, and/or distribute JOVE, provided that # .\"# this notice is included in all the source files and documentation. # .\"########################################################################## .TH TEACHJOVE 1 "24 June 1993" .ad .SH NAME teachjove \- learn how to use the JOVE editor .SH SYNOPSIS .B teachjove [ .BI \-s \ sharedir ] .SH DESCRIPTION .hy 0 TEACHJOVE (or TEACHJOV on MSDOS) is a simple program that calls up the JOVE editor with the -T option to load an interactive tutorial for the JOVE editor. Once in JOVE all you do is follow the instructions and by doing so you will learn all about JOVE! NOTE: If you use the .I save-file command (or the the keystrokes Control-X Control-S ), TEACHJOVE saves a copy of the tutorial in your home directory; if you ever want to start over (if you save a trashed file by accident) all you need to do is remove the file .I ~/teach-jove and run teachjove again. .LP TEACHJOVE passes switches to Jove, though some may not be meaningful for the tutorial. One that may be useful: .TP .BI \-s \ sharedir Allows the user to specify the directory in which the special teach-jove file can be found (default ). .SH FILES .I /teach-jove \(em THE special file. .SH SEE ALSO .I jove(1) \(em to learn about JOVE in general. .SH AUTHOR Jonathan Payne jove-4.17.5.5/doc/test.rc000066400000000000000000000027771501102521500147750ustar00rootroot00000000000000# This is just a test file for joverc processing # not to be installed or considered an example. # numbers ending in 0 are the expected path, so # if this works, Main should have lines with # 10, 20, 30, ... 100 followed by a line with 200 300 define-macro testbegin ^[xselect-buffer^M*testlog*^[xend-of-file^M^M++^[xnewline^M define-macro testend --^[xnewline^M^[xmake-buffer-unmodified^M execute-macro testbegin if true set right-margin 10 else set right-margin 11 endif insert-variable right-margin newline # if false set right-margin 21 else set right-margin 20 endif insert-variable right-margin newline # if true if true set right-margin 30 else set right-margin 31 endif else if true set right-margin 32 else set right-margin 33 endif endif insert-variable right-margin newline # if false if true set right-margin 41 else set right-margin 42 endif else if true set right-margin 40 else set right-margin 43 endif endif insert-variable right-margin newline # if true if true set right-margin 50 else set right-margin 51 endif endif insert-variable right-margin newline # if true if false set right-margin 61 else set right-margin 60 endif endif insert-variable right-margin newline # if false else if true set right-margin 70 else set right-margin 71 endif endif insert-variable right-margin newline # if false else if false set right-margin 81 else set right-margin 80 endif endif insert-variable right-margin newline source doc/test1.rc # execute-macro testend jove-4.17.5.5/doc/test1.rc000066400000000000000000000006561501102521500150500ustar00rootroot00000000000000execute-macro testbegin define-macro insrm ^[xend-of-file^M^[xinsert-variable^Mright-margin^M define-macro inslm ^[xend-of-file^M^[xinsert-variable left-margin^M define-macro inslmrmnl ^[xexecute-macro inslm^M ^[xexecute-macro insrm^M^[xnewline^M set left-margin 90 set right-margin 100 execute-macro inslm newline execute-macro insrm newline set left-margin 200 set right-margin 300 execute-macro inslmrmnl execute-macro testend jove-4.17.5.5/doc/xjove.nr000066400000000000000000000165531501102521500151610ustar00rootroot00000000000000.TH XJOVE 1 "8 July 1993" .SH NAME Xjove, Jovetool \- run JOVE under X-windows or Sunview with function-key and mouse support. .SH SYNOPSIS .B xjove [ .I window_args ] [ .B "\-f | \-nf" ] [ .BI \-rc \ run_command_path ]\&.\|.\|. [ args \&.\|.\|. ] .br .B jovetool [ .I window_args ] [ .B \-nf ] [ .BI \-rc \ run_command_path ]\&.\|.\|. [ .I args \&.\|.\|. ] .SH DESCRIPTION .I Xjove (or .IR Jovetool ) creates an XView or SunView frame and a tty subwindow within which mouse events and function keys are translated to ASCII sequences which JOVE can parse. The translated input events are sent to the process running in the tty subwindow, which is typically JOVE. .I Xjove thereby allows JOVE users to make full use of the mouse and function keys. JOVE has functions to interpret the mouse and function-key events to make a truly fine screen oriented editor for any workstation supporting XView or SunView. .SH OPTIONS .I Xjove supports all the standard window arguments, including font and icon specifiers. .PP .I Xjove has the ability to fork off a separate process to run the window that is created, leaving the shell from which the .I Xjove command was issued free to accept other commands. This feature is enabled by the .B \-f (for fork) flag and disabled by the .B \-nf (for no fork) flag. The default is set by the .I xjove.forking resource which can be set to True or False in your .Xdefaults file (default False). .PP By default, .I Xjove runs the program .I jove in the created subwindow. The value of the environment variable .I JOVETOOL can be used to override this if your version of JOVE is not accessible on your search path by the name .IR jove . In addition, the run command can be set by the .I pathname following the last occurrence of the .B \-rc flag. This is convenient for using .I Xjove to run on remote machines. .PP All other command line arguments not used by the window system are passed as arguments to the program that runs in the Xjove window. .PP For example: .PP local% xjove \-rc rlogin remote .PP will create an Xjove window logged in to a machine named .IR remote . .I Xjove will encode mouse and function keys, and send them to rlogin. If JOVE is run from this shell on the remote machine, it will see the mouse and function keys properly. .SH "USING XJOVE" The following assumes the use of the recommended bindings from the mouse operations to the Jove mouse-commands. Note how, in general, LEFT does things involving the .IR point , whereas MIDDLE does things involving the .IR mark . .PP Use of mouse buttons .TP 5 LEFT Sets the cursor at the character pointed to. Actually, it is the place you are pointing at when you release the button that counts. .TP 5 MIDDLE Sets the .I mark at the character pointed to when you press it. You may then move to another point before releasing it, thus delineating the .I region from where you pressed to where you released. The position of the mark always remains underlined (not easy to see if the cursor is at the same place). .TP 5 MIDDLE + CTRL Sets the region as before, but then does a COPY (copy-region). .TP 5 MIDDLE + CTRL + SHIFT Sets the region as before, but then does a CUT (kill-region). .TP 5 LEFT + CTRL Sets the cursor as before, but then does a PASTE (yank). This can be used in conjunction with the previous two commands so as to copy or move text from one place to another. However, the following two commands do this job better. .TP 5 MIDDLE + PASTE Remembers the current position of the cursor, then does a COPY (copy-region) on the region you select (possibly in another window), and finally PASTEs (yanks) it at the remembered position. .TP 5 MIDDLE + CUT Remembers the current position of the cursor, then does a CUT (kill-region) on the region you select (possibly in another window), and finally PASTEs (yanks) it at the remembered position. .TP 10 Multiple clicks on MIDDLE In all the above usages of MIDDLE, a double click will set the .I mark at the start of the word pointed into and the .I point at the end of that word. Likewise, a triple click selects the whole of the current line. This is similar to the effects of multiple clicks in Open-Look windows and Sunview. .PP Note that the above commands only work if you point within the current window. Except when in conjunction with PASTE or CUT, the first click into a different window simply selects that other window. Click twice if you want to set the cursor or the mark in the other window. .TP 5 LEFT when in the Modeline Assuming the variable scroll-bar is ON, the position of the window within the overall buffer is shown by unhighlighting the corresponding part of the Modeline. Pointing at a place in the Modeline and pressing either of LEFT or MIDDLE causes the text to scroll to that place. You may hold the button down and move the mouse left or right until you see what you want in the window. .TP 5 RIGHT Brings up a menu with pull-right options enabling you to obey any JOVE command, or set any JOVE variable. If the command requires a parameter (or the variable requires a value other than ON/OFF), you still have to type it in as usual. .TP 5 SHIFT Holding SHIFT down at the same time as any other key or mouse operation (except with CTRL \(em see above) reverts to the normal behaviour of .IR Shelltool(1) . Thus you can make selections, and copy and paste them to/from the clipboard using L6, L8 and L10. .SH OPERATION JOVE will automatically load the file .IR jove.rc.$TERM . It is therefore necessary that this file understands the code sequences that are produced when function keys are pressed in Xjove (these are not necessarily the same as might normally be produced by that $TERM). These follow, more or less, the practice of Sun Workstations (with the addition, except when SHIFT is down, of some keys such as L-1,6,8,9 and 10 which Shelltool usually reserves for its own purposes, and of the KP-* keys around the outside of the numeric keypad, such as KP_Add and KP_Enter). .PP In addition, .I Xjove sets the environment variable .I IN_JOVETOOL .B "= 't'" , so that applications running in an Xjove window can be aware of the fact. .PP Mouse buttons are encoded as `^Xm[0-9](c x y t)\\n'. ^Xm is the JOVE mouse-command prefix, [0-9] indicate which key was pressed, and whether it was a down, up, drag or multi-click event. These are followed by a list indicating the state of CTRL, SHIFT, PASTE and CUT, the character row and column of the point in the window where the mouse cursor is, and the number of pixels in the width of a character. In JOVE, these ^Xm* dispatch to appropriate mouse-command handlers which then read the following list. .SH BUGS The normal Sunview "selection" facilities that enable text to be Cut and Pasted between windows (as provided by Shelltool and Cmdtool) only work when SHIFT is pressed. .br Because SHIFT and CTRL together have a special meaning, it is not possible under SunView to make a selection "Pending Delete". .br Due to a bug in some versions of XView, the underlining of the mark may not occur (but emboldening may be used as an alternative). .br Under SunView, the initial terminal settings for the tty window are apparently taken from the controling tty. This can lead to surprises. .SH "ENVIRONMENT VARIABLES" .I "JOVETOOL IN_JOVETOOL TERM" .br For Xjove, the XView shared library must be visible. It may therefore be necessary to arrange for the Environment Variable LD_LIBRARY_PATH to include $OPENWINHOME/lib, where $OPENWINHOME would usually be /usr/openwin. .SH "SEE ALSO" .I jove(1) jove-4.17.5.5/extend.c000066400000000000000000000577011501102521500143530ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "fp.h" #include "jctype.h" #include "chars.h" #include "commands.h" #include "disp.h" #include "re.h" #include "ask.h" #include "extend.h" #include "fmt.h" #include "insert.h" #include "move.h" #include "sysprocs.h" #include "proc.h" /* #include "util.h" */ #include "vars.h" #include "macros.h" #ifdef MAC # include "mac.h" #endif private void DefAutoExec proto((const data_obj *(*proc) ptrproto((const char *)))); int InJoverc = 0; /* Auto execute code */ #define NEXECS 20 private struct AutoExec { const char *a_pattern; const data_obj *a_cmd; int a_arg_state; long a_arg_count; } AutoExecs[NEXECS]; /* must be initialized by system to 0 */ private int ExecIndex = 0; /* Command auto-execute. */ void CAutoExec() { DefAutoExec(findcom); } /* Macro auto-execute. */ void MAutoExec() { DefAutoExec(findmac); } private void DefAutoExec(proc) const data_obj *(*proc) ptrproto((const char *)); { const data_obj *d = (*proc)(ProcFmt); const char *pattern; register struct AutoExec *p; pattern = do_ask("\r\n", NULL_ASK_EXT, (char *) NULL, ": %f %s ", d->Name); for (p = AutoExecs; p != &AutoExecs[ExecIndex]; p++) if (p->a_cmd == d && ((pattern == NULL || p->a_pattern == NULL)? (pattern == p->a_pattern) : (strcmp(pattern, p->a_pattern) == 0)) && p->a_arg_state == arg_state && p->a_arg_count == arg_count) return; /* eliminate duplicates */ if (ExecIndex >= NEXECS) { complain("Too many auto-executes, max %d.", NEXECS); /* NOTREACHED */ } p->a_pattern = copystr(pattern); p->a_cmd = d; p->a_arg_state = arg_state; p->a_arg_count = arg_count; ExecIndex += 1; } /* DoAutoExec: NEW and OLD are file names, and if NEW and OLD aren't the * same kind of file (i.e., match the same pattern) or OLD is NULL and it * matches, OR if the pattern is NULL (none was specified) then, we execute * the command associated with that kind of file. */ void DoAutoExec(new, old) register char *new, *old; { register struct AutoExec *p; for (p = AutoExecs; p != &AutoExecs[ExecIndex]; p++) { if (p->a_pattern == NULL || ((new != NULL && LookingAt(p->a_pattern, new, 0)) && !(old != NULL && LookingAt(p->a_pattern, old, 0)))) { arg_state = p->a_arg_state; arg_count = p->a_arg_count; ExecCmd(p->a_cmd); clr_arg_value(); } } } ZXchar addgetc() /* NOTE: can return EOF */ { ZXchar c; if (!InJoverc) { Asking = YES; AskingWidth = strlen(mesgbuf); c = getch(); Asking = NO; add_mess("%p ", c); } else { c = getch(); switch (c) { case '\n': c = EOF; /* this isn't part of the sequence */ break; case '\\': case '^': c = DecodePair(c, getch()); break; } } return c; } void Extend() { ExecCmd(findcom(": ")); } /* Read a positive long integer from CP. It must be in base BASE, and * complains if it isn't. If allints, all the characters * in the string must be integers or we return NO (failure); otherwise * we stop reading at the first nondigit and return YES (success). */ jbool chr_to_long(cp, base, allints, result) register const char *cp; int base; jbool allints; register long *result; { register char c; long value = 0; int sign; if ((c = *cp) == '-') { sign = -1; cp += 1; } else sign = 1; while ((c = *cp++) != '\0') { if (!jisdigit(c)) { if (allints) return NO; break; } c = c - '0'; if (c >= base) { complain("You must specify in base %d.", base); /* NOTREACHED */ } value = value * base + c; } *result = value * sign; return YES; } /* Read a positive integer from CP. It must be in base BASE, and * complains if it isn't. If allints, all the characters * in the string must be integers or we return NO (failure); otherwise * we stop reading at the first nondigit and return YES (success). */ jbool chr_to_int(cp, base, allints, result) register const char *cp; int base; jbool allints; register int *result; { long value; jbool ret = chr_to_long(cp, base, allints, &value); if (ret == YES) *result = (int)(value & ~0); /* XXX but no worse than before */ return ret; } long ask_long(def, prompt, base) const char *def; const char *prompt; int base; { const char *val = ask(def, prompt); long value; if (!chr_to_long(val, base, YES, &value)) { complain("That's not a number!"); /* NOTREACHED */ } return value; } int ask_int(def, prompt, base) const char *def; const char *prompt; int base; { const char *val = ask(def, prompt); int value = 0; /* avoid gcc complaint */ if (!chr_to_int(val, base, YES, &value)) { complain("That's not a number!"); /* NOTREACHED */ } return value; } void vpr_aux(vp, buf, size) register const struct variable *vp; char *buf; size_t size; { switch (vp->v_flags & V_TYPEMASK) { case V_INT: case V_WHOLEX: case V_WHOLE: case V_NAT: swritef(buf, size, (vp->v_flags & V_FMODE)? "%03o" : "%d", *((int *) vp->v_value)); break; case V_BOOL: swritef(buf, size, (*((int *) vp->v_value)) ? "on" : "off"); break; case V_STRING: case V_FILENAME: swritef(buf, size, "%s", vp->v_value); break; case V_CHAR: swritef(buf, size, "%p", *((ZXchar *) vp->v_value)); break; } } void PrVar() { struct variable *vp = (struct variable *) findvar(ProcFmt); char prbuf[MAXCOLS]; vpr_aux(vp, prbuf, sizeof(prbuf)); f_mess(": %f %s => %s", vp->Name, prbuf); stickymsg = YES; } void InsVar() { struct variable *vp = (struct variable *) findvar(ProcFmt); char prbuf[MAXCOLS]; vpr_aux(vp, prbuf, sizeof(prbuf)); ins_str(prbuf); stickymsg = YES; } void vset_aux(vp, prompt) const struct variable *vp; char *prompt; { if (vp->v_flags & V_READONLY) complain("[cannot set readonly variable %s]", vp->Name); switch (vp->v_flags & V_TYPEMASK) { case V_INT: case V_WHOLEX: case V_WHOLE: case V_NAT: { char def[30]; static const int lwbt[] = { ~0, /* V_INT -- I hope we are two's complement */ -1, /* V_WHOLEX */ 0, /* V_WHOLE */ 1, /* V_NAT */ }; int val, lwb = lwbt[(vp->v_flags & V_TYPEMASK) - V_INT]; vpr_aux(vp, def, sizeof(def)); val = ask_int(def, prompt, (vp->v_flags & V_FMODE)? 8 : 10); if (val < lwb) { complain("[%s must not be less than %d]", vp->Name, lwb); /* NOTREACHED */ } *((int *) vp->v_value) = val; break; } case V_BOOL: { static const char *possible[/*jbool*/] = {"off", "on", NULL }; jbool *valp = (jbool *) vp->v_value; int newval = complete(possible, possible[!*valp], prompt, CASEIND | ALLOW_OLD | ALLOW_EMPTY); if (newval < 0) newval = !*valp; *valp = newval; #ifdef MAC MarkVar(vp, -1, 0); /* mark the menu item */ #endif s_mess("%s%s", prompt, possible[newval]); break; } case V_FILENAME: { char fbuf[FILESIZE]; strcpy((char *) vp->v_value, ask_file(prompt, (char *) vp->v_value, fbuf)); break; } case V_STRING: { /* do_ask() so you can set string to "" if you so desire */ const char *str = do_ask("\r\n", NULL_ASK_EXT, (char *) vp->v_value, prompt); jamstrsub((char *) vp->v_value, str == NULL? NullStr : str, vp->v_size); break; } case V_CHAR: s_mess(prompt); *((ZXchar *) vp->v_value) = addgetc(); break; } if (vp->v_flags & V_MODELINE) UpdModLine = YES; if (vp->v_flags & V_CLRSCREEN) ClAndRedraw(); if (vp->v_flags & V_TTY_RESET) tty_adjust(); #ifdef UNIX if (vp->v_flags & V_UPDFREQ) SetClockAlarm(YES); #endif #if defined(USE_CTYPE) && !defined(NO_SETLOCALE) if (vp->v_flags & V_LOCALE) { locale_adjust(); ClAndRedraw(); } #endif } void SetVar() { struct variable *vp = (struct variable *) findvar(ProcFmt); char prompt[128]; swritef(prompt, sizeof(prompt), ": %f %s ", vp->Name); vset_aux(vp, prompt); } /* complete: buffer/command/keymap/macro/variable name completion. * * possible: an array of strings * prompt: the prompt to use * flags: a set of flags: * CASEIND: ignore case * ALLOW_OLD: allow answer listed in possible * ALLOW_NEW: allow answer not listed in possible * ALLOW_EMPTY: allow empty answer * * complete returns an index into possible, or -1 if there is no * right answer there, in which case what the user typed is in Minibuf. * * aux_complete is called by real_ask, on behalf of complete, to handle: * * ? Typeout possible completions (does not change the answer) * * TAB Extend answer as much as possible (this might actually * involve shrinking the answer until it is the prefix of * at least one Possible; if so, error). * * SP If answer is complete (i.e. matches a whole entry in Possible), * accept it. Otherwise, extend answer as much as possible; * if the result is unique, and we didn't shrink the answer, * accept it. * * CR or NL If ALLOW_NEW and answer non-empty: accept the answer. * If ALLOW_EMPTY and answer empty: accept the answer. * If ALLOW_OLD and answer is complete: accept it. * If ALLOW_OLD and answer is prefix of a unique Possible: accept that Possible. * If ALLOW_INDEX and answer is a numeral that is a legitimate * index into possible, accept as that possible. * Otherwise: error * * If we are InJoverc, we cannot be interactive, so ? is forbidden * and all the others are treated as CR; an error is fatal. * * The following file-static variables smuggle values from complete * to aux_complete and vice versa, behind the back of do_ask etc. * This could be nicer if C supported nested procedures (closures); * perhaps we should simulate them. */ private const char *const *Possible; /* possible arg of complete */ private int comp_flags, /* flags arg of complete */ comp_value; /* return value for complete; set by aux_complete */ private jbool aux_complete proto((ZXchar c)); /* needed to comfort dumb MS Visual C */ private jbool aux_complete(c) ZXchar c; { if (comp_flags & CASEIND) { char lc; char *lp; for (lp = linebuf; (lc = *lp) != '\0'; lp++) *lp = CharDowncase(lc); } if (c == '?') { int i; size_t len = strlen(linebuf); if (InJoverc) { complain("[invalid `?']"); /* NOTREACHED */ } /* kludge: in case we're using UseBuffers, in which case * linebuf gets written all over (but restored by TOstop/TOabort) */ strcpy(Minibuf, linebuf); TOstart("Completion"); /* for now ... */ for (i = 0; Possible[i] != NULL && !TOabort; i++) { if ((comp_flags & ALLOW_INDEX) && len == 0) Typeout("%2d %s", i+1, Possible[i]); else if (strncmp(Possible[i], Minibuf, len) == 0) Typeout("%s", Possible[i]); } TOstop(); } else { /* let's do some completion! */ int i, numeral = 0, /* avoid gcc complaint */ len = strlen(linebuf), minmatch = 1000, /* init with dummy to placate picky compilers */ maxmatch = 0, numfound = 0, lastmatch = -1; /* init with dummy to placate picky compilers */ if (InJoverc || c == '\n') c = '\r'; /* NL is synonym for CR; InJoverc, all are treated as CR */ for (i = 0; Possible[i] != NULL; i++) { int this_len = *Possible[i] == *linebuf ? numcomp(Possible[i], linebuf) : 0; if (maxmatch < this_len) maxmatch = this_len; if (this_len >= len) { if (Possible[i][len] == '\0' && c != '\t') { /* an exact match */ if (comp_flags & ALLOW_OLD) { comp_value = i; /* good: done */ return NO; } else { if (InJoverc) { complain("[%s already exists]"); /* NOTREACHED */ } add_mess(" [already exists]"); SitFor(7); return YES; } } minmatch = numfound == 0 ? (int)strlen(Possible[i]) : jmin(minmatch, numcomp(Possible[lastmatch], Possible[i])); numfound += 1; lastmatch = i; } } if (c == '\r' && len > 0 && (comp_flags & ALLOW_INDEX) && chr_to_int(linebuf, 10, YES, &numeral) && 0 < numeral && numeral <= i ) { comp_value = numeral - 1; /* accept as an index into possible */ return NO; } if (c == '\r' && (comp_flags & (len == 0? ALLOW_EMPTY : ALLOW_NEW))) { comp_value = -1; /* accept as new value (perhaps empty) */ return NO; } if (numfound == 1 && c != '\t' && (comp_flags & ALLOW_OLD)) { comp_value = lastmatch; return NO; } if (InJoverc) { complain("[\"%s\" %s]", linebuf, numfound == 0? "unknown" : "ambiguous"); /* NOTREACHED */ } if (numfound == 0) { /* Unknown: either not ALLOW_NEW (bad) or not CR (not good enough) */ add_mess(" [unknown]"); SitFor(7); if (maxmatch < len && (comp_flags & ALLOW_NEW) == 0) { linebuf[maxmatch] = '\0'; Eol(); } } else { /* Ambiguous (or unique, but TAB): extend as much as * possible without precluding any of the ambiguous matches. * Explain if we were expected to be done (CR) * or if we made no progress. */ null_ncpy(linebuf, Possible[lastmatch], (size_t) minmatch); modify(); makedirty(curline); Eol(); if (c == '\r' || minmatch == len) { add_mess(numfound == 1? " [complete]" : " [ambiguous]"); SitFor(7); } } } return YES; } int complete(possible, def, prompt, flags) register const char *const *possible; const char *def; const char *prompt; int flags; { /* protect static "Possible" etc. from being overwritten due to recursion */ if (InRealAsk) { complain((char *) NULL); /* NOTREACHED */ } Possible = possible; comp_flags = flags; (void) do_ask("\r\n \t?", aux_complete, def, prompt); return comp_value; } void Source() { char fnamebuf[FILESIZE]; jbool silence = is_an_arg(); PathCat(fnamebuf, sizeof(fnamebuf), HomeDir, #ifdef MSFILESYSTEM "jove.rc" #else ".joverc" #endif ); (void) ask_file((char *)NULL, fnamebuf, fnamebuf); if (!joverc(fnamebuf) && !silence) { message(IOerr("read", fnamebuf)); complain((char *)NULL); /* NOTREACHED */ } } /* TODO: Make this unsigned long when we dump support for pre-ANSI C */ /* calculate percentage without float and no overflow */ private int calc_percent(a, b) long a, b; { int v; if (b == 0) { v = 100; } else if (a > (~(1L << ((sizeof(long)*CHAR_BIT)-1)))/100) { v = (int) (a / (b / 100)); } else { v = (int) ((a * 100) / b); } return v; } /* TODO: Make dotchar, nchars unsigned long when we dump support for pre-ANSI C */ void BufPos() { register LinePtr lp = curbuf->b_first; register long i, dotline = 0; /* avoid uninitialized complaint from gcc -W */ long dotchar = 0; /* avoid uninitialized complaint from gcc -W */ long nchars; for (i = nchars = 0; lp != NULL; i++, lp = lp->l_next) { if (lp == curline) { dotchar = nchars + curchar; dotline = i + 1; } nchars += length(lp) + (lp->l_next != NULL); /* include the NL */ } f_mess("[\"%s\" line %D/%D, char %D/%D (%d%%), cursor = %d/%d]", filename(curbuf), dotline, i, dotchar, nchars, calc_percent(dotchar, nchars), calc_pos(linebuf, curchar), calc_pos(linebuf, (int)strlen(linebuf))); stickymsg = YES; } #ifdef SUBSHELL private jbool do_if(cmd) char *cmd; { char *args[12]; /* Parse cmd into an argv. Handle various quotes * but not environment variable references. */ { char *ip = cmd, *op = cmd, **ap = args; for (;;) { while (jiswhite(*ip)) ip++; if (*ip == '\0') break; if (ap == &args[elemsof(args)]) { complain("Too many args for IF shell command"); /* NOTREACHED */ } *ap++ = op; for (;;) { char c = *ip++, c2; switch (c) { case '\0': ip -= 1; /*FALLTHROUGH*/ case ' ': case '\t': break; case '"': case '\'': while ((c2 = *ip++) != c) { switch (c2) { case '\0': complain("Unpaired quote in IF command"); /*NOTREACHED*/ case '\\': if (c == '"') { c2 = *ip++; if (c2 == '\0') { complain("Misplaced \\ in IF command"); /* NOTREACHED */ } } /*FALLTHROUGH*/ default: *op++ = c2; break; } } continue; case '\\': c = *ip++; if (c == '\0') { complain("Misplaced \\ in IF command"); /* NOTREACHED */ } /*FALLTHROUGH*/ default: *op++ = c; continue; } break; } *op++ = '\0'; } *ap = NULL; } /* Exec the parsed command */ # ifdef UNIX { wait_status_t status; switch (ChildPid = fork()) { case -1: complain("[Fork failed for IF: %s]", strerror(errno)); /*NOTREACHED*/ case 0: close(0); /* we want reads to fail */ /* close(1); but not writes or ioctl's */ /* close(2); */ (void) execvp(args[0], args); _exit(errno); /*NOTREACHED*/ } dowait(&status); if (!WIFEXITED(status)) { complain("[no status returned from child in IF test]"); /* NOTREACHED */ } if (WIFSIGNALED(status)) { complain("[IF test terminated by signal %d]", WTERMSIG(status)); /* NOTREACHED */ } return WEXITSTATUS(status)==0; } # else # ifdef MSDOS_PROCS { int status; if ((status = spawnvp(0, args[0], args)) < 0) { complain("[Spawn failed: IF]"); /* NOTREACHED */ } return (status == 0); /* 0 means successful */ } # else /* !MSDOS_PROCS */ I do not know how to do this # endif /* !MSDOS_PROCS */ # endif /* !UNIX */ } #endif /* SUBSHELL */ private jbool cmdmatch(inp, verb, oppat) char *inp; char *verb; char *oppat; { int len = strlen(verb); if (caseeqn(inp, verb, (size_t)len) && (inp[len] == '\0' || jiswhite(inp[len]))) { if (!LookingAt(oppat, inp, len)) { complain("[malformed %s]", verb); /* NOTREACHED */ } return YES; } return NO; } jbool joverc(file) char *file; { char fbuf[LBSIZE], lbuf[LBSIZE]; jmp_buf savejmp; volatile int lnum = 0; File *volatile fp; volatile jbool eof = NO; volatile unsigned int /* bitstrings */ finger = 1, skipping = 0, inelse = 0; /* * joverc is a weird quasi-event loop (reading a line, setting * Inputp to point to the line, doing some special hackery to handle * a number as a numeric arg, invoking Extend() to parse the line * (with getch() taking chars from from Inputp rather than from the * keyboard) and execute the parsed command. If the command was * "execute-macro", then it will push the macro onto the stack, but * in order to run that macro immediately, we must perform a * mac_getc()+dispatch() loop immediately after each command (note * that a running macro might in-turn execute macros by pushing new * ones on the stack, so we must drain the macro stack fully before * proceeding to read the next line in the joverc). However, this * macro dispatch would go badly wrong if it called "source" * recursively into joverc() because the new joverc() loop would * then pop all the remaining strokes of the invoking macro from the * outer joverc(). While we could generalize this by saving and * restoring macro_stack before/after each command in joverc, that * seems excessive for typical use-cases of joverc, so instead, we * just disallow joverc from being invoked from a macro. If someone * encounters a valid use case for this, we can reconsider. */ if (in_macro()) { complain("cannot source file %s from within a macro", file); /* NOTREACHED */ } fp = open_file(file, fbuf, F_READ, NO); if (fp == NULL) return NO; /* Catch any errors, here, and do the right thing with them, * and then restore the error handle to whoever did a setjmp * last. */ InJoverc += 1; push_env(savejmp); if (setjmp(mainjmp)) { Buffer *savebuf = curbuf; SetBuf(do_select((Window *)NULL, "RC errors")); ins_str(sprint("%s:%d:%s", pr_name(file, YES), lnum, lbuf)); ins_str(sprint("\t%s\n", mesgbuf)); unmodify(); SetBuf(savebuf); Asking = NO; unwind_macro_stack(); } while (!eof) { /* This peculiar delayed EOF testing allows the last line to * end without a NL. We add NL later, so we leave room for it. */ eof = f_gets(fp, lbuf, sizeof(lbuf)-1); lnum += 1; Inputp = lbuf; while (jiswhite(*Inputp)) Inputp += 1; /* skip white space */ if (*Inputp == '#' || *Inputp == '\0') { /* a comment */ #ifdef SUBSHELL } else if (cmdmatch(Inputp, "if", "[ \t]*\\(.*\\)$")) { char cmd[128]; finger <<= 1; if (finger == 0) { complain("[`if' nested too deeply]"); /* NOTREACHED */ } putmatch(1, cmd, sizeof cmd); jdbg("%s:%d:if finger=0x%x skipping=0x%x inelse=0x%x cmd=\"%s\"\n", file, lnum, finger, skipping, inelse, cmd); if (skipping == 0 && !do_if(cmd)) skipping |= finger; #endif /* SUBSHELL */ #ifndef MAC /* no environment in MacOS */ } else if (cmdmatch(Inputp, "ifenv", "\\>[ \t]*\\<\\([^ \t][^ \t]*\\)\\>[ \t]\\(.*\\)$")) { finger <<= 1; if (finger == 0) { complain("[`ifenv' nested too deeply]"); /* NOTREACHED */ } jdbg("%s:%d:ifenv finger=0x%x skipping=0x%x inelse=0x%x\n", file, lnum, finger, skipping, inelse); if (skipping == 0) { char envname[128], envpat[128], *envval; putmatch(1, envname, sizeof envname); putmatch(2, envpat, sizeof envpat); envval = getenv(envname); if (envval==NULL || !LookingAt(envpat, envval, 0)) skipping |= finger; } #endif } else if (cmdmatch(Inputp, "ifvar", "\\>[ \t]*\\<\\([^ \t][^ \t]*\\)\\>[ \t]\\(.*\\)$")) { finger <<= 1; if (finger == 0) { complain("[`if' nested too deeply]"); /* NOTREACHED */ } jdbg("%s:%d:ifvar finger=0x%x skipping=0x%x inelse=0x%x\n", file, lnum, finger, skipping, inelse); if (skipping == 0) { char vname[128], vpat[128], vbuf[128], *val; jbool matched = NO; putmatch(1, vname, sizeof vname); putmatch(2, vpat, sizeof vpat); val = (char *)getvar(vname, vbuf, sizeof(vbuf)); jdbg("ifvar var \"%s\" => \"%s\" vpat \"%s\"\n", vname, val != NULL? val : "(null)", vpat); if (val==NULL || !(matched = LookingAt(vpat, val, 0))) skipping |= finger; jdbg("ifvar matched=%d skipping=0x%x\n", matched, skipping); } } else if (cmdmatch(Inputp, "else", "[ \t]*$")) { if (finger == 1 || (inelse & finger)) { complain("[Unexpected `else']"); /* NOTREACHED */ } inelse |= finger; skipping ^= finger; jdbg("%s:%d:else finger=0x%x skipping=0x%x inelse 0x%x\n", file, lnum, finger, skipping, inelse); } else if (cmdmatch(Inputp, "endif", "[ \t]*$")) { if (finger == 1) { complain("[Unexpected `endif']"); /* NOTREACHED */ } inelse &= ~finger; skipping &= ~finger; finger >>= 1; jdbg("%s:%d:endif finger=0x%x skipping=0x%x inelse=0x%x\n", file, lnum, finger, skipping, inelse); } else if (skipping == 0) { (void) strcat(Inputp, "\n"); for (;;) { ZXchar c; cmd_sync(); this_cmd = OTHER_CMD; if ((c = ZXC(*Inputp)) == '-' || jisdigit(c)) { LastKeyStruck = c; Inputp += 1; Digit(); } else { Extend(); /* run command, which might call getch, which might make Inputp NULL */ } /* get any pending input hiding in the peek buffer */ if ((c = peekchar) != EOF) { peekchar = EOF; if (Inputp != NULL && ZXRC(Inputp[-1]) == c) { Inputp -= 1; } else if (!jiswhite(c) && c != '\n' && c != '\0') { complain("[junk at end of line, c = %d %c]", c, jisprint(c)?c:' '); /* NOTREACHED */ } } while (Inputp && jiswhite(*Inputp)) Inputp += 1; /* skip white space */ if (Inputp == NULL || *Inputp == '\0' || *Inputp == '\n') { Inputp = NULL; /* * processed the line, now finish * running any macros that might * have been executed by the line. */ dispatch_macros(); break; } if (this_cmd != ARG_CMD) { complain("[junk at end of line, this_cmd = %d]", this_cmd); /* NOTREACHED */ } } } else { jdprintf("%s:%d:skip finger=0x%x skipping=0x%x inelse=0x%x \"%s\"\n", file, lnum, finger, skipping, inelse, Inputp); } } #ifdef SUBSHELL if (finger != 1) { finger = 1; complain("[Missing endif]"); /* NOTREACHED */ } #endif f_close(fp); pop_env(savejmp); Inputp = NULL; Asking = NO; InJoverc -= 1; return YES; } jove-4.17.5.5/extend.h000066400000000000000000000034721501102521500143540ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* values for the `flags' argument to complete (may be combined) */ #define CASEIND 001 /* map all to lower case */ #define ALLOW_OLD 002 /* accept member */ #define ALLOW_INDEX 004 /* accept index number as answer (on CR) */ #define ALLOW_NEW 010 /* accept non-member (on CR) */ #define ALLOW_EMPTY 020 /* accept empty answer (on CR) */ extern int InJoverc; /* depth in sourcing */ extern jbool joverc proto((char *file)); #ifdef USE_PROTOTYPES struct variable; /* forward declaration preventing prototype scoping */ #endif /* USE_PROTOTYPES */ extern void DoAutoExec proto((char *new, char *old)), vpr_aux proto((const struct variable *, char *, size_t)), vset_aux proto((const struct variable *, char *)); extern ZXchar addgetc proto((void)); extern long ask_long proto((const char *def, const char *prompt, int base)); extern int ask_int proto((const char *def, const char *prompt, int base)), complete proto((const char *const *possible, const char *def, const char *prompt, int flags)); extern jbool chr_to_int proto((const char *cp, int base, jbool allints, int *result)), chr_to_long proto((const char *cp, int base, jbool allints, long *result)); /* Commands: */ extern void BufPos proto((void)), CAutoExec proto((void)), Extend proto((void)), MAutoExec proto((void)), PrVar proto((void)), InsVar proto((void)), SetVar proto((void)), Source proto((void)); jove-4.17.5.5/externs.h000066400000000000000000000161601501102521500145530ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef MAC /* UNIX Library/System Routine Emulations for old Macintosh (mac.c) */ extern int creat proto((const char *, jmode_t)), /* open may have an optional third argument, promo(jmode_t) mode */ open proto((const char */*path*/, int /*flags*/, ...)), close proto((int)), unlink proto((const char *)), chdir proto((const char *)); extern off_t lseek proto((int /*fd*/, off_t /*offset*/, int /*whence*/)); extern time_t time proto((time_t *)); extern void menus_off proto((void)); /* called by real_ask, findcom, waitchar */ #endif /* MAC */ /*==== Declarations of Library/System Routines ====*/ #ifndef REALSTDC extern int errno; /* Redundant if declared in -- DHR */ #endif extern char *strerror proto((int)); /* errno.h or string.h? */ /* General Utilities: */ #ifdef REALSTDC #include #endif extern int abs proto((int)); extern void abort proto((void)); extern void exit proto((int)); extern int atoi proto((const char */*nptr*/)); extern void qsort proto((UnivPtr /*base*/, size_t /*nmemb*/, size_t /*size*/, int (*/*compar*/) ptrproto((UnivConstPtr, UnivConstPtr)))); extern char *getenv proto((const char *)); extern int system proto((const char *)); extern void free proto((UnivPtr)); extern UnivPtr calloc proto((size_t, size_t)), malloc proto((size_t)), realloc proto((UnivPtr, size_t)); /* Date and Time */ extern time_t time proto((time_t */*tloc*/)); extern char *ctime proto((const time_t *)); /* UNIX */ #ifdef MSFILESYSTEM # include #else # include #endif #ifdef MSC51 #define const /* the const's in the following defs conflict with MSC 5.1 */ #endif #if defined(WIN32) # define JRWSIZE_T unsigned int /* MSVC for 64bit uses this, not size_t */ #else # define JRWSIZE_T size_t #endif #ifndef NO_FCNTL # include #endif #ifndef O_RDONLY /* in POSIX or Unix */ # define O_RDONLY 0 # define O_WRONLY 1 # define O_RDWR 2 #endif #ifndef O_BINARY /* needed for MSDOS and perhaps others */ # define O_BINARY 0 /* fake if missing with value harmless when ORed */ #endif #ifndef O_CLOEXEC # define O_CLOEXEC 0 #endif #ifdef POSIX_UNISTD # include #else /* !POSIX_UNISTD */ extern int chdir proto((const char */*path*/)); /* POSIX, System Vr4, MSDOS have getcwd() of this form. * System Vr4 (sometimes?) types the second argument "int"!! * In io.c, we implement alternatives with getwd() and the pwd * command! Win32 has a getcwd with different signature! * Our old mac.c code provides a getcwd() replacement. */ # ifdef USE_GETCWD extern char *getcwd proto((char *, size_t)); # endif # ifdef HAS_SYMLINKS /* bufsiz might be of type int in old systems e.g. 4.3BSD and earlier */ extern JSSIZE_T readlink proto((const char */*path*/, char */*buf*/, size_t /*bufsiz*/)); # endif extern int access proto((const char */*path*/, int /*mode*/)); # ifndef F_OK /* in POSIX */ # define F_OK 0 /* does file exist? */ # define X_OK 1 /* is it executable by caller? */ # define W_OK 2 /* writable by caller? */ # define R_OK 4 /* readable by caller? */ # endif extern int creat proto((const char */*path*/, jmode_t /*mode*/)); /* open may have an optional third argument, promo(jmode_t) mode */ extern int open proto((const char */*path*/, int /*flags*/, ...)); extern jmode_t umask proto((jmode_t)); # ifdef NO_MKSTEMP # ifndef NO_MKTEMP extern char *mktemp proto((char */*template*/)); # endif # else extern int mkstemp proto((char */*template*/)); # endif extern JSSIZE_T read proto((int /*fd*/, UnivPtr /*buf*/, JRWSIZE_T /*nbytes*/)), write proto((int /*fd*/, UnivConstPtr /*buf*/, JRWSIZE_T /*nbytes*/)); # ifdef UNIX /* Zortech incorrectly defines argv as const char **. * Borland incorrectly defines argv as char *[] and omits some consts * Watcom incorrectly defines argv as const char *const * MSC incorrectly defines argv as char const* const * * on some or all exec*() prototype declarations that they supply. * Jove uses spawn on these platforms anyway. */ extern int execl proto((const char * /*path*/, const char * /*arg*/, ...)); extern int execlp proto((const char * /*file*/, const char * /*arg*/, ...)); extern int execv proto((const char * /*path*/, char *const /*argv*/[])); extern int execve proto((const char * /*path*/, char *const /*argv*/[], char *const /*envp*/[])); extern int execvp proto((const char * /*file*/, char *const /*argv*/[])); # endif # ifdef MSC51 # undef const # endif extern void _exit proto((int)); /* exit(), without flush, etc. */ extern unsigned alarm proto((unsigned /*seconds*/)); extern int pipe proto((int *)); extern int close proto((int)); extern int dup proto((int)); extern int dup2 proto((int /*old_fd*/, int /*new_fd*/)); extern off_t lseek proto((int /*fd*/, off_t /*offset*/, int /*whence*/)); extern int fchmod proto((int /*fd*/, jmode_t /*mode*/)); extern int chown proto((const char *, int, int)); extern int unlink proto((const char */*path*/)); #endif /* !POSIX_UNISTD */ #if defined(IBMPCDOS) || defined(WIN32) /* * At least as of 2007, perhaps earlier, the Microsoft runtime has * no X_OK and considers a value of 1 to be invalid, e.g see * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=30972 * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/access-waccess?view=vs-2019 * Older runtimes may have accepted it, but VS 2019, in Win 7 Pro, * crashes the program. */ # define J_X_OK F_OK #else # define J_X_OK X_OK #endif #ifndef FULL_UNISTD extern int fsync proto((int)); /* BSD UNIX * * Note: in most systems, declaration of a non-existant function is * OK if the function is never actually called. The parentheses around * the name prevent any macro expansion. Of course, if the types in the * prototype are not declared, the compiler gets upset. */ # ifdef USE_BCOPY extern void UNMACRO(bcopy) proto((UnivConstPtr, UnivPtr, size_t)); extern void UNMACRO(bzero) proto((UnivPtr, size_t)); # endif #endif /* !FULL_UNISTD */ /* termcap */ #ifdef TERMCAP # ifdef JTC #define DEFINE_PC_BC_UP_OSPEED 1 /* curses declares these, jtc does not! should it?*/ extern char * UNMACRO(jtcarg1) proto((const char *, int /* parm */)); extern char * UNMACRO(jtcarg2) proto((const char *, int /*destcol*/, int /*destline*/)); # define targ1(s, i) jtcarg1(s, i) # define targ2(s, c, l) jtcarg2(s, c, l) # else /* !JTC */ # ifdef TERMINFO extern char *UNMACRO(tparm) proto((const char *, ...)); # define targ1(s, i) tparm(s, i) # define targ2(s, c, l) tparm(s, l, c) # else /* !TERMINFO */ extern char *UNMACRO(tgoto) proto((const char *, int /*destcol*/, int /*destline*/)); # define targ1(s, i) tgoto(s, 0, i) # define targ2(s, c, l) tgoto(s, c, l) # endif /* TERMINFO */ # endif /* JTC */ #endif /* TERMCAP */ jove-4.17.5.5/fmt.c000066400000000000000000000214211501102521500136400ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "chars.h" #include "fp.h" #include "jctype.h" #include "disp.h" #include "extend.h" #include "fmt.h" #ifdef MAC # include "mac.h" #endif private void doformat proto((File *, const char *, va_list)), pad proto((DAPchar, int)); char mesgbuf[MESG_SIZE]; /* Formatting codes supported: * * %%: => '%' * %O, %D, %X: long => octal, decimal, or hex * %lo, %ld, %lx: long => octal, decimal, or hex * %o, %d, %x: int => octal, decimal, or hex * %c: char => character * %s: char* => string * * %b: buffer pointer => buffer's name * %f: void => current command's name * %n: int => int == 1? "" : "s" * %p: char => visible rep */ #ifdef ZTCDOS /* ZTCDOS only accepts va_list in a prototype */ void format(char *buf, size_t len, const char *fmt, va_list ap) #else void format(buf, len, fmt, ap) char *buf; size_t len; const char *fmt; va_list ap; #endif { File strbuf; strbuf.f_ptr = strbuf.f_base = buf; strbuf.f_fd = -1; /* Not legit for files */ strbuf.f_bufsize = strbuf.f_cnt = len; strbuf.f_flags = F_STRING; doformat(&strbuf, fmt, ap); f_putc('\0', &strbuf); /* f_putc will place this, even if overflow */ } /* pretty-print character c into buffer cp (up to PPWIDTH bytes) */ void PPchar(c, cp) ZXchar c; char *cp; { if (jisprint(c)) { cp[0] = c; cp[1] = '\0'; } else if (c < DEL) { strcpy(cp, "^?"); cp[1] = c +'@'; } else if (c == DEL) { strcpy(cp, "^?"); } else { cp[0] = '\\'; cp[1] = '0'+(c >> 6); cp[2] = '0'+((c >> 3) & 07); cp[3] = '0'+(c & 07); cp[4] = '\0'; } } private struct fmt_state { int precision, width; jbool leftadj; char padc; File *iop; } current_fmt; /* TODO: Make this unsigned long when we dump support for pre-ANSI C (use flag to ask for sign?) */ private void putld(d, base) long d; int base; { static const char chars[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; int len = 0; long tmpd = d; char ubuf[32], *ep = ubuf + sizeof(ubuf), *up = ep; if (d < 0) { len += 1; tmpd = -d; } if (current_fmt.width == 0 && current_fmt.precision) { current_fmt.width = current_fmt.precision; current_fmt.padc = '0'; } do { int i = tmpd % base; tmpd = tmpd / base; *--up = chars[i]; len += 1; } while (tmpd != 0); if (!current_fmt.leftadj) pad(current_fmt.padc, current_fmt.width - len); if (d < 0) f_putc('-', current_fmt.iop); while (up != ep) { f_putc((int)*up, current_fmt.iop); up++; } if (current_fmt.leftadj) pad(current_fmt.padc, current_fmt.width - len); } private void fmt_puts(str) const char *str; { int len; register const char *cp; if (str == NULL) str = "(null)"; len = strlen(str); if (current_fmt.precision == 0 || len < current_fmt.precision) current_fmt.precision = len; else len = current_fmt.precision; cp = str; if (!current_fmt.leftadj) pad(' ', current_fmt.width - len); while (--current_fmt.precision >= 0) f_putc(*cp++, current_fmt.iop); if (current_fmt.leftadj) pad(' ', current_fmt.width - len); } private void pad(c, amount) register DAPchar c; register int amount; { while (c && --amount >= 0) f_putc(c, current_fmt.iop); } /* * TODO: Support U and u for unsigned long and unsigned when * we dump support for pre-ANSI C, OXox should probably use * unsigned too. */ #ifdef ZTCDOS /* ZTCDOS only accepts va_list in a prototype */ private void doformat(register File *sp, register const char *fmt, va_list ap) #else private void doformat(sp, fmt, ap) register File *sp; register const char *fmt; va_list ap; #endif { register char c; struct fmt_state prev_fmt; prev_fmt = current_fmt; current_fmt.iop = sp; while ((c = *fmt++) != '\0') { if (c != '%') { f_putc(c, current_fmt.iop); continue; } current_fmt.padc = ' '; current_fmt.precision = current_fmt.width = 0; current_fmt.leftadj = NO; c = *fmt++; if (c == '-') { current_fmt.leftadj = YES; c = *fmt++; } if (c == '0') { current_fmt.padc = '0'; c = *fmt++; } while (c >= '0' && c <= '9') { current_fmt.width = current_fmt.width * 10 + (c - '0'); c = *fmt++; } if (c == '*') { current_fmt.width = va_arg(ap, int); c = *fmt++; } if (c == '.') { c = *fmt++; while (c >= '0' && c <= '9') { current_fmt.precision = current_fmt.precision * 10 + (c - '0'); c = *fmt++; } if (c == '*') { current_fmt.precision = va_arg(ap, int); c = *fmt++; } } reswitch: /* At this point, fmt points at one past the format letter. */ switch (c) { case '%': f_putc('%', current_fmt.iop); break; case 'O': case 'D': case 'X': putld(va_arg(ap, long), (c == 'O') ? 8 : (c == 'D') ? 10 : 16); break; case 'b': { Buffer *b = va_arg(ap, Buffer *); fmt_puts(b->b_name); break; } case 'c': f_putc(va_arg(ap, DAPchar), current_fmt.iop); break; case 'o': case 'd': case 'x': putld((long) va_arg(ap, int), (c == 'o') ? 8 : (c == 'd') ? 10 : 16); break; case 'f': /* current command name gets inserted here! */ fmt_puts(LastCmd->Name); break; case 'l': c = CharUpcase(*++fmt); goto reswitch; case 'n': if (va_arg(ap, int) != 1) fmt_puts("s"); break; case 'p': { ZXchar cc = ZXC(va_arg(ap, DAPchar)); if (cc == ESC) { fmt_puts("ESC"); } else { char cbuf[PPWIDTH]; PPchar(cc, cbuf); fmt_puts(cbuf); } } break; case 's': fmt_puts(va_arg(ap, char *)); break; default: complain("Unknown format directive: \"%%%c\"", c); /* NOTREACHED */ } } current_fmt = prev_fmt; } #ifdef STDARGS char * sprint(const char *fmt, ...) #else /*VARARGS1*/ char * sprint(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; static char line[LBSIZE]; va_init(ap, fmt); format(line, sizeof line, fmt, ap); va_end(ap); return line; } #ifdef STDARGS void writef(const char *fmt, ...) #else /*VARARGS1*/ void writef(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; va_init(ap, fmt); #ifdef NO_JSTDOUT /* Can't use sprint because caller might have * passed the result of sprint as an arg. */ { char line[100]; format(line, sizeof(line), fmt, ap); putstr(line); } #else /* !NO_JSTDOUT */ doformat(jstdout, fmt, ap); #endif /* !NO_JSTDOUT */ va_end(ap); } #ifdef STDARGS void fwritef(File *fp, const char *fmt, ...) #else /*VARARGS2*/ void fwritef(fp, fmt, va_alist) File *fp; const char *fmt; va_dcl #endif { va_list ap; va_init(ap, fmt); doformat(fp, fmt, ap); va_end(ap); } #ifdef STDARGS void swritef(char *str, size_t size, const char *fmt, ...) #else /*VARARGS3*/ void swritef(str, size, fmt, va_alist) char *str; size_t size; const char *fmt; va_dcl #endif { va_list ap; va_init(ap, fmt); format(str, size, fmt, ap); va_end(ap); } /* send a message (supressed if input pending) */ #ifdef STDARGS void s_mess(const char *fmt, ...) #else /*VARARGS1*/ void s_mess(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; if (InJoverc) return; va_init(ap, fmt); format(mesgbuf, sizeof mesgbuf, fmt, ap); va_end(ap); message(mesgbuf); } /* force a message: display it now no matter what. * If you wish it to stick, set stickymsg on after calling f_mess. */ #ifdef STDARGS void f_mess(const char *fmt, ...) #else /*VARARGS1*/ void f_mess(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; va_init(ap, fmt); format(mesgbuf, sizeof mesgbuf, fmt, ap); va_end(ap); DrawMesg(NO); stickymsg = NO; UpdMesg = YES; /* still needs updating (for convenience) */ } #ifdef STDARGS void add_mess(const char *fmt, ...) #else /*VARARGS1*/ void add_mess(fmt, va_alist) const char *fmt; va_dcl #endif { int mesg_len = strlen(mesgbuf); va_list ap; if (InJoverc) return; va_init(ap, fmt); format(&mesgbuf[mesg_len], (sizeof mesgbuf) - mesg_len, fmt, ap); va_end(ap); message(mesgbuf); } jbool jdebug = YES; /* so that first jdprintf is called */ const char *jdpath = NULL; /* if non-NULL, will be opened on first jdprintf */ #ifdef STDARGS void jdprintf(const char *fmt, ...) #else /*VARARGS1*/ void jdprintf(fmt, va_alist) const char *fmt; va_dcl #endif { static jbool first_time = YES; static File *dfp = NULL; va_list ap; if (first_time && jdpath != NULL) { dfp = f_open(jdpath, F_WRITE | F_LOCKED, NULL, LBSIZE); jdebug = (dfp != NULL); first_time = NO; } va_init(ap, fmt); if (dfp != NULL) { doformat(dfp, fmt, ap); flushout(dfp); } va_end(ap); } jove-4.17.5.5/fmt.h000066400000000000000000000021611501102521500136450ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #define MESG_SIZE MAXCOLS extern char mesgbuf[MESG_SIZE]; #define PPWIDTH 5 /* maximum width of PPchar output: "\\000\0" */ extern void format proto((char *buf, size_t len, const char *fmt, va_list ap)), PPchar proto((ZXchar c, char *cp)), add_mess proto((const char *, ...)), f_mess proto((const char *, ...)), fwritef proto((File *, const char *, ...)), writef proto((const char *, ...)), s_mess proto((const char *, ...)), swritef proto((char *, size_t, const char *, ...)); extern char *sprint proto((const char *, ...)); extern jbool jdebug; extern const char *jdpath; extern void jdprintf proto((const char *, ...)); #define jdbg if (!jdebug) ; else jdprintf jove-4.17.5.5/fp.c000066400000000000000000000203401501102521500134560ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "fp.h" #include "jctype.h" #include "disp.h" #include "fmt.h" #ifdef MAC # include "mac.h" #else /* !MAC */ # include #endif /* !MAC */ #ifdef RAINBOW private int rbwrite proto((int, char *, int)); #endif #ifndef L_SET # define L_SET 0 #endif #define MAXFILES 20 /* good enough for my purposes */ private File openfiles[MAXFILES]; /* must be zeroed initially */ File * fd_open(name, flags, fd, buffer, buf_size) const char *name; char *buffer; int flags, fd, buf_size; { register File *fp; register int i; for (fp = openfiles, i = 0; i < MAXFILES; i++, fp++) if (fp->f_flags == 0) break; if (i == MAXFILES) { complain("[Too many open files!]"); /* NOTREACHED */ } fp->f_bufsize = buf_size; fp->f_cnt = 0; fp->f_fd = fd; fp->f_flags = flags; if (buffer == NULL) { buffer = emalloc((size_t)buf_size); fp->f_flags |= F_MYBUF; } fp->f_base = fp->f_ptr = buffer; fp->f_name = copystr(name); return fp; } void gc_openfiles() { register File *fp; for (fp = openfiles; fp < &openfiles[MAXFILES]; fp++) if (fp->f_flags != 0 && (fp->f_flags & F_LOCKED) == 0) f_close(fp); } File * f_open(name, flags, buffer, buf_size) const char *name; char *buffer; int flags, buf_size; { register int fd; switch (F_MODE(flags)) { case F_READ: fd = open(name, O_RDONLY | O_BINARY | O_CLOEXEC); break; case F_APPEND: fd = open(name, O_WRONLY | O_BINARY | O_CLOEXEC); if (fd != -1) { (void) lseek(fd, (off_t)0, 2); break; } /* FALLTHROUGH */ case F_WRITE: #ifdef O_CREAT fd = open(name, O_CREAT | O_TRUNC | O_BINARY | O_RDWR | O_CLOEXEC, # ifdef UNIX (jmode_t)CreatMode # else S_IWRITE | S_IREAD # endif ); #else fd = creat(name, (jmode_t)CreatMode); #endif #ifdef O_TRUNC_BROKEN /* * Cygwin 3.1.2 open(..., O_TRUNC) seems to * not truncate files on VirtualBox shared * folders, perhaps on any network drive? But * it has ftruncate and that appears to * workaround the problem. Since most uses of * this function will subsequently write to * the minibuf, seems pointless to report * an error on ftruncate, which really should * never happen if we successfully opened the file! */ if (fd >= 0) (void) ftruncate(fd, 0); #endif break; default: fd = -1; /* avoid uninitialized complaint from gcc -W */ error("invalid F_MODE"); /* NOTREACHED */ } if (fd == -1) return NULL; return fd_open(name, flags, fd, buffer, buf_size); } void f_close(fp) File *fp; { const char *what = "close"; int err = 0; if ((fp->f_flags & (F_WRITE|F_APPEND)) && (fp->f_flags & F_ERR) == 0) { flushout(fp); #ifdef USE_FSYNC if (fsync(fp->f_fd) != 0) { what = "fsync"; err = errno; } #endif } if (close(fp->f_fd) != 0 && err == 0) err = errno; if (fp->f_flags & F_MYBUF) free((UnivPtr) fp->f_base); free((UnivPtr) fp->f_name); fp->f_flags = 0; /* indicates that we're available */ if (err != 0) { /* It would be nice to print fp->f_name, but it's gone. * Perhaps we should allow the memory to leak so that we * could easily print it. */ error("[%s error: %s]", what, strerror(err)); /* NOTREACHED */ } } ZXchar f_filbuf(fp) File *fp; { if (fp->f_flags & (F_EOF|F_ERR)) return EOF; fp->f_ptr = fp->f_base; #ifndef MSDOS do { #endif /* MSDOS */ fp->f_cnt = read(fp->f_fd, (UnivPtr) fp->f_base, (size_t) fp->f_bufsize); #ifndef MSDOS } while (fp->f_cnt == -1 && errno == EINTR); #endif /* MSDOS */ if (fp->f_cnt == -1) { /* I/O error -- treat as EOF */ writef("[Read error: %s]", strerror(errno)); fp->f_flags |= F_ERR | F_EOF; return EOF; } if (fp->f_cnt == 0) { fp->f_flags |= F_EOF; return EOF; } io_chars += fp->f_cnt; return f_getc(fp); } void putstr(s) register const char *s; { register char c; while ((c = *s++) != '\0') scr_putchar(c); } void fputnchar(s, n, fp) register char *s; register int n; register File *fp; { while (--n >= 0) f_putc(*s++, fp); } #ifndef NO_JSTDOUT void flushscreen() { flushout(jstdout); } #endif /* !NO_JSTDOUT */ void f_seek(fp, offset) register File *fp; off_t offset; { if (fp->f_flags & (F_WRITE|F_APPEND)) flushout(fp); fp->f_cnt = 0; /* next read will f_filbuf(), next write will flush() with no bad effects */ lseek(fp->f_fd, offset, L_SET); } void flushout(fp) register File *fp; { if (fp->f_flags & (F_READ | F_STRING | F_ERR)) { if (fp->f_flags != F_STRING) abort(); /* IMPOSSIBLE */ /* We just banged into the end of a string. * In the interests of continuing, we will cause * the rest of the output to be be heaped in the * last position. Surely it will end up as a NUL. UGH! */ fp->f_cnt = 1; fp->f_ptr = &fp->f_base[fp->f_bufsize - 1]; } else { char *p = fp->f_base; for (;;) { JSSIZE_T n = fp->f_ptr - p, wr; if (n <= 0) break; #ifdef RAINBOW wr = rbwrite(fp->f_fd, (UnivPtr) p, (size_t)n); #else wr = write(fp->f_fd, (UnivPtr) p, (size_t)n); #endif if (wr >= 0) { p += wr; } else { #ifndef MSDOS if (errno != EINTR) { #endif /* MSDOS */ #ifndef NO_JSTDOUT if (fp == jstdout) break; /* bail out, silently */ #endif fp->f_flags |= F_ERR; error("[I/O error(%s); file = %s, fd = %d]", strerror(errno), fp->f_name, fp->f_fd); /* NOTREACHED */ #ifndef MSDOS } #endif /* MSDOS */ } } fp->f_cnt = fp->f_bufsize; fp->f_ptr = fp->f_base; } } jbool f_gets(fp, buf, max) register File *fp; char *buf; size_t max; { register char *cp = buf; register ZXchar c; char *endp = buf + max - 1; if (fp->f_flags & F_EOF) return YES; while ((c = f_getc(fp)) != EOF && c != EOL) { /* We can't store NUL in our buffer, so ignore it. * Similarly, we can only store characters less than NCHARS. * Of course, with a little ingenuity we could store NUL: * NUL could be represented by EOL. */ if (c == '\0' #if NCHARS != UCHAR_ROOF || c >= NCHARS #endif ) continue; if (cp >= endp) { fp->f_flags |= F_LINETOOLONG; add_mess(" [Line too long]"); rbell(); return YES; } *cp++ = c; } *cp = '\0'; if (c == EOF) { if (cp != buf) add_mess(" [Incomplete last line]"); return YES; } #ifdef USE_CRLF /* a CR followed by a LF is treated as a NL. * Bug: the line-buffer is effectively shortened by one character. */ if (cp != buf && cp[-1] == '\r') *--cp = '\0'; #endif /* USE_CRLF */ io_lines += 1; return NO; /* this means okay */ } /* skip to beginning of next line, i.e., next read returns first * character of new line */ void f_toNL(fp) register File *fp; { if (fp->f_flags & F_EOF) return; for (;;) { switch (f_getc(fp)) { case EOF: fp->f_flags |= F_EOF; /*FALLTHROUGH*/ case EOL: return; } } } #ifdef PIPEPROCS size_t f_readn(fp, addr, n) register File *fp; register char *addr; size_t n; { register size_t nleft; for (nleft = n; nleft > 0; nleft--) { ZXchar c = f_getc(fp); if (f_eof(fp)) break; *addr++ = c; } return n - nleft; } #endif /* PIPEPROCS */ /* ScrBufSize is the size of the buffer for jstdout. It is also the * number of characters to be output between checks for input, so * it is meaningful even if jstdout isn't used. Its value is set by * settout based on the baud rate of output (on systems with baud rates). */ #ifdef NO_JSTDOUT int ScrBufSize = 256; #else int ScrBufSize = 1; /* until settout decides a better value & allocates a buf */ #endif #ifndef NO_JSTDOUT private char one_buf; private File stdout_File = {1, 1, 1, F_WRITE, &one_buf, &one_buf, (char *)NULL}; File *jstdout = &stdout_File; #endif #ifdef RAINBOW /* * use the Rainbow's video output function */ #include private int rbwrite(fd, buf, cnt) int fd; char *buf; int cnt; { union REGS vr; if (fd != 1) { write(fd, buf, cnt); } else { while (cnt-- > 0) { vr.x.ax = *buf++; vr.x.di = 0; int86(0x18, &vr, &vr); } } } #endif /* RAINBOW */ jove-4.17.5.5/fp.h000066400000000000000000000056111501102521500134670ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef NO_JSTDOUT extern void scr_putchar proto((char c)); /* defined in win32.c */ # ifdef IBMPCDOS # define flushscreen() { } # else /* !IBMPCDOS */ extern void flushscreen proto((void)); # endif /* !IBMPCDOS */ #else /* !NO_JSTDOUT */ extern File *jstdout; # define scr_putchar(c) f_putc((c), jstdout) extern void flushscreen proto((void)); #endif /* !NO_JSTDOUT */ #define f_putc(c, fp) { while (--(fp)->f_cnt < 0) flushout(fp); *(fp)->f_ptr++ = (c); } #define f_getc(fp) \ ((--(fp)->f_cnt < 0) ? f_filbuf(fp) : ZXRC(*(fp)->f_ptr++)) #define f_eof(fp) (((fp)->f_flags & F_EOF) != 0) /* typedef struct FileStruct File in jove.h */ struct FileStruct { int f_cnt, /* number of characters left in buffer */ f_bufsize, /* size of what f_base points to */ f_fd, /* fildes */ f_flags; /* various flags */ char *f_ptr, /* current offset */ *f_base; /* pointer to base */ char *f_name; /* name of open file */ }; #define F_READ 01 #define F_WRITE 02 #define F_APPEND 04 #define F_MODE(x) ((x)&07) #define F_EOF 010 #define F_STRING 020 #define F_ERR 040 #define F_LOCKED 0100 /* don't close this file upon error */ #define F_MYBUF 0200 /* f_alloc allocated the buffer, so f_close knows to free it up */ #define F_TELLALL 0400 /* whether to display info upon close */ #define F_READONLY 01000 /* file is read only */ #define F_LINETOOLONG 02000 /* read lines that are too long */ /* ScrBufSize is the size of the buffer for jstdout. It is also the * number of characters to be output between checks for input, so * it is meaningful even if jstdout isn't used. Its value is set by * settout based on the baud rate of output (on systems with baud rates). */ extern int ScrBufSize; extern File *f_open proto((const char *name, int flags, char *buffer, int buf_size)), *fd_open proto((const char *name, int flags, int fd, char *buffer, int bsize)); extern int f_filbuf proto((File *fp)); #ifdef PIPEPROCS extern size_t f_readn proto((File *fp,char *addr,size_t n)); #endif #if defined(ZTCDOS) || defined(__BORLANDC__) /* POSIX defines this as some signed arithmetic type * suitable for holding file sizes. */ typedef long off_t; #endif extern void f_close proto((File *fp)), f_seek proto((File *fp, off_t offset)), f_toNL proto((File *fp)), flushout proto((File *fp)), fputnchar proto((char *s,int n,File *fp)), gc_openfiles proto((void)), putstr proto((const char *s)); extern jbool f_gets proto((File *fp,char *buf,size_t max)); jove-4.17.5.5/ibmpcdos.c000066400000000000000000000233331501102521500146560ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #ifdef IBMPCDOS /* the body is the rest of this file */ #include "fp.h" /* scr_putchar */ #include "chars.h" #include "screen.h" #include "term.h" /* here come the actual emulation routines */ #include #include typedef unsigned char BYTE; typedef unsigned int WORD; #define VBS_set_cursor_position 0x02 #define VBS_get_cursor_position_and_size 0x03 #define VBS_select_active_display_page 0x05 #define VBS_scroll_window_up 0x06 #define VBS_scroll_window_down 0x07 #define VBS_read_character_and_attribute 0x08 #define VBS_write_character_and_attribute 0x09 #define VBS_TTY_character_output 0x0e #define VBS_get_current_video_state 0x0f #define VBSF_get_font_information 0x1130 #define VideoBIOS(r) int86(0x10, (r), (r)); private BYTE c_attr = 0x07, /* current attribute white on black */ c_row = 0, /* current row */ c_col = 0; /* current column */ int Txattr = 0x07, /* VAR: text-attribute (white on black) */ Mlattr = 0x70, /* VAR: mode-line-attribute (black on white) */ Hlattr = 0x10; /* VAR: highlight-attribute */ void getTERM() { /* Check if 101- or 102-key keyboard is installed. * This test is apparently unreliable, so we allow override. * Courtesy of Ralph Brown's interrupt list. */ char _far *kbd_stat_byte3 = (char _far *)0x00400096UL; enhanced_keybrd = (0x10 & *kbd_stat_byte3) != 0; pcSetTerm(); } private void setcolor(attr) BYTE attr; { c_attr = attr; } private void set_cur() { union REGS vr; vr.h.ah = VBS_set_cursor_position; vr.h.bh = 0; /* video page 0 */ vr.h.dl = c_col; vr.h.dh = c_row; VideoBIOS(&vr); } private void get_cur() { union REGS vr; vr.h.ah = VBS_get_cursor_position_and_size; vr.h.bh = 0; /* video page 0 */ VideoBIOS(&vr); c_col = vr.h.dl; c_row = vr.h.dh; } private BYTE chpl() { union REGS vr; vr.h.ah = VBS_get_current_video_state; VideoBIOS(&vr); return vr.h.ah; } #define cur_mov(r, c) { c_row = (r); c_col = (c); set_cur(); } private void scr_win(op, no, ur, lr) int op, no, ur, lr; { union REGS vr; vr.h.ah = op; /* scroll window up or down */ vr.h.al = no; /* number of rows to scroll */ vr.h.ch = ur; /* upper row */ vr.h.cl = 0; /* left column */ vr.h.dh = lr; /* lower row */ vr.h.dl = CO-1; /* right column */ vr.h.bh = c_attr; VideoBIOS(&vr); } void i_lines(top, bottom, num) int top, bottom, num; { scr_win(VBS_scroll_window_down, num, top, bottom); } void d_lines(top, bottom, num) int top, bottom, num; { scr_win(VBS_scroll_window_up, num, top, bottom); } void clr_page() { SO_off(); /* Note: VBS_scroll_window_up with a count of 0 clears the screen! */ scr_win(VBS_scroll_window_up, 0, 0, ILI); cur_mov(0, 0); } private void ch_out(c, n) BYTE c, n; { union REGS vr; vr.h.ah = VBS_write_character_and_attribute; vr.h.al = c; vr.h.bl = c_attr; vr.h.bh = 0; /* video page 0 */ vr.x.cx = n; VideoBIOS(&vr); } void clr_eoln() { ch_out(' ', CO-c_col); } /* Video mode setting derived from code posted to comp.os.msdos.programmer * by Joe Huffman 1990 August 15 (found on SIMTEL in msdos/screen/vidmode.zip) */ private BYTE lpp() { union REGS vr; int lines; vr.x.ax = VBSF_get_font_information; vr.h.bh = 0; /* we don't care which pointer we get back */ vr.h.dl = 0; /* default, if BIOS doesn't know how to this */ VideoBIOS(&vr); lines = vr.h.dl; /* number of last line on screen */ switch (lines) { default: return lines + 1; case 25: case 28: case 43: case 50: return lines; /* IBM EGA BUG!*/ case 0: return 25; /* Who knows? Just a guess. */ } } /* discover current video attribute */ private void get_c_attr() { union REGS vr; vr.h.dl = ' '; /* write out a SPace, using DOS */ vr.h.ah = 0x02; int86(0x21, &vr, &vr); vr.h.ah = VBS_TTY_character_output; /* backspace over it, using BIOS */ vr.h.al = BS; vr.h.bh = 0; /* page number 0 */ VideoBIOS(&vr); vr.h.ah = VBS_read_character_and_attribute; /* find out attribute */ VideoBIOS(&vr); c_attr = vr.h.ah; } /* codes for selecting scan lines for alpha mode (service 0x12, function 0x30) */ #define EGA200 0 #define EGA350 1 #define EGA400 2 /* codes for selecting ROM font (function code for service 0x11) * Notes from Ralf Brown's Interrupt List: * The routines called with AL=1xh are designed to be called only * immediately after a mode set and are similar to the routines called * with AL=0xh, except that: * Page 0 must be active. * Bytes/character is recalculated. * Max character rows is recalculated. * CRT buffer length is recalculated. * CRTC registers are reprogrammed as follows: * R09 = bytes/char-1 ; max scan line (mode 7 only) * R0A = bytes/char-2 ; cursor start * R0B = 0 ; cursor end * R12 = ((rows+1)*(bytes/char))-1 ; vertical display end * R14 = bytes/char ; underline loc * (*** BUG: should be 1 less ***) * the current block specifiers may be determined with INT 10/AH=1Bh, * looking at offsets 2Bh and 2Ch of the returned data (VGA only) */ #define EGA8x8 0x12 /* not 0x02 or 0x23 */ #define EGA8x14 0x11 /* not 0x01 or 0x22 */ #define EGA8x16 0x14 /* not 0x04 or 0x24 */ private void EGAsetup(scanlines, font) BYTE scanlines; BYTE font; { union REGS vr; vr.h.ah = VBS_select_active_display_page; vr.h.al = 0; /* page 0 */ VideoBIOS(&vr); vr.h.ah = 0x12; /* request EGA information */ vr.h.bl = 0x10; /* function number */ vr.x.cx = 0x0000; VideoBIOS(&vr); if (vr.x.cx != 0) { /* the display seems to be EGA or better */ vr.h.ah = 0x12; /* select scan lines for alpha mode */ vr.h.al = scanlines; vr.h.bl = 0x30; VideoBIOS(&vr); /* Note: bh is left over from VideoBIOS call *before* last! */ if (vr.h.bh == 0) vr.x.ax = 0x0003; /* monochrome */ else vr.x.ax = 0x0007; /* 80x25 color text */ VideoBIOS(&vr); vr.h.ah = 0x11; /* load ROM font */ vr.h.al = font; vr.h.bl = 0; /* into block 0 */ VideoBIOS(&vr); } get_c_attr(); } private jbool set_lines(lines) int lines; { switch (lines) { case 25: EGAsetup(EGA400, EGA8x16); break; case 28: EGAsetup(EGA400, EGA8x14); break; case 43: EGAsetup(EGA350, EGA8x8); break; case 50: EGAsetup(EGA400, EGA8x8); break; default: return NO; } return YES; } private jbool pc_set = NO; private int unsetLI; void pcSetTerm() { char *t = getenv("TERM"); if (!pc_set) { int lines = lpp(); unsetLI = lines; if (t != NULL) { if (stricmp(t, "ega25") == 0) lines = 25; else if (stricmp(t, "ega28") == 0) lines = 28; else if (stricmp(t, "ega43") == 0) lines = 43; else if (stricmp(t, "ega50") == 0) lines = 50; } if (lines != unsetLI && set_lines(lines)) pc_set = YES; } CO = chpl(); if (CO > MAXCOLS) CO = MAXCOLS; LI = lpp(); ILI = LI - 1; get_cur(); } void ttsize() { } void pcUnsetTerm() { if (pc_set) { pc_set = NO; (void) set_lines(unsetLI); } } private void line_feed() { if (++c_row > ILI) { c_row = ILI; scr_win(VBS_scroll_window_up, 1, 0, ILI); } set_cur(); } #define BELL_P 0x61 /* speaker */ #define BELL_D 0x2dc /* 550 hz */ #define TIME_P 0x40 /* timer */ #define TINI 182 /* 10110110b timer initialization */ void dobell(n) /* declared in term.h */ int n; { unsigned char spkr_state = inp(BELL_P); /* ??? Should accesses to timer be run with interrupts disabled? * It looks as if the timer would be in a bad state if a sequence * of accesses is interrupted. -- DHR 1995 Sept. */ outp(TIME_P+3, TINI); outp(TIME_P+2, BELL_D&0xff); outp(TIME_P+2, BELL_D>>8); outp(BELL_P, spkr_state|3); /* turn speaker on */ while (n-- > 0) { #ifdef NEVER /* Control duration by counting half cycles of the audio tone. * We detect a half-cycle boundary by noting when the high-order * byte of the counter changes between zero and non-zero. * This should be unaffected by CPU speed. * We can't use the BIOS interval timer facility because * I think it would use the timer channel we're already using. */ int half_cycs = 200; /* number of half-cycles to play */ jbool hi_is_0 = NO; /* detect zero transitions; initial lie unimportant */ for (;;) { (void) inp(TIME_P+2); /* low-order counter 2 byte */ if ((inp(TIME_P+2) == 0) != hi_is_0) { hi_is_0 = !hi_is_0; if (--half_cycs <= 0) break; } } #else unsigned int i = 0x8888; /* a CPU-speed dependent duration */ do {} while (--i > 0); #endif } outp(BELL_P, spkr_state); } /* scr_putchar: put char on screen. Declared in fp.h */ #ifdef USE_PROTOTYPES /* char is subject to default argument promotions */ void scr_putchar(char c) #else void scr_putchar(c) char c; #endif { switch (c) { case LF: line_feed(); break; case CR: c_col = 0; set_cur(); break; case BS: if (c_col > 0) c_col--; set_cur(); break; case CTL('G'): /* ??? is this ever used? */ dobell(1); break; default: ch_out((c), 1); if (++c_col > CO-1) { c_col = 0; line_feed(); } set_cur(); break; } } /* No cursor optimization on an IBMPCDOS, this simplifies things a lot. * Think about it: it would be silly! */ void Placur(line, col) int line, col; { cur_mov(line, col); CapCol = col; CapLine = line; } private jbool doing_so = NO, doing_us = NO; private void doattr() { setcolor((doing_so? Mlattr : Txattr) ^ (doing_us? Hlattr : 0)); } void SO_effect(f) jbool f; { doing_so = f; doattr(); } void US_effect(f) jbool f; { doing_us = f; doattr(); } #endif /* IBMPCDOS */ jove-4.17.5.5/insert.c000066400000000000000000000422511501102521500143620ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "list.h" #include "chars.h" #include "disp.h" #include "abbrev.h" #include "ask.h" #include "c.h" #include "delete.h" #include "insert.h" #include "fmt.h" #include "macros.h" #include "marks.h" #include "misc.h" #include "move.h" #include "para.h" #include "screen.h" /* for tabstop */ #include "sysprocs.h" #include "proc.h" #include "wind.h" private void DoNewline proto((jbool indentp)); #ifdef LISP private Bufpos *lisp_indent proto((void)); #endif /* Make a new line after "after" in buffer "buf", unless "after" is NULL, * in which case we insert the new line before first line. */ LinePtr listput(buf, after) register Buffer *buf; register LinePtr after; { register LinePtr newline = nbufline(); newline->l_prev = after; if (after == NULL) { /* Before the first line */ newline->l_next = buf->b_first; buf->b_first = newline; } else { newline->l_next = after->l_next; after->l_next = newline; } if (newline->l_next != NULL) newline->l_next->l_prev = newline; else if (buf != NULL) buf->b_last = newline; if (buf && buf->b_dot == NULL) buf->b_dot = newline; return newline; } /* Divide the current line and move the current line to the next one */ void LineInsert(num) register long num; { char newline[LBSIZE]; register LinePtr newdot, olddot; int oldchar; olddot = curline; oldchar = curchar; newdot = curline; while (--num >= 0) { newdot = listput(curbuf, newdot); SavLine(newdot, NullStr); } modify(); if (curchar != 0) { strcpy(newline, &linebuf[curchar]); linebuf[curchar] = '\0'; /* Shorten this line */ SavLine(curline, linebuf); strcpy(linebuf, newline); } else { /* Redisplay optimization */ newdot->l_dline = curline->l_dline; SavLine(curline, NullStr); } makedirty(curline); curline = newdot; curchar = 0; makedirty(curline); IFixMarks(olddot, oldchar, curline, curchar); } /* Inserts tabs and spaces to move the cursor to column GOAL. It * Uses the most optimal number of tabs and spaces no matter what * was there beforehand. */ void n_indent(goal) register int goal; { int dotcol; DelWtSpace(); dotcol = calc_pos(linebuf, curchar); if (tabstop != 0) { for (;;) { int incrmt = TABDIST(dotcol); if (dotcol + incrmt > goal) break; insert_c('\t', 1); dotcol += incrmt; } } if (dotcol != goal) insert_c(' ', (goal - dotcol)); } #ifdef ABBREV void MaybeAbbrevExpand() { if (MinorMode(Abbrev) && !jisident(LastKeyStruck) && !bolp() && jisident(linebuf[curchar - 1])) AbbrevExpand(); } #endif private void Insert(c) char c; { if (c == CTL('J')) LineInsert(arg_value()); else insert_c(c, arg_value()); } void overwrite(c, n) DAPchar c; int n; { register int i; for (i = 0; i < n; i++) { /* Delete one *column* forward (except that we don't * notice that control characters take two columns). */ if (!eolp() && (linebuf[curchar] != '\t' || tabstop == 0 || TABDIST(calc_pos(linebuf, curchar)) == 1)) { del_char(FORWARD, 1, NO); } insert_c(c, 1); } } void SelfInsert() { #ifdef ABBREV MaybeAbbrevExpand(); #endif if (LastKeyStruck != CTL('J') && MinorMode(OverWrite)) overwrite(LastKeyStruck, arg_value()); else Insert(LastKeyStruck); /* If we are in fill mode and at or beyond the right margin, * we break the line. However, we won't do this if the new * character is whitespace and we are at the end of the line: * DoJustify would discard the trailing space. */ if (MinorMode(Fill) && calc_pos(linebuf, curchar) >= RMargin && !(jiswhite(LastKeyStruck) && eolp())) { int margin; Bufpos save; if (MinorMode(Indent)) { DOTsave(&save); ToIndent(); margin = calc_pos(linebuf, curchar); SetDot(&save); } else { margin = LMargin; } DoJustify(curline, 0, curline, curchar + (int)strlen(&linebuf[curchar]), YES, margin); } } /* insert character C N times at point */ void insert_c(c, n) DAPchar c; int n; { if (n > 0) { modify(); makedirty(curline); ins_c(c, linebuf, curchar, n, LBSIZE); IFixMarks(curline, curchar, curline, curchar + n); curchar += n; } } /* Tab in to the right place for C mode */ void Tab() { #ifdef LISP if (MajorMode(LISPMODE) && (bolp() || !eolp())) { int dotchar = curchar; ToIndent(); if (dotchar > curchar) { Mark *m = MakeMark(curline, dotchar); (void) lisp_indent(); ToMark(m); DelMark(m); } else { (void) lisp_indent(); ToIndent(); } return; } #endif if (MajorMode(CMODE)) { if (within_indent()) (void) c_indent(NO); else { int curpos, tabbed_pos; skip_wht_space(); curpos = calc_pos(linebuf, curchar); tabbed_pos = curpos + (CIndIncrmt - (curpos % CIndIncrmt)); n_indent(tabbed_pos); } } else SelfInsert(); } void QuotChar() { ZXchar c = ask_ks(); if (c == '\0') { int n = arg_value(); while (n-- > 0) ins_str("^@"); } else { Insert(c); #ifdef PCNONASCII if (c == PCNONASCII) { c = waitchar(); if (c == '\0') { int n = arg_value(); while (n-- > 0) ins_str("^@"); } else { Insert(c); } } #endif } } /* Insert the paren. If in C mode and c is a '}' then insert the * '}' in the "right" place for C indentation; that is indented * the same amount as the matching '{' is indented. */ int PDelay = 5, /* VAR: paren flash delay in tenths of a second */ CIndIncrmt = 8; /* VAR: how much each indentation level pushes over in C mode */ void DoParen() { Bufpos *bp = NULL; /* avoid uninitialized complaint from gcc -W */ ZXchar c = LastKeyStruck; jbool tried = NO; if (!jisclosep(c)) { SelfInsert(); return; } if (MajorMode(CMODE) && c == '}' && within_indent()) { bp = c_indent(YES); tried = YES; } #ifdef LISP if (MajorMode(LISPMODE) && c == ')' && blnkp(linebuf)) { bp = lisp_indent(); tried = YES; } #endif SelfInsert(); if (MinorMode(ShowMatch) #ifndef MAC && !PreEmptOutput() #endif && !in_macro()) { b_char(1); /* Back onto the ')' */ if (!tried) bp = m_paren(c, BACKWARD, NO, YES); f_char(1); if (bp != NULL) { int nx = in_window(curwind, bp->p_line); if (nx != -1) { /* is visible */ Bufpos b; DOTsave(&b); SetDot(bp); SitFor(PDelay); SetDot(&b); } else s_mess("%s", lcontents(bp->p_line)); } mp_error(); /* display error message */ } } void LineAI() { DoNewline(YES); } void Newline() { DoNewline(MinorMode(Indent)); } private void DoNewline(indentp) jbool indentp; { Bufpos save; int indent; /* first we calculate the indent of the current line */ DOTsave(&save); ToIndent(); indent = calc_pos(linebuf, curchar); SetDot(&save); #ifdef ABBREV MaybeAbbrevExpand(); #endif if ( #ifdef LISP MajorMode(LISPMODE) || #endif indentp) { DelWtSpace(); } /* If there is more than 2 blank lines in a row then don't make * a newline, just move down one. */ if (arg_value() == 1 && eolp() && TwoBlank()) SetLine(curline->l_next); else LineInsert(arg_value()); if (indentp) { #ifdef LISP if (MajorMode(LISPMODE)) (void) lisp_indent(); else #endif { Bol(); n_indent((LMargin == 0) ? indent : LMargin); } } } void ins_str(str) const char *str; { ins_str_wrap(str, NO, LBSIZE-1); } void ins_str_wrap(str, ok_nl, wrap_off) const char *str; jbool ok_nl; int wrap_off; { register char c; Bufpos save; int llen; if (*str == '\0') return; /* ain't nothing to insert! */ if (wrap_off > LBSIZE-1) wrap_off = LBSIZE-1; DOTsave(&save); llen = strlen(linebuf); while ((c = *str++) != '\0') { if (c == '\n' || (ok_nl && llen >= wrap_off)) { IFixMarks(save.p_line, save.p_char, curline, curchar); modify(); makedirty(curline); LineInsert(1); DOTsave(&save); llen = strlen(linebuf); } if (c != '\n') { ins_c(c, linebuf, curchar++, 1, LBSIZE); llen += 1; } } IFixMarks(save.p_line, save.p_char, curline, curchar); modify(); makedirty(curline); } void open_lines(n) long n; { Bufpos dot; DOTsave(&dot); LineInsert(n); /* Open the lines... */ SetDot(&dot); } void OpenLine() { open_lines(arg_value()); } /* Take the region FLINE/FCHAR to TLINE/TCHAR and insert it at * ATLINE/ATCHAR in WHATBUF. */ Bufpos * DoYank(fline, fchar, tline, tchar, atline, atchar, whatbuf) LinePtr fline, tline, atline; int fchar, tchar, atchar; Buffer *whatbuf; { register LinePtr newline; static Bufpos bp; char save[LBSIZE], buf[LBSIZE]; LinePtr startline = atline; int startchar = atchar; lsave(); if (whatbuf != NULL) modify(); (void) ltobuf(atline, genbuf); strcpy(save, &genbuf[atchar]); (void) ltobuf(fline, buf); if (fline == tline) buf[tchar] = '\0'; linecopy(genbuf, atchar, &buf[fchar]); atline->l_dline = jputline(genbuf); makedirty(atline); fline = fline->l_next; while (fline != tline->l_next) { newline = listput(whatbuf, atline); newline->l_dline = fline->l_dline; makedirty(newline); fline = fline->l_next; atline = newline; atchar = 0; } jgetline(atline->l_dline, genbuf); atchar += tchar; linecopy(genbuf, atchar, save); atline->l_dline = jputline(genbuf); makedirty(atline); IFixMarks(startline, startchar, atline, atchar); bp.p_line = atline; bp.p_char = atchar; if (whatbuf != NULL) this_cmd = YANKCMD; getDOT(); /* Whatever used to be in linebuf */ return &bp; } void YankPop() { Mark *mp = CurMark(); LinePtr line, last; Bufpos *dot; switch (last_cmd) { case YANKCMD: { /* Direction to rotate the ring */ int dir = arg_value() < 0? 1 : NUMKILLS - 1; /* Now must find a recently killed region. */ do { killptr = (killptr+dir) % NUMKILLS; } while (killbuf[killptr] == NULL); } break; case UNDOABLECMD: break; default: complain("Yank something first!"); /*NOTREACHED*/ } lfreelist(reg_delete(mp->m_line, mp->m_char, curline, curchar)); line = killbuf[killptr]; last = lastline(line); dot = DoYank(line, 0, last, length(last), curline, curchar, curbuf); MarkSet(CurMark(), curline, curchar); SetDot(dot); if (last_cmd == UNDOABLECMD) this_cmd = OTHER_CMD; } /* This is an attempt to reduce the amount of memory taken up by each line. * Without this each malloc of a line uses sizeof (line) + sizeof(HEADER) * where line is 3 words and HEADER is 1 word. * This is going to allocate memory in chucks of CHUNKSIZE * sizeof (line) * and divide each chuck into Lines. A line is free in a chunk when its * line->l_dline == NULL_DADDR, so freeline sets l_dline to NULL_DADDR. */ #define CHUNKSIZE 300 #ifdef FAR_LINES # ifdef __BORLANDC__ # include /* Borland farmalloc() */ # else # ifdef OWCDOS # include # define farmalloc(sz) _fmalloc(sz) # define farfree(x) _ffree(x) # else # include /* Zortech farmalloc(), MSC (?) */ # endif # endif typedef struct chunk _far *ChunkPtr; # define CHUNKMALLOC(s) ((ChunkPtr) farmalloc(s)) # define CHUNKFREE(c) farfree((void _far *) (c)) #else typedef struct chunk *ChunkPtr; # define CHUNKMALLOC(s) ((ChunkPtr) malloc(s)) # define CHUNKFREE(c) free((UnivPtr) (c)) #endif struct chunk { ChunkPtr c_nextchunk; /* Next chunk of lines */ int c_nlines; /* Number of lines in this chunk (so they don't all have to be CHUNKSIZE long). */ struct line c_block[1 /* or larger */]; /* Chunk of memory */ }; private ChunkPtr fchunk = NULL; /* first chunk */ private LinePtr ffline = NULL; /* First free line */ private LinePtr faline = NULL; /* First available line */ private void freeline(line) register LinePtr line; { line->l_dline = NULL_DADDR; line->l_next = ffline; if (ffline) ffline->l_prev = line; line->l_prev = NULL; ffline = line; } /* Make sure that there are no dangling references to lines in the free list, * then move them to the end of the avail list. */ private void RecycleLines() { if (ffline == NULL) return; /* nothing to do */ ChkErrorLines(); /* ChkWindowLines(); -- nothing needs attention */ /* ChkBufLines(); -- nothing needs attention */ if (faline == NULL) { faline = ffline; } else { LinePtr laline = lastline(faline); laline->l_next = ffline; ffline->l_prev = laline; } ffline = NULL; } void lfreelist(first) register LinePtr first; { if (first != NULL) lfreereg(first, lastline(first)); } /* Append region from line1 to line2 onto the free list of lines */ void lfreereg(line1, line2) register LinePtr line1, line2; { register LinePtr next, last = line2->l_next; while (line1 != last) { next = line1->l_next; freeline(line1); line1 = next; } } private jbool newchunk() { register LinePtr newline; register long i; ChunkPtr f; long nlines = CHUNKSIZE; jbool done_gc = NO; for (;;) { f = CHUNKMALLOC(sizeof(struct chunk) + sizeof(struct line) * (nlines-1)); if (f != NULL) break; if (!done_gc) { GCchunks(); done_gc = YES; } else { nlines /= 2; if (nlines <= 0) return NO; } } f->c_nlines = nlines; for (i = 0, newline = f->c_block; i < nlines; newline++, i++) { newline->l_dline = NULL_DADDR; newline->l_next = faline; if (faline) faline->l_prev = newline; newline->l_prev = NULL; faline = newline; } f->c_nextchunk = fchunk; fchunk = f; return YES; } /* New BUFfer LINE */ LinePtr nbufline() { register LinePtr newline; if (faline == NULL) { RecycleLines(); if (faline == NULL) { if (!newchunk()) { complain("[Out of lines] "); /* NOTREACHED */ } } } newline = faline; faline = newline->l_next; if (faline) faline->l_prev = NULL; return newline; } /* Remove the free lines, in chunk c, from the free list because they are * no longer free. */ private void remfreelines(c) register ChunkPtr c; { register LinePtr lp; register long i; for (lp = c->c_block, i = c->c_nlines; i != 0 ; lp++, i--) { if (lp->l_prev == NULL) faline = lp->l_next; else lp->l_prev->l_next = lp->l_next; if (lp->l_next != NULL) lp->l_next->l_prev = lp->l_prev; } } /* This is used to garbage collect the chunks of lines when malloc fails * and we are NOT looking for a new buffer line. This goes through each * chunk, and if every line in a given chunk is not allocated, the entire * chunk is `free'd by "free()". */ /* ??? I think that this WILL be called when we are looking for a new * buffer line: nbufline() => newchunk() => GCchunks() -- DHR */ void GCchunks() { register ChunkPtr cp; ChunkPtr prev = NULL, next; register long i; register LinePtr newline; RecycleLines(); for (cp = fchunk; cp != NULL; cp = next) { next = cp->c_nextchunk; for (i = cp->c_nlines, newline = cp->c_block; ; newline++, i--) { if (i == 0) { /* Empty: unlink and free it!!! */ if (prev == NULL) fchunk = cp->c_nextchunk; else prev->c_nextchunk = cp->c_nextchunk; remfreelines(cp); CHUNKFREE(cp); break; } if (newline->l_dline != NULL_DADDR) { /* it's a keeper */ prev = cp; break; } } } } #ifdef LISP #include "re.h" /* Grind S-Expr */ void GSexpr() { Bufpos dot, end; if (linebuf[curchar] != '(') { complain((char *)NULL); /* NOTREACHED */ } DOTsave(&dot); FSexpr(); DOTsave(&end); SetDot(&dot); for (;;) { if (curline == end.p_line) break; line_move(FORWARD, 1, NO); if (!blnkp(linebuf)) (void) lisp_indent(); } SetDot(&dot); } /* lisp_indent() indents a new line in Lisp Mode, according to where * the matching close-paren would go if we typed that (sort of). */ private List *specials = NULL; private void init_specials() { static const char *const words[] = { "case", "def", "dolist", "fluid-let", "lambda", "let", "lexpr", "macro", "named-l", /* named-let and named-lambda */ "nlambda", "prog", "selectq", NULL }; const char *const *wordp = words; while (*wordp != NULL) list_push(&specials, (UnivPtr) *wordp++); } void AddSpecial() { const char *word; register List *lp; if (specials == NULL) init_specials(); word = ask((char *)NULL, ProcFmt); for (lp = specials; lp != NULL; lp = list_next(lp)) if (strcmp((char *) list_data(lp), word) == 0) return; /* already in list */ (void) list_push(&specials, (UnivPtr) copystr(word)); } private Bufpos * lisp_indent() { Bufpos *bp, savedot; int goal; bp = m_paren(')', BACKWARD, NO, YES); if (bp == NULL) return NULL; /* We want to end up * * (atom atom atom ... * ^ here. */ DOTsave(&savedot); SetDot(bp); f_char(1); if (linebuf[curchar] != '(') { register List *lp; if (specials == NULL) init_specials(); for (lp = specials; lp != NULL; lp = list_next(lp)) if (caseeqn((char *) list_data(lp), &linebuf[curchar], strlen((char *) list_data(lp)))) break; if (lp == NULL) { /* not special */ int c_char = curchar; while (jisident(linebuf[curchar])) curchar += 1; if (LookingAt("[ \t]*;\\|[ \t]*$", linebuf, curchar)) { curchar = c_char; } else { while (linebuf[curchar] == ' ') curchar += 1; } } else { curchar += 1; } } goal = calc_pos(linebuf, curchar); SetDot(&savedot); Bol(); n_indent(goal); return bp; } #endif /* LISP */ jove-4.17.5.5/insert.h000066400000000000000000000032311501102521500143620ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* ??? Why, for example, are GCchunks, lfreelist, and lfreereg here? -- DHR */ extern Bufpos *DoYank proto(( LinePtr fline, int fchar, LinePtr tline, int tchar, LinePtr atline, int atchar, Buffer *whatbuf)); extern void ins_str proto((const char *str)), ins_str_wrap proto((const char *str, jbool ok_nl, int wrap_off)), LineInsert proto((long num)), open_lines proto((long n)), overwrite proto((DAPchar c, int n)), insert_c proto((DAPchar c,int n)), GCchunks proto((void)), lfreelist proto((LinePtr first)), lfreereg proto((LinePtr line1,LinePtr line2)), n_indent proto((int goal)); #ifdef ABBREV extern void MaybeAbbrevExpand proto((void)); #endif extern LinePtr nbufline proto((void)); /* Commands: */ extern void #ifdef LISP AddSpecial proto((void)), /* add lisp special form */ GSexpr proto((void)), /* Grind S Expression. */ #endif DoParen proto((void)), LineAI proto((void)), Newline proto((void)), OpenLine proto((void)), QuotChar proto((void)), SelfInsert proto((void)), Tab proto((void)), YankPop proto((void)); /* Variables: */ extern int CIndIncrmt; /* VAR: how much each indentation level pushes over in C mode */ extern int PDelay; /* VAR: paren flash delay in tenths of a second */ jove-4.17.5.5/io.c000066400000000000000000001310131501102521500134600ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "list.h" #include "fp.h" #include "jctype.h" #include "disp.h" #include "ask.h" #include "fmt.h" #include "insert.h" #include "marks.h" #include "sysprocs.h" #include "proc.h" #include "wind.h" /* only used by JReadFile for fixup */ #include "rec.h" #ifdef MAC # include "mac.h" #else # include #endif #ifdef MSFILESYSTEM # include # include # include /* _splitpath, _makepath */ extern int UNMACRO(rename)(const char *old, const char *new); /* */ # ifndef _MAX_DIR # define _MAX_DIR FILESIZE # endif # ifndef _MAX_FNAME # define _MAX_FNAME 9 # endif # ifndef _MAX_EXT # define _MAX_EXT 4 # endif #endif /* MSFILESYSTEM */ private void filemunge proto((char *newname)), chk_divergence proto((Buffer *thisbuf, const char *fname, const char *how)); private struct block *lookup_block proto((daddr)); private char *getblock proto((daddr, jbool)); private jbool f_getputl proto((LinePtr line,File *fp)); #ifdef BACKUPFILES private void file_backup proto((char *fname)); #endif long io_chars; /* number of chars in this open_file */ long io_lines; /* number of lines in this open_file */ #ifdef BACKUPFILES jbool BkupOnWrite = NO; /* VAR: make backup files when writing */ #endif #ifndef MSFILESYSTEM #define Dchdir(to) chdir(to) #else /* MSFILESYSTEM */ # ifdef WIN32 # define _dos_getdrive(dd) (*(dd)=_getdrive()) # define _dos_setdrive(d, n) ((*(n)=_getdrive()), _chdrive((d))) # endif # ifdef ZTCDOS # define _dos_getdrive(dd) dos_getdrive(dd) # define _dos_setdrive(d, n) dos_setdrive((d), (n)) private void _splitpath(const char *path, char *drv, char *dir, char *fn, char *ext) { const char *p; size_t l; if (path[0]!='\0' && path[1]==':') { *drv++ = *path++; *drv++ = *path++; } *drv = '\0'; p = strrchr(path, '/'); if (p != NULL) { /* ??? should we have / at the end of the directory? */ p++; memcpy(dir, path, (size_t) (p-path)); dir += p-path; path = p; } *dir = '\0'; p = strchr(path, '.'); if (p == NULL) p = path+strlen(path); l = p-path; if (l > 8) l = 8; null_ncpy(fn, path, l); l = strlen(p); if (l > 4) l = 4; null_ncpy(ext, p, l); } private void _makepath(char *path, const char *drv, const char *dir, const char *fn, const char *ext) { if (drv[0] != '\0') { *path++ = drv[0]; *path++ = ':'; *path = '\0'; } if (dir[0] != '\0') { strcpy(path, dir); path += strlen(path); if (path[-1] != '/' && path[-1] != '\\') { *path++ = '/'; *path = '\0'; } } strcpy(path, fn); path += strlen(path); switch (ext[0]) { case '\0': break; default: *path++ = '.'; /*FALLTHROUGH*/ case '.': strcpy(path, ext); break; } } # endif /* ZTCDOS */ /* Change drive and directory * This is not quite like a UNIX chdir because each drive has a * separate current directory. If the path is not absolute, it * will be relative to the current directory of the drive. * On the other hand, this is not the DOS chdir because it does * change the current drive if one is specified. */ private int Dchdir(to) char *to; { unsigned d, dd; if (to[1] == ':') { d = CharUpcase(to[0]) - ('A' - 1); if (d < 'A'-('A'-1) || 'Z'-('A'-1) < d) { complain("invalid drive"); /* NOTREACHED */ } _dos_getdrive(&dd); if (dd != d) _dos_setdrive(d, &dd); /* ??? no failure report? */ to += 2; /* skip drive spec */ } return *to == '\0'? 0 : chdir(to); } private char * fixpath(path) char *path; { char *p; for (p = path; *p != '\0'; p++) if (*p == '\\') *p = '/'; # ifdef MSDOS return strlwr(path); # else return path; /* Win32 is case-preserving. */ # endif } private void abspath(so, dest) char *so, *dest; { char cwd[FILESIZE], cwdD[3], cwdDIR[_MAX_DIR], cwdF[_MAX_FNAME], cwdEXT[_MAX_EXT], soD[3], soDIR[_MAX_DIR], soF[_MAX_FNAME], soEXT[_MAX_EXT]; _splitpath(fixpath(so), soD, soDIR, soF, soEXT); getcwd(cwd, FILESIZE); if (*soD != '\0') { /* Find current working directory on specified drive * There is a DOS system call to do this (service 0x47), * but the C library doesn't have a glue routine for it. * We get the same effect with this kludgy code. */ Dchdir(soD); /* note: without a path, current directory is unchanged */ getcwd(cwdDIR, FILESIZE); cwd[2] = '\0'; /* toss away path, leaving only drive spec */ Dchdir(cwd); strcpy(cwd, cwdDIR); } (void) fixpath(cwd); if (cwd[strlen(cwd)-1] != '/') strcat(cwd, "/x.x"); /* need dummy filename */ _splitpath(fixpath(cwd), cwdD, cwdDIR, cwdF, cwdEXT); /* Reconstruct the path as follows: * - If it is NOT a UNC (network) name, and doesn't have a drive letter, * add one. * - If it is a relative path, add the current drive/directory * to convert it to an absolute path. */ _makepath(dest, *soD == '\0' && (soDIR[0]!='/'||soDIR[1]!='/') ? cwdD : soD, *soDIR != '/'? strcat(cwdDIR, soDIR) : soDIR, soF, soEXT); fixpath(dest); /* can't do it often enough */ } #endif /* MSFILESYSTEM */ int MakeTemp(buf, complaint) char *buf; const char *complaint; { const char *errfmt = "cannot create \"%s\" for %s: %s (%d)"; #ifdef NO_MKSTEMP # ifdef NO_MKTEMP /* Some systems don't provide mkstemp or mktemp (nor should * they -- ANSI defines tmpnam). Unfortunately tmpnam doesn't * do what we want either, so we roll one by hand. */ char *seq; char *p; for (seq = buf + strlen(buf); seq>buf && seq[-1]=='X'; seq--) ; for (p = seq; *p != '\0'; p++) *p = '0'; for (;;) { struct stat sb; jdbg("stat temp \"%s\"\n", buf); if (stat(buf, &sb) < 0 # ifdef ZTCDOS /* Zortech yields ENOTDIR when path isn't found, * even if the prefix does exist. Pretty silly! */ && errno == ENOTDIR # else && errno == ENOENT # endif ) { # ifdef O_EXCL int fd = open(buf, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IWRITE | S_IREAD); # else /* !O_EXCL */ int fd = creat(buf, 0600); # endif /* !O_EXCL */ jdbg("opened temp \"%s\" %d %d\n", buf, fd, errno); if (fd != -1) return fd; } for (p = seq; ; ) { if (*p == '\0') { /* we ran out of possible names! */ complain(errfmt, buf, complaint, "ran out of names", 0); /*NOTREACHED*/ } else if (*p == '9') { *p++ = '0'; } else { *p += 1; break; } } } # else /* !NO_MKTEMP */ int fd; jdbg("mktemp \"%s\"\n", buf); if (mktemp(buf) == NULL || -1 == (fd = # ifdef O_EXCL open(buf, O_CREAT | O_EXCL | O_RDWR | O_BINARY, S_IWRITE | S_IREAD) # else /* !O_EXCL */ creat(buf, 0600) # endif /* !O_EXCL */ )) { complain(errfmt, buf, complaint, strerror(errno), errno); /* NOTREACHED */ } return fd; # endif /* !NO_MKTEMP */ #else /* !NO_MKSTEMP */ /* Ordinary mkstemp, except that we juggle umask to ensure * that the file is only readable by the owner. * Modern mkstemp implementations don't need this, * because they create the tempfile with 0600, * but old ones use 0666. Making the umask 0077 should * solve this. */ jmode_t saved_umask #ifdef S_IRWXG = umask(S_IRWXG | S_IRWXO); #else = umask(077); #endif int fd = mkstemp(buf); int saved_errno = errno; jdbg("mkstemp \"%s\" %d %d\n", buf, fd, saved_errno); (void) umask(saved_umask); errno = saved_errno; if (fd == -1) { complain(errfmt, buf, complaint, strerror(errno), errno); /*NOTREACHED*/ } return fd; #endif /* !NO_MKSTEMP */ } void close_file(fp) File *fp; { if (fp != NULL) { if (fp->f_flags & F_TELLALL) add_mess(" %D lines, %D characters.", io_lines, io_chars); f_close(fp); } } /* Write the region from line1/char1 to line2/char2 to FP. This * never CLOSES the file since we don't know if we want to. */ jbool EndWNewline = 1; /* VAR: end files with a blank line */ void putreg(fp, line1, char1, line2, char2, makesure) register File *fp; LinePtr line1, line2; int char1, char2; jbool makesure; { if (makesure) (void) fixorder(&line1, &char1, &line2, &char2); while (line1 != line2->l_next) { register char *lp = lcontents(line1) + char1; if (line1 == line2) { fputnchar(lp, (char2 - char1), fp); io_chars += (char2 - char1); } else { register char c; while ((c = *lp++) != '\0') { f_putc(c, fp); io_chars += 1; } } if (line1 != line2) { io_lines += 1; io_chars += 1; #ifdef USE_CRLF f_putc('\r', fp); #endif /* USE_CRLF */ f_putc(EOL, fp); } line1 = line1->l_next; char1 = 0; } flushout(fp); } private void dofread(fp) register File *fp; { char end[LBSIZE]; jbool xeof; LinePtr savel = curline; int savec = curchar; strcpy(end, linebuf + curchar); xeof = f_gets(fp, linebuf + curchar, (size_t) (LBSIZE - curchar)); SavLine(curline, linebuf); while(!xeof) { curline = listput(curbuf, curline); xeof = f_getputl(curline, fp); } getDOT(); linecopy(linebuf, (curchar = strlen(linebuf)), end); SavLine(curline, linebuf); IFixMarks(savel, savec, curline, curchar); } void read_file(file, is_insert) char *file; jbool is_insert; { Bufpos save; File *fp; jbool err; int save_type; char *save_fname; if (!is_insert) curbuf->b_ntbf = NO; fp = open_file(file, iobuff, F_READ | F_TELLALL, NO); if (fp == NULL) { if (!is_insert && errno == ENOENT) s_mess("(new file)"); else s_mess(IOerr("open", file)); return; } if (!is_insert) { (void) do_stat(curbuf->b_fname, curbuf, DS_SET); set_arg_value((fp->f_flags & F_READONLY)? 1 : 0); TogMinor(BReadOnly); } DOTsave(&save); /* * if read fails, e.g. too long line, it would be * dangerous to save the buffer back to the real * filename, so we mark the buffer as scratch (unless * we are inserting, in which case the buffer might * have other valuable info worth saving, even with * the truncated line, sigh!), and give it a temporary * fname, which we restore after the read succeeds. */ save_type = curbuf->b_type; save_fname = curbuf->b_fname; if (save_fname) { char *tmpfname = (char *)emalloc(FILESIZE); backup_name(save_fname, "+", tmpfname, FILESIZE); jdbg("temporary name \"%s\"\n", tmpfname); curbuf->b_fname = tmpfname; } if (!is_insert) curbuf->b_type = B_SCRATCH; dofread(fp); if (is_insert && io_chars > 0) { modify(); set_mark(); } SetDot(&save); getDOT(); err = (fp->f_flags & (F_ERR | F_LINETOOLONG)) != 0; close_file(fp); if (err) { if (save_fname) free((UnivPtr)save_fname); complain("[Error reading file%s]", is_insert ? ", buffer has tmp name now" : ", buffer marked as scratch with tmp name"); /* NOTREACHED */ } curbuf->b_type = save_type; if (save_fname) { char *tmpfname = curbuf->b_fname; jdbg("restoring original name \"%s\"\n", save_fname); curbuf->b_fname = save_fname; free((UnivPtr) tmpfname); } } void SaveFile() { if (!IsModified(curbuf) && !curbuf->b_diverged) { if (curbuf->b_fname != NULL) (void) do_stat(curbuf->b_fname, curbuf, DS_NONE); if (!curbuf->b_diverged) { message("No changes need to be written."); return; } } if (curbuf->b_fname == NULL) { /* We change LastCmd because otherwise the prompt for * the filename will be ": visit-file". With this * fudge, it will be ": write-file". */ const data_obj *saved_lc = LastCmd; static const data_obj dummy = { 0, "write-file" }; LastCmd = &dummy; JWriteFile(); LastCmd = saved_lc; } else { filemunge(curbuf->b_fname); chk_divergence(curbuf, curbuf->b_fname, "save"); file_write(curbuf->b_fname, NO); } } const char *HomeDir; /* home directory */ size_t HomeLen; /* length of home directory string */ private List *DirStack = NULL; #define dir_name(dp) ((char *) list_data((dp))) #define PWD_PTR (list_data(DirStack)) #define PWD ((char *) PWD_PTR) char * pwd() { return PWD; } /* Format a file name without redundant prefix. * The result will be in a static buffer. * Note: by always using the static buffer, we allow ask_ford, * as it is currently coded, to accept aliased arguments. * The result will always fit in a FILESIZE buffer. */ char * pr_name(fname, okay_home) const char *fname; jbool okay_home; { if (fname == NULL) { return NULL; } else { static char name_buf[FILESIZE]; size_t PWDlen = strlen(PWD); size_t improvement = 0; if (strlen(fname) >= (size_t)FILESIZE) { complain("filename longer than %d", FILESIZE-1); /* NOTREACHED */ } strcpy(name_buf, fname); /* default: unchanged */ if (strncmp(fname, PWD, PWDlen) == 0 && fname[PWDlen] == '/') { /* Below current directory: strip prefix and /. * Assumption: fname[PWDlen+1] is not / or \0. */ strcpy(name_buf, fname + PWDlen + 1); improvement = PWDlen + 1; } if (okay_home && HomeLen > improvement + 1 && strncmp(fname, HomeDir, HomeLen) == 0 && fname[HomeLen] == '/') { /* Below home directory: replace prefix with ~. */ name_buf[0] = '~'; strcpy(name_buf + 1, fname + HomeLen); /* improvement = HomeLen - 1; */ } return name_buf; } } void Chdir() { char dirbuf[FILESIZE]; (void) ask_dir((char *)NULL, PWD, dirbuf); if (Dchdir(dirbuf) == -1) { s_mess("cd: cannot change into %s.", dirbuf); return; } UpdModLine = YES; setCWD(dirbuf); prCWD(); #ifdef MAC Bufchange = YES; #endif } #ifdef USE_GETWD extern char *getwd proto((char *)); /* ARGSUSED bufsize */ char * getcwd(buffer, bufsize) char *buffer; size_t bufsize; { return getwd(buffer); } #endif #ifdef USE_PWD /* ARGSUSED bufsize */ char * getcwd(buffer, bufsize) char *buffer; size_t bufsize; { Buffer *old = curbuf; char *ret_val; /* ??? The use of a buffer ought to be more polite -- * what if it were already in use? (a) the buffer contents * might be valuable, so we should ask whether we can clobber, * and (b) we don't have any code to empty the buffer anyway. * Luckily, this is only called once, at the beginning of time, * so things ought to be OK. Perhaps we should delete this buffer * after we are finished with it. * (MSDOS calls its own version of this routine more often, * but that version is quite different.) */ SetBuf(do_select((Window *)NULL, "pwd-output")); curbuf->b_type = B_PROCESS; (void) UnixToBuf(0, "pwd-output", (char *)NULL, "/bin/pwd"); ToFirst(); jamstrsub(buffer, linebuf, bufsize); SetBuf(old); return buffer; } #endif /* USE_PWD */ /* Check if dn is the name of the current working directory * and that it is in cannonical form */ jbool chkCWD(dn) char *dn; { #ifdef USE_INO char filebuf[FILESIZE]; struct stat dnstat, dotstat; if (dn[0] != '/') return NO; /* need absolute pathname */ PathParse(dn, filebuf); return stat(filebuf, &dnstat) == 0 && stat(".", &dotstat) == 0 && dnstat.st_dev == dotstat.st_dev && dnstat.st_ino == dotstat.st_ino; #else /* !USE_INO */ return NO; /* no way of telling */ #endif /* !USE_INO */ } void setCWD(d) char *d; { if (DirStack == NULL) list_push(&DirStack, (UnivPtr)NULL); PWD_PTR = freealloc((UnivPtr) PWD, strlen(d) + 1); strcpy(PWD, d); } void getCWD() { char *cwd; char pathname[FILESIZE]; #ifndef MAC /* no environment in MacOS */ cwd = getenv("CWD"); if (cwd == NULL || !chkCWD(cwd)) { cwd = getenv("PWD"); if (cwd == NULL || !chkCWD(cwd)) { #endif cwd = getcwd(pathname, sizeof(pathname)); if (cwd == NULL) { error("Cannot get current directory"); /* NOTREACHED */ } #ifndef MAC /* no environment in MacOS */ } } #endif #ifdef MSFILESYSTEM cwd = fixpath(cwd); #endif /* MSFILESYSTEM */ setCWD(cwd); } void prDIRS() { register List *lp; s_mess(ProcFmt); for (lp = DirStack; lp != NULL; lp = list_next(lp)) add_mess("%s ", pr_name(dir_name(lp), YES)); } void prCWD() { f_mess(": %f => \"%s\"", PWD); stickymsg = YES; } private void doPushd(newdir) char *newdir; { UpdModLine = YES; if (*newdir == '\0') { /* Wants to swap top two entries */ if (list_next(DirStack) == NULL) { complain("pushd: no other directory."); /* NOTREACHED */ } newdir = dir_name(list_next(DirStack)); if (Dchdir(newdir) == -1) { s_mess("pushd: cannot change back into %s.", newdir); return; } list_data(list_next(DirStack)) = list_data(DirStack); list_data(DirStack) = (UnivPtr) newdir; } else { if (Dchdir(newdir) == -1) { s_mess("pushd: cannot change into %s.", newdir); return; } (void) list_push(&DirStack, (UnivPtr)NULL); setCWD(newdir); } prDIRS(); } void Pushd() { char dirbuf[FILESIZE]; (void) ask_dir((char *)NULL, NullStr, dirbuf); doPushd(dirbuf); } void Pushlibd() { char dirbuf[FILESIZE]; /* Do we even need to make a copy of ShareDir? -- MM */ jamstrsub(dirbuf, ShareDir, sizeof(dirbuf)); doPushd(dirbuf); } void Popd() { char *newdir; if (list_next(DirStack) == NULL) { complain("popd: directory stack is empty."); /* NOTREACHED */ } newdir = dir_name(list_next(DirStack)); if (Dchdir(newdir) == -1) { s_mess("popd: cannot change back into %s.", newdir); return; } UpdModLine = YES; free((UnivPtr) list_pop(&DirStack)); prDIRS(); } #ifdef UNIX # ifdef USE_GETPWNAM #include private void get_hdir(user, buf) register char *user, *buf; { struct passwd *p; p = getpwnam(user); endpwent(); if (p == NULL) { add_mess(" [unknown user: %s]", user); SitFor(7); complain((char *)NULL); /* NOTREACHED */ } jamstrsub(buf, p->pw_dir, (size_t)FILESIZE); } # else /* ! USE_GETPWNAM */ # include "re.h" private void get_hdir(user, buf) register char *user, *buf; { char fbuf[LBSIZE], pattern[100]; register int u_len; File *fp; u_len = strlen(user); fp = open_file("/etc/passwd", fbuf, F_READ, YES); swritef(pattern, sizeof(pattern), "%s:[^:]*:[^:]*:[^:]*:[^:]*:\\([^:]*\\):", user); while (!f_gets(fp, genbuf, LBSIZE)) if ((strncmp(genbuf, user, u_len) == 0) && LookingAt(pattern, genbuf, 0)) { putmatch(1, buf, FILESIZE); close_file(fp); return; } close_file(fp); add_mess(" [unknown user: %s]", user); SitFor(7); complain((char *)NULL); /* NOTREACHED */ } # endif /* USE_GETPWNAM */ #endif /* UNIX */ /* Concatenate two parts of a pathname. * They should end up separated by a '/' (or optionally '\\', if MSFILESYSTEM) * but we are careful not to add one if the prefix already ends in one. * Arbitrarily, if pre is empty, the result is the same as if it were root (/). */ void PathCat(buf, buflen, pre, post) char *buf; size_t buflen; const char *pre, *post; { size_t prelen = strlen(pre); swritef(buf, buflen, prelen > 0 && (pre[prelen-1] == '/' #ifdef MSFILESYSTEM || pre[prelen-1] == '\\' #endif )? "%s%s" : "%s/%s", pre, post); } /* Convert path in name into a more-canonical one in intobuf. * - makes path absolute * - handles ~ (and \~, if not MSFILESYSTEM) * - if MSFILESYSTEM, turns \ into / * - on MSDOS, lower cases everything * Note: name and intobuf must not be aliases. * Note: because \~ is turned into ~, this routine is not idempotent. * ??? I suspect that there are places where in the code that presume * it is idempotent! -- DHR * It seems that all callers of PathParse (or their callers) provide * an intobuf of size FILESIZE, which is important, and it seems * that the operations in PathParse or callees are careful to * not go outside FILESIZE bounds, but I really wish I could feel * more confident of that. -- MM */ void PathParse(name, intobuf) const char *name; char *intobuf; /* MUST BE at least FILESIZE */ { char localbuf[FILESIZE]; intobuf[0] = localbuf[0] = '\0'; if (*name == '\0') return; /* Place pathname in localbuf, with any specified home directory */ if (*name == '~') { if (name[1] == '/' || name[1] == '\0') { jamstrsub(localbuf, HomeDir, sizeof(localbuf)); name += 1; } #ifdef UNIX /* may add for mac in future */ else { const char *uendp = strchr(name, '/'); char unamebuf[30]; if (uendp == NULL) uendp = name + strlen(name); name += 1; if ((size_t) (uendp - name) >= sizeof(unamebuf)) { len_error(JMP_COMPLAIN); /* NOTREACHED */ } null_ncpy(unamebuf, name, (size_t) (uendp - name)); get_hdir(unamebuf, localbuf); name = uendp; } #endif #ifndef MSFILESYSTEM } else if (name[0] == '\\' && name[1] == '~') { /* allow quoting of ~ (but \ is a path separator in MSDOS) */ name += 1; #endif /* MSFILESYSTEM */ } jamstrcat(localbuf, name, sizeof(localbuf)); /* Make path absolute, and prepare for processing each component * of the path by placing prefix in intobuf. */ #ifndef MSFILESYSTEM jamstrsub(intobuf, localbuf[0] == '/'? "/" : PWD, FILESIZE); #else /* MSFILESYSTEM */ /* Convert to an absolute path, and then fudge thing so that the * generic code does not have to deal with drive specifications. * If the path starts with '//' it is a UNC name. Otherwise, * our absolute path starts with a d: drive specification and * uses forward slashes as the path separator (including one * right after the drive specification). */ abspath(localbuf, intobuf); if (localbuf[0] == '/' && localbuf[1] == '/') { strcpy(localbuf, intobuf+1); intobuf += 1; intobuf[1] = '\0'; } else { strcpy(localbuf, intobuf+3); /* copy back all but d:/ */ intobuf += 2; /* "forget" drive spec: point to / */ intobuf[1] = '\0'; /* truncate after d:/ */ } #endif /* MSFILESYSTEM */ /* Process each path component, attempting to make the path canonical. */ { char *fp = localbuf, /* start of current component */ *dp = intobuf; /* current end of resulting path (but lazy) */ #ifdef HAS_SYMLINKS int linkcnt = 0; /* to detect symlink loops */ #endif while (*fp != '\0') { /* for each path component: */ char *sp = strchr(fp, '/'); /* end of current component */ if (sp != NULL) *sp = '\0'; dp += strlen(dp); /* move to end of resulting path */ if (*fp == '\0' || strcmp(fp, ".") == 0) { /* ignore this component */ } else if (strcmp(fp, "..") == 0) { /* Strip one directory name from "intobuf". * Assume that intobuf[0] == '/'. * Symlinks are the only hard part. * ??? is this correct for the Mac? CP/M? */ #ifdef HAS_SYMLINKS char linkbuf[FILESIZE]; JSSIZE_T linklen; #endif do {} while (dp > intobuf+1 && *--dp != '/'); #ifdef HAS_SYMLINKS /* If we find that the path up to the .. is a symlink, * and we don't appear to be in a symlink loop * and we have room to handle it, * we jam the symlink's target on the front of fp * and try again. * Note: this code will only work for UNIX-like pathnames. */ if (sp != NULL) *sp = '/'; linklen = readlink(intobuf, linkbuf, sizeof(linkbuf)-1); if (linklen >= 0 && ++linkcnt < 100 && strlen(fp) + linklen + (linkbuf[0]=='/'? 0 : dp - intobuf) + 2 <= sizeof(linkbuf)) { if (linklen <= 1 || linkbuf[linklen-1] != '/') linkbuf[linklen++] = '/'; strcpy(&linkbuf[linklen], fp); strcpy(localbuf, linkbuf); fp = localbuf; if (linkbuf[0] == '/') { fp += 1; dp = &intobuf[0]; *dp++ = '/'; } *dp = '\0'; continue; } #endif *dp = '\0'; } else { if (dp!=intobuf && dp[-1]!='/') *dp++ = '/'; strcpy(dp, fp); } if (sp == NULL) break; fp = sp + 1; } } } #ifdef UNIX int CreatMode = DFLT_MODE; /* VAR: default mode for creat'ing files */ #endif private void DoWriteReg(app) jbool app; { char fnamebuf[FILESIZE]; Mark *mp = CurMark(); File *fp; /* Won't get here if there isn't a Mark */ (void) ask_file((char *)NULL, (char *)NULL, fnamebuf); if (!app) { filemunge(fnamebuf); chk_divergence((Buffer *)NULL, fnamebuf, "write-region"); #ifdef BACKUPFILES if (BkupOnWrite) file_backup(fnamebuf); #endif } fp = open_file(fnamebuf, iobuff, app ? F_APPEND|F_TELLALL : F_WRITE|F_TELLALL, YES); putreg(fp, mp->m_line, mp->m_char, curline, curchar, YES); close_file(fp); } void WrtReg() { DoWriteReg(NO); } void AppReg() { DoWriteReg(YES); } jbool OkayBadChars = NO; /* VAR: allow bad characters in filenames created by JOVE */ void JWriteFile() { char fnamebuf[FILESIZE]; #ifdef MAC if (Macmode) { if (pfile(fnamebuf) == NULL) return; } else #endif /* MAC */ (void) ask_file((char *)NULL, curbuf->b_fname, fnamebuf); /* Don't allow bad characters when creating new files. */ if (!OkayBadChars && (curbuf->b_fname==NULL || strcmp(curbuf->b_fname, fnamebuf) != 0)) { #ifdef UNIX static const char badchars[] = "!$^&*()~`{}\"'\\|<>? "; #endif #ifdef MSDOS static const char badchars[] = "*|<>? "; #endif #ifdef WIN32 static const char badchars[] = "*|<>?\""; #endif #ifdef MAC static const char badchars[] = ":"; #endif register char *cp = fnamebuf; register char c; while ((c = *cp++) != '\0') { if (!jisprint(c) || strchr(badchars, c)!=NULL) { complain("'%p': bad character in filename.", c); /* NOTREACHED */ } } } filemunge(fnamebuf); chk_divergence(curbuf, fnamebuf, "write"); curbuf->b_type = B_FILE; /* in case it wasn't before */ setfname(curbuf, fnamebuf); file_write(fnamebuf, NO); } void WtModBuf() { if (!ModBufs(NO)) message("[No buffers need saving]"); else put_bufs(is_an_arg()); } void put_bufs(askp) jbool askp; { register Buffer *oldb = curbuf, *b; for (b = world; b != NULL; b = b->b_next) { if (!IsModified(b) || b->b_type != B_FILE) continue; SetBuf(b); /* Make this current Buffer */ if (curbuf->b_fname == NULL) { const char *newname; newname = ask(NullStr, "Buffer \"%s\" needs a file name; type Return to skip: ", b->b_name); if (*newname == '\0') continue; setfname(b, newname); } if (askp && !yes_or_no_p("Write %s? ", curbuf->b_fname)) continue; SaveFile(); } SetBuf(oldb); } /* Open file FNAME supplying the buffer IO routine with buffer BUF. * HOW is F_READ, F_WRITE or F_APPEND. HOW can have the F_TELLALL * flag to request the displaying of I/O status. Only if COMPLAINIFBAD * will a complain diagnostic be produced for a failed open. * * NOTE: This opens the pr_name(fname, NO) of fname. That is, FNAME * is usually an entire pathname, which can be slow when the * pathname is long and there are lots of symbolic links along * the way (which has become very common in my experience). So, * this speeds up opens file names in the local directory. It * will not speed up things like "../scm/foo.scm" simply because * by the time we get here that's already been expanded to an * absolute pathname. But this is a start. */ File * open_file(fname, buf, how, complainifbad) register char *fname; char *buf; register int how; jbool complainifbad; { register File *fp; io_chars = 0; io_lines = 0; fp = f_open(pr_name(fname, NO), how, buf, LBSIZE); if (fp == NULL) { if (complainifbad) { message(IOerr((F_MODE(how) == F_READ) ? "open" : "create", fname)); complain((char *)NULL); /* NOTREACHED */ } } else { const char *rd_only = NullStr; #ifndef MAC if (access(pr_name(fname, NO), W_OK) == -1 && errno != ENOENT) { rd_only = " [Read only]"; fp->f_flags |= F_READONLY; } #endif if (how & F_TELLALL) f_mess("\"%s\"%s", pr_name(fname, YES), rd_only); } return fp; } /* We're about to write to a file (save-file, write-region, append-region, * or write-file): query user when it is an existing but different file. * Note: even if we are doing an append-region or write-region, * we assume that the current buffer's file is fair game. */ private void filemunge(newname) char *newname; { if (do_stat(newname, curbuf, DS_NONE) != curbuf && was_file) { rbell(); confirm("\"%s\" already exists; overwrite it? ", newname); /* in case user has fiddled some more, refresh stat cache */ (void) do_stat(newname, (Buffer *)NULL, DS_NONE); } } /* Check to see if the file has been modified since it was * last visited or saved. If so, make sure they know what * they're doing. Buffer "thisbuf" is tested for divergence; * if thisbuf is NULL, the first buffer with the file is tested. * * To avoid excessive stats, we presume that the stat cache is * already primed. We refresh it if we get a confirmation because * it left the user a window of opportunity for fiddling. */ private void chk_divergence(thisbuf, fname, how) Buffer *thisbuf; const char *fname, *how; { static const char mesg[] = "Shall I go ahead and %s anyway? "; Buffer *buf = do_stat(fname, thisbuf, DS_REUSE); if (buf != NULL && buf->b_diverged) { rbell(); redisplay(); /* Ring that bell! */ TOstart("Warning"); Typeout("\"%s\" now saved on disk is not what you last", pr_name(fname, YES)); Typeout("visited or saved. Probably someone else is editing"); Typeout("your file at the same time."); Typeout(NullStr); Typeout("Type \"y\" if I should %s, anyway.", how); f_mess(mesg, how); TOstop(); confirm(mesg, how); /* in case user has fiddled some more, refresh stat cache */ (void) do_stat(fname, (Buffer *)NULL, DS_NONE); } } void file_write(fname, app) char *fname; jbool app; { File *fp; #ifdef BACKUPFILES if (!app && BkupOnWrite) file_backup(fname); #endif fp = open_file(fname, iobuff, app ? F_APPEND|F_TELLALL : F_WRITE|F_TELLALL, YES); if (EndWNewline) { /* Make sure file ends with a newLine */ Bufpos save; DOTsave(&save); ToLast(); if (length(curline)) /* Not a blank Line */ LineInsert(1); SetDot(&save); } putreg(fp, curbuf->b_first, 0, curbuf->b_last, length(curbuf->b_last), NO); close_file(fp); (void) do_stat(curbuf->b_fname, curbuf, DS_SET); unmodify(); } void JReadFile() { char fnamebuf[FILESIZE]; jbool reloading; Window *wp; long curlineno; #ifdef MAC if (Macmode) { if (gfile(fnamebuf) == NULL) return; } else #endif /* MAC */ (void) ask_file((char *)NULL, curbuf->b_fname, fnamebuf); if (IsModified(curbuf) && yes_or_no_p("Shall I make your changes to \"%s\" permanent? ", curbuf->b_name)) SaveFile(); (void) do_stat(fnamebuf, (Buffer *)NULL, DS_NONE); /* prime stat cache */ chk_divergence(curbuf, fnamebuf, "read"); reloading = do_stat(fnamebuf, curbuf, DS_REUSE) == curbuf; /* preserve w_line in each window into curbuf */ wp = fwind; do { if (wp->w_bufp == curbuf) { /* hijack w_topnum -- nobody was using it anyway */ wp->w_topnum = reloading? LinesTo(curbuf->b_first, wp->w_line) : 0; wp->w_top = wp->w_line = NULL; wp->w_flags |= W_TOPGONE; } } while ((wp = wp->w_next) != fwind); curlineno = reloading? LinesTo(curbuf->b_first, curline) : 0; buf_clear(curbuf); setfname(curbuf, fnamebuf); read_file(fnamebuf, NO); /* recover dot in each window into curbuf */ wp = fwind; do { if (wp->w_bufp == curbuf) { wp->w_top = curbuf->b_first; wp->w_line = next_line(curbuf->b_first, wp->w_topnum); } } while ((wp = wp->w_next) != fwind); SetLine(next_line(curbuf->b_first, curlineno)); } void InsFile() { char fnamebuf[FILESIZE]; #ifdef MAC if (Macmode) { if (gfile(fnamebuf) == NULL) return; } else #endif /* MAC */ (void) ask_file((char *)NULL, curbuf->b_fname, fnamebuf); read_file(fnamebuf, YES); } #include "temp.h" jbool DOLsave = NO; /* Do Lsave flag. If lines aren't being saved * when you think they should have been, this * flag is probably not being set, or is being * cleared before lsave() was called. */ private int nleft, /* number of good characters left in current block */ tmpfd = -1; daddr DFree = 1; /* pointer to end of tmp file */ private char *tfname; /* pathname of tempfile where buffer lines go */ private void tmpinit() { char buf[FILESIZE]; PathCat(buf, sizeof(buf), TmpDir, #ifdef MAC ".joveXXX" /* must match string in mac.c:Ffilter() */ #else "jvXXXXXX" #endif ); tfname = copystr(buf); tmpfd = MakeTemp(tfname, "editing"); #ifdef RECOVER rectmpname(strrchr(tfname, '/') + 1); #endif } /* Close tempfile before execing a child process. * Since we might be vforking, we must not change any variables * (in particular tmpfd). */ void tmpclose() { if (tmpfd != -1) (void) close(tmpfd); } /* Close and remove tempfile before exiting. */ void tmpremove() { if (tmpfd != -1) { tmpclose(); (void) unlink(tfname); } } /* get a line at `tl' in the tmp file into `buf' which should be LBSIZE * long */ /* A prototyped definition is needed because daddr might be affected * by default argument promotions. */ int Jr_Len; /* length of Just Read Line */ void #ifdef USE_PROTOTYPES jgetline proto((daddr addr, register char *buf)) #else jgetline(addr, buf) daddr addr; register char *buf; #endif { register char *bp, *lp; lp = buf; bp = getblock(addr, NO); do {} while ((*lp++ = *bp++) != '\0'); Jr_Len = (lp - buf) - 1; } /* Put `buf' and return the disk address */ daddr jputline(buf) char *buf; { register char *bp, *lp; register int nl; daddr line_daddr; lp = buf; bp = getblock(DFree, YES); nl = nleft; while ((*bp = *lp++) != '\0') { if (*bp++ == '\n') { *--bp = '\0'; break; } if (--nl == 0) { DFree = blk_chop(DFree) + BLK_CHNKS; bp = getblock(DFree, YES); lp = buf; /* start over ... */ nl = nleft; } } line_daddr = DFree; DFree += REQ_CHNKS(lp - buf); /* (lp - buf) includes the null */ return line_daddr; } /* The theory is that the critical section of code inside this procedure * will never cause a problem to occur. Basically, we need to ensure * that two blocks are in memory at the same time, but I think that * this can never screw up. */ #define lockblock(addr) #define unlockblock(addr) private jbool f_getputl(line, fp) LinePtr line; register File *fp; { register char *bp; register ZXchar c; register int nl, room = LBSIZE-1; char *base; base = bp = getblock(DFree, YES); nl = nleft; for (;;) { c = f_getc(fp); if (c == EOF) break; /* We can't store NUL in our buffer, so ignore it. * Similarly, we can only store characters less than NCHARS. * Of course, with a little ingenuity we could store NUL: * NUL could be represented by \n. */ if (c == '\0' #if NCHARS != UCHAR_ROOF || c >= NCHARS #endif ) continue; if (c == EOL) { #ifdef USE_CRLF /* a CR followed by an EOL is treated as a NL. * Bug: the line-buffer is effectively shortened by one character. */ if (bp != base && bp[-1] == '\r') { bp -= 1; room += 1; } #endif /* USE_CRLF */ break; } if (--room < 0) break; /* no room for this character */ if (--nl == 0) { char *newbp; size_t nbytes; daddr old_free_block = blk_chop(DFree); lockblock(old_free_block); DFree = old_free_block + BLK_CHNKS; nbytes = bp - base; newbp = getblock(DFree, YES); nl = nleft; byte_copy(base, newbp, nbytes); bp = newbp + nbytes; base = newbp; unlockblock(old_free_block); } *bp++ = c; } *bp++ = '\0'; line->l_dline = DFree; DFree += REQ_CHNKS(bp - base); if (room < 0) { fp->f_flags |= F_LINETOOLONG; add_mess(" [Line too long]"); rbell(); return YES; } if (c == EOF) { if (--bp != base) add_mess(" [Incomplete last line]"); return YES; } io_lines += 1; return NO; } typedef struct block { char b_dirty; /* (jbool) */ daddr b_bno; char b_buf[JBUFSIZ]; struct block *b_LRUnext, *b_LRUprev, *b_HASHnext; } Block; #define HASHSIZE 7 /* Primes work best (so I'm told) */ #define B_HASH(bno) ((bno) % HASHSIZE) #ifdef MALLOC_CACHE private Block *b_cache = NULL; #else private Block b_cache[NBUF]; #endif private Block *bht[HASHSIZE], /* Block hash table. Must be zero initially */ *f_block = NULL, *l_block = NULL; private daddr next_bno = 0; /* Needed to comfort MS Visual C */ private void blkio proto((Block *, JSSIZE_T (*) ptrproto((int, UnivPtr, JRWSIZE_T)))); private void blkio(b, iofcn) register Block *b; register JSSIZE_T (*iofcn) ptrproto((int, UnivPtr, JRWSIZE_T)); { off_t boff = bno_to_seek_off(b->b_bno); JSSIZE_T nb; static jbool first_time = YES; if (first_time) { tmpinit(); first_time = NO; } if (lseek(tmpfd, boff, 0) < 0) { error("[Tmp file seek error to %D: %d %s; to continue editing would be dangerous]", (long)boff, errno, strerror(errno)); /* NOTREACHED */ } else if ((nb = (*iofcn)(tmpfd, (UnivPtr) b->b_buf, (JRWSIZE_T)JBUFSIZ)) != JBUFSIZ) { error("[Tmp file %s error got %D: %d %s: to continue editing would be dangerous]", (iofcn == read) ? "READ" : "WRITE", (long)nb, nb < 0 ? errno : 0, nb < 0 ? strerror(errno): ""); /* NOTREACHED */ } } void d_cache_init() { register Block *bp, /* Block pointer */ **hp; /* Hash pointer */ register daddr bno; jdbg("MAX_BLOCKS=%D\n", (long)MAX_BLOCKS); jdbg("CHNK_CHARS=%D\n", (long)CHNK_CHARS); jdbg("BLK_CHNKS=%D\n", (long)BLK_CHNKS); #ifdef MALLOC_CACHE if (b_cache == NULL) { b_cache = (Block *) calloc((size_t)NBUF,sizeof(Block)); if (b_cache == NULL) { error("cannot allocate buffer cache"); /* NOTREACHED */ } } #endif /* MALLOC_CACHE */ for (bp = b_cache, bno = NBUF; bno-- > 0; bp++) { bp->b_dirty = NO; bp->b_bno = bno; if (l_block == NULL) l_block = bp; bp->b_LRUprev = NULL; bp->b_LRUnext = f_block; if (f_block != NULL) f_block->b_LRUprev = bp; f_block = bp; bp->b_HASHnext = *(hp = &bht[B_HASH(bno)]); *hp = bp; } } void SyncTmp() { register Block *b; #ifdef MSDOS register daddr bno = 0; /* sync the blocks in order, for file systems that don't allow * holes (MSDOS). Perhaps this benefits floppy-based file systems. */ for (bno = 0; bno < next_bno; bno++) { if ((b = lookup_block(bno)) != NULL && b->b_dirty) { blkio(b, (JSSIZE_T (*) ptrproto((int, UnivPtr, JRWSIZE_T)))write); b->b_dirty = NO; } } #else /* !MSDOS */ for (b = f_block; b != NULL; b = b->b_LRUnext) if (b->b_dirty) { blkio(b, (JSSIZE_T (*) ptrproto((int, UnivPtr, JRWSIZE_T)))write); b->b_dirty = NO; } #endif /* !MSDOS */ } /* A prototyped definition is needed because daddr might be affected * by default argument promotions. */ private Block * #ifdef USE_PROTOTYPES lookup_block proto((register daddr bno)) #else lookup_block(bno) register daddr bno; #endif { register Block *bp; for (bp = bht[B_HASH(bno)]; bp != NULL; bp = bp->b_HASHnext) if (bp->b_bno == bno) break; return bp; } private void LRUunlink(b) register Block *b; { if (b->b_LRUprev == NULL) f_block = b->b_LRUnext; else b->b_LRUprev->b_LRUnext = b->b_LRUnext; if (b->b_LRUnext == NULL) l_block = b->b_LRUprev; else b->b_LRUnext->b_LRUprev = b->b_LRUprev; } private Block * b_unlink(bp) register Block *bp; { register Block *hp, *prev = NULL; LRUunlink(bp); /* Now that we have the block, we remove it from its position * in the hash table, so we can THEN put it somewhere else with * it's new block assignment. */ for (hp = bht[B_HASH(bp->b_bno)]; hp != NULL; prev = hp, hp = hp->b_HASHnext) if (hp == bp) break; if (hp == NULL) { writef("\rBlock %ld missing!", (long)bp->b_bno); finish(0); } if (prev) prev->b_HASHnext = hp->b_HASHnext; else bht[B_HASH(bp->b_bno)] = hp->b_HASHnext; if (bp->b_dirty) { /* do, now, the delayed write */ blkio(bp, (JSSIZE_T (*) ptrproto((int, UnivPtr, JRWSIZE_T)))write); bp->b_dirty = NO; } return bp; } /* Get a block which contains at least part of the line with the address * atl. Returns a pointer to the block and sets the global variable * nleft (number of good characters left in the buffer). */ /* A prototyped definition is needed because daddr might be affected * by default argument promotions. */ private char * #ifdef USE_PROTOTYPES getblock proto((daddr atl, jbool IsWrite)) #else getblock(atl, IsWrite) daddr atl; jbool IsWrite; #endif { register daddr bno, off; register Block *bp; static Block *lastb = NULL; bno = da_to_bno(atl); off = da_to_off(atl); /* We don't allow block number MAX_BLOCKS-1 to be used because * NOWHERE_DADDR and NOTYET_DADDR must not be valid disk references, * and we want to prevent space overflow from being undetected * through arithmetic overflow. */ if (bno >= MAX_BLOCKS-1) { error("Tmp file too large for line %D bno %D, max is %D. Get help!", (long)atl, (long)bno, (long)(MAX_BLOCKS-1)); /* NOTREACHED */ } nleft = JBUFSIZ - off; if (lastb != NULL && lastb->b_bno == bno) { bp = lastb; /* same as last time */ } else if ((bp = lookup_block(bno)) != NULL) { /* The requested block already lives in memory, so we move * it to the end of the LRU list (making it Most Recently Used) * and then return a pointer to it. */ if (bp != l_block) { LRUunlink(bp); if (l_block == NULL) f_block = bp; else l_block->b_LRUnext = bp; bp->b_LRUprev = l_block; l_block = bp; bp->b_LRUnext = NULL; } if (bno >= next_bno) next_bno = bno + 1; } else { /* The block we want doesn't reside in memory so we take the * least recently used clean block (if there is one) and use * it. */ bp = f_block; if (bp->b_dirty) /* The best block is dirty ... */ SyncTmp(); bp = b_unlink(bp); if (l_block == NULL) f_block = bp; else l_block->b_LRUnext = bp; /* Place it at the end ... */ bp->b_LRUprev = l_block; l_block = bp; bp->b_LRUnext = NULL; /* so it's Most Recently Used */ bp->b_dirty = NO; bp->b_bno = bno; bp->b_HASHnext = bht[B_HASH(bno)]; bht[B_HASH(bno)] = bp; /* Get the current contents of the block UNLESS this is a new * block that's never been looked at before, i.e., it's past * the end of the tmp file. */ if (bno < next_bno) blkio(bp, read); else next_bno = bno + 1; } lastb = bp; bp->b_dirty |= IsWrite; return bp->b_buf + off; } char * lbptr(line) LinePtr line; { return getblock(line->l_dline, NO); } /* save the current contents of linebuf, if it has changed */ void lsave() { if (curbuf == NULL || !DOLsave) /* Nothing modified recently */ return; if (strcmp(lbptr(curline), linebuf) != 0) SavLine(curline, linebuf); /* Put linebuf on the disk. */ DOLsave = NO; } /* build backup file name, also used by SetBuf */ void backup_name(fname, btype, bfname, bfnamesize) const char *fname, *btype; char *bfname; size_t bfnamesize; { char *s = strrchr(fname, '/'); size_t dirlen = (s == NULL)? 0 : s + 1 - fname; jamstrsub(bfname, fname, bfnamesize); swritef(bfname+dirlen, (size_t) (bfnamesize - dirlen), "#%s%s~", fname+dirlen, btype); } #ifdef BACKUPFILES private void file_backup(fname) char *fname; { # ifndef MSFILESYSTEM JSSIZE_T rr; int ffd, bffd = 0; /* avoid uninitialized complaint from gcc -W */ char buf[JBUFSIZ], bfname[FILESIZE]; backup_name(fname, "", bfname, sizeof(bfname)); if ((ffd = open(fname, O_RDONLY | O_BINARY | O_CLOEXEC)) < 0) return; /* cannot open original file: nothing to backup, we assume */ /* create backup file with same mode as input file */ { # ifdef MAC jmode_t mode = CreatMode; /* dummy */ # else struct stat statbuf; jmode_t mode = fstat(ffd, &statbuf) != 0? (jmode_t)CreatMode : statbuf.st_mode; # endif /* Unlink the pathname before creating. It may have been * created by someone else, or worse it may be linked or * symlinked somewhere else, none of which we want to * overwrite. There is still a possible race-condition, * so we need to use O_EXCL if we can. */ if ((unlink(bfname) < 0 && errno != ENOENT) # ifdef O_EXCL || (bffd = open(bfname, O_CREAT | O_EXCL | O_RDWR | O_CLOEXEC, mode)) < 0 # else || (bffd = creat(bfname, mode)) < 0 # endif ) { int e = errno; (void) close(ffd); complain("[cannot create backup \"%s\": %d %s]", bfname, e, strerror(e)); /* NOTREACHED */ } } /* copy the contents */ while ((rr = read(ffd, (UnivPtr) buf, sizeof(buf))) > 0) { char *p = buf; while (rr > 0) { JSSIZE_T wr = write(bffd, (UnivPtr) p, (size_t) rr); if (wr < 0) { int e = errno; close(bffd); close(ffd); complain("[error writing backup: %d %s]", e, strerror(e)); /* NOTREACHED */ } p += wr; rr -= wr; } } if (rr < 0 || close(ffd) != 0) { complain("[error reading \"%s\": %d %s]", fname, errno, strerror(errno)); /* NOTREACHED */ } # ifdef USE_FSYNC if (fsync(bffd) != 0) { int e = errno; (void) close(bffd); complain("[error fsyncing backup: %d %s]", e, strerror(e)); /* NOTREACHED */ } # endif /* USE_FSYNC */ if (close(bffd) != 0) { complain("[error closing backup: %d %s]", errno, strerror(errno)); /* NOTREACHED */ } # else /* MSFILESYSTEM */ /* This code is designed to fit withing the 8.3 limitation of * MSDOS ("FAT" -- huh!) file systems. Even though newer versions * of these APIs (Win32) may support longer file names, we may still * be dealing with a FAT file system. */ char *dot, *slash, tmp[FILESIZE]; if (access(fname, 0) < 0) return; /* cannot open original file: nothing to backup, we assume */ strcpy(tmp, fname); slash = (char *)jbasename(tmp); if ((dot = strrchr(slash, '.')) != NULL) { if (stricmp(dot,".bak") == 0) return; /* don't rename .bak to .bak */ *dot = '\0'; } strcat(tmp, ".bak"); unlink(tmp); if (rename(fname, tmp) != 0) { complain("[cannot rename to \"%s\": %s]", tmp, strerror(errno)); /* NOTREACHED */ } # endif /* MSFILESYSTEM */ } #endif /* BACKUPFILES */ jove-4.17.5.5/io.h000066400000000000000000000052551501102521500134750ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern const char *HomeDir; extern size_t HomeLen; extern jbool DOLsave; /* Do Lsave flag. If lines aren't being saved when you think they should have been, this flag is probably not being set, or is being cleared before lsave() was called. */ extern daddr DFree; /* pointer to end of tmp file */ extern int Jr_Len; /* length of Just Read Line */ extern long io_chars, io_lines; extern int MakeTemp proto((char *, const char *)); extern char *lbptr proto((LinePtr line)), *pr_name proto((const char *fname,jbool okay_home)), *pwd proto((void)); extern File *open_file proto((char *fname,char *buf,int how,jbool complainifbad)); extern void setCWD proto((char *d)), getCWD proto((void)), PathCat proto((char *buf, size_t, const char *pre, const char *post)), PathParse proto((const char *name, char *intobuf)), SyncTmp proto((void)), close_file proto((File *fp)), d_cache_init proto((void)), file_write proto((char *fname, jbool app)), jgetline proto((daddr addr, char *buf)), lsave proto((void)), putreg proto((File *fp,LinePtr line1,int char1,LinePtr line2,int char2,jbool makesure)), read_file proto((char *file, jbool is_insert)), put_bufs proto((jbool askp)), tmpclose proto((void)), tmpremove proto((void)); extern jbool chkCWD proto((char *dn)); extern daddr jputline proto((char *buf)); /* Commands: */ extern void AppReg proto((void)), Chdir proto((void)), InsFile proto((void)), Popd proto((void)), Pushd proto((void)), Pushlibd proto((void)), JReadFile proto((void)), /* ReadFile conflicts with Win32 library */ SaveFile proto((void)), JWriteFile proto((void)), /* WriteFile conflicts with Win32 library */ WtModBuf proto((void)), WrtReg proto((void)), prCWD proto((void)), prDIRS proto((void)), backup_name proto((const char *fname, const char *btype, char *bfname, size_t bfnamesize)); /* Variables: */ #ifdef BACKUPFILES extern jbool BkupOnWrite; /* VAR: make backup files when writing */ #endif #ifdef UNIX extern int CreatMode; /* VAR: default mode for creat'ing files */ #endif #ifdef MAC # define CreatMode 0 /* dummy */ #endif extern jbool EndWNewline; /* VAR: end files with a blank line */ extern jbool OkayBadChars; /* VAR: allow bad characters in files created by JOVE */ jove-4.17.5.5/iproc.c000066400000000000000000001357041501102521500142000ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #ifdef IPROCS /* the body is the rest of this file */ #define MAX_BUSY_WAIT 3 /* seconds to ignore errors on pty */ #include #include "re.h" #include "jctype.h" #include "disp.h" #include "fp.h" #include "sysprocs.h" #include "iproc.h" #include "ask.h" #include "extend.h" #include "fmt.h" #include "insert.h" #include "marks.h" #include "move.h" #include "proc.h" #include "wind.h" #ifdef USE_KILLPG # ifndef FULL_UNISTD extern int UNMACRO(killpg) proto((int /*pgrp*/, int /*sig*/)); # endif #else /* !USE_KILLPG */ #define killpg(pid, sig) kill(-(pid), (sig)) #endif /* USE_KILLPG */ struct process { Process p_next; #ifdef PIPEPROCS int p_toproc; /* write end of pipe to process */ pid_t p_portpid, /* pid of direct child (the portsrv) */ p_pid; /* pid of real child i.e. not portsrv */ jbool p_portlive; /* is portsrv still live? */ #else int p_fd; /* file descriptor of pty? opened r/w */ # define p_portpid p_pid /* pid of direct child (the shell) */ pid_t p_pid; /* pid of child (the shell) */ time_t p_start; /* time we started this child */ #endif Buffer *p_buffer; /* add output to end of this buffer */ char *p_name; /* ... */ int p_io_state; /* state of communication with child and descendents */ # define IO_NEW 0 /* brand new, process has not yet sent output */ # define IO_RUNNING 1 /* just running */ # define IO_EOFED 2 /* we have sent EOF, or have received it */ int p_child_state; /* state of child process, as disclosed by SIGCHLD/wait */ # define C_LIVE 0 /* no news is good news */ # define C_STOPPED 1 # define C_EXITED 2 # define C_KILLED 3 int p_reason; /* If killed, p_reason is the signal; if exited, it is the the exit code */ Mark *p_mark; /* where output left us */ }; private void proc_rec proto((Process, char *, size_t)), proc_close proto ((Process)), SendData proto((jbool)), obituary proto((register Process child, wait_status_t w)); private jbool proc_kill proto((Process, int)); #define child_dead(p) ((p)->p_child_state >= C_EXITED) #define io_eofed(p) ((p)->p_io_state == IO_EOFED) private jbool dead(p) Process p; { return p == NULL || (io_eofed(p) && child_dead(p)); } #define proc_cmd(p) ((p)->p_name) private Process procs = NULL; private Process proc_pid(pid) pid_t pid; { register Process p; for (p = procs; ; p = p->p_next) if (p == NULL || p->p_portpid == pid) return p; } private const char * proc_bufname(p) Process p; { Buffer *b = p->p_buffer; return (b != NULL) ? b->b_name : ""; } void ProcKill() { (void) proc_kill( buf_exists(ask_buf(curbuf, ALLOW_OLD | ALLOW_INDEX))->b_process, SIGKILL); } private void make_argv(argv, ap) register char *argv[]; va_list ap; { register int i = 0; argv[i++] = va_arg(ap, char *); argv[i++] = (char *)jbasename(argv[0]); /* lose const (but it's safe) */ do {} while ((argv[i++] = va_arg(ap, char *)) != NULL); } /* environment manipulation for interactive processes */ private Env iproc_env; private char IEnvExpBuf[LBSIZE]; private char IEnvUnsetBuf[LBSIZE]; /* Erase misleading knowledge of the terminal type from the environment. * The value of variable TERMCAP has two interpretations: * If it starts with /, it is a path to the database. * If it does not, it is the database entry. * Only happens in child. */ private void set_process_env() { static const char tcn[] = "TERMCAP"; const char *tc = getenv(tcn); if (tc != NULL && tc[0] != '/') junsetenv(&iproc_env, tcn); environ = (char **) jenvdata(&iproc_env); /* avoid gcc warning */ } void IprocEnvExport() { jamstr(IEnvExpBuf, ask(IEnvExpBuf, ProcFmt)); jputenv(&iproc_env, IEnvExpBuf); } void IprocEnvShow() { const char **p; TOstart("i-shell environment"); for (p = jenvdata(&iproc_env); *p; p++) { Typeout("%s", *p); } TOstop(); } void IprocEnvUnset() { jamstr(IEnvUnsetBuf, ask(IEnvUnsetBuf, ProcFmt)); junsetenv(&iproc_env, IEnvUnsetBuf); } /* There are two very different implementation techniques: pipes and ptys. * The following two chunks of code implement the same operations using * the two techniques: the first uses pipes and the second uses ptys. */ #include "ttystate.h" #ifdef PIPEPROCS char Portsrv[FILESIZE]; /* path to portsrv program (in LibDir) */ const char *procarg0 = "jove-portsrv"; /* helpful identifying it in ps */ int NumProcs = 0; File *ProcInput; private int ProcOutput = -1; pid_t kbd_pid = -1; void read_pipe_proc(pid, nbytes) pid_t pid; register int nbytes; { register Process p = proc_pid(pid); jdbg("read_pipe_proc pid %D %d\n", (long) pid, nbytes); if (p == NULL) { writef("\riproc: unknown pid (%D)", (long) pid); } else if (p->p_io_state == IO_NEW) { /* first message: pid of real child, not of portsrv */ pid_t rpid; (void) f_readn(ProcInput, (char *) &rpid, sizeof(pid_t)); p->p_pid = rpid; p->p_io_state = IO_RUNNING; UpdModLine = YES; } else if (nbytes == -1) { /* okay to clean up this process */ wait_status_t status; (void) f_readn(ProcInput, (char *) &status, sizeof(status)); /* Reap portsrv process, if it still remains. * Note that any status for this process is uninteresting: * the interesting status came (just now) by pipe. */ while (p->p_portlive) { wait_status_t w; pid_t rpid = wait(&w); if (rpid == -1) { if (errno == ECHILD) { /* oops: no children, not even portsrv */ p->p_portlive = NO; } } else { kill_off(rpid, w); } } proc_close(p); obituary(p, status); } else { /* regular data */ while (nbytes > 0) { char ibuf[512+1]; /* NOTE: room for added NUL */ size_t n = f_readn(ProcInput, ibuf, (size_t)jmin((int)(sizeof ibuf) - 1, nbytes)); nbytes -= n; proc_rec(p, ibuf, n); } } } void ProcInt() { (void) proc_kill(curbuf->b_process, SIGINT); } void ProcQuit() { (void) proc_kill(curbuf->b_process, SIGQUIT); } private void proc_close(p) Process p; { if (p->p_toproc >= 0) { jdbg("closing proc fd %d pid %D NumProcs %d\n", p->p_toproc, (long) (p->p_pid), NumProcs); (void) close(p->p_toproc); p->p_toproc = -1; /* writes will fail */ NumProcs -= 1; p->p_io_state = IO_EOFED; /* process output EOF is tied to reaping */ UpdModLine = YES; } } private void proc_write(p, buf, nbytes) Process p; char *buf; size_t nbytes; { if (p->p_toproc >= 0) { while (nbytes != 0) { JSSIZE_T wr = write(p->p_toproc, (UnivConstPtr)buf, nbytes); if (wr >= 0) { nbytes -= wr; buf += wr; } else if (errno != EINTR) { complain("[error writing to iproc: %d %s]", errno, strerror(errno)); /* NOTREACHED */ } } } } # ifdef STDARGS private void proc_strt(char *bufname, jbool clobber, char *procname, ...) # else private /*VARARGS3*/ void proc_strt(bufname, clobber, procname, va_alist) char *bufname; jbool clobber; char *procname; va_dcl # endif { Window *owind = curwind; int toproc[2]; pid_t pid; Process newp; Buffer *newbuf; char *argv[32]; va_list ap; untieDeadProcess(buf_exists(bufname)); isprocbuf(bufname); /* make sure BUFNAME is either nonexistant or is of type B_PROCESS */ if (access(Portsrv, J_X_OK) < 0) { complain("[Couldn't access %s: %s]", Portsrv, strerror(errno)); /* NOTREACHED */ } dopipe(toproc); jdbg("proc_strt NumProcs=%d buf \"%s\" proc \"%s\"\n", NumProcs, bufname, procname); if (NumProcs++ == 0) kbd_strt(); /* may create kbd process: must be done before fork */ switch (pid = fork()) { case -1: pipeclose(toproc); if (--NumProcs == 0) kbd_stop(); complain("[Fork failed: %s]", strerror(errno)); /* NOTREACHED */ case 0: argv[0] = (char*)procarg0; va_init(ap, procname); make_argv(&argv[1], ap); va_end(ap); (void) dup2(toproc[0], 0); (void) dup2(ProcOutput, 1); (void) dup2(ProcOutput, 2); pipeclose(toproc); jcloseall(); set_process_env(); jdbg("ready to exec %s %s %s %s\n", Portsrv, argv[0], argv[1]? argv[1] : "(null)", argv[2]? argv[2] : "(null)"); execv(Portsrv, argv); raw_complain("execl failed: %s", strerror(errno)); _exit(1); } newp = (Process) emalloc(sizeof *newp); newp->p_next = procs; newp->p_io_state = IO_NEW; newp->p_child_state = C_LIVE; newp->p_name = copystr(procname); procs = newp; newp->p_portpid = pid; newp->p_pid = -1; newp->p_portlive = YES; newbuf = do_select((Window *)NULL, bufname); newbuf->b_type = B_PROCESS; newp->p_buffer = newbuf; newbuf->b_process = newp; /* sorta circular, eh? */ pop_wind(bufname, clobber, B_PROCESS); ToLast(); if (!bolp()) LineInsert(1); /* Pop_wind() after everything is set up; important! * Bindings won't work right unless newbuf->b_process is already * set up BEFORE NEWBUF is first SetBuf()'d. */ newp->p_mark = MakeMark(curline, curchar); newp->p_toproc = toproc[1]; (void) close(toproc[0]); SetWind(owind); } void closeiprocs() { Process p; if (ProcOutput != -1) close(ProcOutput); for (p=procs; p!=NULL; p=p->p_next) if (p->p_toproc >= 0) close(p->p_toproc); } private void kbd_init() { /* Initiate the keyboard process. * We only get here after a portsrv process has been started * so we know that the portsrv program must exist -- no need to test. */ int p[2]; if (pipe(p) < 0) { complain("Cannot create pipe to kbd process! %s\n", strerror(errno)); /* NOTREACHED */ } ProcInput = fd_open("process-input", F_READ|F_LOCKED, p[0], (char *)NULL, 512); ProcOutput = p[1]; switch (kbd_pid = fork()) { case -1: complain("Cannot fork kbd process! %s\n", strerror(errno)); /* NOTREACHED */ case 0: (void) setsighandler(SIGINT, SIG_IGN); (void) setsighandler(SIGALRM, SIG_IGN); close(1); if (dup(ProcOutput) < 0) { raw_complain("Cannot dup output fd: %s", strerror(errno)); EXIT(-1); } jcloseall(); jdbg("ready to exec %s as %s --kbd\n", Portsrv, procarg0); execl(Portsrv, procarg0, "--kbd", (char *)NULL); raw_complain("kbd exec failed: %s", strerror(errno)); EXIT(-1); } } /* kbd_stop() returns true if it changes the state of (i.e. stops) * the keyboard process. This is so kbd stopping and starting in * pairs works - see finish() in jove.c. */ private jbool kbd_state = NO; void kbd_strt() { jdbg("kbd_strt state %d pid %D NumProcs %d\n", kbd_state, (long) kbd_pid, NumProcs); if (!kbd_state) { if (kbd_pid == -1) kbd_init(); else kill(kbd_pid, KBDSIG); kbd_state = YES; } } jbool kbd_stop() { jdbg("kbd_stop state %d pid %D NumProcs %d\n", kbd_state, (long) kbd_pid, NumProcs); if (kbd_state) { kbd_state = NO; kill(kbd_pid, KBDSIG); return YES; } return NO; } void kbd_kill() { jdbg("kbd_kill state %d pid %D Numprocs %d\n", kbd_state, (long) kbd_pid, NumProcs); if (kbd_pid != -1) { kill(kbd_pid, SIGKILL); kbd_pid = -1; } } #else /* !PIPEPROCS */ #include #include "select.h" # ifdef USE_OPENPTY /* modern BSDs have openpty(3) */ # ifdef HAVE_LIBUTIL_H /* but disagree about header! */ # include # else # ifdef HAVE_PTY_H # include # else # include # endif # endif # endif # ifdef SVR4_PTYS # include /* for grantpt and unlockpt, at least in Solaris 2.3 */ # if _XOPEN_SOURCE >= 500 /* Linux/glibc no longer pretends to support STREAMS (XSR) (2008) */ # if defined(_XOPEN_STREAMS) && _XOPEN_STREAMS != -1 # include # endif # else # include # endif extern char *ptsname proto((int /*filedes*/)); /* get name of slave */ # endif # ifdef IRIX_PTYS # include # include # endif void read_pty_proc(fd) register int fd; { register Process p; int n; char ibuf[1024+1]; /* NOTE: room for added NUL */ for (p = procs; ; p = p->p_next) { if (p == NULL) { writef("\riproc: unknown fd %d", fd); return; } if (p->p_fd == fd) break; } n = read(fd, (UnivPtr) ibuf, sizeof(ibuf) - 1); jdbg("pty read %d returned %d errno %d from %s\n", fd, n, errno, p->p_name); if (n <= 0) { if (n < 0) { if (errno == EIO || RETRY_ERRNO(errno)) { /* * ??? On some systems, pty reads fail * initially, for reasons that are not clear to * me (DHR). This code forgives these specific * kinds of failure until the process leaves the * NEW state. We hope that this does not cause * a long busy wait. */ if (p->p_io_state == IO_NEW) { time_t now = time(NULL); jdbg("IO_NEW err %d start %D now %D\n", errno, (long)p->p_start,(long)now); if (now < p->p_start+MAX_BUSY_WAIT) return; } jdbg("treating error as EOF\n"); /* We get here if the i-proc closes stdout * before exiting (eg. Bourne Shell), * so we treat it as a simple EOF. */ } else { /* true I/O error */ swritef(ibuf, sizeof(ibuf), "\n[pty read error: %s]\n", strerror(errno)); proc_rec(p, ibuf, strlen(ibuf)); /* now treat as EOF... */ } } /* else, EOF received */ proc_close(p); } else { if (p->p_io_state == IO_NEW) { p->p_io_state = IO_RUNNING; UpdModLine = YES; } proc_rec(p, ibuf, (size_t)n); } } void ProcCont() { Process p = curbuf->b_process; jdbg("ProcCont pid %D %s\n", (long)(p->p_pid), p->p_name); if (proc_kill(p, SIGCONT) && p->p_child_state == C_STOPPED) { p->p_child_state = C_LIVE; UpdModLine = YES; } } /* Sending non-character info through "keyboard" * * There are two kinds of "out of band" signals we wish to send * through the pty: signals (such as SIGINT) and EOF. On top * of that, there is a kind of out of band signal we wish not to * send: ERASE and KILL. Unfortunately, there are a number of ways * in which our environment may vary. Two ioctls are useful: * TIOCREMOTE and TIOCSIGNAL/TIOCSIG. * * * TIOCREMOTE: * * Some systems support the TIOCREMOTE ioctl. With this ioctl, * the "input editing" is suppressed on the characters sent * to the slave. Input editing involves interpreting ERASE, * KILL, INTERRUPT, QUIT, EOF, etc. characters. It is best * to run this way since JOVE already does input editing. * * The scant documentation on TIOCREMOTE in Solaris2.3 suggests * that the third argument to the TIOCREMOTE ioctl ought to be * an integer (but a pointer to the integer works). The SunOS4 * ldterm(4m) manpage says that the third argument is to be a * pointer to an integer. At the moment, we only use the pointer * form. * * Although IRIX defines TIOCREMOTE, it does not seem to work. * This may well be true of other systems, so as a safety, * we support "NO_TIOCREMOTE" as a feature deselect macro * for systems that define TIOCREMOTE but are broken. * * Under BSDI's BSD/386 v1.[01], the TIOCREMOTE ioctls appear to fail * for send_xc (without an error indication), but work otherwise. This * only affects dstop-process, so it is probably best not to define * NO_TIOCREMOTE. Even if we do define NO_TIOCREMOTE, the dstop-process * may require the user to do a process-newline (apparently, if the tty * input is being canonicalized). How odd. * * * TIOCSIGNAL/TIOCSIG: * * Some systems support the TIOCSIGNAL ioctl. With this ioctl, * a signal can be sent through the pty. Recent (4.3 or later?) * BSD systems seem to provide a TIOCSIG ioctl which is similar. * * The TIOCSIGNAL ioctl is not well documented and seems to be * broken on at least IRIX 5.3. Again, we provide "NO_TIOCSIGNAL" * to prevent using it on systems that define it but are broken. * * Another mystery: systems vary on how the signal number should be * passed in the TIOCSIGNAL ioctl. SunOS4 requires that the third * argument be a pointer to an integer, the signal number. Vanilla * SVR4 requires that the third argument be a an integer, the signal * number. Solaris2.3 accepts either. The SunOS 5.3 STREAMS * Programmer's Guide says that the third argument is an int. We have * not figured out, for an arbitrary system with TIOCSIGNAL, how to * tell which form the third argument should take. For now, it is * conditionalized on SVR4_PTYS. * * If TIOCSIGNAL/TIOCSIG isn't supplied (perhaps from termios.h), we * cannot send signals to the child when TIOCREMOTE is on, so we just * turn it off for a moment. This is pretty dubious because the user * might have done an stty to change or disable the characters. * * We don't know how to implement dstop using TIOCSIGNAL/TIOCSIG, so * we use the dubious trick. */ # if !defined(NO_TIOCREMOTE) && !defined(TIOCREMOTE) # define NO_TIOCREMOTE 1 # endif # if !defined(NO_TIOCSIGNAL) && !defined(TIOCSIGNAL) && !defined(TIOCSIG) # define NO_TIOCSIGNAL 1 # endif # ifdef NO_TIOCSIGNAL # define kbd_sig(sig, tch, sch) send_oxc(tch, sch) # define kbd_sig_ls(sig, tch, sch) send_oxc_ls(tch, sch) # else /* !NO_TIOCSIGNAL */ # define kbd_sig(sig, tch, sch) send_sig(sig) # define kbd_sig_ls(sig, tch, sch) kbd_sig(sig, tch, sch) private void send_sig(sig) int sig; { Process p; jdbg("send_sig %d\n", sig); if ((p = curbuf->b_process) == NULL || p->p_fd < 0) { complain("[No process]"); /* NOTREACHED */ } ToLast(); # ifdef TIOCSIG jdbg("TIOCSIG pid %d %s\n", p->p_pid, p->p_name); if (ioctl(p->p_fd, TIOCSIG, sig) < 0) { complain("TIOCSIG failed: %d %s", errno, strerror(errno)); /* NOTREACHED */ } # else /* !TIOCSIG */ # ifdef SVR4_PTYS jdbg("SVR4 TIOCSIGNAL pid %d %s\n", p->p_pid, p->p_name); if (ioctl(p->p_fd, TIOCSIGNAL, sig) < 0) { complain("TIOCSIGNAL failed: %d %s", errno, strerror(errno)); /* NOTREACHED */ } # else /* !SVR4_PTYS */ jdbg("TIOCSIGNAL pid %d %s\n", p->p_pid, p->p_name); if (ioctl(p->p_fd, TIOCSIGNAL, (void *) &sig) < 0) { complain("TIOCSIGNAL failed: %d %s", errno, strerror(errno)); /* NOTREACHED */ } # endif /* !SVR4_PTYS */ # endif /* !TIOCSIG */ } # endif /* !NO_TIOCSIGNAL */ # if defined(NO_TIOCREMOTE) || defined(NO_TIOCSIGNAL) || (!defined(TERMIO) && !defined(TERMIOS)) || defined(VDSUSP) # if defined(TERMIO) || defined(TERMIOS) # define send_oxc(tch, sch) send_xc(sg[NO].c_cc[tch]) # define send_oxc_ls(tch, sch) send_oxc(tch, sch) # else # define send_oxc(tch, sfld) send_xc(tc[NO].sfld) # define send_oxc_ls(tch, sfld) send_xc(ls[NO].sfld) # endif private void send_xc(c) char c; { Process p; if ((p = curbuf->b_process) == NULL || p->p_fd < 0) { complain("[No process]"); /* NOTREACHED */ } jdbg("send_xc 0x%x pid %d %s \n", c, p->p_pid, p->p_name); ToLast(); { char buf[1+1]; /* NOTE: room for added NUL */ buf[0] = c; proc_rec(p, buf, (size_t)1); { # ifndef NO_TIOCREMOTE int off = 0, on = 1; jdbg("TIOCREMOTE off pid %d %s\n", p->p_pid, p->p_name); while (ioctl(p->p_fd, TIOCREMOTE, (UnivPtr) &off) < 0) if (errno != EINTR) { complain("TIOCREMOTE OFF failed: %d %s", errno, strerror(errno)); /* NOTREACHED */ } # endif /* !NO_TIOCREMOTE */ for (;;) { switch (write(p->p_fd, (UnivPtr) &c, sizeof(c))) { case -1: /* error: consider ERRNO */ if (errno == EINTR) continue; /* interrupted: try again */ complain("pty write of control failed: %d %s", errno, strerror(errno)); /* NOTREACHED */ case 0: /* nothing happened: try again */ continue; case 1: /* done */ break; } break; } # ifndef NO_TIOCREMOTE jdbg("TIOCREMOTE on pid %d %s\n", p->p_pid, p->p_name); while (ioctl(p->p_fd, TIOCREMOTE, (UnivPtr) &on) < 0) { if (errno != EINTR) { complain("TIOCREMOTE ON failed: %d %s", errno, strerror(errno)); /* NOTREACHED */ } } # endif /* !NO_TIOCREMOTE */ } } } # endif /* defined(NO_TIOCREMOTE) || defined(NO_TIOCSIGNAL) */ void ProcEof() { # ifdef NO_TIOCREMOTE /* we have to write a char */ send_oxc(VEOF, t_eofc); # else /* !NO_TIOCREMOTE */ /* write a zero-length record to signify EOF */ static char mess[] = " "; /* NOTE: NUL will be overwritten */ Process p; if ((p = curbuf->b_process) == NULL || p->p_fd < 0) { complain("[No process]"); /* NOTREACHED */ } ToLast(); proc_rec(p, mess, sizeof(mess)-1); jdbg("ProcEof pid %d %s\n", p->p_pid, p->p_name); while (write(p->p_fd, (UnivPtr) mess, (size_t)0) < 0) { if (errno != EINTR) { complain("[error writing EOF to iproc: %d %s]", errno, strerror(errno)); /* NOTREACHED */ } } # endif /* !NO_TIOCREMOTE */ } void ProcInt() { kbd_sig(SIGINT, VINTR, t_intrc); } void ProcQuit() { kbd_sig(SIGQUIT, VQUIT, t_quitc); } void ProcStop() { # if (!defined(TERMIO) && !defined(TERMIOS)) || defined(VSUSP) kbd_sig_ls(SIGTSTP, VSUSP, t_suspc); # else complain("[stop-process not supported]"); /* NOTREACHED */ # endif } void ProcDStop() { /* we don't know how to send a dstop via TIOCSIGNAL/TIOCSIG */ # if (!defined(TERMIO) && !defined(TERMIOS)) || defined(VDSUSP) send_oxc_ls(VDSUSP, t_dsuspc); # else complain("[dstop-process not supported]"); /* NOTREACHED */ # endif } private void proc_close(p) Process p; { jdbg("proc_close %d %s\n", p->p_pid, p->p_name); if (p->p_fd >= 0) { (void) close(p->p_fd); FD_CLR(p->p_fd, &global_fd); p->p_fd = -1; p->p_io_state = IO_EOFED; /* I/O is finished */ UpdModLine = YES; } } private void proc_write(p, buf, nbytes) Process p; char *buf; size_t nbytes; { jdbg("proc_write %d bytes to pid %d %s\n", nbytes, p->p_pid, p->p_name); if (p->p_fd >= 0) { fd_set mask; FD_ZERO(&mask); FD_SET(p->p_fd, &mask); while (write(p->p_fd, (UnivPtr) buf, nbytes) < 0) (void) select(p->p_fd + 1, (fd_set *)NULL, &mask, (fd_set *)NULL, (struct timeval *)NULL); } } # ifdef STDARGS private void proc_strt(char *bufname, jbool clobber, const char *procname, ...) # else private /*VARARGS2*/ void proc_strt(bufname, clobber, procname, va_alist) char *bufname; jbool clobber; const char *procname; va_dcl # endif { va_list ap; char *argv[32]; Window *owind = curwind; pid_t pid; Process newp; Buffer *newbuf; int ptyfd = -1; int slvptyfd = -1; # if !defined(TERMIO) && !defined(TERMIOS) # ifdef TIOCSETD int ldisc; /* tty line discipline */ # endif # ifdef TIOCLSET int lmode; /* tty local flags */ # endif # endif char ttybuf[32]; # ifdef TERMIO struct termio sgt; # endif # ifdef TERMIOS struct termios sgt; # endif # ifdef SGTTY struct sgttyb sgt; # endif # ifdef TIOCGWINSZ struct winsize win; # else # ifdef BTL_BLIT # include struct jwinsize jwin; # endif # endif strcpy(ttybuf, "?"); /* to safely print when debugging */ untieDeadProcess(buf_exists(bufname)); isprocbuf(bufname); /* make sure BUFNAME is either nonexistant or is of type B_PROCESS */ va_init(ap, procname); make_argv(argv, ap); va_end(ap); if (access(argv[0], J_X_OK) != 0) { complain("[Couldn't access shell %s: %s]", argv[0], strerror(errno)); /* NOTREACHED */ } # ifdef IRIX_PTYS /* _getpty may fork off a child to execute mkpts to make a slave pty * in /dev (if we need more) and set the correct ownership and * modes on the slave pty. Since _getpty uses waitpid this works * fine with regard to our other children, but we do have to be * prepared to catch a SIGCHLD for an unknown child and ignore it ... */ { register char *s = _getpty(&ptyfd, O_RDWR | O_NDELAY, 0600, 0); if (s == NULL) { message("[No pty from getpty!]"); goto fail; } (void)strcpy(ttybuf, s); jdbg("IRIX_PTYS _getpty ptyfd %d %s\n", ptyfd, ttybuf); } # endif /* IRIX_PTYS */ # ifdef SVR4_PTYS if ((ptyfd = open("/dev/ptmx", O_RDWR | O_BINARY)) < 0) { message("[No pty from /dev/ptmx!]"); goto fail; } jdbg("SVR4_PTYS ptmx ptyfd %d\n", ptyfd); # ifndef GRANTPT_BUG /* grantpt() seems to be implemented using a fork/exec. * This is done to allow grantpt do do priviledged things * via a setuid program. One consequence is that JOVE's * SIGCLD/SIGCHLD handler must not do a wait that would * reap the grantpt process. So much for library routines * being black boxes. Worse, this restriction is not documented. */ if (grantpt(ptyfd) < 0) { message("[grantpt failed]"); goto fail; } if (unlockpt(ptyfd) < 0) { message("[unlockpt failed]"); goto fail; } jdbg("SVR4_PTYS grantpt and unlockpt ptyfd %d\n", ptyfd); # endif /* !GRANTPT_BUG */ #ifdef TIOCGPTPEER /* if we have TIOCGPTPEER (Linux post-2017), much better to use it! */ slvptyfd = ioctl(ptyfd, TIOCGPTPEER, O_RDWR | O_NOCTTY); if (slvptyfd == -1 && errno != EINVAL && errno != ENOTTY) { message("[ioctl TIOCGPTPEER failed]"); goto fail; } jdbg("SVR4_PTYS TIOCGPTPEER ptyfd %d slv %d\n", ptyfd, slvptyfd); #endif { register char *s = ptsname(ptyfd); if (s == NULL) { message("[ptsname failed]"); goto fail; } strcpy(ttybuf, s); jdbg("SVR4_PTYS ptyfd %d %s\n", ptyfd, ttybuf); } # ifdef TIOCFLUSH jdbg("TIOCFLUSH ptyfd %d\n", ptyfd); (void) ioctl(ptyfd, TIOCFLUSH, (UnivPtr) NULL); /* ??? why? */ # endif # endif /* SVR4_PTYS */ # ifdef BSD_PTYS # ifdef USE_OPENPTY if (openpty(&ptyfd, &slvptyfd, ttybuf, NULL, NULL) < 0) { message("[No pty from openpty!]"); goto fail; } jdbg("openpty ptyfd %d slv %d %s\n", ptyfd, slvptyfd, ttybuf); # else /* !USE_OPENPTY */ { register const char *s; for (s = "pqrs"; ptyfd<0; s++) { register const char *t; if (*s == '\0') { message("[Out of ptys in /dev/pty*!]"); goto fail; } for (t = "0123456789abcdef"; *t; t++) { swritef(ttybuf, sizeof(ttybuf), "/dev/pty%c%c", *s, *t); jdbg("trying pty %s\n", ttybuf); if ((ptyfd = open(ttybuf, O_RDWR | O_BINARY)) >= 0) { ttybuf[5] = 't'; /* pty => tty */ /* Make sure other end is available too */ slvptyfd = open(ttybuf, O_RDWR | O_BINARY); if (slvptyfd > 0) break; /* it worked: use this one */ /* can't open, so give up on this pty */ (void) close(ptyfd); ptyfd = slvptyfd = -1; } } } } # endif /* !USE_OPENPTY */ # endif /* BSD_PTYS */ /* Check that we can write to the pty, else things will fail in the * child, where they're harder to detect. This will not work with * GRANTPT_BUG because the grantpt and unlockpt have not been done yet. */ # ifndef GRANTPT_BUG if (access(ttybuf, R_OK | W_OK) != 0) { s_mess("[Couldn't access %s: %s]", ttybuf, strerror(errno)); goto fail; } jdbg("can access pty %s\n", ttybuf); # endif /* !GRANTPT_BUG */ # if !defined(TERMIO) && !defined(TERMIOS) # ifdef TIOCGETD jdbg("TIOCGETD %s\n", ttybuf); (void) ioctl(0, TIOCGETD, (UnivPtr) &ldisc); # endif # ifdef TIOCLGET jdbg("TIOCLGET %s\n", ttybuf); (void) ioctl(0, TIOCLGET, (UnivPtr) &lmode); # endif # endif /* !defined(TERMIO) && !defined(TERMIOS) */ # ifdef TIOCGWINSZ jdbg("TIOCGWINSZ %s\n", ttybuf); (void) ioctl(0, TIOCGWINSZ, (UnivPtr) &win); # else # ifdef BTL_BLIT jdbg("JWINSIZE %s\n", ttybuf); (void) ioctl(0, JWINSIZE, (UnivPtr) &jwin); # endif /* BTL_BLIT */ # endif jdbg("before fork, ptyfd %d slv %d buf %s\n", ptyfd, slvptyfd, ttybuf); switch (pid = fork()) { case -1: /* fork failed */ s_mess("[Fork failed! %s]", strerror(errno)); goto fail; case 0: /* child process */ # ifdef GRANTPT_BUG /* grantpt() seems to be implemented using a fork/exec. * This is done to allow grantpt do do priviledged things * via a setuid program. One consequence is that JOVE's * SIGCLD/SIGCHLD handler must not do a wait that would * reap the grantpt process. So much for library routines * being black boxes. Worse, this restriction is not documented. * * Worse still, at least Solaris 2.0 and SVR4.0 appear to have * a bug: the wait is not restarted once interrupted. If the wait * is interrupted, (1) the grantpt will return a failure status * and (2) the process will not be reaped -- it will remain a * zombie until JOVE exits or happens to reap it accidentally. * Any interrupt could cause the premature end of the wait, * but SIGCHLD (actually, SIGCLD) is the most probable. * * To dodge these bullets, we moved the grantpt into the child * where we can turn off signal handling. Too bad this prevents * us giving good diagnostics for grantpt and unlockpt. * I hope I've found all the signals caught everywhere else. */ jdbg("child grantpt bug, ptyfd %d slv %d buf %s\n", ptyfd, slvptyfd, ttybuf); (void) setsighandler(SIGCHLD, SIG_DFL); (void) setsighandler(SIGWINCH, SIG_DFL); (void) setsighandler(SIGALRM, SIG_DFL); (void) setsighandler(SIGINT, SIG_DFL); /* (void) setsighandler(SIGQUIT, SIG_DFL); */ /* dead anyway */ /* (void) setsighandler(SIGHUP, SIG_DFL); */ /* dead anyway */ /* (void) setsighandler(SIGTERM, SIG_DFL); */ /* no longer used */ /* (void) setsighandler(SIGBUS, SIG_DFL); */ /* dead anyway */ /* (void) setsighandler(SIGSEGV, SIG_DFL); */ /* dead anyway */ /* (void) setsighandler(SIGPIPE, SIG_DFL); */ /* dead anyway */ if (grantpt(ptyfd) < 0) { _exit(errno + 1); } if (unlockpt(ptyfd) < 0) { _exit(errno + 1); } # endif /* GRANTPT_BUG */ jcloseall(); (void) close(0); (void) close(1); (void) close(2); # ifdef TERMIOS jdbg("child setsid %s\n", ttybuf); setsid(); # else /* !TERMIOS */ # ifdef TIOCNOTTY /* get rid of controlling tty */ { int i = open("/dev/tty", O_RDWR | O_BINARY); jdbg("child TIOCNOTTY %d %s\n", i, ttybuf); if (i >= 0) { (void) ioctl(i, TIOCNOTTY, (UnivPtr)NULL); (void) close(i); } } # endif /* TIOCNOTTY */ # endif /* !TERMIOS */ jdbg("child ptyfd %d slv %d buf %s\n", ptyfd, slvptyfd, ttybuf); if (slvptyfd < 0) { if ((slvptyfd = open(ttybuf, O_RDWR | O_BINARY)) != 0) _exit(errno+1); jdbg("child slv slv %d\n", slvptyfd); } /* else use what we got from openpty */ (void) dup2(slvptyfd, 1); (void) dup2(slvptyfd, 2); if (slvptyfd != 0) { (void) dup2(slvptyfd, 0); jdbg("child closing slv %d %s\n", slvptyfd, ttybuf); (void) close(slvptyfd); /* safe to close now that std* are open */ } jdbg("child std 0, 1, 2 duped\n"); # ifdef SVR4_PTYS # ifdef I_PUSH /* LINUX/glibc no longer even pretends to support this (2008) */ jdbg("child SVR4_PTYS I_PUSH ptem ldterm ttcompat %s\n", ttybuf); (void) ioctl(0, I_PUSH, (UnivPtr) "ptem"); (void) ioctl(0, I_PUSH, (UnivPtr) "ldterm"); (void) ioctl(0, I_PUSH, (UnivPtr) "ttcompat"); # endif # endif # ifdef TIOCSCTTY /* Make this controling tty. * This is needed by OSF. It may be needed by BSDPOSIX systems. * It should not hurt on any system that defines TIOCSCTTY. * On Solaris (OpenIndiana 2019.11), the ioctl fails with errno 25 (ENOTTY) * but that seems harmless, so we just log but ignore error returns * (as used to be the case before 4.16.0.31!) */ jdbg("child TIOCSTTY %s\n", ttybuf); if (ioctl(0, TIOCSCTTY) < 0) { jdbg("TIOCSCTTY failed errno %d %s\n", errno, strerror(errno)); } # endif # ifndef NO_TIOCREMOTE /* The TIOCREMOTE ioctl prevents the pty code from doing * input editing on characters from the master. In particular * we don't want ERASE, KILL, INTERRUPT, QUIT, etc. characters * interpreted. * On SVR4, this must be done *after* the slave side is set up. * The easiest way to ensure this is to put it here, in the child * after the slave is opened and has the STREAMS modules pushed, * and before the master is closed. */ { int on = 1; jdbg("child TIOCREMOTE on %d %s\n", ptyfd, ttybuf); if (ioctl(ptyfd, TIOCREMOTE, (UnivPtr) &on) < 0) _exit(errno+1); /* no good way to signal user */ } # endif jdbg("child closing %d %s\n", ptyfd, ttybuf); close(ptyfd); # if !defined(TERMIO) && !defined(TERMIOS) # ifdef TIOCSETD jdbg("child TIOCSETD %s\n", ttybuf); (void) ioctl(0, TIOCSETD, (UnivPtr) &ldisc); # endif # ifdef TIOCLSET jdbg("child TIOCLSET %s\n", ttybuf); (void) ioctl(0, TIOCLSET, (UnivPtr) &lmode); # endif # ifdef TIOCSETC (void) ioctl(0, TIOCSETC, (UnivPtr) &tc[NO]); # endif # ifdef USE_TIOCSLTC jdbg("child TIOCSLTC %s\n", ttybuf); (void) ioctl(0, TIOCSLTC, (UnivPtr) &ls[NO]); # endif # endif /* !defined(TERMIO) && !defined(TERMIOS) */ # ifdef TIOCGWINSZ jdbg("child TIOCSWINSZ %s\n", ttybuf); win.ws_row = curwind->w_height; (void) ioctl(0, TIOCSWINSZ, (UnivPtr) &win); # else /* !TIOCGWINSZ */ # ifdef BTL_BLIT jdbg("child JSWINSIZE %s\n", ttybuf); jwin.bytesy = curwind->w_height; (void) ioctl(0, JSWINSIZE, (UnivPtr) &jwin); # endif # endif /* !TIOCGWINSZ */ # if defined(TERMIO) || defined(TERMIOS) jdbg("child set termio(s)%s\n", ttybuf); sgt = sg[NO]; sgt.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | ICRNL # ifdef IXANY /* not in QNX */ | IXANY # endif | IXON | IXOFF); sgt.c_lflag &= ~(ECHO); sgt.c_oflag &= ~(ONLCR | TABDLY); # ifdef TERMIO jdbg("child TCSETAW %s\n", ttybuf); do {} while (ioctl(0, TCSETAW, (UnivPtr) &sgt) < 0 && errno == EINTR); # endif # ifdef TERMIOS jdbg("child TCSADRAIN %s\n", ttybuf); do {} while (tcsetattr(0, TCSADRAIN, &sgt) < 0 && errno == EINTR); # endif # else /* !(defined(TERMIO) || defined(TERMIOS)) */ jdbg("child set sgt %s\n", ttybuf); sgt = sg[NO]; sgt.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE | CBREAK | TANDEM); (void) stty(0, &sgt); # endif /* !(defined(TERMIO) || defined(TERMIOS)) */ jdbg("child newpg %s\n", ttybuf); NEWPG(); { int i = getpid(); # ifdef POSIX_PROCS jdbg("child tcsetpgrp %d %s\n", i, ttybuf); tcsetpgrp(0, getpid()); # else /* !POSIX_PROCS */ jdbg("child TIOCSPGRP %d %s\n", i, ttybuf); (void) ioctl(0, TIOCSPGRP, (UnivPtr) &i); # endif /* POSIX_PROCS */ } set_process_env(); jdbg("child ready to exec %s %s\n", argv[0], argv[1]); execvp(argv[0], &argv[1]); raw_complain("execvp failed! %s", strerror(errno)); _exit(errno + 1); } # ifdef BSD_PTYS jdbg("closing slv %d %s\n", slvptyfd, ttybuf); close(slvptyfd); # endif /* BSD_PTYS */ newp = (Process) emalloc(sizeof *newp); # ifdef O_NDELAY jdbg("O_NDELAY %d %s\n", ptyfd, ttybuf); fcntl(ptyfd, F_SETFL, O_NDELAY); # endif # ifdef O_NONBLOCK jdbg("O_NONBLOCK %d %s\n", ptyfd, ttybuf); fcntl(ptyfd, F_SETFL, O_NONBLOCK); # endif (void) time(&(newp->p_start)); jdbg("start pid %d fd %d %s %D\n", pid, ptyfd, ttybuf, (long) newp->p_start); newp->p_fd = ptyfd; newp->p_pid = pid; newbuf = do_select((Window *)NULL, bufname); newbuf->b_type = B_PROCESS; newp->p_buffer = newbuf; newbuf->b_process = newp; /* sorta circular, eh? */ pop_wind(bufname, clobber, B_PROCESS); /* Pop_wind() after everything is set up; important! * Bindings won't work right unless newbuf->b_process is already * set up BEFORE NEWBUF is first SetBuf()'d. */ ToLast(); if (!bolp()) LineInsert(1); newp->p_name = copystr(procname); newp->p_io_state = IO_NEW; newp->p_child_state = C_LIVE; newp->p_mark = MakeMark(curline, curchar); newp->p_next = procs; procs = newp; FD_SET(newp->p_fd, &global_fd); if (global_maxfd <= newp->p_fd) global_maxfd = newp->p_fd + 1; SetWind(owind); return; fail: jdbg("pty open fail %d %d %s\n", ptyfd, slvptyfd, ttybuf); if (ptyfd >= 0) close(ptyfd); # ifdef BSD_PTYS if (slvptyfd >= 0) close(slvptyfd); # endif /* BSD_PTYS */ } /* NOTE 1: SIGCHLD is an asynchronous signal. To safely handle it, * the sigchld_handler simply sets a flag requesting later processing. * reap_procs is called synchronously to do the actual work. * * NOTE 2: SIGCHLD is "level triggered" on some systems (HPUX, IRIX, ...). * If the signal signal handler is re-established before the child is reaped, * another signal will be generated immediately. For this reason, we * defer the re-establishment until reap_procs is done. */ volatile jbool procs_to_reap = NO; /*ARGSUSED*/ SIGRESTYPE sigchld_handler(junk) int UNUSED(junk); /* needed for signal handler; not used */ { procs_to_reap = YES; return SIGRESVALUE; } void reap_procs() { wait_status_t w; register pid_t pid; for (;;) { pid = wait_opt(&w, (WNOHANG | WUNTRACED)); if (pid <= 0) { if (procs_to_reap) { resetsighandler(SIGCHLD, sigchld_handler); procs_to_reap = NO; /* go around once more to avoid window of vulnerability */ } else { break; } } else { kill_off(pid, w); } } } void closeiprocs() { Process p; for (p=procs; p!=NULL; p=p->p_next) if (p->p_fd >= 0) close(p->p_fd); } #endif /* !PIPEPROCS */ /* This is for the shell window. Supports sh, csh and ksh. */ char proc_prompt[128] = "^[^%$#]*[%$#] "; /* VAR: process prompt */ const char * pstate(p) Process p; { static const char *const ios_name[] = { "New", "Running", "EOFed" }; if (p == NULL) return "No process"; /* Try *not* to report the whole cross-product of child and IO states. */ switch (p->p_child_state) { case C_LIVE: return ios_name[p->p_io_state]; case C_STOPPED: return io_eofed(p)? "Stopped; EOFed" : "Stopped"; case C_EXITED: if (io_eofed(p) && p->p_reason == 0) return "Done"; /* FALLTHROUGH */ default: return sprint("%s %d%s", (p->p_child_state == C_EXITED? "Exited" : "Killed"), p->p_reason, (io_eofed(p)? "" : "; not EOFed")); } } jbool KillProcs() { register Process p; jbool asked = NO; for (p = procs; p != NULL; p = p->p_next) { if (!dead(p)) { if (!asked) { if (!yes_or_no_p("Some interactive processes are still running; leave anyway? ")) return NO; /* processes not killed */ asked = YES; } if (!child_dead(p)) (void) proc_kill(p, SIGKILL); proc_close(p); } } return YES; /* processes killed */ } /* VAR: dbx-mode parse string */ char dbx_parse_fmt[128] = "line \\([0-9]*\\) in \\{file\\|\\} *\"\\([^\"]*\\)\""; private void watch_input(m) Mark *m; { Bufpos save; char fname[FILESIZE], lineno[FILESIZE]; long lnum; Window *savew = curwind; Buffer *buf; DOTsave(&save); ToMark(m); if (dosearch(dbx_parse_fmt, FORWARD, YES) != NULL) { get_FL_info(fname, lineno); buf = do_find((Window *)NULL, fname, YES, YES); pop_wind(buf->b_name, NO, -1); lnum = atol(lineno); SetLine(next_line(buf->b_first, lnum - 1)); SetWind(savew); } SetDot(&save); } /* Process receive: receives the characters in buf, and appends them to * the buffer associated with p. */ private void proc_rec(p, buf, len) register Process p; char *buf; size_t len; { Buffer *saveb = curbuf; register Window *w; register Mark *savepoint; jbool sameplace, do_disp; if (curwind->w_bufp == p->p_buffer) w = curwind; else w = windbp(p->p_buffer); /* Is this window visible? */ do_disp = w != NULL && in_window(w, p->p_mark->m_line) != -1; SetBuf(p->p_buffer); savepoint = MakeMark(curline, curchar); ToMark(p->p_mark); /* where output last stopped */ sameplace = savepoint->m_line == curline && savepoint->m_char == curchar; /* insert contents of buffer, carefully translating NUL to ^@ */ buf[len] = '\0'; /* NUL-terminate buffer */ while (len != 0) { if (*buf == '\0') { ins_str_wrap("^@", YES, WrapProcessLines ? CO-1 : LBSIZE-1); buf++; len--; } else { size_t sublen = strlen(buf); ins_str_wrap(buf, YES, WrapProcessLines ? CO-1 : LBSIZE-1); buf += sublen; len -= sublen; } } if (do_disp && BufMinorMode(p->p_buffer, DbxMode)) watch_input(p->p_mark); MarkSet(p->p_mark, curline, curchar); if (!sameplace) ToMark(savepoint); /* back to where we were */ DelMark(savepoint); /* redisplay now, instead of right after the ins_str, so that * we don't get a bouncing effect if point is not the same as * the process output position */ if (do_disp) { w->w_line = curline; w->w_char = curchar; redisplay(); } SetBuf(saveb); } private jbool proc_kill(p, sig) register Process p; int sig; { if (p == NULL) { complain("[no process]"); /* NOTREACHED */ } if (!child_dead(p)) { if (killpg(p->p_pid, sig) != -1) return YES; s_mess("Cannot kill %s!", proc_bufname(p)); } return NO; } /* Free process CHILD. Do all the necessary cleaning up (closing fd's, * etc.). */ private void free_proc(child) Process child; { register Process p, prev = NULL; if (!dead(child)) return; untieDeadProcess(child->p_buffer); for (p = procs; p != child; prev = p, p = p->p_next) ; if (prev == NULL) procs = child->p_next; else prev->p_next = child->p_next; proc_close(child); /* if not already closed */ free((UnivPtr) child->p_name); free((UnivPtr) child); } void untieDeadProcess(b) register Buffer *b; { if (b != NULL) { register Process p = b->b_process; if (p != NULL) { Buffer *old = curbuf; if (!dead(p)) { complain("Process %s, attached to %b, is %s.", proc_cmd(p), b, pstate(p)); /* NOTREACHED */ } SetBuf(p->p_buffer); DelMark(p->p_mark); SetBuf(old); p->p_buffer = NULL; b->b_process = NULL; } } } void ProcList() { register Process p, next; const char *fmt = "%-15s %-15s %-8s %s"; char pidstr[16]; if (procs == NULL) { message("[No subprocesses]"); return; } TOstart("Process list"); Typeout(fmt, "Buffer", "Status", "Pid ", "Command"); Typeout(fmt, "------", "------", "--- ", "-------"); for (p = procs; p != NULL; p = next) { next = p->p_next; swritef(pidstr, sizeof(pidstr), "%d", (int) p->p_pid); Typeout(fmt, proc_bufname(p), pstate(p), pidstr, p->p_name); if (dead(p)) { free_proc(p); UpdModLine = YES; } } TOstop(); } private void do_rtp(mp) register Mark *mp; { register Process p = curbuf->b_process; LinePtr line1 = curline, line2 = mp->m_line; int char1 = curchar, char2 = mp->m_char; char *gp; size_t nbytes; if (dead(p) || p->p_buffer != curbuf) return; (void) fixorder(&line1, &char1, &line2, &char2); while (line1 != line2->l_next) { gp = ltobuf(line1, genbuf) + char1; if (line1 == line2) { nbytes = char2 - char1; } else { genbuf[Jr_Len] = EOL; /* replace NUL with EOL */ nbytes = Jr_Len - char1 + 1; /* and include it */ } if (nbytes != 0) proc_write(p, gp, nbytes); line1 = line1->l_next; char1 = 0; } } void ProcNewline() { #ifdef ABBREV MaybeAbbrevExpand(); #endif SendData(YES); } void ProcSendData() { #ifdef ABBREV MaybeAbbrevExpand(); #endif SendData(NO); } private void SendData(newlinep) jbool newlinep; { register Process p = curbuf->b_process; register char *lp, *gp; /* JF fix for better prompt handling */ if (dead(p)) return; /* If the process mark was involved in a big deletion, because * the user hit ^W or something, then let's do some magic with * the process mark. Problem is that if the user yanks back the * text he deleted, the mark stays at the beginning of the region, * and so the next time SendData() is called the entire region * will be sent. That's not good. So, to deal with that we reset * the mark to the last line, after skipping over the prompt, etc. */ if (p->p_mark->m_big_delete) { Bufpos bp; p->p_mark->m_big_delete = NO; DOTsave(&bp); ToLast(); Bol(); /* While we're looking at a prompt, and while we're * moving forward. This is for people who accidently * set their process-prompt to ">*" which will always * match! */ while (LookingAt(proc_prompt, linebuf, curchar) && (REeom > curchar)) curchar = REeom; MarkSet(p->p_mark, curline, curchar); SetDot(&bp); } if (lastp(curline)) { Eol(); if (newlinep) LineInsert(1); do_rtp(p->p_mark); MarkSet(p->p_mark, curline, curchar); } else { /* Either we're looking at a prompt, or we're not, in * which case we want to strip off the beginning of the * line anything that looks like what the prompt at the * end of the file is. In other words, if "(dbx) stop in * ProcessNewline" is the line we're on, and the last * line in the buffer is "(dbx) ", then we strip off the * leading "(dbx) " from this line, because we know it's * part of the prompt. But this only happens if "(dbx) " * isn't one of the process prompts ... follow what I'm * saying? */ Bol(); if (LookingAt(proc_prompt, linebuf, curchar)) { do { curchar = REeom; } while (LookingAt(proc_prompt, linebuf, curchar) && (REeom > curchar)); strcpy(genbuf, linebuf + curchar); Eof(); ins_str(genbuf); } else { strcpy(genbuf, linebuf + curchar); Eof(); gp = genbuf; lp = linebuf; while (*lp == *gp && *lp != '\0') { lp += 1; gp += 1; } ins_str(gp); } } } void ShellProc() { char shbuf[20]; register Buffer *b; swritef(shbuf, sizeof(shbuf), "[shell-%d]", arg_value()); b = buf_exists(shbuf); if (b == NULL || dead(b->b_process)) { char cbnspace[FILESIZE]; proc_strt(shbuf, NO, "i-shell", Shell, "-is", curbuf->b_fname == NULL? (char *)NULL : strcpy(cbnspace, pr_name(curbuf->b_fname, NO)), (char *)NULL); } pop_wind(shbuf, NO, -1); } void Iprocess() { char scratch[64], *bnm; int cnt = 1; Buffer *bp; char fnspace[FILESIZE]; char *fn = curbuf->b_fname == NULL ? (char *) NULL : strcpy(fnspace, pr_name(curbuf->b_fname, NO)); jamstr(ShcomBuf, ask(ShcomBuf, ProcFmt)); bnm = MakeName(ShcomBuf); truncstr(scratch, bnm); while ((bp = buf_exists(scratch)) != NULL && !dead(bp->b_process)) swritef(scratch, sizeof(scratch), "%s.%d", bnm, cnt++); proc_strt(scratch, YES, ShcomBuf, Shell, ShFlags, ShcomBuf, fn, fn, (char *)NULL); } pid_t DeadPid; /* info about ChildPid, if reaped by kill_off */ wait_status_t DeadStatus; #ifdef USE_PROTOTYPES void kill_off(pid_t pid, wait_status_t w) #else void kill_off(pid, w) register pid_t pid; wait_status_t w; #endif { register Process child; if (pid == ChildPid) { /* we are reaping the non-iproc process: record info */ DeadPid = pid; DeadStatus = w; return; } if ((child = proc_pid(pid)) == NULL) return; UpdModLine = YES; /* we're changing state ... */ if (WIFSTOPPED(w)) child->p_child_state = C_STOPPED; else { #ifdef PIPEPROCS /* the true process status comes by pipe, not from wait(). * However, we must note the death of portsrv processes. */ child->p_portlive = NO; #else /* !PIPEPROCS */ /* record the details of the death of the process. * Kludge: see if we can get any queued EOF from pty first. * We wish to do this to make our message less confusing. */ while (!io_eofed(child)) { int nfds; fd_set reads; struct timeval notime; FD_ZERO(&reads); FD_SET(child->p_fd, &reads); notime.tv_sec = 0; notime.tv_usec = 0; nfds = select(global_maxfd, &reads, (fd_set *)NULL, (fd_set *)NULL, ¬ime); if (nfds == 1) read_pty_proc(child->p_fd); else if (nfds >= 0 || errno != EINTR) { # ifdef NO_EOF_FROM_PTY /* Certain systems never indicate EOF from a slave. * On those systems, we force a close when the direct * child terminates. */ proc_close(child); # endif break; } } obituary(child, w); #endif /* !PIPEPROCS */ } } #ifdef USE_PROTOTYPES private void obituary(register Process child, wait_status_t w) #else private void obituary(child, w) register Process child; wait_status_t w; #endif { UpdModLine = YES; /* we're changing state ... */ if (WIFEXITED(w)) { child->p_child_state = C_EXITED; child->p_reason = WEXITSTATUS(w); } else if (WIFSIGNALED(w)) { child->p_child_state = C_KILLED; child->p_reason = WTERMSIG(w); } else { /* presume it died peacefully! */ child->p_child_state = C_EXITED; child->p_reason = 0; } { Buffer *save = curbuf; Bufpos bp; char mesg[128]; /* insert status message now */ swritef(mesg, sizeof(mesg), "[Process %s: %s]\n", proc_cmd(child), pstate(child)); SetBuf(child->p_buffer); DOTsave(&bp); ToLast(); ins_str(mesg); SetDot(&bp); SetBuf(save); redisplay(); } } #endif /* IPROCS */ jove-4.17.5.5/iproc.h000066400000000000000000000046371501102521500142050ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef IPROCS /* the body is the rest of this file */ typedef struct process *Process; /* process reference (opaque type) */ # ifdef PIPEPROCS extern char Portsrv[FILESIZE]; /* path to portsrv program (in LibDir) */ extern int NumProcs; # define KBDSIG SIGUSR1 /* used for shoulder tapping */ /* Messages from kbd and portsrv to jove. * We depend on writes to a pipe being atomic. * This seems to be the case if the write is short enough (<4k?) * but not documented in the UNIX manuals. */ struct header { pid_t pid; /* sender */ int nbytes; /* data length */ }; struct lump { struct header header; char data[128]; /* data being sent */ }; extern File *ProcInput; extern pid_t kbd_pid; extern void kbd_strt proto((void)); extern jbool kbd_stop proto((void)); extern void read_pipe_proc proto((pid_t, int)); extern void kbd_kill proto((void)); # else /* !PIPEPROCS */ extern void read_pty_proc proto((int)); extern SIGRESTYPE sigchld_handler proto((int)); extern volatile jbool procs_to_reap; extern void reap_procs proto((void)); # endif /* !PIPEPROCS */ extern void closeiprocs proto((void)), untieDeadProcess proto((Buffer *)); extern jbool KillProcs proto((void)); extern const char *pstate proto((Process)); extern pid_t DeadPid; /* info about ChildPid, if reaped by kill_off */ extern wait_status_t DeadStatus; extern void kill_off proto((pid_t, wait_status_t)); /* Commands: */ extern void ProcInt proto((void)), Iprocess proto((void)), ShellProc proto((void)), ProcQuit proto((void)), ProcKill proto((void)), # ifdef PTYPROCS ProcCont proto((void)), ProcDStop proto((void)), ProcEof proto((void)), ProcStop proto((void)), # endif ProcSendData proto((void)), ProcNewline proto((void)), ProcList proto((void)), IprocEnvExport proto((void)), IprocEnvShow proto((void)), IprocEnvUnset proto((void)); /* Variables: */ extern char proc_prompt[128], /* VAR: process prompt */ dbx_parse_fmt[128]; /* VAR: dbx-mode parse string */ #endif /* IPROCS */ jove-4.17.5.5/jctype.c000066400000000000000000000517541501102521500143640ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #define cU (C_UPPER | C_WORD | C_PRINT) /* Upper case => Word => Printable */ #define cL (C_LOWER | C_WORD | C_PRINT) /* Lower case => Word => Printable */ #define cN (C_DIGIT | C_WORD | C_PRINT) /* Numeric => Word => Printable */ #define cP (C_PUNCT | C_PRINT) /* Punctuation => Printable */ #define cV C_PRINT /* printable (Visible) */ #define cW (C_WORD | C_PRINT) /* Word => Printable */ #define cO (C_BRA | C_PUNCT | C_PRINT) /* Open parenthesis => Punctuation => Printable */ #define cC (C_KET | C_PUNCT | C_PRINT) /* Close parenthesis => Punctuation => Printable */ const unsigned char CharTable[NCHARS] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 030 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 040 */ cO, cC, cP, cP, cP, cP, cP, cP, /* 050 */ cN, cN, cN, cN, cN, cN, cN, cN, /* 060 */ cN, cN, cP, cP, cP, cP, cP, cP, /* 070 */ cP, cU, cU, cU, cU, cU, cU, cU, /* 100 */ cU, cU, cU, cU, cU, cU, cU, cU, /* 110 */ cU, cU, cU, cU, cU, cU, cU, cU, /* 120 */ cU, cU, cU, cO, cP, cC, cP, cP, /* 130 */ cP, cL, cL, cL, cL, cL, cL, cL, /* 140 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 150 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 160 */ cL, cL, cL, cO, cP, cC, cP, 0, /* 170 */ #if NCHARS != 128 # ifdef ISO_8859_1 0, 0, 0, 0, 0, 0, 0, 0, /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 230 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 240 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 250 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 260 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 270 */ cU, cU, cU, cU, cU, cU, cU, cU, /* 300 */ cU, cU, cU, cU, cU, cU, cU, cU, /* 310 */ cU, cU, cU, cU, cU, cU, cU, cP, /* 320 */ cU, cU, cU, cU, cU, cU, cU, cL, /* 330 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 340 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 350 */ cL, cL, cL, cL, cL, cL, cL, cP, /* 360 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 370 */ # else /* !ISO_8859_1 */ # ifdef CODEPAGE437 cU, cL, cL, cL, cL, cL, cL, cL, /* 200 */ cL, cL, cL, cL, cL, cL, cU, cU, /* 210 */ cU, cL, cU, cL, cL, cL, cL, cL, /* 220 */ cL, cU, cU, cP, cP, cP, cP, cP, /* 230 */ cL, cL, cL, cL, cL, cU, cP, cP, /* 240 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 250 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 260 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 270 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 300 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 310 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 320 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 330 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 340 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 350 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 360 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 370 */ # else /* !CODEPAGE437 */ # ifdef MAC /* See Inside Macintosh Vol One p. 247 */ cU, cU, cU, cU, cU, cU, cU, cL, /* 200 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 210 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 220 */ cL, cL, cL, cL, cL, cL, cL, cL, /* 230 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 240 */ cP, cP, cP, cP, cP, cP, cU, cU, /* 250 */ cP, cP, cP, cP, cP, cU, cL, cU, /* 260 */ cU, cL, cP, cP, cP, cU, cL, cL, /* 270 */ cP, cP, cP, cP, cP, cP, cU, cP, /* 300 */ cP, cP, cP, cU, cU, cU, cU, cU, /* 310 */ cP, cP, cP, cP, cP, cP, cP, cP, /* 320 */ cU, 0, 0, 0, 0, 0, 0, 0, /* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 370 */ # else /* !MAC */ /* control, by default */ 0, 0, 0, 0, 0, 0, 0, 0, /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 240 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 250 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 260 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 270 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 300 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 310 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 320 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 370 */ # endif /* !MAC */ # endif /* !CODEPAGE437 */ # endif /* !ISO_8859_1 */ #endif /* NCHARS != 128 */ }; #undef cU #undef cL #undef cN #undef cP #undef cV #undef cW #undef cO #undef cC /* Which characters are legal in an identifier (word)? * This depends on the major mode. Anything considered * part of an identifier in Fundamental mode is considered to * be a part of an identifier in any other mode (this is * an assumption of the USE_LCTYPE code). For other modes, * more characters are considered to be part of identifiers: * - text mode adds ' * - C mode adds _ * - lisp mode adds !$%& *+-/ :<=>? @ ^_{|}~ * Note that none of these modes currently adds anything in the * upper half of an 8-bit character set. */ #define wF (1 << FUNDAMENTAL) #define wT (1 << TEXTMODE) #define wC (1 << CMODE) #ifdef LISP # define wL (1 << LISPMODE) #else # define wL 0 #endif #define w (wF|wT|wC|wL) private const unsigned char IdChartable[NCHARS] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 030 */ 0, wL, 0, 0, wL, wL, wL, wT, /* 040 */ 0, 0, wL, wL, 0, wL, 0, wL, /* 050 */ w, w, w, w, w, w, w, w, /* 060 */ w, w, wL, 0, wL, wL, wL, wL, /* 070 */ wL, w, w, w, w, w, w, w, /* 100 */ w, w, w, w, w, w, w, w, /* 110 */ w, w, w, w, w, w, w, w, /* 120 */ w, w, w, 0, 0, 0, wL, wC|wL, /* 130 */ 0, w, w, w, w, w, w, w, /* 140 */ w, w, w, w, w, w, w, w, /* 150 */ w, w, w, w, w, w, w, w, /* 160 */ w, w, w, wL, wL, wL, wL, wL, /* 170 */ #if NCHARS != 128 # ifdef ISO_8859_1 0, 0, 0, 0, 0, 0, 0, 0, /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 240 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 250 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 260 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 270 */ w, w, w, w, w, w, w, w, /* 300 */ w, w, w, w, w, w, w, w, /* 310 */ w, w, w, w, w, w, w, 0, /* 320 */ w, w, w, w, w, w, w, w, /* 330 */ w, w, w, w, w, w, w, w, /* 340 */ w, w, w, w, w, w, w, w, /* 350 */ w, w, w, w, w, w, w, 0, /* 360 */ w, w, w, w, w, w, w, w, /* 370 */ # else /* !ISO_8859_1 */ # ifdef CODEPAGE437 w, w, w, w, w, w, w, w, /* 200 */ w, w, w, w, w, w, w, w, /* 210 */ w, w, w, w, w, w, w, w, /* 220 */ w, w, w, 0, 0, 0, 0, 0, /* 230 */ w, w, w, w, w, w, 0, 0, /* 240 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 250 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 260 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 270 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 300 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 310 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 320 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 370 */ # else /* !CODEPAGE437 */ # ifdef MAC /* See Inside Macintosh Vol One p. 247 */ w, w, w, w, w, w, w, w, /* 200 */ w, w, w, w, w, w, w, w, /* 210 */ w, w, w, w, w, w, w, w, /* 220 */ w, w, w, w, w, w, w, w, /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 240 */ 0, 0, 0, 0, 0, 0, w, w, /* 250 */ 0, 0, 0, 0, 0, w, w, w, /* 260 */ w, w, 0, 0, 0, w, w, w, /* 270 */ 0, 0, 0, 0, 0, 0, w, 0, /* 300 */ 0, 0, 0, w, w, w, w, w, /* 310 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 320 */ w, 0, 0, 0, 0, 0, 0, 0, /* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 370 */ # else /* !MAC */ /* control, by default */ 0, 0, 0, 0, 0, 0, 0, 0, /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 240 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 250 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 260 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 270 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 300 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 310 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 320 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 330 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 340 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 350 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 360 */ 0, 0, 0, 0, 0, 0, 0, 0, /* 370 */ # endif /* !MAC */ # endif /* !CODEPAGE437 */ # endif /* !ISO_8859_1 */ #endif /* NCHARS != 128 */ }; #undef wF #undef wT #undef wC #undef wL #undef w jbool jisident(c) DAPchar c; { #ifdef USE_CTYPE return (IdChartable[ZXC(c)] & (1 << curbuf->b_major)) != 0 || jisword(c); #else return (IdChartable[ZXC(c)] & (1 << curbuf->b_major)) != 0; #endif } #ifdef USE_CTYPE # ifndef NO_SETLOCALE # include char LcCtype[32] = ""; /* VAR: lc-ctype, for use in setlocale */ /* adjust the locale to reflect possible change to LcCtype */ void locale_adjust() { char *res = setlocale(LC_CTYPE, LcCtype); if (res != NULL) { /* success: if it fits, record result */ if (strlen(res) < sizeof(LcCtype)) strcpy(LcCtype, res); } else if (LcCtype[0] != '\0') { /* Failure, but not for "". Complain, after recovering. * Note: We don't try to print a message if "" fails because it * might be the initializing call, too early for "complain", * or it might be the recursive call. */ char temp[sizeof(LcCtype)]; strcpy(temp, LcCtype); res = setlocale(LC_CTYPE, (char *)NULL); if (res != NULL && strlen(res) < sizeof(LcCtype)) { strcpy(LcCtype, res); } else { LcCtype[0] = '\0'; /* default */ locale_adjust(); /* note: this will recurse only one level */ } complain("Unrecognized lc-ctype: %s", temp); /* NOTREACHED */ } } # endif /* !NO_SETLOCALE */ #else /* !USE_CTYPE */ /* Map lower case characters to upper case and the rest to themselves. */ const char RaiseTable[NCHARS] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', '\040', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', '\177', # if NCHARS != 128 # ifdef ISO_8859_1 '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\367', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\377', # else /* !ISO_8859_1 */ # ifdef CODEPAGE437 /* Only codes changed are lowercase Umlauted letters (indented): * Ae '\216'; ae '\204' * Oe '\231'; oe '\224' * Ue '\232'; ue '\201' */ '\200', '\232', '\202', '\203', '\216', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\231', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # else /* !CODEPAGE437 */ # ifdef MAC /* '\230' -> '\313' * '\212' -> '\200' * '\213' -> '\314' * '\214' -> '\201' * '\215' -> '\202' * '\216' -> '\203' * '\226' -> '\204' * '\232' -> '\205' * '\233' -> '\315' * '\237' -> '\206' * '\271' -> '\270' * '\317' -> '\316' */ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\313', '\211', '\200', '\314', '\201', '\202', '\203', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\204', '\227', '\230', '\231', '\205', '\315', '\234', '\235', '\236', '\206', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\306', '\267', '\270', '\270', '\272', '\273', '\274', '\275', '\256', '\257', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\316', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # else /* !MAC */ /* identity, by default */ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # endif /* !MAC */ # endif /* !CODEPAGE437 */ # endif /* !ISO_8859_1 */ # endif /* NCHARS != 128*/ }; /* Map upper case characters to lower case and the rest to themselves. */ const char LowerTable[NCHARS] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', '\040', '!', '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~', '\177', # if NCHARS != 128 # ifdef ISO_8859_1 '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\327', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # else /* !ISO_8859_1 */ # ifdef CODEPAGE437 /* Only codes changed are uppercase Umlauted letters (indented): * Ae '\216'; ae '\204' * Oe '\231'; oe '\224' * Ue '\232'; ue '\201' */ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\204', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\224', '\201', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # else /* !CODEPAGE437 */ # ifdef MAC /* '\200' -> '\212' * '\201' -> '\214' * '\202' -> '\215' * '\203' -> '\216' * '\204' -> '\226' * '\205' -> '\232' * '\206' -> '\237' * '\270' -> '\271' * '\313' -> '\230' * '\314' -> '\213' * '\315' -> '\233' * '\316' -> '\317' */ '\212', '\214', '\215', '\216', '\226', '\232', '\237', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\271', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\230', '\213', '\233', '\317', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # else /* !MAC */ /* identity, by default */ '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307', '\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317', '\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327', '\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', # endif /* !MAC */ # endif /* !CODEPAGE437 */ # endif /* !ISO_8859_1 */ # endif /* NCHARS != 128*/ }; #endif /* !USE_CTYPE */ jove-4.17.5.5/jctype.h000066400000000000000000000040521501102521500143560ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* NOTE: unlike standard is* routines, these must not be applied * to EOF. On the other hand, they may safely be applied to * sign-extended values. */ #define C_UPPER 0001 /* UPPER case */ #define C_LOWER 0002 /* LOWER case */ #define C_DIGIT 0004 /* DIGIT */ #define C_PUNCT 0010 /* PUNCTuation */ #define C_PRINT 0020 /* PRINTable */ #define C_WORD 0040 /* WORD */ #define C_BRA 0100 /* open BRAket */ #define C_KET 0200 /* close braKET */ extern const unsigned char CharTable[NCHARS]; #define has_syntax(c,s) ((CharTable[ZXC(c)]&(s)) != 0) #define jisdigit(c) has_syntax(c, C_DIGIT) #define jisopenp(c) has_syntax(c, C_BRA) #define jisclosep(c) has_syntax(c, C_KET) #define jiswhite(c) ((c) == ' ' || (c) == '\t') /* NOT isspace! */ extern jbool jisident proto((DAPchar)); #ifdef USE_CTYPE # include # define jisprint(c) isprint(ZXC(c)) # define jisword(c) isalnum(ZXC(c)) # define jisupper(c) isupper(ZXC(c)) # define jislower(c) islower(ZXC(c)) # define CharUpcase(c) toupper(ZXC(c)) # define CharDowncase(c) tolower(ZXC(c)) #ifndef NO_SETLOCALE extern char LcCtype[32]; /* VAR: lc-ctype, for use in setlocale */ extern void locale_adjust proto ((void)); #endif #else /* !USE_CTYPE */ # define jisprint(c) has_syntax(c, C_PRINT) # define jisword(c) has_syntax(c, C_WORD) # define jisupper(c) has_syntax(c, C_UPPER) # define jislower(c) has_syntax(c, C_LOWER) extern const char RaiseTable[NCHARS], LowerTable[NCHARS]; # define CharUpcase(c) ZXC(RaiseTable[ZXC(c)]) # define CharDowncase(c) ZXC(LowerTable[ZXC(c)]) #endif /* !USE_CTYPE */ #define cind_eq(a, b) (CharUpcase(a) == CharUpcase(b)) jove-4.17.5.5/jjove.ico000066400000000000000000000013761501102521500145260ustar00rootroot00000000000000 ( @    ????jove-4.17.5.5/jjove.rc000066400000000000000000000061361501102521500143570ustar00rootroot00000000000000//Microsoft Developer Studio generated resource script. // #define APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 2 resource. // #include // per https://mattshaw.org/news/fix-for-error-rc2144-primary-language-id-not-a-number/ #include "version.h" ///////////////////////////////////////////////////////////////////////////// #undef APSTUDIO_READONLY_SYMBOLS ///////////////////////////////////////////////////////////////////////////// // English (Canada) resources #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENC) #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_CAN #pragma code_page(1252) #endif //_WIN32 ///////////////////////////////////////////////////////////////////////////// // // Icon // // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_JOVE_ICON ICON DISCARDABLE "jjove.ico" #ifdef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // TEXTINCLUDE // 1 TEXTINCLUDE DISCARDABLE BEGIN "\0" END 2 TEXTINCLUDE DISCARDABLE BEGIN "\0" END 3 TEXTINCLUDE DISCARDABLE BEGIN "#include ""version.h""\r\n" "\0" END #endif // APSTUDIO_INVOKED #ifndef _MAC ///////////////////////////////////////////////////////////////////////////// // // Version // VS_VERSION_INFO VERSIONINFO FILEVERSION jversion_lnum PRODUCTVERSION jversion_lnum FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L #else FILEFLAGS 0x0L #endif FILEOS 0x40004L FILETYPE 0x1L FILESUBTYPE 0x0L BEGIN BLOCK "StringFileInfo" BEGIN BLOCK "100904b0" BEGIN VALUE "Comments", "Originally authored by Jonathan Payne\0" VALUE "CompanyName", "github.com/jonmacs/jove\0" VALUE "LegalCopyright", "Copyright (C) 1986-1999 by Jonathan Payne." VALUE "Copyright", "This program is Copyright (C) 1986-1999 by Jonathan Payne. JOVE is " "provided by Jonathan and Jovehacks without charge and without " "warranty. You may copy, modify, and/or distribute JOVE, provided that " "this notice is included in all the source files and documentation.\0" VALUE "FileDescription", "Jonathan's Own Version of Emacs\0" VALUE "FileVersion", jversion "\0" VALUE "InternalName", "Jove\0" VALUE "OriginalFilename", "JOVE.EXE\0" VALUE "ProductName", "Jove for Win32" "\0" VALUE "ProductVersion", jversion "\0" END END BLOCK "VarFileInfo" BEGIN VALUE "Translation", 0x1009, 1200 END END #endif // !_MAC #endif // English (Canada) resources ///////////////////////////////////////////////////////////////////////////// #ifndef APSTUDIO_INVOKED ///////////////////////////////////////////////////////////////////////////// // // Generated from the TEXTINCLUDE 3 resource. // #include "version.h" ///////////////////////////////////////////////////////////////////////////// #endif // not APSTUDIO_INVOKED jove-4.17.5.5/jmake.sh000077500000000000000000000075011501102521500143370ustar00rootroot00000000000000#!/bin/sh -ex # NOTE: Jove does not use autotools/configure. This is # a minimal convenience wrapper that crudely auto-detects the OS on # a few of the most common modern (2020+) open-source # operating systems by using uname (which can be overridden for # testing or cross-build). It sets appropriate variables # (CC, SYSDEFS, OPTFLAGS, LDLIBS, LDFLAGS) for make. # All command-line arguments given to jmake.sh are # passed directly onward to make. # For distro maintainers or sysadmins with complex or multi-target # build environments, or those who just prefer full control of config, # just ignore this script, invoke make directly with # the flags you want (see last line for examples. # JMAKE_RELATIVE=1 to set SHAREDIR=doc LIBDIR= for a portable # install (can copy around a directory with the jove, recover and portsrv # executables and a doc subdirectory with cmds.txt, teach-jove, jove.rc) # JMAKE_UNAME=i686-w64-mingw32 sets up a cross-compile for Win32 u=${JMAKE_UNAME-`uname | tr -d -c '[a-zA-Z0-9_]'`} defcc=${CC-cc} sysdefs="-D$u" # see sysdep.h for symbols to define for porting Jove to various systems # most modern compilers are gcc-compatible (even if called cc) optflags=${OPTFLAGS-${CFLAGS-"-g -Os -Wall -Werror -pedantic"}} ldlibs= ldflags= # special link flags, usually none needed extra= # older UN*X (e.g Solaris, SunOS, etc, might need these) rel= locc=${LOCALCC-$defcc} case "$u" in *mingw*) # presumably set via something like JMAKE_UNAME=i686-w64-mingw32 : ${JMAKE_RELATIVE=1} defcc="$u-gcc" sysdefs="-DMINGW" case "$u" in *x86_64*) optflags="$optflags -Wno-long-long" # Win64 needs long long, and older gcc produce a C90 complaint;; esac extra="LOCALCC=$locc XEXT=.exe WINDRES=$u-windres EXTRAOBJS=win32.o ICON=jjove.coff" ldlibs=-lcomdlg32 ;; *-linux-musl*) # presumably set via something like JMAKE_UNAME=i486-linux-musl : ${JMAKE_RELATIVE=1} defcc="$u-gcc" sysdefs="-DLinux -DJTC" optflags="$optflags -static" extra="LOCALCC=$locc" # for setmaps ;; CYGWIN*) sysdefs="-DCYGWIN" ;; *BSD|DragonFly|Darwin) # openpty on *BSD requires libutil ldlibs="-ltermcap -lutil" optflags="$optflags" ;; SunOS) for dx in /usr/bin /usr/sfw/bin; do if test -e $dx/gcc; then defcc=$dx/gcc break fi done case "${CC-$defcc}" in *gcc|*clang) ;; *) optflags=-O;; # generally not gcc, perhaps Sunpro or classic Unix cc esac ldlibs="-ltermcap" extra="$extra NROFF=nroff TROFF=troff" xi=/usr/gnu/bin/install if test ! -x $xi; then xi=cp fi extra="$extra XINSTALL=$xi TINSTALL=$xi" ;; GNU|Linux) if dpkg-buildflags > /dev/null 2>&1; then sysdefs="$sysdefs `dpkg-buildflags --get CPPFLAGS`" optflags="$optflags `dpkg-buildflags --get CFLAGS`" ldflags="$ldflags `dpkg-buildflags --get LDFLAGS`" fi jtc=y # see if we can find ncurses installed via pkgconf or pkg-config # generally results in no cflags, but some libs for pkc in pkgconf pkg-config; do if $pkc --version > /dev/null 2>&1; then if $pkc ncurses > /dev/null 2>&1; then optflags="$optflags `$pkc --cflags ncurses`" ldlibs="$ldlibs `$pkc --libs ncurses`" jtc=n fi break fi done if test x$jtc = xy -a -e /etc/gentoo-release; then ldlibs="$ldlibs -ltinfo" jtc=n fi # if no ncurses, use built-in VT1xx code case "$jtc" in y) sysdefs="$sysdefs -DJTC";; esac # best to use openpty on Linux, so need libutil ldlibs="$ldlibs -lutil" ;; *) # for unknown platforms, we try fairly generic, builtin vt1xx sysdefs="-DBSDPOSIX -DJTC"; optflags="-O" ;; esac case "${JMAKE_RELATIVE-}" in y*|1|t*) # Use relative paths for share and bin, useful for mingw or personal rel="DESTDIR=${DESTDIR-/none/} JOVEHOME= JBINDIR= JSHAREDIR=doc JLIBDIR=" ;; esac exec make ${JMAKE_OPTS-} CC="${CC-$defcc}" LOCALCC="$locc" SYSDEFS="$sysdefs" OPTFLAGS="$optflags" LDLIBS="$ldlibs" LDFLAGS="$ldflags" $rel $extra "$@" jove-4.17.5.5/jove.c000066400000000000000000001365121501102521500140250ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Contains the main loop initializations, and some system dependent type things, e.g. putting terminal in CBREAK mode, etc. */ #include "jove.h" #include "fp.h" #include "jctype.h" #include "chars.h" #include "disp.h" #include "re.h" /* for dosearch() */ #include "reapp.h" /* for find_tag(), UseRE */ #include "sysprocs.h" #include "rec.h" #include "ask.h" #include "extend.h" #include "fmt.h" #include "macros.h" #include "marks.h" #include "mouse.h" #ifndef MAC /* Mac does without! */ # include "paths.h" #endif #include "proc.h" #include "screen.h" #include "term.h" #include "version.h" #include "wind.h" #ifdef IPROCS # include "iproc.h" #endif #ifdef USE_SELECT # include # include "select.h" #endif #ifdef SCO /* ??? what is this for? */ # include # include #endif #include #ifdef MAC # include "mac.h" #else /* !MAC */ # include #endif /* !MAC */ #ifdef MSDOS # include # include # include # define SIGHUP 99 # ifdef OWCDOS # include /* for _heapgrow */ # endif #endif /* MSDOS */ #ifdef WIN32 # undef Fill /* sigh, used as a field name in some windows header! */ # undef CR /* sigh, used as a field name in some windows header! */ # include /* ??? is this needed? */ # undef FIONREAD /* This is defined but ioctl isn't so we cannot use it. */ extern char *getLastErrorString(void); #endif #ifdef STACK_DECL /* provision for setting up appropriate stack */ STACK_DECL #endif /* * This is the maximum length of the basename of files in * ShareDir or LibDir (plus 1 for leading slash), as a check * if the specified paths, even if they fit in FILESIZE, are * too long to be used subsequently. At the moment, in * ShareDir, "teach-jove" at 10 chars is currently the longest * filename, while in LibDir, "portsrv" or "recover" only go * over to 11 chars if ".exe" is appended to them for * MSFILESYSTEM (DOS or Windows), so 14 seems plenty (and is * also a little tribute to the traditional early Unix * filesystem maximum!) */ #define MAXBASENAMELEN (1+14+1) private void UnsetTerm proto((jbool)), DoKeys proto((jbool firsttime)), ShowKeyStrokes proto((void)), jexecpath proto((char *, size_t)); #ifdef NONBLOCKINGREAD private void setblock proto((jbool on)); #endif #ifdef POSIX_SIGS SIGHANDLERTYPE setsighandler(signo, handler) /* simulate BSD's safe signal() */ int signo; SIGHANDLERTYPE handler; { static struct sigaction act; /* static so unspecified fields are 0 */ struct sigaction oact; act.sa_handler = handler; sigemptyset(&act.sa_mask); sigaddset(&act.sa_mask, signo); sigaction(signo, &act, &oact); return oact.sa_handler; } #endif jbool TimeDisplayed = YES; /* is time actually displayed in modeline? */ char JoveFeatures[MAXCOLS]; /* VAR: list of compiled-in features */ #ifdef UNIX /* set things up to update the modeline every UpdFreq seconds */ int UpdFreq = 30; /* VAR: how often to update modeline */ jbool InSlowRead = NO; void SetClockAlarm(unset) jbool unset; /* unset alarm if none needed */ { if (TimeDisplayed && UpdFreq != 0) (void) alarm((unsigned) (UpdFreq - (time((time_t *)NULL) % UpdFreq))); else if (unset) alarm((unsigned)0); } /* AlarmHandler gets all SIGALRMs. It decides, based on InWaitChar, * whether this is an alarm for updating the mode line or for showing * keystrokes. Theoretically, InWaitChar is a state variable that ought * to be reset in complain and other exceptional cases, but waitchar * is called often enough that it turns out to be self-correcting. */ private volatile jbool InWaitChar = NO; /*ARGSUSED*/ private SIGRESTYPE AlarmHandler(junk) int UNUSED(junk); /* passed in on signal; of no interest */ { int save_errno = errno; /* Subtle, but necessary! */ resetsighandler(SIGALRM, AlarmHandler); if (InWaitChar) { if (InSlowRead) { InSlowRead = NO; ShowKeyStrokes(); redisplay(); InSlowRead = YES; InWaitChar = NO; /* might as well allow modeline updates */ SetClockAlarm(NO); } else { alarm((unsigned)1); /* try again later */ } } else { UpdModLine = YES; if (InSlowRead) { /* needed because of stupid BSD restartable I/O */ InSlowRead = NO; redisplay(); InSlowRead = YES; } SetClockAlarm(NO); } errno = save_errno; return SIGRESVALUE; } #endif /* UNIX */ jbool stickymsg; /* the last message should stick around */ char NullStr[] = ""; jmp_buf mainjmp; #ifdef USE_SELECT fd_set global_fd; /* set of file descriptors of interest (for select) */ int global_maxfd; #endif /* paths */ /* VAR: directory path of machine-independent library with joverc, docs, etc */ char ShareDir[FILESIZE] = SHAREDIR; /* VAR: directory/device to store tmp files */ char TmpDir[FILESIZE] = TMPDIR; #ifdef SUBSHELL char Shell[FILESIZE] = DFLTSHELL, /* VAR: shell to use */ # ifdef MSFILESYSTEM ShFlags[sizeof(ShFlags)] = "/c"; /* VAR: flags to shell */ # else ShFlags[sizeof(ShFlags)] = "-c"; /* VAR: flags to shell */ # endif /* MSFILESYSTEM */ #endif /* VAR: directory path of machine-dependent library (for Portsrv and Recover) */ #if defined(SUBSHELL) && (defined(PIPEPROCS) || defined(RECOVER)) # define NEED_LIBDIR 1 char LibDir[FILESIZE] = LIBDIR; #endif /* finish: handle bad-news signals. * It also handles internally generated requests for termination. * For most values of code (signal types) an attempt * is made to save the buffers for recovery by "recover". * For most values of code, this routine stops JOVE * by calling abort, which causes a core dump under UNIX. * * - code -1 is an internally generated request to die with an * attempt to save the buffers. It had better not be the code * for some real signal (it cannot be one under UNIX). * * - code 0 is an internally generated request to die quietly. * It had better not be the code for some real signal * (it cannot be one under UNIX). This is the only code * for which buffers are not saved. * * - SIGHUP is caused by loss of connection. This code and * code 0 are the only ones which don't cause an abort. * Generated by OS and by JOVE itself. */ SIGRESTYPE finish(code) int code; { #ifdef RECOVER int save_errno = errno; /* Subtle, but necessary! */ #endif jbool DelTmps = YES; /* Usually we delete them. */ DisabledRedisplay = YES; #ifndef MAC UnsetTerm(NO); #endif #ifdef PIPEPROCS kbd_kill(); /* kill the keyboard process */ #endif #ifdef RECOVER if (code != 0) { static jbool Crashing = NO; /* we are in the middle of crashing */ if (!Crashing) { Crashing = YES; lsave(); SyncRec(); writef("JOVE CRASH!! (code %d; last errno %d)\n", code, save_errno); if (ModBufs(YES)) { writef("Your buffers have been saved.\n"); writef("Use \"jove -r\" to have a look at them.\n"); DelTmps = NO; /* Don't delete anymore. */ } else { writef("No buffers needed saving: you didn't lose any work.\n"); } } else { writef("\r\nYou may have lost your work!\n"); } } #endif /* RECOVER */ flushscreen(); if (DelTmps) { tmpremove(); #ifdef RECOVER recremove(); #endif /* RECOVER */ } #ifdef UNIX if (code != 0 && code != SIGHUP) abort(); #endif /* UNIX */ EXIT(0); /*NOTREACHED*/ } /* SIGINT is caused by the user hitting the INTR key. * We give him a choice of death or continuation. */ private SIGRESTYPE handle_sigint(code) int code; { int save_errno = errno; /* Subtle, but necessary! */ char c; #ifdef WIN32 c = FatalErrorMessage("Fatal interrupt encountered. Abort?"); #else /* !WIN32 */ # ifdef PIPEPROCS jbool started; # endif resetsighandler(SIGINT, handle_sigint); f_mess("Abort (Type 'n' if you're not sure)? "); Placur(ILI, jmin(CO - 2, calc_pos(mesgbuf, MAXCOLS))); flushscreen(); # ifdef UNIX # ifdef PIPEPROCS started = kbd_stop(); # endif /* * Yuk! This doesn't deal with all cases, we really need a * standard jove input routine that's lower than kbd_getch so * that this can use it. The code that this replaces was even * more ugly. What about nonblocking reads? -- MM. */ # ifdef NONBLOCKINGREAD setblock(YES); /* turn blocking on (in case it was off) */ # endif do { c = 'n'; } while (read(0, (UnivPtr) &c, sizeof(c)) < 0 && RETRY_ERRNO(errno)); # ifdef PIPEPROCS if (started) kbd_strt(); # endif /* PIPEPROCS */ # endif /* UNIX */ # ifdef MSDOS c = getrawinchar(); # endif /* MSDOS */ message(NullStr); #endif /* !WIN32 */ if (c == 'y') { errno = save_errno; finish(code); /* NOTREACHED */ } redisplay(); errno = save_errno; return SIGRESVALUE; } private char smbuf[20], *bp = smbuf; private int nchars = 0; #ifdef NONBLOCKINGREAD private void setblock(on) /* turn blocking on or off */ jbool on; { static int blockf, nonblockf; static jbool first = YES; if (first) { int flags; first = NO; if ((flags = fcntl(0, F_GETFL, 0)) == -1) finish(SIGHUP); # ifdef O_NONBLOCK /* POSIX form */ blockf = flags & ~O_NONBLOCK; /* make sure O_NONBLOCK is off */ nonblockf = flags | O_NONBLOCK; /* make sure O_NONBLOCK is on */ # else /* pre-POSIX form */ blockf = flags & ~O_NDELAY; /* make sure O_NDELAY is off */ nonblockf = flags | O_NDELAY; /* make sure O_NDELAY is on */ # endif } if (fcntl(0, F_SETFL, on ? blockf : nonblockf) == -1) finish(SIGHUP); } #endif /* NONBLOCKINGREAD */ /* To optimize screen refreshing, we try to detect if there is pending input. * If there is, we defer screen updating, hoping that when we eventually * do an update it will be more efficient. To implement this, we use * charp to poll for pending input (from any source but macro body). * "InputPending" records the last value returned by charp, or what * was known by kbd_getch or kbd_ungetch. Note that the kbd_* routines * only consider keyboard input, but charp considers other sources of * input. These are the only routines that should set InputPending * (currently, a fudge to redisplay for the mac also sets it -- * this should be fixed). * * This heuristic confuses the user if a command takes a long time: * the screen may be "frozen" in an inaccurate state until the command * completes. The variable "SlowCmd" is a count of the nesting of slow * commands. If it is positive, display updating is not pre-empted. * The macros PreEmptOutput() and CheapPreEmptOutput() implement the tests. */ int SlowCmd = 0; /* depth of nesting of slow commands */ jbool InputPending = NO; /* is there input waiting to be processed? */ /* Inputp is used to jam a NUL-terminated string into JOVE's input stream. * It is used to feed each line of the joverc file, to fill in the default * make_cmd in compile-it, and to fill in the default i-search string. * To make this work, we prevent i-search and compile-it from using Inputp * when it is already in use. */ char *Inputp = NULL; /* kbd_ungetch must only be used to push back a character that * was just returned by kbd_getch. */ private ZXchar kbdpeek = EOF; void kbd_ungetch(c) ZXchar c; { InputPending = YES; kbdpeek = c; } ZXchar kbd_getch() { register ZXchar c; if (kbdpeek != EOF) { c = kbdpeek; kbdpeek = EOF; InputPending = nchars > 0; return c; } #if NCHARS != UCHAR_ROOF do { #endif while (nchars <= 0) { bp = smbuf; #ifdef MSDOS *bp = getrawinchar(); nchars = 1; #else /* !MSDOS */ # ifdef WIN32 if (UpdModLine || !charp()) { redisplay(); flushscreen(); } nchars = getInputEvents(smbuf, sizeof(smbuf)); # else /* !WIN32 */ # ifdef PTYPROCS /* Get a character from the keyboard, first checking for any input from a process. Handle that first, and then deal with the terminal input. */ { fd_set reads; int nfds, fd; bp = smbuf; for (;;) { while (procs_to_reap) reap_procs(); /* synchronous process reaping */ reads = global_fd; InSlowRead = YES; nfds = select(global_maxfd, &reads, (fd_set *)NULL, (fd_set *)NULL, (struct timeval *)NULL); InSlowRead = NO; if (nfds >= 0) break; if (errno != EINTR) { complain("\rerror in select: %s", strerror(errno)); /* NOTREACHED */ } } if (FD_ISSET(0, &reads)) { do { nchars = read(0, (UnivPtr) smbuf, sizeof(smbuf)); } while (nchars < 0 && errno == EINTR); if (nchars <= 0) finish(SIGHUP); nfds -= 1; } for (fd=1; nfds != 0; fd += 1) { if (FD_ISSET(fd, &reads)) { nfds -= 1; read_pty_proc(fd); if (UpdModLine) redisplay(); } } } # else /* !PTYPROCS */ # ifdef PIPEPROCS if (NumProcs > 0) { /* Handle process input until kbd input arrives */ struct header header; size_t n; InSlowRead = YES; n = f_readn(ProcInput, (char *) &header, sizeof(header)); InSlowRead = NO; if (n != sizeof(header)) { raw_complain("\r\nError reading kbd process, expected %d, got %d bytes", sizeof header, n); finish(SIGHUP); /* NOTREACHED */ } if (header.pid == kbd_pid) { /* data is from the keyboard process */ nchars = f_readn(ProcInput, smbuf, (size_t)header.nbytes); if (nchars != header.nbytes) { raw_complain("\r\nError reading kbd process, expected %d, got %d bytes.", header.nbytes, nchars); finish(SIGHUP); /* NOTREACHED */ } } else { /* data is from an interactive process */ read_pipe_proc(header.pid, header.nbytes); if (NumProcs == 0) (void) kbd_stop(); if (UpdModLine) redisplay(); } } else /*...*/ # endif /* PIPEPROCS */ /*...*/ { do { # ifdef UNIX InSlowRead = YES; # endif nchars = read(0, (UnivPtr) smbuf, sizeof smbuf); # ifdef UNIX InSlowRead = NO; # endif } while (nchars < 0 && RETRY_ERRNO(errno)); if (nchars <= 0) finish(SIGHUP); } # endif /* !PTYPROCS */ # endif /* !WIN32 */ #endif /* !MSDOS */ } c = ZXRC(*bp++); #if !defined(PCNONASCII) && !defined(MAC) /* if not done elsewhere */ if ((c & METABIT) && MetaKey) { *--bp = c & ~METABIT; nchars += 1; c = ESC; } #endif /* !defined(PCNONASCII) && !defined(MAC) */ InputPending = --nchars > 0; #if NCHARS != UCHAR_ROOF } while (c >= NCHARS); /* discard c if it is a bad char */ #endif return c; } /* Returns YES if a character waiting (excluding macro body) */ jbool charp() { if (InJoverc != 0 || kbdpeek != EOF || nchars > 0 || Inputp != NULL) return InputPending = YES; #ifdef FIONREAD { /* * Some manual pages, notably SunOS4.1.3 say 'c' should be * 'long', but that's a lie -- it's an 'int' according to all * kernels I've seen (including SunOS4.1.3) and most other * manual pages. At any rate, 'int' works correctly on 32- and * 64-bit architectures, whereas long breaks on the 64 * bitters. -- MM. */ int c; if (ioctl(0, FIONREAD, (UnivPtr) &c) == -1) c = 0; return InputPending = c > 0; } #else /* !FIONREAD */ # ifdef NONBLOCKINGREAD setblock(NO); /* turn blocking off */ nchars = read(0, (UnivPtr) smbuf, sizeof smbuf); /* Is anything there? */ setblock(YES); /* turn blocking on */ bp = smbuf; /* make sure bp points to it */ return InputPending = nchars > 0; /* just say we found something */ # else /* !NONBLOCKINGREAD */ # ifdef USE_SELECT { struct timeval timer; fd_set readfds; timer.tv_sec = 0; timer.tv_usec = 0; FD_ZERO(&readfds); FD_SET(0, &readfds); return InputPending = select(1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer) > 0; } # else /* !USE_SELECT */ # ifdef MSDOS return InputPending = rawkey_ready(); # else /* !MSDOS */ # ifdef MAC return InputPending = rawchkc(); # else # ifdef WIN32 return InputPending = inputEventWaiting(0); # else return InputPending = NO; /* who knows? */ # endif /* !WIN32 */ # endif /* !MAC */ # endif /* !MSDOS */ # endif /* !USE_SELECT */ # endif /* !NONBLOCKINGREAD */ #endif /* !FIONREAD */ } /* * Tries to pause for delay/10 seconds OR until a character is typed at the * keyboard. This works well on systems with select() and not so well on the * rest. */ #ifdef MAC # include /* defines Ticks */ #endif void SitFor(delay) int delay; { #ifdef MAC long start, end; Keyonly = YES; redisplay(); start = Ticks; end = start + delay * 6; do {} while (!charp() && Ticks < end); #else /* !MAC */ # ifndef MSDOS if (!charp()) { # ifdef USE_SELECT struct timeval timer; fd_set readfds; /* So messages that aren't error messages don't * hang around forever. * Gross that I had to snarf this from getch() */ if (!UpdMesg && !Asking && mesgbuf[0] && !stickymsg) message(NullStr); redisplay(); timer.tv_sec = (delay / 10); timer.tv_usec = (delay % 10) * 100000; FD_ZERO(&readfds); FD_SET(0, &readfds); (void) select(1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); # else /* ! USE_SELECT */ # ifdef WIN32 redisplay(); inputEventWaiting(delay*100); # else /* ! WIN32 */ /* Pause by spitting NULs at the terminal. Ugh! */ static const int cps[] = { 0, 5, 7, 11, 13, 15, 20, 30, 60, 120, 180, 240, 480, 960, 1920, 1920, }; register int nchars, check_cnt; nchars = (delay * cps[ospeed]) / 10; check_cnt = ScrBufSize; redisplay(); if (!NP) { while ((--nchars > 0) && !InputPending) { scr_putchar(PC); if (--check_cnt == 0) { check_cnt = ScrBufSize; (void) charp(); } } } # endif /* !WIN32 */ # endif /* !USE_SELECT */ } # else /* MSDOS */ /* All time representations must wrap eventually. * Since all delays are much less than a minute, we represent * time as hundredths of a second past the minute we start. * NOTE: this is a busy wait. I know of no alternative. */ int start, now, end; struct dostime_t tc; redisplay(); _dos_gettime(&tc); start = tc.second * 100 + tc.hsecond; end = start + delay * 10; for (;;) { if (charp()) break; _dos_gettime(&tc); now = tc.second * 100 + tc.hsecond; if (now < start) now += 60 * 100; /* must be in next minute */ if (now >= end) break; } # endif /* MSDOS */ #endif /* !MAC */ } #define WAITCHAR_CURSOR_DOWN 1 /* during slow keying, cursor is after displayed prefix */ private char key_strokes[100], *keys_p = key_strokes; private jbool in_ask_ks; private volatile jbool slow_keying = NO; /* for waitchar() */ void cmd_sync() { if (this_cmd != ARG_CMD) { clr_arg_value(); last_cmd = this_cmd; slow_keying = NO; in_ask_ks = NO; keys_p = key_strokes; } } ZXchar ask_ks() { in_ask_ks = YES; keys_p = key_strokes; return waitchar(); } void add_stroke(c) ZXchar c; { if (keys_p < &key_strokes[sizeof (key_strokes) - 1]) *keys_p++ = c; } void pp_key_strokes(buffer, size) char *buffer; size_t size; { char *buf_end = buffer + size - 1, *kp = key_strokes; *buffer = '\0'; while (kp != keys_p) { swritef(buffer, (size_t) (buf_end-buffer), "%p ", *kp++); buffer += strlen(buffer); } } private void ShowKeyStrokes() { char buffer[100]; slow_keying = YES; pp_key_strokes(buffer, sizeof (buffer)); f_mess(in_ask_ks? ": %f %s" : "%s", buffer); #ifdef WAITCHAR_CURSOR_DOWN Asking = YES; AskingWidth = strlen(mesgbuf); #endif } #define N_SEC 1 /* will be precisely 1 second on 4.2 */ ZXchar waitchar() { ZXchar c; #ifdef WAITCHAR_CURSOR_DOWN jbool oldAsking; int oldAskingWidth; #endif /* short circuit, if we can */ if (InJoverc || (!Interactive && in_macro()) || InputPending) return getch(); #ifdef WAITCHAR_CURSOR_DOWN oldAsking = Asking; oldAskingWidth = AskingWidth; #endif #ifdef MAC Keyonly = YES; #endif if (!slow_keying) { /* not yet slow_keying */ #ifdef UNIX /* set up alarm */ InWaitChar = YES; (void) alarm((unsigned) N_SEC); #else /* !UNIX */ # ifdef WIN32 if (!charp()) { if ((slow_keying = !inputEventWaiting(N_SEC*1000))) { ShowKeyStrokes(); } } # else /* !WIN32 */ /* NOTE: busy wait (until char typed or timeout)! */ time_t sw = N_SEC + time((time_t *)NULL); while (!slow_keying && !charp()) { if (time((time_t *)NULL) > sw) { /* transition to slow_keying */ # ifdef MAC menus_off(); # endif ShowKeyStrokes(); } } # endif /* !WIN32 */ #endif /* !UNIX */ #ifdef WAITCHAR_CURSOR_DOWN } else { /* Already slow_keying: presume bottom line has old keystrokes. * Tell refresh(?) to place cursor at end of them. */ Asking = YES; AskingWidth = strlen(mesgbuf); #endif } c = getch(); if (slow_keying) { ShowKeyStrokes(); #ifdef UNIX } else { /* not yet slow_keying: tear down alarm */ InWaitChar = NO; SetClockAlarm(YES); #endif } #ifdef WAITCHAR_CURSOR_DOWN Asking = oldAsking; AskingWidth = oldAskingWidth; #endif return c; } private void SetTerm() { #ifdef IBMPCDOS pcSetTerm(); #endif ttysetattr(YES); #ifdef TERMCAP putpad(TI, 1); /* Cursor addressing start */ putpad(VS, 1); /* Visual start */ putpad(KS, 1); /* Keypad mode start */ # ifdef MOUSE MouseOn(); # endif #endif #ifdef UNIX (void) chkmail(YES); /* force it to check so we can be accurate */ #endif } private void UnsetTerm(WarnUnwritten) jbool WarnUnwritten; { #ifdef TERMCAP # ifdef ID_CHAR INSmode(NO); # endif /* ID_CHAR */ # ifdef MOUSE MouseOff(); # endif putpad(KE, 1); putpad(VE, 1); Placur(ILI, 0); putpad(CE, 1); putpad(TE, 1); #else /* !TERMCAP */ Placur(ILI, 0); clr_eoln(); #endif /* !TERMCAP */ flushscreen(); #ifdef MSDOS pcUnsetTerm(); #endif ttysetattr(NO); if (WarnUnwritten && ModBufs(NO)) raw_complain("[There are modified buffers]"); } #ifdef JOB_CONTROL void PauseJove() { UnsetTerm(YES); (void) kill(0, SIGTSTP); SetTerm(); # ifdef WINRESIZE /* Some systems (eg System V Release 4) don't give us SIGWINCHes * that happen while we are away. */ ResizePending = YES; # endif ClAndRedraw(); } #endif /* JOB_CONTROL */ #ifdef SUBSHELL # ifndef MSDOS void jcloseall() { tmpclose(); # ifdef RECOVER recclose(); # endif # ifdef IPROCS closeiprocs(); # endif } # endif /* !MSDOS */ void Push() { # ifdef MSDOS_PROCS # ifdef MSDOS UnsetTerm(YES); /* Zortech's prototype for the third parameter to spawnl is missing "const" */ if (spawnl(0, Shell, (char *)jbasename(Shell), (char *)NULL) == -1) s_mess("[Spawn failed %d]", errno); SetTerm(); # ifdef WINRESIZE /* Some systems (eg System V Release 4) don't give us SIGWINCHes * that happen while we are away. */ ResizePending = YES; # endif ClAndRedraw(); getCWD(); # else /* !MSDOS */ # ifdef WIN32 STARTUPINFO startinfo = { sizeof(STARTUPINFO) }; PROCESS_INFORMATION procinfo; CreateProcess(Shell, NULL, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &startinfo, &procinfo); # endif /* WIN32 */ # endif /* !MSDOS */ # else /* !MSDOS_PROCS */ /* UNIX, or something like it */ SIGHANDLERTYPE old_int = setsighandler(SIGINT, SIG_IGN); int forkerr = 0; # ifdef PIPEPROCS jbool started = kbd_stop(); # endif UnsetTerm(YES); switch (ChildPid = fork()) { case -1: /* parent, fork failed */ forkerr = errno; break; default: /* parent, fork worked */ dowait((wait_status_t *) NULL); break; case 0: /* child */ /* (void) setsighandler(SIGTERM, SIG_DFL); */ (void) setsighandler(SIGINT, SIG_DFL); jcloseall(); /* note that curbuf->bfname may be NULL */ execl(Shell, jbasename(Shell), "-is", pr_name(curbuf->b_fname, NO), (char *)NULL); raw_complain("[Execl failed: %s]", strerror(errno)); _exit(1); /*NOTREACHED*/ } SetTerm(); # ifdef WINRESIZE /* Some systems (eg System V Release 4) don't give us SIGWINCHes * that happen while we are away. */ ResizePending = YES; # endif ClAndRedraw(); (void) setsighandler(SIGINT, old_int); SetClockAlarm(NO); # ifdef PIPEPROCS if (started) kbd_strt(); # endif if (forkerr != 0) { complain("[Fork failed: %s]", strerror(errno)); /* NOTREACHED */ } # endif /* !MSDOS_PROCS */ } #endif /* SUBSHELL */ /* adjust the tty to reflect possible change to JOVE variables */ void tty_adjust() { ttysetattr(YES); #ifdef MOUSE MouseOn(); /* XtermMouse might have changed */ #endif } jbool Interactive = NO; /* True when we invoke with the command handler? */ ZXchar peekchar = EOF, /* holds pushed-back getch output */ LastKeyStruck; /* used by SelfInsert and friends */ jbool MetaKey = NO; /* VAR: this terminal has a meta key */ void Ungetc(c) ZXchar c; { peekchar = c; } /* * input from macro always needs to be preceded by a check for * a character that may have been pushed back after a number * was gathered into argcount. */ ZXchar peek_or_mac_getch() { ZXchar c; if ((c = peekchar) != EOF) { /* got input from pushback */ peekchar = EOF; LastKeyStruck = c; } else if (!Interactive && (c = mac_getc()) != EOF) { /* might be in an execute-macro! */ add_stroke(LastKeyStruck = c); } return c; } /* * In joverc, or do_find, we need to run all macros to completion before * processing the next line, or any other input, which means reading and * dispatching mac_getc (while dealing with peekchar for numeric args) * * ??? This code (which was in do_find) is a fudge, and should be replaced * by a more elegant solution. */ void dispatch_macros() { ZXchar c; int saved_tcmd = this_cmd; int saved_lcmd = last_cmd; int saved_as, saved_ac; save_arg(saved_as, saved_ac); last_cmd = this_cmd = OTHER_CMD; for (;;) { cmd_sync(); if ((c = peek_or_mac_getch()) == EOF) break; dispatch(c); } last_cmd = saved_lcmd; this_cmd = saved_tcmd; restore_arg(saved_as, saved_ac); } ZXchar getch() { register ZXchar c; if (Inputp != NULL) { if ((c = ZXC(*Inputp++)) != '\0') return LastKeyStruck = c; /* done with all faux input */ Inputp = NULL; } if (InJoverc && !in_macro()) { /* something is wrong if Inputp ran out (and * nothing from a macro) while reading a .joverc file. */ complain("[command line too short]"); /* NOTREACHED */ } #ifdef RECOVER if (ModCount >= SyncFreq) { ModCount = 0; SyncRec(); } #endif /* RECOVER */ if ((c = peek_or_mac_getch()) == EOF) { if (!InJoverc) { /* So messages that aren't error messages don't * hang around forever. * Note: this code is duplicated in SitFor()! */ if (!UpdMesg && !Asking && mesgbuf[0] != '\0' && !stickymsg) message(NullStr); redisplay(); c = kbd_getch(); if (!Interactive && InMacDefine) mac_putc(c); add_stroke(LastKeyStruck = c); } } return c; } void TeachJove() { char tnamebuf[FILESIZE]; PathCat(tnamebuf, sizeof(tnamebuf), HomeDir, TEACHJOVE); SetABuf(curbuf); SetBuf(do_find(curwind, tnamebuf, YES, NO)); if (curbuf->b_first == curbuf->b_last) { char teachref[FILESIZE]; PathCat(teachref, sizeof(teachref), ShareDir, TEACHJOVE); read_file(teachref, YES); } } void ShowVersion() { s_mess("Jonathan's Own Version of Emacs (%s)", jversion); } private void UNIX_cmdline(argc, argv) int argc; char *argv[]; { long lineno = 0; int nwinds = 1; char *pattern = NULL; while (argc > 1) { switch (argv[1][0]) { case '+': if ('0' <= argv[1][1] && argv[1][1] <= '9') { (void) chr_to_long(&argv[1][1], 10, NO, &lineno); break; } else switch (argv[1][1]) { case '\0': /* goto end of file just like some people's favourite editor */ lineno = -1; break; case '/': /* search for pattern */ /* check if syntax is +/pattern or +/ pattern */ if (argv[1][2] != 0) { pattern = &argv[1][2]; } else { argv += 1; argc -= 1; if (argv[1] != 0) pattern = &argv[1][0]; } break; default: error("Invalid switch %s",argv[1]); /* NOTREACHED */ } break; case '-': switch (argv[1][1]) { case 'd': /* Ignore current directory path */ case 'D': /* Ignore debug file name */ case 'l': /* Ignore libdir path */ case 's': /* Ignore sharedir path */ argv += 1; argc -= 1; break; case 'J': /* Ignore jove.rc in SHAREDIR */ case 'j': /* Ignore ~/.joverc */ break; case 'p': /* parse errors in file */ argv += 1; argc -= 1; if (argv[1] != NULL) { SetBuf(do_find(curwind, argv[1], YES, YES)); ErrParse(); nwinds = 0; } break; case 'T': /* teach-jove */ TeachJove(); break; case 't': /* find tag */ /* check if syntax is -tTag or -t Tag */ if (argv[1][2] != '\0') { find_tag(&(argv[1][2]), YES); } else { argv += 1; argc -= 1; if (argv[1] != NULL) find_tag(argv[1], YES); } break; case 'w': /* multiple windows */ if (argv[1][2] == '\0') nwinds += 1; else { int n; (void) chr_to_int(&argv[1][2], 10, NO, &n); nwinds += -1 + n; } (void) div_wind(curwind, nwinds - 1); break; case '-': /* Ignore -- which visudo provides */ break; default: error("Invalid switch %s",argv[1]); /* NOTREACHED */ } break; default: /* Process a file argument. * We arrange that the last file that has a window * becomes the current buffer and that the last file * without a window (if any) becomes the alternate buffer. */ minib_add(argv[1], nwinds > 0); if (nwinds > 0 || lineno != 0 || pattern != NULL) { Buffer *prevbuf = curbuf, *b = do_find(curwind, argv[1], YES, YES); SetABuf(prevbuf); SetBuf(b); if (lineno > 0) SetLine(next_line(curbuf->b_first, lineno - 1)); else if (lineno == -1) SetLine(curbuf->b_last); if (pattern != NULL) { Bufpos *bufp; if ((bufp = dosearch(pattern, FORWARD, UseRE)) != NULL || (bufp = dosearch(pattern, BACKWARD, UseRE)) != NULL) { SetDot(bufp); } else { complain("Couldn't match pattern in file."); /* NOTREACHED */ } } if (nwinds > 0) { nwinds -= 1; if (nwinds > 0) NextWindow(); } else { /* We only borrowed the window: * let's restore the rightful tennant. * As a consolation, make this buffer the alternate. */ SetABuf(b); SetBuf(prevbuf); tiewind(curwind, prevbuf); } } else { /* There is no need to actually read the file. * find the file, but don't force it, or select the buffer. * As a consolation, make this buffer the alternate. */ SetABuf(do_find((Window *)NULL, argv[1], NO, YES)); } lineno = 0; pattern = NULL; break; } argv += 1; argc -= 1; } } #ifdef STDARGS void error(const char *fmt, ...) #else /*VARARGS1*/ void error(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; if (fmt) { va_init(ap, fmt); format(mesgbuf, sizeof mesgbuf, fmt, ap); va_end(ap); UpdMesg = YES; } rbell(); longjmp(mainjmp, JMP_ERROR); /* NOTREACHED */ } #ifdef STDARGS void complain(const char *fmt, ...) #else /*VARARGS1*/ void complain(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; if (fmt) { va_init(ap, fmt); format(mesgbuf, sizeof mesgbuf, fmt, ap); va_end(ap); UpdMesg = YES; } rbell(); longjmp(mainjmp, JMP_COMPLAIN); /* NOTREACHED */ } /* format and display a message without using the normal display mechanisms */ #ifdef STDARGS void raw_complain(const char *fmt, ...) #else /*VARARGS1*/ void raw_complain(fmt, va_alist) const char *fmt; va_dcl #endif { char buf[MESG_SIZE]; va_list ap; const char *bp; size_t rem; JSSIZE_T r; va_init(ap, fmt); format(buf, sizeof(buf) - 2, fmt, ap); va_end(ap); strcat(buf, "\r\n"); /* \r *may* be redundant */ for (bp = buf, rem = strlen(buf) ; rem > 0 && (r = write(2, bp, rem)) != (JSSIZE_T)rem ; bp += r, rem -=r) { if (r < 0 || errno != EINTR) break; /* give up */ } } #ifdef STDARGS void confirm(const char *fmt, ...) #else /*VARARGS1*/ void confirm(fmt, va_alist) const char *fmt; va_dcl #endif { va_list ap; va_init(ap, fmt); format(mesgbuf, sizeof mesgbuf, fmt, ap); va_end(ap); if (!yes_or_no_p("%s", mesgbuf)) { longjmp(mainjmp, JMP_COMPLAIN); /* NOTREACHED */ } } /* Recursive edit. * Guarantee: current buffer will still be current and * it will be in the current window. If not, complain! */ int RecDepth = 0; void Recur() { Buffer *b = curbuf; Mark *m; m = MakeMark(curline, curchar); RecDepth += 1; UpdModLine = YES; DoKeys(NO); /* NO means not first time */ UpdModLine = YES; RecDepth -= 1; if (!valid_bp(b)) { complain("Buffer gone!"); /* NOTREACHED */ } tiewind(curwind, b); SetBuf(b); if (!is_an_arg()) ToMark(m); DelMark(m); } jbool SaveOnExit = NO; /* VAR: offer to save buffers on exit */ private int iniargc; /* main sets these for DoKeys() */ private char **iniargv; private void DoKeys(firsttime) jbool firsttime; { jmp_buf savejmp; push_env(savejmp); switch (setjmp(mainjmp)) { case 0: if (firsttime) UNIX_cmdline(iniargc, iniargv); break; case JMP_QUIT: if (RecDepth == 0) { if (ModMacs()) { rbell(); if (!yes_or_no_p("Some MACROS haven't been saved; leave anyway? ")) break; } /* Maybe should offer to save macros too ? */ if (ModBufs(NO)) { rbell(); if (SaveOnExit) put_bufs(YES); else if (!yes_or_no_p("Some buffers haven't been saved; leave anyway? ")) break; } #ifdef IPROCS if (!KillProcs()) break; /* user chickened out */ #endif } pop_env(savejmp); return; case JMP_ERROR: getDOT(); /* God knows what state linebuf was in */ /*FALLTHROUGH*/ case JMP_COMPLAIN: { gc_openfiles(); /* close any files we left open */ stickymsg = YES; unwind_macro_stack(); Asking = NO; curwind->w_bufp = curbuf; DisabledRedisplay = NO; SlowCmd = 0; redisplay(); break; } } this_cmd = last_cmd = OTHER_CMD; for (;;) { #ifdef MAC setjmp(auxjmp); #endif cmd_sync(); #ifdef MAC HiliteMenu(0); EventCmd = NO; menus_on(); #endif dispatch(getch()); } } private char ** scanvec(args, str) register char **args, *str; { while (*args) { if (strcmp(*args, str) == 0) return args; args += 1; } return NULL; } #ifdef WINRESIZE /*ARGSUSED*/ SIGRESTYPE win_reshape(junk) int UNUSED(junk); /* passed in when invoked by a signal; of no interest */ { int save_errno = errno; /* Subtle, but necessary! */ ResizePending = YES; #ifdef UNIX resetsighandler(SIGWINCH, win_reshape); if (InSlowRead) { /* needed because of stupid BSD restartable I/O */ InSlowRead = NO; redisplay(); InSlowRead = YES; } #else redisplay(); #endif errno = save_errno; return SIGRESVALUE; } #endif /* WINRESIZE */ private jbool carefulcpy(to, from, maxsize, mess, raw) char *to,*from; size_t maxsize; char *mess; jbool raw; { if (from != NULL) { const char *ugh; if (strlen(from) >= maxsize) ugh = "too long"; else if (*from == '\0') ugh = "empty"; else { strcpy(to, from); return YES; } if (raw) { raw_complain("\r\n%s %s", mess, ugh); } else { swritef(mesgbuf, sizeof mesgbuf, "%s %s", mess, ugh); message(mesgbuf); } } return NO; } #define envcpy(buf, varname) \ carefulcpy(buf, getenv(varname), sizeof(buf), varname, NO) private void dojovercs(dosys, dousr) jbool dosys; jbool dousr; { char Joverc[FILESIZE]; if (dosys) { PathCat(Joverc, sizeof(Joverc), ShareDir, "jove.rc"); (void) joverc(Joverc); /* system wide jove.rc */ } if (dousr) { #ifdef MSFILESYSTEM /* We don't want to run the same rc file twice */ if (!dosys || strcmp(HomeDir, ShareDir) != 0) { PathCat(Joverc, sizeof(Joverc), HomeDir, "jove.rc"); (void) joverc(Joverc); /* jove.rc in home directory */ } #else PathCat(Joverc, sizeof(Joverc), HomeDir, ".joverc"); (void) joverc(Joverc); /* .joverc in home directory */ #endif } } private void setfeatures() { JoveFeatures[0] = '\0'; #ifdef UNIX jamstrcat(JoveFeatures, ":unix", sizeof(JoveFeatures)); #endif #ifdef MSDOS jamstrcat(JoveFeatures, ":msdos", sizeof(JoveFeatures)); #endif #ifdef WIN32 jamstrcat(JoveFeatures, ":win32", sizeof(JoveFeatures)); #endif #ifdef MAC jamstrcat(JoveFeatures, ":mac", sizeof(JoveFeatures)); #endif #ifdef IBMPCDOS jamstrcat(JoveFeatures, ":ibmpc", sizeof(JoveFeatures)); #endif #ifdef ABBREV jamstrcat(JoveFeatures, ":abbr", sizeof(JoveFeatures)); #endif #ifdef BACKUPFILES jamstrcat(JoveFeatures, ":bak", sizeof(JoveFeatures)); #endif #ifdef BIFF jamstrcat(JoveFeatures, ":biff", sizeof(JoveFeatures)); #endif #ifdef CMT_FMT jamstrcat(JoveFeatures, ":cmtfmt", sizeof(JoveFeatures)); #endif #ifdef F_COMPLETION jamstrcat(JoveFeatures, ":fcomp", sizeof(JoveFeatures)); #endif #ifdef IPROCS jamstrcat(JoveFeatures, ":iproc", sizeof(JoveFeatures)); #endif #ifdef PIPEPROCS jamstrcat(JoveFeatures, ":pipe", sizeof(JoveFeatures)); #endif #ifdef PTYPROCS jamstrcat(JoveFeatures, ":pty", sizeof(JoveFeatures)); #endif #ifdef LISP jamstrcat(JoveFeatures, ":lisp", sizeof(JoveFeatures)); #endif #ifdef SUBSHELL jamstrcat(JoveFeatures, ":proc", sizeof(JoveFeatures)); #endif #ifdef SPELL jamstrcat(JoveFeatures, ":spell", sizeof(JoveFeatures)); #endif #ifdef RECOVER jamstrcat(JoveFeatures, ":rec", sizeof(JoveFeatures)); #endif #ifdef JOB_CONTROL jamstrcat(JoveFeatures, ":job", sizeof(JoveFeatures)); #endif #ifdef JSMALL jamstrcat(JoveFeatures, ":jsmall", sizeof(JoveFeatures)); #endif #ifdef ID_CHAR jamstrcat(JoveFeatures, ":idchar", sizeof(JoveFeatures)); #endif #ifdef HIGHLIGHTING jamstrcat(JoveFeatures, ":hl", sizeof(JoveFeatures)); #endif #ifdef JTC jamstrcat(JoveFeatures, ":jtc", sizeof(JoveFeatures)); #endif #ifdef TERMCAP jamstrcat(JoveFeatures, ":tcap", sizeof(JoveFeatures)); #endif #ifdef TERMINFO jamstrcat(JoveFeatures, ":tinfo", sizeof(JoveFeatures)); #endif #ifdef USE_CTYPE jamstrcat(JoveFeatures, ":ctype", sizeof(JoveFeatures)); #endif #ifdef ISO_8859_1 jamstrcat(JoveFeatures, ":iso88591", sizeof(JoveFeatures)); #endif jamstrcat(JoveFeatures, ":", sizeof(JoveFeatures)); jdbg("setfeatures \"%s\n", JoveFeatures); } /* * returns NULL if the input path is absolute, else returns a * pointer to the start of the relative path, which will be * the same as path for POSIX machines, or will strip off a * leading drive: for MSFILESYSTEM */ private const char * relpathstart(path) const char *path; { const char *cp = path, c = *cp; jdbg("relpathstart \"%s\"\n", path); if (c == '/' #ifdef MSFILESYSTEM || c == '\\' || (((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) && *++cp == ':' && (*++cp == '/' || *cp == '\\')) #endif ) { jdbg("absolute \"%c\" \"%c\"\n", c, *cp); return NULL; /* absolute */ } #ifdef MSFILESYSTEM if (cp > path && path[1] == ':') { /* * should we complain, having a drive spec on a * relative path for ShareDir, LibDir is * confusing? For now, just skip it */ jdbg("relative-drive \"%s\"\n", path+2); return path+2; } #endif jdbg("relative \"%s\"\n", path); return path; } /* * if val is non-NULL, it overrides current value of var, * else uses var. If relative, the path to the Jove binary is * prepended to val, canonicalized with PathParse and stored * in var. Typically, var is either ShareDir or LibDir. * varname holds the name to indicate which one, for error messages. */ private void fixrelpath(val, var, varname) const char *val; char *var; /* MUST BE FILESIZE */ const char *varname; { const char *rel; char tempbuf[FILESIZE]; if (val == NULL) val = var; rel = relpathstart(val); /* NULL if not relative */ if (rel) { jexecpath(tempbuf, sizeof(tempbuf)); jamstrcat(tempbuf, rel, sizeof(tempbuf)); } else { jamstrsub(tempbuf, val, sizeof(tempbuf)); } PathParse(tempbuf, var); /* * check that there will be enough space for the * basename of the files in LibDir or ShareDir */ if (strlen(var) > FILESIZE-MAXBASENAMELEN) { complain("%s \"%s\" too long", varname, var); /* NOTREACHED */ } } int main(argc, argv) int argc; char *argv[]; { char **argp; #ifdef AUTO_BUFS /* allocate these usually static buffers on the stack: * preserves addressability on some systems. */ char s_iobuff[LBSIZE], s_genbuf[LBSIZE], s_linebuf[LBSIZE]; iobuff = s_iobuff; genbuf = s_genbuf; linebuf = s_linebuf; #endif #ifdef MAC MacInit(); /* initializes all */ argc = getArgs(&argv); #endif #ifdef OWCDOS /* Watcom C under DOS won't grow the near heap after any far * allocation, so we must bump it up to the full 64K now. */ _heapgrow(); #endif iniargc = argc; iniargv = argv; if ((argp = scanvec(argv, "-D")) != NULL) { jdpath = argp[1]; jdbg("jove debug started %s\n", get_time((time_t *)NULL, (char *)NULL, 0, -1)); } jdbg("MAXCOLS=%d\n", MAXCOLS); jdbg("NBUF=%d\n", NBUF); jdbg("JBUFSIZ=%d\n", JBUFSIZ); jdbg("NCHARS=%d\n", NCHARS); if (setjmp(mainjmp)) { ttysetattr(NO); writef("\nAck! I can't deal with error \"%s\" now.\n", mesgbuf); flushscreen(); return 1; } #if defined(USE_CTYPE) && !defined(NO_SETLOCALE) /* make ctype reflect "native environment" */ locale_adjust(); #endif #ifndef MAC /* no environment in MacOS */ if (getenv("METAKEY")) MetaKey = YES; if ((argp = scanvec(argv, "-d")) != NULL && chkCWD(argp[1])) setCWD(argp[1]); else getCWD(); /* After we setup curbuf in case we have to getwd() */ #ifdef MAC HomeDir = gethome(); #else /* !MAC */ HomeDir = getenv("HOME"); if (HomeDir == NULL) { # ifdef MSDOS HomeDir = copystr(pwd()); /* guess at current (initial) directory */ # else # ifdef WIN32 /* Following are set up automatically by NT on logon. */ char *homedrive = getenv("HOMEDRIVE"); char *homepath = getenv("HOMEPATH"); if (homedrive != NULL && homepath != NULL) { char *p = emalloc(strlen(homedrive) + strlen(homepath) + 1); strcpy(p, homedrive); strcat(p, homepath); HomeDir = p; } else { HomeDir = copystr(pwd()); } # else /* !WIN32 */ HomeDir = "/"; # endif /* !WIN32 */ # endif /* !MSDOS */ } #endif /* !MAC */ HomeLen = strlen(HomeDir); /* Handle overrides for ShareDir and LibDir. * We take care to use the last specification. * LibDir is only accepted via -l, -sl, -ls, or * JOVELIB if NEED_LIBDIR is defined. PWD and HomeDir * must be setup before fixrelpath is called. */ { char *so = getenv("JOVESHARE"); # ifdef NEED_LIBDIR char *lo = getenv("JOVELIB"); # endif for (argp = argv; argp[0] != NULL && argp[1] != NULL; argp++) { if (strcmp(*argp, "-s") == 0) so = *++argp; # ifdef NEED_LIBDIR else if (strcmp(*argp, "-l") == 0) lo = *++argp; else if (strcmp(*argp, "-ls") == 0 || strcmp(*argp, "-sl") == 0) lo = so = *++argp; # endif } fixrelpath(so, ShareDir, "ShareDir"); # ifdef NEED_LIBDIR fixrelpath(lo, LibDir, "LibDir"); # endif /* NEED_LIBDIR */ # ifdef PIPEPROCS PathCat(Portsrv, sizeof(Portsrv), LibDir, "portsrv"); # endif } /* import the temporary file path from the environment * and fix the string, so that we can append a slash * safely */ # ifdef MSFILESYSTEM envcpy(TmpDir, "TEMP"); # else envcpy(TmpDir, "TMPDIR"); # endif { char *cp = &TmpDir[strlen(TmpDir)]; do {} while (cp != TmpDir && (*--cp == '/' # ifdef MSFILESYSTEM || *cp == '\\' # endif )); cp[1] = '\0'; } # ifdef SUBSHELL # ifdef MSFILESYSTEM /* ??? Is this the right test? */ envcpy(Shell, "COMSPEC"); /* SHELL, if present in DOS environment, will take precedence over COMSPEC */ # endif /* MSFILESYSTEM */ envcpy(Shell, "SHELL"); # ifdef RECOVER if (scanvec(argv, "-r") != NULL) { char Recover[FILESIZE]; /* path to recover program (in LibDir) */ PathCat(Recover, sizeof(Recover), LibDir, "recover"); # ifdef MSFILESYSTEM jamstrcat(Recover, ".exe", sizeof(Recover)); if (spawnl(P_WAIT, Recover, "recover", "-d", TmpDir, (char *)NULL) == -1) # else /* !MSFILESYSTEM */ if (execl(Recover, "recover", "-d", TmpDir, (char *) NULL) == -1) # endif /* !MSFILESYSTEM */ { writef("%s: execl failed! %s\n", Recover, strerror(errno)); EXIT(-1); } EXIT(0); /* only Win32, but no harm otherwise, avoids another ifdef */ /* NOTREACHED */ } # endif /* RECOVER */ # endif /* SUBSHELL */ #endif /* ! MAC */ getTERM(); /* Get terminal. */ ttysetattr(YES); ttsize(); #ifdef UNIX # ifdef WINRESIZE (void) setsighandler(SIGWINCH, win_reshape); # endif #endif #ifdef MAC InitEvents(); #endif d_cache_init(); /* initialize the disk buffer cache */ make_scr(); flushscreen(); /* kludge: prevent interleaving output with diagnostic */ mac_init(); /* Initialize Macros */ winit(); /* Initialize Window */ #ifdef PTYPROCS # ifdef SIGCHLD (void) setsighandler(SIGCHLD, sigchld_handler); # endif #endif #ifdef USE_SELECT FD_ZERO(&global_fd); FD_SET(0, &global_fd); global_maxfd = 1; #endif buf_init(); InitKeymaps(); settout(); /* not until we know baudrate */ SetTerm(); setfeatures(); #ifdef UNIX envcpy(Mailbox, "MAIL"); #endif dojovercs(scanvec(argv, "-J") == NULL, scanvec(argv, "-j") == NULL); ShowVersion(); /* but the 'carefulcpy's which follow might overwrite it */ #ifdef SIGINT /* * Jove binds INTR to a key, typically ^], which can * sometimes get hit accidentally, but it prompts in the handler. */ (void) setsighandler(SIGINT, handle_sigint); #endif #ifdef UNIX /* * always cleanup on HUP (terminal disconnected), or * TERM (typically, system going down) */ (void) setsighandler(SIGHUP, finish); (void) setsighandler(SIGTERM, finish); # ifndef DEBUGCRASH /* * DEBUGCRASH means we do not set handlers for SIGBUS, * SIGSEGV, and SIGPIPE, so this can drop into a debugger or * leave a core file to assist debugging. */ # ifdef SIGBUS (void) setsighandler(SIGBUS, finish); # endif /* SIGBUS */ (void) setsighandler(SIGSEGV, finish); (void) setsighandler(SIGPIPE, finish); # endif /* DEBUGCRASH */ (void) setsighandler(SIGALRM, AlarmHandler); SetClockAlarm(NO); #else UpdModLine = YES; /* so Windows updates mode line on first display */ #endif /* UNIX */ ClAndRedraw(); flushscreen(); RedrawDisplay(); /* start the redisplay process. */ DoKeys(YES); finish(0); /* NOTREACHED */ } #ifdef PNAME_SYSCTL_OID /* FreeBSD, NetBSD */ # include #endif #ifdef PNAME_DYLD # include /* MacOSX */ #endif /* determine and return the directory in which the jove executable resides */ private void jexecpath(namebuf, namebufsz) char *namebuf; size_t namebufsz; { const char *cp; namebuf[0] = '\0'; #ifdef PNAME_GETEXECNAME if (namebuf[0] == '\0') { const char *ename = getexecname(); if (ename) { jamstrsub(namebuf, ename, namebufsz); } else { complain("getexecname failed: %s", strerror(errno)); /* NOTREACHED */ } } #endif #ifdef PNAME_SYSCTL_OID /* FreeBSD, NetBSD */ if (namebuf[0] == '\0') { static int oid[] = PNAME_SYSCTL_OID; size_t sz = namebufsz; int rc = sysctl(oid, sizeof(oid)/sizeof(oid[0]), namebuf, &sz, NULL, 0); if (rc < 0 || sz == 0) { complain("sysctl failed: %s", strerror(errno)); /* NOTREACHED */ } } #endif #ifdef PNAME_DYLD /* MacOSX */ if (namebuf[0] == '\0') { size_t sz = namebufsz; int rc = _NSGetExecutablePath(namebuf, &sz); if (rc < 0 || sz == 0) { complain("_NSGetExecutablePath failed: %s", strerror(errno)); /* NOTREACHED */ } } #endif #ifdef WIN32 /* Windows */ if (namebuf[0] == '\0') { DWORD nc = GetModuleFileNameA(NULL, namebuf, namebufsz); if (nc == 0 || nc == namebufsz) { complain("GetModuleFileNameA failed: %s", getLastErrorString()); /* NOTREACHED */ } } #endif #ifdef PNAME_PROC_SELF /* Linux */ if (namebuf[0] == '\0') { JSSIZE_T linklen; struct stat stbuf; const char *procself = "/proc/self/exe"; if (lstat(procself, &stbuf) == 0) { linklen = readlink(procself, namebuf, namebufsz); if (linklen < 0) { complain("readlink(%s) failed: %s", procself, strerror(errno)); /* NOTREACHED */ } namebuf[linklen] = '\0'; } } #endif if (namebuf[0] == '\0') { jamstrsub(namebuf, iniargv[0], namebufsz); } cp = jbasename(namebuf); if (!cp) { complain("could not find basename for %s", namebuf); /* NOTREACHED */ } namebuf[cp-namebuf] = '\0'; } jove-4.17.5.5/jove.h000066400000000000000000000321421501102521500140240ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* jove.h header file to be included by EVERYONE */ #ifndef TUNED # include "tune.h" /* must include first since it controls everything else */ #endif #include #include #include #ifndef EWOULDBLOCK /* older Unix, e.g. V7 */ # define RETRY_ERRNO(e) ((e) == EINTR || (e) == EAGAIN) #else # define RETRY_ERRNO(e) ((e) == EINTR || (e) == EAGAIN || (e) == EWOULDBLOCK) #endif #ifdef USE_STDIO_H # include /* for recover, setmaps */ #endif #ifndef MAC # include #else # include # include /* for time_t */ #endif /* proto: macro to allow us to prototype any function declaration * without upsetting old compilers. */ #ifdef REALSTDC # define USE_PROTOTYPES 1 #endif #ifdef USE_PROTOTYPES # define proto(x) x # ifdef NO_PTRPROTO /* on these systems, a prototype cannot be used for a pointer to function */ # define ptrproto(x) () # else # define ptrproto(x) x # endif #else # define proto(x) () # define ptrproto(x) () #endif /* There are two ways to handle functions with a variable number of args. * The old portable way uses varargs.h. The way sanctioned by ANSI X3J11 * uses stdarg.h. */ #ifdef REALSTDC #define STDARGS 1 #endif #ifdef STDARGS # include # define va_init(ap, parmN) { va_start((ap), parmN); } #else # include # define va_init(ap, parmN) { va_start((ap)); } #endif /* ANSI Goodies and their substitutes * * const: readonly type qualifier * * volatile: type qualifier indicating one of two kinds of magic. * 1. This object may be modified by an event unknown to the implementation * (eg. asynchronous signal or memory-mapped I/O device). * 2. This automatic variable might be modified between a setjmp() * and a longjmp(), and we wish it to have the correct value after * the longjmp(). This second meaning is an X3J11 abomination. * So far, only the second meaning is used. * * UnivPtr: universal pointer type * * UnivConstPtr: universal pointer to const */ #ifdef REALSTDC typedef void *UnivPtr; typedef const void *UnivConstPtr; #else /* !REALSTDC */ # ifndef const # define const /* Only in ANSI C. Pity */ # endif # ifndef volatile # define volatile # endif typedef char *UnivPtr; typedef const char *UnivConstPtr; #endif /* !REALSTDC */ /* According to the ANSI standard for C, any library routine may * be defined as a macro with parameters. In order to prevent * the expansion of this macro in a declaration of the routine, * ANSI suggests parenthesizing the identifier. This is a reasonable * and legal approach, even for K&R C. * * A bug in the MIPS compiler used on MIPS, IRIS, and probably other * MIPS R[23]000 based systems, causes the compiler to reject * these declarations (at least at the current time, 1989 August). * To avoid this bug, we conditionally define and use UNMACRO. */ #ifdef MIPS_CC_BUG # define UNMACRO(proc) proc #else # define UNMACRO(proc) (proc) #endif /* Since Jove does not use stdio.h (recover and setmaps do), we may have to define NULL and EOF */ #ifndef NULL #define NULL (void *)0 #endif #ifndef EOF #define EOF (-1) #endif /* Pervasive data types and constants */ #ifndef CHAR_BIT # define CHAR_BIT 8 /* factor to convert sizeof => bits */ #endif #ifndef NCHARS # define NCHARS 0400 #endif #define NULL_DADDR ((daddr) 0) #define DDIRTY ((daddr)1 << (sizeof(daddr)*CHAR_BIT - 1)) /* daddr dirty flag */ #define private static typedef int jbool; #define NO 0 #define YES 1 #define elemsof(a) (sizeof(a) / sizeof(*(a))) /* number of array elements */ /* Safe-where-possible signal handling. * * SIGHANDLERTYPE: the type of a pointer to a signal handler * setsighandler: the best way to establish a signal handler * resetsighandler: the best way to re-establish a signal handler */ typedef SIGRESTYPE (*SIGHANDLERTYPE) ptrproto((int)); #ifdef POSIX_SIGS extern SIGHANDLERTYPE setsighandler proto((int, SIGHANDLERTYPE)); # define resetsighandler(signo, handler) /* nothing */ #else /* !POSIX_SIGS */ # ifdef USE_SIGSET # define setsighandler(signo, handler) sigset((signo), (handler)) # define resetsighandler(signo, handler) /* nothing */ # else /* !USE_SIGSET */ /* BSD_SIGS or default: use signal() */ # define setsighandler(signo, handler) signal((signo), (handler)) # endif /* !USE_SIGSET */ #endif /* !POSIX_SIGS */ #ifndef resetsighandler /* On some systems, the signal handler is left established, * but this is not the case with original UNIX signals. * This code adjusts to the system at hand, at fairly low cost. * This code is even used for BSD_SIGS, even though it should not * be needed: it compensates for mis-configuration. * Note: this routine will only work if every execution of a particular * call is for the same handler. Furthermore, all executions should * be due to the handler being invoked by a signal. These restrictions * ensure that the setting of the static variable indicates whether * signal handlers need to be re-established. */ # define resetsighandler(signo, handler) { \ static SIGHANDLERTYPE reset_handler; \ \ if (reset_handler != (handler)) \ reset_handler = setsighandler((signo), (handler)); \ } #endif /* Principles of character representation in JOVE: * * - Only legal characters (excluding NUL) may be stored in the buffer. * * - Only legal characters will be found in the input stream, as * delivered by getch and kbd_getch (the meta-key feature * may cause invalid characters to be read, but they will be * confined within kbd_getch). * * - Bad characters from a file should be discarded. Perhaps a message * should be generated. NUL should be considered one of these bad * characters. [The elimination of these characters is the duty of * callers of jgetc.] * * - The type of a string (ignoring const or volatile) should be "char *". * This is the standard type specified by the ANSI/ISO C standard. * As such, it is the type expected by the standard library. * * - In general, it is reasonable to use a plain char type * to represent an individual character, avoiding the expense and * fuss of widening. * * + The character must be known not to be an EOF. * * + The character must only be used in ways in which sign extension * is known to not cause problems: * * * The value is coerced into a char type (the most common example * is assignment to a char; another is the search character in a * call to strchr). Of course, EOF must not appear in these * contexts. * * * The value is used for equality or inequality comparison where * all operands are subject to identical char widening. A * special case of this is 7-bit ASCII char literals: * they can be safely compared for equality or inequality with * chars widened explicitly or implicitly. * * - ZXchar is the type for a character that has been widened without * sign extension. It can represent EOF distinctly from characters. * The ZXC and ZXRC functions should be used to do the widening. * * - DAPchar is the type that results from the "default argument promotions" * applied to the char type. Since most of our function definitions are * in the old style, formals declared in these definitions to be of type * char should be declared to be of type DAPchar in any prototype (this is * an arcane ANSI C rule). The widening involved might be sign-extension * or it might not, but we don't care because it will be immediately * narrowed. A C implementation can legally make the type "unsigned int", * but this is highly unlikely. By extension, a value of this type may be * used anywhere a char is needed. * * The following functions widen char type to an int, without sign * extension. There are two kinds: * * ZXC(c): zero-extend an internal char. It is presumed that * the character is clean, but we may have to prevent sign extension. * * ZXRC(c): zero-extend a external (raw) char. The purpose is to prevent * sign extension, even if the char is invalid. */ typedef int ZXchar; /* type for expanded char (possibly EOF) */ #ifndef DAPchar # define DAPchar int /* DefaultArgPromotion(char) */ #endif #ifndef UCHAR_ROOF # define UCHAR_ROOF 256 /* better be true! */ #endif #if NCHARS == 128 # ifndef ZXC # define ZXC(c) (c) /* identity op -- sign bit must be off */ # endif #else # if NCHARS == UCHAR_ROOF # ifndef ZXC # define ZXC(c) ((ZXchar) (unsigned char) (c)) # endif # else /* ??? */ # endif #endif #ifndef ZXRC # define ZXRC(c) ((ZXchar) (unsigned char) (c)) #endif /* Pervasive exports of other modules */ /* disp.c */ extern volatile jbool UpdModLine; /* Does the mode line need to be updated? */ /* term.c: universal termcap-like declarations */ extern int SG, /* number of magic cookies left by SO and SE */ LI, /* number of lines */ ILI, /* number of internal lines (LI - 1) */ CO; /* number of columns (CO <= MAXCOLS) */ extern jbool TABS; /* terminal supports tabs */ /* typedef pervasive structure definitions */ typedef struct window Window; /* wind.h */ typedef struct position Bufpos; /* buf.h */ typedef struct mark Mark; /* buf.h (not mark.h!) */ typedef struct buffer Buffer; /* buf.h */ #ifdef FAR_LINES typedef struct line _far *LinePtr; /* buf.h */ #else typedef struct line *LinePtr; /* buf.h */ #endif typedef struct FileStruct File; /* fp.h */ #include "buf.h" #include "io.h" #include "dataobj.h" #include "keymaps.h" #include "argcount.h" #include "util.h" #ifndef NO_EXTERNS /* setmaps.c does not need externs, messes up cross-compiles */ #include "externs.h" #endif #define FORWARD 1 #define BACKWARD (-1) /* jove.c exports: */ /* paths */ extern char ShareDir[FILESIZE], /* VAR: directory path of machine-independent support files */ LibDir[FILESIZE], /* VAR: directory path of machine-dependent support programs */ TmpDir[FILESIZE]; /* VAR: directory path to store tmp files, must exist */ #ifdef SUBSHELL extern char Shell[FILESIZE], /* VAR: shell to use */ ShFlags[16]; /* VAR: flags to shell */ #endif /* setjmp/longjmp args for DoKeys() mainjmp */ #define JMP_ERROR 1 #define JMP_COMPLAIN 2 /* do the error without a getDOT */ #define JMP_QUIT 3 /* leave this level of recursion */ extern jmp_buf mainjmp; #define IDX(c) ((c)-'a') #define IDXSZ (IDX('z')+1) extern char NullStr[]; extern ZXchar peekchar, /* holds pushed-back getch output */ LastKeyStruck; /* used by SelfInsert and friends */ extern int RecDepth, /* recursion depth (used by disp.c for modeline) */ SlowCmd; /* depth of nesting of slow commands */ extern jbool TOabort, /* flag set by Typeout() */ stickymsg, /* the last message should stick around */ InputPending, /* is there input waiting to be processed? */ Interactive; #ifdef UNIX extern jbool InSlowRead; /* Can we do a redisplay in a signal handler? */ #endif extern char *Inputp; #ifdef WINRESIZE # define PreEmptOutput() (ResizePending || (SlowCmd == 0 && charp())) # define CheapPreEmptOutput() (ResizePending || (SlowCmd == 0 && InputPending)) #else # define PreEmptOutput() (SlowCmd == 0 && charp()) # define CheapPreEmptOutput() (SlowCmd == 0 && InputPending) #endif #ifdef SUBSHELL extern void jcloseall proto((void)); #endif extern SIGRESTYPE finish proto((int code)) NEVER_RETURNS, /* doesn't return at all! */ win_reshape proto((int /*junk*/)); extern jbool charp proto((void)); extern ZXchar getch proto((void)), kbd_getch proto((void)), peek_or_mac_getch proto((void)), waitchar proto((void)), ask_ks proto((void)); extern void cmd_sync proto((void)), add_stroke proto((ZXchar)), error proto((const char *, ...)) NEVER_RETURNS, complain proto((const char *, ...)) NEVER_RETURNS, raw_complain proto((const char *, ...)), confirm proto((const char *, ...)), SitFor proto((int delay)), pp_key_strokes proto((char *buffer, size_t size)), tty_adjust proto ((void)), Ungetc proto((ZXchar c)), kbd_ungetch proto((ZXchar c)), dispatch_macros proto((void)); /* Commands: */ extern void #ifdef JOB_CONTROL PauseJove proto((void)), #endif #ifdef SUBSHELL Push proto((void)), #endif Recur proto((void)), TeachJove proto((void)), ShowVersion proto((void)); /* Variables: */ extern jbool MetaKey; /* VAR: this terminal has a meta key */ extern jbool TimeDisplayed; /* is time actually displayed in modeline? */ extern char JoveFeatures[MAXCOLS]; /* VAR: list of compiled-in features */ #if defined(UNIX) || defined(MINGW) extern char JoveCompiled[MAXCOLS]; /* VAR: compile flags used to build this */ extern char JoveLinked[MAXCOLS]; /* VAR: link flags used to build this */ #endif /* UNIX || MINGW */ #ifdef UNIX extern int UpdFreq; /* VAR: how often to update modeline */ extern void SetClockAlarm proto((jbool unset)); #endif /* UNIX */ extern jbool SaveOnExit; /* VAR: offer to save buffers on exit */ jove-4.17.5.5/jtc.c000066400000000000000000000266211501102521500136410ustar00rootroot00000000000000/************************************************************************** * This file is Copyright (C) 2020 by Mark Moraes. It is provided * * without charge and without warranty. You may copy, modify, and/or * * distribute it, provided that this notice is included in all the source * * file and documentation. * **************************************************************************/ /* * Simple standalone hardwired terminfo/termcap replacement * that only supports the subset of vt[123]xx/ANSI * X3.64/ECMA-48/ISO6429 needed by Jove. Since everyone in * the year 2020CE probably uses a terminal emulator that * supports far more than the set needed by Jove, the approach * here is to define a few levels of capabilities, use JOVEVT * or TERM to select a level and fake out the tgetent/tputs * routines. This does not provide tparm/tgoto to interpret * the termcap/terminfo % operators, instead providing just * the one and two-arg functions (jtcarg[12]) that Jove needs, * and assuming the two-arg increments row/col as %i does. If * someone finds themselves on a terminal that does not * support the necessary minimal subset of ANSI X.3, then you * need to compile jove with one of termcap/terminfo/curses/ncurses/ncursesw! */ /* Mark Moraes, 20200109 */ #include "jove.h" #ifndef JTC extern int avoid_pedantic_complaints_about_empty_translation_unit; #else #include "jctype.h" #include "fmt.h" /* for swritef */ #include "fp.h" /* for flushscreen */ #include #include "select.h" #ifdef TERMIOS # include # include # ifdef TIOCGWINSZ private struct winsize jtwin; # define JVTCOLS jtwin.ws_col # define JVTROWS jtwin.ws_row # endif /* TIOCGWINSZ */ #endif /* TERMIOS */ #ifndef JVTCOLS # define JVTCOLS 80 # define JVTROWS 24 #endif #ifdef TEST_STANDALONE extern int strncasecmp proto((const char *, const char *, size_t)); extern int snprintf proto((char *, size_t, const char *, ...)); extern int printf(const char *, ...); extern int putchar(int); extern void fflush(void *); /* XXX */ extern void *stdout; /* XXX */ #define flushscreen() fflush(stdout) #define caseeqn(s1, s2, n) (strncasecmp(s1, s2, n) == 0) #define swritef snprintf #undef jisdigit #define jisdigit(c) (c >= '0' && c <= '9') #endif /* symbolic values for capability level */ #define ANSI 99 /* cursor motions, standout/underline */ #define VT100 100 /* scrolling region, flash/visual bell, cursor 'application keypad' mode */ #define VT102 102 /* generally what most VT100 emulators handle */ #define VT125 125 /* anything above this has a meta- or alt- key */ #define VT320 320 /* SR/SF aka SU/SD to pan up or down by multiple lines */ #define VTALT 999 /* alternate screen, like xterm, rxvt, and friends */ typedef struct jtermcap { const char *capname; const char *capval; unsigned caplevel; } JTermcap; #define JTMAX 128 private char jtarg[JTMAX]; private int jtlev = -1; private JTermcap jtc[] = { {"vs", "\033[?12;25h", VTALT}, /* ATT610 blinking cursor + DECTCEM show cursor*/ {"ve", "\033[?12l\033[?25h", VTALT}, /* turn off ATT610 but leave cursor? */ {"al", "\033[L", ANSI}, {"dl", "\033[M", ANSI}, {"cs", "\033[%d;%dr", VT100}, /* DECSTBM, so I assume not ANSI? targ2 so will do %i-like incr both args */ {"so", "\033[7m", ANSI}, {"se", "\033[27m", ANSI}, {"us", "\033[4m", ANSI}, {"ue", "\033[24m", ANSI}, {"cm", "\033[%d;%dH", ANSI}, /* targ2, so will do %i-like incr both args */ {"cl", "\033[H\033[J", ANSI}, /* more portable than \033[2J if we need the \033[H to position cursor anyway? */ {"ce", "\033[K", ANSI}, {"ho", "\033[H", ANSI}, {"up", "\033[A", ANSI}, {"do", "\n", 0}, /* shorter than \033[B */ {"sf", "\n", 0}, /* shorter than \033D */ {"sr", "\033M", ANSI}, {"vb", "\033[?5h$\033[?5l", VT100}, /* $ means 100ms delay, i.e. $<100/> */ {"ks", "\033[?1h\033=", VT100}, {"ke", "\033[?1l\033>", VT100}, {"ti", "\0337\033[?47h", VTALT}, /* or \033[?1049h */ {"te", "\033[2J\033[?47l\0338", VTALT}, /* or \033[?1049l */ {"bl", "\007", 0}, {"AL", "\033[%dL", VT102}, {"DL", "\033[%dM", VT102}, {"SF", "\033[%dS", VT320}, /* in ANSI, but not much support, it seems. vttest says it appeared in VT320 */ {"SR", "\033[%dT", VT320}, /* in ANSI, but not much support, it seems. vttest says it appeared in VT320 */ {"im", "\033[4h", VT102}, {"dc", "\033[P", VT102}, {"ei", "\033[4l", VT102}, {"IC", "\033[%d@", VT102}, {"DC", "\033[%dP", VT102}, }; typedef struct jtlevel { const char *tprefix; unsigned tlevel; } JTLevel; private JTLevel jtc_emu[] = { {"ansi", ANSI}, {"xterm", VTALT}, {"rxvt", VTALT}, {"xnuppc", VTALT}, {"putty", VTALT}, {"linux", VT125}, {"screen", VTALT}, {"tmux", VTALT}, {"gnome", VTALT}, {"konsole", VTALT}, {"eterm", VTALT}, {"nsterm", VTALT}, {"kterm", VTALT}, {"vte", VTALT}, {"st", VTALT}, }; char * jtcarg1(fmt, p) const char *fmt; int p; { if (fmt) swritef(jtarg, sizeof jtarg, fmt, p); else jtarg[0] = '\0'; return jtarg; } /* * XXX always increment both args because the capability * strings for cm and cs on ANSI/ECMA/VTxxx terminals need * that, and that is all JOVE uses targ2 for. i.e. * hardwires the %i behaviour from terminfo/termcap */ char * jtcarg2(fmt, destcol, destline) const char *fmt; int destcol, destline; { if (fmt) swritef(jtarg, sizeof jtarg, fmt, destline+1, destcol+1); else jtarg[0] = '\0'; return jtarg; } /* * same as jove.c SitFor but without charp/redisplay to avoid * risk of recursion. If you do not have select, use regular * termcap. A jdelay function ought to be factored out of jove.c * and moved to unix.c, ibmpcdos.c, win32.c, mac.c. */ void jdelay(delay) int delay; { struct timeval timer; fd_set readfds; timer.tv_sec = (delay / 10); timer.tv_usec = (delay % 10) * 100000; FD_ZERO(&readfds); FD_SET(0, &readfds); (void) select(1, &readfds, (fd_set *)NULL, (fd_set *)NULL, &timer); } void tputs(str, lines, putfunc) const char *str; int lines; void (*putfunc) proto((int)); { const char *cp = str; ZXchar c; jbool needflush = NO; while (cp && (c = ZXC(*cp++)) != '\0') { if (c == '$') { flushscreen(); needflush = YES; jdelay(1); /* tenth of a second */ } else { (*putfunc)(c); } } if (needflush) flushscreen(); } int tgetent(buf, tenv) char *buf; const char *tenv; { const char *jtcenv = getenv("JOVEVT"); if (jtcenv != NULL) { if (caseeqn(jtcenv, "alt", 3) || caseeqn(jtcenv, "vtalt", 5)) { jtlev = VTALT; } else if (caseeqn(jtcenv, "vt", 2)) { jtlev = atoi(jtcenv+2); } else { jtlev = atoi(jtcenv); } } else { JTLevel *j = jtc_emu; if (caseeqn(tenv, "vt", 2) && jisdigit(tenv[2])) { jtlev = atoi(&tenv[2]); } for (j = jtc_emu; j < jtc_emu + (sizeof(jtc_emu)/sizeof(jtc_emu[0])); j++) { size_t tlen = strlen(j->tprefix); if (caseeqn(tenv, j->tprefix, tlen) && (tenv[tlen] == '\0' || tenv[tlen] == '-' || tenv[tlen] == '.' || jisdigit(tenv[tlen]))) { jtlev = j->tlevel; break; } } } #ifdef TIOCGWINSZ if (ioctl(0, TIOCGWINSZ, (UnivPtr) &jtwin) < 0) return -1; #endif return jtlev >= 0; } #define capeq(cap, val) (cap[0] == val[0] && cap[1] == val[1] && \ cap[2] == val[2] && cap[2] == '\0') int tgetflag(capname) const char *capname; { if (capeq(capname, "mi") && jtlev >= VT125) return YES; /* terminfo for vt102 does not have move-in-insert */ else if (capeq(capname, "km") && jtlev >= VTALT) return YES; /* metakey only on modern terminal emulators */ /* * NP is not checked on modern machines with select(), * which are the only ones with xterm etc where NP * might be true. */ return NO; } int tgetnum(capname) const char *capname; { if (capeq(capname, "co")) { return JVTCOLS; } else if (capeq(capname, "li")) { return JVTROWS; } else if (capeq(capname, "it")) { return 8; } else if (capeq(capname, "ug") || capeq(capname, "sg")) { return 0; } return -1; } const char * tgetstr(capname, area) const char *capname; char **area; { JTermcap *j; for (j = jtc; j < jtc + (sizeof(jtc)/sizeof(jtc[0])); j++) { if (capeq(j->capname, capname) && j->caplevel <= jtlev) { if (area && *area) { size_t caplen = strlen(j->capval) + 1; memcpy(*area, j->capval, caplen); *area += caplen; } return j->capval; } } return 0; } #ifdef TEST_STANDALONE /* To test, build with * LANG=C gcc -o testjtc jtc.c -g -O -Wall -DTEST_STANDALONE -DJTC -DTERMIOS */ /* make terminfo string printable */ void puts_encoded(s) const char *s; { unsigned c; if (s) while ((c = (*s++)&0xff) != '\0') { /*printf(" 0x%x\n", c);*/ if (c == 0x1b) { /* convention for ESC per terminfo(5) */ printf("\\E"); } else if (c == 0x7f) { /* convention for DEL e.g. terminfo(5) */ printf("^?"); } else if (c < ' ') { /* ^ followed up uppercase letter */ printf("^%c", c | 0x40); } else if (c < 0x7f) { printf("%c", c); } else { printf("\\%03o", c); } } printf("\n"); } void xtputs(delay, s, li) int delay, li; const char *s; { tputs(s, li, putchar); fflush(stdout); jdelay(delay); } int main(argc, argv) int argc; char **argv; { int i, j; static const char *capn[] = {"co", "li", "it", "ug", "sg", "xx"}; static const char *capf[] = {"NP", "mi", "km", "ul", "xs", "hz"}; const char *cp; for (i = 1; i < argc; i++) { int r = tgetent(NULL, argv[i]); printf("tgetent(%s) -> %d jtlev=%d\n", argv[i], r, jtlev); for (j = 0; j < sizeof(capn)/sizeof(capn[0]); j++) { int v = tgetnum(capn[j]); printf(" %s=%d\n", capn[j], v); } for (j = 0; j < sizeof(capf)/sizeof(capf[0]); j++) { int v = tgetflag(capf[j]); printf(" %s=%s\n", capf[j], v == YES ? "YES" : "NO"); } for (j = 0; j < sizeof(jtc)/sizeof(jtc[0]); j++) { const char *s = tgetstr(jtc[j].capname, NULL); printf(" %s=", jtc[j].capname); puts_encoded(s); } } if (argc > 1) exit(0); printf("about to enter screen mode:\n"); fflush(stdout); jdelay(10); cp = getenv("TERM"); tgetent(NULL, cp); xtputs(1, tgetstr("ti", NULL), 0); xtputs(1, jtcarg1(tgetstr("ks", NULL),0), 0); xtputs(10, tgetstr("cl", NULL), 24); xtputs(10, "hello\nworld", 2); xtputs(1, jtcarg2(tgetstr("cm", NULL), 4, 0), 1); xtputs(10, jtcarg1(tgetstr("dc", NULL), 1), 1); xtputs(1, jtcarg2(tgetstr("cm", NULL), 2, 1), 1); xtputs(10, "wsa", 1); xtputs(1, jtcarg2(tgetstr("cs", NULL), 5, 0), 1); xtputs(1, tgetstr("ho", NULL), 1); xtputs(10, tgetstr("sr", NULL), 1); xtputs(10, "111111", 1); xtputs(1, tgetstr("ho", NULL), 1); xtputs(1, tgetstr("do", NULL), 1); xtputs(1, tgetstr("do", NULL), 1); xtputs(10, tgetstr("sf", NULL), 1); xtputs(10, "222222", 1); xtputs(5, jtcarg1(tgetstr("ho", NULL), 1), 1); cp = tgetstr("SR", NULL); if (cp) xtputs(10, jtcarg1(cp, 2), 2); else { xtputs(5, jtcarg1(tgetstr("sr", NULL), 1), 1); xtputs(5, jtcarg1(tgetstr("sr", NULL), 1), 1); } xtputs(5, jtcarg2(tgetstr("cm", NULL),0,5), 1); cp = tgetstr("SF", NULL); if (cp) xtputs(10, jtcarg1(cp, 2), 2); else { xtputs(5, jtcarg1(tgetstr("sf", NULL),1), 1); xtputs(5, jtcarg1(tgetstr("sf"),1), 1); } j = tgetnum("li"); xtputs(5, tgetstr("dl", NULL), 1); xtputs(5, tgetstr("so", NULL), 1); printf("%d",j); fflush(stdout); xtputs(5, tgetstr("se", NULL), 1); xtputs(5, tgetstr("vb", NULL), 1); xtputs(5, jtcarg2(tgetstr("cs", NULL),j-1,0), 0); xtputs(5, jtcarg2(tgetstr("cm", NULL),0,j-1), 0); xtputs(5, tgetstr("ce", NULL), 0); xtputs(0, tgetstr("ke", NULL), 0); xtputs(0, tgetstr("te", NULL), 0); printf("done.\n"); return 0; } #endif /* TEST_STANDALONE */ #endif /* JTC */ jove-4.17.5.5/keymaps.c000066400000000000000000000534701501102521500145340ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "list.h" #include "fp.h" #include "jctype.h" #include "chars.h" #include "disp.h" #include "re.h" #include "ask.h" #include "commands.h" #include "macros.h" #include "extend.h" #include "fmt.h" #include "screen.h" /* for Placur */ #include "vars.h" #ifdef IPROCS # include "sysprocs.h" /* this and below ... */ # include "iproc.h" /* ... for definition of ProcNewline() */ #endif #ifdef PCNONASCII private const char *const altseq[] = { /*000*/NULL, "Alt Esc", NULL, "Ctl-@", NULL, NULL, NULL, "Ctl-^", /*010*/NULL, NULL, NULL, NULL, "Ctl-_", "Enter", "Alt-Bksp", "Left", /*020*/"Alt-Q", "Alt-W", "Alt-E", "Alt-R", "Alt-T", "Alt-Y", "Alt-U", "Alt-I", /*030*/"Alt-O", "Alt-P", "Alt-[", "Alt-]", "Alt-Enter", NULL, "Alt-A", "Alt-S", /*040*/"Alt-D", "Alt-F", "Alt-G", "Alt-H", "Alt-J", "Alt-K", "Alt-L", "Alt-;", /*050*/"Alt-'", "Alt-~", NULL, "Alt-\\", "Alt-Z", "Alt-X", "Alt-C", "Alt-V", /*060*/"Alt-B", "Alt-N", "Alt-M", "Alt-,", "Alt-.", "Alt-/", NULL, "Alt KP-", /*070*/NULL, NULL, NULL, "F1", "F2", "F3", "F4", "F5", /*100*/"F6", "F7", "F8", "F9", "F10", NULL, NULL, "Home", /*110*/"Up", "PgUp", "Alt KP-", "Left", "Shift KP5", "Right", "Alt KP+", "End", /*120*/"Down", "PgDn", "Ins", "Del", "Shift F1", "Shift F2", "Shift F3", "Shift F4", /*130*/"Shift F5", "Shift F6", "Shift F7", "Shift F8", "Shift F9", "Shift F10", "Ctl F1", "Ctl F2", /*140*/"Ctl F3", "Ctl F4", "Ctl F5", "Ctl F6", "Ctl F7", "Ctl F8", "Ctl F9", "Ctl F10", /*150*/"Alt F1", "Alt F2", "Alt F3", "Alt F4", "Alt F5", "Alt F6", "Alt F7", "Alt F8", /*160*/"Alt F9", "Alt F10", "Ctl PrtSc", "Ctl Left", "Ctl Right", "Ctl End", "Ctl PgDn", "Ctl Home", /*170*/"Alt 1", "Alt 2", "Alt 3", "Alt 4", "Alt 5", "Alt 6", "Alt 7", "Alt 8", /*200*/"Alt 9", "Alt 0", "Alt Minus", "Alt Equals", "Ctl PgUp", "F11", "F12", "Shift F11", /*210*/"Shift F12", "Ctl F11", "Ctl F12", "Alt F11", "Alt F12", "Ctl Up", "Ctl KP-", "Ctl KP5", /*220*/"Ctl KP+", "Ctl Down", "Ctl Ins", "Ctl Del", "Ctl Tab", "Ctl KP/", "Ctl KP*", "Alt Home", /*230*/"Alt Up", "Alt PgUp", NULL, "Alt Left", NULL, "Alt Right", NULL, "Alt End", /*240*/"Alt Down", "Alt PgDn", "Alt Ins", "Alt Del", "Alt KP/", "Alt Tab", "Alt KP Enter", NULL, /*250*/NULL, NULL, NULL, "Shift Home", "Shift Up", "Shift PgUp", "Shift Alt KP-", "Shift Left", /*260*/"Shift KP5", "Shift Right", "Shift Alt KP+", "Shift End", "Shift Down", "Shift PgDn", "Shift Ins", "Shift Del" }; #endif /* PCNONASCII */ int this_cmd, last_cmd; /* * A data_obj can be a command, a macro, a variable or a keymap. So a keymap * can be bound to a key just like commands, macros and variables can. Users * don't bind keymaps to keys, though, they just bind the other things to * keys, and this package automatically creates keymaps as they are needed to * accomodate the specified key sequences. * * NOTE: Since users don't bind keymaps to keys, there is no reason for keymaps * to have names. Right now they do, but perhaps that can be fixed later. At * least the names need not be made visible. */ /* * A keymap is either a sparse keymap or a full keymap. The main keymap as * well as escape and control X maps are full maps, because they are almost * full. All other keymaps that the system creates on behalf of users in * order to accomodate an arbitrary key binding will be sparse maps, on the * theory that they will be pretty small. Sparse keymaps are sorted. */ #define KEYMAP_QUANTUM 8 /* sparse keymap allocation batch size */ #define SPARSE_LIMIT (NCHARS/3 - KEYMAP_QUANTUM) /* threshold for conversion */ struct keybinding { ZXchar key; data_obj *value; }; struct keymap { int Type; /* keymap type (sparse or full) */ char *Name; /* keymap name */ struct keymap *next_map; jbool unfreeable; jbool mark; /* used for cycle avoidance */ union { struct { data_obj **map; /* keys array indexed by key */ } full; struct { struct keybinding *bindings; short nused; /* number of keybindings used */ short nalloc; /* number of keybindings allocated */ } sparse; } u; }; #define IsKeymap(/* data_obj* */ o) ((o) != NULL && \ ((o)->Type == FULL_KEYMAP || \ (o)->Type == SPARSE_KEYMAP)) private struct keymap *keymaps = NULL; /* list of all keymaps */ private struct keymap *mainmap; #ifdef IPROCS private struct keymap *procsmap; #endif /* * Make a new keymap. Type is either FULL_KEYMAP or SPARSE_KEYMAP. If it's * full, the keys is either NULL or a pointer to a valid keymap of length * NCHARS. */ private void km_init(km, kind, keys) struct keymap *km; int kind; data_obj **keys; { byte_zero((UnivPtr) &km->u, sizeof(km->u)); /* zero integral fields */ if ((km->Type = kind) == FULL_KEYMAP) { if (keys == NULL) { data_obj **p; keys = (data_obj **) emalloc(NCHARS * sizeof(data_obj *)); p = &keys[NCHARS]; do *--p = NULL; while (p != keys); } else { km->unfreeable = YES; } km->u.full.map = keys; } else { km->u.sparse.bindings = NULL; } } private struct keymap * km_new(kind, keys, name) int kind; data_obj **keys; char *name; { struct keymap *km = (struct keymap *) emalloc(sizeof(struct keymap)); km->Name = name; km->next_map = keymaps; keymaps = km; km->unfreeable = NO; /* provisional */ km_init(km, kind, keys); return km; } /* km_getkey: look up key in keymap * * If the keymap is sparse, km_getkey sets km_sparsepos to the index * of the entry found (if any), or the index of the entry which would * be its successor (if not found). */ private int km_sparsepos; private data_obj * km_getkey(km, key) struct keymap *km; ZXchar key; { if (km->Type == FULL_KEYMAP) { return (km->u.full.map[key]); } else { struct keybinding *b = km->u.sparse.bindings; int lwb = 0; /* closed lower bound */ int upb = km->u.sparse.nused; /* open upper bound */ for (;;) { int mid = (lwb + upb) >> 1; /* fast average */ if (mid == lwb) break; if (b[mid].key <= key) lwb = mid; else upb = mid; } if (lwb != upb) { if (b[lwb].key == key) { /* found */ km_sparsepos = lwb; return b[lwb].value; } if (b[lwb].key > key) upb = lwb; /* make upb tight */ } /* not found; insertion would be before upb */ km_sparsepos = upb; return NULL; } } private ZXchar km_nextkey(km, key) struct keymap *km; ZXchar key; { if (km->Type == FULL_KEYMAP) { while (key != NCHARS && km->u.full.map[key] == NULL) key++; } else { (void) km_getkey(km, key); key = km_sparsepos == km->u.sparse.nused ? NCHARS : km->u.sparse.bindings[km_sparsepos].key; } return key; } /* Free a dataobj reference formerly bound in or as a keymap. * At the present time, only values that represent keymaps * can be usefully freed, and only those that are not marked as * unfreeable. unfreeable ones have other references (mainmap * or procsmap), or they include a non-heap (static) allocation. */ void DelObjRef(value) data_obj *value; { if (IsKeymap(value)) { struct keymap *km = (struct keymap *)value; if (!km->unfreeable) { ZXchar k; for (k = 0; (k = km_nextkey(km, k)) != NCHARS; k++) DelObjRef(km_getkey(km, k)); switch (km->Type) { case FULL_KEYMAP: free((UnivPtr) km->u.full.map); break; case SPARSE_KEYMAP: free((UnivPtr) km->u.sparse.bindings); break; } { /* remove km from list of all keymaps */ struct keymap **p; for (p = &keymaps; *p != km; p = &(*p)->next_map) ; *p = (*p)->next_map; } free((UnivPtr) km); } } } private void km_setkey(km, key, d) struct keymap *km; ZXchar key; data_obj *d; { if (km->Type == FULL_KEYMAP) { DelObjRef(km->u.full.map[key]); km->u.full.map[key] = d; } else { struct keybinding *b = km->u.sparse.bindings; int nused = km->u.sparse.nused; if (km_getkey(km, key) != NULL) { /* overwriting a binding */ int i = km_sparsepos; DelObjRef(b[i].value); /* note: overwrites km_sparsepos */ if (d == NULL) { /* overwriting with NULL is actually deleting an entry */ while (++i < nused) b[i-1] = b[i]; km->u.sparse.nused -= 1; } else { b[i].value = d; } } else if (d != NULL) { /* inserting a new binding. */ if (nused == km->u.sparse.nalloc) { /* grow the keymap */ if (nused >= SPARSE_LIMIT) { /* convert to full keymap (in place!) */ km_init(km, FULL_KEYMAP, (data_obj **) NULL); while (nused-- != 0) km->u.full.map[b[nused].key] = b[nused].value; free((UnivPtr) b); km->u.full.map[key] = d; return; } else { km->u.sparse.bindings = b = (struct keybinding *) erealloc( (UnivPtr) km->u.sparse.bindings, (km->u.sparse.nalloc += KEYMAP_QUANTUM) * sizeof(struct keybinding)); } } km->u.sparse.nused += 1; for (; nused > km_sparsepos; nused--) b[nused] = b[nused-1]; b[km_sparsepos].key = key; b[km_sparsepos].value = d; } } } private void UnmarkMaps() { struct keymap *km; for (km = keymaps; km != NULL; km = km->next_map) km->mark = NO; } /* get the currently active keymaps into km_buf */ #define MAX_KEYMAPS 3 /* bound on number of keymaps found by get_keymaps */ private int get_keymaps(km_buf) struct keymap **km_buf; { int nmaps = 0; /* add maps to array in order of decreasing priority (and specificity) */ if (curbuf->b_map != NULL) km_buf[nmaps++] = curbuf->b_map; #ifdef IPROCS if (curbuf->b_process != NULL) km_buf[nmaps++] = procsmap; #endif km_buf[nmaps++] = mainmap; return nmaps; } jbool IsPrefixChar(c) ZXchar c; { return IsKeymap(km_getkey(mainmap, c)); } private struct keymap * GetKeymap(m, key) struct keymap *m; ZXchar key; { data_obj *val = km_getkey(m, key); return IsKeymap(val)? (struct keymap *) val : (struct keymap *) NULL; } private const data_obj * findmap(fmt) const char *fmt; { struct keymap *km; const char *strings[128]; int i; for (km = keymaps, i = 0; km != NULL; km = km->next_map) if (i < (int) elemsof(strings) - 1 && km->Name != NULL) strings[i++] = km->Name; strings[i] = NULL; i = complete(strings, (char *)NULL, fmt, ALLOW_OLD | ALLOW_INDEX); for (km = keymaps; ; km = km->next_map) { if (km->Name != NULL && i-- == 0) { km->unfreeable = YES; return (data_obj *) km; } } } private void BindSequence(m, keys, k_len, obj) struct keymap *m; char *keys; int k_len; data_obj *obj; { int i; if (k_len == 0) { complain("can't bind empty key sequence"); /* NOTREACHED */ } for (i = 0; i < k_len - 1; i++) { struct keymap *submap = GetKeymap(m, ZXC(keys[i])); if (submap == NULL) { submap = km_new(SPARSE_KEYMAP, (data_obj **)NULL, (char *)NULL); km_setkey(m, ZXC(keys[i]), (data_obj *) submap); } m = submap; } km_setkey(m, ZXC(keys[i]), obj); #ifdef MAC /* info for About Jove ... */ if (obj != NULL && obj_type(obj) == COMMAND) { struct cmd *cmd = (struct cmd *) obj; char map = 0; if (m->Type == FULL_KEYMAP) { if (m->u.full.map == MainKeys) map = F_MAINMAP; else if (m->u.full.map == EscKeys) map = F_PREF1MAP; else if (m->u.full.map == CtlxKeys) map = F_PREF2MAP; } if (map != 0) { cmd->c_map = map; cmd->c_key = ZXC(keys[i]); /* see about_j() in mac.c */ } } #endif } private void DoBind(findproc, map) const data_obj *(*findproc) ptrproto((const char *)); struct keymap *map; { const data_obj *d = (*findproc) (ProcFmt); char keys[64]; int i; struct keymap *m; s_mess(": %f %s ", d->Name); if (obj_type(d) == COMMAND && ((struct cmd *)d)->c_proc == Unbound) d = NULL; i = 0; m = map; for (;;) { ZXchar c = addgetc(); if (c == EOF) break; if (i == sizeof(keys) - 1) { complain("key sequence too long"); /* NOTREACHED */ } keys[i++] = c; if (!InJoverc) { if (is_an_arg()) { /* Disgusting hack to allow more interactive power. * This ought to be replaced by a cleaner mechanism. */ if (c == '\r' || c == '\n') { i -= 1; break; } if (c == '\\') keys[i-1] = addgetc(); } else { if ((m = GetKeymap(m, c)) == NULL) break; } } } BindSequence(map, keys, i, (data_obj *)d); /* lose const on d */ } private void DoLBind(findproc) const data_obj *(*findproc) ptrproto((const char *)); { if (curbuf->b_map == NULL) curbuf->b_map = km_new(SPARSE_KEYMAP, (data_obj **)NULL, (char *)NULL); DoBind(findproc, curbuf->b_map); } /* bind a command to a key in the buffer's local keymap. */ void LBindAKey() { DoLBind(findcom); } /* bind a macro to a key in the buffers local keymap. */ void LBindMac() { DoLBind(findmac); } void LBindMap() { DoLBind(findmap); } void BindAKey() { DoBind(findcom, mainmap); } void BindMac() { DoBind(findmac, mainmap); } void BindMap() { DoBind(findmap, mainmap); } #ifdef IPROCS void PBindAKey() { DoBind(findcom, procsmap); } void PBindMac() { DoBind(findmac, procsmap); } void PBindMap() { DoBind(findmap, procsmap); } #endif void Unbound() { complain("%f"); /* NOTREACHED */ } void KeyDesc() { struct keymap *maps[MAX_KEYMAPS]; int nmaps; nmaps = get_keymaps(maps); s_mess(ProcFmt); while (YES) { int i; jbool still_hope = NO; ZXchar key = addgetc(); for (i = 0; i < nmaps; i++) { if (maps[i] != NULL) { data_obj *cp = km_getkey(maps[i], key); if (cp != NULL) { if (!IsKeymap(cp)) { add_mess("is bound to %s.", cp->Name); stickymsg = YES; return; } still_hope = YES; } maps[i] = (struct keymap *) cp; } } if (!still_hope) break; } add_mess("is unbound."); } private void DescMap(map, pref) struct keymap *map; char *pref; { if (map != NULL && !map->mark) { ZXchar c1, c2; map->mark = YES; for (c1 = km_nextkey(map, 0); c1 < NCHARS; c1 = km_nextkey(map, c2 + 1)) { data_obj *c1obj = km_getkey(map, c1); char keydescbuf[40]; c2 = c1; do {} while (++c2 < NCHARS && c1obj == km_getkey(map, c2)); c2 -= 1; swritef(keydescbuf, sizeof(keydescbuf), c1 == c2 ? "%s %p" : c1 + 1 == c2 ? "%s {%p,%p}" : "%s [%p-%p]", pref, c1, c2); if (IsKeymap(c1obj)) { #ifdef PCNONASCII /* horrible kludge to handle PC non-ASCII keys */ if (c1 == PCNONASCII) { ZXchar pc; struct keymap *pcm = (struct keymap *)c1obj; c2 = c1; /* don't handle range */ for (pc = km_nextkey(pcm, 0); pc < NCHARS; pc = km_nextkey(pcm, pc + 1)) { data_obj *pcobj = km_getkey(pcm, pc); const char *as = pc < elemsof(altseq)? altseq[pc] : NULL; char pckeydescbuf[40]; if (as == NULL) swritef(pckeydescbuf, sizeof(pckeydescbuf), "%s %p %p", pref, PCNONASCII, pc); else swritef(pckeydescbuf, sizeof(pckeydescbuf), "%s %s", pref, as); if (IsKeymap(pcobj)) DescMap((struct keymap *)pcobj, pckeydescbuf); else Typeout("%-18s %s", pckeydescbuf, pcobj->Name); } continue; } #endif /* PCNONASCII */ DescMap((struct keymap *)c1obj, keydescbuf); } else { Typeout("%-18s %s", keydescbuf, c1obj->Name); } } map->mark = NO; } } void DescBindings() { TOstart("Key Bindings"); UnmarkMaps(); DescMap(mainmap, NullStr); DescMap(curbuf->b_map, "Local:"); #ifdef IPROCS DescMap(procsmap, "Proc:"); #endif TOstop(); } private char * fb_aux(cp, map, prefix, buf, room) register const data_obj *cp; struct keymap *map; char *prefix, *buf; size_t room; { char *bufp = buf; if (map != NULL && !map->mark) { ZXchar c1, c2; map->mark = YES; for (c1 = km_nextkey(map, 0); c1 < NCHARS; c1 = km_nextkey(map, c2 + 1)) { data_obj *c1obj = km_getkey(map, c1); c2 = c1; if (c1obj == cp) { do {} while (++c2 < NCHARS && c1obj == km_getkey(map, c2)); c2 -= 1; swritef(bufp, room - (bufp-buf), c1==c2? "%s%p, " : c1+1==c2? "%s{%p,%p}, " : "%s[%p-%p], ", prefix, c1, c2); bufp += strlen(bufp); } if (IsKeymap(c1obj)) { char prefbuf[20]; #ifdef PCNONASCII /* horrible kludge to handle PC non-ASCII keys */ if (c1 == PCNONASCII) { struct keymap *pcm = (struct keymap *)c1obj; ZXchar pc; c2 = c1; /* don't handle range */ for (pc = km_nextkey(pcm, 0); pc < NCHARS; pc = km_nextkey(pcm, pc + 1)) { const char *as = pc < elemsof(altseq)? altseq[pc] : NULL; data_obj *pcobj = km_getkey(pcm, pc); if (pcobj == cp) { if (as == NULL) swritef(bufp, room - (bufp-buf), "%s%p %p, ", prefix, PCNONASCII, pc); else swritef(bufp, room - (bufp-buf), "%s%s, ", prefix, as); bufp += strlen(bufp); } if (IsKeymap(pcobj)) { if (as == NULL) swritef(prefbuf, sizeof(prefbuf), "%s%p %p ", prefix, PCNONASCII, pc); else swritef(prefbuf, sizeof(prefbuf), "%s%s ", prefix, as); bufp = fb_aux(cp, (struct keymap *) pcobj, prefbuf, bufp, room-(bufp-buf)); } } continue; } #endif /* PCNONASCII */ swritef(prefbuf, sizeof(prefbuf), "%s%p ", prefix, c1); bufp = fb_aux(cp, (struct keymap *) c1obj, prefbuf, bufp, room-(bufp-buf)); } } map->mark = NO; } return bufp; } private void find_binds(dp, buf, size) const data_obj *dp; char *buf; size_t size; { char *endp; UnmarkMaps(); buf[0] = '\0'; endp = fb_aux(dp, mainmap, NullStr, buf, size); endp = fb_aux(dp, curbuf->b_map, "Local:", endp, size - (endp - buf)); #ifdef IPROCS endp = fb_aux(dp, procsmap, "Proc:", endp, size - (endp - buf)); #endif if ((endp > buf+2) && (strcmp(endp-2, ", ") == 0)) endp[-2] = '\0'; } private void ShowDoc(doc_type, dp, show_bindings) char *doc_type; const data_obj *dp; jbool show_bindings; { char pattern[100]; char CmdDb[FILESIZE]; File *fp; PathCat(CmdDb, sizeof(CmdDb), ShareDir, "cmds.txt"); fp = open_file(CmdDb, iobuff, F_READ, YES); Placur(ILI, 0); flushscreen(); swritef(pattern, sizeof(pattern), "^:entry \"%s\" \"%s\"$", dp->Name, doc_type); TOstart("Help"); for (;;) { if (f_gets(fp, genbuf, (size_t) LBSIZE)) { Typeout("There is no documentation for \"%s\".", dp->Name); break; } if (genbuf[0] == ':' && LookingAt(pattern, genbuf, 0)) { /* found it ... let's print it */ static const char entrystr[] = ":entry"; if (show_bindings) { char binding[128]; find_binds(dp, binding, sizeof(binding)); if (blnkp(binding)) { Typeout("To invoke %s, type \"ESC X %s\".", dp->Name, dp->Name); } else { Typeout("Type \"%s\" to invoke %s.", binding, dp->Name); } } else Typeout("%s", dp->Name); Typeout(NullStr); while (!f_gets(fp, genbuf, (size_t) LBSIZE) && strncmp(genbuf, entrystr, sizeof(entrystr) - 1) != 0) Typeout("%s", genbuf); break; } } f_close(fp); TOstop(); } void DescCom() { ShowDoc("Command", findcom(ProcFmt), YES); } void DescVar() { ShowDoc("Variable", findvar(ProcFmt), NO); } void Apropos() { register const struct cmd *cp; register struct macro *m; register const struct variable *v; const char *ans; jbool anyfs = NO, anyvs = NO, anyms = NO; char buf[MAXCOLS]; ans = ask((char *) NULL, ": %f (keyword) "); if (strcmp(ans, "?") == 0) ans = NullStr; /* matches everything */ TOstart("Help"); for (cp = commands; cp->Name != NULL && !TOabort; cp++) if (sindex(ans, cp->Name)) { if (!anyfs) { anyfs = YES; Typeout("Commands"); Typeout("--------"); } find_binds((data_obj *) cp, buf, sizeof(buf)); if (buf[0] != '\0') Typeout(": %-35s (%s)", cp->Name, buf); else Typeout(": %s", cp->Name); } for (v = variables; v->Name != NULL && !TOabort; v++) if (sindex(ans, v->Name)) { if (!anyvs) { anyvs = YES; if (anyfs) Typeout(NullStr); Typeout("Variables"); Typeout("---------"); } vpr_aux(v, buf, sizeof(buf)); Typeout(": set %-26s %s", v->Name, buf); } for (m = macros; m != NULL && !TOabort; m = m->m_nextm) if (sindex(ans, m->Name)) { if (!anyms) { anyms = YES; if (anyfs || anyvs) Typeout(NullStr); Typeout("Macros"); Typeout("------"); } find_binds((data_obj *) m, buf, sizeof(buf)); if (buf[0]) Typeout(": %-35s (%s)", m->Name, buf); else Typeout(": %s", m->Name); } TOstop(); } void InitKeymaps() { struct keymap *km; mainmap = km_new(FULL_KEYMAP, MainKeys, "global-map"); /* setup ESC map */ km = km_new(FULL_KEYMAP, EscKeys, "ESC-map"); km_setkey(mainmap, ESC, (data_obj *) km); /* setup Ctlx map */ km = km_new(FULL_KEYMAP, CtlxKeys, "CtlX-map"); km_setkey(mainmap, CTL('X'), (data_obj *) km); #ifdef PCNONASCII km = km_new(FULL_KEYMAP, NonASCIIKeys, "non-ASCII-map"); km_setkey(mainmap, PCNONASCII, (data_obj *) km); #endif #ifdef IPROCS procsmap = km_new(SPARSE_KEYMAP, (data_obj **) NULL, "process-map"); procsmap->unfreeable = YES; BindSequence(procsmap, "\r", 1, (data_obj *) FindCmd(ProcNewline)); #endif } /* * Dispatch a character. If the specified character maps to a sub keymap, * this routine reads more characters until (1) a command is found, or (2) an * unbound key error occurs. Callers of this routine can be assured that it * won't return before completing a key sequence. */ void dispatch(c) ZXchar c; { struct keymap *maps[MAX_KEYMAPS]; int nmaps; if (InMacDefine) note_dispatch(); this_cmd = OTHER_CMD; nmaps = get_keymaps(maps); while (YES) { int i; jbool still_hope = NO; for (i = 0; i < nmaps; i++) { if (maps[i] != NULL) { data_obj *cp = km_getkey(maps[i], c); if (cp != NULL) { if (!IsKeymap(cp)) { ExecCmd(cp); return; } still_hope = YES; } maps[i] = (struct keymap *) cp; } } if (!still_hope) { char strokes[128]; pp_key_strokes(strokes, sizeof(strokes)); s_mess("[%sunbound]", strokes); rbell(); clr_arg_value(); stickymsg = NO; break; } c = waitchar(); if (c == AbortChar) { message("[Aborted]"); rbell(); break; } } } jove-4.17.5.5/keymaps.h000066400000000000000000000037041501102521500145340ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* tables defined in keys.txt/keys.c */ extern data_obj *MainKeys[NCHARS]; extern data_obj *EscKeys[NCHARS]; extern data_obj *CtlxKeys[NCHARS]; #ifdef PCNONASCII extern data_obj *NonASCIIKeys[NCHARS]; #endif #ifdef MAC /* used in About Jove... */ #define F_MAINMAP '\001' #define F_PREF1MAP '\002' #define F_PREF2MAP '\003' #endif #define OTHER_CMD 0 #define ARG_CMD 1 #define LINECMD 2 /* so we can preserve screen col in moves */ #define KILLCMD 3 /* so we can merge kills */ #define YANKCMD 4 /* so we can do yank-pop (ESC Y) */ #define UNDOABLECMD 5 /* so we can do yank-pop to undo */ #define MOUSE_CMD 6 /* to detect other cmds when button is down */ extern int this_cmd; /* ... */ extern int last_cmd; /* last command ... to implement appending to kill buffer */ extern void InitKeymaps proto((void)); extern void dispatch proto((ZXchar c)); extern jbool IsPrefixChar proto((ZXchar c)); extern void DelObjRef proto((data_obj *)); /* Commands: */ extern void Apropos proto((void)); extern void LBindAKey proto((void)); extern void LBindMac proto((void)); extern void LBindMap proto((void)); extern void BindAKey proto((void)); extern void BindMac proto((void)); extern void BindMap proto((void)); extern void DescBindings proto((void)); extern void DescCom proto((void)); extern void DescVar proto((void)); extern void KeyDesc proto((void)); extern void Unbound proto((void)); #ifdef IPROCS extern void PBindAKey proto((void)); extern void PBindMac proto((void)); extern void PBindMap proto((void)); #endif jove-4.17.5.5/keys.txt000066400000000000000000001010151501102521500144200ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* keys.c is derived from keys.txt by setmaps */ /* Only edit keys.txt, not keys.c. * * keys.txt is processed as text by setmaps. This means that what follows * is a very restricted subset of C. * * - Lines beginning with "#if", "#else", and "#endif" are understood * to be the parts of conditional compilation. * They will not be recognized if they are "spelled" differently * (say, with whitespace). Generally, there ought to be the same * number of table entries in each branch of the if. * * - On a Mac, lines begining with "#MENU" are used to specify that * the table is for a menu. * * - Lines begining with a tab followed by a " are treated as table entries. * * - Other lines are passed through, and are assumed to delimit tables. * This means that they must not be within tables. */ #include "jove.h" #include "commands.h" #include "vars.h" /* IDX_TAG do not change this comment: used by setmaps to add cmdidx & varidx */ data_obj *MainKeys[NCHARS] = { "set-mark", /* ^@ */ "beginning-of-line", /* ^A */ "backward-character", /* ^B */ "unbound", /* ^C */ "delete-next-character", /* ^D */ "end-of-line", /* ^E */ "forward-character", /* ^F */ "unbound", /* ^G */ "delete-previous-character", /* ^H */ "handle-tab", /* ^I */ "newline-and-indent", /* ^J */ "kill-to-end-of-line", /* ^K */ "redraw-display", /* ^L */ "newline", /* ^M */ "next-line", /* ^N */ "newline-and-backup", /* ^O */ "previous-line", /* ^P */ "quoted-insert", /* ^Q */ "search-reverse", /* ^R */ "search-forward", /* ^S */ "transpose-characters", /* ^T */ "gather-numeric-argument", /* ^U */ "next-page", /* ^V */ "kill-region", /* ^W */ "unbound", /* ^X */ "yank", /* ^Y */ "scroll-up", /* ^Z */ "unbound", /* ^[ */ #ifdef MAC /* peculiar cursor key codes */ "backward-character", /* ^\ */ "forward-character", /* ^] */ "previous-line", /* ^^ */ "next-line", /* ^_ */ #else "search-forward", /* ^\ */ "find-tag-at-point", /* ^] */ "quoted-insert", /* ^^ */ "unbound", /* ^_ */ #endif "self-insert", /* */ "self-insert", /* ! */ "self-insert", /* " */ "self-insert", /* # */ "self-insert", /* $ */ "self-insert", /* % */ "self-insert", /* & */ "self-insert", /* ' */ "self-insert", /* ( */ "paren-flash", /* ) */ "self-insert", /* * */ "self-insert", /* + */ "self-insert", /* , */ "self-insert", /* - */ "self-insert", /* . */ "self-insert", /* / */ "self-insert", /* 0 */ "self-insert", /* 1 */ "self-insert", /* 2 */ "self-insert", /* 3 */ "self-insert", /* 4 */ "self-insert", /* 5 */ "self-insert", /* 6 */ "self-insert", /* 7 */ "self-insert", /* 8 */ "self-insert", /* 9 */ "self-insert", /* : */ "self-insert", /* ; */ "self-insert", /* < */ "self-insert", /* = */ "self-insert", /* > */ "self-insert", /* ? */ "self-insert", /* @ */ "self-insert", /* A */ "self-insert", /* B */ "self-insert", /* C */ "self-insert", /* D */ "self-insert", /* E */ "self-insert", /* F */ "self-insert", /* G */ "self-insert", /* H */ "self-insert", /* I */ "self-insert", /* J */ "self-insert", /* K */ "self-insert", /* L */ "self-insert", /* M */ "self-insert", /* N */ "self-insert", /* O */ "self-insert", /* P */ "self-insert", /* Q */ "self-insert", /* R */ "self-insert", /* S */ "self-insert", /* T */ "self-insert", /* U */ "self-insert", /* V */ "self-insert", /* W */ "self-insert", /* X */ "self-insert", /* Y */ "self-insert", /* Z */ "self-insert", /* [ */ "self-insert", /* \ */ "paren-flash", /* ] */ "self-insert", /* ^ */ "self-insert", /* _ */ "self-insert", /* ` */ "self-insert", /* a */ "self-insert", /* b */ "self-insert", /* c */ "self-insert", /* d */ "self-insert", /* e */ "self-insert", /* f */ "self-insert", /* g */ "self-insert", /* h */ "self-insert", /* i */ "self-insert", /* j */ "self-insert", /* k */ "self-insert", /* l */ "self-insert", /* m */ "self-insert", /* n */ "self-insert", /* o */ "self-insert", /* p */ "self-insert", /* q */ "self-insert", /* r */ "self-insert", /* s */ "self-insert", /* t */ "self-insert", /* u */ "self-insert", /* v */ "self-insert", /* w */ "self-insert", /* x */ "self-insert", /* y */ "self-insert", /* z */ "self-insert", /* { */ "self-insert", /* | */ "paren-flash", /* } */ "self-insert", /* ~ */ "delete-previous-character" /* ^? */ #if NCHARS != 128 "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ "self-insert", /* ALT- or Option- */ #ifdef PCNONASCII "unbound" /* "PCNONASCII" */ #else "self-insert" /* ALT- or Option- */ #endif #endif /* NCHARS != 128 */ }; data_obj *EscKeys[NCHARS] = { "set-mark", /* ^@ */ "unbound", /* ^A */ "backward-s-expression", /* ^B */ "unbound", /* ^C */ "down-list", /* ^D */ "unbound", /* ^E */ "forward-s-expression", /* ^F */ "unbound", /* ^G */ "unbound", /* ^H */ "unbound", /* ^I */ "unbound", /* ^J */ "kill-s-expression", /* ^K */ "clear-and-redraw", /* ^L */ "unbound", /* ^M */ "forward-list", /* ^N */ "unbound", /* ^O */ "backward-list", /* ^P */ "unbound", /* ^Q */ "unbound", /* ^R */ "unbound", /* ^S */ "unbound", /* ^T */ "backward-up-list", /* ^U */ "page-next-window", /* ^V */ "unbound", /* ^W */ "unbound", /* ^X */ "unbound", /* ^Y */ "unbound", /* ^Z */ "unbound", /* ^[ */ "unbound", /* ^\ */ "unbound", /* ^] */ "unbound", /* ^^ */ "unbound", /* ^_ */ "unbound", /* */ "unbound", /* ! */ "unbound", /* " */ "unbound", /* # */ "unbound", /* $ */ "unbound", /* % */ "unbound", /* & */ "unbound", /* ' */ "unbound", /* ( */ "unbound", /* ) */ "unbound", /* * */ "unbound", /* + */ "beginning-of-window", /* , */ "digit-minus", /* - */ "end-of-window", /* . */ "unbound", /* / */ "digit", /* 0 */ "digit", /* 1 */ "digit", /* 2 */ "digit", /* 3 */ "digit", /* 4 */ "digit", /* 5 */ "digit", /* 6 */ "digit", /* 7 */ "digit", /* 8 */ "digit", /* 9 */ "unbound", /* : */ "unbound", /* ; */ "beginning-of-file", /* < */ "unbound", /* = */ "end-of-file", /* > */ "describe-command", /* ? */ "unbound", /* @ */ "backward-sentence", /* A */ "backward-word", /* B */ "case-word-capitalize", /* C */ "kill-next-word", /* D */ "forward-sentence", /* E */ "forward-word", /* F */ "goto-line", /* G */ "unbound", /* H */ "make-macro-interactive", /* I */ "fill-paragraph", /* J */ "kill-to-end-of-sentence", /* K */ "case-word-lower", /* L */ "first-non-blank", /* M */ "unbound", /* N */ "unbound", /* O */ "unbound", /* P */ "query-replace-string", /* Q */ "replace-string", /* R */ #ifdef JOB_CONTROL "pause-jove", /* S */ #else "unbound", /* S */ #endif "unbound", /* T */ "case-word-upper", /* U */ "previous-page", /* V */ "copy-region", /* W */ "execute-named-command", /* X */ "yank-pop", /* Y */ "scroll-down", /* Z */ "backward-paragraph", /* [ */ "delete-white-space", /* \ */ "forward-paragraph", /* ] */ "unbound", /* ^ */ "unbound", /* _ */ "unbound", /* ` */ "backward-sentence", /* a */ "backward-word", /* b */ "case-word-capitalize", /* c */ "kill-next-word", /* d */ "forward-sentence", /* e */ "forward-word", /* f */ "goto-line", /* g */ "unbound", /* h */ "make-macro-interactive", /* i */ "fill-paragraph", /* j */ "kill-to-end-of-sentence", /* k */ "case-word-lower", /* l */ "first-non-blank", /* m */ "unbound", /* n */ "unbound", /* o */ "unbound", /* p */ "query-replace-string", /* q */ "replace-string", /* r */ #ifdef JOB_CONTROL "pause-jove", /* s */ #else "unbound", /* s */ #endif "unbound", /* t */ "case-word-upper", /* u */ "previous-page", /* v */ "copy-region", /* w */ "execute-named-command", /* x */ "yank-pop", /* y */ "scroll-down", /* z */ "unbound", /* { */ "unbound", /* | */ "unbound", /* } */ "make-buffer-unmodified", /* ~ */ "kill-previous-word" /* ^? */ #if NCHARS != 128 "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound" /* ALT- or Option- */ #endif /* NCHARS != 128 */ }; data_obj *CtlxKeys[NCHARS] = { "unbound", /* ^@ */ "unbound", /* ^A */ "list-buffers", /* ^B */ "exit-jove", /* ^C */ "unbound", /* ^D */ #ifdef SUBSHELL "compile-it", /* ^E */ #else "unbound" /* ^E */ #endif "find-file", /* ^F */ "unbound", /* ^G */ "unbound", /* ^H */ "insert-file", /* ^I */ "unbound", /* ^J */ "unbound", /* ^K */ "unbound", /* ^L */ "write-modified-files", /* ^M */ "next-error", /* ^N */ "delete-blank-lines", /* ^O */ "previous-error", /* ^P */ "unbound", /* ^Q */ "visit-file", /* ^R */ "save-file", /* ^S */ "transpose-lines", /* ^T */ "unbound", /* ^U */ "visit-file", /* ^V */ "write-file", /* ^W */ "exchange-point-and-mark", /* ^X */ "unbound", /* ^Y */ "unbound", /* ^Z */ "unbound", /* ^[ */ "save-file", /* ^\ */ "unbound", /* ^] */ "unbound", /* ^^ */ "unbound", /* ^_ */ "unbound", /* */ #ifdef SUBSHELL "shell-command", /* ! */ #else "unbound" /* ! */ #endif "unbound", /* " */ "unbound", /* # */ "unbound", /* $ */ "unbound", /* % */ "unbound", /* & */ "unbound", /* ' */ "begin-kbd-macro", /* ( */ "end-kbd-macro", /* ) */ "unbound", /* * */ "unbound", /* + */ "unbound", /* , */ "unbound", /* - */ "unbound", /* . */ "unbound", /* / */ "unbound", /* 0 */ "delete-other-windows", /* 1 */ "split-current-window", /* 2 */ "unbound", /* 3 */ "window-find", /* 4 */ "unbound", /* 5 */ "unbound", /* 6 */ "unbound", /* 7 */ "unbound", /* 8 */ "unbound", /* 9 */ "unbound", /* : */ "unbound", /* ; */ "unbound", /* < */ "unbound", /* = */ "unbound", /* > */ "describe-key", /* ? */ "unbound", /* @ */ "unbound", /* A */ "select-buffer", /* B */ "unbound", /* C */ "delete-current-window", /* D */ "execute-kbd-macro", /* E */ "unbound", /* F */ "unbound", /* G */ "unbound", /* H */ "unbound", /* I */ "unbound", /* J */ "delete-buffer", /* K */ "unbound", /* L */ "unbound", /* M */ "next-window", /* N */ "previous-window", /* O */ "previous-window", /* P */ "unbound", /* Q */ "unbound", /* R */ "save-file", /* S */ "find-tag", /* T */ "unbound", /* U */ "unbound", /* V */ "unbound", /* W */ "unbound", /* X */ "unbound", /* Y */ "unbound", /* Z */ "unbound", /* [ */ "unbound", /* \ */ "unbound", /* ] */ "grow-window", /* ^ */ "unbound", /* _ */ "unbound", /* ` */ "unbound", /* a */ "select-buffer", /* b */ "unbound", /* c */ "delete-current-window", /* d */ "execute-kbd-macro", /* e */ "unbound", /* f */ "unbound", /* g */ "unbound", /* h */ "unbound", /* i */ "unbound", /* j */ "delete-buffer", /* k */ "unbound", /* l */ "unbound", /* m */ "next-window", /* n */ "previous-window", /* o */ "previous-window", /* p */ "unbound", /* q */ "unbound", /* r */ "save-file", /* s */ "find-tag", /* t */ "unbound", /* u */ "unbound", /* v */ "unbound", /* w */ "unbound", /* x */ "unbound", /* y */ "unbound", /* z */ "unbound", /* { */ "unbound", /* | */ "unbound", /* } */ "unbound", /* ~ */ "kill-to-beginning-of-sentence" /* ^? */ #if NCHARS != 128 "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound", /* ALT- or Option- */ "unbound" /* ALT- or Option- */ #endif /* NCHARS != 128 */ }; #ifdef PCNONASCII /* These are codes generated by non-ASCII keys on an IBM-PC keyboard. * Codes marked with [E] are only generated by enhanced keyboards. * The codes 171 to 183 are synthesized by JOVE when it detects * shift + a code in 71 to 83. */ data_obj *NonASCIIKeys[NCHARS] = { "unbound", /* ^Break 0 */ "unbound", /* alt Esc [E] */ "unbound", "unbound", /* [^@ and ^Space mapped to ASCII NUL] */ "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", /* 10 */ "unbound", "unbound", "unbound", "unbound", /* alt BackSpace [E] */ "unbound", /* shift Tab (BackTab) */ "query-replace-string", /* alt q */ "copy-region", /* alt w */ "forward-sentence", /* alt e */ "replace-string", /* alt r */ "unbound", /* alt t 20 */ "yank-pop", /* alt y */ "case-word-upper", /* alt u */ "make-macro-interactive", /* alt i */ "unbound", /* alt o */ "unbound", /* alt p */ "unbound", /* alt [ [E] */ "unbound", /* alt ] [E] */ "unbound", /* alt Return [E] */ "unbound", "backward-sentence", /* alt a 30 */ "unbound", /* alt s */ "kill-next-word", /* alt d */ "forward-word", /* alt f */ "goto-line", /* alt g */ "unbound", /* alt h */ "fill-paragraph", /* alt j */ "kill-to-end-of-sentence", /* alt k */ "case-word-lower", /* alt l */ "unbound", /* alt ; [E] */ "unbound", /* alt ' [E] 40 */ "unbound", /* alt ` [E] */ "unbound", "unbound", /* alt \ [E] */ "scroll-down", /* alt z */ "execute-named-command", /* alt x */ "case-word-capitalize", /* alt c */ "previous-page", /* alt v */ "backward-word", /* alt b */ "unbound", /* alt n */ "first-non-blank", /* alt m 50 */ "unbound", /* alt , [E] */ "unbound", /* alt . [E] */ "unbound", /* alt / [E] */ "unbound", "unbound", /* alt keypad* [E] */ "unbound", "unbound", "unbound", "unbound", /* F1 */ "unbound", /* F2 60 */ "unbound", /* F3 */ "unbound", /* F4 */ "unbound", /* F5 */ "unbound", /* F6 */ "unbound", /* F7 */ "unbound", /* F8 */ "unbound", /* F9 */ "unbound", /* F10 */ "unbound", "unbound", /* 70 */ "beginning-of-line", /* Home */ "previous-line", /* Up */ "previous-page", /* PgUp */ "unbound", /* alt keypad- [E] */ "backward-character", /* Left */ "unbound", "forward-character", /* Right*/ "unbound", /* alt keypad+ [E] */ "end-of-line", /* End */ "next-line", /* Down 80 */ "next-page", /* PgDn */ "over-write-mode", /* Ins */ "unbound", /* [Del mapped to ASCII DEL] */ "unbound", /* shift F1 */ "unbound", /* shift F2 */ "unbound", /* shift F3 */ "unbound", /* shift F4 */ "unbound", /* shift F5 */ "unbound", /* shift F6 */ "unbound", /* shift F7 90 */ "unbound", /* shift F8 */ "unbound", /* shift F9 */ "unbound", /* shift F10 */ "unbound", /* ^F1 */ "unbound", /* ^F2 */ "unbound", /* ^F3 */ "unbound", /* ^F4 */ "unbound", /* ^F5 */ "unbound", /* ^F6 */ "unbound", /* ^F7 100 */ "unbound", /* ^F8 */ "unbound", /* ^F9 */ "unbound", /* ^F10*/ "unbound", /* alt F1 */ "unbound", /* alt F2 */ "unbound", /* alt F3 */ "unbound", /* alt F4 */ "unbound", /* alt F5 */ "unbound", /* alt F6 */ "unbound", /* alt F7 110 */ "unbound", /* alt F8 */ "unbound", /* alt F9 */ "unbound", /* alt F10 */ "unbound", /* ^PrtScrn */ "backward-word", /* ^Left */ "forward-word", /* ^Right */ "end-of-file", /* ^End */ "next-window", /* ^PgDn */ "beginning-of-file", /* ^Home */ "select-buffer-1", /* alt 1 120 */ "select-buffer-2", /* alt 2 */ "select-buffer-3", /* alt 3 */ "select-buffer-4", /* alt 4 */ "select-buffer-5", /* alt 5 */ "select-buffer-6", /* alt 6 */ "select-buffer-7", /* alt 7 */ "select-buffer-8", /* alt 8 */ "select-buffer-9", /* alt 9 */ "select-buffer-10", /* alt 0 */ "unbound", /* alt - 130 */ "unbound", /* alt = */ "previous-window", /* ^PgUp */ "unbound", /* F11 [E] */ "unbound", /* F12 [E] */ "unbound", /* Shift F11 [E] */ "unbound", /* Shift F12 [E] */ "unbound", /* ^F11 [E] */ "unbound", /* ^F12 [E] */ "unbound", /* alt F11 [E] */ "unbound", /* alt F12 [E] 140 */ "unbound", /* ^Up [E] */ "unbound", /* ^keypad- [E] */ "unbound", /* ^keypad5 [E] */ "unbound", /* ^keypad+ [E] */ "unbound", /* ^Down [E] */ "unbound", /* ^Ins [E] */ "unbound", /* ^Del [E] */ "unbound", /* ^Tab [E] */ "unbound", /* ^keypad/ [E] */ "unbound", /* ^keypad* [E] 150 */ "unbound", /* alt Home [E] */ "unbound", /* alt Up [E] */ "unbound", /* alt PgUp [E] */ "unbound", "unbound", /* alt Left [E] */ "unbound", "unbound", /* alt Right [E] */ "unbound", "unbound", /* alt End [E] */ "unbound", /* alt Down [E] 160 */ "unbound", /* alt PgDn [E] */ "unbound", /* alt Ins [E] */ "unbound", /* alt Del [E] */ "unbound", /* alt keypad/ [E] */ "unbound", /* alt Tab [E] */ "unbound", /* alt Enter [E] */ "unbound", "unbound", "unbound", "unbound", /* 170 */ "unbound", /* shift Home */ "unbound", /* shift Up */ "unbound", /* shift PgUp */ "unbound", /* shift alt keypad- [E] */ "unbound", /* shift Left */ "unbound", "unbound", /* shift Right */ "unbound", /* shift alt keypad+ [E] */ "unbound", /* shift End */ "unbound", /* shift Down 180 */ "unbound", /* shift PgDn */ "unbound", /* shift Ins */ "unbound", /* shift Del */ "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound", "unbound" }; #endif /* PCNONASCII */ jove-4.17.5.5/list.c000066400000000000000000000020121501102521500140200ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "list.h" private List * list_new() { List *new; new = (List *) emalloc(sizeof (List)); new->car = NULL; return new; } /* push an object to the beginning of list */ UnivPtr list_push(list, element) register List **list; UnivPtr element; { List *new; new = list_new(); new->cdr = *list; new->car = element; *list = new; return element; } UnivPtr list_pop(list) List **list; { List *cell = *list; UnivPtr element; if (cell == NULL) return NULL; element = cell->car; *list = cell->cdr; free((UnivPtr) cell); return element; } jove-4.17.5.5/list.h000066400000000000000000000013521501102521500140330ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* generic singly linked list package */ typedef struct cons List; struct cons { UnivPtr car; /* pointer to element */ List *cdr; }; #define list_next(lp) ((lp)->cdr) #define list_data(lp) ((lp)->car) extern UnivPtr list_push proto((List **, UnivPtr)), list_pop proto((List **)); jove-4.17.5.5/mac.c000066400000000000000000001612261501102521500136220ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* (C) 1986, 1987, 1988 Ken Mitchum. This code is intended only for use with Jove. */ /* This code is not needed for MacOS X onwards, i.e any modern Mac, * on which Jove's classic UNIX/POSIX code works well, as of 4.17. * All #ifdef MAC is will be removed in a future version of Jove, * unless someone volunteers to test it. * * This code was last tested since 1995 December, when D. Hugh Redelmeier * hacked on the code to make it work on Think C 5.0 under System 7.1. * * Obligatory excuses: * - Hugh is not a Mac expert * - Think C 5.0 is quite obsolete (1991) * - The only goal was to get the code working, not working well. * * Known issues: * - the keyboard routines were designed for the Mac Plus keyboard. * + "Command" is taken as "Control" and ` is taken as ESC. * + There should be support for a distinct Command keymap * with Mac-like default bindings. * - "macify" ought to be extended to find-file and perhaps * other commands * - perhaps there are newer MacOS facilities that ought to be * exploited. Apple Events? * - the hacky way the command keystrokes are described in About Jove * ought to be improved. * - Highlighting ought to be supported. * - Mouse support ought to be better. For example, selecting text * ought to be at least as well done as under XTerm! * - [supposition] Because double-clicking is supported, nothing * is done for a single click until the double-click timeout * happens. Since the double-click action is a superset of * the single-click action, the single click action ought to * be immediately performed and then augmented if a double-click * happens. * - see also comments containing ??? */ #include "tune.h" #ifdef MAC /* the body is the rest of this file */ #include "jove.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mac.h" #include "ask.h" #include "chars.h" #include "disp.h" #include "extend.h" #include "fp.h" /* for flushscreen() */ #include "commands.h" #include "fmt.h" #include "marks.h" #include "misc.h" #include "move.h" #include "screen.h" #include "scandir.h" #include "term.h" #include "vars.h" #include "version.h" #include "wind.h" extern struct menu Menus[NMENUS]; /* from menumaps.txt => menumaps.c */ private EventRecord the_Event; private void SetBounds proto((void)); private void Set_std proto((void)); private void Reset_std proto((void)); private jbool findtext proto((void)); /* tn.h Modified for variable screen size 11/21/87. K. Mitchum */ #define SCREENSIZE (wc->w_rows * ROWSIZE) #define FONT monaco #define TEXTSIZE 9 #define HEIGHT 11 #define WIDTH 6 #define DESCENT 2 #define TWIDTH CO * WIDTH #define THEIGHT LI * HEIGHT /* window specs */ #define SCROLLWIDTH 16 /* width of scroll bar control in pixels */ #define WINDWIDTH (wc->w_width - SCROLLWIDTH + 1) /* local coordinates */ #define WINDHEIGHT (wc->w_height) /* local coordinates */ #define MAXROW ILI #define MAXCOL (CO - 1) /* for keyboard routines */ #define MCHARS 32 /* length of circular buffer -- must be a power of two */ #define NCHMASK (MCHARS - 1) /* mask for modulo MCHARS */ /***************************************************/ private void putcurs proto((unsigned row, unsigned col, jbool vis)), curset proto((jbool desired)), dellines proto((int n, int bot)), inslines proto((int n, int bot)); private Rect LimitRect; /* bounds we can't move past */ struct wind_config { int w_width; /* pixel width of the Mac window */ int w_height; int w_rows; /* rows of characters which fit the window */ int w_cols; } wc_std, wc_user, *wc; private WindowPtr theScreen; jbool Windchange, EventCmd, Keyonly, Bufchange, Modechange; jbool Macmode = NO; /* VAR: use Mac file selector */ /* Initialization Routines. */ void getTERM() { } /* For each binding, mark the command with the binding. * We use it for "About Jove ...". * ??? This is faster than using find_binds, but it has problems: * - it only notes the last binding of each command * - it only reflects the three listed keymaps * - it requires a wart on struct cmd * - it is MAC-only */ private void InitMapBinds(km, kmc) data_obj **km; char kmc; { ZXchar i; for (i = 0; i < NCHARS; i++) { if (*km != NULL && obj_type(*km) == COMMAND) { struct cmd *c = (struct cmd *) *km; c->c_map = kmc; c->c_key = i; } km += 1; } } private void InitBinds() { InitMapBinds(MainKeys, F_MAINMAP); InitMapBinds(EscKeys, F_PREF1MAP); InitMapBinds(CtlxKeys, F_PREF2MAP); } private WindowPtr window; private Rect r; private CursHandle cross; private void InitSysMenu proto((void)); void InitEvents() { window = theScreen; InitSysMenu(); SetRect(&r, window->portRect.left, window->portRect.top, window->portRect.right - SCROLLWIDTH, window->portRect.bottom - SCROLLWIDTH); cross = GetCursor(crossCursor); } private void tn_init proto((void)); private int getdir proto((void)); void MacInit() { tn_init(); getdir(); strcpy(TmpDir, gethome()); strcpy(ShareDir, TmpDir); InitBinds(); } void ttysetattr(n) jbool n; /* also used as subscript! */ { } /* Surrogate unix-style file i/o routines for Jove. These replace the * routines distributed in the libraries. They work with Jove, but may * not be general enough for other purposes. */ #define NFILES 10 private int cur_vol; /* Disk or volume number */ private long cur_dir; /* Directory number */ private int cur_vref; /* ugh.. Vref for volume + directory */ struct ftab { jbool inuse; int refnum; /* Mac file reference number */ } ft[NFILES]; private void fsetup(p) HParmBlkPtr p; { byte_zero(p, sizeof(HParamBlockRec)); p->fileParam.ioVRefNum = cur_vol; p->fileParam.ioDirID = cur_dir; /* p->fileParam.ioFVersNum = 0; */ } private void isetup(p) IOParam *p; { byte_zero(p, sizeof(IOParam)); p->ioVRefNum = cur_vol; } /* Kludge to convert Macintosh error codes to something like Unix. */ private int cvt_err(err) /* some of these don't make sense... */ int err; { switch(err) { case noErr: errno = 0; return 0; case dirFulErr: case dskFulErr: errno = ENOSPC; break; /* case nsvErr: */ /* case mFulErr: */ /* case tmfoErr: */ /* case fnfErr: */ default: errno = ENOENT; break; case ioErr: errno = EIO; break; case bdNamErr: case opWrErr: case paramErr: errno = EINVAL; break; case fnOpnErr: /* dubious... */ case rfNumErr: errno = EBADF; break; case eofErr: /* ditto */ case posErr: errno = /* no longer defined: ESPIPE */ EIO; break; case wPrErr: errno = EROFS; break; case fLckdErr: case permErr: errno = EACCES; break; case fBsyErr: errno = EBUSY; break; case dupFNErr: errno = EEXIST; break; case gfpErr: case volOffLinErr: case volOnLinErr: case nsDrvErr: errno = ENODEV; break; case noMacDskErr: case extFSErr: errno = EIO; break; case fsRnErr: case badMDBErr: case wrPermErr: errno = /* no longer defined: EPERM */ EACCES; break; } return -1; } private StringPtr cvt_fnm(file) const char *file; { static char nm[255]; char *t; if (*file == '/') { strcpy(nm, file + 1); /* full path */ } else { if (strchr(file + 1, '/') != NULL) strcpy(nm, "/"); /* make a partial pathname */ else nm[0] = '\0'; strcat(nm, file); } for (t = nm; (t = strchr(t, '/')) != NULL; ) *t++ = ':'; return CtoPstr(nm); } private int do_creat proto((HParmBlkPtr p, StringPtr nm)); int creat(name, perm) const char *name; jmode_t perm; /* perm is irrelevant on a Mac */ { int fd, err; StringPtr nm; HParamBlockRec p; nm = cvt_fnm(name); /* convert filename to Mac type name */ for (fd = 0; ft[fd].inuse; fd++) { if (fd == NFILES-1) { errno = EMFILE; return -1; } } fsetup(&p); /* try to delete it, whether it is there or not. */ p.fileParam.ioNamePtr = nm; if ((err = PBHDelete(&p, 0)) != noErr && err != fnfErr) return cvt_err(err); if (do_creat(&p, nm) != 0) return -1; ft[fd].inuse = YES; ft[fd].refnum = p.ioParam.ioRefNum; return fd + 1; } #ifdef USE_PROTOTYPES int open(const char *path, int flags, ...) #else int open(path, flags) const char *path; int flags; #endif { int fd, err; StringPtr nm; HParamBlockRec p; nm = cvt_fnm(path); /* convert filename to Mac type name */ for (fd = 0; ft[fd].inuse; fd++) { if (fd == NFILES-1) { errno = EMFILE; return -1; } } fsetup(&p); switch (flags & 03) { case O_RDONLY: p.ioParam.ioPermssn = fsRdPerm; break; case O_WRONLY: p.ioParam.ioPermssn = fsWrPerm; break; case O_RDWR: p.ioParam.ioPermssn = fsRdWrPerm; break; } p.ioParam.ioNamePtr = nm; p.ioParam.ioMisc = 0; if ((err = PBHOpen(&p, 0)) != noErr) return cvt_err(err); ft[fd].refnum = p.ioParam.ioRefNum; p.ioParam.ioPosMode = fsFromStart; p.ioParam.ioPosOffset = 0; if ((err = PBSetFPos((ParamBlockRec *) &p, 0)) != noErr) return cvt_err(err); ft[fd].inuse = YES; errno = 0; return fd + 1; } private int do_creat(p, nm) HParmBlkPtr p; StringPtr nm; { int err; fsetup(p); p->fileParam.ioNamePtr = nm; if ((err = PBHCreate(p, 0)) != noErr) return cvt_err(err); fsetup(p); p->fileParam.ioNamePtr = nm; p->fileParam.ioFDirIndex = 0; if ((err = PBHGetFInfo(p, 0)) != noErr) return cvt_err(err); p->fileParam.ioDirID = cur_dir; p->fileParam.ioFlFndrInfo.fdType = 'TEXT'; p->fileParam.ioFlFndrInfo.fdCreator = 'JV01'; p->fileParam.ioFlFndrInfo.fdFlags = 0; p->fileParam.ioFVersNum = 0; if ((err = PBHSetFInfo(p, 0)) != noErr) return cvt_err(err); fsetup(p); p->ioParam.ioNamePtr = nm; p->ioParam.ioPermssn = fsRdWrPerm; p->ioParam.ioMisc = 0; if (cvt_err(PBHOpen(p, 0))) return -1; return 0; } int close(fd) int fd; { int err; HParamBlockRec p; if (!ft[--fd].inuse) { errno = EBADF; return -1; } fsetup(&p); p.ioParam.ioRefNum = ft[fd].refnum; ft[fd].inuse = NO; if (cvt_err(PBClose((ParamBlockRec *) &p, 0)) < 0) return -1; fsetup(&p); p.ioParam.ioNamePtr = NULL; if (cvt_err(PBFlushVol((ParamBlockRec *) &p, 0)) < 0) return -1; return 0; } private JSSIZE_T con_read proto((char *buf, size_t size)); /* Raw UNIX-like read */ JSSIZE_T read(fd, ubuf, n) int fd; UnivPtr ubuf; size_t n; { char *buf = ubuf; /* char * is more useful */ int err; IOParam p; if (fd == 0) { return con_read(buf, n); } else { if (!ft[--fd].inuse) { errno = EBADF; return -1; } isetup(&p); p.ioRefNum = ft[fd].refnum; p.ioBuffer = buf; p.ioReqCount = n; p.ioPosMode = fsFromMark; p.ioPosOffset = 0; if ((err = PBRead((ParamBlockRec *)&p, 0)) != noErr && err != eofErr) return cvt_err(err); errno = 0; return p.ioActCount; } } /* Raw UNIX-like write */ JSSIZE_T write(fd, ubuf, n) int fd; UnivConstPtr ubuf; size_t n; { const char *buf = ubuf; /* char * is more convenient */ if (fd == 0) { writetext((unsigned char *)buf, n); return n; } else { IOParam p; int err; const char *ebuf = buf + n; if (!ft[--fd].inuse) { errno = EBADF; return -1; } isetup(&p); p.ioRefNum = ft[fd].refnum; p.ioPosMode = fsFromMark; p.ioReqCount = n; p.ioBuffer = (Ptr)buf; p.ioPosOffset = 0L; /* bidirectional */ if ((err = PBWrite((ParamBlockRec *)&p, 0)) != noErr) return cvt_err(err); return p.ioActCount; } } long lseek(fd, offset, whence) int fd; off_t offset; int whence; { int err; long cur_mark, leof, new_mark; IOParam p; if (!ft[--fd].inuse) { errno = EBADF; return -1; } isetup(&p); p.ioRefNum = ft[fd].refnum; if ((err = PBGetFPos((ParamBlockRec *)&p, 0)) != noErr) return cvt_err(err); cur_mark = p.ioPosOffset; isetup(&p); p.ioRefNum = ft[fd].refnum; if ((err = PBGetEOF((ParamBlockRec *)&p, 0)) != noErr) return cvt_err(err); leof = (long) p.ioMisc; switch(whence) { case 0: new_mark = offset; break; case 1: new_mark = offset + cur_mark; break; case 2: new_mark = offset + leof; break; default: errno = EINVAL; return -1; } if (new_mark > leof) { /* need more space in file -- grow it */ isetup(&p); p.ioRefNum = ft[fd].refnum; p.ioMisc = (Ptr) new_mark; if ((err = PBSetEOF((ParamBlockRec *)&p, 0)) != noErr) return cvt_err(err); } isetup(&p); p.ioRefNum = ft[fd].refnum; p.ioPosOffset = new_mark; p.ioPosMode = fsFromStart; if ((err = PBSetFPos((ParamBlockRec *)&p, 0)) != noErr) return cvt_err(err); errno = 0; return p.ioPosOffset; } /* delete file, if it exists */ int unlink(name) const char *name; { int fd, err; HParamBlockRec p; fsetup(&p); p.fileParam.ioNamePtr = cvt_fnm(name); if ((err = PBHDelete(&p, 0)) != noErr && err != fnfErr) return cvt_err(err); return 0; } /* Console read routine */ private ZXchar rawgetc proto((void)); private JSSIZE_T con_read(buf, size) char *buf; size_t size; { size_t n; ZXchar p; n = 0; do { p = rawgetc(); *buf++ = p; n++; } while (rawchkc() && n <= size); return n; } void dobell(n) /* declared in term.h */ int n; { while (--n >= 0) SysBeep(5); flushscreen(); } /* Simplified stat() routine emulates what is needed most. */ int stat(fname, buf) const char *fname; struct stat *buf; { CInfoPBRec p; StringPtr nm; nm = cvt_fnm(fname); byte_zero(&p, sizeof(CInfoPBRec)); p.hFileInfo.ioCompletion = 0; p.hFileInfo.ioNamePtr = nm; p.hFileInfo.ioFVersNum = 0; p.hFileInfo.ioFDirIndex = 0; p.hFileInfo.ioVRefNum = cur_vol; p.hFileInfo.ioDirID = cur_dir; switch (PBGetCatInfo(&p, 0)) { case noErr: errno = 0; buf->st_dev = p.hFileInfo.ioVRefNum + 1; /* don't want 0 */ buf->st_ino = p.hFileInfo.ioDirID; buf->st_size = p.hFileInfo.ioFlLgLen; buf->st_mtime = p.hFileInfo.ioFlMdDat; buf->st_mode = (p.hFileInfo.ioFlAttrib & 0x10) ? S_IFDIR : S_IFREG; return 0; case nsvErr: case paramErr: case bdNamErr: case fnfErr: errno = ENOENT; break; case ioErr: errno = EIO; break; default: errno = ENOENT; break; } return -1; } /* Directory related routines. Jove keeps track of the true Volume (disk) * number and directory number, and avoids "Working Directory Reference * Numbers", which are confusing. */ private int getdir() /* call this only once, during startup. */ { WDPBRec p; p.ioCompletion = 0; p.ioNamePtr = NULL; if (PBHGetVol(&p, 0) != noErr) return -1; /* BIG trouble (but caller never checks returned value!) */ cur_vol = p.ioWDVRefNum; cur_dir = p.ioWDDirID; SFSaveDisk = 0 - cur_vol; /* these are for SF dialogs */ CurDirStore = cur_dir; return 0; } private int setdir(vol, dir) int vol; long dir; { WDPBRec p; p.ioCompletion = 0; p.ioNamePtr = NULL; p.ioVRefNum = vol; p.ioWDDirID = dir; if (PBHSetVol(&p, 0) != noErr) return -1; cur_vol = vol; cur_dir = dir; SFSaveDisk = 0 - vol; /* these are for SF dialogs */ CurDirStore = dir; return 0; } private jbool lookupdir(dir, d) const char *dir; /* UNIX-like pathname for directory */ CInfoPBPtr d; /* info from directory */ { char nm[FILESIZE + 1], *t; if (strcmp(dir, ".") == 0) getcwd(nm, sizeof(nm) - 1); else strcpy(nm, dir); for (t = nm; (t = strchr(t, '/')) != NULL; ) *t++ = ':'; t = nm; /* get rid of initial slashes */ while (*t == ':') t++; strcat(t, ":"); /* force trailing ':', signifying directory */ byte_zero(d, sizeof(*d)); /* d->dirInfo.ioCompletion = 0; */ d->dirInfo.ioNamePtr = CtoPstr(t); d->dirInfo.ioVRefNum = cur_vol; /* d->dirInfo.ioFDirIndex = 0; */ /* d->dirInfo.ioDrDirID = 0; */ PBGetCatInfo(d, 0); return d->dirInfo.ioResult == noErr && (d->dirInfo.ioFlAttrib & 0x10) != 0; } int chdir(dir) const char *dir; { CInfoPBRec d; if (strcmp(dir, "/") == 0 /* There is no root... */ || !lookupdir(dir, &d) || setdir(d.dirInfo.ioVRefNum, d.dirInfo.ioDrDirID) < 0) return -1; return 0; } /* Scandir returns the number of entries or -1 if the directory cannot * be opened or malloc fails. * Note: if we ever support RECOVER, this code will have to be moved * to scandir.c */ int jscandir(dir, nmptr, qualify, sorter) const char *dir; char ***nmptr; jbool (*qualify) ptrproto((char *)); int (*sorter) ptrproto((UnivConstPtr, UnivConstPtr)); { long DirID; char **ourarray; unsigned int nalloc = 10, nentries = 0, index = 1; if (strcmp(dir, "/") == 0) { /* we are enumerating volumes */ DirID = 0; } else { /* we are enumerating the contents of a volume or directory */ CInfoPBRec d; if (!lookupdir(dir, &d)) return -1; DirID = d.dirInfo.ioDrDirID; } ourarray = (char **) emalloc(nalloc * sizeof (char *)); for (;;) { Str32 name; /* 31 is limit, but we might add a '/' */ if (DirID == 0) { /* we are enumerating volumes */ ParamBlockRec d; byte_zero(&d, sizeof(d)); d.volumeParam.ioCompletion = 0; d.volumeParam.ioNamePtr = name; d.volumeParam.ioVRefNum = 0; d.volumeParam.ioVolIndex = index++; if (PBGetVInfo(&d, 0) != noErr) break; /* we are done, then */ PtoCstr(name); #ifdef DIRECTORY_ADD_SLASH /* I *think* this has got to be a volume */ strcat((char *)name, "/"); #endif } else { /* we are enumerating the contents of a volume or directory */ CInfoPBRec d; byte_zero(&d, sizeof(d)); d.dirInfo.ioCompletion = 0; d.dirInfo.ioNamePtr = name; d.dirInfo.ioVRefNum = cur_vol; d.dirInfo.ioFDirIndex = index++; d.dirInfo.ioDrDirID = DirID; /* .ioDirID == .ioDrDirID */ if (PBGetCatInfo(&d, 0) != noErr) break; /* we are done, then */ PtoCstr(name); #ifdef DIRECTORY_ADD_SLASH if (d.dirInfo.ioFlAttrib & 0x10) /* see Inside Mac IV-122 */ strcat((char *)name, "/"); #endif } if (qualify != NULL && !(*qualify)((char *) name)) continue; /* note: test ensures one space left in ourarray for NULL */ if (nentries+1 == nalloc) ourarray = (char **) erealloc((char *) ourarray, (nalloc += 10) * sizeof (char *)); ourarray[nentries++] = copystr((char *)name); } ourarray[nentries] = NULL; if (sorter != NULL) qsort((char *) ourarray, nentries, sizeof (char **), sorter); *nmptr = ourarray; return nentries; } char * getcwd(buf, size) char *buf; size_t size; { CInfoPBRec d; Str31 nm; char *p = buf + size; /* build from right */ if (p == buf) return NULL; /* not even room for NUL */ *--p = '\0'; for (d.dirInfo.ioDrDirID = cur_dir; ; d.dirInfo.ioDrDirID = d.dirInfo.ioDrParID) { d.dirInfo.ioCompletion = 0; d.dirInfo.ioNamePtr = nm; d.dirInfo.ioVRefNum = cur_vol; d.dirInfo.ioFDirIndex = -1; PBGetCatInfo(&d, 0); if (d.dirInfo.ioResult != noErr) return NULL; if (p - buf <= Length(nm)) return NULL; /* insufficient room for / and name */ p -= Length(nm); memcpy((UnivPtr)p, (UnivPtr) (nm+1), Length(nm)); *--p = '/'; if (d.dirInfo.ioDrDirID == 2) break; /* home directory */ } /* strcpy(buf, p) won't do because the destination overlaps the source */ memmove((UnivPtr)buf, (UnivPtr)p, buf + size - p); /* left justify */ return buf; } char * gethome() /* this will be startup directory */ { static char *ret = NULL; char space[FILESIZE]; if (ret == NULL) ret = copystr(getcwd(space, sizeof(space))); return ret; } /* Routines that put up and manipulate the "About Jove" dialog. */ /* (ORIGINALLY IN) about_j.c. */ #define DLOGNAME "\pABOUT_JDLOG" #define DONE_ITEM 1 #define LIST_ITEM 2 #define DWIDTH 460 /* there should be an easy way to get this */ #define DHEIGHT 240 /* from the resource file! */ WindowPtr makedisplay(); ListHandle makelist(); private WindowPtr theWindow; private ListHandle theList; private Rect theListRect; private EventRecord theEvent; private void do_list proto((void)), do_events proto((void)); private WindowPtr makedisplay proto((void)); private ListHandle makelist proto((void)); private void about_j() { WindowPtr OldWindow; GetPort(&OldWindow); if ((theWindow = makedisplay()) == 0) return; SetPort(theWindow); if (theList = makelist()) { LActivate(1, theList); do_list(); ShowWindow(theWindow); do_events(); } SetPort(OldWindow); LDispose(theList); DisposDialog(theWindow); } private WindowPtr makedisplay() { static short dlogid = 0; DialogPtr theDialog; Handle theHandle; Handle theResource; Str255 buf; ResType resType; short itemType; Rect theRect; short dh, dv; /* to center dialog on the screen */ Str255 nostring; if (dlogid == 0) { if ((theResource = GetNamedResource('DLOG', DLOGNAME)) == NULL) return (WindowPtr)NULL; itemType = 'DLOG'; GetResInfo(theResource, &dlogid, &resType, buf); } theDialog = GetNewDialog(dlogid, 0L, (WindowPtr) -1); nostring[0] = 0; /* set length of Pascal String to 0 */ ParamText( "\pMacJove - Copyright (C) 1986-1999 J. Payne, K. Gegenfurtner,", "\pK. Mitchum. Portions (C) THINK Technologies, Inc.", nostring, nostring); dh = qd.screenBits.bounds.left + (qd.screenBits.bounds.right - DWIDTH) / 2; dv = qd.screenBits.bounds.top + (qd.screenBits.bounds.bottom - DHEIGHT) / 2; MoveWindow((WindowPtr)theDialog, dh, dv, 0); ShowWindow((WindowPtr)theDialog); GetDItem(theDialog, LIST_ITEM, &itemType, &theHandle, &theRect); theListRect = theRect; theListRect.right -= 15; ((WindowPtr)theDialog)->txFont = FONT; ((WindowPtr)theDialog)->txSize = TEXTSIZE; return (WindowPtr) theDialog; } private void do_display() /* draw necessary controls, lines */ { Rect rViewF; /* framing rect for list */ int offset; rViewF = theListRect; rViewF.left--; rViewF.top--; rViewF.right++; rViewF.bottom++; FrameRect(&rViewF); DrawControls(theWindow); } private ListHandle makelist() { Point csize; Rect dataBounds, rView; /* list boundaries */ csize.h = csize.v = 0; SetRect(&dataBounds, 0, 0, 1, 0); return LNew(&theListRect, &dataBounds, csize, 0, theWindow, 0, 0, 0, 1); } private void printbind(f, buf) const struct cmd *f; char *buf; { char c; if (f->c_map == 0 || (c = f->c_key) == 0x7f) { strcpy(buf, " "); return; } switch(f->c_map) { case F_MAINMAP: strcpy(buf, " "); break; case F_PREF1MAP: strcpy(buf, " ESC "); break; case F_PREF2MAP: strcpy(buf, " ^X "); break; } if (c < ' ') { buf[5] = '^'; /* control char */ c |= 0x40; } else { buf[5] = ' '; } if ('a' <= c && c <= 'z') c &= 0x5f; buf[6] = c; buf[7] = ' '; buf[8] = '\0'; } private void do_list() { int row, col; const struct cmd *f; char buf[255]; Point theCell; theCell.h = 0; for (f = commands, row = 0; f->Name; f++, row++) { LAddRow(1, row, theList); theCell.v = row; printbind(f, buf); strcat(buf, f->Name); LSetCell(buf, strlen(buf), theCell, theList); } } private pascal Boolean ProcFilter(theDialog, event, itemHit) DialogPtr theDialog; EventRecord *event; short *itemHit; { theEvent = *event; if (theEvent.what == keyDown && theEvent.message & charCodeMask == '\r') { *itemHit = 1; return YES; } if (theEvent.what == activateEvt && (WindowPtr) theEvent.message == theWindow) { LDoDraw(1, theList); LActivate(1, theList); } if (theEvent.what == updateEvt && (WindowPtr) theEvent.message == theWindow) { BeginUpdate(theWindow); do_display(); DrawDialog(theWindow); LUpdate(theWindow->visRgn, theList); EndUpdate(theWindow); } return NO; } void do_events() { short item; jbool done = NO; Point p; while (!done) { ModalDialog(ProcFilter, &item); switch(item) { case DONE_ITEM: done = YES; /* ??? fall through? -- DHR */ case LIST_ITEM: p = theEvent.where; GlobalToLocal(&p); LClick(p, theEvent.modifiers, theList); break; } } } /* Window and Control related routines. */ /* (ORIGINALLY IN) tcon.c. * control handler routines for Jove. K. Mitchum 12/86 */ #define MINC 0 #define MAXC 100 #define INITC 0 #define EVENTLIST (mDownMask | keyDownMask ) private Point p; private jbool wc_adjust proto((int, int, struct wind_config *, int)); private void MakeScrollBar proto((Window *w)), AdjustScrollBar proto((Window *w)), drawfluff proto((void)); void docontrols() /* called from redisplay routines */ { Window *w; int top; w = fwind; top = 0; do { if (w->w_control != NULL) HideControl(w->w_control); w = w->w_next; } while (w != fwind); w = fwind; do { w->w_topline = top; if (w->w_control != NULL) AdjustScrollBar(w); else MakeScrollBar(w); ShowControl(w->w_control); top += w->w_height; w = w->w_next; } while (w != fwind); Windchange = NO; drawfluff(); } private void MakeScrollBar(w) /* set up control */ Window *w; { Rect BarRect; int wheight, wtop; WindowPtr window = theScreen; wheight = w->w_height; wtop = w->w_topline; SetRect(&BarRect, window->portRect.right - SCROLLWIDTH + 1, window->portRect.top -2 + wtop * HEIGHT, window->portRect.right +1, window->portRect.top + ((wheight + wtop) * HEIGHT + 1)); w->w_control = NewControl(window, &BarRect, "\psbar", 1, INITC, MINC, MAXC, scrollBarProc, (long)w); } private void AdjustScrollBar(w) /* redo existing control */ Window *w; { ControlHandle handle = w->w_control;; if (handle != NULL) { int wtop = w->w_topline; int wheight = w->w_height; WindowPtr window = (*handle)->contrlOwner; SizeControl(handle, SCROLLWIDTH, wheight * HEIGHT + 1); MoveControl(handle, window->portRect.right - SCROLLWIDTH + 1, window->portRect.top - 1 + wtop * HEIGHT); } } private int ltoc proto((void)); /* calculate ctlvalue for line position */ void SetScrollBar(w) /* set value of the bar */ Window *w; { SetCtlValue(w->w_control, ltoc()); } private void drawfluff() /* draw controls and dividers */ { Window *w = fwind; DrawControls(theScreen); DrawGrowIcon(theScreen); } void RemoveScrollBar(w) Window *w; { if (w->w_control != NULL) DisposeControl(w->w_control); w->w_control = NULL; } private pascal void DScroll(control, part) ControlHandle control; int part; { DownScroll(); redisplay(); } private pascal void UScroll(control, part) ControlHandle control; int part; { UpScroll(); redisplay(); } private pascal void NPage(control, part) ControlHandle control; int part; { NextPage(); redisplay(); } private pascal void PPage(control, part) ControlHandle control; int part; { PrevPage(); redisplay(); } private long npos; /* number of lines in buffer */ private int ltoc() /* calculate ctlvalue for line position */ { long ipos = LinesTo(curbuf->b_first, curline) + 1; npos = ipos + LinesTo(curline, (LinePtr)NULL) - 1; return (int) ((ipos * MAXC) / npos); } private LinePtr ctol(ctlv) /* find buffer line for ctlvalue */ int ctlv; { return next_line(curbuf->b_first, (long) ((npos * ctlv)/MAXC)); } private void doWind(event, window) EventRecord *event; WindowPtr window; { p = event->where; GlobalToLocal(&p); if (event->what == mouseDown) { ControlHandle whichControl; Window *jwind, *cwind; jbool notcurwind = NO; int cpart; /* control part */ if ((cpart = FindControl(p, window, &whichControl)) == 0) return; if ((jwind = (Window *) (*whichControl)->contrlRfCon) != curwind) { notcurwind = YES; cwind = curwind; SetWind(jwind); } switch (cpart) { case inUpButton: TrackControl(whichControl, p, (ProcPtr) DScroll); break; case inDownButton: TrackControl(whichControl, p, (ProcPtr) UScroll); break; case inPageUp: TrackControl(whichControl, p, (ProcPtr) PPage); break; case inPageDown: TrackControl(whichControl, p, (ProcPtr) NPage); break; case inThumb: if (TrackControl(whichControl, p, (ProcPtr)NULL)) { int newval = GetCtlValue(whichControl); if (newval == MAXC) Eof(); else if (newval == MINC) Bof(); else SetLine(ctol(newval)); } break; } if (notcurwind) { SetWind(cwind); redisplay(); } redisplay(); /* again, to set the cursor */ } else { if (findtext()) redisplay(); } } #define std_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->stdState #define user_state(w) (*((WStateData **)((WindowPeek)((w)))->dataHandle))->userState private void doDrag(event, window) EventRecord *event; WindowPtr window; { Rect old_std = std_state(window); DragWindow(window, event->where, &LimitRect); if (wc == &wc_std) { wc_user = wc_std; user_state(theScreen) = std_state(theScreen); ZoomWindow(window, 7, 1); wc = &wc_user; Reset_std(); } } private void doGrow(event, window) EventRecord *event; WindowPtr window; { long size; /* zero means user didn't change anything */ if ((size = GrowWindow(window, event->where, &LimitRect)) != 0) { if (wc == &wc_std) { wc_user = wc_std; user_state(theScreen) = std_state(theScreen); ZoomWindow(window, 7, 1); wc = &wc_user; Reset_std(); } if (wc_adjust(LoWord(size), HiWord(size), wc, 0)) { EraseRect(&window->portRect); SizeWindow(window, wc->w_width, wc->w_height, YES); win_reshape(0); /* no signals here... */ } } } private void doZoomIn(event, window) EventRecord *event; WindowPtr window; { if (TrackBox(window, event->where, 7)) { EraseRect(&window->portRect); ZoomWindow(window, 7, 1); wc = &wc_user; win_reshape(0); /* we do our own toggle, not ZoomWindow() */ } } private void doZoomOut(event, window) EventRecord *event; WindowPtr window; { if (TrackBox(window, event->where, 8)) { EraseRect(&window->portRect); ZoomWindow(window, 8, 1); wc = &wc_std; win_reshape(0); /* we do our own toggle, not ZoomWindow() */ } } private void doGoAway(event, window) EventRecord *event; WindowPtr window; { if (TrackGoAway(window, event->where)) Leave(); } private Window * rtowind(row) /* return jove window row is in */ int row; { Window *w = fwind; do { if ((w->w_topline <= row) && ((w->w_height + w->w_topline) > row)) return w; w = w->w_next; } while (w != fwind); return NULL; } private LinePtr windtol(w, row) /* return line for row in window */ Window *w; int row; { LinePtr l = w->w_top; while (row-- && l != NULL) l = l->l_next; return l; } private int ptoxy proto((Point, int *, int *)); /* convert Point to terminal x, y coordinate */ private jbool findtext() /* locate and move the point to match the mouse */ { int row, col; int offset; long ticks; EventRecord event; Window *w; LinePtr l; ticks = Ticks; ptoxy(p, &row, &col); if ((w = rtowind(row)) == NULL) return NO; if (w != curwind) SetWind(w); offset = PhysScreen[row].s_offset; /* account for horizontal scrolling and */ offset += SIWIDTH(offset) + W_NUMWIDTH(w); /* line number */ row -= w->w_topline; /* now have row number in window */ if (row >= w->w_height -1) return NO; if ((l = windtol(w, row)) == NULL) return NO; if (l->l_dline == NULL_DADDR) return NO; this_cmd = LINECMD; SetLine(l); /* Curline is in linebuf now */ col -= offset; if (col < 0) col = 0; curchar = how_far(curline, col); do { if (GetNextEvent(mUpMask, &event) && (event.when < ticks + DoubleTime)) { set_mark(); break; } } while ((Ticks - ticks) < DoubleTime); return YES; } private int ptoxy(p, row, col) /* convert Point to terminal x, y coordinate */ Point p; int *row, *col; { *row = (p.v / HEIGHT); *col = (p.h / WIDTH ); if ((*row > MAXROW) || (*col > MAXCOL)) return JMP_ERROR; return 0; } /* Event-related routines. The Event loop is CheckEvents(), and is called * whenever a console read occurs or a call to charp(). During certain * activities, such as ask(), etc. non-keyboard events are ignored. * This is set by the variable Keyonly. As an update or activate event * generates a call to redisplay(), it is important that redisplay() and * related routines NOT check for keyboard characters. */ /* (ORIGINALLY IN) tevent.c * event handler for Jove. K Mitchum 12/86 */ #define SYS_ID 100 #define NOFUNC ((void (*) ptrproto((EventRecord *event)))NULL) #define NEVENTS 16 private void doMouse proto((EventRecord *event)), dokeyDown proto((EventRecord *event)), doUpdate proto((EventRecord *event)), doActivate proto((EventRecord *event)); private void p_refresh proto((void)); private MenuHandle SysMenu; private void (*eventlist[]) ptrproto((EventRecord *event)) = { NOFUNC, /* nullEvent */ doMouse, /* mouseDown */ doMouse, /* mouseUp */ dokeyDown, /* keyDown */ NOFUNC, /* keyUp */ dokeyDown, /* autoKey */ doUpdate, /* updateEvt */ NOFUNC, /* diskEvt */ doActivate, /* activateEvt */ NOFUNC, /* not used */ NOFUNC, /* networkEvt = 10 */ NOFUNC, /* driverEvt */ NOFUNC, /* app1Evt */ NOFUNC, /* app2Evt */ NOFUNC, /* app3Evt */ NOFUNC /* app4Ev */ }; private void SetBufMenu proto((void)), MarkModes proto((void)); private void CheckEvents() { EventRecord theEvent; static long time = 0; static void (*fptr) ptrproto((EventRecord *event)); if (FrontWindow() == window) { Point Mousep; GetMouse(&Mousep); if (PtInRect(Mousep, &r)) SetCursor(*cross); else SetCursor(&qd.arrow); } SystemTask(); if (EventCmd && !Keyonly) return; if (Bufchange) SetBufMenu(); if (Modechange) MarkModes(); while (GetNextEvent(everyEvent, &theEvent)) { if ((theEvent.what < NEVENTS) && (fptr = eventlist[theEvent.what])) { (*fptr)(&theEvent); } SystemTask(); } if (TimeDisplayed && (Ticks - time) > 3600) { time = Ticks; UpdModLine = YES; redisplay(); } } private void InitLocalMenus proto((void)); private void InitSysMenu() { SysMenu = NewMenu(SYS_ID, "\p\24"); AppendMenu(SysMenu, "\pAbout Jove"); AddResMenu(SysMenu, 'DRVR'); InsertMenu(SysMenu, 0); InitLocalMenus(); DrawMenuBar(); } private void doWind proto((EventRecord *event, WindowPtr window)), doGoAway proto((EventRecord *event, WindowPtr window)), doSysMenu proto((EventRecord *event, WindowPtr window)), doSysClick proto((EventRecord *event, WindowPtr window)), doDrag proto((EventRecord *event, WindowPtr window)), doGrow proto((EventRecord *event, WindowPtr window)), doZoomIn proto((EventRecord *event, WindowPtr window)), doZoomOut proto((EventRecord *event, WindowPtr window)); #define NMEVENTS 9 private void (*mouselist[]) ptrproto((EventRecord *event, WindowPtr window)) = { (void (*) ptrproto((EventRecord *event, WindowPtr window)))NULL, /* inDesk */ doSysMenu, /* inMenuBar */ doSysClick, /* inSysWindow */ doWind, /* inContent */ doDrag, /* inDrag */ doGrow, /* inGrow */ doGoAway, /* inGoAway */ doZoomIn, /* inZoomIn */ doZoomOut /* inZoomOut */ }; private void doMouse(event) EventRecord *event; { if (Keyonly) { if (event->what == mouseDown) SysBeep(2); } else { WindowPtr theWindow; int wpart = FindWindow(event->where, &theWindow); void (*fptr) ptrproto((EventRecord *event, WindowPtr window)); if (wpart < NMEVENTS && (fptr = mouselist[wpart]) != NULL) (*fptr)(event, theWindow); } } private void ProcMenu proto((int menuno, int itemno)); private void doSysMenu(event, window) EventRecord *event; WindowPtr window; { long result = MenuSelect(event->where); int Menu = (result >> 16) & 0xffff; int Item = result & 0xffff; if (Item == 0) return; /* no choice made */ if (Menu == SYS_ID) { /* apple menu */ Str255 Name; GrafPtr Port; if (Item == 1) { about_j(); } else { GetItem(SysMenu, Item, Name); GetPort(&Port); OpenDeskAcc(Name); SetPort(Port); } } else { ProcMenu(Menu, Item); } HiliteMenu(0); EventCmd = YES; menus_on(); } private void doSysClick(event, window) EventRecord *event; WindowPtr window; { SystemClick(event, window); } private void doUpdate(event) EventRecord *event; { WindowPtr theWindow = (WindowPtr) event->message, oldPort; GetPort(&oldPort); SetPort(theWindow); BeginUpdate(theWindow); p_refresh(); drawfluff(); EndUpdate(theWindow); SetPort(oldPort); } private void doActivate(event) EventRecord *event; { WindowPtr theWindow = (WindowPtr) event->message; ControlHandle control; int hilite; SetPort(theWindow); hilite = (event->modifiers & activeFlag)? 0 : 255; for (control = (ControlHandle) (((WindowPeek) theWindow)->controlList) ; (control != 0); control = (*control)->nextControl) { HiliteControl(control, hilite); } } /* Keyboard routines. */ /* Keycodes (from Inside MacIntosh I-251). This table is ONLY used when * we are trying to make the Option key work as a Meta key. When we are * doing this, the system-supplied character is wrong, so we retranslate * the key code to a character code. * * Since we only use this table when the character generated by an * option-modified key is greater than DEL, and since the Option * modifier does not so affect keypad keys, we need not provide for * them in this table. * * ??? This may need to be updated to reflect keyboards newer than the Mac+! */ #define NOKEY '?' private char nsh_keycodes[] = { 'a','s','d','f','h', /* 00 - 04 */ 'g','z','x','c','v', /* 05 - 09 */ NOKEY,'b','q','w','e', /* 0A - 0E */ 'r','y','t','1','2', /* 0F - 13 */ '3','4','6','5','=', /* 14 - 18 */ '9','7','-','8','0', /* 19 - 1D */ ']','O','u','[','i', /* 1E - 22 */ 'p',CR,'l','j','\'', /* 23 - 27 */ 'k',';','\\',',','/', /* 28 - 2C */ 'n','m','.','\t',NOKEY, /* 2D - 31 */ '`',DEL /* 32 - 33*/ }; private char sh_keycodes[] = { 'A','S','D','F','H', /* 00 - 04 */ 'G','Z','X','C','V', /* 05 - 09 */ NOKEY,'B','Q','W','E', /* 0A - 0E */ 'R','Y','T','!','@', /* 0F - 13 */ '#','$','^','%','+', /* 14 - 18 */ '(','&','_','*',')', /* 19 - 1D */ '}','O','U','{','I', /* 1E - 22 */ 'P',CR,'L','J','\'', /* 23 - 27 */ 'K',';','|','<','?', /* 28 - 2C */ 'N','M','>','\t',NOKEY, /* 2D - 31 */ '~',DEL /* 32 - 33 */ }; /* (ORIGINALLY IN) tkey.c * keyboard routines for Macintosh. K Mitchum 12/86 */ jmp_buf auxjmp; private nchars = 0; private char charbuf[MCHARS]; /* The following kludges a meta key out of the option key by * sending an escape sequence back to the dispatch routines. This is * not elegant but it works, and doesn't alter escape sequences for * those that prefer them. To remap the control or meta keys, * see mackeys.h. */ private void dokeyDown(event) EventRecord *event; { unsigned mods; int c; static int cptr = 0; if (MCHARS - nchars < 2) return; c = event->message & charCodeMask; mods = event->modifiers; if (MetaKey && (mods & optionKey)) { /* Treat the Option key as a Meta key. * We have to "undo" the normal option key effect. * This means that, if the character is greater than DEL * and the code is known to our table, we retranslate the * code into a character. * This seems pretty dubious. I wonder if "KeyTrans" would * be a better tool. */ int code = (event->message & keyCodeMask) >> 8; if (c > DEL && code < elemsof(sh_keycodes)) c = ((mods & shiftKey)? sh_keycodes : nsh_keycodes)[code]; /* jam an ESC prefix */ charbuf[cptr++] = ESC; cptr &= NCHMASK; nchars++; } if (mods & (cmdKey | controlKey)) { /* control key (command key is treated as a control key too) */ if (c == '@' || c == '2' || c == ' ') c = '\0'; /* so we have a null char */ if (c != '`') c = CTL(c); /* make a control char */ } else if (c == '`') { c = ESC; /* for those used to escapes */ } charbuf[cptr++] = c; cptr &= NCHMASK; nchars++; } private ZXchar rawgetc() { static int cptr = 0; ZXchar c; if (EventCmd) { longjmp(auxjmp, 1); /* NOTREACHED */ } while (nchars <= 0) { nchars = 0; if (EventCmd) { longjmp(auxjmp, 1); /* NOTREACHED */ } CheckEvents(); /* ugh! WAIT for a character */ } nchars--; c = ZXRC(charbuf[cptr++]); cptr &= NCHMASK; /* zero if necessary */ return c; } jbool rawchkc() { if (EventCmd) { longjmp(auxjmp, 1); /* NOTREACHED */ } if (nchars == 0) CheckEvents(); /* this should NOT be necessary! */ return nchars > 0; } /* Routines for calling the standard file dialogs, when macify is YES. * If the user changes the directory using the file dialogs, Jove's notion * of the current directory is updated. */ /* (ORIGINALLY IN) tmacf.c. K. Mitchum 12/86. * Macify routines for jove. */ int CurrentVol; /* see tfile.c */ #define TYPES (-1) private Point px = {100, 100}; private unsigned char pmess[] = "\pSave file as: "; private pascal Boolean Ffilter(p) ParmBlkPtr p; { Boolean r; char *name; if (p->fileParam.ioFlFndrInfo.fdType == 'APPL') return YES; /* Filter out our tempfiles. * ??? the test doesn't check to see if the directories match. */ name = PtoCstr(p->fileParam.ioNamePtr); r = strcmp(name, ".joveXXX") == 0 #ifdef ABBREV || strcmp(name, ".jabbXXX") == 0 #endif #ifdef RECOVER || strcmp(name, ".jrecXXX") == 0 #endif ; CtoPstr(name); return r; } private void check_dir() { if (cur_vol != 0 - SFSaveDisk || cur_dir != CurDirStore) { char space[FILESIZE]; setdir(0 - SFSaveDisk, CurDirStore); UpdModLine = YES; /* make sure jove knows the change */ Modechange = YES; setCWD(getcwd(space, sizeof(space))); } } char * gfile(namebuf) /* return a filename to get */ char *namebuf; { SFReply frec; char ans[FILESIZE]; SFSaveDisk = 0 - cur_vol; /* in case a Desk Accessory changed them */ CurDirStore = cur_dir; SFGetFile(px, 0L, Ffilter, TYPES, 0L, 0L, &frec); check_dir(); /* see if any change, set if so */ if (frec.good) { EventRecord theEvent; do; while (GetNextEvent(updateMask, &theEvent) == 0); doUpdate(&theEvent); strcpy(ans, PtoCstr(frec.fName)); CtoPstr((char *)frec.fName); PathParse(ans, namebuf); return namebuf; } return NULL; } char * pfile(namebuf) char *namebuf; { SFReply frec; StringPtr nm; SFSaveDisk = 0 - cur_vol; /* in case a Desk Accessory changed them */ CurDirStore = cur_dir; strncpy(namebuf, filename(curbuf), FILESIZE-1); nm = cvt_fnm(namebuf); SFPutFile(px, pmess, nm, 0L, &frec); check_dir(); /* see if any change, set if so */ if (frec.good) { EventRecord theEvent; char *h, *p; do; while (GetNextEvent(updateMask, &theEvent) == 0); doUpdate(&theEvent); h = PtoCstr(frec.fName); while (*h == ':') h++; /* convert to unix style */ for (p = h; (p = strchr(p, ':')) != NULL; ) *p++ = '/'; PathParse(h, namebuf); return namebuf; } return NULL; } /* getArgs() returns an argument list based on documents clicked on by the user. */ int getArgs(avp) char ***avp; { int argc, old_vol; short nargs, type; long old_dir; char **argv; char *pathname; AppFile p; WDPBRec d; old_vol = cur_vol; old_dir = cur_dir; CountAppFiles(&type, &nargs); if (nargs > 0) { /* files to open... */ argv = (char **) emalloc((nargs + 2) * sizeof(char *)); for (argc = 1; argc <= nargs; argc++) { GetAppFiles(argc, &p); if (type == 0) { char space[FILESIZE]; PtoCstr((StringPtr)p.fName); d.ioCompletion = 0; d.ioNamePtr = NULL; d.ioVRefNum = p.vRefNum; d.ioWDIndex = 0; PBGetWDInfo(&d, 0); cur_vol = d.ioWDVRefNum; cur_dir = d.ioWDDirID; pathname = getcwd(space, sizeof(space)); argv[argc] = emalloc(strlen((char *)p.fName) + strlen(pathname) + 2); strcpy(argv[argc], pathname); strcat(argv[argc], "/"); strcat(argv[argc], (char *)p.fName); } ClrAppFiles(argc); } if (type != 0) argc = 1; } else { argv = (char **) emalloc(2 * sizeof(char*)); argc = 1; } argv[0] = "jove"; argv[argc] = NULL; *avp = argv; cur_dir = old_dir; cur_vol = old_vol; return argc; } /* Menu routines. The menus items are set up in a similar manner as keys, and * are bound prior to runtime. See menumaps.txt, which must be run through * setmaps. Unlike keys, menu items may be bound to variables, and to * buffers. Buffer binding is only done at runtime. */ private void InitMenu proto((struct menu *M)), make_edits proto((int menu)); private void InitLocalMenus() { int i; for (i = 0; i < NMENUS; i++) { InitMenu(&Menus[i]); if (i == 0) make_edits(Menus[i].menu_id + 1); } } private void InitMenu(M) struct menu *M; { int i; StringPtr ps; if (M->menu_id == 0) return; M->Mn = NewMenu(M->menu_id, ps=CtoPstr(M->Name)); PtoCstr(ps); for (i = 0; i < NMENUITEMS; i++) { data_obj *d = M->m[i]; if (d == NULL) break; /* last item... */ switch (d->Type & TYPEMASK) { case STRING: AppendMenu(M->Mn, ps=CtoPstr(d->Name)); PtoCstr(ps); break; case VARIABLE: AppendMenu(M->Mn, ps=CtoPstr(d->Name)); PtoCstr(ps); if ((((struct variable *)d)->v_flags & V_TYPEMASK) == V_BOOL && *(jbool *)(((struct variable *)d)->v_value)) CheckItem(M->Mn, i + 1, YES); break; case COMMAND: AppendMenu(M->Mn, ps=CtoPstr(d->Name)); PtoCstr(ps); break; } } InsertMenu(M->Mn, 0); } private void MacSetVar proto((struct variable *vp, int mnu, int itm)); private void ProcMenu(menuno, itemno) int menuno, itemno; { int i; data_obj *d; for (i = 0; i < NMENUS; i++) { if (Menus[i].menu_id == menuno) { itemno--; d = Menus[i].m[itemno]; switch(d->Type & TYPEMASK) { case COMMAND: ExecCmd((data_obj *) d); break; case BUFFER: SetABuf(curbuf); tiewind(curwind, (Buffer *) d); SetBuf((Buffer *) d); break; case VARIABLE: MacSetVar((struct variable *) d, i, itemno); break; } break; } } } private void make_edits(menu) /* add dummy edit menu */ int menu; { MenuHandle M; int item; char *fname; M = NewMenu((menu), "\pEdit"); AppendMenu(M, "\pUndo/Z;(-;Cut/X;Copy/C;Paste/V;Clear;Select All;(-;Show Clipboard"); InsertMenu(M, 0); DisableItem(M, 0); } void menus_off() { int i; if (Keyonly || EventCmd) return; #ifdef MENU_DISABLE /* NOBODY likes this, but it's here if you want it... */ DisableItem(SysMenu, 0); for (i = 0; i < NMENUS; i++) if (Menus[i].Mn) DisableItem(Menus[i].Mn, 0); DrawMenuBar(); #endif Keyonly = YES; } void menus_on() { int i; if (!Keyonly) return; #ifdef MENU_DISABLE EnableItem(SysMenu, 0); for (i = 0; i < NMENUS; i++) if (Menus[i].Mn) EnableItem(Menus[i].Mn, 0); DrawMenuBar(); #endif Keyonly = NO; } private char * BufMPrint(b, i) Buffer *b; int i; { char *p; char *nm = filename(b); char t[35]; if (strlen(nm) > 30) { strcpy(t, "..."); strcat(t, nm + strlen(nm) - 30); } else { strcpy(t, nm); } nm = t; while (*nm) { switch(*nm) { /* ugh... these are metacharacter for Menus */ case '/': *nm = ':'; break; case '^': case '!': case '<': case '(': case ';': *nm = '.'; break; /* that will confuse everybody */ } nm++; } p = sprint("%-2d %-11s \"%-s\"", i, b->b_name, t); return p; } private void SetBufMenu() { Buffer *b; int i, j, stop; struct menu *M; Bufchange = NO; for (i = 0; i < NMENUS; i++) { if (strcmp(Menus[i].Name, "Buffer") == 0) { M = &Menus[i]; for (j = 0; j < NMENUITEMS; j++) { data_obj *d = Menus[i].m[j]; if (d == NULL) break; if ((d->Type & TYPEMASK) == BUFFER) { for (i = j, b = world; i < NMENUITEMS && b != NULL; i++, b = b->b_next) { if (M->m[i] == NULL) AppendMenu(M->Mn, CtoPstr(BufMPrint(b, i-j+1))); /* add the item */ else SetItem(M->Mn, i + 1, CtoPstr(BufMPrint(b, i-j+1))); /* or change it */ M->m[i] = (data_obj *) b; } stop = i; /* out of buffers? */ for (; i < NMENUITEMS && M->m[i]; i++) { DelMenuItem(M->Mn, stop + 1); /* take off last item */ M->m[i] = NULL; } break; } } break; } } } private void MacSetVar(vp, mnu, itm) /* Set a variable from the menu */ struct variable *vp; int mnu, itm; { if ((vp->v_flags & V_TYPEMASK) == V_BOOL) { /* toggle the value */ *((jbool *) vp->v_value) = !*((jbool *) vp->v_value); MarkVar(vp, mnu, itm); } else { char prompt[128]; swritef(prompt, sizeof(prompt), "Set %s: ", vp->Name); vset_aux(vp, prompt); } } private void MarkModes() { int mnu, itm; data_obj *d; Modechange = NO; for (mnu = 0; mnu < NMENUS; mnu++) { for (itm = 0; itm < NMENUITEMS; itm++) { if ((d = Menus[mnu].m[itm]) == NULL) break; if ((d->Type & (MAJOR_MODE | MINOR_MODE)) || ((d->Type & TYPEMASK) == BUFFER)) { jbool checked; if (d->Type & (MAJOR_MODE)) checked = curbuf->b_major == (d->Type >> 8); else if (d->Type & (MINOR_MODE)) checked = (curbuf->b_minor & (d->Type >> 8)) != 0; else checked = d == (data_obj *) curbuf; CheckItem(Menus[mnu].Mn, itm + 1, checked); } } } } void MarkVar(vp, mnu, itm) /* mark a boolean menu item */ const struct variable *vp; int mnu, itm; { if (mnu == -1) { /* we don't know the item... slow */ for (mnu = 0; ; mnu++) { if (mnu >= NMENUS) return; /* not found */ for (itm = 0; (itm < NMENUITEMS); itm++) { if ((struct variable *) (Menus[mnu].m[itm]) == vp) break; } if (itm < NMENUITEMS) break; } } CheckItem(Menus[mnu].Mn, itm + 1, *(jbool *)vp->v_value); } /* Screen routines and driver. The Macinitosh Text Edit routines are not utilized, * as they are slow and cumbersome for a terminal emulator. Instead, direct QuickDraw * calls are used. The fastest output is obtained writing a line at a time, rather * than on a character basis, so the major output routine is writechr(), which takes * a pascal-style string as an argument. See do_sputc() in screen.c. */ void Placur(line, col) int line, col; { CapCol = col; CapLine = line; putcurs(line, col, YES); } void NPlacur(line, col) int line, col; { CapCol = col; CapLine = line; putcurs(line, col, NO); } void i_lines(top, bottom, num) int top, bottom, num; { Placur(bottom - num + 1, 0); dellines(num, bottom); Placur(top, 0); inslines(num, bottom); } void d_lines(top, bottom, num) int top, bottom, num; { Placur(top, 0); dellines(num, bottom); Placur(bottom + 1 - num, 0); inslines(num, bottom); } /* (ORIGINALLY IN) tn.c * Window driver for MacIntosh using windows. * K. Mitchum 9/86 */ /*#define VARFONT*/ #ifdef VARFONT private height, width, theight, twidth, descent; #else # define height HEIGHT # define width WIDTH # define theight THEIGHT # define twidth TWIDTH # define descent DESCENT #endif private int trow, tcol; private jbool cursvis; #ifdef NEVER private jbool insert; #endif private Rect cursor_rect; private char *p_scr, *p_curs; /* physical screen and cursor */ private int p_size; private Rect vRect; private WindowRecord myWindowRec; #define active() SetPort(theScreen) #define maxadjust(r) OffsetRect((r), 0, 2) private char * conv_p_curs(row, col) int row, col; { return p_scr + (row * (CO)) + col; } #ifdef NEVER private void INSmode(new) jbool new; { insert = new; } #endif void SO_effect(new) jbool new; { theScreen->txMode = new? notSrcCopy : srcCopy; } private void init_slate proto((void)); private void tn_init() { #ifdef NEVER INSmode(NO); #endif init_slate(); SO_off(); ShowPen(); } void clr_page() /* clear and home function */ { Rect r; memset(p_scr, ' ', p_size); active(); SetRect(&r, 0, 0, WINDWIDTH, WINDHEIGHT); EraseRect(&r); putcurs(0, 0, NO); /* ??? "NO" guess by DHR */ drawfluff(); } private void putcurs(row, col, vis) unsigned row, col; jbool vis; { active(); curset(NO); trow = row; tcol = col; curset(vis); } private void curset(invert) jbool invert; { int colpix = tcol * width, rowpix = trow * height; if (trow == MAXROW) rowpix += 2; /* leave space for 2 pixel rule */ p_curs = conv_p_curs(trow, tcol); MoveTo(colpix, rowpix + height - descent); DrawChar(*p_curs); cursvis = invert; if (invert) { SetRect(&cursor_rect, colpix, rowpix, colpix + width - 1, rowpix + height - 1); InvertRect(&cursor_rect); } MoveTo(colpix, rowpix + height - descent); } void clr_eoln() { Rect r; active(); SetRect(&r, tcol * width, trow * height, WINDWIDTH, (trow +1) * height); if (trow == MAXROW) maxadjust(&r); EraseRect(&r); memset(p_curs, ' ', CO - tcol); curset(YES); } #ifdef NEVER private void delchars() { Rect r; RgnHandle updateRgn; active(); curset(NO); updateRgn = NewRgn(); SetRect(&r, tcol * width, trow * height, twidth - width, (trow+1) * height); if (trow == MAXROW) maxadjust(&r); ScrollRect(&r, -width, 0, updateRgn); DisposeRgn(updateRgn); BlockMove(p_curs + 1, p_curs, (long) (MAXCOL - tcol)); *conv_p_curs(trow, MAXCOL) = ' '; curset(YES); } #endif /* NEVER */ private void dellines(n, bot) int n, bot; { RgnHandle updateRgn = NewRgn(); Rect r; long len; active(); curset(NO); SetRect(&r, 0, ((trow) * height), WINDWIDTH, ((bot + 1) * height)); ScrollRect(&r, 0, 0 - (n * height), updateRgn); DisposeRgn(updateRgn); len = ((bot - trow - n + 1) * CO); BlockMove(conv_p_curs(trow + n, 0), conv_p_curs(trow, 0), len); memset(conv_p_curs(bot - n + 1, 0), ' ', n * CO); putcurs(trow, 0, YES); /* ??? "YES" guess by DHR */ } private void inslines(n, bot) int n, bot; { RgnHandle updateRgn = NewRgn(); Rect r; long len; active(); curset(NO); SetRect(&r, 0, trow * height, WINDWIDTH, (bot +1) * height); ScrollRect(&r, 0, (n * height), updateRgn); DisposeRgn(updateRgn); len = ((bot - trow - n +1) * CO); BlockMove(conv_p_curs(trow, 0), conv_p_curs(trow + n, 0), len); memset(conv_p_curs(trow, 0), ' ', (n * CO)); putcurs(trow, 0, YES); /* ??? "YES" guess by DHR */ } void writetext(str, len) const unsigned char *str; size_t len; { active(); curset(NO); #ifdef NEVER if (insert) { RgnHandle updateRgn = NewRgn(); Rect r; SetRect(&r, tcol * width, trow * height, twidth - width * len, (trow +1) * height -1); if (trow == MAXROW) maxadjust(&r); ScrollRect(&r, width * len, 0, updateRgn); DisposeRgn(updateRgn); } #endif DrawText(str, (short)0, (short)len); #ifdef NEVER if (insert) BlockMove(p_curs, p_curs + len, (long) (CO - tcol - len)); #endif memcpy((UnivPtr)p_curs, (UnivPtr)str, len); putcurs(trow, tcol+len <= MAXCOL? tcol+len : MAXCOL, YES); /* ??? "YES" guess by DHR */ } private Rect myBoundsRect; private void init_slate() { FontInfo f; char *Name = "Jove "; char *Title; InitGraf(&qd.thePort); InitWindows(); InitCursor(); InitFonts(); InitMenus(); InitDialogs((ProcPtr)NULL); /* no restart proc */ /* figure limiting rectangle for window moves */ SetRect(&LimitRect, qd.screenBits.bounds.left + 3, qd.screenBits.bounds.top + 20, qd.screenBits.bounds.right - 3, qd.screenBits.bounds.bottom -3); Set_std(); SetBounds(); /* initialize char array for updates */ p_scr = emalloc(p_size = wc_std.w_cols * wc_std.w_rows); /* only once */ p_curs = p_scr; Title = sprint("%s%s", Name, jversion); theScreen = NewWindow(&myWindowRec, &myBoundsRect, CtoPstr(Title), 1, 8, (WindowPtr) -1, 1, 0L); /* figure an initial window configuration and adjust it */ wc = &wc_std; wc_user = wc_std; /* initially, only one configuration to toggle */ user_state(theScreen) = std_state(theScreen); SetPort(theScreen); theScreen->txFont = FONT; theScreen->txSize = TEXTSIZE; #ifdef VARFONT GetFontInfo(&f); height = f.ascent+f.descent+f.leading; width = f.widMax; twidth = width * wc->w_cols; theight = height * wc->w_rows; descent = f.descent; #endif theScreen->txMode = srcCopy; theScreen->pnMode = patCopy; PenNormal(); } private void p_refresh() { int lineno; for (lineno = 0; lineno < LI; lineno++) { char *curs = conv_p_curs(lineno, 0); MoveTo(0, (lineno+1) * height - descent + (lineno == MAXROW? 2 : 0)); /* The following kludgy line is to get SO right. It depends on: * - !defined(HIGHLIGHTING) * - this routine not being called at an inauspicious time * i.e. in the middle of a SO output. * - the fact that the last line will non-SO so that the text * mode will be left non-SO. */ SO_effect(Screen[lineno].s_effects); DrawText(curs, (short)0, (short)CO); } curset(cursvis); } private jbool wc_adjust(w, h, wcf, init) /* adjust window config to look nice */ int w, h; struct wind_config *wcf; int init; { static int LIMIT_R, LIMIT_C; int rows, cols; if (init) { LIMIT_R = (h - 4) / HEIGHT; LIMIT_C = (w - SCROLLWIDTH - 1) / WIDTH + 1; } if ((w < WIDTH * 40) ||(h < HEIGHT * 10) /* too small */ || ((rows = (h - 4) / HEIGHT) > LIMIT_R) /* too big */ || ((cols = (w - SCROLLWIDTH - 1) / WIDTH + 1) > LIMIT_C)) return NO; wcf->w_rows = rows; wcf->w_cols = cols; wcf->w_width = wcf->w_cols * WIDTH + 1 + SCROLLWIDTH; wcf->w_height = wcf->w_rows * HEIGHT + 4; return YES; } private int getCO() /* so that jove knows params */ { return wc->w_cols; } private int getLI() { return wc->w_rows; } void ttsize() { /* ??? We really ought to wait until the screen is big enough: * at least three lines high (one line each for buffer, mode, * and message) and at least twelve columns wide (eight for * line number, one for content, two for overflow indicators, * and one blank at end). */ /* ??? This should be made more like UNIX version */ CO = getCO(); if (CO > MAXCOLS) CO = MAXCOLS; LI = getLI(); Windchange = YES; clr_page(); ILI = LI - 1; } private void SetBounds() { SetRect(&myBoundsRect, qd.screenBits.bounds.left + 3, qd.screenBits.bounds.top + 40, qd.screenBits.bounds.left + 3 + wc_std.w_width, qd.screenBits.bounds.top + 40 + wc_std.w_height); } private void Set_std() { (void) wc_adjust(qd.screenBits.bounds.right - qd.screenBits.bounds.left - 6, qd.screenBits.bounds.bottom - qd.screenBits.bounds.top - 42, &wc_std, 1); } private void Reset_std() { Set_std(); std_state(theScreen) = myBoundsRect; } #endif /* MAC */ jove-4.17.5.5/mac.h000066400000000000000000000034711501102521500136240ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Macintosh related things. K. Mitchum 2/88 */ #ifdef MAC /* the body is the rest of this file */ #include #define NMENUS 6 #define NMENUITEMS 40 /* This has GOT to be enough! */ typedef data_obj *menumap[NMENUITEMS]; struct menu { char *Name; int menu_id; MenuHandle Mn; menumap m; }; struct stat { int st_dev; /* volume number */ long st_ino; /* file number on volume */ dev_t st_rdev; off_t st_size; /* logical end of file */ jmode_t st_mode; time_t st_mtime; /* last modified */ }; /* mask and values for simulating file modes */ #define S_IFMT 03 #define S_IFREG 01 #define S_IFDIR 02 int stat proto((const char *, struct stat *)); #define SIGHUP 1 /* fake */ extern void MarkVar proto((const struct variable *vp, int mnu, int itm)); extern jmp_buf auxjmp; extern char *gethome proto((void)), *pfile proto((char *)), *gfile proto((char *)); extern int getArgs proto((char ***)); extern jbool rawchkc proto((void)); extern void MacInit proto((void)), writetext proto((const unsigned char *, size_t)), NPlacur proto((int, int)), docontrols proto((void)), SetScrollBar proto((Window *)), RemoveScrollBar proto((Window *)), InitEvents proto((void)), menus_on proto((void)); extern jbool Keyonly, Bufchange, Modechange, EventCmd, Windchange; /* Variables: */ extern jbool Macmode; /* VAR: use Mac file selector */ #endif /* MAC */ jove-4.17.5.5/macros.c000066400000000000000000000200041501102521500143320ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "fp.h" #include "chars.h" #include "disp.h" #include "ask.h" #include "commands.h" #include "macros.h" #include "extend.h" #include "fmt.h" /* #include "util.h" */ private void pop_macro_stack proto((void)); private struct macro *ask_macname proto((const char *, int)); private jbool UnsavedMacros = NO; /* are there any macros that need saving to a file? */ struct macro *macros = NULL; /* macros */ jbool InMacDefine = NO; private void add_mac(new) struct macro *new; { register struct macro *mp, *prev = NULL; for (mp = macros; mp != NULL; prev = mp, mp = mp->m_nextm) if (mp == new) return; if (prev) prev->m_nextm = new; else macros = new; new->m_nextm = NULL; new->Type = MACRO; } /* * Jove keeps a "stack" of running macros. Whenever we * execute a macro, we push it on the stack. The main event * loops (getch(), joverc(), do_find()) call mac_getc() and * dispatch() to actually run whatever is on the macro stack. */ struct m_thread { struct m_thread *mt_prev; struct macro *mt_mp; int mt_offset, mt_count; }; private struct m_thread *mac_stack = NULL; private struct m_thread * alloc_mthread() { return (struct m_thread *) emalloc(sizeof (struct m_thread)); } private void free_mthread(t) struct m_thread *t; { free((UnivPtr) t); } /* abandon/drain any running macros */ void unwind_macro_stack() { while (mac_stack != NULL) pop_macro_stack(); } private void pop_macro_stack() { register struct m_thread *m; if ((m = mac_stack) == NULL) return; mac_stack = m->mt_prev; jdprintf("pop_macro_stack \"%s\" newtop=\"%s\"\n", m->mt_mp->Name, mac_stack?mac_stack->mt_mp->Name : ""); free_mthread(m); } private void push_macro_stack(m, count) register struct macro *m; int count; { register struct m_thread *t; jdprintf("push_macro_stack \"%s\" %d\n", m->Name, count); for (t = mac_stack; t != NULL; t = t->mt_prev) { jdprintf("stack \"%s\"\n", t->mt_mp->Name); if (t->mt_mp == m) { complain("[Cannot execute macro recursively]"); /* NOTREACHED */ } } if (count <= 0) { complain("[Cannot execute macro a negative number of times]"); /* NOTREACHED */ } t = alloc_mthread(); t->mt_prev = mac_stack; mac_stack = t; t->mt_offset = 0; t->mt_mp = m; t->mt_count = count; jdprintf("push_macro_stack added \"%s\"\n", m->Name); } void do_macro(mac) struct macro *mac; { push_macro_stack(mac, arg_value()); } private struct macro KeyMacro = { /* Macro used for defining */ MACRO, "keyboard-macro", 0, NULL, NULL }; private int kmac_len; private int kmac_buflen = 0; void mac_init() { add_mac(&KeyMacro); } void mac_putc(c) DAPchar c; { if (kmac_len >= kmac_buflen) { KeyMacro.m_body = erealloc((UnivPtr) KeyMacro.m_body, (size_t) kmac_buflen + 16); kmac_buflen += 16; } KeyMacro.m_body[kmac_len++] = c; } void note_dispatch() { if (kmac_len > 0) KeyMacro.m_len = kmac_len - 1; } jbool in_macro() { return (mac_stack != NULL); } ZXchar mac_getc() { struct m_thread *mthread; struct macro *m; ZXchar zc; if ((mthread = mac_stack) == NULL) return EOF; m = mthread->mt_mp; jdprintf("mac_getc \"%s\" len=%d off=%d count=%d \n", m->Name, m->m_len, mthread->mt_offset, mthread->mt_count); if (mthread->mt_offset == m->m_len) { mthread->mt_offset = 0; if (--mthread->mt_count == 0) pop_macro_stack(); return mac_getc(); } zc = ZXC(m->m_body[mthread->mt_offset++]); jdbg("mac_getc -> %d %c\n", zc, jisprint(zc)?zc:'~'); return zc; } private void MacDef(m, name, len, body) struct macro *m; /* NULL, or def to overwrite */ const char *name; /* must be stable if m isn't NULL */ int len; char *body; { if (m == NULL) { m = (struct macro *) emalloc(sizeof *m); m->Name = name; } else { if (m->m_body != NULL) free((UnivPtr) m->m_body); } m->m_len = len; if (len == 0) { m->m_body = NULL; } else { m->m_body = emalloc((size_t) len); byte_copy(body, m->m_body, (size_t) len); } add_mac(m); if (!InJoverc) UnsavedMacros = YES; } void NameMac() { char *name = NULL; struct macro *m; if (KeyMacro.m_len == 0) { complain("[No keyboard macro to name!]"); /* NOTREACHED */ } if (in_macro() || InMacDefine) { complain("[Can't name while defining/executing]"); /* NOTREACHED */ } if ((m = ask_macname(ProcFmt, ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW)) == NULL) name = copystr(Minibuf); if (m == &KeyMacro) { complain("[Can't name it that!]"); /* NOTREACHED */ } MacDef(m, name, KeyMacro.m_len, KeyMacro.m_body); } void RunMacro() { do_macro((struct macro *) findmac(ProcFmt)); } private void pr_putc(c, fp) ZXchar c; File *fp; { if (c == '\\' || c == '^') { f_putc('\\', fp); f_putc(c, fp); } else { char buf[PPWIDTH]; char *p; PPchar(c, buf); for (p = buf; *p != '\0'; p++) f_putc(*p, fp); } } void WriteMacs() { struct macro *m; char fnamebuf[FILESIZE]; File *fp; int i; (void) ask_file((char *)NULL, (char *)NULL, fnamebuf); fp = open_file(fnamebuf, iobuff, F_WRITE, YES); /* Don't write the keyboard macro which is always the first */ for (m = macros->m_nextm; m != NULL; m = m->m_nextm) { fwritef(fp, "define-macro %s ", m->Name); for (i = 0; i < m->m_len; i++) pr_putc(ZXC(m->m_body[i]), fp); #ifdef USE_CRLF f_putc('\r', fp); #endif /* USE_CRLF */ f_putc(EOL, fp); } close_file(fp); UnsavedMacros = NO; } void DefKBDMac() { struct macro *m = ask_macname(ProcFmt, ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW); ZXchar c; const char *macro_name = m == NULL? copystr(Minibuf) : m->Name, *macro_body; char macro_buffer[LBSIZE]; int len; if (m == &KeyMacro) { complain("[Can't name it that!]"); /* NOTREACHED */ } /* ??? I hope that this ask doesn't change *m! */ macro_body = ask(NullStr, ": %f %s enter body: ", macro_name); len = 0; while ((c = ZXC(*macro_body++)) != '\0') { if (c == '\\' || c == '^') c = DecodePair(c, ZXC(*macro_body++)); if (len >= LBSIZE) { complain("Macro too large"); /* NOTREACHED */ } macro_buffer[len++] = c; } MacDef(m, macro_name, len, macro_buffer); } void Remember() { /* If we are already executing macros or in a joverc, disallow any * attempts to define the keyboard macro */ if (in_macro() || InJoverc) { complain("Cannot define keyboard macro from macro or joverc"); /* NOTREACHED */ } if (InMacDefine) message("[Already defining ... continue with definition]"); else { UpdModLine = YES; InMacDefine = YES; kmac_len = KeyMacro.m_len = 0; message("Defining..."); } } void Forget() { UpdModLine = YES; if (InMacDefine) { message("Keyboard macro defined."); InMacDefine = NO; } else { complain("[end-kbd-macro: not currently defining macro!]"); /* NOTREACHED */ } } void ExecMacro() { do_macro(&KeyMacro); } void MacInter() { if (Asking) Interactive = YES; } jbool ModMacs() { return UnsavedMacros; } /* Ask for macro name, with completion. * Flags is passed directly to complete. If ALLOW_NEW is on, * the name might be new, in which case NULL is returned and the * actual name in in Minibuf. */ private struct macro * ask_macname(prompt, flags) const char *prompt; int flags; { const char *strings[100]; register const char **strs = strings; register int com; register struct macro *m; for (m = macros; m != NULL; m = m->m_nextm) { if (strs == &strings[elemsof(strings)-1]) { complain("[too many macros]"); /* NOTREACHED */ } *strs++ = m->Name; } *strs = NULL; if ((com = complete(strings, (char *)NULL, prompt, flags)) < 0) return NULL; m = macros; while (--com >= 0) m = m->m_nextm; return m; } const data_obj * findmac(prompt) const char *prompt; { return (data_obj *)ask_macname(prompt, ALLOW_OLD | ALLOW_INDEX); } jove-4.17.5.5/macros.h000066400000000000000000000025221501102521500143440ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ struct macro { /* Type and Name must match data_obj */ int Type; /* in this case a macro */ const char *Name; /* name is always second ... */ int m_len; /* length of macro so we can use ^@ */ char *m_body; /* actual body of the macro */ struct macro *m_nextm; }; extern jbool InMacDefine; /* are we defining a macro right now? */ extern struct macro *macros; extern jbool in_macro proto((void)), ModMacs proto((void)); extern ZXchar mac_getc proto((void)); extern void mac_init proto((void)), do_macro proto((struct macro *mac)), unwind_macro_stack proto((void)), mac_putc proto((DAPchar c)), note_dispatch proto((void)); /* Commands: */ extern void DefKBDMac proto((void)), ExecMacro proto((void)), Forget proto((void)), MacInter proto((void)), NameMac proto((void)), Remember proto((void)), RunMacro proto((void)), WriteMacs proto((void)); /* dataobj.h: * findmac */ jove-4.17.5.5/marks.c000066400000000000000000000111731501102521500141720ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "fmt.h" #include "marks.h" #include "disp.h" private Mark *FreeMarksList = NULL; #define RecycleMark(m) { \ (m)->m_next = FreeMarksList; \ FreeMarksList = (m); \ (m)->m_line = NULL; /* DEBUG */ \ } Mark * MakeMark(line, column) register LinePtr line; int column; { register Mark *newmark; if ((newmark = FreeMarksList) != NULL) FreeMarksList = newmark->m_next; else newmark = (Mark *) emalloc(sizeof *newmark); MarkSet(newmark, line, column); newmark->m_big_delete = NO; newmark->m_next = curbuf->b_marks; curbuf->b_marks = newmark; return newmark; } void flush_marks(b) Buffer *b; { register Mark *m, *next; for (m = b->b_marks; m != NULL; m = next) { next = m->m_next; RecycleMark(m) } } private void DelBufMark(b, m) Buffer *b; register Mark *m; { register Mark *mp = b->b_marks; if (MarkHighlighting) makedirty(m->m_line); if (m == mp) b->b_marks = m->m_next; else { while (mp != NULL && mp->m_next != m) mp = mp->m_next; if (mp == NULL) { complain("Unknown mark!"); /* NOTREACHED */ } mp->m_next = m->m_next; } RecycleMark(m); } void DelMark(m) register Mark *m; { DelBufMark(curbuf, m); } /* AllMarkReset is used when a buffer is completely replaced. * We delete the marks in the mark ring, but we cannot find * the references to other marks, so those we make point * to the start of the buffer. */ void AllMarkReset(b, line) Buffer *b; register LinePtr line; { { register Mark **mpp; for (mpp = &b->b_markring[0]; mpp != &b->b_markring[NMARKS]; mpp++) { if (*mpp != NULL) { DelBufMark(b, *mpp); *mpp = NULL; } } b->b_themark = 0; } { register Mark *mp; for (mp = b->b_marks; mp != NULL; mp = mp->m_next) MarkSet(mp, line, 0); } } void MarkSet(m, line, column) Mark *m; LinePtr line; int column; { m->m_line = line; m->m_char = column; m->m_big_delete = NO; if (MarkHighlighting) makedirty(line); } void PopMark() { int pmark; if (curmark == NULL) return; ExchPtMark(); pmark = curbuf->b_themark; do { if (--pmark < 0) pmark = NMARKS - 1; } while (curbuf->b_markring[pmark] == NULL); curbuf->b_themark = pmark; if (MarkHighlighting) makedirty(curmark->m_line); } void SetMark() { if (is_an_arg()) PopMark(); else set_mark(); } void set_mark() { do_set_mark(curline, curchar); } void do_set_mark(l, c) LinePtr l; int c; { Mark **mr = curbuf->b_markring; int tm = curbuf->b_themark; if (mr[tm] != NULL) { if (MarkHighlighting) makedirty(mr[tm]->m_line); curbuf->b_themark = tm = (tm + 1) % NMARKS; if (mr[NMARKS-1] == NULL) { /* there is an empty slot: make sure one is here */ int i; for (i = NMARKS-1; i != tm; i--) mr[i] = mr[i-1]; mr[i] = NULL; } } if (mr[tm] == NULL) mr[tm] = MakeMark(l, c); else MarkSet(mr[tm], l, c); s_mess("[Point pushed]"); } /* Move point to Mark */ void ToMark(m) Mark *m; { int len; if (m == NULL) return; DotTo(m->m_line, m->m_char); if (curchar > (len = length(curline))) curchar = len; } Mark * CurMark() { if (curmark == NULL) { complain("No mark."); /* NOTREACHED */ } return curmark; } void ExchPtMark() { LinePtr mline; int mchar; Mark *m = CurMark(); mline = curline; mchar = curchar; ToMark(m); if (MarkHighlighting) makedirty(m->m_line); MarkSet(m, mline, mchar); } /* Fix marks after a deletion. */ void DFixMarks(line1, char1, line2, char2) register LinePtr line1, line2; int char1, char2; { register Mark *m; LinePtr lp; if (curbuf->b_marks == NULL) return; for (lp = line1; lp != line2->l_next; lp = lp->l_next) { for (m = curbuf->b_marks; m != NULL; m = m->m_next) { if (m->m_line == lp && (lp != line1 || m->m_char > char1)) { if (lp == line2 && m->m_char > char2) { m->m_char -= char2-char1; } else { m->m_char = char1; if (line1 != line2) m->m_big_delete = YES; } m->m_line = line1; } } } } /* Fix marks after an insertion. */ void IFixMarks(line1, char1, line2, char2) register LinePtr line1, line2; int char1, char2; { register Mark *m; for (m = curbuf->b_marks; m != NULL; m = m->m_next) { if (m->m_line == line1 && m->m_char > char1) { m->m_line = line2; m->m_char += char2 - char1; } } } jove-4.17.5.5/marks.h000066400000000000000000000020311501102521500141700ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern void AllMarkReset proto((Buffer *b,LinePtr line)), DFixMarks proto((LinePtr line1,int char1,LinePtr line2,int char2)), DelMark proto((Mark *m)), IFixMarks proto((LinePtr line1, int char1, LinePtr line2, int char2)), MarkSet proto((Mark *m, LinePtr line, int column)), ToMark proto((Mark *m)), flush_marks proto((Buffer *)), do_set_mark proto((LinePtr l, int c)), set_mark proto((void)); extern Mark *CurMark proto((void)), *MakeMark proto((LinePtr line,int column)); /* Commands: */ extern void PopMark proto((void)), ExchPtMark proto((void)), SetMark proto((void)); jove-4.17.5.5/menumaps.txt000066400000000000000000000063671501102521500153100ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* menumaps.txt K. Mitchum 1/88. The same warnings apply as in keymaps.txt. You MUST use a version of setmaps compiled with MAC defined for this file to be converted correctly. */ #include "jove.h" #include "mac.h" #include "commands.h" #include "vars.h" #MENU data_obj MDIV = { STRING, "(-" }; data_obj MAJM = { STRING, "(Major Modes:" }; data_obj MINM = { STRING, "(Minor Modes:" }; data_obj BOOL = { STRING, "(Boolean:" }; data_obj DECM = { STRING, "(Decimal:" }; data_obj STRM = { STRING, "(String:" }; data_obj FILM = { STRING, "(File:" }; data_obj CHAR = { STRING, "(Character:" }; #define MENU_DIV &MDIV struct menu Menus[NMENUS] = { "File",101,0, { "visit-file", "find-file", "insert-file", MENU_DIV, "save-file", "write-file", MENU_DIV, "write-modified-files", "write-region", MENU_DIV, "write-macros-to-file", MENU_DIV, "exit-jove", 0 }, "Buffer",103,0, { &MAJM, "c-mode", "fundamental-mode", "lisp-mode", "text-mode", &MINM, "auto-fill-mode", "auto-indent-mode", "over-write-mode", "read-only-mode", "show-match-mode", "word-abbrev-mode", MENU_DIV, 0 }, "Window",104,0, { "grow-window", "shrink-window", MENU_DIV, "split-current-window", "delete-other-windows", "window-find", MENU_DIV, "number-lines-in-window", 0 }, "Point",105,0, { "set-mark", "exchange-point-and-mark", MENU_DIV, "search-forward", "search-reverse", "i-search-forward", "i-search-reverse", "query-replace-string", "replace-string", MENU_DIV, "find-tag", 0 }, "Command",106,0, { "begin-kbd-macro", "end-kbd-macro", "name-kbd-macro", "execute-kbd-macro", "execute-macro", MENU_DIV, "bind-macro-to-key", "bind-to-key", "describe-key", MENU_DIV, "execute-named-command", 0 }, "Set",107,0, { &BOOL, "allow-bad-characters-in-filenames", #ifdef ABBREV "auto-case-abbrev", #endif "case-ignore-search", #ifdef BIFF "disable-biff", #endif #ifdef F_COMPLETION "display-filenames-with-bad-extensions", #endif "files-should-end-with-newline", #ifdef HIGHLIGHTING "highlight-mark", #endif #ifdef MAC "macify", #endif #ifdef BACKUPFILES "make-backup-files", #endif "match-regular-expressions", "meta-key" "mode-line-should-standout", "one-key-confirmation", "scroll-all-lines", #ifdef HIGHLIGHTING "scroll-bar", #endif "send-typeout-to-buffer", "space-sentence-2", "visible-bell", "wrap-search", #ifdef SUBSHELL "write-files-on-make", #endif &DECM, "c-argument-indentation", "c-indentation-increment", "error-window-size", "left-margin", "mark-threshold", "paren-flash-delay", "right-margin", "scroll-step", #ifdef RECOVER "sync-frequency", #endif "tab-width", &FILM, "tag-file", "tmp-file-pathname", &STRM, #ifdef F_COMPLETION "bad-filename-extensions", #endif "comment-format", "error-format-string", "mode-line", "paragraph-delimiter-pattern", &CHAR, "abort-char", 0 } }; jove-4.17.5.5/misc.c000066400000000000000000000121221501102521500140030ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "disp.h" #include "ask.h" #include "c.h" #include "delete.h" #include "insert.h" #include "extend.h" #include "fmt.h" #include "marks.h" #include "misc.h" #include "move.h" #include "para.h" void prCTIME() { f_mess(": %f %s", get_time((time_t *)NULL, (char *)NULL, 0, -1)); stickymsg = YES; } void ChrToOct() { ZXchar c = ask_ks(); ins_str(sprint("\\%03o", c)); #ifdef PCNONASCII if (c == PCNONASCII) { c = waitchar(); ins_str(sprint("\\%03o", c)); } #endif } void StrLength() { static const char inquotes[] = "Where are the quotes?"; char *cp; int numchars = 0; for (cp = linebuf+curchar; ; cp--) { if (*cp == '"' && (cp == linebuf || cp[-1] != '\\')) break; if (cp == linebuf) { complain(inquotes); /* NOTREACHED */ } } cp += 1; /* skip opening quote */ for (;;) { switch (*cp++) { case '\0': complain(inquotes); /*NOTREACHED*/ case '"': f_mess("%d characters", numchars); stickymsg = YES; return; case '\\': if (!jisdigit(*cp)) { if (*cp == '\0') { complain(inquotes); /* NOTREACHED */ } cp += 1; } else { int num = 3; do cp += 1; while (--num != 0 && jisdigit(*cp)); } break; } numchars += 1; } } /* Transpose cur_char with cur_char - 1 */ void TransChar() { char before; if (curchar == 0 || (eolp() && curchar == 1)) { complain((char *)NULL); /* BEEP */ /* NOTREACHED */ } if (eolp()) b_char(1); before = linebuf[curchar - 1]; del_char(BACKWARD, 1, NO); f_char(1); insert_c(before, 1); } /* Switch current line with previous one */ void TransLines() { daddr old_prev; if (firstp(curline)) return; lsave(); /* Exchange l_dline values. * CHEAT: this breaks the buffer abstraction. * The getDOT unfools a few caching mechanisms. */ old_prev = curline->l_prev->l_dline; curline->l_prev->l_dline = curline->l_dline; curline->l_dline = old_prev; getDOT(); if (!lastp(curline)) line_move(FORWARD, 1, NO); else Eol(); /* can't move to next line, so we do the next best thing */ modify(); DOLsave = NO; /* CHEAT: contents of linebuf need not override l_dline. */ } /* exit-jove command */ void Leave() { longjmp(mainjmp, JMP_QUIT); /* NOTREACHED */ } /* If argument is specified, kill that many lines down. Otherwise, * if we "appear" to be at the end of a line, i.e. everything to the * right of the cursor is white space, we delete the line separator * as if we were at the end of the line. */ void KillEOL() { LinePtr line2; int char2; long num = arg_value(); if (is_an_arg()) { if (num == 0) { /* Kill to beginning of line */ line2 = curline; char2 = 0; } else { line2 = next_line(curline, num); if ((LineDist(curline, line2) < num) || (line2 == curline)) char2 = length(line2); else char2 = 0; } } else if (blnkp(&linebuf[curchar])) { line2 = next_line(curline, 1); if (line2 == curline) char2 = length(curline); else char2 = 0; } else { line2 = curline; char2 = length(curline); } reg_kill(line2, char2, NO); } /* kill to beginning of sentence */ void KillBos() { negate_arg(); KillEos(); } /* Kill to end of sentence */ void KillEos() { LinePtr line1; int char1; line1 = curline; char1 = curchar; Eos(); reg_kill(line1, char1, YES); } void KillExpr() { LinePtr line1; int char1; line1 = curline; char1 = curchar; FSexpr(); reg_kill(line1, char1, YES); } void Yank() { LinePtr line, lp; Bufpos *dot; if (killbuf[killptr] == NULL) { complain("[Nothing to yank!]"); /* NOTREACHED */ } lsave(); line = killbuf[killptr]; lp = lastline(line); dot = DoYank(line, 0, lp, length(lp), curline, curchar, curbuf); set_mark(); SetDot(dot); } void ToIndent() { Bol(); skip_wht_space(); } void skip_wht_space() { register char *cp = linebuf + curchar; while (jiswhite(*cp)) cp += 1; curchar = cp - linebuf; } /* GoLine -- go to a line, usually wired to goto-line, ESC g or ESC G. * If no argument is specified it asks for a line number. */ void GoLine() { LinePtr newline; if (!is_an_arg()) set_arg_value(ask_long("1", "Line: ", 10)); if (arg_value() < 0) newline = prev_line(curbuf->b_last, -1 - arg_value()); else newline = next_line(curbuf->b_first, arg_value() - 1); PushPntp(newline); SetLine(newline); } void NotModified() { unmodify(); } void SetLMargin() { int lmarg = calc_pos(linebuf, curchar); if (lmarg >= RMargin) { complain("[Left margin must be left of right margin]"); /* NOTREACHED */ } LMargin = lmarg; } void SetRMargin() { int rmarg = calc_pos(linebuf, curchar); if (rmarg <= LMargin) { complain("[Right margin must be right of left margin]"); /* NOTREACHED */ } RMargin = rmarg; } jove-4.17.5.5/misc.h000066400000000000000000000016411501102521500140140ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern void skip_wht_space proto((void)); /* Commands: */ extern void ChrToOct proto((void)), GoLine proto((void)), KillBos proto((void)), KillEOL proto((void)), KillEos proto((void)), KillExpr proto((void)), Leave proto((void)), NotModified proto((void)), SetLMargin proto((void)), SetRMargin proto((void)), StrLength proto((void)), ToIndent proto((void)), TransChar proto((void)), TransLines proto((void)), Yank proto((void)), prCTIME proto((void)); jove-4.17.5.5/mjovers.Hqx000066400000000000000000000021211501102521500150510ustar00rootroot00000000000000(This file must be converted with BinHex 4.0) :#QeUEhCP,R*cFQ-!2j!%5PB`-3#3#!1JIqJ!N!3"!*!$![i!!!(q!*!$SJ%,!3F ""J%'!3F"#3%(!3J"#3%+!38!"J!'!3S"#`!(#QeUEhCP,R*cFQ0b!J#30Cj)c4F !N!B$S!-5!!N!!J#3!c-!N$+L!%e5J!#3$`(!!*!,!`#3"6!!!!)Dd!#3#"!!N"- F5PB`-3#3!`&*3diM!*!&J%C548B!N!@!!*!("d&38%`!N!8"!2q3!`#J!!%![q- "`+!!!8#2rm&`J!!"8)2rm9b!!!&8Mrr"9)!!!95i!!&8J!!"92q3!e5!!!&8[q- "9)!!!952rm&8J!!"9)2rm95!!!&8Mrr"9)!!!95i!!&8J!!"92q3!e6rN!08)!! !9$rrrp3)!!!8$rrrp!)!!!3$rrrmrj!$!2q3!`$rN!2!rj!$`2q3!r$rN!2`rj! $r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj! $r2q3!rcrN!2mrj!$r2q3!rcrN!2mrj!$r2q3!r`rrrrm2rrrr!rrrr`2rrrm!rr rr!2rrr`!N!1Z!!B!N!@q!A)!dJ'Z"!*25`#3"5J!&!$`!8m!N!F$!"3!$3(##!* H-!#3"3m!&!!M!A`)!Pia!*!&+!&H!$F"c!J2B#!p)%963d&345"VCANZ%J#3"6F "AJ"'!F`)%N0[E@eKEQ3JB#!p)'!JDf9j,J#3"8X"AJ"Z!F`))80[ER4bEf`J25" $EfeYB@jN)'pb)%0[ER4bEf`J5f9j,JJ!N!-9!*!%!33"c!!"!*!)"q3!N!-"!*! $![i!!!(q!*!$SJ!"h(B%DJ#3!a`!PJ!&3Nj%6!#3!c*+9M!a!*!$2NC548B!N!0 +5801)`#3!eC%594-!*!$BN4-6dF!N!0Z!)$rr`#3"3(XXJ!!rrm!N!-J!!(Y!J# !rrm!N!-N!!(H8J#!rrm!N!-[!!(XpJINrrm!!!%c!!(XeJI3!*!%!H8!!HbL#d& #6e98AdT%6%p(Ep3: jove-4.17.5.5/mouse.c000066400000000000000000000667531501102521500142230ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* This file contains all functions associated with mouse buttons being * pressed and any movement of the mouse (except on the Macintosh). * These procedures will only be called if JOVE is run under xterm, * xJove, or Jovetool. */ #include "jove.h" #ifdef MOUSE /* the body is the rest of this file */ /* #include "argcount.h" */ #include "commands.h" /* for cmdproc_t */ #include "disp.h" #include "misc.h" #include "ask.h" #include "chars.h" #include "delete.h" #include "fmt.h" #include "insert.h" /* for lfreelist, in MouseLine */ #include "marks.h" #include "move.h" #include "wind.h" #include "term.h" /* for M_SR */ #include "fp.h" /* for putstr */ #include "jctype.h" #include "mouse.h" #include "xjove/mousemsg.h" /* xterm control sequences, including those related to mousing, are described * in a file called ctlseqs.ms which is part of the X Distribution. * * We document some xterm bugs/features here: a good place * to capture the hard-won knowledge. * * - In Hilite mode, after a button 1 press (producing ^[[M xy), and after * the program has replied with ^[f;sx;sy;fr;lrT (as required in Hilite * mode), it treats the next character read as if it had been preceded by * "^[[". For example, if that next character happens to be A, B, C or D * you therefore get a cursor movement. See the #ifdef XTERMHLBUG below * for the workaround. * * - mouse tracking and highlight tracking modes do not support modifiers * other than CTRL, contrary to ctlseqs.ms. See the #ifdef NEVER below. * * - mouse hilite tracking mode (MHTM) only seems to work for button 1. * * - MHTM does not seem to yield mouse-button-1-up events (but if * a non-empty drag occurred, that will be reported) * * - The documentation specifies that the ^[ [ T x y x y x y message * should only be generated by MHTM when the user has dragged outside * the specified bounds. It seems to also be generated: * + by a multiclick (of button 1, of course) * + by a drag to the left or up * + when the button is released to the right of the end of a text line * (but xterm's idea of this may well differ from JOVE's since JOVE * optimizes screen output) * * - When the mouse is enabled, xterm interprets ^[[ ... T as an * Initiate Hilite Mouse Tracking command. Otherwise, recent * versions interpret it as Parameterized Scroll Down. Some recent * termcap/terminfo xterm entries define the SR capability using * this sequence. But it doesn't work all the time! * It is hard to say what the best fix would be: * + get X to distinguish the two T commands by the number of parameters * + correctly document the limitation and remove SR from the * xterm termcap and terminfo datebases * * In any case, the problem will be in the wild for some time * so JOVE now has an ugly kludge to dodge the bug. * KLUDGE: suppress M_SR (our name for SR) if in mouse mode and M_SR * ends in "T". * * First observed and analyzed in Fedora Core 4 in 2005 September. * * - xterm has gained more capabilities over the years. Some misguided * people of revised the termcap/terminfo entries for xterm to exploit * new features. This has unfortunate consequences when the xterm * is on a different system from the termcap/terminfo database: * if they don't match, JOVE will potentially curdle the screen. * JOVE cannot work around this problem, the user must. */ jbool XtermMouse = NO; /* VAR: should we enable xterm mouse? */ private jbool xtMouseState = NO; /* have we enabled the mouse? */ /* sequences to enable/disable mouse hilite tracking in xterm */ private const char xtMouseEnable[] = "\033[?1001h", xtMouseDisable[] = "\033[?1001l"; private int but_state; /* button state (and more) at mouse event */ private int x_coord; /* mouse x-coordinate, in pixels, origin 0 */ private int y_coord; /* mouse y-coordinate, in characters, origin 0 */ private int /* xterm drag range coordinates */ startx, starty, endx, endy; private int font_width; /* width of a character in pixels */ private Window *oldwind; private Mark *oldpos = NULL; /* Use a Mark so it is adjusted automatically */ #define LMA_NONE 0000 #define LMA_COPY 0001 #define LMA_CUT 0002 #define LMA_PASTE 0010 #define LMA_CHAR 0020 #define LMA_WORD 0030 #define LMA_LINE 0040 private int last_mouse_act = LMA_NONE; private const char *saved_M_SR = NULL; /* KLUDGE for xterm/termcap bug */ void MouseOn() { if (XtermMouse != xtMouseState) { /* KLUDGE for xterm/termcap bug */ if (XtermMouse && M_SR != NULL) { size_t len = strlen(M_SR); saved_M_SR = M_SR; if (len > 0 && M_SR[len-1] == 'T') M_SR = NULL; } /* end if KLUDGE */ putstr(XtermMouse? xtMouseEnable : xtMouseDisable); xtMouseState = XtermMouse; } } void MouseOff() { if (xtMouseState) { putstr(xtMouseDisable); xtMouseState = NO; M_SR = saved_M_SR; /* KLUDGE for xterm/termcap bug */ } } /* Set cursor position to that of mouse pointer. */ private void SetCursor() { int line_pos = in_window(curwind, curline); int offset = PhysScreen[y_coord].s_offset; int num_moves; if (line_pos < 0) { SetLine(curwind->w_top); line_pos = in_window(curwind, curline); } num_moves = y_coord - line_pos; if (num_moves > 0) line_move(FORWARD, num_moves, NO); if (num_moves < 0) line_move(BACKWARD, -num_moves, NO); curchar = how_far(curline, (x_coord + font_width/2) / font_width + offset - (W_NUMWIDTH(curwind) + SIWIDTH(offset))); } private void ScrollToMouse() { register int lc; const int width = (CO - 1 - (4 * SG)) * font_width; /* must match size in ModeLine */ int top; /* This code ought to match the scroll-bar layout computed by * WindowRange(). * - a click in the first column ought to force top-of-file * - a click in the last column ought to force end-of-file * - don't waste space by displaying less than a screenful at end-of-file. * - After clicking at a given point in the scroll bar, the cursor * should be found to be exactly in the middle of the highlighted * region (except near the ends, of course). */ lc = LinesTo(curbuf->b_first, (LinePtr)NULL); top = 1 + (long)(x_coord-font_width) * (lc-2) / (width-2*font_width) - WSIZE(curwind)/2; if (top > lc - WSIZE(curwind)) top = lc - WSIZE(curwind); if (top < 0) top = 0; SetTop(curwind, next_line(curbuf->b_first, top)); if (in_window(curwind, curline) == -1) SetLine(next_line(curwind->w_top, WSIZE(curwind)/2)); } private jbool ObeyProc(p) cmdproc_t p; { if (BufMinorMode(curbuf, BReadOnly)) { rbell(); message("[Buffer is read-only]"); return NO; } else { (*p)(); return YES; } } /* Get next value in number sequence */ private int NextValue() { int val; (void) waitchar(); Digit(); val = arg_value(); clr_arg_value(); return val; } /* Select appropriate window */ private int SelectWind(winforce) Window *winforce; /* if non-null, must be within this window */ { register Window *wp = fwind; int total_lines = wp->w_height; /* Find which window mouse pointer is in. */ while (y_coord >= total_lines) { wp = wp->w_next; if (wp == fwind) return -1; total_lines += wp->w_height; } if (winforce != NULL && wp != winforce) return -1; SetWind(wp); /* Set current window */ return (total_lines - y_coord - 1); /* Cursor pos within window */ } /* get an origin-0 coordinate in funny representation used by xterm */ private int xtGetCoord(upb) int upb; { ZXchar c = waitchar(); /* coordinate */ /* undo MetaKey if we think it was done */ if (c == ESC && MetaKey) c = waitchar() | METABIT; /* It appears that mouse events near the extreme right hand edge of * a window can give coordinates as large as LI. Perhaps this is * true for CO too. So the range is inclusive. */ return '!' <= c && c - '!' <= upb? c - '!' : -1; } /* get some X Y pair from xterm; return indication of success */ private jbool xtGetXY(xp, yp) int *xp, *yp; { int x = xtGetCoord(CO); if (x != -1) { int y = xtGetCoord(LI); if (y != -1) { *xp = x; *yp = y; font_width = 1; return YES; } } return NO; } #define MPROTO_XTERM 0 #define MPROTO_XTDRAG 1 #define MPROTO_JOVETOOL 2 #define XtermProto(p) ((p) <= MPROTO_XTDRAG) /* Format of command to xterm to start or stop mouse hilite tracking: * ^[ [ func ; startx ; starty ; firstrow ; lastrow T * * [1997 September] All xterm's up until now have a bug whereby * the character sent after this sequence is interpreted as if * it were preceded by an ESC. We pad with an "x" character to * be ignored. * * [1998 Sept 21] XFree86 3.2's xterm fixes the original bug * so we have to refine our work-around: make sure that the * character to be ignored has no semantics (DEL). * * [2004 July 11] XFree86's xterm no longer ignores DEL! * This is an xterm bug. A fix to xterm has been accepted * by XFree86 and been submitted to x.org. Even so, * this bug will be in the field for a long time, so we * need to live with it. * The only character that seems to be reliably ignored * in XFree86-4.0.1's xterm is NUL. * * This fudge is intended to be harmless on xterms * with or without these bugs. */ #define XTERMHLBUG 1 /* always enable: we think that it is safe */ static void hl_mode(hl_setting, startx, starty, endx, endy) int hl_setting, startx, starty, endx, endy; { static const char hl_fmt[] = "\033[%d;%d;%d;%d;%dT"; char buf[sizeof(hl_fmt) + 4*(5-2)]; swritef(buf, sizeof(buf), hl_fmt, hl_setting, startx, starty, endx, endy); putstr(buf); #ifdef XTERMHLBUG scr_putchar('\0'); #endif } private jbool MouseParams(mproto) int mproto; { /* The mouse commands will be invoked by hitting a mouse * button but can also be invoked by typing the escape sequence * CTRL-Xm so the following validation checks are necessary. */ static int wind_pos; /* reverse y-coordinate within window */ static jbool mode_mode = NO; /* true while doing modeline */ /* up_expected is an extended jbool: it can be YES, NO, and -1! * -1 signifies that we are in xterm mouse hilite tracking mode * which appears to fail to yield an up event if it deems the * event uninteresting (i.e. no motion). */ static int up_expected = NO; /* true while button held down */ static int estartx, estarty; /* from last enable */ jbool input_good = NO; /* This switch reads and decodes the control sequence. * - input_good is set to YES if the sequence looks valid. * - but_state, x_coord, and y_coord are changed to reflect the new state * - if the event could follow an "initiate hilite tracking" * and up_expected is -1, the decoder should adjust up_expected. */ switch (mproto) { case MPROTO_XTERM: { ZXchar cb = LastKeyStruck; switch (cb) { default: if (' ' <= cb && cb < ' '+040 && xtGetXY(&x_coord, &y_coord)) { /* ^[ [ M buttoninfo mousex mousey * Button event with coordinates. * On a release event we aren't told which button * is being released. */ cb -= ' '; if ((cb & 03) == 03) { /* guess that released button is last depressed */ but_state = (but_state & JT_BUTMASK) | JT_UPEVENT; /* We are welcome in xterm mouse hilite tracking mode */ if (up_expected == -1) up_expected = YES; } else { static const int butcode[] = { JT_LEFT, JT_MIDDLE, JT_RIGHT }; but_state = butcode[cb & 03] | JT_DOWNEVENT; /* We are welcome in xterm mouse hilite tracking mode */ if (up_expected == -1) up_expected = NO; } #ifdef NEVER /* surprise: xterm won't generate these modifiers! */ if (cb & 04) but_state |= JT_SHIFT; if (cb & 010) but_state |= JT_META; #endif if (cb & 020) but_state |= JT_CONTROL; input_good = YES; } break; } } break; case MPROTO_XTDRAG: /* handle xterm hilite tracking drag event: ^[ [ t or ^[ [ T * These are only generated for left-button acts. * Each is some drag-like event. */ switch (LastKeyStruck) { case 'T': /* ^[ [ T startx starty endx endy mousex mousey * returned on Left Button release beyond end-of-line, * or (undocumented) a drag to left or up, or * (undocumented) for a multi-click select. These are * transformed into three kinds of event, distinguished * by JT_CLICK2 and JT_CLICK3. The JT_CLICKn are used to * indicate that it was a multi-click select (by * eliminating the other cases). Note that a double click * beyond end-of-line (or on an empty line) is not reported * even though a third such click is. Oh the joys of * relying on undocumented features! */ if (xtGetXY(&startx, &starty) && xtGetXY(&endx, &endy) && xtGetXY(&x_coord, &y_coord)) { input_good = YES; if ((( endy != estarty || endx != estartx || y_coord > estarty || (y_coord == estarty && x_coord >= estartx) ) /* it isn't a drag left or up */ && ( endx != 0 || startx == endx ) /* it isn't a drag across an e-o-l */ ) || (but_state & JT_CLICKMASK) == JT_CLICK2) /* it is clearly a third click */ { /* a complex selection */ if ((but_state & JT_CLICKMASK) == JT_CLICK2 || endx == 0) /* this is a third click: * endx == 0 implies that we * missed the second one */ but_state = JT_LEFT | JT_DRAGEVENT | JT_CLICK3; else but_state = JT_LEFT | JT_DRAGEVENT | JT_CLICK2; } else { /* A simple drag. * Note: code is the same as for case 't' below. */ but_state = JT_LEFT | JT_DRAGEVENT; } } break; case 't': /* ^[ [ t mousex mousey * returned on Left Button release within valid text. * A simple drag. * Note: code is duplicated above as part of case 'T'. */ if (xtGetXY(&x_coord, &y_coord)) { but_state = JT_LEFT | JT_DRAGEVENT; input_good = YES; } break; } /* We are welcome in xterm mouse hilite tracking mode */ if (input_good && up_expected == -1) up_expected = YES; break; case MPROTO_JOVETOOL: if (waitchar() == '(') { but_state = NextValue(); /* Read in parameters */ switch (waitchar()) { case ' ': { int x = NextValue(); if (waitchar() == ' ') { int y = NextValue(); if (waitchar() == ' ') { font_width = NextValue(); if (waitchar() == ')' && waitchar() == '\r') { input_good = YES; x_coord = x; y_coord = y; } } } } break; case ')': input_good = (waitchar() == '\r'); break; } } break; } this_cmd = OTHER_CMD; /* no longer gathering args */ if (!input_good) { if (XtermProto(mproto) && but_state == (JT_LEFT | JT_DOWNEVENT)) { /* abort Hilite mode to prevent hangups */ hl_mode(0,1,1,1,1); } complain("[mouse input of wrong format]"); /* NOTREACHED */ } /* Note: at this point, up_expected still reflects previous state. * Unfortunately, xterm seems to elide some button-up events! * For this reason, some cases above adjust up_expected to * prevent the following sanity check from going off. */ /* check: button_(was)_held iff currently event is UP or DRAG */ if (up_expected != ((but_state & JT_EVENTMASK)!=JT_DOWNEVENT) || (up_expected == YES && last_cmd != MOUSE_CMD)) { if (XtermProto(mproto) && but_state == (JT_LEFT | JT_DOWNEVENT)) { /* abort Hilite mode to prevent hangups */ hl_mode(0,1,1,1,1); } up_expected = NO; /* resynch in neutral */ complain("[Mouse events out of order]"); /* NOTREACHED */ } /* update up_expected to reflect new state */ up_expected = XtermProto(mproto) && (but_state&JT_EVENTMASK) == JT_DRAGEVENT ? -1 : (but_state & JT_EVENTMASK) != JT_UPEVENT; if (up_expected != NO) this_cmd = MOUSE_CMD; if ((but_state & JT_EVENTMASK) == JT_DOWNEVENT && (but_state & JT_PASTEMASK) && (but_state & JT_CSMASK) == 0) { /* Hugh: ??? is this leak possible? -- checking code added as a probe. */ /* CHL believes assert oldpos==NULL */ if (oldpos != NULL) { complain("[internal error: mark leak from MouseParams]"); /* NOTREACHED */ } oldpos = MakeMark(curline, curchar); } /* UP events in xterm should do nothing in foreign windows */ if (XtermProto(mproto) && (but_state & JT_EVENTMASK) == JT_UPEVENT && curwind != oldwind && !mode_mode) return NO; if ((but_state & (JT_CLICKMASK | JT_EVENTMASK)) == JT_DOWNEVENT) { /* button down, and first click at that: * - ok to changing window * - ok to move in or out of modeline (scroll bar) */ oldwind = curwind; wind_pos = SelectWind((Window *) NULL); mode_mode = (wind_pos == 0); if (XtermProto(mproto) && but_state == (JT_LEFT | JT_DOWNEVENT)) { /* Initiate or abort mouse hilite tracking. We use hilite * tracking if we are not on the modeline. * When hilite tracking is used, apparently the up event is * elided if it would report no change in location. */ jbool use_hilite = !mode_mode; if (use_hilite) up_expected = -1; /* half-expect an up */ hl_mode(use_hilite, (estartx = x_coord)+1, (estarty = y_coord)+1, y_coord + wind_pos - curwind->w_height + 2, y_coord + wind_pos + 1); } } else if (!mode_mode) { /* can only stay within the window, and cannot switch into modeline */ wind_pos = SelectWind(oldwind); } if (mode_mode) { /* An event in mode_mode only scrolls or resizes, with no * action (unless it were a first down event, when it might * have caused a new window to be selected). Shifts and * multiclicks indicate a confused user. */ if ((but_state & JT_BUTMASK) == JT_LEFT && (but_state & JT_EVENTMASK) != JT_UPEVENT) { ScrollToMouse(); if (but_state & (JT_CSMASK | JT_CLICKMASK)) { complain("[You are just scrolling a window]"); /* NOTREACHED */ } } else if ((but_state & JT_BUTMASK) == JT_MIDDLE && (but_state & (JT_UPEVENT | JT_DRAGEVENT)) != 0) { oldwind = curwind; if ((wind_pos = SelectWind((Window *) NULL)) < 0) return NO; if (curwind == oldwind->w_next) { wind_pos -= curwind->w_height; SetWind(oldwind); } if (curwind == oldwind && curwind->w_next != fwind) WindSize(curwind->w_next, wind_pos); if (but_state & (JT_CSMASK | JT_CLICKMASK)) { complain("[You are just resizing a window]"); /* NOTREACHED */ } } } else if ((but_state & JT_PASTEMASK) && (but_state & JT_CSMASK) == 0) { /* With JT_PASTE/CUT, window switching is allowed. */ return YES; } else if (curwind != oldwind) { /* Clicking within a different window (as opposed to its * mode line) only switches to that window, with no action. * Other shifts and multiclicks indicate a confused user. */ if (but_state & (JT_CSMASK | JT_CLICKMASK)) { complain("[You were just changing windows]"); /* NOTREACHED */ } } else if (wind_pos <= 0) { /* ignore out-of-window events */ } else { /* We've run the gauntlet. Give the OK for action. */ return YES; } last_mouse_act = LMA_NONE; if (oldpos != NULL) { SetWind(oldwind); DelMark(oldpos); oldpos = NULL; } return NO; } private void MousePoint(mproto) int mproto; { last_mouse_act = LMA_NONE; if (MouseParams(mproto)) SetCursor(); } void xjMousePoint() { MousePoint(MPROTO_JOVETOOL); } void xtMousePoint() { MousePoint(MPROTO_XTERM); } private void MouseMark(mproto) int mproto; { last_mouse_act = LMA_NONE; if (MouseParams(mproto)) { SetCursor(); set_mark(); } } void xjMouseMark() { MouseMark(MPROTO_JOVETOOL); } void xtMouseMark() { MouseMark(MPROTO_XTERM); } /* xtMouseYank is a reduced xtMousePointYank. * Although xtMousePointYank should be more useful, * xtMouseYank is more like XTerm's native behavior. */ void xtMouseYank() { last_mouse_act = LMA_NONE; if (MouseParams(MPROTO_XTERM)) { ObeyProc(Yank); this_cmd = MOUSE_CMD; } } void xtMousePointYank() { last_mouse_act = LMA_NONE; if (MouseParams(MPROTO_XTERM)) { SetCursor(); ObeyProc(Yank); this_cmd = MOUSE_CMD; } } void xtMouseCutPointYank() { Mark *m; last_mouse_act = LMA_NONE; if (MouseParams(MPROTO_XTERM) && ObeyProc(set_mark)) { SetCursor(); set_mark(); m = curmark; PopMark(); /* pop our 2nd set_mark */ PopMark(); /* pop our 1st set_mark */ DelReg(); /* because we are (usually) about to yank the same region again */ ToMark(m); Yank(); this_cmd = MOUSE_CMD; } } void xtMouseNull() { MouseParams(MPROTO_XTERM); } /* Double clicking selects either an identifier (according to the current * major mode) or, if the current char is not part of an identifier, it * selects the gap between two identifiers. However, the selection is always * within one line. startMouseWord and endMouseWord are called to locate the * two ends of the selected (un)identifier. Note that the selection can be * empty. */ private void startMouseWord() { jbool in_id; if (eolp() && !bolp()) curchar -= 1; in_id = jisident(linebuf[curchar]); while (!bolp() && jisident(linebuf[curchar-1]) == in_id) curchar -= 1; } private void endMouseWord() { jbool in_id; if (eolp() && !bolp()) curchar -= 1; in_id = jisident(linebuf[curchar]); while (!eolp() && jisident(linebuf[curchar]) == in_id) curchar += 1; } private void doMouseWord() { startMouseWord(); set_mark(); endMouseWord(); } private void doMouseLine() { Bol(); set_mark(); line_move(FORWARD, 1, NO); } /* * This command extends the region, at either end, in units of chars, words, * or lines depending on last_mouse_act (i.e. on whether the region was * selected by dragging, single or double clicking). If used to shrink the * region, it is the point end (not the mark end) that gets moved. */ private jbool doMouseExtend() { jbool region_forward, new_forward; if (last_mouse_act == LMA_NONE) return NO; /* treat as xtMouseNull */ region_forward = !inorder(curline, curchar, curmark->m_line, curmark->m_char); ExchPtMark(); /* for better effect when shrinking region */ set_mark(); SetCursor(); new_forward = !inorder(curline, curchar, curmark->m_line, curmark->m_char); switch (last_mouse_act) { case LMA_CHAR: if (region_forward != new_forward) { PopMark(); SetCursor(); } break; case LMA_WORD: if (region_forward != new_forward) { PopMark(); SetCursor(); } if (new_forward) endMouseWord(); else startMouseWord(); break; case LMA_LINE: if (region_forward != new_forward) { PopMark(); SetCursor(); } Bol(); if (new_forward) line_move(FORWARD, 1, NO); break; } return !(curmark->m_line==curline && curmark->m_char==curchar); } /* This command is intended to be bound to ^[ [ t and ^[ [ T, which * are the button UP events for the left button in Hilite mode. * It is not clear whether or not these codes should be produced * after a simple click, so the following code plays safe. * * Should a multiclick select what XTerm shows ("visual fidelity"), * thus using XTerm's definition of "word", or should it select based * on JOVE's version of "word"? To select the latter, define XTJOVEWORD. * * This choice also affects how JOVE decides at which end of the selection * "point" should be placed. * * - When JOVE uses its own definition of word or line (they are of a piece) * it selects the current unit, and then, if necessary, extends to envelop * the current mouse position. If no extension is needed the point will be * at the right. If extension is needed (usually because a drag was used) * point will be at the far end of the extension. This sounds complicated, * but feels quite nice. * * - When JOVE uses XTerm's selection range, it places point at the end * closest to the final mouse position. This sounds simple, but it may * be slightly surprising when no drag was done. */ void xtMouseMarkDragPointCopy() { if (MouseParams(MPROTO_XTDRAG)) { /* assert((but_state & JT_EVENTMASK) == JT_DRAGEVENT) */ if ((but_state & JT_CLICKMASK) == 0) { /* simple (character-based) drag (from point to mouse) */ set_mark(); SetCursor(); CopyRegion(); last_mouse_act = LMA_CHAR; #ifdef XTJOVEWORD } else if ((but_state & JT_CLICKMASK) == JT_CLICK2) { /* select based on JOVE's notion of words */ doMouseWord(); last_mouse_act = LMA_WORD; if (doMouseExtend()) CopyRegion(); } else /* ((but_state & JT_CLICKMASK) == JT_CLICK3) */ { /* select lines */ if (last_mouse_act == LMA_WORD) { /* Second click was not missed. * Avoid nasty mark and kill buildup. */ PopMark(); DelKillRing(); } doMouseLine(); last_mouse_act = LMA_LINE; if (doMouseExtend()) CopyRegion(); } #else } else { /* select based on xterm's selection: startxy through endxy * Set point to whichever is closer to mouse position * and set mark to farther. */ int which_end; /* distance difference: negative if closer to start */ if (last_mouse_act != LMA_NONE) { /* avoid nasty mark and kill buildup */ PopMark(); DelKillRing(); } which_end = (y_coord - starty) - (endy - y_coord); if (which_end == 0) which_end = (x_coord - startx) - (endx - x_coord); x_coord = startx; y_coord = starty; SetCursor(); set_mark(); x_coord = endx; y_coord = endy; SetCursor(); if (which_end < 0) ExchPtMark(); CopyRegion(); last_mouse_act = last_mouse_act == LMA_WORD? LMA_LINE : LMA_WORD; } #endif } } /* Extend the region to the pointed-at character, word or line * (depending on last_mouse_act). Only valid after an event which * selects and copies a region (e.g. xtMouseMarkDragPointCop). */ void xtMouseExtend() { if (MouseParams(MPROTO_XTERM)) { if (doMouseExtend()) { DelKillRing(); CopyRegion(); } } } /* undo effect of preceding MouseCopyCut, if any */ private void MouseUndo() { if (last_mouse_act & LMA_PASTE) { ObeyProc(DelReg); /* at old curwind/line/char */ this_cmd = MOUSE_CMD; PopMark(); } SelectWind((Window *)NULL); switch (last_mouse_act & ~LMA_PASTE) { case LMA_CUT: ToMark(CurMark()); Yank(); this_cmd = MOUSE_CMD; PopMark(); /*FALLTHROUGH*/ case LMA_COPY: /* remove the entry we previously put in the kill-ring */ ToMark(CurMark()); DelKillRing(); } PopMark(); last_mouse_act = LMA_NONE; } void xjMouseWord() { if (MouseParams(MPROTO_JOVETOOL)) { MouseUndo(); doMouseWord(); } } void xjMouseLine() { if (MouseParams(MPROTO_JOVETOOL)) { MouseUndo(); SetCursor(); doMouseLine(); } } void xjMouseYank() { last_mouse_act = LMA_NONE; if (MouseParams(MPROTO_JOVETOOL)) { SetCursor(); if (but_state & JT_CONTROL) ObeyProc(Yank); } } void xjMouseCopyCut() { register Mark *mp = curmark; if (MouseParams(MPROTO_JOVETOOL)) { if (mp!=NULL && (mp->m_line != curline || mp->m_char != curchar)) { switch(but_state & (JT_CSMASK | JT_PASTEMASK)) { case JT_CONTROL: CopyRegion(); last_mouse_act = LMA_COPY; break; case JT_CONTROL | JT_SHIFT: last_mouse_act = ObeyProc(DelReg)? LMA_CUT : LMA_NONE; break; case JT_PASTE: CopyRegion(); SetWind(oldwind); ToMark(oldpos); ObeyProc(Yank); DelMark(oldpos); oldpos = NULL; last_mouse_act = LMA_COPY | LMA_PASTE; break; case JT_CUT: ObeyProc(DelReg); SetWind(oldwind); ToMark(oldpos); ObeyProc(Yank); DelMark(oldpos); oldpos = NULL; last_mouse_act = LMA_CUT | LMA_PASTE; break; /* default: ignore */ } } else if (but_state & JT_PASTEMASK) { SetWind(oldwind); ToMark(oldpos); DelMark(oldpos); oldpos = NULL; } } } #endif /* MOUSE */ jove-4.17.5.5/mouse.h000066400000000000000000000020771501102521500142150ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef MOUSE /* the body is the rest of this file */ extern void MouseOn proto((void)), MouseOff proto((void)), xjMousePoint proto((void)), xjMouseMark proto((void)), xjMouseWord proto((void)), xjMouseLine proto((void)), xjMouseYank proto((void)), xjMouseCopyCut proto((void)), xtMouseYank proto((void)), xtMousePointYank proto((void)), xtMouseCutPointYank proto((void)), xtMouseExtend proto((void)), xtMouseMark proto((void)), xtMouseMarkDragPointCopy proto((void)), xtMouseNull proto((void)), xtMousePoint proto((void)); extern jbool XtermMouse; /* VAR: should we enable xterm mouse? */ #endif /* MOUSE */ jove-4.17.5.5/move.c000066400000000000000000000122341501102521500140220ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "re.h" #include "chars.h" #include "jctype.h" #include "disp.h" #include "move.h" #include "screen.h" /* for tabstop */ private int line_pos; void f_char(n) register long n; { if (n < 0) { b_char(-n); return; } while (--n >= 0) { if (eolp()) { /* Go to the next Line */ if (curline->l_next == NULL) break; SetLine(curline->l_next); } else curchar += 1; } } void b_char(n) register long n; { if (n < 0) { f_char(-n); return; } while (--n >= 0) { if (bolp()) { if (curline->l_prev == NULL) break; SetLine(curline->l_prev); Eol(); } else curchar -= 1; } } void ForChar() { f_char(arg_value()); } void BackChar() { b_char(arg_value()); } void NextLine() { if ((curline == curbuf->b_last) && eolp()) { complain(NullStr); /* NOTREACHED */ } line_move(FORWARD, arg_value(), YES); } void PrevLine() { if ((curline == curbuf->b_first) && bolp()) { complain(NullStr); /* NOTREACHED */ } line_move(BACKWARD, arg_value(), YES); } /* moves to a different line in DIR; LINE_CMD says whether this is * being called from NextLine() or PrevLine(), in which case it tries * to line up the column with the column of the current line */ void line_move(dir, n, line_cmd) int dir; long n; jbool line_cmd; { LinePtr (*proc) ptrproto((LinePtr, long)) = (dir == FORWARD) ? next_line : prev_line; LinePtr line; line = (*proc)(curline, n); if (line == curline) { if (dir == FORWARD) Eol(); else Bol(); return; } if (line_cmd) { this_cmd = LINECMD; if (last_cmd != LINECMD) line_pos = calc_pos(linebuf, curchar); } SetLine(line); /* curline is in linebuf now */ if (line_cmd) curchar = how_far(curline, line_pos); } /* how_far returns what cur_char should be to be at or beyond col * screen columns in to the line. * * Note: if col indicates a position in the middle of a Tab or other * extended character, the result corresponds to that character * (as if col had indicated its start). * * Note: the calc_pos, how_far, and DeTab must be in synch -- * each thinks it knows how characters are displayed. */ int how_far(line, col) LinePtr line; int col; { register char *lp; register int pos; register ZXchar c; char *base; base = lp = lcontents(line); pos = 0; do { if ((c = ZXC(*lp)) == '\t' && tabstop != 0) { pos += TABDIST(pos); } else if (jisprint(c)) { pos += 1; } else { if (c <= DEL) pos += 2; else pos += 4; } lp += 1; } while (pos <= col && c != '\0'); return lp - base - 1; } void Bol() { curchar = 0; } void Eol() { curchar = length(curline); } void Eof() { PushPntp(curbuf->b_last); ToLast(); } void Bof() { PushPntp(curbuf->b_first); ToFirst(); } /* Move forward (if dir > 0) or backward (if dir < 0) a sentence. Deals * with all the kludgery involved with paragraphs, and moving backwards * is particularly yucky. */ private void to_sent(dir) int dir; { for (;;) { Bufpos old, /* where we started */ *new; /* where dosearch stopped */ DOTsave(&old); new = dosearch( "^[ \t]*$\\|[?.!]\\{''\\|[\"')\\]]\\|\\}\\{$\\|[ \t]\\}", dir, YES); if (new == NULL) { if (dir == BACKWARD) ToFirst(); else ToLast(); break; } SetDot(new); if (dir < 0) { to_word(FORWARD); if ((old.p_line != curline || old.p_char > curchar) && (!inorder(new->p_line, new->p_char, old.p_line, old.p_char) || !inorder(old.p_line, old.p_char, curline, curchar))) break; SetDot(new); } else { if (blnkp(linebuf)) { Bol(); b_char(1); if (old.p_line != curline || old.p_char < curchar) break; to_word(FORWARD); /* Oh brother this is painful */ } else { curchar = REbom + 1; /* Just after the [?.!] */ if (LookingAt("''\\|[\"')\\]]", linebuf, curchar)) curchar = REeom; break; } } } } void Bos() { register int num = arg_value(); if (num < 0) { negate_arg(); Eos(); } else { while (--num >= 0) { to_sent(BACKWARD); if (bobp()) break; } } } void Eos() { register int num = arg_value(); if (num < 0) { negate_arg(); Bos(); } else { while (--num >= 0) { to_sent(FORWARD); if (eobp()) break; } } } void f_word(num) register long num; { if (num < 0) { while (++num <= 0) { to_word(BACKWARD); while (!bolp() && jisword(linebuf[curchar - 1])) curchar -= 1; if (bobp()) break; } } else { while (--num >= 0) { register char c; to_word(FORWARD); while ((c = linebuf[curchar]) != '\0' && jisword(c)) curchar += 1; if (eobp()) break; } } /* ??? why is the following necessary? -- DHR */ this_cmd = OTHER_CMD; /* Semi kludge to stop some unfavorable behavior */ } void ForWord() { f_word(arg_value()); } void BackWord() { f_word(-arg_value()); } jove-4.17.5.5/move.h000066400000000000000000000017171501102521500140330ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern void b_char proto((long n)), f_char proto((long n)), f_word proto((long num)), line_move proto((int dir, long n, jbool line_cmd)); extern int how_far proto((LinePtr line,int col)); /* Commands: */ extern void BackChar proto((void)), BackWord proto((void)), Bof proto((void)), Bol proto((void)), Bos proto((void)), Eof proto((void)), Eol proto((void)), Eos proto((void)), ForChar proto((void)), ForWord proto((void)), ForIdent proto((void)), NextLine proto((void)), PrevLine proto((void)); jove-4.17.5.5/msgetch.c000066400000000000000000000157521501102521500145160ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* MSDOS keyboard routines */ #include "jove.h" #ifdef MSDOS /* the body is the rest of this file */ #include "chars.h" #include "disp.h" /* for redisplay() */ #include #include private void rawkey_wait proto((void)); #ifdef IBMPCDOS private ZXchar last = EOF; jbool enhanced_keybrd; /* VAR: exploit "enhanced" keyboard? */ /* Unlike the other _NKEYBRD services, the _NKEYBRD_READY service * *requires* specific support within _bios_keybrd. In particular * the key information is returned in the ZF flag, which is not * captured otherwise. If _NKEYBRD_READY is defined in the headers, * we presume that _bios_keybrd supports it. */ # ifdef _NKEYBRD_READY # define jkbready() \ (_bios_keybrd(enhanced_keybrd? _NKEYBRD_READY : _KEYBRD_READY) != 0) # else /* !_NKEYBRD_READY */ # ifdef ZTCDOS /* Workaround for Zortech 3.0: use Zortech's asm() capability. * * Interrupt 16h, service 1h (get keyboard status) and * interrupt 16h, service 11h (get enhanced keyboard status) * return with ZF cleared iff there is a character. * The zkbready macro returns YES iff there is a character. * * Note that the nature of the Zortech asm facility demands * that the "service" argument be a constant expression. */ # define zkbready(service) (0 == (int) asm( \ 0xB4, service, /* mov ah,service */ \ 0xCD, 0x16, /* int 16h */ \ 0x9F, /* lahf */ \ 0x25, 0x00, 0x40, /* and ax,04000h */ \ 0x99 /* cwd [needed due to a Zortech bug] */ \ )) # define _NKEYBRD_READY 0x11 # define jkbready() \ (enhanced_keybrd? zkbready(_NKEYBRD_READY) : zkbready(_KEYBRD_READY)) # endif/* ZTCDOS */ # endif /* !_NKEYBRD_READY */ # ifdef jkbready /* we can support enhanced keyboard */ # ifndef _NKEYBRD_READ # define _NKEYBRD_READ 0x10 # endif # define jkbread() _bios_keybrd(enhanced_keybrd? _NKEYBRD_READ : _KEYBRD_READ) # ifndef _NKEYBRD_SHIFTSTATUS # define _NKEYBRD_SHIFTSTATUS 0x12 # endif # define jkbshift() _bios_keybrd(enhanced_keybrd? _NKEYBRD_SHIFTSTATUS : _KEYBRD_SHIFTSTATUS) # else /* !kebready */ /* We don't know how to support the enhanced keyboard, so we won't */ # define jkbready() _bios_keybrd(_KEYBRD_READY) # define jkbread() _bios_keybrd(_KEYBRD_READ) # define jkbshift() _bios_keybrd(_KEYBRD_SHIFTSTATUS) # endif /* !kebready */ /* This table returns an Ascii character corresponding to a Scan Code index. * If a key has no ASCII equivalent, the table contains 0. */ static const char scanToAsciiLower[] = { /* 00 */ 0, '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', '\\', '\b', /* 10 */ '-', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', 0, 0, 'a', /* 20 */ 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 0, '\r', 0, 'z', 'x', /* 30 */ 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 0, 0, 0, 0, 0, ' ', 0, 0 }; static const char scanToAsciiUpper[] = { /* 00 */ 0, '!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '_', '+', '|', '\177', /* 10 */ '_', 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P', '{', '}', 0, 0, 'A', /* 20 */ 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L', ':', '\"', 0, '\r', 0, 'Z', 'X', /* 30 */ 'C', 'V', 'B', 'N', 'M', '<', '>', '?', 0, 0, 0, 0, 0, ' ', 0, 0 }; #endif /* IBMPCDOS */ ZXchar getrawinchar() { #ifdef IBMPCDOS unsigned scan; if (last != EOF) { scan = last; last = EOF; return scan; } rawkey_wait(); scan = jkbread(); /* check for Ctrl-spacebar and magically turn it into a Ctrl-@ * (scan == 0x03, char == 0x00). Because keystrokes are queued * but shift state is real-time, we add a (heuristic!) check * requiring that no further characters are in the queue. * Warning: the heuristic is not perfect. The control could be * recognized even if the it was pressed after the spacebar was * released! */ if ((scan&0xff) == ' ' && (jkbshift() & 0x04) && !jkbready()) scan = 0x0300; if ((scan&0xff) == 0 || (scan&0xff) == 0xe0) { ZXchar next = ZXRC(scan >> 8); ZXchar asciiChar; if (MetaKey && next < sizeof(scanToAsciiUpper) && 0 != (asciiChar = ((jkbshift() & 0x03) && !jkbready() ? scanToAsciiUpper : scanToAsciiLower)[next])) { last = asciiChar; scan = ESC; } else { /* Re-map shifted arrow keys and shifted Insert, Delete, Home, End, * PgUp, and PgDn from 71-83 to 171-183. This hack depends on * the same heuristic as the ctrl-spacebar hack. */ if (71 <= next && next <= 83 && (jkbshift() & 0x03) && !jkbready()) next += 100; /* Re-map keys that should have been ASCII */ switch (next) { case 0x03: /* ^@ and ^Space key */ scan = '\0'; /* ASCII NUL */ break; case 0x53: /* Delete key */ scan = DEL; /* ASCII DEL */ break; default: last = next; /* not ASCII: more to come next time */ scan = PCNONASCII; break; } } } return scan&0xff; #else /* !IBMPCDOS */ # ifdef RAINBOW union REGS regs; rawkey_wait(); for (;;) { regs.x.di = 2; int86(0x18, ®s, ®s); if (regs.h.al != 0) /* should never happen, but who knows */ return regs.h.al; } # else /* !RAINBOW */ rawkey_wait(); return bdos(0x06, 0x00ff, 0xff) & 0xff; # endif /* !RAINBOW */ #endif /* !IBMPCDOS */ } private jbool waiting = NO; jbool rawkey_ready() { #ifdef IBMPCDOS return !waiting && (last != EOF || jkbready()); #else /* !IBMPCDOS */ union REGS regs; if (waiting) return NO; # ifdef RAINBOW regs.x.di = 4; int86(0x18, ®s, ®s); return regs.h.cl != 0; # else /* !RAINBOW */ regs.h.ah = 0x44; /* ioctl call */ regs.x.bx = 0; /* stdin file handle */ regs.h.al = 0x06; /* get input status */ intdos(®s, ®s); return regs.h.al & 1; # endif /* !RAINBOW */ #endif /* !IBMPCDOS */ } /* Wait for next character, updating the modeline if it displays the time. * NOTE: this is a busy wait. */ private void rawkey_wait() { while (!rawkey_ready()) { if (UpdModLine) { waiting = YES; redisplay(); waiting = NO; } else if (TimeDisplayed) { struct dostime_t tc; static char lastmin = 0; _dos_gettime(&tc); if (tc.minute != lastmin) { UpdModLine = YES; lastmin = tc.minute; } } else { /* No reason to busy wait: return to do a blocking read. * This might improve performance in multitasking systems. */ break; } } } void ttysetattr(n) jbool n; /* also used as subscript! */ { static char break_state; if (n) { /* set the break state to off */ union REGS regs; regs.h.ah = 0x33; /* break status */ regs.h.al = 0x00; /* request current state */ intdos(®s, ®s); break_state = regs.h.dl; bdos(0x33, 0, 1); /* turn off break */ } else { /* restore the break state */ bdos(0x33, break_state, 1); } } #endif /* MSDOS */ jove-4.17.5.5/old/000077500000000000000000000000001501102521500134645ustar00rootroot00000000000000jove-4.17.5.5/old/Makefile.bcc000066400000000000000000000122351501102521500156550ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## # Makefile for Borland C/C++ 3.1 # # - supported targets: # + jjove.exe (build JOVE, but don't install it) # + jovedosx.zip (build executable JOVE kit) # + clean # # - to install, do the following: # + copy jjove.exe where you wish # + copy doc/cmds.doc to /cmds.doc # + optional: copy some jove rc (none supplied) file to /jove.rc # =================================================================== # Jove configuration: default JOVE paths. # Note that all these can be set from environment variables as well; # see README.DOS for details. # # TMPDIR is where the tmp files get stored, usually /tmp or /usr/tmp. # RECDIR is the directory in which RECOVER looks for JOVE's tempfiles. # LIBDIR is for the PORTSRV and RECOVER programs. # SHAREDIR is for online documentation, and the system-wide jove.rc file. ## BINDIR is where to put the executables JOVE and TEACHJOVE. # DFLTSHELL is the default shell invoked by JOVE and TEACHJOVE. TMPDIR = c:/tmp RECDIR = c:/tmp LIBDIR = c:/jove SHAREDIR = $(LIBDIR) # BINDIR = c:/jove DFLTSHELL = command # Compiler: CC = bcc # Compiler options # # Memory model: 'm' for medium or 'l' for large # MEM = -ml # Medium-model: # Uses a smaller buffer cache (3K vs 64K in large model), but can # still use (up to) all available memory for editing. If you have # a disk cache (e.g. smartdrv) running, you probably won't notice. # The medium model saves about 30K in size of jove.exe MEM = -mm # No floating point FP = -f- # Use 386 instructions # CPU = -3 # Optimizations: -Ox is untested # -Ox : fastest # -O1 : smallest # -Od : none at all OPT = -O1 # Suppress warnings about functions defined first but # not prototyped (pro) & structures declared but undefined (stu). # There are still a few unused variable warnings. WARN = -w-pro -w-stu # Debugging options: # -v : source level debugging # -N : compile in stack checking DEB = CFLAGS = $(MEM) $(FP) $(CPU) $(OPT) $(WARN) $(DEB) $(SYSDEFS) # Linker: LD = $(CC) # Flags peculiar to link step. Use '-l' to $(CC) to specify # a flag that is passed to the linker # m : create map file # LINKFLAGS = -lm LINKFLAGS = LDFLAGS = $(CFLAGS) $(LINKFLAGS) # =================================================================== # Don't rely on Borland make's builtin rules .SUFFIXES .exe .obj .c .c.obj: $(CC) $(CFLAGS) -c $< .obj.exe: $(LD) $(LDFLAGS) $< # Location of BCC libraries (needed to find wildargs.obj) # for BC/C++ v3.1: BCCLIB = c:/borlandc/lib # for BC/C++ v4.0: #BCCLIB = c:/borlandc/lib/16bit OBJECTS = keys.obj commands.obj abbrev.obj ask.obj buf.obj c.obj \ case.obj jctype.obj delete.obj extend.obj argcount.obj insert.obj \ io.obj jove.obj macros.obj marks.obj misc.obj mouse.obj move.obj \ para.obj proc.obj re.obj reapp.obj scandir.obj list.obj \ keymaps.obj util.obj vars.obj wind.obj fmt.obj disp.obj term.obj \ fp.obj screen.obj msgetch.obj ibmpcdos.obj HEADERS = abbrev.h argcount.h ask.h buf.h c.h case.h chars.h commands.h \ jctype.h dataobj.h delete.h disp.h extend.h externs.h \ fmt.h fp.h insert.h io.h iproc.h jove.h \ keymaps.h list.h loadavg.h mac.h macros.h marks.h \ misc.h mouse.h move.h para.h proc.h \ re.h reapp.h rec.h scandir.h screen.h \ sysdep.h sysprocs.h temp.h term.h ttystate.h \ tune.h util.h vars.h version.h wind.h # This is what we really want to use, but Borland's make complains # when a target appears in more than one rule. So, as it stands, # changing a header will *not* force recompilation :-( # # $(OBJECTS): $(HEADERS) # # For this reason, we can only force the building of paths.h # by adding it to the dependencies for explicit targets. # In the hope that it is built soon enough, we put it at the front. jjove.exe: paths.h $(OBJECTS) $(LD) $(LDFLAGS) -e$* @&&! $(BCCLIB)/wildargs.obj $(OBJECTS) ! jovedosx.zip: paths.h jjove.exe -del jovedosx.zip -del jove.exe rename jjove.exe jove.exe pkzip -aP jovedosx.zip jove.exe doc\*.* paths.h README.dos # Note that quotes are not stripped by the shell that will # execute the recipe for paths.h # The truly bizarre quoting is necessary to quote the pound # character and the double quotes for Borland make (v3.6). # This 'feature' is undocumented and fragile. Use at your own risk! paths.h: makefile.bcc echo "/* Changes should be made in Makefile, not to this file! */" > paths.h echo "#"define TMPDIR '"$(TMPDIR)"' >> paths.h echo "#"define RECDIR '"$(RECDIR)"' >> paths.h echo "#"define LIBDIR '"$(LIBDIR)"' >> paths.h echo "#"define SHAREDIR '"$(SHAREDIR)"' >> paths.h echo "#"define DFLTSHELL '"$(DFLTSHELL)"' >> paths.h setmaps.exe: commands.tab keys.txt setmaps.c $(CC) $(CFLAGS) setmaps.c keys.c: setmaps.exe keys.txt setmaps < keys.txt > keys.c clean: -del *.obj -del *.exe -del *.bak -del *.map -del keys.c jove-4.17.5.5/old/Makefile.zor000066400000000000000000000105571501102521500157450ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## # Makefile for Zortech C 3.0 # # - supported targets: # + jjove.exe (build JOVE, but don't install it) # + jovedosx.zip (build executable JOVE kit) # + clean # # - to install, do the following: # + copy jjove.exe where you wish # + copy doc/cmds.doc to /cmds.doc # + optional: copy some jove rc (none supplied) file to /jove.rc # =================================================================== # Jove configuration: default JOVE paths. # Note that all these can be set from environment variables as well; # see README.DOS for details. # # TMPDIR is where the tmp files get stored, usually /tmp or /usr/tmp. # RECDIR is the directory in which RECOVER looks for JOVE's tempfiles. # LIBDIR is for the PORTSRV and RECOVER programs. # SHAREDIR is for online documentation, and the system-wide jove.rc file. ## BINDIR is where to put the executables JOVE and TEACHJOVE. # DFLTSHELL is the default shell invoked by JOVE and TEACHJOVE. TMPDIR = c:/tmp RECDIR = c:/tmp LIBDIR = c:/jove SHAREDIR = $(LIBDIR) # BINDIR = c:/jove DFLTSHELL = command # Compiler: CC = ztc # Zortech Compiler Flags: # -e show effects of the preprocessor in error messages and list file (-l) # -m memory model (M for medium, L for large), also i for integer-only # # Same as UNIX: # -c compile, don't link # -D define macro # -g debugger info # -o optimize (not O!!) # -ofilename object output # # NOTE: quotes around the macro body in a -D are actually taken as part # of that body!! # CFLAGS = -g -e -mLi -DZTCDOS # CFLAGS = -g -e -mMi -DZTCDOS CFLAGS = -o -e -mMi -DZTCDOS # Linker: LD = $(CC) LDFLAGS = $(CFLAGS) # =================================================================== # Zortech's make has no default rules! # Rules must only refer to defined macros. .c.obj: $(CC) $(CFLAGS) -c $< .obj.exe: $(LD) $(LDFLAGS) $< OBJECTS = keys.obj commands.obj abbrev.obj ask.obj buf.obj c.obj \ case.obj jctype.obj delete.obj extend.obj argcount.obj insert.obj \ io.obj jove.obj macros.obj marks.obj misc.obj mouse.obj move.obj \ para.obj proc.obj re.obj reapp.obj scandir.obj list.obj \ keymaps.obj util.obj vars.obj wind.obj fmt.obj disp.obj term.obj \ fp.obj screen.obj msgetch.obj ibmpcdos.obj HEADERS = abbrev.h argcount.h ask.h buf.h c.h case.h chars.h commands.h \ jctype.h dataobj.h delete.h disp.h extend.h externs.h \ fmt.h fp.h insert.h io.h iproc.h jove.h \ keymaps.h list.h loadavg.h mac.h macros.h marks.h \ misc.h mouse.h move.h para.h proc.h \ re.h reapp.h rec.h scandir.h screen.h \ sysdep.h sysprocs.h temp.h term.h ttystate.h \ tune.h util.h vars.h version.h wind.h # This is what we really want to use, but Zortech's make doesn't work # when a target appears in more than one rule. So, as it stands, # changing a header will *not* force recompilation :-( # # $(OBJECTS): $(HEADERS) # # For this reason, we can only force the building of paths.h # by adding it to the dependencies for explicit targets. # In the hope that it is built soon enough, we put it at the front. jjove.exe: paths.h $(OBJECTS) $(LD) $(LDFLAGS) -o$* $(OBJECTS) jovedosx.zip: paths.h jjove.exe -del jovedosx.zip -del jove.exe rename jjove.exe jove.exe pkzip -aP jovedosx.zip jove.exe doc\*.* paths.h README.dos # Note that quotes are not stripped by the shell that will # execute the recipe for paths.h paths.h: Makefile.zor echo /* Changes should be made in Makefile, not to this file! */ > paths.h echo \#define TMPDIR "$(TMPDIR)" >> paths.h echo \#define RECDIR "$(RECDIR)" >> paths.h echo \#define LIBDIR "$(LIBDIR)" >> paths.h echo \#define SHAREDIR "$(SHAREDIR)" >> paths.h echo \#define DFLTSHELL "$(DFLTSHELL)" >> paths.h setmaps.exe: commands.tab keys.txt setmaps.c $(CC) $(CFLAGS) setmaps.c -osetmaps.exe # Zortech's make can't handle redirection in commands. # A prefix of + forces the use of the more powerful (!) command.com. keys.c: setmaps.exe keys.txt + setmaps < keys.txt > keys.c clean: -del *.obj -del *.exe -del *.bak -del *.map -del keys.c jove-4.17.5.5/old/README.cyg000066400000000000000000000062421501102521500151310ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## [Last updated: 2020 January] Jove for Cygwin ================= On modern Cygwin (at least 1.7 onwards, tested recently on 3.1.2), either for Cygwin32 or Cygwin64, make SYSDEFS=-DCYGWIN_JTC TERMCAPLIB= XEXT=.exe should work (Jove's new builtin JTC termcap replacement should work fine on the cygwin console and any terminal emulators shipped with cygwin) It should also work fine with the Cygwin ncurses package if support for ancient non-ANSI/non-VT1xx terminals is desired for some reason. make SYSDEFS=-DCYGWIN TERMCAPLIB=-lncurses XEXT=.exe Older/obsolete notes from the original port to Cygwin32, for historical record. ==============================================================================-= Jove has been ported to the Cygwin32 environment using the GNU-Win32 tools. Cygwin32 is a POSIX API for Win32, developed by Cygnus Solutions, Inc. The GNU-Win32 tools are Win32 ports of the GNU development tools for Windows NT and 95, built using the Cygwin32 API. For more information on the Cygwin32 project and the GNU-Win32 toolset, consult http://www.cygnus.com/misc/gnu-win32 Jove was originally ported to the environment by Arlindo da Silva. A more complete port was done, based on Arlindo's work, by Dave Curry. The regular UNIX Makefile is used, with remarkably few changes to definitions: - XEXT=.exe - XINSTALL=install $(INSTALLFLAGS) -c -m 755 - TINSTALL=install $(INSTALLFLAGS) -c -m 644 - SYSDEFS=-DCYGWIN32 - TERMCAPLIB = -L/usr/local/lib -lcurses Search for Cygwin32 in the Makefile. The environment used for the port was GNU-Win32 Beta 19.1 and the EGCS 2.90.27 compiler set, and Windows 95. You'll need either GNU Termcap 1.3 or ncurses to build from source. Note that you may want to set the CYGWIN32 environment variable to "tty" so that the CTRL-C key doesn't get treated as an interrupt. Arlindo da Silva dasliva@alum.mit.edu Dave Curry davy@ers.ibm.com [Addendum from Mark Moraes, 2013 April] I recently built jove on a Cygwin environment (1.7.18) with the default cc (gcc 3.4.4), and noted that our instructions in README.* and Makefile are slightly obsolete. With the changes/notes below, jove 4.16.0.73 seemed to compile and run fine with make SYSDEFS=-DCYGWIN32 TERMCAPLIB=-lcurses XEXT=.exe 1. Rather than building 'GNU Termcap 1.3 or ncurses' from source, all one needs to do is include the ncurses-devel package when installing Cygwin. 2. Setting CYGWIN=tty is no longer needed, it seems, since the cygwin default shell runs under mintty which emulates a terminal. (Once upon a time, I used to have to set TERM=ansi to avoid some sort of redisplay misbehaviour, it currently says TERM=xterm and I wonder if that misbehaviour still exists, I'll have to search my archive to see what it was). Or just use xterm or rxvt... jove-4.17.5.5/old/README.mac000066400000000000000000000471101501102521500151060ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## Changes for 4.16: Mac support had been left to run down for quite some time. In December 1995, Hugh re-ported it to Think C 5.0 (a compiler circa 1991). Hugh is neither a Mac hack, nor a Mac user, so this port should be considered amateur. More excuses and apologies appear in the mac.c source file. Changes in usage: - Since "recover" is not yet supported, the .jrecXXX file is no longer created. - For file name completion, the set of mounted volumes now acts much like a UNIX root. Note that no files may appear here. - The Option key is used as a meta key if the meta-key variable is on. This doesn't work well for the Option combinations that are accents ("dead keys") since JOVE doesn't get those keystrokes. Pressing a combination twice does work. - C-@ now generates NUL too. C-\ no longer does so (it generates C-\). - The arrow keys are now bound appropriately in the default main keymap. The codes ^\, ^], ^^, and ^_ are generated by the left, right, up, and down keys. Beware that previous default bindings for these keys no longer apply. - mode-line-should-standout now works on the Mac. Changes in building: - "setmaps" now automatically processes the appropriate files when you run it: you no longer have to type in a "command line". - The libraries have changed. + setmaps uses only "ANSI" + JOVE uses only "ANSI" and MacTraps. Perhaps these could be optimized by customizing them. - The msetmaps project needs only the setmaps.c source file. - The mjove project needs all .c files in the main directory except for setmaps.c, teachjove.c, and recover.c (other inapplicable files are protected by #ifdef). Segmenting is necessary. Since I didn't do a careful job, I won't specify how to do it. Far data was not needed (but only just). - I think that little is specific to Think C. I used 2-byte ints, but 4-byte ints should work too. I used strict prototype checking. None of the Think Class Library was used. We welcome any contributions from Mac users. Changes between 4.9 and 4.10: New features: 1) Reshapeable windows with zoom boxes. 2) Filename/directory name completion with macify OFF. 3) Double click mouse to set the mark. 4) Control-space and control-@ correctly send NUL on MacII/SE. 5) Control-` fixed to send backquote char. 6) Display update code fixed. Sources: 1) Compiles under LSC 3.0. (Probably under 2.13 as well, but not tested with that version). 2) Include files redone, with fewer total lines of code. 3) No need to modify include files, unless NBUF changed. 4) "keymaps.txt" is now "keys.txt". Planned: 1) Recover command as separate application. 2) Support for MPW compiler vers 2.02. Introduction This file contains a brief description of MacJove, along with information necessary to make MacJove from the source files. It is assumed that the reader is familiar with Jove from other systems, and is somewhat familiar with the Macintosh as well. In the future there may be a separate user's manual for MacJove: for the time being, the reader should refer to the Jove manual for Unix users. Description MacJove is a direct port of Jove to the Macintosh, with the overall structure, commands and key bindings left intact. In addition, elements of the Macintosh user interface - menus, window controls, and the mouse, have been integrated in a manner consistent with the overall functioning of Jove. While the integration of these tools into the Jove environment is consistent and, to most users, familiar, Jove departs in several places from "Macintosh User Interface Guidelines". Most notably, the mouse is used to position the point only, not to drag or select text, and the Jove buffer structure is not integrated with the clipboard. Also, key bindings conform to Jove/Emacs tradition, and not to Macintosh guidelines: i.e. control (command)-N is next-line, not "NewFile". The reason for these departures is that the majority of MacJove users are likely to be those already familiar with Jove or other Emacs editors on other systems, and for these users, consistency between machines and operating systems is more important than fully exploiting the features of a single system. There are numerous other text editors which fully follow the Macintosh User Interface Guidelines. MacJove retains most features of other Joves, but certain commands cannot be implemented because of the Macintosh operating system. Thus, there is no way to run a sub-process or a shell in a window, because there are no shells to run on the Macintosh, and a program (currently) can only transfer control to another program, not run a child process. For similar reasons, commands dealing with mail, with running make, and checking errors, are omitted. Running MacJove System Requirements MacJove should run without difficulty on any Macintosh Plus, SE, or Macintosh II, providing that the hierarchical file system (HFS) is used, and assuming a reasonably current system file is used. An upgraded 512K Mac (with 128K rom) should also work if there is enough memory. MacJove was developed on a Macintosh Plus and Macintosh II running system 4.2 and Finder 6.0., and has not been fully tested on earlier systems - however, it is likely that it will run on system 3.2 and later versions. MacJove has been used to a limited extent with Switcher and under Multifinder. In both cases, it is important to reserve enough memory for MacJove, as discussed below. MacJove, as compiled from the sources, uses memory as follows: Program Code approx 116K Static Data approx 20K Tempfile Cache 64K (heap) ____ 200K total before stack/heap considerations To this must be added stack and heap space. A bare minimum for this is probably 100K or so, but the usage will vary as buffers are created. With Jove, the file itself takes up space only in the tempfile and its cache, but the buffer structure requires 3 pointers (12 bytes) for each line in the file. For a reasonable editing session with files totalling, say 10000 to 20000 lines, this additional space can add up. For this reason, it is unrealistic to expect to run Jove on a 512K system, unless a very small system file is used, few, small files are edited each session, and the tempfile cache is reduced (see cache size under Making Jove). You can experiment with various memory allocations under Switcher and Multifinder to see what works with your editing habits (backup your files first!), but a realistic minimum is 400K - 500K and more is great. When first using MacJove, and if memory space is questionable, SAVE YOUR FILES FREQUENTLY. If it is necessary to edit many files, it is often better to exit MacJove and restart once in a while, especially if there is a question of limited memory. Operation Running MacJove is similar to other Macintosh applications, and should be intuitive. You start up MacJove by either opening, or double-clicking, the MacJove icon. If you have previously saved files created with MacJove, double-clicking on them will also start up the program, and the files will be put into buffers. Several files can be selected simultaneously by this method. There is no current way to select command-line options with MacJove, but this may change in the future. The .joverc file, if used, must be present in the same directory as MacJove, the "home" directory. The help file, "cmds.doc", must also be in this directory. The tempfile, ".joveXXX", will be placed in whatever directory is current when the tempfile is first opened - this may or may not be the home directory, and may change in the future. The recover file, ".jrecXXX" is placed in the home directory. While this file is created and updated as on Unix versions of Jove, there is currently no "recover" program for MacJove. Hopefully, this will be available soon. MacJove can edit any text file on the Macintosh, whether created with MacJove or another editor. It cannot be used to edit graphics material, and graphics material cannot be inserted during operation of MacJove. Files created with MacJove are of type 'TEXT' and of signature 'JV01'. This signature is being registered with Apple, and may change if necessary. Note that once MacJove files have been re-edited with another editor, they likely will have new signatures, and double-clicking on them will start the other editor, not MacJove. The standard Macintosh keyboard is inadequate for MacJove (and most anything else), so that it is necessary to change a couple of keys. The "`" key becomes the ESCAPE key, since it is in the right place for one: to send a real "'", hold the command key down while typing it. The command key is used for a control key - unfortunately, the location of it is horrible for such a purpose. On Macintosh SE and Macintosh II models, a real escape key exists, and also a real control key. Note, however, that because of a small bug in the keyboard encoding in MacJove, you cannot directly send a NUL (control-@) with the control key. Typing command-@ or command-2 will still do this, however. During operation, you can use the keyboard as you would when running Jove on any other system. However, many commands also have menu equivalents: as long as MacJove is waiting for a command, you can use either the keyboard or the menus. Once you begin selecting a command with either the menus or the keyboard, the other is locked out: thus, once you type control-X, MacJove expects more characters, and will not let you choose menu items. Also, if you are prompted for input on the command line, the menus are locked out. Regardless of how a command is begun, however, only the prompt line (message line) is used for input: MacJove does not use dialog boxes, except under the "About Jove" menu selection. Commands listed in the menus are given exactly as their string name in the command list, for example "write-file". In addition, variables are listed under the "Set" menu. Variables are grouped by type. Non-boolean variables are changed on the message line after being selected. Boolean variables are marked with a check mark if on, and selecting them toggles the value of the variable. The "Buffer" menu is a special menu, whose action is different from the others. The first entries on this menu are the major and minor modes of operation, with those of the current buffer marked with check marks. Clicking on a major mode will change the major mode of the current buffer to that mode, while clicking on a minor mode will toggle that mode's status (on/off) for the current buffer. Beneath this is a list of buffers, one for each menu item, with the current buffer marked. Clicking on a buffer selects that as the current buffer, and the active window will change accordingly. Window controls (scroll bars) work as expected, and are simply bound to the appropriate MacJove command. Occasionally the position of the scroll bar may appear inaccurate, particularly with a small buffer. Files and directories may be selected in two ways. The default method is to use the message line to input filenames, and to change directories using "cd". If the variable "macify" is set, however, filenames and directories can also be set using the standard file dialogs familiar to most Mac users. Filename paths are normally given via Unix conventions, and not Macintosh conventions: i.e. directories are separated with "/" and not ":". On the Buffer menu, however, filenames are listed with ":" as the separation character, since "/" cannot be displayed in menu items. It is not possible to back up directories beyond the volume level, so there is not true "root". To change volumes (disks), macify must be on, and the "Drive" selection used. "Macify" only works for those commands which REQUIRE a file operation, such as "visit-file", "insert-file", "write-file". Operations which first look in buffers for files, such as "window-find" and "find-file" never use the standard file dialogs. For a list of all commands and bindings, click on "About Jove" in the Apple menu. In the future this may also support the help file. Making MacJove System Requirements To make MacJove from the sources, you need a hard disk based Macintosh, at least 1 mb of ram, and the LightspeedC compiler, version 2.13 or later. Earlier versions may work but have not been used recently. Allow for the MacJove files to take up to 1.5 mb of your hard disk. You will need a copy of the "BinHex" utility, also. Since LightspeedC does not work with a Makefile, none is supplied. In general, the compiler itself will figure out dependencies for you, within a "project". Since there are three separate projects to MacJove, you will still have to keep track of some changes, particularly for the setmaps project. Also, since LightspeedC only knows of .c and .h dependencies, you will have to keep track of setmaps.txt and menumaps.txt yourself. Preliminary Steps 0) CREATE A FOLDER (DIRECTORY) FOR JOVE. If I have to tell you how to do that, don't go any further! Copy the source files - a few aren't needed by MacJove, but copy them anyway, so you'll have them in one place. You do not need anything in the "doc" subdirectory to create MacJove (but you will eventually need cmds.doc, the help file, if you want the "describe-command" command to work). 1) CREATE THE RESOURCE FILE: There is only one eight-bit file supplied, "mjove.rsrc". This is a small file which contains the program icon and a dialog template. This file must have the same name as the MacJove project, plus extension ".rsrc". The MacJove project (below), has name "mjove", so this file is "mjove.rsrc". IF YOU RENAME THE PROJECT YOU MUST RENAME THIS FILE, ALSO. Using "BinHex", unload the file "mjovers.Hqx" --> "mjove.rsrc". 2) CREATE THE "MJOVELIB" PROJECT: MacJove does not use many of the library functions. Despite what the LightspeedC manual states, projects are loaded as a whole: since we need only a few functions, we will build a "library" of them in the form of a project. Run LightspeedC and create a new project, and name it "mjovelib". Add the following files, from the Library Sources, to the project. They all go in the same segment: onexit.c qsort.c stddata_ctype.c unixexit.c unixid.c unixmem.c unixtime.c 3) EXAMINE THE FILE UNIXTIME.C and make the following correction, if necessary. The LightspeedC library function "unixtime.c" returns a string containing the time for what is supposed to be Greenwich Mean Time, instead of local time. Using the LightspeedC editor, and with the project open, examine the file, comment out the definition of "GMTzonedif", and add: #define GMTzonedif 0 4) MAKE THE "MJOVELIB" PROJECT. Keeping the edited "unixtime.c" open, run "make" on the project - everything will be compiled, with the altered version of "unixtime.c". You do not have to permanently save the change to unixtime.c, but if you do not, the next time you run "make" on the project, it will tell you that it needs recompiling - simply ignore it. After the mjovelib project is made, close it. You do not have to convert it to a library - it is okay to leave it as a project. 6) CREATE THE "MSETMAPS" PROJECT. Create a new project, name it "msetmaps", and add the following files to it: setmaps.c stdio strings (segment 1) unix unix main.c -------- MacTraps (segment 2) You should not change anything else at this point - unless you want to reduce memory requirements (see "Running MacJove", above). If it is necessary to reduce the memory requirements, then reduce the number of cache buffers, NBUF, which is defined near the end of the file (each buffer takes up 1K of space while MacJove is running). #ifdef MAC # undef F_COMPLETION # define F_COMPLETION 1 # define rindex strrchr # define bzero(s,n) setmem(s,n,0) # define swritef sprintf # define LINT_ARGS 1 # define NBUF 64 <---- here # define BUFSIZ 1024 # undef LISP # define LISP 1 # define ANSICODES 0 # undef ABBREV # define ABBREV 1 # undef CMT_FMT # define CMT_FMT 1 #endif 7) MAKE THE "MSETMAPS" PROJECT. Then choose "Build Application",and name it "setmaps". 8) RUN "SETMAPS" ON THE KEYMAPS.TXT FILE. You can either run "setmaps" from LightspeedC, before closing the project, or as the standalone application. When prompted for the "Unix command line", enter: < keys.txt > keys.c You will get a few messages from setmaps that it can't find certain commands. You can ignore these. 9) RUN "SETMAPS" ON THE MENUMAPS.TXT FILE. Just as before, run "setmaps" and enter the following command line: < menumaps.txt > menumaps.c You should not get any messages from setmaps. If the "msetmaps" project is still open, close it. 10) CREATE THE "MJOVE" PROJECT. Create a new project, name it "MJOVE" and set the Creator (signature) to 'JV01'. Add the following files in the following segments: abbrev.c argcount.c ask.c buf.c c.c case.c (segment 1) jctype.c delete.c disp.c extend.c keys.c -------- fmt.c fp.c funcdefs.c (segment 2) insert.c io.c jove.c keymaps.c list.c -------- mac.c macros.c marks.c menumaps.c (segment 3) misc.c move.c paragraph.c -------- re.c re1.c rec.c screen.c term.c (segment 4) util.c vars.c wind.c -------- MacTraps mjovelib setjmp.Lib (segment 5) storage strings 11) MAKE THE MJOVE PROJECT. If you experience any errors, it will most likely be from #include files not being in the default path - see the LightspeedC manual on setting up your directories. When you are done, run the program from the compiler to verify that it is okay, then save it as "MacJove" using the "Build Application" command. 12) (Optional) CREATE THE HELP FILE, "CMDS.DOC". If you do not have a copy of "cmds.doc", it must be created using nroff. Assuming you have the Jove sources on a Unix machine, run "Make doc/cmds.doc" to create this file in the "doc" subdirectory, then move the file to the Mac. If you obtained the sources from a non-Unix source, this file may already be supplied. Place the file in the same directory that MacJove will be in. COMMENTS AND QUESTIONS, BUGS Although Jove appears to work well on the Mac, I know there are some problems. Since Jove cannot effectively use the TextEdit routines, it does not comply with some aspects of the Macintosh User Interface Guidelines. As has recently been brought to my attention, Jove accesses files by pathname only, so that if you have two disks in your machine with the same volume (disk) name, it will become confused. This has not been fixed. Support for variant keyboards is not good at present. I try to reply to all inquiries about MacJove, but my schedule is busy, and it may be several days before you hear from me on the net. Please reply via email to me, or through usenet if possible: the chances that I will respond quickly to a written question or suggestion are very small, and I am difficult to reach by phone. Please do NOT send disks unless I ask you to. Ken Mitchum Decision Systems Laboratory University of Pittsburgh 1360 Scaife Hall Pittsburgh, Pa. 15261 (km@cadre.dsl.pittsburgh.edu) [Ken's email address (1995): Ken Mitchum ] jove-4.17.5.5/old/sysdep.h000066400000000000000000000275701501102521500151570ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* * All the systems in this file have not been tested in the * current version of Jove. The ones with XXX_ were not even * tested in the last version (Jove 4.16, circa 1996 CE). * The XXX* symbos are preserved have been left in to * provide a guide to re-porting this version to those * architectures. If you do so successfully, please send a * copy of these changes to github.com/jonmacs/jove and we'll * try to incorporate those changes above and get rid of the * XXX_, and move the tested definition back to sysdep.h. #ifdef SUNOS41 /* System: SunOS4.1 to 4.1.3 */ # define TERMIOS 1 # define NO_IOCTL_H_TTY 1 /* conflicts with ? */ # define USE_GETCWD 1 # define POSIX_UNISTD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define POSIX_PROCS 1 # define BSD_SIGS 1 # define JOB_CONTROL 1 # define BSD_SETPGRP 1 # define USE_KILLPG 1 # define USE_GETPWNAM 1 # define USE_GETHOSTNAME 1 # define NO_STRERROR 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 # define USE_CTYPE 1 #endif #ifdef SUNOS40 /* System: SunOS4.0 to 4.0.3c */ /* Almost identical to SUNOS41, main difference is that SUNOS41 uses * POSIX_PROCS, this one uses BSD_WAIT/WAIT3, USE_MEMORY_H. * Beware: TERMIO under SunOS 4.0 does not allow VSUSP to be changed, * so we cannot use it. */ /* try to patch over problems */ # define TERMIOS 1 # define setsid() /* SunOS 4.0 apparently has no concept of session */ # define cfgetospeed(p) (CBAUD & (p)->c_cflag) # define tcgetattr(fd, p) ioctl((fd), TCGETS, (UnivPtr)(p)) # define tcsetattr(fd, oa, p) ioctl((fd), (oa), (UnivPtr)(p)) /* fake values for "optional_actions" (oa) arg to tcsetattr */ # define TCSANOW TCSETS # define TCSADRAIN TCSETSW # define TCSAFLUSH TCSETSF /* end of patches */ # define NO_IOCTL_H_TTY 1 /* conflicts with ? */ # define USE_GETCWD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define BSD_WAIT 1 # define WAIT3 1 # define BSD_SIGS 1 # define JOB_CONTROL 1 # define USE_VFORK 1 # define BSD_SETPGRP 1 # define USE_KILLPG 1 # define USE_GETPWNAM 1 # define USE_GETHOSTNAME 1 # define NO_STRERROR 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 # define USE_MEMORY_H 1 #endif #ifdef SUNOS3 /* System: SunOS before 4.0, eg. 3.5. not recently tested */ /* This is very close to BSD4 */ # define SGTTY 1 # define USE_GETWD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define BSD_WAIT 1 # define WAIT3 1 # define BSD_SIGS 1 # define JOB_CONTROL 1 # define USE_VFORK 1 # define BSD_SETPGRP 1 # define USE_KILLPG 1 # define BSD_DIR 1 # define USE_GETPWNAM 1 # define SIGRESTYPE int # define SIGRESVALUE 0 # define USE_GETHOSTNAME 1 # define NO_STRERROR 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 /* # define USE_BCOPY 1 */ /* # define USE_INDEX 1 */ #endif #ifdef AIX3_2 /* System: IBM RS6000 running AIX 3.2 */ # define AIX 1 # define FULL_UNISTD 1 # define USE_GETWD 1 # define TERMIOS 1 /* uses termio struct for terminal modes */ # define USE_UNAME 1 # define USE_SELECT 1 # define USE_SELECT_H 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define NO_EOF_FROM_PTY 1 /* BUG! */ # define POSIX_PROCS 1 # define WAIT3 1 # define POSIX_SIGS 1 # define JOB_CONTROL 1 # define USE_GETPWNAM 1 # define USE_UNAME 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 # define USE_CTYPE 1 #endif #ifdef AIX4_2 /* System: IBM AIX 4.2 */ # define AIX 1 # define FULL_UNISTD 1 # define USE_GETWD 1 # define TERMIOS 1 /* uses termio struct for terminal modes */ # define USE_UNAME 1 # define USE_SELECT 1 # define USE_SELECT_H 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define NO_EOF_FROM_PTY 1 /* BUG! */ # define POSIX_PROCS 1 # define WAIT3 1 # define POSIX_SIGS 1 # define JOB_CONTROL 1 # define USE_GETPWNAM 1 # define USE_UNAME 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 # define USE_CTYPE 1 /* Only difference from AIX3_2, perhaps due to switching from * -ltermcap to -lcurses (-ltermcap seems to have disappeared): */ # define DEFINE_PC_BC_UP_OSPEED 1 /* May be needed for all SYSVR2 */ #endif #ifdef _convex__ /* System: ConvexOS (versions 10.x - 11.x) */ /* Note: this must be placed before BSDPOSIX ifdef (we define BSDPOSIX). */ # define BSDPOSIX 1 /* mostly like BSDPOSIX */ # define STICKY_TTYSTATE 1 /* fudge: many progs stupidly set ISTRIP */ # define ISO_8859_1 1 /* fudge: doesn't work for 8-bit chars, but X does */ #endif #ifdef _QNX__ /* System: QNX OS for x86 family */ /* Note: this must be placed before BSDPOSIX ifdef (we define BSDPOSIX). */ # define BSDPOSIX 1 # define ONLCR OPOST /* how to do ONLCR */ # define USE_SELECT_H 1 #endif #ifdef IRIX # define _BSD_COMPAT 1 /* Turn on BSD setpgrp and other neat things */ # define TERMIOS 1 # define USE_GETCWD 1 # define FULL_UNISTD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define POSIX_PROCS 1 # define POSIX_SIGS 1 # define JOB_CONTROL 1 # ifdef IRIX4 /* Should work for IRIX 4.0.4 back to 3.2 or 3.3. This is a Posix system * with its own way of doing PTYS. Older versions may need MIPS_CC_BUG * defined as well. */ # define IRIX_PTYS 1 # define NO_TIOCREMOTE 1 # define SIGRESTYPE int # define SIGRESVALUE 0 # else /* IRIX 5 and later */ # define SVR4_PTYS 1 # define NO_TIOCREMOTE 1 # define NO_TIOCSIGNAL 1 # define SIGRESTYPE void # define SIGRESVALUE /*void!*/ # endif # define BSD_SETPGRP 1 # define USE_GETPWNAM 1 # define USE_KILLPG 1 # define USE_GETHOSTNAME 1 # define HAS_SYMLINKS 1 # define USE_CTYPE 1 #endif #ifdef HPUX /* System: Hewlett-Packard HP-UX 9.01 & 11, probably others */ # define TERMIOS 1 # define USE_BSDTTYINCLUDE 1 /* No other way to turn off ^Y */ # define USE_GETCWD 1 # define FULL_UNISTD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define POSIX_PROCS 1 # define NO_EOF_FROM_PTY 1 /* BUG! */ # define POSIX_SIGS 1 # define JOB_CONTROL 1 # define USE_UNAME 1 # define DEFINE_PC_BC_UP_OSPEED 1 /* May be needed for all SYSVR2 */ # define HAS_SYMLINKS 1 #endif #ifdef SCO_ODT3 /* System: SCO ODT 3.0 */ # define TERMIOS 1 /* # define FULL_UNISTD 1 */ /* Not tested! May be worth trying. */ # define USE_GETCWD 1 # define POSIX_UNISTD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define POSIX_PROCS 1 # define JOB_CONTROL 1 # define USE_UNAME 1 /* In SCO ODT 3.0, a wait() will never finish if SIGCHLD is being held. * We think that this is a bug. It's rumoured to be "fixed" in the next * release. JOVE's IPROCS code no longer triggers this bug. */ # define PTYPROCS 1 # define HAS_SYMLINKS 1 # define USE_CTYPE 1 #endif #ifdef ZTCDOS /* System: Zortech C V3.0 for the IBM-PC under MSDOS */ # define IBMPCDOS 1 # define getch jgetch /* UGH! Zortech steals from our namespace. */ # define MALLOC_CACHE 1 /* DGROUP gets full otherwise */ # define REALSTDC 1 /* close enough for us, but ZTCDOS doesn't define __STDC__ */ # ifdef M_I86LM /* large memory model */ # define NBUF 62 /* NBUF*JBUFSIZ must be less than 64 kB */ # else # define NBUF 3 # define FAR_LINES 1 /* to squeeze larger files, distance Lines */ # endif /* (1) specify stack size, and * (2) request support of wildcards in command-line args (UGH!) */ # define STACK_DECL unsigned int _stack = 0x2000; WILDCARDS # define dostime_t dos_time_t /* is Zortech out of step? */ # define _dos_gettime dos_gettime # define NO_MKSTEMP 1 # define NO_MKTEMP 1 #endif #if defined(_OWCDOS__) && defined(MSDOS) /* System: Watcom C V10.0 for the IBM-PC under MSDOS */ # define IBMPCDOS 1 # define MALLOC_CACHE 1 /* DGROUP gets full otherwise */ # define REALSTDC 1 /* close enough for us, but ZTCDOS doesn't define __STDC__ */ # ifdef M_I86LM /* large memory model */ # define NBUF 62 /* NBUF*JBUFSIZ must be less than 64 kB */ # else # define NBUF 3 # define FAR_LINES 1 /* to squeeze larger files, distance Lines */ # endif # define NO_MKSTEMP 1 # define NO_MKTEMP 1 #endif #ifdef _BORLANDC__ /* System: Borland C/C++ (v3.1) for the IBM-PC under MSDOS */ # define IBMPCDOS 1 # define MALLOC_CACHE 1 /* DGROUP gets full otherwise */ # define REALSTDC 1 /* close enough for us, but not strict ANSI */ # ifdef __LARGE__ # define NBUF 62 /* NBUF*JBUFSIZ must be less than 64 kB */ # define FAR_LINES 1 /* to squeeze larger files, distance Lines */ # else # ifdef __MEDIUM__ # define NBUF 3 # define FAR_LINES 1 /* to squeeze larger files, distance Lines */ # endif # endif # define STACK_DECL unsigned int _stklen = 0x2000; /* Borland's way of specifying stack size */ /* probably: # define NO_MKSTEMP 1 */ /* probably: # define NO_MKTEMP 1 */ #endif /* All the systems marked with XXX_ are ones that even Jove 4.16 * has not been tested on. 4.15 was the transition from implicit #ifdefs * scattered throughout the code to feature-based ifdefs that MUST be * enabled in sysdep.h in order to enable the relevant code. */ #ifdef XXX_M_XENIX /* System: Microsoft or SCO Xenix */ /* #define NBUF 48 */ /* if we are on a 286, NBUF*JBUFSIZ must be less than 64 kB */ # define BSD_DIR 1 #endif #ifdef XXX_SYSV /* System: System V Rel. 2, System III */ # define TERMIO 1 # define USE_PWD # define NONBLOCKINGREAD 1 # define USE_MEMORY_H 1 # define DIRENT_EMULATE 1 /* for truly old versions? */ #endif #ifdef XXX_A_UX /* System: A/UX on a MacII (Do *not* define "MAC") */ /* It might be better to try BSDPOSIX for newer A/UX. */ # define BSD_WAIT 1 # define BSD_DIR 1 # define WAIT3 1 # define BSD_SIGS 1 /* ??? */ # define USE_KILLPG 1 # define TERMIO 1 /* uses termio struct for terminal modes */ # define USE_GETHOSTNAME 1 # define USE_SELECT 1 #endif #ifdef XXX_OLDMIPS /* System: MIPS-SYSV, Irix before 3.3. */ /* Older MIPS (UMIPS-SYSV, anything other than their 4.3 port before * RISCOS4.x) and SGI 4D OSes (anything before Irix3.3) have BSD style wait, * and directory routines if you link -lbsd and define -I/usr/include/bsd on * the compile line. But they have SysV style signals. Jove was ported to the * SGI 68K boxes once, but it the mods seem to have been lost. */ # define BSD_WAIT 1 /* Berkeley style sys/wait.h */ # define BSD_DIR 1 /* Berkeley style dirent routines */ #endif #ifdef XXX_MSC51 /* System: Microsoft C 5.1 on IBM PC under DOS*/ /* This hasn't been tested recently. Consider stealing ZTCDOS settings. */ # define IBMPCDOS 1 # define NO_PTRPROTO 1 # define REALSTDC 1 /* well, almost */ # ifdef M_I86LM /* large memory model */ # define NBUF 62 /* NBUF*JBUFSIZ must be less than 64 kB */ # else # define JSMALL 1 # endif /* probably: # define NO_MKSTEMP 1 */ /* probably: # define NO_MKTEMP 1 */ #endif #ifdef THINK_C /* System: Think C version 5.0 on the Macintosh */ # define MAC 1 # define REALSTDC 1 /* we hope */ # define MALLOC_CACHE 1 /* Only 32K of static space on Mac, so... */ typedef long off_t; # define USE_GETCWD 1 # define USE_INO 1 /* we fake it */ typedef int dev_t; typedef int ino_t; # define DIRECTORY_ADD_SLASH 1 # define NO_MKSTEMP 1 /* no mkstemp library routine */ # define NO_MKTEMP 1 /* no mktemp library routine */ # define NO_FCNTL 1 /* no header */ # define EOL '\r' /* end-of-line character for files */ # define WINRESIZE 1 # define AUTO_BUFS 1 /* slim down data segment */ #endif jove-4.17.5.5/para.c000066400000000000000000000370641501102521500140070ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "disp.h" #include "delete.h" #include "insert.h" #include "fmt.h" #include "marks.h" #include "misc.h" #include "move.h" #include "para.h" #include "re.h" private int get_indent proto((LinePtr)); /* Thanks to Brian Harvey for this paragraph boundary finding algorithm. * It's really quite hairy figuring it out. This deals with paragraphs that * are seperated by blank lines, lines beginning with a Period (assumed to * be an nroff command), lines beginning with BackSlash (assumed to be Tex * commands). Also handles paragraphs that are separated by lines of * different indent; and it deals with outdented paragraphs, too. It's * really quite nice. Here's Brian's algorithm. * * Definitions: * * THIS means the line containing the cursor. * PREV means the line above THIS. * NEXT means the line below THIS. * * BLANK means empty, empty except for spaces and tabs, starts with a period * or a backslash, or nonexistent (because the edge of the buffer is * reached). ((BH 12/24/85 A line starting with backslash is blank only if * the following line also starts with backslash. This is so that \noindent * is part of a paragraph, but long strings of TeX commands don't get * rearranged. It still isn't perfect but it's better.)) * * BSBLANK means BLANK or starts with a backslash. (BH 12/24/85) * * HEAD means the first (nonblank) line of the paragraph containing THIS. * BODY means all other (nonblank) lines of the paragraph. * TAIL means the last (nb) line of the paragraph. (TAIL is part of BODY.) * * HEAD INDENT means the indentation of HEAD. M-J should preserve this. * BODY INDENT means the indentation of BODY. Ditto. * * Subprocedures: * * TAILRULE(BODYLINE) * If BODYLINE is BLANK, the paragraph has only one line, and there is no * BODY and therefore no TAIL. Return. Otherwise, starting from BODYLINE, * move down until you find a line that either is BSBLANK or has a different * indentation from BODYLINE. The line above that different line is TAIL. * Return. * * Rules: * * 1. If THIS is BLANK, which command are you doing? If M-J or M-[, then go * up to the first non-BLANK line and start over. (If there is no non-BLANK * line before THIS, ring the bell.) If M-], then the first non-BLANK line * below THIS is HEAD, and the second consecutive non-BSBLANK line (if any) is * the beginning of BODY. (If there is no non-BLANK line after THIS, ring * the bell.) Do TAILRULE(beginning-of-BODY). Go to rule A. * * 2. If PREV is BLANK or THIS is BSBLANK, then THIS is HEAD, and NEXT (if * not BSBLANK) is in BODY. Do TAILRULE(NEXT). Go to rule A. * * 3. If NEXT is BSBLANK, then THIS is TAIL, therefore part of BODY. Go to * rule 5 to find HEAD. * * 4. If either NEXT or PREV has the same indentation as THIS, then THIS is * part of BODY. Do TAILRULE(THIS). Go to rule 5 to find HEAD. Otherwise, * go to rule 6. * * 5. Go up until you find a line that is either BSBLANK or has a different * indentation from THIS. If that line is BLANK, the line below it is HEAD; * If that line is non-BLANK, then call that new line THIS for what follows. * If THIS is BSBLANK (that is, THIS starts with backslash), THIS is HEAD; * otherwise, if (the new) PREV has the same indent as THIS, then (the new) * NEXT is HEAD; if PREV has a different indent from THIS, then THIS is * HEAD. Go to rule A. * * 6. If you got here, then both NEXT and PREV are nonblank and are * differently indented from THIS. This is a tricky case and there is no * guarantee that you're going to win. The most straightforward thing to do * is assume that we are not using hanging indentation. In that case: * whichever of PREV and THIS is indented further is HEAD. Do * TAILRULE(HEAD+1). Go to rule A. * * 6+. A more complicated variant would be this: if THIS is indented further * than PREV, we are using regular indentation and rule 6 applies. If PREV * is indented further than THIS, look at both NEXT and the line after NEXT. * If those two lines are indented equally, and more than THIS, then we are * using hanging indent, THIS is HEAD, and NEXT is the first line of BODY. * Do TAILRULE(NEXT). Otherwise, rule 6 applies. * * A. You now know where HEAD and TAIL are. The indentation of HEAD is HEAD * INDENT; the indentation of TAIL is BODY INDENT. * * B. If you are trying to M-J, you are now ready to do it. * * C. If you are trying to M-], leave point after the newline that ends * TAIL. In other words, leave the cursor at the beginning of the line * after TAIL. It is not possible for this to leave point where it started * unless it was already at the end of the buffer. * * D. If you are trying to M-[, if the line before HEAD is not BLANK, then * leave point just before HEAD. That is, leave the cursor at the beginning * of HEAD. If the line before HEAD is BLANK, then leave the cursor at the * beginning of that line. If the cursor didn't move, go up to the first * earlier non-BLANK line and start over. * * * End of Algorithm. I implemented rule 6+ because it seemed nicer. */ jbool SpaceSent2 = YES; /* VAR: space-sentence-2 */ int LMargin = 0, /* VAR: left margin */ RMargin = 78; /* VAR: right margin */ char ParaDelim[sizeof(ParaDelim)] = "[ \t]*$\\|\\.\\|\\\\"; /* VAR: paragraph-delimiter-pattern */ private LinePtr para_head, para_tail; private int head_indent, body_indent; private jbool use_lmargin; /* some defines for paragraph boundary checking */ #define I_DELIM (-1) /* line matched by paragraph-delimiter-pattern */ #define I_BUFEDGE (-2) /* line is nonexistent (edge of buffer) */ private jbool bslash; /* Nonzero if get_indent finds line starting with backslash */ private jbool i_blank(lp) LinePtr lp; { return get_indent(lp) < 0; } private jbool i_bsblank(lp) LinePtr lp; { return i_blank(lp) || bslash; } private int get_indent(lp) register LinePtr lp; { Bufpos save; register int indent; bslash = NO; if (lp == NULL) return I_BUFEDGE; DOTsave(&save); SetLine(lp); if (LookingAt(ParaDelim, linebuf, 0)) { indent = I_DELIM; if (linebuf[0] == '\\' && REeom == 1) { /* BH 12/24/85. Backslash is delimiter only if next line * also starts with Backslash. */ bslash = YES; SetLine(lp->l_next); if (linebuf[0] != '\\') indent = 0; } } else { ToIndent(); indent = calc_pos(linebuf, curchar); } SetDot(&save); return indent; } private LinePtr tailrule(lp) register LinePtr lp; { int i; i = get_indent(lp); if (i < 0) return lp; /* one line paragraph */ do { if ((get_indent(lp->l_next) != i) || bslash) /* BH line with backslash is head of next para */ break; } while ((lp = lp->l_next) != NULL); if (lp == NULL) { complain((char *) NULL); /* NOTREACHED */ } return lp; } /* Finds the beginning, end and indent of the current paragraph, and sets * the above global variables. HOW says how to behave when we're between * paragraphs. That is, it's either FORWARD or BACKWARD depending on which * way we're favoring. */ private void find_para(how) int how; { LinePtr this, prev, next, head = NULL, body = NULL, tail = NULL; int this_indent; Bufpos orig; /* remember where we were when we started */ DOTsave(&orig); strt: this = curline; prev = curline->l_prev; next = curline->l_next; this_indent = get_indent(this); if (i_blank(this)) { /* rule 1 */ if (how == BACKWARD) { while (i_blank(curline)) if (firstp(curline)) { complain((char *)NULL); /* NOTREACHED */ } else { line_move(BACKWARD, 1, NO); } goto strt; } else { while (i_blank(curline)) if (lastp(curline)) { complain((char *)NULL); /* NOTREACHED */ } else { line_move(FORWARD, 1, NO); } head = curline; next = curline->l_next; body = !i_bsblank(next)? next : head; } } else if (i_bsblank(this) || i_blank(prev)) { /* rule 2 */ head = this; if (!i_bsblank(next)) body = next; } else if (i_bsblank(next)) { /* rule 3 */ tail = this; body = this; } else if (get_indent(next) == this_indent /* rule 4 */ || get_indent(prev) == this_indent) { body = this; } else { /* rule 6+ */ if (get_indent(prev) > this_indent) { /* hanging indent maybe? */ if (next != NULL && get_indent(next) == get_indent(next->l_next)) { head = this; body = next; } } /* Now we handle hanging indent else and the other * case of this_indent > get_indent(prev). That is, * if we didn't resolve HEAD in the above if, then * we are not a hanging indent. */ if (head == NULL) { /* still don't know */ head = this_indent > get_indent(prev)? this : prev; body = head->l_next; } } /* rule 5 -- find the missing parts */ if (head == NULL) { /* haven't found head of paragraph so do so now */ LinePtr lp; int i; lp = this; do { i = get_indent(lp->l_prev); if (i < 0) /* is blank */ head = lp; else if (bslash) head = lp->l_prev; else if (i != this_indent) { this = lp->l_prev; if (get_indent(this->l_prev) == i) head = this->l_next; else head = this; } } while (head == NULL && (lp = lp->l_prev) != NULL); if (lp == NULL) { complain((char *)NULL); /* NOTREACHED */ } } if (body == NULL) /* this must be a one line paragraph */ body = head; if (tail == NULL) tail = tailrule(body); if (tail == NULL || head == NULL || body == NULL) { complain("BUG! tail(%d),head(%d),body(%d)!", tail, head, body); /* NOTREACHED */ } para_head = head; para_tail = tail; head_indent = get_indent(head); body_indent = get_indent(body); SetDot(&orig); } void FillParagraph() { LinePtr nl; int lenparatail; use_lmargin = is_an_arg(); find_para(BACKWARD); nl = new_kill(); lenparatail = length(para_tail); (void) DoYank(para_head, 0, para_tail, lenparatail, nl, 0, (Buffer *)NULL); DoJustify(para_head, 0, para_tail, lenparatail, NO, use_lmargin ? LMargin : body_indent); } private LinePtr max_line(l1, l2) LinePtr l1, l2; { return inorder(l1, 0, l2, 0)? l2 : l1; } private LinePtr min_line(l1, l2) LinePtr l1, l2; { return inorder(l1, 0, l2, 0)? l1 : l2; } void FillRegion() { CopyRegion(); /* enable yank-pop for undo */ do_rfill(is_an_arg()); this_cmd = UNDOABLECMD; /* allow yank-pop to undo */ } void do_rfill(ulm) jbool ulm; { Mark *mp = CurMark(), *endmark; LinePtr l1 = curline, l2 = mp->m_line; int c1 = curchar, c2 = mp->m_char; use_lmargin = ulm; (void) fixorder(&l1, &c1, &l2, &c2); endmark = MakeMark(l2, c2); for (;;) { Mark *tailmark; LinePtr rl1, rl2; int rc1, rc2; DotTo(l1, c1); find_para(FORWARD); rl1 = max_line(l1, para_head); rc1 = (rl1 == l1) ? c1 : 0; rl2 = min_line(endmark->m_line, para_tail); rc2 = (rl2 == endmark->m_line) ? endmark->m_char : length(rl2); tailmark = MakeMark(rl2, rc2); if (rl1 != rl2 || rc1 != rc2) DoJustify(rl1, rc1, rl2, rc2, NO, use_lmargin ? LMargin : body_indent); ToMark(tailmark); DelMark(tailmark); if (curline == endmark->m_line) break; l1 = curline->l_next; c1 = 0; if (l1 == NULL || (l1 == endmark->m_line && c1 >= endmark->m_char)) break; } DelMark(endmark); } private void do_space() { int c1, diff, nspace = 0; jbool funny_space = NO; skip_wht_space(); for (c1 = curchar; --c1 >= 0 && jiswhite(linebuf[c1]); ) if (linebuf[c1] != ' ') funny_space = YES; c1 += 1; diff = (curchar - c1); if (diff != 0) { if (c1 > 0 && !eolp()) { nspace = 1; if (diff >= 2) { int topunct = c1; do { topunct -= 1;; } while (topunct > 0 && strchr("\"')]", linebuf[topunct]) != NULL); if (SpaceSent2 && topunct > 0 && (linebuf[c1-1] == ':' || strchr("?!.", linebuf[topunct]) != NULL)) nspace = 2; } } if (funny_space || diff > nspace) { /* NOTE: insert spaces left of deletion before doing * deletion so that marks will remain on the same side. */ b_char(diff); ins_str(&" "[2-nspace]); del_char(FORWARD, diff, NO); } } } #ifdef MSDOS /*#pragma loop_opt(off) */ #endif void DoJustify(l1, c1, l2, c2, scrunch, indent) LinePtr l1, l2; int c1, c2, indent; jbool scrunch; { Mark *savedot = MakeMark(curline, curchar), *endmark; int okay_char, /* end of what fits */ start_char; /* where we started the line */ (void) fixorder(&l1, &c1, &l2, &c2); /* l1/c1 will be before l2/c2 */ DotTo(l1, c1); if (get_indent(l1) >= c1) { if (use_lmargin) { Bol(); n_indent(indent + (head_indent - body_indent)); use_lmargin = NO; /* turn this off now */ } ToIndent(); } endmark = MakeMark(l2, c2); okay_char = start_char = curchar; for (;;) { /* for each word ... */ int word_start = curchar; /* skip to end of (possibly empty) input word */ while (!eolp() && !jiswhite(linebuf[curchar])) curchar += 1; if (word_start != curchar && okay_char != start_char && calc_pos(linebuf, curchar) > RMargin) { /* This non-empty word won't fit in output line * (the first word on a line is always considered to fit). */ curchar = okay_char; /* go back to last success */ /* break line here. Note that we split the line before * deleting the (possibly split) whitespace. This way * marks before and after the current whitespace character * end up on the appropriate side of the newline that * replaces it. */ LineInsert(1); b_char(1); DelWtSpace(); f_char(1); DelWtSpace(); if (scrunch && TwoBlank()) { Eol(); del_char(FORWARD, 1, NO); Bol(); } n_indent(indent); okay_char = start_char = curchar; } else { /* this word fits (it might be empty, but that's OK) */ okay_char = curchar; /* nail down success */ /* stop if we've run out of range */ if (curline == endmark->m_line && curchar >= endmark->m_char) break; /* process word separator */ if (eolp() && !lastp(curline)) { /* Replace line separator with TWO spaces: this * allows sentence ends to end up with two spaces. * NOTE: insert spaces left of deletion before doing * deletion so that marks will remain on the same side. */ ins_str(" "); del_char(FORWARD, 1, NO); } do_space(); /* compress space; advance past it */ } } ToMark(savedot); /* Back to where we were */ DelMark(endmark); /* Free up marks */ DelMark(savedot); /* ??? why is the following necessary? -- DHR */ this_cmd = last_cmd = OTHER_CMD; /* So everything is under control */ f_mess(NullStr); } #ifdef MSDOS /*#pragma loop_opt() */ #endif private void DoPara(dir) int dir; { register int num = arg_value(); jbool first_time = YES; if (num < 0) { num = -num; dir = -dir; } while (--num >= 0) { tryagain: find_para(dir); /* find paragraph bounderies */ if (dir == BACKWARD && (!first_time || (para_head == curline && bolp()))) { if (bobp()) { complain((char *)NULL); /* NOTREACHED */ } b_char(1); first_time = !first_time; goto tryagain; } SetLine((dir == BACKWARD) ? para_head : para_tail); if (dir == BACKWARD && !firstp(curline) && i_blank(curline->l_prev)) { line_move(BACKWARD, 1, NO); } else if (dir == FORWARD) { if (lastp(curline)) { Eol(); break; } /* otherwise */ line_move(FORWARD, 1, NO); } } } void BackPara() { DoPara(BACKWARD); } void ForPara() { DoPara(FORWARD); } jove-4.17.5.5/para.h000066400000000000000000000016651501102521500140120ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern void DoJustify proto((LinePtr l1, int c1, LinePtr l2, int c2, jbool scrunch, int indent)), do_rfill proto((jbool ulm)); /* Commands: */ extern void BackPara proto((void)), ForPara proto((void)), FillParagraph proto((void)), FillRegion proto((void)); /* Variables: */ extern jbool SpaceSent2; /* VAR: space-sentence-2 */ extern int LMargin, /* VAR: left margin */ RMargin; /* VAR: right margin */ extern char ParaDelim[128]; /* VAR: paragraph-delimiter-pattern */ jove-4.17.5.5/pkg/000077500000000000000000000000001501102521500134675ustar00rootroot00000000000000jove-4.17.5.5/pkg/README000066400000000000000000000005061501102521500143500ustar00rootroot00000000000000Config files to generate reference packages. These may differ from the ones used by actual distros, which may be modified by the distro maintainers, these are mainly intended as a starting point and for test. Fixes and improvements are welcome, it is unlikely we are familiar with the best practices for each distro family. jove-4.17.5.5/pkg/deb/000077500000000000000000000000001501102521500142215ustar00rootroot00000000000000jove-4.17.5.5/pkg/deb/debian/000077500000000000000000000000001501102521500154435ustar00rootroot00000000000000jove-4.17.5.5/pkg/deb/debian/NEWS000066400000000000000000000012631501102521500161440ustar00rootroot00000000000000jove (4.17.2.0-1) unstable; urgency=low Beginning with Version 4.17.x we drop the automatic recover of crashed jove sessions. This means that your crashed sessions are kept in /var/tmp and will not moved on reboot to /var/lib/jove/recover. You can still recover crashed files with 'jove -r'. You should clean /var/lib/jove/recover from remains of old sessions. If you want to keep the old behaviour, you need to reinstall the init.d script. It is in /usr/share/doc/jove. Don't forget to 'update-rc.d jove start 20 2 3 4 5 .' You also need to set /var/lib/jove/recover to 1777. -- Cord Beermann Fri, 14 Feb 2020 19:40:48 +0100 jove-4.17.5.5/pkg/deb/debian/README.Debian000066400000000000000000000003331501102521500175030ustar00rootroot00000000000000jove for Debian -------------- xjove depends on xview, which fails to build on some new architectures, and which is unmaintained Upstream for years. -- Cord Beermann , Sun, 9 Jan 2006 21:52:36 +0100 jove-4.17.5.5/pkg/deb/debian/changelog000066400000000000000000000454241501102521500173260ustar00rootroot00000000000000jove (4.17.5.4-1) unstable; urgency=low * New upstream release. -- Cord Beermann Thu, 30 Nov 2023 00:52:19 -0500 jove (4.17.5.3-1) unstable; urgency=low * New upstream release. -- Cord Beermann Sun, 19 Mar 2023 17:08:52 -0400 jove (4.17.5.2-1) unstable; urgency=low * New upstream release. -- Cord Beermann Sun, 26 Feb 2023 17:48:09 -0500 jove (4.17.5.1-1) unstable; urgency=low * New upstream release. -- Cord Beermann Thu, 23 Feb 2023 16:14:57 -0500 jove (4.17.5.0-1) unstable; urgency=low * New upstream release. + upstream incorporates jem* -- Cord Beermann Sun, 08 Jan 2023 17:55:26 -0500 jove (4.17.4.9-1) unstable; urgency=low * New upstream release. -- Cord Beermann Sun, 18 Dec 2022 03:29:31 -0500 jove (4.17.4.8-1) unstable; urgency=low * New upstream release. + switched back to make -- Cord Beermann Sun, 18 Dec 2022 02:05:35 +0100 jove (4.17.4.7-1) unstable; urgency=low * New upstream release. + switched from plain make to jmake.sh wrapper with pkgconf and dropped compilerflags from debian/rules * includes compiler hardening * includes correct debugsym * fix FTCBFS: Do not build jove during dh_auto_install without cross tools (closes: 1023583) thanks to Helmut Grohne * make Lintian happy again. (better documentation about change of syntax would have been nice.) -- Cord Beermann Sat, 10 Dec 2022 22:15:35 +0100 jove (4.17.4.4-1) unstable; urgency=low * New upstream release. * added fdocs-target which was removed from default upstream. -- Cord Beermann Sat, 11 Jun 2022 14:28:18 +0200 jove (4.17.4.3-1) unstable; urgency=low * New upstream release. + should now build on Hurd * cleaned changelog from a double entry out of order. -- Cord Beermann Fri, 10 Jun 2022 21:09:41 +0200 jove (4.17.4.1-1) unstable; urgency=low * New upstream release. * dropping pkg-config as Build Dependency * removed SYSDEFS-Definition from build process -- Cord Beermann Mon, 30 May 2022 16:51:56 +0200 jove (4.17.4.0-1) unstable; urgency=medium * New upstream release. * added pkg-config as Build Dependency for modified building. * Bump Standard to 4.6.0, no changes * Fixed Lintian Overrides -- Cord Beermann Sun, 29 May 2022 12:14:32 +0200 jove (4.17.3.6-2) unstable; urgency=medium * Bump Policy. no changes. * Convert po-Files to utf-8 * Minor changes to make Lintian Happy. -- Cord Beermann Sat, 16 Jan 2021 12:07:43 +0100 jove (4.17.3.6-1) unstable; urgency=medium * New upstream release -- Cord Beermann Sun, 05 Apr 2020 11:00:17 +0200 jove (4.17.3.5-1) unstable; urgency=medium * New upstream release + LG_JBUFSIZ default is now 15, 32k chars per line. Dropping our own modification to 14 (16k chars) -- Cord Beermann Thu, 19 Mar 2020 21:54:13 +0100 jove (4.17.3.2-1) unstable; urgency=medium * New upstream release + Documentation enhanced -- Cord Beermann Sat, 14 Mar 2020 11:05:48 +0100 jove (4.17.3.1-1) unstable; urgency=medium * New upstream release -- Cord Beermann Sun, 08 Mar 2020 12:21:12 +0100 jove (4.17.2.9-1) unstable; urgency=medium * New upstream release + JLGBUFSIZ is now LG_JBUFSIZ -- Cord Beermann Wed, 04 Mar 2020 18:33:08 +0100 jove (4.17.2.8-1) unstable; urgency=low * New upstream release -- Cord Beermann Tue, 03 Mar 2020 21:19:54 +0100 jove (4.17.2.7-1) unstable; urgency=low * New upstream release * Refresh Debian specific jove.rc * Add ctags or emacs-bin-common to Suggest * change Suggest on spell to aspell -- Cord Beermann Wed, 26 Feb 2020 19:07:26 +0100 jove (4.17.2.0-2) unstable; urgency=low * Fixed Regression + Let dh_auto_build pass cross compilers to make. * Updated Translations + eu by Iñaki Larrañaga Murgoitio + pt by Miguel Figueiredo (closes: #951358) -- Cord Beermann Sat, 15 Feb 2020 13:40:22 +0100 jove (4.17.2.0-1) unstable; urgency=low * New upstream release + move shared-files to /usr/share + adopted most of the patches from previous package * Rebuild Package from scratch. + From 1.0 to 3.0 (quilt) + Pulled all not applied patches and install modifications from debian/* * Installed Manual, Quickreference and Commands to /usr/share/doc/jove * Removed init.d-recover-Job. Script placed in doc-dir, added a NEWS about it. jove -r still does things. * Dropped Function-keys from Beginners Menu (closes: #172206, #322980, #478561, #588002) * Bumped Debian Policy-Version to 4.5.0 + added Rules-Requires-Root: no * Updated Translations + de by Helge Kreutzmann (closes: #950469, #950752) + es by Jonatan Porras + ru by Yuri Kozlov (closes: #950668) + sv by Sebastian Rasmussen + eu by Iñaki Larrañaga Murgoitio + fi by Sami Kallio + it by Beatrice Torracca (closes: #951145) + nl by Frans Spiesschaert (closes: #951328) + fr by Jean-Pierre Giraud (closes: #951342) -- Cord Beermann Fri, 14 Feb 2020 19:29:24 +0100 jove (4.16.0.73-5) unstable; urgency=low * Fix FTCBFS: Let dh_auto_build pass cross compilers to make. thanks Helmut Grohne (Closes: #883116) * Bump Policy-Version to 4.1.1 (no change) -- Cord Beermann Fri, 01 Dec 2017 18:13:04 +0100 jove (4.16.0.73-4) unstable; urgency=low * force nroff to ascii to work towards reproducible builds. (choosing ascii as this program itself doesn't support utf-8) * rework debian/copyright * switch to Debhelper 9 * add 'set -e' to maintainer scripts. * ignore homepage-field. we don't have one. -- Cord Beermann Thu, 20 Aug 2015 11:14:38 +0200 jove (4.16.0.73-3) unstable; urgency=low * The Debconf15 release * bumped Policy-Version to 3.9.5 (no change) * configured to allow a maximum line length of 16k (instead of 4096) -- Cord Beermann Tue, 11 Aug 2015 21:54:46 +0200 jove (4.16.0.73-2) unstable; urgency=low * added it.po (closes: #729795) * added lsb sourcisng to init.d to make lintian happy * lowered MTA recommends to Suggest * bumped Policy-Version to 3.9.5 (no change) -- Cord Beermann Fri, 22 Nov 2013 22:06:08 +0100 jove (4.16.0.73-1) unstable; urgency=low * New upstream release (Upstream accepted our changes) * acknowledge NMUs (Closes: #596569, #478558, #583662) * added hardening * added empty status init.d * cleaned watch-file * add recommended build targets * bumped Policy-Version to 3.9.3 (no change) -- Cord Beermann Thu, 21 Jun 2012 21:33:34 +0200 jove (4.16.0.72-2.2) unstable; urgency=low * Non-maintainer upload. * Drop xjove binary removal, xview is being removed from the archive (Closes: #596569, #478558) -- Moritz Muehlenhoff Tue, 24 May 2011 23:07:41 +0200 jove (4.16.0.72-2.1) unstable; urgency=low * Non-maintainer upload. * Fix pending l10n issues. Debconf translations: - Danish (Joe Hansen). Closes: #583662 -- Christian Perrier Thu, 07 Apr 2011 08:30:00 +0200 jove (4.16.0.72-2) unstable; urgency=low * Rebuild with reworked Architectures. + Modified debian/rules so it simply looks for xviewg to + Now use a whitelist for Architectures in debian/control (Please file a bug if your architecture has xview so xjove can be build) -- Cord Beermann Tue, 25 May 2010 15:48:36 +0200 jove (4.16.0.72-1) unstable; urgency=low * New upstream release + fixes a bug that shows up on 64-bit Ubuntu 10.4 * Make Lintian Happy + Bumped Policy-version + Depends on dh 7 + Adding Source-Format * Dropped linking against libolgx (not used by xjove) * Fixed a typo in the manpage * Acknowledge the NMUs -- Cord Beermann Tue, 25 May 2010 08:04:56 +0200 jove (4.16.0.70-3.2) unstable; urgency=low * Non-maintainer upload with maintainer approval to fix release goal. * Correct init.d script dependencies and move from rcS.d/ to runlevels 2-5 (Closes: 548312). -- Petter Reinholdtsen Thu, 18 Mar 2010 19:07:01 +0100 jove (4.16.0.70-3.1) unstable; urgency=low * Non-maintainer upload to fix pending l10n issues. * Debconf translations: - Dutch. Closes: #418402 - Brazilian Portuguese. Closes: #447798 - Spanish. Closes: #465159 - Finnish. Closes: #476318 - Galician. Closes: #478059 - Vietnamese. Closes: #478148 - Basque. Closes: #479082 * Use "linux-any" in the architectures list instead of a long pile of arches while we really want to exclude non Linux arches Closes: #470034 * Do not uncoditionnally strip binaries. Closes: #437241 * [Lintian] Remove generic sentences from README.Debian * [Lintian] Correct menu section to Applications/Editors * [Lintian] Set debhelper compatibility with debian/compat -- Christian Perrier Thu, 10 Apr 2008 08:23:23 +0200 jove (4.16.0.70-3) unstable; urgency=medium * Updated ja.po (closes: #402611) * Updated ru.po (closes: #404429) * adding build-dependency po-debconf * no more changes, should be safe for release. -- Cord Beermann Wed, 3 Jan 2007 22:02:12 +0100 jove (4.16.0.70-2) unstable; urgency=low * added provides for 'editor' (closes: #398749) * debconf translations + updated french translation (closes: #374528) + added portugese translation (closes: #381195) + added swedish translation (closes: #387507) + updated czech translation (closes: #389213) + updated german translation (closes: #396421) -- Cord Beermann Sun, 19 Nov 2006 14:12:47 +0100 jove (4.16.0.70-1) unstable; urgency=low * New upstream release * bumped Standard to 3.7.2 + removed references on /usr/X11R6 + no more changes * made lintian (mostly) happy by modifying debconf-templates -- Cord Beermann Wed, 31 May 2006 22:43:51 +0200 jove (4.16.0.69-5) unstable; urgency=low * Re-upload without change to trigger buildd. (last time there was a missing dependency on xviewg-dev, so buildds failed.) -- Cord Beermann Thu, 19 Jan 2006 21:10:07 +0100 jove (4.16.0.69-4) unstable; urgency=low * dpkg-sig signature aren't acccepted by ftp-master anymore. this sucks. (still closes: #333417, #346620) -- Cord Beermann Tue, 10 Jan 2006 21:12:24 +0100 jove (4.16.0.69-3) unstable; urgency=low * Upload failed, as the xviewg-Maintainer promised an upload for the xlib-dev Transition i add xjove back. (closes: #333417, #346620) -- Cord Beermann Mon, 9 Jan 2006 21:49:15 +0100 jove (4.16.0.69-2) unstable; urgency=low * added swedish debconf template sv.po (closes: #333417) * I rebuild the package now without the X dependency. this also means that xjove will be no longer available. If xview, which is unmaintained for many years now, comes back to life, i will add xjove again. (closes: #346620) -- Cord Beermann Mon, 9 Jan 2006 21:46:47 +0100 jove (4.16.0.69-1) unstable; urgency=low * New upstream release * Updated watch-File -- Cord Beermann Sat, 1 Oct 2005 12:07:09 +0200 jove (4.16.0.68-1) unstable; urgency=low * New upstream release * Workarounds a problem which garbles the display if you scroll up. -- Cord Beermann Thu, 29 Sep 2005 22:54:05 +0200 jove (4.16.0.67-2) unstable; urgency=low * Fixed debconf-dependency -- Cord Beermann Thu, 29 Sep 2005 21:13:42 +0200 jove (4.16.0.67-1) unstable; urgency=low * New upstream release * debhelper compatibility 2 -> 4 * po-debconf-usage has been introduced some time ago (closes: #237464) * added czech debconf template cs.po (closes: #298214) * added japanese debconf template ja.po (closes: #310163) * added vietnamese debconf template vi.po (closes: #314259) * fixed alternatives-handling (closes: #327537) -- Cord Beermann Sat, 17 Sep 2005 20:45:35 +0200 jove (4.16.0.65-4) unstable; urgency=low * added frensch debconf tmeplate (closes: #303018) * disabled building of xjove for amd64, ppc64, because no xview there. (closes: #299943) * reintroduced the same handling for hurd-i386 -- Cord Beermann Thu, 7 Apr 2005 20:52:07 +0200 jove (4.16.0.65-3) unstable; urgency=medium * Madeexcludes to not try to build ia64 * added amd64 and ppc64 to build architectures (closes #299943) * urgency medium, because of bug #271313 -- Cord Beermann Sun, 20 Mar 2005 21:05:01 +0100 jove (4.16.0.65-2) unstable; urgency=low * xjove doesn't build/work on ia64 because of a missing xviewg-Package. see bug 228957. I fixed Build-Deps and Architecture, so this shouldn't stop jove to go to testing. * deleted Provides: emacsen, as this seems to have another meaning according to http://www.debian.org/doc/packaging-manuals/debian-emacs-policy -- Cord Beermann Sat, 12 Mar 2005 14:03:05 +0100 jove (4.16.0.65-1) unstable; urgency=low * New upstream release * added Provides: emacsen (it is emacs compatible) * added emacs alternative * made lintian happy + added sendmail as alternative for mail-transport-agent + switched to po-debconf + moved xjove from /usr/X11R6 to /usr -- Cord Beermann Sat, 26 Feb 2005 22:57:41 +0100 jove (4.16.0.64-1) unstable; urgency=low * New upstream release * bumped Standard to 3.6.1. (no change) -- Cord Beermann Fri, 27 Feb 2004 17:30:28 +0100 jove (4.16.0.58-1) unstable; urgency=low * New upstream release * Fixed references of jove.rc in the manpage (closes: #162636) * I would like to remove the /usr/doc -> /usr/share/doc link, but the debhelper-version currently in testing isn't able to. So it remains for now. (and lintian is unhappy.) * As we don't need to restart the temp-file recovery after a dpkg-reconfigure i don't see a sense in adding a debconf-versioning. (lintian is unhappy.) * removed 'full stop' from descriptons. (lintian is a little happier.) * bumped Standard to 3.5.8.0. (no change) -- Cord Beermann Wed, 29 Jan 2003 20:43:11 +0100 jove (4.16.0.56-1) unstable; urgency=low * New upstream release + License update. jove is now DFSG-free again (closes: #120759) * added russian debconf template (closes: #136926) -- Cord Beermann Thu, 21 Mar 2002 19:54:43 +0100 jove (4.16.0.52-3) unstable; urgency=low * fixed template. (closes: #123774, #123810) -- Cord Beermann Thu, 13 Dec 2001 19:37:54 +0100 jove (4.16.0.52-2) unstable; urgency=low * added german template by Sebastian Feltel (closes: #109144) * moved jove to non-free (closes: #120759) i'll reopen this bug as wishlist item, the Original Author Jonathan Payne said 'I've always personally considered it a "do whatever the hell you want with it" piece of code, as long as you don't try to sell it.'. Sadly the people at jovehacks@cs.toronto.edu, who now maintain that project haven't yet answered my mail or released a copyright-fixed version. -- Cord Beermann Mon, 10 Dec 2001 22:00:28 +0100 jove (4.16.0.52-1) unstable; urgency=low * New upstream release * Standards: 3.5.6.0 -- Cord Beermann Sun, 12 Aug 2001 11:35:40 +0200 jove (4.16.0.50-1) unstable; urgency=low * new upstream * recompile with current testing including XFree86 V4.x * removed Hurdish-excludes from Build-depends, because 1. it stops Autobuilders from working correctly 2. as xlibs/Xview gets available for the Hurd, jove should be compile fine there. Since then i'll port it myself. -- Cord Beermann Sun, 18 Feb 2001 14:54:16 +0100 jove (4.16.0.49-4) unstable; urgency=low * debconf'ed -- Cord Beermann Wed, 17 Jan 2001 20:40:09 +0100 jove (4.16.0.49-3) unstable; urgency=low * fixed bug in preinst-script (Closes: #82374) (Thanks to Nathaniel Smith) * changed my address, as i'm now in the project. -- Cord Beermann Mon, 15 Jan 2001 08:58:51 +0100 jove (4.16.0.49-2) unstable; urgency=low * fixed a 'cannot build from source' bug. (Closes: #81878) * removed a tailing space from the menu-file. (patches supplied by Martin Michlmayr) -- Cord Beermann Thu, 11 Jan 2001 08:04:57 +0100 jove (4.16.0.49-1) unstable; urgency=low * previous Maintainer Loic Prylli gives now Package away to me. Thanks. * New Maintainer: Cord Beermann * New Upstream version. * started packaging up from scratch. * activated mouse and scrollbar * split off xjove as seperate package (depending on jove) * finally closing bugs from previous NMU-Release (Closes: #79015, #50917) * Standards-Version: 3.2.1 -- Cord Beermann Sun, 21 Dec 2000 13:38:50 +0100 jove (4.16-5.1) unstable; urgency=low * NMU * Patches for compiling on the Hurd (Fixes #79015) * Update to Standards-Version: 3.1.1.1 (Fixes #50917) * Added script to recover crashed jove buffers * changed CONFIGDIR to /etc/jove * Added Beginners Menu (adapted from Gerold Meerkoetter) * Added update-alternatives * Added menu-entry * fixed problem with 'make install' -- Cord Beermann Tue, 12 Dec 2000 23:36:36 +0100 jove (4.16-5) frozen unstable; urgency=low * recompile for ncurses3.4 * fix wrong path in manpages (bug #21457) * remove irrelevant jovetool and xjove manpages (bug #22312,#22313) -- Loic Prylli Wed, 11 Nov 1998 19:09:28 +0100 jove (4.16-4) unstable; urgency=low * fix Bug#25308: jove 4.16-3 requires /usr/tmp -- Loic Prylli Wed, 14 Oct 1998 01:12:02 +0200 jove (4.16-3) unstable; urgency=low * use dh_testdir and dh_testroot * change buf.c, with glibc stat modifies its args even when failing * change CONFIGDIR, now /etc/jove.rc -- Loic Prylli Fri, 20 Feb 1998 00:27:17 +0100 jove (4.16-2) unstable; urgency=low * removed unneeded patches * cleaned configuration -- Loic Prylli Mon, 9 Feb 1998 23:59:02 +0100 jove (4.16-1) unstable; urgency=low * Initial Release. -- Loic Prylli Tue, 31 Dec 1996 00:41:08 +0100 jove-4.17.5.5/pkg/deb/debian/compat000066400000000000000000000000031501102521500166420ustar00rootroot0000000000000011 jove-4.17.5.5/pkg/deb/debian/control000066400000000000000000000014331501102521500170470ustar00rootroot00000000000000Source: jove Section: editors Priority: optional Maintainer: Cord Beermann Build-Depends: debhelper, po-debconf, libncurses-dev, groff, pkgconf Standards-Version: 4.6.1 Homepage: https://github.com/jonmacs/jove Rules-Requires-Root: no Package: jove Architecture: any Depends: ${shlibs:Depends}, ${misc:Depends} Provides: editor Suggests: aspell, ctags | emacs-bin-common Description: Jonathan's Own Version of Emacs - a compact, powerful editor Jove is a compact, powerful Emacs-style text-editor. It provides the common emacs keyboard bindings, together with a reasonable assortment of the most popular advanced features (e.g. interactive shell windows, compile-it, language specific modes) while weighing in with CPU, memory, and disk requirements comparable to vi(1). jove-4.17.5.5/pkg/deb/debian/copyright000066400000000000000000000052221501102521500173770ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: jove Upstream-Contact: jovehacks@cs.toronto.edu Source: https://github.com/jonmacs/jove/releases Files: * Copyright: 1986-2002 by Jonathan Payne License: permissive-1 ########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## Files: xjove/* Copyright: 1991-1999 by C.H.Lindsey License: permissive-2 ########################################################################### # This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of # # Manchester. (X)JOVETOOL is provided to you without charge, and with no # # warranty. You may copy, modify, and/or distribute (X)JOVETOOL, # # provided that this notice is included in all the files, except insofar # # as a more specific copyright notices attaches to the file (x)jovetool.c # ########################################################################### Files: jtc.c Copyright: 2020 by Mark Moraes License: permissive-3 /************************************************************************** * This file is Copyright (C) 2020 by Mark Moraes. It is provided * * without charge and without warranty. You may copy, modify, and/or * * distribute it, provided that this notice is included in all the source * * file and documentation. * **************************************************************************/ Files: debian/* Copyright: 2020-2022 Cord Beermann License: GPL-2+ This package 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 package 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, see . On Debian systems, the complete text of the GNU General Public License version 2 can be found in "/usr/share/common-licenses/GPL-2". jove-4.17.5.5/pkg/deb/debian/jove.config000066400000000000000000000005471501102521500176030ustar00rootroot00000000000000#!/bin/sh set -e # We need debconf. . /usr/share/debconf/confmodule go=0 if [ -f /etc/jove.rc ] then if [ ! -f /etc/jove/jove.rc ] then db_input high jove/upgradewarn-1 || true mkdir /etc/jove mv /etc/jove.rc /etc/jove/jove.rc else db_input high jove/upgradewarn-2 || true mv /etc/jove.rc /etc/jove/jove.rc.old fi fi exit 0 jove-4.17.5.5/pkg/deb/debian/jove.doc-base000066400000000000000000000005611501102521500200070ustar00rootroot00000000000000Document: jove.man.txt Title: Debian jove Manual Author: Jonathan Payne Abstract: JOVE is considered a display editor because normally the text being edited is visible on the screen and is updated automatically as you type your commands. Section: Editors Format: pdf Files: /usr/share/doc/jove/jove.man.pdf.gz Format: text Files: /usr/share/doc/jove/jove.man.txt.gz jove-4.17.5.5/pkg/deb/debian/jove.docs000066400000000000000000000000301501102521500172510ustar00rootroot00000000000000README debian/rc.d-jove jove-4.17.5.5/pkg/deb/debian/jove.lintian-overrides000066400000000000000000000004631501102521500217710ustar00rootroot00000000000000jove: executable-in-usr-lib [usr/lib/jove/recover] jove: package-contains-documentation-outside-usr-share-doc [usr/share/jove/cmds.txt] jove: package-contains-documentation-outside-usr-share-doc [usr/share/jove/jem.txt] jove: package-contains-documentation-outside-usr-share-doc [usr/share/jove/teach-jove] jove-4.17.5.5/pkg/deb/debian/jove.menu000066400000000000000000000003071501102521500172740ustar00rootroot00000000000000?package(jove):\ needs="text"\ hints="small, useful, featureful"\ section="Applications/Editors"\ title="jove"\ longtitle="Jove, Jonathan's Own Version of EMACS"\ command="/usr/bin/jove" jove-4.17.5.5/pkg/deb/debian/jove.postinst000066400000000000000000000013421501102521500202130ustar00rootroot00000000000000#!/bin/sh -e set -e . /usr/share/debconf/confmodule # These are for the generic editor links update-alternatives --install /usr/bin/editor editor /usr/bin/jove 60 \ --slave /usr/share/man/man1/editor.1.gz editor.1.gz \ /usr/share/man/man1/jove.1.gz update-alternatives --install /usr/bin/emacs emacs /usr/bin/jove 0 \ --slave /usr/share/man/man1/emacs.1.gz emacs.1.gz \ /usr/share/man/man1/jove.1.gz if dpkg --compare-versions "$2" le "4.17.2.0-1" ; then if [ -f /etc/init.d/jove ] then db_input high jove/removeinitd || true update-rc.d -f jove remove >/dev/null rm /etc/init.d/jove fi if ls -A /var/lib/jove/preserve/ >/dev/null then db_input high jove/preservefiles || true fi fi #DEBHELPER# jove-4.17.5.5/pkg/deb/debian/jove.prerm000066400000000000000000000002531501102521500174550ustar00rootroot00000000000000#!/bin/sh -e set -e if [ "$1" != "upgrade" ] then update-alternatives --remove editor /usr/bin/jove update-alternatives --remove emacs /usr/bin/jove fi #DEBHELPER# jove-4.17.5.5/pkg/deb/debian/jove.rc000066400000000000000000000000641501102521500167340ustar00rootroot00000000000000# Debian config, sourced from SHAREDIR/jove/jove.rc jove-4.17.5.5/pkg/deb/debian/jove.templates000066400000000000000000000011321501102521500203230ustar00rootroot00000000000000Template: jove/upgradewarn-1 Type: note _Description: Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc Template: jove/upgradewarn-2 Type: note _Description: Old version of /etc/jove.rc and new version /etc/jove/jove.rc found Moving old version to /etc/jove/jove.rc.old Template: jove/removeinitd Type: note _Description: Removed obsolete /etc/init.d/jove script Check NEWS.Debian for more information Template: jove/preservefiles Type: note _Description: Found old files in /var/lib/jove/preserve/ You can recover those by running jove -r Check NEWS.Debian for more information. jove-4.17.5.5/pkg/deb/debian/po/000077500000000000000000000000001501102521500160615ustar00rootroot00000000000000jove-4.17.5.5/pkg/deb/debian/po/POTFILES.in000066400000000000000000000000511501102521500176320ustar00rootroot00000000000000[type: gettext/rfc822deb] jove.templates jove-4.17.5.5/pkg/deb/debian/po/cs.po000066400000000000000000000040061501102521500170260ustar00rootroot00000000000000# # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # msgid "" msgstr "" "Project-Id-Version: jove\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2006-09-24 17:57+0200\n" "Last-Translator: Miroslav Kure \n" "Language-Team: Czech \n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Byla nalezena starší verze /etc/jove.rc. Přesunul jsem ji do /etc/jove/jove." "rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Byla nalezena starší verze /etc/jove.rc i novější varianta /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Přesunuji starou verzi do /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" jove-4.17.5.5/pkg/deb/debian/po/da.po000066400000000000000000000032501501102521500170050ustar00rootroot00000000000000# Danish translation jove. # Copyright (C) 2010 jove & Joe Hansen. # This file is distributed under the same license as the jove package. # Joe Hansen , 2010. # msgid "" msgstr "" "Project-Id-Version: jove\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2010-05-29 17:30+01:00\n" "Last-Translator: Joe Hansen \n" "Language-Team: Danish \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Fandt gammel version af /etc/jove.rc. Flyttede den til /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "Gammel version af /etc/jove.rc og ny version /etc/jove/jove.rc fundet" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Flytter gammel version til /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" jove-4.17.5.5/pkg/deb/debian/po/de.po000066400000000000000000000046051501102521500170160ustar00rootroot00000000000000# # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # # Helge Kreutzmann , 2006,2020. # msgid "" msgstr "" "Project-Id-Version: jove 4.17.1.0-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-02 09:31+0100\n" "Last-Translator: Helge Kreutzmann \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=ISO-8859-15\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Alte Version von /etc/jove.rc gefunden. Datei wird nach /etc/jove/jove.rc " "verschoben." #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Alte Version von /etc/jove.rc und neue Version von /etc/jove/jove.rc gefunden." #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Die alte Version wird nach /etc/jove/jove.rc.old verschoben." #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Es wurde das veraltete Skript /etc/init.d/jove entfernt." #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Bitte lesen Sie NEWS.Debian für weitere Informationen." #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Es wurden alte Dateien in /var/lib/jove/preserve/ gefunden." #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Sie können diese mittels »jove -r« wiederherstellen. Bitte lesen Sie NEWS." "Debian für weitere Informationen." jove-4.17.5.5/pkg/deb/debian/po/es.po000066400000000000000000000056661501102521500170450ustar00rootroot00000000000000# jove po-debconf translation to Spanish # Copyright (C) 2005 Software in the Public Interest # This file is distributed under the same license as the jove package. # # Changes: # - Initial translation # César Gómez Martín # # - Updates: # Jonatan Porras , 2020 # # Traductores, si no conoce el formato PO, merece la pena leer la # documentación de gettext, especialmente las secciones dedicadas a este # formato, por ejemplo ejecutando: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # Equipo de traducción al español, por favor, lean antes de traducir # los siguientes documentos: # # - El proyecto de traducción de Debian al español # http://www.debian.org/intl/spanish/ # especialmente las notas de traducción en # http://www.debian.org/intl/spanish/notas # # - La guía de traducción de po's de debconf: # /usr/share/doc/po-debconf/README-trans # o http://www.debian.org/intl/l10n/po-debconf/README-trans # msgid "" msgstr "" "Project-Id-Version: jove 4.16.0.69-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2008-02-10 19:09-0500\n" "Last-Translator: César Gómez Martín \n" "Language-Team: Debian l10n spanish \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=utf-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Poedit-Language: Spanish\n" "X-Poedit-Country: SPAIN\n" "X-Poedit-SourceCharset: utf-8\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Se ha encontrado una versión antigua de /etc/jove.rc. Se ha movido a " "/etc/jove/jove.rc." #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Se ha encontrado tanto la versión antigua de /etc/jove.rc como la nueva " "/etc/jove/jove.rc." #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Se va a mover la versión antigua del fichero a /etc/jove/jove.rc.old." #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Se elimino el script obsoleto /etc/init.d/jove" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Consulte NEWS.Debian para más información." #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" "Se encontraron archivos antiguos en /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "Puede recuperarlos ejecutando jove -r Consulte NEWS.Debian para más " "información." jove-4.17.5.5/pkg/deb/debian/po/eu.po000066400000000000000000000040661501102521500170400ustar00rootroot00000000000000# translation of jove-eu.po to Euskara # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the PACKAGE package. # # Piarres Beobide , 2008. # Iñaki Larrañaga Murgoitio , 2020. msgid "" msgstr "" "Project-Id-Version: jove-eu\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-15 11:21+0100\n" "Last-Translator: dooteo \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 2.0\n" "Plural-Forms: nplurals=2; plural=n != 1;\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "/etc/jove.rc-ren bertsio zaharra aurkitu da. /etc/jove/jove.rc-ra mugitua" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "/etc/jove.rc bertsio zaharra eta /etc/jove/jove.rc bertsio berria aurkitu " "dira" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Bertsio zaharra /etc/jove/jove.rc.old-ra mugitzen" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "/etc/init.d/jove script zaharkitua ezabatuta" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Begiratu NEWS.Debian informazio gehiagorako" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Fitxategi zaharrak aurkitu dira /var/lib/jove/preserve/ pean" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Hauek berreskuratzeko exekutatu: jove -r. Begiratu NEWS.Debian informazio" " gehiagorako." jove-4.17.5.5/pkg/deb/debian/po/fi.po000066400000000000000000000037101501102521500170200ustar00rootroot00000000000000# # Sami Kallio , 2020. # msgid "" msgstr "" "Project-Id-Version: jove\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-09 16:06+0200\n" "Last-Translator: Sami Kallio \n" "Language-Team: Finnish \n" "Language: fi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" "X-Poedit-Language: Finnish\n" "X-Poedit-Country: FINLAND\n" "X-Generator: Gtranslator 3.34.0\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Löydettiin vanha tiedosto /etc/jove.rc. Se siirrettiin nimelle /etc/jove/" "jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "Löydettiin vanha versio /etc/jove.rc ja uusi versio /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Vanha versio siirrettiin nimelle /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Poistettiin vanhentunut /etc/init.d/jove komentosarja" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Tarkista lisätiedot tiedostosta NEWS.Debian" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Löydettiin vanhoja tiedostoja hakemistosta /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Voit palauttaa nämä komennolla jove -r Tarkista lisätiedot tiedostosta NEWS." "Debian." jove-4.17.5.5/pkg/deb/debian/po/fr.po000066400000000000000000000046061501102521500170360ustar00rootroot00000000000000# Translation of jove debconf templates to French # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # msgid "" msgstr "" "Project-Id-Version: jove 4.16.0.0.70-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2006-06-15 23:52+0200\n" "Last-Translator: Christophe Masson \n" "Language-Team: French \n" "Language: fr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Un ancien fichier /etc/jove.rc a été trouvé et renommé en /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Un ancien /etc/jove.rc et un nouveau /etc/jove/jove.rc ont été trouvés " "simultanément" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "L'ancienne version est renommée /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Une version obsolète du script /etc/init.d/jove a été supprimée" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Consultez NEWS.Debian pour plus d'informations" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" "Des anciens fichiers ont été découverts dans /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Il est possible de les récupérer en exécutant jove -r. Consultez NEWS.Debian " "pour plus d'informations" jove-4.17.5.5/pkg/deb/debian/po/gl.po000066400000000000000000000032621501102521500170260ustar00rootroot00000000000000# Galician translation of jove's debconf templates # This file is distributed under the same license as the jove package. # Jacobo Tarrio , 2008. # msgid "" msgstr "" "Project-Id-Version: jove\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2008-04-26 18:39+0100\n" "Last-Translator: Jacobo Tarrio \n" "Language-Team: Galician \n" "Language: gl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Atopouse unha versión antiga de /etc/jove.rc. Trasladouse a /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Atopouse unha versión antiga de /etc/jove.rc e unha nova versión de /etc/" "jove/jove.rc." #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "A trasladar a versión antiga a /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" jove-4.17.5.5/pkg/deb/debian/po/it.po000066400000000000000000000040541501102521500170400ustar00rootroot00000000000000# Italian translation of jove debconf messages # Copyright (C) 2020, jove package copyright holder # This file is distributed under the same license as the jove package. # Beatrice Torracca , 2020. msgid "" msgstr "" "Project-Id-Version: jove\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-11 17:25+0100\n" "Last-Translator: Beatrice Torracca \n" "Language-Team: Italian \n" "Language: it\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.2.4\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Trovata una vecchia versione di /etc/jove.rc. Spostata in /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Trovate una vecchia versione di /etc/jove.rc e una nuova in /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "La vecchia versione viene spostata in /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Rimosso lo script obsoleto /etc/init.d/jove" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Controllare NEWS.Debian per maggiori informazioni." #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Trovati vecchi file in /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Possono essere recuperati eseguendo jove -r. Controllare NEWS.Debian per " "maggiori informazioni." jove-4.17.5.5/pkg/deb/debian/po/ja.po000066400000000000000000000042111501102521500170110ustar00rootroot00000000000000# # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans # # Developers do not need to manually edit POT or PO files. # msgid "" msgstr "" "Project-Id-Version: jove 4.16.0.70-2\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2006-11-28 19:41+0900\n" "Last-Translator: Atsushi Shimono \n" "Language-Team: Japanese \n" "Language: ja\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "古いバージョンである /etc/jove.rc が検出されました。これは /etc/jove/jove.rc " "に移動されます。" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "古いバージョンである /etc/jove.rc と新しいバージョンである /etc/jove/jove.rc " "が検出されました。" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "古いバージョンを /etc/jove/jove.rc.old に移動します。" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" jove-4.17.5.5/pkg/deb/debian/po/nl.po000066400000000000000000000042011501102521500170270ustar00rootroot00000000000000# Dutch debconf template translation for jove. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the jove package. # FIRST AUTHOR , YEAR. # Frans Spiesschaert , 2020. # msgid "" msgstr "" "Project-Id-Version: jove_4.17.1.4-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-05 17:07+0100\n" "Last-Translator: Frans Spiesschaert \n" "Language-Team: Debian Dutch l10n Team \n" "Language: nl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Gtranslator 3.30.1\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Er is een oudere /etc/jove.rc gevonden; deze is verplaatst naar /etc/jove/" "jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Er is zowel een oude /etc/jove.rc als een nieuwe /etc/jove/jove.rc gevonden" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "De oude versie wordt verplaatst naar /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Verouderd script /etc/init.d/jove werd verwijderd" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Lees NEWS.Debian voor meer informatie" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Oude bestanden gevonden in /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "U kunt deze herstellen door jove -r uit te voeren. Lees NEWS.Debian voor " "meer informatie." jove-4.17.5.5/pkg/deb/debian/po/pt.po000066400000000000000000000037231501102521500170510ustar00rootroot00000000000000# Portuguese translation for jove debconf messages # This file is distributed under the same license as the clamav-data package. # Miguel Figueiredo , 2020 # Ricardo Silva , 2006 # msgid "" msgstr "" "Project-Id-Version: jove 4.16.0.70-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-08 19:28+0000\n" "Last-Translator: Miguel Figueiredo \n" "Language-Team: Native Portuguese \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "Encontrada uma versão antida de /etc/jove.rc. Movida para /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "Encontrada versão antiga de /etc/jove.rc e versão nova de /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Movendo versão antiga para /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Foi removido o script obsoleto /etc/init.d/jove" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Para mais informação verifique NEWS.Debian" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Foram encontrados ficheiros antigos em /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Pode-os recuperar ao correr jove -r Verifique NEWS.Debian para mais " "informação." jove-4.17.5.5/pkg/deb/debian/po/pt_BR.po000066400000000000000000000042451501102521500174340ustar00rootroot00000000000000# jove Brazilian Portuguese translation # Copyright (C) 2007 jove'S PACKAGE COPYRIGHT HOLDER # This file is distributed under the same license as the jove package. # Eder L. Marques (frolic) , 2007. # Paulo Henrique de Lima Santana (phls) , 2025. # msgid "" msgstr "" "Project-Id-Version: jove_4.17.5.3-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2025-02-22 16:51-0300\n" "Last-Translator: Paulo Henrique de Lima Santana (phls) \n" "Language-Team: l10n Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" "X-Generator: Poedit 3.5\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Uma versão antiga do /etc/jove.rc foi encontrada. Ela foi movida para /etc/" "jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Uma versão antiga do /etc/jove.rc e uma versão nova do /etc/jove/jove.rc " "foram encontradas" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Movendo a versão antiga para /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Removido script obsoleto /etc/init.d/jove" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Leia NEWS.Debian para mais informações" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Arquivos antigos encontrados em /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Você pode recuperá-los executando jove -r. Leia NEWS.Debian para mais " "informações." jove-4.17.5.5/pkg/deb/debian/po/ru.po000066400000000000000000000052071501102521500170530ustar00rootroot00000000000000# translation of jove_4.16.0.70-2_ru.po to Russian # # Translators, if you are not familiar with the PO format, gettext # documentation is worth reading, especially sections dedicated to # this format, e.g. by running: # info -n '(gettext)PO Files' # info -n '(gettext)Header Entry' # Some information specific to po-debconf are available at # /usr/share/doc/po-debconf/README-trans # or http://www.debian.org/intl/l10n/po-debconf/README-trans# # Developers do not need to manually edit POT or PO files. # # Yuri Kozlov , 2006, 2020. msgid "" msgstr "" "Project-Id-Version: 4.17.1.4-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-05 18:46+0300\n" "Last-Translator: Yuri Kozlov \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Lokalize 2.0\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n" "%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "Найдена старая версия /etc/jove.rc. Переносится в /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "Найдены старая версия /etc/jove.rc и новая версия /etc/jove/jove.rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Старая версия переносится в /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "Удалён старый сценарий /etc/init.d/jove" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "Подробности смотрите в NEWS.Debian." #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "Найдены старые файлы в /var/lib/jove/preserve/" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "Вы можете восстановить их запуском команды jove -r. Подробности смотрите в " "NEWS.Debian." jove-4.17.5.5/pkg/deb/debian/po/sv.po000066400000000000000000000046571501102521500170650ustar00rootroot00000000000000# Swedish translations for the jove package. # Copyright (C) 2006, 2019 jove package maintainer # This file is distributed under the same license as the jove package. # Daniel Nylander , 2006. # Sebastian Rasmussen , 2019. # msgid "" msgstr "" "Project-Id-Version: jove 4.16.0.70-1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2020-02-11 02:12+0800\n" "Last-Translator: Sebastian Rasmussen \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 2.2.4\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Hittade en gammal version av /etc/jove.rc. Flyttade den till /etc/jove/jove." "rc" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Gammal version av /etc/jove.rc och nya versionen /etc/jove/jove.rc hittades" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Flyttar gammal version till /etc/jove/jove.rc.old" #. Type: note #. Description #: ../jove.templates:3001 #, fuzzy #| msgid "we found the obsolete /etc/init.d/jove script and have now" msgid "Removed obsolete /etc/init.d/jove script" msgstr "vi hittade det föråldrade skriptet /etc/init.d/jove och har nu" #. Type: note #. Description #: ../jove.templates:3001 #, fuzzy #| msgid "removed it. check NEWS.Debian for more information." msgid "Check NEWS.Debian for more information" msgstr "tagit bort det. titta i NEWS.Debian för vidare information." #. Type: note #. Description #: ../jove.templates:4001 #, fuzzy #| msgid "we found old files in /var/lib/jove/preserve/ . You can recover" msgid "Found old files in /var/lib/jove/preserve/" msgstr "vi hittade gamla filer i /var/lib/jove/preserve/ . Du kan återskapa" #. Type: note #. Description #: ../jove.templates:4001 #, fuzzy #| msgid "those by running jove -r. check NEWS.Debian for more information." msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" "dessa genom att köra jove -r. titta i NEWS.Debian för vidare information." jove-4.17.5.5/pkg/deb/debian/po/templates.pot000066400000000000000000000027311501102521500206060ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER # This file is distributed under the same license as the jove package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: jove\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=CHARSET\n" "Content-Transfer-Encoding: 8bit\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" jove-4.17.5.5/pkg/deb/debian/po/vi.po000066400000000000000000000034711501102521500170440ustar00rootroot00000000000000# Vietnamese translation for jove. # Copyright © 2008 Free Software Foundation, Inc. # Clytie Siddall , 2005-2008. # msgid "" msgstr "" "Project-Id-Version: jove 4.16.0.70-3.1\n" "Report-Msgid-Bugs-To: jove@packages.debian.org\n" "POT-Creation-Date: 2020-02-04 22:52+0100\n" "PO-Revision-Date: 2008-04-27 23:41+0930\n" "Last-Translator: Clytie Siddall \n" "Language-Team: Vietnamese \n" "Language: vi\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: LocFactoryEditor 1.7b3\n" #. Type: note #. Description #: ../jove.templates:1001 msgid "Found old version of /etc/jove.rc. Moved it to /etc/jove/jove.rc" msgstr "" "Tìm thấy phiên bản « /etc/jove.rc » cũ. Đã di chuyển nó vào « /etc/jove/jove." "rc »." #. Type: note #. Description #: ../jove.templates:2001 msgid "Old version of /etc/jove.rc and new version /etc/jove/jove.rc found" msgstr "" "Tìm thấy cả hai phiên bản cũ « /etc/jove.rc » và phiên bản mới « /etc/jove/" "jove.rc »." #. Type: note #. Description #: ../jove.templates:2001 msgid "Moving old version to /etc/jove/jove.rc.old" msgstr "Đang di chuyển phiên bản cũ vào « /etc/jove/jove.rc.old »." #. Type: note #. Description #: ../jove.templates:3001 msgid "Removed obsolete /etc/init.d/jove script" msgstr "" #. Type: note #. Description #: ../jove.templates:3001 msgid "Check NEWS.Debian for more information" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "Found old files in /var/lib/jove/preserve/" msgstr "" #. Type: note #. Description #: ../jove.templates:4001 msgid "" "You can recover those by running jove -r Check NEWS.Debian for more " "information." msgstr "" jove-4.17.5.5/pkg/deb/debian/rc.d-jove000077500000000000000000000021101501102521500171520ustar00rootroot00000000000000#!/bin/sh -e # # This file was automatically customized by debmake on Sun, 17 Dec 2000 14:36:36 +0100 # # Written by Miquel van Smoorenburg . # Modified for Debian GNU/Linux by Ian Murdock . # Modified for Debian by Christoph Lameter . /lib/lsb/init-functions ### BEGIN INIT INFO # Provides: jove # Required-Start: $remote_fs # Required-Stop: # Default-Start: 2 3 4 5 # Default-Stop: # Short-Description: Recovers broken jove sessions. # Description: Recovers broken jove sessions. ### END INIT INFO PATH=/bin:/usr/bin:/sbin:/usr/sbin # The following value is extracted by debstd to figure out how to generate # the postinst script. Edit the field to change the way the script is # registered through update-rc.d (see the manpage for update-rc.d!) FLAGS="start 50 S ." # NO_RESTART_ON_UPGRADE case "$1" in start) /usr/lib/jove/recover -syscrash ;; stop|status|reload|restart|force-reload) ;; *) echo "Usage: /etc/init.d/jove {start|stop|restart|force-reload}" exit 1 ;; esac exit 0 jove-4.17.5.5/pkg/deb/debian/rules000077500000000000000000000021131501102521500165200ustar00rootroot00000000000000#!/usr/bin/make -f # See debhelper(7) # (uncomment to enable) # output every command that modifies files on the build system. export DH_VERBOSE=1 export DEB_BUILD_MAINT_OPTIONS=hardening=+all export DPKG_EXPORT_BUILDFLAGS=1 include /usr/share/dpkg/buildflags.mk include /usr/share/dpkg/buildtools.mk CPPFLAGS+=$(shell $(PKG_CONFIG) --cflags ncurses) LDLIBS+=$(shell $(PKG_CONFIG) --libs ncurses) -lutil %: dh $@ override_dh_auto_build: dh_auto_build -- \ SYSDEFS="-DLinux" \ OPTFLAGS="$(CFLAGS)" \ LDLIBS="$(LDLIBS)" \ LDFLAGS="$(LDFLAGS)" \ JOVEHOME=/usr \ JMANDIR=/usr/share/man/man1 \ LOCALCC=$(CC_FOR_BUILD) \ CC=$(CC) \ fdocs all # Install flags must be same as build flags since paths.h and keys.c # are regenerated each time Makefile runs. override_dh_auto_install: dh_auto_install -- \ SYSDEFS="-DLinux" \ OPTFLAGS="$(CFLAGS)" \ LDLIBS="$(LDLIBS)" \ LDFLAGS="$(LDFLAGS)" \ JOVEHOME=/usr \ JMANDIR=/usr/share/man/man1 \ LOCALCC=$(CC_FOR_BUILD) \ CC=$(CC) cp debian/jove.rc debian/jove/etc/jove/jove.rc override_dh_clean: dh_clean debconf-updatepo jove-4.17.5.5/pkg/deb/debian/source/000077500000000000000000000000001501102521500167435ustar00rootroot00000000000000jove-4.17.5.5/pkg/deb/debian/source/format000066400000000000000000000000141501102521500201510ustar00rootroot000000000000003.0 (quilt) jove-4.17.5.5/pkg/deb/debian/watch000066400000000000000000000002301501102521500164670ustar00rootroot00000000000000version=4 opts=filenamemangle=s/.+\/v?(\d\S+)\.tar\.gz/jove-$1\.tar\.gz/ \ https://github.com/jonmacs/jove/tags .*/v?(\d\S+)\.tar\.gz debian uupdate jove-4.17.5.5/pkg/deb/gpg-testhome.tar000066400000000000000000000240001501102521500173300ustar00rootroot00000000000000gpg/0000700000000000000000000000000014356710724010330 5ustar rootrootgpg/secring.gpg0000600000000000000000000000113314356710607012461 0ustar rootrootcџ!X=vz9Yh= b=<6FXvxE79ۦ'P؞OP&^-a!n38;FpvŽixߕcI,&˸cΞcW Z/>s,)"TZ:.W~FۍkquK/o+$2Ɛ=o7TC_ c"X27z1HS=<Ӌ^`%^ `24a\sDI~vfwuWq oU H},b-ntsM١̷WTֳl\m!^Γk&QǤt3p$G(6vP[ksH zsu_Xȫð>rKϪ ș X;PYy՚<_PwsReb2 (2Jove Developers Testing Only (Do NOT use this key)c#c    dP.NJۭ-:G4\bՀ!|`k5Xܰgpg/pubring.gpg0000600000000000000000000000110214356710607012471 0ustar rootrootcџ!X=vz9Yh= b=<6FXvxE79ۦ'P؞OP&^-a!n38;FpvŽixߕcI,&˸cΞcW Z/>s,)"TZ:.W~FۍkquK/o+$2Ɛ=o7TC_ c"X27z1HS=<Ӌ^`%^ `24a\sDI~vfwuWq oU H},b-ntsM١̷WTֳl\m!^Γk&QǤt3p$G(6vP[ksH zsu_Xȫð>rKϪ ș X;PYy2Jove Developers Testing Only (Do NOT use this key)c#c    dP.NJۭ-:G4\bՀ!|`k5Xܰgpg/trustdb.gpg0000600000000000000000000000240014356710607012514 0ustar rootrootgpgc  5eq%Se d .SkDp:Ajove-4.17.5.5/pkg/deb/testdeb.sh000077500000000000000000000051021501102521500162100ustar00rootroot00000000000000#!/bin/sh # Prereq: apt install pbuilder debian-keyring debian-archive-keyring # Mark Moraes, 20230108 # : ${DEBVER=buster} : ${DEBARCHS="i386 amd64 armhf arm64"} set -eux case "$#" in 1) tar="$1";; *) echo "Usage: gendsc TARBALL where TARBALL can be https://github.com/jonmacs/jove/archive/refs/tags/VERSION.tar.gz or .../jove-VERSION.tgz" >&2; exit 1;; esac if test ! -r debian/changelog; then echo "$0: must run in a parent directory of debian/" >&2 exit 1 fi # fragile regexp for ver ver=$(expr "$tar" : ".*/.*[-/]\([0-9.]*\)\..*gz") case "$ver" in [0-9]*) echo "$0: version $ver tarball $tar";; *) echo "$0: failure to extract version from tarball name" >&2 exit 1 ;; esac if ! grep -s ${ver} debian/changelog; then cat - debian/changelog <<- EOF > debian/changelog.new jove (${ver}-1) unstable; urgency=low * New upstream release. -- Cord Beermann $(date +'%a, %d %b %Y %H:%M:%S %z') EOF rm debian/changelog && mv debian/changelog.new debian/changelog fi odir=$(mktemp -d) tar -C "$odir" -xvf gpg-testhome.tar GNUPGHOME="$odir/gpg" export GNUPGHOME test -e $odir/gpg/secring.gpg tar -Jcf "$odir/jove_${ver}-1.debian.tar.xz" debian ofile="$odir/jove_${ver}.orig.tar.gz" case "$tar" in http:*|https:*|ftp:*) wget -O "$ofile" "$tar" ;; *) if test ! -r "$tar"; then echo "$0: tarball $tar does not exist" >&2 exit 1; fi cp -av "$tar" "$ofile" ;; esac ( cat << EOF Format: 3.0 (quilt) Source: jove Binary: jove Architecture: any Version: ${ver}-1 Maintainer: Cord Beermann Homepage: https://github.com/jonmacs/jove Standards-Version: 4.6.1 Build-Depends: debhelper, po-debconf, libncurses-dev, groff, pkgconf Package-List: jove deb editors optional arch=any EOF while read hdr cmd; do echo "$hdr" for f in "$odir/jove_${ver}.orig.tar.gz" "$odir/jove_${ver}-1.debian.tar.xz"; do sz=$(stat --format=%s "$f") echo '' $("$cmd" < "$f" | awk '{print $1}') "$sz" $(basename "$f") done done << EOF Checksums-Sha1: sha1sum Checksums-Sha256: sha256sum Files: md5sum EOF ) | gpg --no-random-seed-file --clearsign > "$odir/jove_${ver}-1.dsc" : ${SUDO=} case "$(stat --format=%u $ofile)" in 0) ;; *) : ${SUDO=sudo};; esac for arch in $DEBARCHS; do echo "Packaging for $DEBVER $arch" base="/var/cache/pbuilder/$DEBVER-$arch-base.tgz" if test ! -f "$base"; then pbuilder create --distribution "$DEBVER" --host-arch "$arch" --mirror http://ftp.us.debian.org/debian/ --basetgz "$base" debootstrapopts "--keyring=/usr/share/keyrings/debian-archive-keyring.gpg" fi pbuilder build --host-arch "$arch" --basetgz "$base" "$odir/jove_${ver}-1.dsc" done rm -r "$odir" jove-4.17.5.5/pkg/rpm/000077500000000000000000000000001501102521500142655ustar00rootroot00000000000000jove-4.17.5.5/pkg/rpm/jspec.in000066400000000000000000000101301501102521500157140ustar00rootroot00000000000000# Redhat Package Manager .spec file for Fedora and EPEL # "Version:" filled in by make Summary: Jonathan's Own Version of Emacs Name: jove Version: __VERSION__ Release: 10%{?dist} License: Copyright only Group: Applications/Editors URL: https://github.com/jonmacs/jove Source0: https://github.com/jonmacs/jove/archive/__VERSION__.tar.gz BuildRequires: ncurses-devel groff %description Jove is a compact, powerful Emacs-style text-editor. It provides the common emacs keyboard bindings, together with a reasonable assortment of the most popular advanced features (e.g. interactive shell windows, compile-it, language specific modes) while weighing in with CPU, memory, and disk requirements comparable to vi(1). It is 8-bit clean, but does not support Unicode (or UTF-8 etc). %prep %setup -q %build # Keep both build and install make commands consistent, except for DESTDIR and targets. # JOVEHOME must be the ultimate path since it will be compiled into JOVE. make JOVEHOME=/usr JLIBDIR=%{_libdir}/jove JSHAREDIR=%{_datadir}/jove JETCDIR=%{_sysconfdir}/jove JMANDIR=%{_mandir}/man1 SYSDEFS=-DLinux OPTFLAGS="%{optflags}" LDLIBS="-lncurses -ltinfo -lutil" all %install # Keep both build and install make commands consistent, except for DESTDIR and targets. # JOVEHOME is a temporary home under $RPM_BUILD_ROOT/. # This can be different from JOVEHOME for the build phase's make. mkdir -p $RPM_BUILD_ROOT%{_bindir} mkdir -p $RPM_BUILD_ROOT%{_libdir} mkdir -p $RPM_BUILD_ROOT%{_datadir} mkdir -p $RPM_BUILD_ROOT%{_mandir}/man1 make DESTDIR=$RPM_BUILD_ROOT JOVEHOME=/usr JLIBDIR=%{_libdir}/jove JSHAREDIR=%{_datadir}/jove JETCDIR=%{_sysconfdir}/jove JMANDIR=%{_mandir}/man1 SYSDEFS=-DLinux OPTFLAGS="%{optflags}" LDLIBS="-lncurses -ltinfo -lutil" install %files %{_libdir}/jove/ %{_datadir}/jove/ %{_sysconfdir}/jove/ %{_bindir}/jove %{_bindir}/teachjove %{_mandir}/man1/jove.1* %{_mandir}/man1/teachjove.1* %doc %{_docdir}/jove/README %doc %{_docdir}/jove/jove.man.txt %doc %{_docdir}/jove/jove.man.pdf %doc %{_docdir}/jove/jove.qref %doc %{_docdir}/jove/example.rc %changelog * Wed Jun 17 2015 Fedora Release Engineering - 4.16.0.73-9 - Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild * Sat Aug 16 2014 Fedora Release Engineering - 4.16.0.73-8 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_22_Mass_Rebuild * Sun Jun 08 2014 Fedora Release Engineering - 4.16.0.73-7 - Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild * Sat Aug 03 2013 Fedora Release Engineering - 4.16.0.73-6 - Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild * Thu Feb 14 2013 Fedora Release Engineering - 4.16.0.73-5 - Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild * Thu Jul 19 2012 Paul Wouters - 4.16.0.73-4 - Include more jove documentation (txt,ps) and quick ref card * Mon Jul 16 2012 Paul Wouters - 4.16.0.73-3 - Fix license to "Copyright only" as per spot's advise - Removed defattr (no el5 built) - use global, not define * Sun Jun 10 2012 Paul Wouters - 4.16.0.73-2 - new .spec file * Sun Jul 11 2010 D. Hugh Redelmeier 4.16.0.73 - added NROFF="nroff -Tascii" to Makefile and jove.spec to force groff to use ASCII - spelling corrections [Cord Beermann] - remove -lolgx from xjove link [Cord Beermann] - improve recover's email Subject [Cord Beermann] * Mon May 24 2010 D. Hugh Redelmeier 4.16.0.72 - eliminate strcpy and byte_copy calls with overlapping source and destination - fix setmaps.c misuse of fprintf * Sun May 16 2010 D. Hugh Redelmeier 4.16.0.71 - add new variable display-default-filenames (Casey Leedom) - eliminate most GCC warnings; improve handling of some errors - allow for Linux/glibc elimination of I_PUSH (pseudo TTY STREAMS) - improve jove.spec for Red Hat packaging - delete obsolete command process-dbx-output - delete obsolete variables allow-bad-filenames, display-bad-filenames, internal-tabstop - add bindings for more xterm function key variants jove-4.17.5.5/pkg/tar/000077500000000000000000000000001501102521500142555ustar00rootroot00000000000000jove-4.17.5.5/pkg/tar/make-shell-untar000077500000000000000000000026201501102521500173540ustar00rootroot00000000000000#!/usr/bin/env python3 # Prepend a portable shell script wrapper that unpacks a tarball # here-document. # Mark Moraes. 20230204 # Released to the public domain. from __future__ import print_function import sys, os tok='__JOVE__TAR__EOF__TOKEN__' tar=' | tar %sxvf -' hdr=r'''#!/bin/sh jhome="$HOME/bin" usage="Usage: $0 [INSTALL_ROOT_DIR]\nto unpack jove binaries, doc and lib, default is $jhome" case $# in 0) ;; 1) case "$1" in -*) echo "$usage" >&2; exit 1;; *) jhome="$1";; esac ;; *) echo "$usage" >&2; exit 1;; esac set -eu if test ! -d "$jhome"; then mkdir "$jhome"; fi cd "$jhome" export LANG=C awk '{printf "%c", $1}' << \ '''+tok if len(sys.argv) != 2 or sys.argv[1].startswith('-') or not os.path.isfile(sys.argv[1]): sys.exit("Usage: "+sys.argv[0]+" INPUT_TARBALL") fname=sys.argv[1] with open(fname, "rb") as f: if fname.endswith('.bz2') or fname.endswith('.tbz2') or fname.endswith('.tbz'): tarcmd = tar % 'j' elif fname.endswith('.xz') or fname.endswith('.txz'): tarcmd = tar % 'J' elif fname.endswith('.gz') or fname.endswith('.tgz'): tarcmd = tar % 'z' elif fname.endswith('.zstd'): tarcmd = tar % '--zstd -' elif fname.endswith('.lzip'): tarcmd = tar % '--lzip -' elif fname.endswith('.lzop'): tarcmd = tar % '--lzma -' elif fname.endswith('.lzma'): tarcmd = tar % '--lzma -' else: tarcmd = tar % '' print(hdr+tarcmd) print("\n".join(["%d"%i for i in f.read()])) print(tok) jove-4.17.5.5/portsrv.c000066400000000000000000000164571501102521500146060ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* This program is invoked by JOVE for two purposes related to PIPEPROCS: * - "kbd": gather tty input into lumps and send them to JOVE proper. * - "portsrv": gather process output into lumps and send them to JOVE * These functions are gathered into one program to reduce the number * of misc. programs to install. The resulting program is small anyway. */ #define USE_STDIO_H 1 #include "jove.h" #ifdef PIPEPROCS /* almost the whole file! */ #include #include #include "sysprocs.h" #include "iproc.h" extern int pause proto((void)); private struct lump lump; /* JOVE sends KBDSIG whenever it wants the kbd process (this program) * to stop competing for input from the keyboard. JOVE does this when * JOVE realizes that there are no more interactive processes running. * The reason we go through all this trouble is that JOVE slows down * a lot when it's getting its keyboard input via a pipe. */ #ifdef POSIX_SIGS SIGHANDLERTYPE setsighandler(signo, handler) int signo; SIGHANDLERTYPE handler; { static struct sigaction act; /* static so unspecified fields are 0 */ struct sigaction oact; act.sa_handler = handler; act.sa_flags = SA_RESTART | SA_NODEFER; sigaction(signo, &act, NULL); return oact.sa_handler; } #else # define setsighandler(signo, handler) signal((signo), (handler)) #endif private SIGRESTYPE strt_read proto((int)); private volatile jbool wait_for_sig = NO; private SIGRESTYPE hold_read(junk) int junk; /* passed in when invoked by a signal; of no interest */ { setsighandler(KBDSIG, strt_read); #if defined(BSD_SIGS)||defined(POSIX_SIGS) /* * with restartable signals, the read() in kbd_process() might never * return EINTR, so need to wait here till we receive KBDSIG again. */ pause(); #else /* For old non-BSD Unix, without restartable signals */ wait_for_sig = YES; #endif return SIGRESVALUE; } private SIGRESTYPE strt_read(junk) int junk; { setsighandler(KBDSIG, hold_read); wait_for_sig = NO; return SIGRESVALUE; } private void detach() { #ifdef POSIX_PROCS setsid(); #endif #ifdef TIOCNOTTY { int fd = open("/dev/tty", O_WRONLY | O_BINARY | O_CLOEXEC); /* * if one tries to use portsrv on modern *n*x, * shells (bash, dash) seem to hang, because * they seem to try to open /dev/tty, even if * given the -s option. portsrv should not be * needed on such machines, since they should * have and use ptys, but for testing on such * machines, need to detach from the * controlling terminal. */ if (fd >= 0) { (void) ioctl(fd, TIOCNOTTY, (UnivPtr)0); (void) close(fd); } } #endif NEWPG(); } private void kbd_process() { int pid, n = -1; detach(); signal(SIGINT, SIG_IGN); pid = getpid(); lump.header.pid = pid; strt_read(0); for (;;) { if (wait_for_sig) { pause(); } n = read(0, (UnivPtr) lump.data, sizeof(lump.data)); if (n < 0) { if (!RETRY_ERRNO(errno)) break; /* something unfortunate hapened?! */ /* most likely KBDSIG */ continue; } lump.header.nbytes = n; /* It is not clear what we can do if this write fails */ do {} while (write(1, (UnivPtr) &lump, sizeof(struct header) + n) < 0 && RETRY_ERRNO(errno)); } } /* This is a server for jove sub processes. By the time we get here, our * standard output goes to jove's process input. */ private void proc_write(ptr, n) UnivConstPtr ptr; size_t n; { /* It is not clear what we can do if this write fails */ do {} while (write(1, ptr, n) < 0 && RETRY_ERRNO(errno)); } private void read_pipe(fd) int fd; { register size_t n; while ((lump.header.nbytes = read(fd, (UnivPtr) lump.data, sizeof lump.data)) > 0) { n = sizeof(struct header) + lump.header.nbytes; proc_write((UnivConstPtr) &lump, n); } } private void proc_error proto((const char * /* str */)) NEVER_RETURNS; private void proc_error(str) const char *str; { lump.header.pid = getpid(); lump.header.nbytes = strlen(str); strcpy(lump.data, str); proc_write((UnivConstPtr) &lump, sizeof(struct header) + lump.header.nbytes); /* It is not clear what we can do if this write fails */ #ifndef TIOCNOTTY { /* * for last-ditch error-reporting on old machines. On new * machines, we are either detached from tty or trying to open * it might hang. */ int tfd = open("/dev/tty", O_WRONLY | O_BINARY); if (tfd >= 0) do {} while (write(tfd, (UnivConstPtr)str, strlen(str)) < 0 && RETRY_ERRNO(errno)); } #endif _exit(-2); } private void portsrv_process(argc, argv) int argc; char **argv; { int p[2]; pid_t pid; if (pipe(p) == -1) { proc_error("Cannot pipe jove portsrv.\n"); /* NOTREACHED */ } switch (pid = fork()) { case -1: proc_error("portsrv: cannot fork.\n"); /*NOTREACHED*/ case 0: /* We'll intercept child's output in p[0] */ (void) dup2(p[1], 1); (void) dup2(p[1], 2); (void) close(p[0]); (void) close(p[1]); detach(); execv(argv[1], &argv[2]); _exit(-4); /*NOTREACHED*/ default: (void) close(0); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGQUIT, SIG_IGN); (void) close(p[1]); /* tell jove the pid of the real child as opposed to us */ lump.header.pid = getpid(); lump.header.nbytes = sizeof (pid_t); byte_copy((UnivConstPtr) &pid, (UnivPtr) lump.data, sizeof(pid_t)); /* It is not clear what we can do if this write fails */ do {} while (write(1, (UnivConstPtr) &lump, sizeof(struct header) + sizeof(pid_t)) < 0 && RETRY_ERRNO(errno)); /* read proc's output and send it to jove */ read_pipe(p[0]); /* received EOF - wait for child to die and then write the * child's status to JOVE. * * Notice that we use a byte count of -1 (an otherwise * impossible value) as a marker. JOVE "knows" the real * length is sizeof(wait_status_t). */ (void) close(p[0]); lump.header.pid = getpid(); lump.header.nbytes = -1; /* tell jove we are finished */ /* try to exit like our child did ... */ { wait_status_t status; do {} while (wait(&status) != pid); byte_copy((UnivPtr)&status, (UnivPtr)lump.data, sizeof(status)); } /* It is not clear what we can do if this write fails */ do {} while (write(1, (UnivConstPtr) &lump, sizeof(struct header) + sizeof(wait_status_t)) < 0 && errno == EINTR); } } int main(argc, argv) int argc; char **argv; { if (argc == 2 && strcmp(argv[1], "--kbd") == 0) { kbd_process(); } else if (argc > 2) { portsrv_process(argc, argv); } else { fprintf(stderr, "Usage: %s --kbd\nor\n%s EXECUTABLE ARGV...\n", argv[0], argv[0]); exit(1); } return 0; } #else /* !PIPEPROCS */ /* * Without PIPEPROCS (ptyprocs or NO_IPROCS), this program * should neither be installed nor called, but just in case, * some verbosity to help with the bug report! */ int main(argc, argv) int argc; char **argv; { int i; fprintf(stderr, "%s not compiled for PIPEPROCS: argc=%d\n", argv[0], argc); for (i = 0; i < argc; i++) fprintf(stderr, "argv[%d] = \"%s\"\n", i, argv[i]); return 1; } #endif /* !PIPEPROCS */ jove-4.17.5.5/proc.c000066400000000000000000000655621501102521500140330ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "fp.h" #include "re.h" #include "disp.h" #include "sysprocs.h" #include "ask.h" #include "delete.h" #include "extend.h" #include "fmt.h" #include "insert.h" #ifdef IPROCS # include "iproc.h" #endif #include "marks.h" #include "misc.h" #include "move.h" #include "proc.h" #include "wind.h" #include #include /* for S_IWRITE and S_IREAD */ #ifdef POSIX_SIGS # define SIGINTMASK_DECL sigset_t sigintmask; # define SIGINTMASK_INIT() { sigemptyset(&sigintmask); sigaddset(&sigintmask, SIGINT); } # define SIGINT_BLOCK() sigprocmask(SIG_BLOCK, &sigintmask, (sigset_t *)NULL) # define SIGINT_UNBLOCK() sigprocmask(SIG_UNBLOCK, &sigintmask, (sigset_t *)NULL) #else /* !POSIX_SIGS */ # ifdef USE_SIGSET # define SIGINT_BLOCK() sighold(SIGINT) # define SIGINT_UNBLOCK() sigrelse(SIGINT) # else /* !USE_SIGSET */ # ifdef BSD_SIGS # define SIGINT_BLOCK() sigsetmask(sigmask(SIGINT)) # define SIGINT_UNBLOCK() sigsetmask(0) # endif /* BSD_SIGS */ # endif /* !USE_SIGSET */ #endif /* !POSIX_SIGS */ /* This disgusting RE search string parses output from the GREP * family, from the pdp11 compiler, pcc, and lint. Jay (HACK) * Fenlasen changed this to work for the lint errors. */ char ErrFmtStr[256] = "^\\{\"\\|\\}\\([^:\"( \t]*\\)\\{\"\\, line \\|:\\|(\\} *\\([0-9][0-9]*\\)[:)]\ \\|:: *\\([^(]*\\)(\\([0-9]*\\))$\ \\|( \\([^(]*\\)(\\([0-9]*\\)) ),"; /* VAR: format string for parse errors */ #ifdef SPELL char SpellCmdFmt[FILESIZE] = SPELL; /* VAR: command to use for spell check */ #endif struct error { Buffer *er_buf; /* Buffer error is in */ LinePtr er_mess, /* Actual error message */ er_text; /* Actual error */ int er_char; /* char pos of error */ struct error *er_prev, /* List of errors */ *er_next; }; private struct error *cur_error = NULL, *errorlist = NULL; /* Eliminate any error records that contain dangling references to Lines. * We only eliminate error structs when either referent is recycled. * If it deleted, we keep it (dormant) in case it will be pasted back * into the same buffer. */ void ChkErrorLines() { register struct error *e; struct error *prev = NULL; for (e = errorlist; e != NULL; ) { struct error *next = e->er_next; if (e->er_mess->l_dline == NULL_DADDR || e->er_text->l_dline == NULL_DADDR) { /* dangling reference: delete */ if (prev == NULL) errorlist = next; else prev->er_next = next; if (next != NULL) next->er_prev = prev; if (cur_error == e) cur_error = next; free((UnivPtr)e); } else { prev = e; } e = next; } } /* Add an error to the end of the list of errors. This is used for * parse-{C,LINT}-errors and for the spell-buffer command */ private struct error * AddError(laste, errline, buf, line, charpos) struct error *laste; LinePtr errline, line; Buffer *buf; int charpos; { struct error *new = (struct error *) emalloc(sizeof *new); new->er_prev = laste; if (laste == NULL) { /* first time: free up old errors */ if (errorlist != NULL) ErrFree(); cur_error = errorlist = new; } else { laste->er_next = new; } new->er_next = NULL; new->er_buf = buf; new->er_text = line; new->er_char = charpos; new->er_mess = errline; return new; } void get_FL_info(fname, lineno) char *fname, *lineno; { putmatch(1, fname, (size_t)FILESIZE); putmatch(2, lineno, (size_t)FILESIZE); /* if error had lineno before fname, switch the two */ if (!jisdigit(lineno[0]) && jisdigit(fname[0])) { putmatch(1, lineno, (size_t)FILESIZE); putmatch(2, fname, (size_t)FILESIZE); } } /* Free up all the errors */ void ErrFree() { cur_error = NULL; while (errorlist != NULL) { struct error *nel = errorlist->er_next; free((UnivPtr) errorlist); errorlist = nel; } } /* Parse errors of the form specified in ErrFmtStr in the current * buffer. Do a show error of the first error. This is neat because this * will work for any kind of output that prints a file name and a line * number on the same line. */ void ErrParse() { struct RE_block re_blk; Bufpos *bp; char fname[FILESIZE], lineno[FILESIZE]; long lnum, last_lnum = -1; struct error *ep = NULL; Buffer *buf, *lastb = NULL; LinePtr err_line = NULL; /* avoid uninitialized complaint from gcc -W */ ErrFree(); /* This is important! */ ToFirst(); perr_buf = curbuf; REcompile(ErrFmtStr, YES, &re_blk); /* Find a line with a number on it. */ while ((bp = docompiled(FORWARD, &re_blk)) != NULL) { SetDot(bp); get_FL_info(fname, lineno); buf = do_find((Window *)NULL, fname, YES, YES); (void) chr_to_long(lineno, 10, NO, &lnum); if (buf != lastb) { lastb = buf; last_lnum = 1; /* new file */ err_line = buf->b_first; } else if (lnum == last_lnum) /* one error per line is nicer */ continue; err_line = next_line(err_line, lnum - last_lnum); ep = AddError(ep, curline, buf, err_line, 0); last_lnum = lnum; } if (cur_error != NULL) ShowErr(); } private void NeedErrors() { if (cur_error == NULL) { complain("No errors!"); /* NOTREACHED */ } } private jbool ErrorHasReferents() { return inlist(cur_error->er_buf->b_first, cur_error->er_text) && inlist(perr_buf->b_first, cur_error->er_mess); } /* Go the the next error, if there is one. Put the error buffer in * one window and the buffer with the error in another window. * It checks to make sure that the error actually exists. */ private void ToError(forward) jbool forward; { register struct error *e = cur_error; int num = arg_value(); NeedErrors(); if ((forward? e->er_next : e->er_prev) == NULL) { s_mess("You're at the %s error.", forward ? "last" : "first"); } else { while (--num >= 0 || !ErrorHasReferents()) { e = forward ? e->er_next : e->er_prev; if (e == NULL) break; cur_error = e; } ShowErr(); } } void NextError() { ToError(YES); } void PrevError() { ToError(NO); } int EWSize = 20; /* VAR: percentage of screen to make the error window */ private void set_wsize(wsize) int wsize; { wsize = (LI * wsize) / 100; if (wsize >= 1 && !one_windp()) WindSize(curwind, wsize - (curwind->w_height - 1)); } /* Show the current error, i.e. put the line containing the error message * in one window, and the buffer containing the actual error in another * window. */ void ShowErr() { Window *err_wind, *buf_wind; NeedErrors(); if (!ErrorHasReferents()) { rbell(); return; } err_wind = windbp(perr_buf); buf_wind = windbp(cur_error->er_buf); if (err_wind == NULL) { if (buf_wind != NULL) { SetWind(buf_wind); pop_wind(perr_buf->b_name, NO, -1); err_wind = curwind; } else { pop_wind(perr_buf->b_name, NO, -1); err_wind = curwind; pop_wind(cur_error->er_buf->b_name, NO, -1); buf_wind = curwind; } } else if (buf_wind == NULL) { SetWind(err_wind); pop_wind(cur_error->er_buf->b_name, NO, -1); buf_wind = curwind; } /* Put the current error message at the top of its Window */ SetWind(err_wind); SetLine(cur_error->er_mess); SetTop(curwind, (curwind->w_line = cur_error->er_mess)); set_wsize(EWSize); /* now go to the the line with the error in the other window */ SetWind(buf_wind); DotTo(cur_error->er_text, cur_error->er_char); } char ShcomBuf[LBSIZE]; /* Make a buffer name given the command `command', i.e. "fgrep -n foo *.c" * will return the buffer name "fgrep". */ char * MakeName(command) char *command; { static char bnm[FILESIZE]; register char *cp = bnm, c; const char *bp; do { c = *command++; } while (jiswhite(c)); *cp++ = '['; /* avoid potential clash with script or program names */ while (cp < &bnm[sizeof(bnm) - 1] && c != '\0' && !jiswhite(c)) { *cp++ = c; c = *command++; } *cp = '\0'; if ((bp = jbasename(&bnm[1])) != &bnm[1]) { /* bp overlaps bnm, cannot use strcpy */ cp = &bnm[1]; do ; while ((*cp++ = *bp++) != '\0'); cp--; /* make sure cp points at '\0' */ } if (cp > &bnm[1] && cp < &bnm[sizeof(bnm)-1]) { *cp++ = ']'; *cp = '\0'; } return bnm; } #ifdef SUBSHELL /* the body is the rest of this file */ /* Run make, first writing all the modified buffers (if the WtOnMk flag is * on), parse the errors, and go the first error. */ jbool WtOnMk = YES; /* VAR: write files on compile-it command */ jbool WrapProcessLines = NO; /* VAR: wrap process lines at CO-1 chars */ private void DoShell proto((char *, char *)), com_finish proto((wait_status_t, char *)); private char make_cmd[LBSIZE] = "make"; void MakeErrors() { Window *old = curwind; if (WtOnMk) put_bufs(NO); /* When we're not doing make or cc (i.e., the last command * was probably a grep or something) and the user just types * ^X ^E, he probably (possibly, hopefully, usually (in my * case)) doesn't want to do the grep again but rather wants * to do a make again; so we ring the bell and insert the * default command and let the person decide. */ if (is_an_arg() || !(sindex("make", make_cmd) || sindex("cc", make_cmd))) { if (!is_an_arg()) rbell(); /* insert the default for the user (Kludge: only if Inputp is free) */ if (Inputp == NULL) Inputp = make_cmd; jamstr(make_cmd, ask(make_cmd, "Compilation command: ")); } com_finish(UnixToBuf(UTB_DISP|UTB_CLOBBER|UTB_ERRWIN|UTB_SH, MakeName(make_cmd), (char *)NULL, make_cmd), make_cmd); ErrParse(); if (!cur_error) SetWind(old); } # ifdef SPELL private void SpelParse(bname) const char *bname; { Buffer *buftospel, *wordsb; char wordspel[100]; Bufpos *bp; struct error *ep = NULL; ErrFree(); /* This is important! */ buftospel = curbuf; wordsb = buf_exists(bname); if (wordsb == NULL) { complain("Buffer %s is gone!", bname); /* NOTREACHED */ } perr_buf = wordsb; /* This is important (buffer containing error messages) */ SetBuf(wordsb); ToFirst(); f_mess("Finding misspelled words ... "); while (!lastp(curline)) { swritef(wordspel, sizeof(wordspel), "\\<%s\\>", linebuf); SetBuf(buftospel); ToFirst(); while ((bp = dosearch(wordspel, FORWARD, NO)) != NULL) { SetDot(bp); ep = AddError(ep, wordsb->b_dot, buftospel, curline, curchar); } SetBuf(wordsb); line_move(FORWARD, 1, NO); } add_mess("Done."); /* undo buffer switches that ought not to be reflected in current window */ SetBuf(curwind->w_bufp); ShowErr(); } void SpelBuffer() { static const char Spell[] = "Spell"; const char *cp; char com[100]; Buffer *savebp = curbuf; if (curbuf->b_fname == NULL) { complain("no file name"); /* NOTREACHED */ } if ((cp = strchr(SpellCmdFmt, '%')) == NULL || cp[1] != 's' || strchr(cp+2, '%') != NULL) { complain("spell-command-format needs one %%s with no other format characters"); /* NOTREACHED */ } if (IsModified(curbuf)) SaveFile(); swritef(com, sizeof(com), SpellCmdFmt, curbuf->b_fname); (void) UnixToBuf(UTB_DISP|UTB_CLOBBER|UTB_ERRWIN|UTB_SH, Spell, (char *)NULL, com); message("[Delete the irrelevant words and then type ^X ^C]"); ToFirst(); Recur(); if (!valid_bp(savebp)) { complain("Buffer gone!"); /* NOTREACHED */ } SetBuf(savebp); SpelParse(Spell); } void SpelWords() { Buffer *wordsb = curbuf; const char *buftospel = ask_buf((Buffer *)NULL, ALLOW_OLD | ALLOW_INDEX); SetBuf(do_select(curwind, buftospel)); SpelParse(wordsb->b_name); } # endif /* SPELL */ void ShToBuf() { char bnm[128], cmd[LBSIZE]; jamstr(bnm, ask((char *)NULL, "Buffer: ")); jamstr(cmd, ask(ShcomBuf, "Command: ")); DoShell(bnm, cmd); } void ShellCom() { jamstr(ShcomBuf, ask(ShcomBuf, ProcFmt)); DoShell(MakeName(ShcomBuf), ShcomBuf); } void ShNoBuf() { jamstr(ShcomBuf, ask(ShcomBuf, ProcFmt)); com_finish(UnixToBuf(UTB_SH|UTB_FILEARG, (char *)NULL, (char *)NULL, ShcomBuf), ShcomBuf); } void Shtypeout() { wait_status_t status; jamstr(ShcomBuf, ask(ShcomBuf, ProcFmt)); status = UnixToBuf(UTB_DISP|UTB_SH|UTB_FILEARG, (char *)NULL, (char *)NULL, ShcomBuf); #ifdef MSDOS_PROCS if (status < 0) Typeout("[%s: not executed %d]", ShcomBuf, status); else if (status > 0) Typeout("[%s: exited with %d]", ShcomBuf, status); else if (!is_an_arg()) Typeout("[%s: completed successfully]", ShcomBuf); #else /* !MSDOS_PROCS */ if (WIFSIGNALED(status)) Typeout("[%s: terminated by signal %d]", ShcomBuf, WTERMSIG(status)); else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) Typeout("[%s: exited with %d]", ShcomBuf, WEXITSTATUS(status)); else if (!is_an_arg()) Typeout("[%s: completed successfully]", ShcomBuf); #endif /* !MSDOS_PROCS */ TOstop(); } /* Run the shell command into `bnm'. Empty the buffer except when we * give a numeric argument, in which case it inserts the output at the * current position in the buffer. */ private void DoShell(bnm, command) char *bnm, *command; { Window *savewp = curwind; com_finish(UnixToBuf( (is_an_arg() ? UTB_DISP|UTB_SH|UTB_FILEARG : UTB_DISP|UTB_CLOBBER|UTB_SH|UTB_FILEARG), bnm, (char *)NULL, command), command); SetWind(savewp); } private void com_finish(status, cmd) wait_status_t status; char *cmd; { #ifdef MSDOS_PROCS if (status < 0) s_mess("[%s: not executed %d]", cmd, status); else if (status > 0) s_mess("[%s: exited with %d]", cmd, status); else s_mess("[%s: completed successfully]", cmd); #else /* !MSDOS_PROCS */ if (WIFSIGNALED(status)) s_mess("[%s: terminated by signal %d]", cmd, WTERMSIG(status)); else if (WIFEXITED(status) && WEXITSTATUS(status)!=0) s_mess("[%s: exited with %d]", cmd, WEXITSTATUS(status)); else s_mess("[%s: completed successfully]", cmd); #endif /* !MSDOS_PROCS */ } #ifndef MSDOS_PROCS /* pid of any outstanding non-iproc process. * Note: since there is only room for one pid, there can be no more than * one running non-iproc process. */ pid_t ChildPid; void dowait(status) wait_status_t *status; /* may be NULL */ { # ifdef IPROCS while (DeadPid != ChildPid) { wait_status_t w; pid_t rpid = wait(&w); if (rpid == -1) { if (errno == ECHILD) { /* fudge what we hope is a bland value */ byte_zero((UnivPtr)&DeadStatus, sizeof(wait_status_t)); break; } } else { kill_off(rpid, w); } } DeadPid = 0; if (status != NULL) *status = DeadStatus; # else wait_status_t w; for (;;) { pid_t rpid = wait(&w); if (rpid == -1) { if (errno == ECHILD) { /* fudge what we hope is a bland value */ byte_zero((UnivPtr)&w, sizeof(wait_status_t)); break; } } else if (rpid == ChildPid) { break; } } if (status != NULL) *status = w; # endif ChildPid = 0; } #endif /* !MSDOS_PROCS */ /* Environment management for subshells */ private Env proc_env; private char PEnvExpBuf[LBSIZE]; private char PEnvUnsetBuf[LBSIZE]; void ProcEnvExport() { jamstr(PEnvExpBuf, ask(PEnvExpBuf, ProcFmt)); jputenv(&proc_env, PEnvExpBuf); } void ProcEnvShow() { const char **p; TOstart("subshell environment"); for (p = jenvdata(&proc_env); *p; p++) { Typeout("%s", *p); } TOstop(); } void ProcEnvUnset() { jamstr(PEnvUnsetBuf, ask(PEnvUnsetBuf, ProcFmt)); junsetenv(&proc_env, PEnvUnsetBuf); } /* Run the command cmd. Output to the buffer named bnm (if not * NULL), first erasing bnm (if UTB_DISP and UTB_CLOBBER), and * redisplay (if UTB_DISP). Leaves bnm as the current buffer and * leaves any windows it creates lying around. It's up to the * caller to fix everything up after we're done. (Usually there's * nothing to fix up.) * * If bnm is non-NULL, the process output goes to that buffer. * Furthermore, if UTB_DISP, the buffer is displayed in a window. * If not UTB_DISP, the buffer is not given a window (of course it * might already have one). If UTB_DISP and UTB_CLOBBER, the buffer * is emptied initially. If UTB_DISP and UTB_ERRWIN, that window's * size is as specified by the variable error-window-size. * * If bnm is NULL, the process output does not go to a buffer. In this * case, if UTB_DISP, it is displayed using Typeout; if not UTB_DISP, * the output is discarded. * * Only if UTB_DISP and bnm is non-NULL are UTB_ERRWIN and * UTB_CLOBBER meaningful. */ wait_status_t UnixToBuf(flags, bnm, InFName, cmd) int flags; /* bunch of booleans: see UTB_* in proc.h */ const char *bnm; /* buffer name (NULL means none) */ const char *InFName; /* name of file for process stdin (NULL means none) */ const char *cmd; /* command to run */ { #ifndef MSDOS_PROCS int p[2]; wait_status_t status; SIGHANDLERTYPE old_int; char bfn[FILESIZE]; /* buffer file name */ char bln[10]; /* buffer line number (big enough for any line number) */ char bc[6]; /* buffer column (big enough for any column) */ #else /* MSDOS_PROCS */ char cmdbuf[129]; int status = 0; char pipename[FILESIZE]; #endif /* MSDOS_PROCS */ jbool eof; char *argv[9]; /* worst case: /bin/sh sh -cf "echo $1" $1 $1 $2 $3 NULL */ char **ap = argv; File *fp; #ifdef SIGINTMASK_DECL SIGINTMASK_DECL SIGINTMASK_INIT(); #endif jdbg("UnixToBuf flags 0x%x \"%s\"\n", flags, cmd); SlowCmd += 1;; if (flags & UTB_SH) { *ap++ = Shell; *ap++ = (char *)jbasename(Shell); /* lose const (but it's safe) */ *ap++ = ShFlags; *ap++ = (char *)cmd; /* lose const (but it's safe) */ #ifdef MSDOS_PROCS /* Kludge alert! * UNIX-like DOS shells and command.com-like DOS shells * seem to differ seem to differ on two points: * - UNIX-like shells use "-" to start flags whereas * command.com-like shells use "/". * - UNIX-like shells seem to require that the argument to * $SHELL -c be quoted to cause it to be taken as a single argument. * command.com-like shells seem to automatically use the rest * of the arguments. This is not an issue under real UNIX * since arguments are passed already broken down. * * E.g., your shell comand: echo foo * jove runs: command /c echo foo OK * jove runs: sh -c echo foo Oops! sh just runs "echo" * jove runs: sh -c "echo foo" Ah, now I get it. * * We use the first character of ShFlags to distinguish * which kind of shell we are dealing with! */ if (ShFlags[0] == '-') { swritef(cmdbuf, sizeof(cmdbuf), "\"%s\"", cmd); ap[-1] = cmdbuf; /* ??? can we usefully jam in a copy or two of current filename? */ } #else /* !MSDOS_PROCS */ /* Two copies of the file name are passed to the shell: * The Cshell uses the first as a definition of $1. * Most versions of the Bourne shell use the second as a * definition of $1. (Unfortunately, these same versions * of the Bourne shell take the first as their own name * for error reporting.) */ if ((flags & UTB_FILEARG) && curbuf->b_fname != NULL) { strcpy(bfn, pr_name(curbuf->b_fname, NO)); *ap++ = bfn; *ap++ = bfn; { int ln = 1; /* origin 1 */ LinePtr lp; for (lp = curbuf->b_first; lp != curline; lp = lp->l_next) ln++; swritef(bln, sizeof(bln), "%d", ln); *ap++ = bln; } swritef(bc, sizeof(bc), "%d", curchar + 1); /* origin 1 */ *ap++ = bc; } #endif /* !MSDOS_PROCS */ } else { *ap++ = (char *)cmd; /* lose const (but it's safe) */ *ap++ = (char *)jbasename(cmd); /* lose const (but it's safe) */ } *ap++ = NULL; if (access(argv[0], J_X_OK) != 0) { complain("[Couldn't access %s: %s]", argv[0], strerror(errno)); /* NOTREACHED */ } if (flags & UTB_DISP) { if (bnm != NULL) { if (flags & UTB_CLOBBER) { isprocbuf(bnm); pop_wind(bnm, YES, B_PROCESS); } else { pop_wind(bnm, NO, B_FILE); } set_wsize(flags & UTB_ERRWIN? EWSize : 0); message("Starting up..."); redisplay(); } else { TOstart(argv[0]); Typeout("Starting up..."); TOstart(argv[0]); /* overwrite "Starting up..." */ } } /* Now I will attempt to describe how I deal with signals during * the execution of the shell command. My desire was to be able * to interrupt the shell command AS SOON AS the window pops up. * So, if we have SIGINT_BLOCK (i.e., a modern signal mechanism) * I hold SIGINT, meaning if we interrupt now, we will eventually * see the interrupt, but not before we are ready for it. We * fork, the child releases the interrupt, it then sees the * interrupt, and so exits. Meanwhile the parent ignores the * signal, so if there was a pending one, it's now lost. * * Without SIGINT_BLOCK, the best behavior you can expect is that * when you type ^] too soon after the window pops up, it may * be ignored. The behavior BEFORE was that it would interrupt * JOVE and then you would have to continue JOVE and wait a * little while longer before trying again. Now that is fixed, * in that you just have to type it twice. */ #ifndef MSDOS_PROCS dopipe(p); # ifdef SIGINT_BLOCK SIGINT_BLOCK(); # else old_int = setsighandler(SIGINT, SIG_IGN), # endif # ifdef USE_VFORK /* * There are several other forks in Jove, but for * machines lacking MMUs, where vfork might be * significantly more performant, it is nice to have * SUBSHELL capability using pipes (MSDOS_PROCS use a * temporary file for subshell output and spawn). * moraes Note from 2020 4.17: vfork has not been tested in a * long time, it is quite possible/likely that it does * not even work (I think that nothing between here * and the exec damages parent state, but using vfork * is a deal with the devil) */ ChildPid = vfork(); # else ChildPid = fork(); # endif if (ChildPid == -1) { int fork_errno = errno; pipeclose(p); # ifdef SIGINT_UNBLOCK SIGINT_UNBLOCK(); # else (void) setsighandler(SIGINT, old_int), # endif complain("[Fork failed: %s]", strerror(fork_errno)); /* NOTREACHED */ } if (ChildPid == 0) { const char *a; /* action name (for error message) */ (void) setsighandler(SIGINT, SIG_DFL); # ifdef SIGINT_UNBLOCK SIGINT_UNBLOCK(); # endif if (!((a = "close 0", close(0)) == 0 && (a = "open", open(InFName==NULL? "/dev/null" : InFName, O_RDONLY | O_BINARY)) == 0 && (a = "close 1", close(1)) == 0 && (a = "dup 1", dup(p[1])) == 1 && (a = "close 2", close(2)) == 0 && (a = "dup 2", dup(p[1])) == 2)) { raw_complain("% in setup for child failed: %s", a, strerror(errno)); _exit(1); } pipeclose(p); jcloseall(); execve(argv[0], &argv[1], (char **) jenvdata(&proc_env)); raw_complain("Execl failed: %s", strerror(errno)); _exit(1); } # ifdef SIGINT_BLOCK old_int = setsighandler(SIGINT, SIG_IGN); /* got to do this eventually */ # endif (void) close(p[1]); fp = fd_open(argv[1], F_READ, p[0], iobuff, LBSIZE); #else /* MSDOS_PROCS*/ { int oldi = dup(0), oldo = dup(1), olde = dup(2); jbool InFailure = NO; int ph, pinh, saverrno = 0; const char *op = ""; PathCat(pipename, sizeof(pipename), TmpDir, "jpXXXXXX"); ph = MakeTemp(pipename, "filter buffer"); jdbg("created temp \"%s\" ph %d\n", pipename, ph); if (InFName == NULL) { char nullname[FILESIZE]; PathCat(nullname, sizeof(nullname), TmpDir, "jnXXXXXX"); pinh = MakeTemp(nullname, "filter null file"); (void) unlink(nullname); } else { pinh = open(InFName, O_RDONLY | O_BINARY); if (pinh < 0) { saverrno = errno; op = InFName; jdbg("error opening \"%s\": %d %s\n", InFName, errno); InFailure = YES; } } if (!InFailure && (dup2(ph, 1) < 0 || dup2(ph, 2) < 0)) { saverrno = errno; op = "dup2 temp"; jdbg("%s file fd failed: %d %s\n", op, errno, strerror(errno)); InFailure = YES; } (void) close(ph); if (!InFailure && dup2(pinh, 0) < 0) { saverrno = errno; op = "dup2 input"; jdbg("%s file fd failed: %d %s\n", op, errno, strerror(errno)); InFailure = YES; } (void) close(pinh); jdbg("InFailure %d InFName \"%s\"\n", InFailure, InFName == NULL ? "(NULL)" : InFName); if (!InFailure) { if (jdebug) { int vk = 0; while (argv[vk]) { jdprintf("%d: \"%s\"\n", vk, argv[vk]); vk++; } } status = spawnve(0, argv[0], &argv[1], (char *const *)jenvdata(&proc_env)); if (status < 0) { saverrno = errno; } } jdbg("restoring fds 0 1 2 from %d %d %d\n", oldi, oldo, olde); (void) dup2(oldi, 0); (void) dup2(oldo, 1); (void) dup2(olde, 2); (void) close(oldi); (void) close(oldo); (void) close(olde); if (InFailure) { complain("[filter %s failed %s %d]", op, strerror(saverrno), saverrno); /* NOTREACHED */ } if (status < 0) s_mess("[Spawn failed, status %d: %s %d]", status, strerror(saverrno), saverrno); jdbg("opening \"%s\" from \"%s\"\n", pipename, argv[1]); ph = open(pipename, O_RDONLY | O_BINARY | O_CLOEXEC); if (ph < 0) { complain("[cannot reopen pipe %s: %s]", pipename, strerror(errno)); /* NOTREACHED */ } fp = fd_open(argv[1], F_READ, ph, iobuff, LBSIZE); } #endif /* MSDOS_PROCS */ do { int wrap_col = WrapProcessLines ? CO-1 : LBSIZE; #ifdef UNIX InSlowRead = YES; #endif eof = f_gets(fp, genbuf, (size_t)LBSIZE); #ifdef UNIX InSlowRead = NO; #endif if (bnm != NULL) { ins_str_wrap(genbuf, YES, wrap_col); if (!eof) LineInsert(1); if ((flags & UTB_DISP) && fp->f_cnt <= 0) { message("Chugging along..."); redisplay(); } } else if (flags & UTB_DISP) Typeout("%s", genbuf); } while (!eof); if (flags & UTB_DISP) DrawMesg(NO); close_file(fp); #ifndef MSDOS_PROCS dowait(&status); # ifdef SIGINT_UNBLOCK SIGINT_UNBLOCK(); # endif (void) setsighandler(SIGINT, old_int); #else /* MSDOS_PROCS */ unlink(pipename); getCWD(); jdbg("removing %s\n", pipename); # ifdef WINRESIZE ResizePending = YES; /* In case subproc did a MODE command or something */ # endif #endif /* MSDOS_PROCS */ SlowCmd -= 1;; jdbg("returning %d\n", status); return status; } /* Send the current region to CMD and insert the output from the * command into OUT_BUF. */ private void RegToUnix(outbuf, cmd, wrap) Buffer *outbuf; char *cmd; jbool wrap; { Mark *m = CurMark(); static char tname[FILESIZE]; Window *save_wind = curwind; volatile wait_status_t status; volatile jbool err = NO; jbool old_wrap = WrapProcessLines; File *volatile fp; jmp_buf sav_jmp; PathCat(tname, sizeof(tname), TmpDir, "jfXXXXXX"); /* safe version of mktemp */ close(MakeTemp(tname, "filter region")); fp = open_file(tname, iobuff, F_WRITE, YES); push_env(sav_jmp); if (setjmp(mainjmp) == 0) { WrapProcessLines = wrap; putreg(fp, m->m_line, m->m_char, curline, curchar, YES); DelReg(); f_close(fp); status = UnixToBuf(UTB_SH|UTB_FILEARG, outbuf->b_name, tname, cmd); } else { f_close(fp); err = YES; } pop_env(sav_jmp); WrapProcessLines = old_wrap; (void) unlink(tname); SetWind(save_wind); if (!err) com_finish(status, cmd); } void FilterRegion() { static char FltComBuf[LBSIZE]; jamstr(FltComBuf, ask(FltComBuf, ": %f (through command) ")); RegToUnix(curbuf, FltComBuf, NO); this_cmd = UNDOABLECMD; } void isprocbuf(bnm) const char *bnm; { Buffer *bp; if ((bp = buf_exists(bnm)) != NULL && bp->b_type != B_PROCESS) confirm("Over-write buffer %s? ", bnm); } #endif /* SUBSHELL */ jove-4.17.5.5/proc.h000066400000000000000000000044321501102521500140250ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* note: sysprocs.h must be included first */ extern char ShcomBuf[LBSIZE]; extern char *MakeName proto((char *command)); extern void isprocbuf proto((const char *bufname)), get_FL_info proto((char *, char *)), ChkErrorLines proto((void)), ErrFree proto((void)); extern wait_status_t UnixToBuf proto((int, const char *, const char *, const char *)); /* flags for UnixToBuf: */ #define UTB_DISP 1 /* Display output? */ #define UTB_CLOBBER 2 /* (if UTB_DISP) clear buffer at start? */ #define UTB_ERRWIN 4 /* (if UTB_DISP) make window size error-window-size? */ #define UTB_SH 8 /* shell command? */ #define UTB_FILEARG 16 /* pass curbuf->b_fname as $0? */ #ifndef MSDOS_PROCS extern pid_t ChildPid; /* pid of any outstanding non-iproc process */ extern void dowait proto((wait_status_t *status)); #endif /* Commands: */ #ifdef SUBSHELL extern void MakeErrors proto((void)), FilterRegion proto((void)), ShNoBuf proto((void)), ShToBuf proto((void)), ShellCom proto((void)), Shtypeout proto((void)), ProcEnvExport proto((void)), ProcEnvShow proto((void)), ProcEnvUnset proto((void)); #endif /* * Even if we don't have MakeErrors, the following are useful because we can * load an error file and parse it with these. */ extern void ErrParse proto((void)), ShowErr proto((void)), NextError proto((void)), PrevError proto((void)); #ifdef SPELL extern void SpelBuffer proto((void)), SpelWords proto((void)); #endif /* Variables: */ extern int EWSize; /* VAR: percentage of screen to make the error window */ extern char ErrFmtStr[256]; /* VAR: format string for parse errors */ #ifdef SUBSHELL extern jbool WtOnMk; /* VAR: write files on compile-it command */ extern jbool WrapProcessLines; /* VAR: wrap process lines at CO-1 chars */ #endif #ifdef SPELL extern char SpellCmdFmt[FILESIZE]; /* VAR: command to use for spell check */ #endif jove-4.17.5.5/re.c000066400000000000000000000511331501102521500134630ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* search package */ #include "jove.h" #include "re.h" #include "jctype.h" #include "ask.h" #include "disp.h" #include "fmt.h" #include "marks.h" private jbool do_comp proto((struct RE_block *,int)); char rep_search[128], /* replace search string */ rep_str[128]; /* contains replacement string */ jbool CaseIgnore = NO, /* VAR: ignore case in search */ WrapScan = NO; /* VAR: make searches wrap */ private ZXchar REpeekc; private const char *REptr; private ZXchar REgetc() { ZXchar c; if ((c = REpeekc) != EOF) REpeekc = EOF; else if (*REptr != '\0') c = ZXC(*REptr++); else c = EOF; return c; } #define STAR 01 /* Match any number of last RE (ORed into other ops). */ #define AT_BOL 2 /* ^ */ #define AT_EOL 4 /* $ */ #define AT_BOW 6 /* \< */ #define AT_EOW 8 /* \> */ #define OPENP 10 /* \( {chunk number} */ #define CLOSEP 12 /* \) {chunk number} */ #define CURLYB 14 /* \{ {number of alt, alts } */ #define NOSTR 14 /* Codes <= NOSTR can't be *'d. */ #define ANYC (NOSTR+2) /* . */ #define NORMC (ANYC+2) /* normal chars {len, char...} */ #define CINDC (NORMC+2) /* case independent chars {len, char...} */ #define ONE_OF (CINDC+2) /* [xxx] {bitmask} */ #define NONE_OF (ONE_OF+2) /* [^xxx] {bitmask} */ #define BACKREF (NONE_OF+2) /* \# {chunk number} */ #define EOP (BACKREF+2) /* end of pattern */ #define CHAR_MASK ((1 << CHAR_BIT) - 1) /* byte mask, really */ #define ALT_LEN_LEN 2 /* an alt starts with a two-byte length */ #define ALT_LEN(p) (((p)[0] & CHAR_MASK) + (((p)[1] & CHAR_MASK) << CHAR_BIT)) /* ONE_OF/NONE_OF is represented as a bit vector. * These symbols parameterize the representation. */ #define SETSIZE (NCHARS / CHAR_BIT) #define SETBYTE(c) ((c) / CHAR_BIT) #define SETBIT(c) (1 << ((c) % CHAR_BIT)) #define NPAR 10 /* [0-9] - 0th is the entire matched string, i.e. & */ private char *comp_ptr, **alt_p, **alt_endp; void REcompile(pattern, re, re_blk) const char *pattern; jbool re; struct RE_block *re_blk; { REptr = pattern; REpeekc = EOF; comp_ptr = re_blk->r_compbuf; alt_p = re_blk->r_alternates; alt_endp = alt_p + NALTS - 1; *alt_p++ = comp_ptr; re_blk->r_nparens = 0; (void) do_comp(re_blk, re ? OKAY_RE : NORM); *alt_p = NULL; re_blk->r_anchored = NO; re_blk->r_firstc = EOF; /* do a little post processing */ if (re_blk->r_alternates[1] == NULL) { char *p; p = re_blk->r_alternates[0]; for (;;) { switch (*p) { case OPENP: case CLOSEP: p += 2; continue; case AT_BOW: case AT_EOW: p += 1; continue; case AT_BOL: re_blk->r_anchored = YES; /* don't set firstc -- won't work */ break; case NORMC: case CINDC: re_blk->r_firstc = CharUpcase(p[2]); break; default: break; } break; } } } /* compile the pattern into an internal code */ private jbool do_comp(re_blk, kind) struct RE_block *re_blk; int kind; { char *this_verb, *prev_verb, *start_p, *comp_endp; int parens[NPAR], *parenp, outer_max_paren = -1; ZXchar c; jbool done_cb = NO; parenp = parens; this_verb = NULL; comp_endp = &re_blk->r_compbuf[COMPSIZE - 6]; /* wrap the whole expression around (implied) parens */ if (kind != IN_CB) { if (re_blk->r_nparens >= NPAR) { complain("Too many ('s; max is %d.", NPAR); /* NOTREACHED */ } *comp_ptr++ = OPENP; *parenp++ = *comp_ptr++ = re_blk->r_nparens++; } start_p = comp_ptr; while ((c = REgetc()) != EOF) { if (comp_ptr > comp_endp) { toolong: complain("Search string too long/complex."); /* NOTREACHED */ } prev_verb = this_verb; this_verb = comp_ptr; /* The following test ought to be * kind == NORM && c != '\\' * but Jon likes to put ^, $, and \ in i-searches. * Don't tell him, but $ only sort of works. -- DHR */ if (kind == NORM && strchr("^$\\", c) == NULL) goto defchar; switch (c) { case '\\': switch (c = REgetc()) { case EOF: complain("[Premature end of pattern]"); /*NOTREACHED*/ case '{': { char *altcntp; /* alternate count */ int init_paren = re_blk->r_nparens, max_paren = -1; *comp_ptr++ = CURLYB; altcntp = comp_ptr; *comp_ptr++ = 0; /* initialize alt-count */ for (;;) { char *comp_len = comp_ptr; jbool done; long len; comp_ptr += ALT_LEN_LEN; re_blk->r_nparens = init_paren; done = do_comp(re_blk, IN_CB); /* We demand that each alternate has the same number * of parens because we currently have no mechanism to * set the matching strings to a meaningful default. */ if (max_paren == -1) max_paren = re_blk->r_nparens; if (max_paren != re_blk->r_nparens) { complain("[each alternate must have the same number of \\( \\)]"); /* NOTREACHED */ } len = comp_ptr - comp_len; comp_len[0] = (char) len; /* truncate */ comp_len[1] = (char) (len >> CHAR_BIT); /* truncate */ (*altcntp) += 1; if (done) break; } break; } case '}': if (kind != IN_CB) { complain("Unexpected \\}."); /* NOTREACHED */ } done_cb = YES; goto outahere; case '(': if (re_blk->r_nparens >= NPAR) { complain("Too many ('s; max is %d.", NPAR); /* NOTREACHED */ } *comp_ptr++ = OPENP; *parenp++ = *comp_ptr++ = re_blk->r_nparens++; break; case ')': if (parenp == parens) { complain("Too many )'s."); /* NOTREACHED */ } *comp_ptr++ = CLOSEP; *comp_ptr++ = *--parenp; break; case '|': if (kind == IN_CB) goto outahere; if (alt_p >= alt_endp) { complain("Too many alternates; max %d.", NALTS); /* NOTREACHED */ } /* close off previous alternate */ *comp_ptr++ = CLOSEP; *comp_ptr++ = *--parenp; if (parenp != parens) { complain("Unmatched \\(."); /* NOTREACHED */ } *comp_ptr++ = EOP; /* We demand that each alternate has the same number * of parens because we currently have no mechanism to * set the matching strings to a meaningful default. */ if (outer_max_paren == -1) outer_max_paren = re_blk->r_nparens; if (outer_max_paren != re_blk->r_nparens) { complain("[each alternate must have the same number of \\( \\)]"); /* NOTREACHED */ } /* start a new alt */ *alt_p++ = comp_ptr; re_blk->r_nparens = 0; *comp_ptr++ = OPENP; *parenp++ = *comp_ptr++ = re_blk->r_nparens++; start_p = comp_ptr; break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': *comp_ptr++ = BACKREF; *comp_ptr++ = c - '0'; break; case '<': *comp_ptr++ = AT_BOW; break; case '>': *comp_ptr++ = AT_EOW; break; default: goto defchar; } break; case '.': *comp_ptr++ = ANYC; break; case '^': if (comp_ptr == start_p) { *comp_ptr++ = AT_BOL; break; } goto defchar; case '$': if ((REpeekc = REgetc()) != EOF && REpeekc != '\\') goto defchar; *comp_ptr++ = AT_EOL; break; case '[': *comp_ptr++ = ONE_OF; if (comp_ptr + SETSIZE >= comp_endp) goto toolong; byte_zero(comp_ptr, (size_t) SETSIZE); c = REgetc(); if (c == '^') { *this_verb = NONE_OF; c = REgetc(); } do { if (c == EOF) break; if (c == '\\') { c = REgetc(); if (c == EOF) break; } if ((REpeekc = REgetc()) == '-') { /* possibly a range */ ZXchar i = c; REpeekc = EOF; /* discard '-' */ c = REgetc(); if (c == EOF) break; if (c == ']') { /* not a range after all */ REpeekc = c; /* push back ']' */ c = '-'; /* recycle '-' */ comp_ptr[SETBYTE(i)] |= SETBIT(i); /* handle initial char */ } else { /* really a range: add members up to c */ if (c == '\\') { c = REgetc(); if (c == EOF) break; } while (i < c) { comp_ptr[SETBYTE(i)] |= SETBIT(i); i += 1; } } } comp_ptr[SETBYTE(c)] |= SETBIT(c); c = REgetc(); } while (c != ']'); if (c == EOF) { complain("Missing ]."); /* NOTREACHED */ } comp_ptr += SETSIZE; break; case '*': if (prev_verb == NULL || *prev_verb <= NOSTR || (*prev_verb&STAR)!=0) goto defchar; if (*prev_verb == NORMC || *prev_verb == CINDC) { char lastc = comp_ptr[-1]; /* The * operator applies only to the * previous character. Since we were * building a string-matching command * (NORMC or CINDC), we must split it * up and work with the last character. * * Note that the STARed versions of these * commands do not operate on strings, and * so do not need or have character counts. */ if (prev_verb[1] == 1) { /* Only one char in string: * delete old command. */ this_verb = prev_verb; } else { /* Several chars in string: * strip off the last. * New verb is derived from old. */ prev_verb[1] -= 1; this_verb -= 1; *this_verb = *prev_verb; } comp_ptr = this_verb + 1; *comp_ptr++ = lastc; } else { /* This command is just the previous one, * whose verb we will modify. */ this_verb = prev_verb; } *this_verb |= STAR; break; default: defchar: if (prev_verb == NULL || !(*prev_verb == NORMC || *prev_verb == CINDC)) { /* create new string command */ *comp_ptr++ = (CaseIgnore) ? CINDC : NORMC; *comp_ptr++ = 0; } else { /* merge this into previous string command */ this_verb = prev_verb; } this_verb[1] += 1; *comp_ptr++ = c; break; } } outahere: /* End of pattern, let's do some error checking. */ if (kind != IN_CB) { *comp_ptr++ = CLOSEP; *comp_ptr++ = *--parenp; } if (parenp != parens) { complain("Unmatched \\(."); /* NOTREACHED */ } if (kind == IN_CB && c == EOF) { /* end of pattern with missing \}. */ complain("Missing \\}."); /* NOTREACHED */ } *comp_ptr++ = EOP; /* We demand that each alternate has the same number * of parens because we currently have no mechanism to * set the matching strings to a meaningful default. */ if (outer_max_paren != -1 && outer_max_paren != re_blk->r_nparens) { complain("[each alternate must have the same number of \\( \\)]"); /* NOTREACHED */ } return done_cb; } private char *pstrtlst[NPAR], /* index into re_blk->r_lbuf */ *pendlst[NPAR], *REbolp, /* begining-of-line pointer */ *locrater, /* roof of last substitution */ *loc1, /* start of matched text */ *loc2; /* roof of matched text */ int REbom, /* beginning and end columns of match */ REeom, REdelta; /* increase in line length due to last re_dosub */ private jbool backref(n, linep) int n; register char *linep; { register char *backsp, *backep; backsp = pstrtlst[n]; backep = pendlst[n]; while (*backsp++ == *linep++) if (backsp >= backep) return YES; return NO; } private jbool member(comp_ptr, c, af) register char *comp_ptr; register ZXchar c; jbool af; { return c != '\0' && ((comp_ptr[SETBYTE(c)] & SETBIT(c))? af : !af); } private jbool REmatch(linep, comp_ptr) register char *linep, *comp_ptr; { char *first_p; register int n; for (;;) switch (*comp_ptr++) { case NORMC: n = *comp_ptr++; while (--n >= 0) if (*linep++ != *comp_ptr++) return NO; continue; case CINDC: /* case independent comparison */ n = *comp_ptr++; while (--n >= 0) if (!cind_eq(*linep++, *comp_ptr++)) return NO; continue; case EOP: loc2 = linep; REeom = (loc2 - REbolp); return YES; /* Success! */ case AT_BOL: if (linep == REbolp && linep != locrater) continue; return NO; case AT_EOL: if (*linep == '\0') continue; return NO; case ANYC: if (*linep++ != '\0') continue; return NO; case AT_BOW: if (linep != locrater && jisident(*linep) && (linep == REbolp || !jisident(linep[-1]))) continue; return NO; case AT_EOW: if (linep != locrater && (*linep == '\0' || !jisident(*linep)) && (linep != REbolp && jisident(linep[-1]))) continue; return NO; case ONE_OF: case NONE_OF: if (member(comp_ptr, ZXC(*linep++), comp_ptr[-1] == ONE_OF)) { comp_ptr += SETSIZE; continue; } return NO; case OPENP: pstrtlst[(int) *comp_ptr++] = linep; continue; case CLOSEP: pendlst[(int) *comp_ptr++] = linep; continue; case BACKREF: if (pstrtlst[n = *comp_ptr++] == NULL) { s_mess("\\%d was not specified.", n + 1); } else if (backref(n, linep)) { linep += pendlst[n] - pstrtlst[n]; continue; } return NO; case CURLYB: { int altcnt = *comp_ptr++; jbool any = NO; while (--altcnt >= 0) { if (!any) any = REmatch(linep, comp_ptr + ALT_LEN_LEN); comp_ptr += ALT_LEN(comp_ptr); } if (!any) return NO; linep = loc2; continue; } case ANYC | STAR: first_p = linep; do {} while (*linep++ != '\0'); goto star; case NORMC | STAR: first_p = linep; do {} while (*comp_ptr == *linep++); comp_ptr += 1; goto star; case CINDC | STAR: first_p = linep; do {} while (cind_eq(*comp_ptr, *linep++)); comp_ptr += 1; goto star; case ONE_OF | STAR: case NONE_OF | STAR: first_p = linep; do {} while (member(comp_ptr, ZXC(*linep++), comp_ptr[-1] == (ONE_OF | STAR))); comp_ptr += SETSIZE; /* fall through */ star: /* linep points *after* first unmatched char. * first_p points at where starred element started matching. */ while (--linep > first_p) { if ((*comp_ptr != NORMC || *linep == comp_ptr[2]) && REmatch(linep, comp_ptr)) return YES; } continue; case BACKREF | STAR: first_p = linep; n = *comp_ptr++; while (backref(n, linep)) linep += pendlst[n] - pstrtlst[n]; while (linep > first_p) { if (REmatch(linep, comp_ptr)) return YES; linep -= pendlst[n] - pstrtlst[n]; } continue; default: complain("RE error match (%d).", comp_ptr[-1]); /* NOTREACHED */ } /* NOTREACHED */ } private void REreset() { register int i; for (i = 0; i < NPAR; i++) pstrtlst[i] = pendlst[i] = NULL; } /* Index LINE at OFFSET. If lbuf_okay is YES it's okay to use linebuf * if LINE is the current line. This should save lots of time in things * like paren matching in LISP mode. Saves all that copying from linebuf * to a local buffer. substitute() is the guy who calls re_lindex with * lbuf_okay as NO, since the substitution gets placed in linebuf ... * doesn't work too well when the source and destination strings are the * same. I hate all these arguments! * * This code is cumbersome, repetetive for reasons of efficiency. Fast * search is a must as far as I am concerned. */ jbool re_lindex(line, offset, dir, re_blk, lbuf_okay, crater) LinePtr line; int offset; int dir; struct RE_block *re_blk; jbool lbuf_okay; int crater; /* offset of previous substitute (or -1) */ { register char *p; register ZXchar firstc = re_blk->r_firstc; register jbool anchored = re_blk->r_anchored; char **alts = re_blk->r_alternates; REreset(); if (lbuf_okay) { REbolp = lbptr(line); if (offset == -1) offset = strlen(REbolp); /* arg! */ } else { REbolp = ltobuf(line, re_blk->r_lbuf); if (offset == -1) { /* Reverse search, find end of line. */ offset = Jr_Len; /* Just Read Len. */ } } if (anchored) { if (dir == FORWARD) { if (offset != 0 || crater != -1) return NO; } else { offset = 0; } } p = REbolp + offset; locrater = REbolp + crater; if (firstc != EOF) { char *first_alt = *alts; if (dir == FORWARD) { while (CharUpcase(*p) != firstc || !REmatch(p, first_alt)) if (*p++ == '\0') return NO; } else { while (CharUpcase(*p) != firstc || !REmatch(p, first_alt)) if (--p < REbolp) return NO; } } else { for (;;) { register char **altp = alts; while (*altp != NULL) if (REmatch(p, *altp++)) goto success; if (anchored || (dir == FORWARD ? *p++ == '\0' : --p < REbolp)) return NO; } success:; } loc1 = p; REbom = loc1 - REbolp; return YES; } jbool okay_wrap = NO; /* Do a wrap search ... not when we're parsing errors ... */ Bufpos * dosearch(pattern, dir, re) const char *pattern; int dir; jbool re; { Bufpos *pos; struct RE_block re_blk; /* global re-compiled buffer */ if (bobp() && eobp()) /* Can't match! There's no buffer. */ return NULL; REcompile(pattern, re, &re_blk); pos = docompiled(dir, &re_blk); return pos; } Bufpos * docompiled(dir, re_blk) int dir; register struct RE_block *re_blk; { static Bufpos ret; register LinePtr lp; register int offset; jbool we_wrapped = NO; lsave(); /* Search now lsave()'s so it doesn't make any assumptions on * whether the the contents of curline/curchar are in linebuf. * Nowhere does search write all over linebuf. However, we have to * be careful about what calls we make here, because many of them * assume (and rightly so) that curline is in linebuf. */ lp = curline; offset = curchar; if (dir == BACKWARD) { if (bobp()) { if (okay_wrap && WrapScan) goto doit; return NULL; } /* here we simulate BackChar() */ if (bolp()) { lp = lp->l_prev; offset = length(lp); } else { offset -= 1; } } else if (dir==FORWARD && lbptr(lp)[offset]=='\0' && !lastp(lp)) { lp = lp->l_next; offset = 0; } do { if (re_lindex(lp, offset, dir, re_blk, YES, -1)) break; doit: lp = (dir == FORWARD) ? lp->l_next : lp->l_prev; if (lp == NULL) { if (okay_wrap && WrapScan) { lp = (dir == FORWARD) ? curbuf->b_first : curbuf->b_last; we_wrapped = YES; } else break; } if (dir == FORWARD) offset = 0; else offset = -1; /* signals re_lindex ... */ } while (lp != curline); if (lp == curline && we_wrapped) lp = NULL; if (lp == NULL) return NULL; ret.p_line = lp; ret.p_char = (dir == FORWARD) ? REeom : REbom; return &ret; } private char * insert(off, endp, which) char *off, *endp; int which; { register char *pp = pstrtlst[which]; register int n; if (pp == NULL) { complain("\\%d not defined", which); /* NOTREACHED */ } n = pendlst[which] - pp; /* note: ensure space will be left for a NUL */ if (off + n >= endp) { len_error(JMP_ERROR); /* NOTREACHED */ } while (--n >= 0) *off++ = *pp++; return off; } /* Perform the substitution. If DELP is YES the matched string is * deleted, i.e., the substitution string is not inserted. */ void re_dosub(re_blk, tobuf, delp) struct RE_block *re_blk; char *tobuf; jbool delp; { register char *tp, *rp; char *endp; tp = tobuf; endp = tp + LBSIZE; rp = re_blk->r_lbuf; while (rp < loc1) *tp++ = *rp++; if (!delp) { register char c; rp = rep_str; while ((c = *rp++) != '\0') { if (c == '\\') { c = *rp++; if (c >= '0' && c < re_blk->r_nparens + '0') { tp = insert(tp, endp, c - '0'); continue; } if (c == '\0') { /* treat \ at the end as if it were \\ */ c = '\\'; rp--; /* be sure to hit again */ } } *tp++ = c; if (tp >= endp) { len_error(JMP_ERROR); /* NOTREACHED */ } } } rp = loc2; REdelta = -REeom; REeom = tp - tobuf; REdelta += REeom; if (loc1==rp && *rp!='\0') { /* Skip an extra character if the matched text was a null * string, but don't skip over the end of line. This is to * prevent an infinite number of replacements in the same * position, e.g., replace "^" with "". */ REeom += 1; } loc2 = re_blk->r_lbuf + REeom; while ((*tp++ = *rp++) != '\0') { if (tp >= endp) { len_error(JMP_ERROR); /* NOTREACHED */ } } } void putmatch(which, buf, size) int which; char *buf; size_t size; { *(insert(buf, buf + size, which)) = '\0'; } void RErecur() { char repbuf[sizeof rep_str]; Mark *m = MakeMark(curline, REbom); message("Type ^X ^C to continue with query replace."); byte_copy(rep_str, repbuf, sizeof rep_str); Recur(); byte_copy(repbuf, rep_str, sizeof rep_str); if (!is_an_arg()) ToMark(m); DelMark(m); } /* Do we match PATTERN at OFFSET in BUF? */ jbool LookingAt(pattern, buf, offset) const char *pattern; char *buf; int offset; { struct RE_block re_blk; char **alt = re_blk.r_alternates; REcompile(pattern, YES, &re_blk); REreset(); locrater = NULL; REbolp = buf; while (*alt) if (REmatch(buf + offset, *alt++)) return YES; return NO; } jbool look_at(expr) char *expr; { struct RE_block re_blk; REcompile(expr, NO, &re_blk); REreset(); locrater = NULL; REbolp = linebuf; return REmatch(linebuf + curchar, re_blk.r_alternates[0]); } jove-4.17.5.5/re.h000066400000000000000000000035701501102521500134720ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #define NALTS 16 /* number of alternate search strings */ #define COMPSIZE 512 /* kinds of regular expression compiles */ #define NORM 0 /* nothing special */ #define OKAY_RE 1 /* allow regular expressions */ #define IN_CB 2 /* in curly brace; implies OKAY_RE */ struct RE_block { char r_compbuf[COMPSIZE], *r_alternates[NALTS], r_lbuf[LBSIZE]; int r_nparens; ZXchar r_firstc; jbool r_anchored; }; extern char rep_search[128], /* replace search string */ rep_str[128]; /* contains replacement string */ extern int REbom, /* beginning and end columns of match */ REeom, REdelta; /* increase in line length due to last re_dosub */ extern jbool okay_wrap; /* Do a wrap search ... not when we're parsing errors ... */ extern jbool re_lindex proto((LinePtr line, int offset, int dir, struct RE_block *re_blk, jbool lbuf_okay, int crater)), LookingAt proto((const char *pattern,char *buf,int offset)), look_at proto((char *expr)); extern Bufpos *docompiled proto((int dir, struct RE_block *re_blk)), *dosearch proto((const char *pattern, int dir, jbool re)); extern void REcompile proto((const char *pattern, jbool re, struct RE_block *re_blk)), putmatch proto((int which, char *buf,size_t size)), re_dosub proto((struct RE_block *re_blk, char *tobuf, jbool delp)), RErecur proto((void)); /* Variables: */ extern jbool CaseIgnore, /* VAR: ignore case in search */ WrapScan; /* VAR: make searches wrap */ jove-4.17.5.5/reapp.c000066400000000000000000000373621501102521500141740ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* regular expression applications: search, replace, and tags */ #include "jove.h" #include "fp.h" #include "re.h" #include "jctype.h" #include "chars.h" #include "disp.h" #include "ask.h" #include "extend.h" /* for chr_to_* */ #include "fmt.h" #include "marks.h" #include "reapp.h" #include "wind.h" #ifdef MAC # include "mac.h" #else # include #endif private void IncSearch proto((int)); private int isearch proto((int, Bufpos *)); private char searchstr[128]; /* global search string */ jbool UseRE = NO; /* VAR: use regular expressions in search */ private void setsearch(str) const char *str; { jamstr(searchstr, str); } private char * getsearch() { return searchstr; } private void search(dir, re, setdefault) int dir; jbool re, setdefault; { Bufpos *newdot; const char *s = ask(searchstr, ProcFmt); if (setdefault) setsearch(s); okay_wrap = YES; newdot = dosearch(s, dir, re); okay_wrap = NO; if (newdot == NULL) { if (WrapScan) { complain("No \"%s\" in buffer.", s); /* NOTREACHED */ } else { complain("No \"%s\" found to %s.", s, (dir == FORWARD) ? "bottom" : "top"); /* NOTREACHED */ } } PushPntp(newdot->p_line); SetDot(newdot); } void ForSearch() { search(FORWARD, UseRE, YES); } void RevSearch() { search(BACKWARD, UseRE, YES); } void FSrchND() { search(FORWARD, UseRE, NO); } void RSrchND() { search(BACKWARD, UseRE, NO); } private int substitute(re_blk, query, l1, char1, l2, char2) struct RE_block *re_blk; LinePtr l1, l2; jbool query; int char1, char2; { LinePtr lp; int numdone = 0, UNDO_nd = 0, offset = char1; jbool stop = NO; daddr UNDO_da = NULL_DADDR; LinePtr UNDO_lp = NULL; lsave(); for (lp = l1; lp != l2->l_next; lp = lp->l_next) { int crater = -1; /* end of last substitution on this line */ jbool LineDone = NO; /* already replaced last empty string on line? */ while (!LineDone && re_lindex(lp, offset, FORWARD, re_blk, NO, crater) && (lp != l2 || REeom <= char2)) { DotTo(lp, REeom); offset = curchar; if (query) { ZXchar c; message("Replace (Type '?' for help)? "); reswitch: redisplay(); c = kbd_getch(); if (c == AbortChar) return numdone; switch (CharUpcase(c)) { case '.': stop = YES; /*FALLTHROUGH*/ case ' ': case 'Y': break; case BS: case DEL: case 'N': if (REbom == REeom) { offset += 1; if (linebuf[REeom] == '\0') LineDone = YES; } continue; case CTL('W'): re_dosub(re_blk, linebuf, YES); if (lp == l2) char2 += REdelta; modify(); numdone += 1; curchar = REbom; makedirty(curline); /*FALLTHROUGH*/ case CTL('R'): case 'R': RErecur(); UNDO_lp = NULL; /* can't reliably undo this */ offset = curchar; lp = curline; continue; case CTL('U'): case 'U': if (UNDO_lp == NULL) { rbell(); goto reswitch; } lp = UNDO_lp; lp->l_dline = UNDO_da; if (UNDO_lp == curline) getDOT(); /* downdate line cache */ makedirty(lp); offset = 0; numdone = UNDO_nd; UNDO_lp = NULL; continue; case 'P': case '!': query = NO; break; case CR: case LF: case 'Q': return numdone; case CTL('L'): RedrawDisplay(); goto reswitch; default: rbell(); message("Space or Y, Period, Delete or N, ^R or R, ^W, ^U or U, P or !, Return."); goto reswitch; } } if (UNDO_lp != curline) { UNDO_da = curline->l_dline; UNDO_lp = curline; UNDO_nd = numdone; } if (REbom == REeom && linebuf[REeom] == '\0') LineDone = YES; re_dosub(re_blk, linebuf, NO); if (lp == l2) char2 += REdelta; numdone += 1; modify(); crater = offset = curchar = REeom; makedirty(curline); if (query) { message(mesgbuf); /* no blinking */ redisplay(); /* show the change */ } if (stop) return numdone; } offset = 0; } return numdone; } /* prompt for search and replacement strings and do the substitution */ private void replace(query, inreg) jbool query, inreg; { LinePtr l1 = curline, l2 = curbuf->b_last; int char1 = curchar, char2 = length(curbuf->b_last), numdone; struct RE_block re_blk; if (inreg) { Mark *m = CurMark(); l2 = m->m_line; char2 = m->m_char; (void) fixorder(&l1, &char1, &l2, &char2); } /* get search string */ jamstr(rep_search, ask(rep_search[0] ? rep_search : (char *)NULL, ProcFmt)); REcompile(rep_search, UseRE, &re_blk); /* Now the replacement string. Do_ask() so the user can play with * the default (previous) replacement string by typing ^R in ask(), * OR, can just hit Return to replace with nothing. */ { const char *rp = do_ask("\r\n", NULL_ASK_EXT, rep_str, ": %f %s with ", rep_search); jamstr(rep_str, rp == NULL? NullStr : rp); } if ((numdone = substitute(&re_blk, query, l1, char1, l2, char2)) != 0 && !inreg) { do_set_mark(l1, char1); add_mess(" "); /* just making things pretty */ } else { message(NullStr); } add_mess("(%d substitution%n)", numdone, numdone); } void RegReplace() { replace(NO, YES); } void QRepSearch() { replace(YES, NO); } void RepSearch() { replace(NO, NO); } /* Lookup a tag in tag file FILE. FILE is assumed to be sorted * alphabetically. The FASTTAGS code, which is implemented with * a binary search, depends on this assumption. If it's not true * it is possible to comment out the fast tag code (which is clearly * labeled), delete the marked test in the sequential loop, and * everything else will just work. */ private jbool lookup_tag(ispat, searchbuf, sbsize, filebuf, tag, file) jbool *ispat; char *searchbuf; size_t sbsize; char *filebuf, *tag, *file; { register size_t taglen = strlen(tag); char line[JBUFSIZ], pattern[200]; register File *fp; struct stat stbuf; jbool success = NO; fp = open_file(file, iobuff, F_READ, NO); if (fp == NULL) { message(IOerr("open", file)); return NO; } /* Build a pattern to parse the tag line. * * - the tag name is at the start of the line. * Since our name may only be a prefix, ignore * the rest of the tab-terminated field. * ^%s[^\t]*\t * * - a file name, terminated by a tab. * Use parens to capture the field as \1: * \\([^\t]*\\)\t * * - EITHER: a pattern to match for the * start of the object within the source file. * Capture the delimiter as \2 and the pattern as \3. * \\([?/]\\)\\(.*\\)\\2 * OR: a line number. * Capture the lack-of-delimiter in \2 and the number in \3. * \\(\\)\\([0-9]*\\) * * - possible gunge in the form of an ex(1) comment: * \\{;".*\\|\\} * * - the end * $ * * Some tag lines collected in the wild: * AddError proc.c /^AddError(laste, errline, buf, line, charpos)$/ * AddError proc.c /^AddError(laste, errline, buf, line, charpos)$/;" f * AT_BOL re.c 49;" d file: */ swritef(pattern, sizeof(pattern), /*tag name *======== file name * ============ pattern * ===================== line number * ================= gunge * ============= */ "^%s[^\t]*\t\\([^\t]*\\)\t\\{\\([?/]\\)\\(.*\\)\\2\\|\\(\\)\\([0-9]*\\)\\}\\{;\".*\\|\\}$", tag); /* ********BEGIN FAST TAG CODE******** */ /* Mac doesn't have fstat */ #ifdef MAC if (stat(file, &stbuf) >= 0) #else if (fstat(fp->f_fd, &stbuf) >= 0) #endif { /* Invariant: if there is a line matching the tag, it * begins somewhere after position lower, and begins * at or before upper. There is one possible * exception: if lower is 0, the line with the tag * might be the very first line. * * When this loop is done, we seek to lower, advance * past the next newline (unless lower is 0), and fall * into the sequential search. */ register off_t lower = 0; register off_t upper = stbuf.st_size; for (;;) { off_t mid; int chars_eq; if (upper - lower < JBUFSIZ) break; /* small range: search sequentially */ mid = (lower + upper) / 2; f_seek(fp, mid); /* mid will not be 0 */ f_toNL(fp); if (f_gets(fp, line, sizeof line)) break; /* unexpected: bail out */ chars_eq = numcomp(line, tag); if ((size_t)chars_eq == taglen && jiswhite(line[chars_eq])) { /* we hit the exact line: get out */ lower = mid; break; } if (line[chars_eq] < tag[chars_eq]) lower = mid; /* line is BEFORE tag */ else upper = mid; /* line is AFTER tag */ } /* sequentially search from lower */ f_seek(fp, lower); if (lower > 0) f_toNL(fp); } /* END FAST TAG CODE */ while (!f_gets(fp, line, sizeof line)) { int cmp = line[0] - *tag; if (cmp == 0) { cmp = strncmp(line, tag, taglen); if (cmp == 0) { /* we've found the match */ if (!LookingAt(pattern, line, 0)) { complain("tag line confuses me: %s", line); /* NOTREACHED */ } else { char patdelim[2]; putmatch(1, filebuf, (size_t)FILESIZE); putmatch(2, patdelim, sizeof(patdelim)); putmatch(3, searchbuf, sbsize); *ispat = patdelim[0] != '\0'; success = YES; } break; } } if (cmp > 0) break; /* failure: gone too far. PRESUMES ALPHABETIC ORDER */ } close_file(fp); if (!success) s_mess("Can't find tag \"%s\".", tag); return success; } char TagFile[FILESIZE] = "tags"; /* VAR: default tag file */ void find_tag(tag, localp) char *tag; jbool localp; { char filebuf[FILESIZE], sstr[200], /* 100 wasn't big enough */ tfbuf[FILESIZE]; register Bufpos *bp; register Buffer *b; jbool ispat; if (lookup_tag(&ispat, sstr, sizeof(sstr), filebuf, tag, localp? TagFile : ask_file("With tag file ", TagFile, tfbuf))) { set_mark(); b = do_find(curwind, filebuf, YES, NO); if (curbuf != b) SetABuf(curbuf); SetBuf(b); if (ispat) { if ((bp = dosearch(sstr, BACKWARD, NO)) == NULL && (bp = dosearch(sstr, FORWARD, NO)) == NULL) message("Well, I found the file, but the tag is missing."); else SetDot(bp); } else { long lnum = 0; /* keep gcc -W quiet */ if (chr_to_long(sstr, 10, YES, &lnum) != YES || lnum < 1) { swritef(mesgbuf, sizeof mesgbuf, "Invalid line number: %s", sstr); message(mesgbuf); } else { LinePtr tagline = next_line(curbuf->b_first, lnum - 1); PushPntp(tagline); SetLine(tagline); } } } } void FindTag() { jbool localp = !is_an_arg(); char tag[128]; jamstr(tag, ask((char *)NULL, ProcFmt)); find_tag(tag, localp); } /* Find Tag at Dot. */ void FDotTag() { int c1 = curchar, c2 = c1; char tagname[50]; if (!jisident(linebuf[curchar])) { complain("Not a tag!"); /* NOTREACHED */ } while (c1 > 0 && jisident(linebuf[c1 - 1])) c1 -= 1; while (jisident(linebuf[c2])) c2 += 1; if ((c2 - c1) >= (int)sizeof(tagname)) { complain("tag too long"); /* NOTREACHED */ } null_ncpy(tagname, linebuf + c1, (size_t) (c2 - c1)); find_tag(tagname, !is_an_arg()); } /* I-search returns a code saying what to do: * I_STOP: We found the match, so unwind the stack and leave * where it is. * I_DELETE: Rubout the last command. * I_BACKUP: Back up to where the isearch was last NOT failing. * I_TOSTART: Abort the search, going back where isearch started * * When a character is typed it is appended to the search string, and * then, isearch is called recursively. When ^S or ^R is typed, isearch * is again called recursively. */ #define I_STOP 1 #define I_DELETE 2 #define I_BACKUP 3 #define I_TOSTART 4 private char ISbuf[128], *incp = NULL; ZXchar SExitChar = CR; /* VAR: type this to stop i-search */ private Bufpos * doisearch(dir, c, failing) register ZXchar c; register int dir; jbool failing; { static Bufpos buf; Bufpos *bp; if (c != CTL('S') && c != CTL('R')) { if (failing) return NULL; DOTsave(&buf); if (dir == FORWARD) { if (ZXC(linebuf[curchar]) == c || (CaseIgnore && cind_eq(linebuf[curchar], c))) { buf.p_char = curchar + 1; return &buf; } } else { if (look_at(ISbuf)) return &buf; } } okay_wrap = YES; if ((bp = dosearch(ISbuf, dir, NO)) == NULL) rbell(); /* ring the first time there's no match */ okay_wrap = NO; return bp; } void IncFSearch() { IncSearch(FORWARD); } void IncRSearch() { IncSearch(BACKWARD); } private void IncSearch(dir) int dir; { Bufpos save_env; DOTsave(&save_env); ISbuf[0] = '\0'; incp = ISbuf; if (isearch(dir, &save_env) == I_TOSTART) SetDot(&save_env); else { if (LineDist(curline, save_env.p_line) >= MarkThresh) do_set_mark(save_env.p_line, save_env.p_char); } setsearch(ISbuf); } /* Nicely recursive. */ private int isearch(dir, bp) int dir; Bufpos *bp; { Bufpos pushbp; ZXchar c; int ndir; jbool failing; char *orig_incp; if (bp != NULL) { /* Move to the new position. */ pushbp.p_line = bp->p_line; pushbp.p_char = bp->p_char; SetDot(bp); failing = NO; } else { DOTsave(&pushbp); failing = YES; } orig_incp = incp; ndir = dir; /* Same direction as when we got here, unless we change it with ^S or ^R. */ for (;;) { SetDot(&pushbp); message(NullStr); if (failing) add_mess("Failing "); if (dir == BACKWARD) add_mess("reverse-"); add_mess("I-search: %s", ISbuf); DrawMesg(NO); add_mess(NullStr); /* tell me this is disgusting ... */ c = getch(); if (c == SExitChar) return I_STOP; if (c == AbortChar) { /* If we're failing, we backup until we're no longer * failing or we've reached the beginning; else, we * just abort the search and go back to the start. */ return failing? I_BACKUP : I_TOSTART; } switch (c) { case DEL: case BS: return I_DELETE; case CTL('\\'): c = CTL('S'); /*FALLTHROUGH*/ case CTL('S'): case CTL('R'): /* If this is the first time through and we have a * search string left over from last time, and Inputp * is not in use [kludge!], use that one now. */ if (Inputp == NULL && incp == ISbuf) { Inputp = getsearch(); continue; } ndir = (c == CTL('S')) ? FORWARD : BACKWARD; /* If we're failing and we're not changing our * direction, don't recur since there's no way * the search can work. */ if (failing && ndir == dir) { rbell(); continue; } break; case '\\': if (incp > &ISbuf[(sizeof ISbuf) - 1]) { rbell(); continue; } *incp++ = '\\'; add_mess("\\"); /*FALLTHROUGH*/ case CTL('Q'): case CTL('^'): add_mess(NullStr); c = getch(); goto literal; default: /* check for "funny" characters */ if (!jisprint(c) || IsPrefixChar(c)) { Ungetc(c); return I_STOP; } /*FALLTHROUGH*/ case '\t': literal: if (incp > &ISbuf[(sizeof ISbuf) - 1]) { rbell(); continue; } *incp++ = c; *incp = '\0'; break; } add_mess("%s", orig_incp); add_mess(" ..."); /* so we know what's going on */ DrawMesg(NO); /* do it now */ switch (isearch(ndir, doisearch(ndir, c, failing))) { case I_TOSTART: return I_TOSTART; case I_STOP: return I_STOP; case I_BACKUP: /* If we're not failing, we just continue to to the * for loop; otherwise we keep returning to the * previous levels until we find one that isn't * failing OR we reach the beginning. */ if (failing) return I_BACKUP; /*FALLTHROUGH*/ case I_DELETE: incp = orig_incp; *incp = '\0'; continue; } } } jove-4.17.5.5/reapp.h000066400000000000000000000020121501102521500141610ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern void find_tag proto((char *tag,jbool localp)); /* Commands: */ extern void FDotTag proto((void)), FindTag proto((void)), IncFSearch proto((void)), IncRSearch proto((void)), QRepSearch proto((void)), RegReplace proto((void)), RepSearch proto((void)), FSrchND proto((void)), ForSearch proto((void)), RSrchND proto((void)), RevSearch proto((void)); /* Variables: */ extern ZXchar SExitChar; /* VAR: type this to stop i-search */ extern char TagFile[FILESIZE]; /* VAR: default tag file */ extern jbool UseRE; /* VAR: use regular expressions in search */ jove-4.17.5.5/rec.c000066400000000000000000000106441501102521500136300ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #ifdef RECOVER /* the body is the rest of this file */ #include "fp.h" #include "sysprocs.h" #include "rec.h" #include "fmt.h" #include "recover.h" private int rec_fd = -1; private char *recfname; private File *rec_out; #define dmpobj(obj) fputnchar((char *) &obj, (int) sizeof(obj), rec_out) #ifndef L_SET # define L_SET 0 #endif private struct rec_head Header; void rectmpname(tfname) char *tfname; { if (strlen(tfname) >= sizeof(Header.TmpFileName)) { complain("temporary filename too long; recovery disabled."); /* NOTREACHED */ } strcpy(Header.TmpFileName, tfname); } private void recinit() { char buf[FILESIZE]; PathCat(buf, sizeof(buf), TmpDir, #ifdef MAC ".jrecXXX" /* must match string in mac.c:Ffilter() */ #else "jrXXXXXX" #endif ); recfname = copystr(buf); rec_fd = MakeTemp(recfname, "recovery (disabling it)"); /* initialize the recovery file */ rec_out = fd_open(recfname, F_WRITE|F_LOCKED, rec_fd, iobuff, LBSIZE); /* Initialize the record header (TmpFileName initialized by rectmpname). */ Header.RecMagic = RECMAGIC; Header.Uid = getuid(); Header.Pid = getpid(); } /* Close recfile before execing a child process. * Since we might be vforking, we must not change any variables * (in particular rec_fd). */ void recclose() { if (rec_fd != -1) (void) close(rec_fd); } /* Close and remove recfile before exiting. */ void recremove() { if (rec_fd != -1) { recclose(); (void) unlink(recfname); } } /* Write out the line pointers for buffer B. */ private void dmppntrs(b) register Buffer *b; { register LinePtr lp; for (lp = b->b_first; lp != NULL; lp = lp->l_next) dmpobj(lp->l_dline); } /* dump the buffer info and then the actual line pointers. */ private void dmp_buf_header(b) register Buffer *b; { struct rec_entry record; byte_zero(&record, sizeof(struct rec_entry)); /* clean out holes for purify */ record.r_dotline = LinesTo(b->b_first, b->b_dot); record.r_dotchar = b->b_char; record.r_nlines = record.r_dotline + LinesTo(b->b_dot, (LinePtr)NULL); strcpy(record.r_fname, b->b_fname ? b->b_fname : NullStr); null_ncpy(record.r_bname, b->b_name, sizeof(record.r_bname) - 1); dmpobj(record); } /* Goes through all the buffers and syncs them to the disk. */ int ModCount = 0; /* number of buffer mods since last sync */ int SyncFreq = 50; /* VAR: how often to sync the file pointers */ void SyncRec() { register Buffer *b; static jbool beenhere = NO; time_t tupd; /* Count number of interesting buffers. If none, don't bother syncing. */ Header.Nbuffers = 0; for (b = world; b != NULL; b = b->b_next) if (b->b_type != B_SCRATCH && IsModified(b)) Header.Nbuffers += 1; if (Header.Nbuffers == 0) return; lsave(); /* this makes things really right */ SyncTmp(); /* note: this will force rectmpname() */ if (!beenhere) { beenhere = YES; recinit(); /* Init recover file. */ } /* Note: once writing to the recover file fails, we permanently * stop trying. This is to avoid useless thrashing. Perhaps * there should be a way to turn this back on. */ if (rec_fd == -1 || (rec_out->f_flags & F_ERR)) return; f_seek(rec_out, (off_t)0); (void) time(&tupd); Header.UpdTime = tupd; Header.FreePtr = DFree; dmpobj(Header); for (b = world; b != NULL; b = b->b_next) if (b->b_type != B_SCRATCH && IsModified(b)) dmp_buf_header(b); for (b = world; b != NULL; b = b->b_next) if (b->b_type != B_SCRATCH && IsModified(b)) dmppntrs(b); flushout(rec_out); } /* To be implemented: * Full Recover. What we have to do is go find the name of the tmp * file data/rec pair and use those instead of the ones we would have * created eventually. The rec file has a list of buffers, and then * the actual pointers. Stored for each buffer is the buffer name, * the file name, the number of lines, the current line, the current * character. The current modes do not need saving as they will be * saved when the file name is set. If a process was running in a * buffer, it will be lost. */ #endif /* RECOVER */ jove-4.17.5.5/rec.h000066400000000000000000000014451501102521500136340ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef RECOVER /* the body is the rest of this file */ extern void SyncRec proto((void)), rectmpname proto((char *)), recclose proto((void)), recremove proto((void)); extern int ModCount; /* number of buffer mods since last sync */ /* Variables: */ extern int SyncFreq; /* VAR: how often to sync the file pointers */ #endif /* RECOVER */ jove-4.17.5.5/recover.c000066400000000000000000000700651501102521500145270ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Recovers JOVE files after a system/editor crash. * Usage: recover [-d directory] [-syscrash] [-uid UID][-v] [-D] * The -syscrash option is specified in /etc/rc. It directs recover to * move all the jove tmp files from tmp_dir (/tmp) to RECDIR (/usr/preserve). * recover -syscrash must be invoked in /etc/rc BEFORE /tmp gets cleared out. * (about the same place as expreserve gets invoked to save ed/vi/ex files. * * The -d option lets you specify the directory to search for tmp files when * the default isn't the right one. * * The -uid option lets you specify the user id if you wish to recover * files for another user (presumably as root, since otherwise you should * not be able to read the recovery/tmp files) * * The -v option turns on some verbose chatter to the screen, and -D * turns on even more verbose debugging to a file. * * Change JRECDIR and JTMPDIR in Makefile to change the default directories. */ #define USE_STDIO_H 1 #include "jove.h" #define SMALLSTRSIZE 30 /* used for small buffers */ #define MAXRECDIRSIZE 64 /* enough for RECDIR */ #define MAXFILENAMESIZE 16 /* /jvNNNNNN and trailing NUL */ #define PATHBUFSIZE (MAXRECDIRSIZE+MAXFILENAMESIZE) #define BUFCHUNK 100 /* number of recs to allocate at once */ #ifndef RECOVER int main(argc, argv) int argc; char *argv[]; { printf("%s: recovery not implemented in this JOVE configuration.\n", argv[0]); return 1; } #else /* RECOVER */ /* the body is the rest of this file */ #include "sysprocs.h" #include "rec.h" #include "paths.h" #include "recover.h" #ifndef UNIX # define signal(x, y) -1 # define kill(x, y) -1 # ifdef WIN32 # define uid_t int # endif #else /*UNIX */ # include # include # include # ifdef USE_UNAME # include # endif /* Strictly speaking, popen is not available in stdio.h in POSIX.1 or ANSI-C. * It is part of POSIX.2, and declared incorrectly in OSF/1, so we suppress * it for OSF. */ #ifndef _OSF_SOURCE extern FILE *popen proto((const char *, const char *)); #endif # ifndef FULL_UNISTD /* The parameter of getpwuid is widened uid_t, * but there no easy portable way to write this */ extern struct passwd *getpwuid proto((uid_t/*widened uid_t*/)); # ifdef USE_UNAME extern int uname proto((struct utsname *)); # endif # ifdef USE_GETHOSTNAME extern int gethostname proto((const char *, size_t)); # endif extern int mkdir proto((const char *, jmode_t)); # endif /* !FULL_UNISTD */ #endif /* UNIX */ #ifndef L_SET # define L_SET 0 # define L_INCR 1 #endif private const char *progname; private char blk_buf[JBUFSIZ]; private long nleft; private long nshort; private FILE *ptrs_fp; private int data_fd = -1; private struct rec_head Header; private long Nchars, Nlines; private char tty[] = "/dev/tty"; private const char *tmp_dir = TMPDIR; private uid_t UserID; private jbool Verbose = NO; private jbool Debug = NO; private FILE *dfp; private const char *RecDir = RECDIR; private struct file_pair { char *file_data, *file_rec; #define INSPECTED 01 int file_flags; struct file_pair *file_next; } *First = NULL; private long maxbufs; private struct rec_entry **buflist; /* system initializes to 0 */ #ifndef F_COMPLETION # define F_COMPLETION /* since scandir.c is surrounded by an ifdef */ #endif /* non-reentrant version of one in util.c since we do not have sprint */ #ifdef NO_STRERROR extern int sys_nerr; extern char *sys_errlist[]; /* * Unix version of strerror - map error number to descriptive string. * ANSI systems have this. */ char * strerror(errnum) int errnum; { static char ebuf[SMALLSTRSIZE]; /* large enough for Error number NNNNN */ if (0 < errnum && errnum < sys_nerr) return sys_errlist[errnum]; (void) sprintf(ebuf, "Error number %d", (errnum % 10000)); /* errno is never larger, but avoid string overflow -- rarely reaches here */ return ebuf; } #endif /* NO_STRERROR */ /* simpler version of one in util.c, needed by scandir.c */ UnivPtr emalloc(size) size_t size; { register UnivPtr ptr; if ((ptr = malloc(size)) == NULL) { fprintf(stderr, "couldn't malloc(%ld)\n", (long)size); exit(1); } return ptr; } /* simpler version of one in util.c, needed by scandir.c */ UnivPtr erealloc(ptr, size) UnivPtr ptr; size_t size; { if (ptr == NULL) return emalloc(size); /* some realloc do not like ptr == NULL */ if ((ptr = realloc(ptr, size)) == NULL) { fprintf(stderr, "couldn't realloc(%ld)\n", (long)size); exit(1); } return ptr; } /* copy a string into buffer; truncate silently if too large; NUL-pad. * Note: buffer must be 1 larger than n to fit NUL! * Duplicated from util.c: needed by scandir.c */ void null_ncpy(to, from, n) char *to; const char *from; size_t n; { (void) strncpy(to, from, n); to[n] = '\0'; } /* strdup s, and if t is not-NULL, concatenate space and t */ char * copystrs(s, t) const char *s, *t; { char *str, *sp; size_t ns = strlen(s) + 1, nt = 0; if (t) nt = strlen(t) + 1; sp = str = emalloc(ns + nt); memcpy(sp, s, ns); if (t) { sp += ns; sp[-1] = ' '; memcpy(sp, t, nt); } return str; } /* needed by scandir.c */ #define copystr(s) copystrs(s, NULL) #include "scandir.c" /* to get dirent simulation and jscandir */ /* Get a line at `tl' in the tmp file into `buf' which should be LBSIZE * long. */ private char *getblock proto((daddr atl)); void jgetline(tl, buf) daddr tl; char *buf; { register char *bp, *lp; register long nl; lp = buf; bp = getblock(tl); nl = nleft; while ((*lp++ = *bp++) != '\0') { if (--nl == 0) { /* oops: line didn't end within block: fake it */ if (Verbose) fprintf(dfp, "warning: truncated line %lu\n", (unsigned long)tl); *lp++ = '\0'; break; } } } private jmp_buf int_env; private char * getblock(atl) daddr atl; { daddr bno, off; static daddr curblock = MAX_BLOCKS; bno = da_to_bno(atl); off = da_to_off(atl); nleft = JBUFSIZ - off; if (Debug) fprintf(dfp, "getblock atl %ld bno %ld off %ld nleft %ld\n", (long)atl, (long)bno, (long)off, (long)nleft); if (bno != curblock) { JSSIZE_T nb; const char *what; off_t r, boff = bno_to_seek_off(bno); if (Debug) fprintf(dfp, "lseek %d to bno %lu 0x%lx boff %ld 0x%lx\n", data_fd, (unsigned long)bno, (unsigned long) bno, (long)boff, (long)boff); what = "lseek"; r = lseek(data_fd, boff, L_SET); if (r >= 0) { what = "read"; nb = read(data_fd, (UnivPtr)blk_buf, (size_t)JBUFSIZ); if (nb >= 0 && nb != JBUFSIZ) { if (nshort == 0) fprintf(stderr, "short read from JOVE tempfile %ld\n", (long)nb); nshort++; bno = MAX_BLOCKS; if (nb > off) { nleft = nb - off; } else { blk_buf[off] = '\0'; nleft = 1; } } else if (nb < 0) { r = -1; } } if (r < 0) { fprintf(stderr, "%s of JOVE tempfile failed bno %ld: %s\n", what, (long)bno, strerror(errno)); longjmp(int_env, 1); /* NOTREACHED */ } curblock = bno; } return blk_buf + off; } private const char *CurDir; /* Scan the DIRNAME directory for jove tmp files, and make a linked list * out of them. */ private jbool add_name proto((char *)); private void free_files() { while (First != NULL) { struct file_pair *p = First; First = p->file_next; free((UnivPtr) p->file_data); free((UnivPtr) p->file_rec); free((UnivPtr) p); } } private void get_files(dirname) const char *dirname; { char **nmptr; int nentries; /* first, free any previous entries */ free_files(); CurDir = dirname; nentries = jscandir(dirname, &nmptr, add_name, (int (*) ptrproto((UnivConstPtr, UnivConstPtr)))NULL); if (nentries != -1) freedir(&nmptr, nentries); } private jbool add_name(fname) char *fname; { char dfile[FILESIZE*2+2], /* CurDir/filename */ rfile[FILESIZE*2+2]; struct file_pair *fp; struct rec_head header; int fd; /* jrecstr must match the start of the string in recinit */ #ifdef MAC static const char jrecstr[] = ".jrec"; #else static const char jrecstr[] = "jr"; #endif struct stat stbuf; if (strncmp(fname, jrecstr, sizeof(jrecstr)-1) != 0) { if (Debug) fprintf(dfp, "skipping %s\n", fname); return NO; } /* If we get here, we found a "recover" tmp file, so now * we look for the corresponding "data" tmp file. First, * though, we check to see whether there is anything in * the "recover" file. If it's 0 length, there's no point * in saving its name. */ (void) sprintf(rfile, "%s/%s", CurDir, fname); if (stat(rfile, &stbuf) != 0 || (stbuf.st_mode & S_IFMT) != S_IFREG) { if (Verbose) fprintf(dfp, "skipping non-regular file %s\n", rfile); return NO; } if (Debug) fprintf(dfp, "checking %s\n", rfile); if ((fd = open(rfile, O_RDONLY | O_BINARY | O_CLOEXEC)) != -1) { if (read(fd, (UnivPtr) &header, sizeof header) != sizeof header) { close(fd); fprintf(stderr, "%s: could not read complete header from %s, skipping\n", progname, rfile); return NO; } if (header.RecMagic != RECMAGIC) { close(fd); fprintf(stderr, "%s: skipping incompatible %s magic 0x%lx != our 0x%lx\n", progname, rfile, header.RecMagic, (unsigned long)RECMAGIC); return NO; } close(fd); } (void) sprintf(dfile, "%s/%s", CurDir, header.TmpFileName); if (access(dfile, F_OK) != 0) { fprintf(stderr, "%s: can't find the data file `%s' for %s\n", progname, header.TmpFileName, rfile); #ifdef NEVER /* * MM: I don't think it's a good idea to delete the files * because access() failed. We should probably ask the user * if it is ok to delete the file! */ fprintf(stderr, "so deleting...\n"); (void) unlink(rfile); #endif return NO; } /* If we get here, we've found both files, so we put them * in the list. */ fp = (struct file_pair *) emalloc(sizeof *fp); fp->file_data = copystr(dfile); fp->file_rec = copystr(rfile); fp->file_flags = 0; fp->file_next = First; First = fp; return YES; } private void options() { printf("Options are:\n"); printf(" ? list options.\n"); printf(" get get a buffer to a file.\n"); printf(" list list known buffers.\n"); printf(" print print a buffer to terminal.\n"); printf(" quit quit and delete jove tmp files.\n"); printf(" restore restore all buffers.\n"); } /* Returns a legitimate buffer # */ private void tellme proto((const char *, char *, size_t)), list proto((void)); private long getsrc() { char name[FILESIZE]; long number; for (;;) { tellme("Which buffer ('?' for list)? ", name, sizeof(name)); if (name[0] == '?') list(); else if (name[0] == '\0') return -1; else if ((number = atoi(name)) > 0 && number <= Header.Nbuffers) return number; else { long i; for (i = 1; i <= Header.Nbuffers; i++) if (strcmp(buflist[i]->r_bname, name) == 0) return i; printf("%s: unknown buffer.\n", name); } } } /* Get a destination file name. */ private char * getdest() { static char filebuf[FILESIZE]; tellme("Output file: ", filebuf, sizeof(filebuf)); if (filebuf[0] == '\0') return NULL; return filebuf; } #include "jctype.h" private char * readword(buf, buflen) char *buf; size_t buflen; { int c; char *bp = buf, *ep = buf + buflen - 1; do {} while (strchr(" \t\n", c = getchar()) != NULL); for (;;) { if (c == EOF) exit(0); if (strchr(" \t\n", c) != NULL) break; if (bp == ep) { *bp = '\0'; fprintf(stderr, "%lu byte buffer too small for word `%s'", (unsigned long) buflen, buf); exit(0); } *bp++ = c; c = getchar(); } *bp = '\0'; return buf; } private void tellme(quest, answer, anslen) const char *quest; char *answer; size_t anslen; { printf("%s", quest); fflush(stdout); readword(answer, anslen); } #ifdef UNIX private SIGRESTYPE catch(junk) int UNUSED(junk); { longjmp(int_env, 1); /*NOTREACHED*/ } #endif /* UNIX */ private void get proto((long src, char *dest)); private void restore() { register long i; char tofile[FILESIZE+1], /* leading # */ answer[SMALLSTRSIZE]; int nrecovered = 0; for (i = 1; i <= Header.Nbuffers; i++) { (void) sprintf(tofile, "#%s", buflist[i]->r_bname); tryagain: printf("Restoring %s to %s, okay?", buflist[i]->r_bname, tofile); tellme(" ", answer, sizeof(answer)); switch (answer[0]) { case 'y': break; case 'n': continue; default: tellme("What file should I use instead? ", tofile, sizeof(tofile)); goto tryagain; } if (Debug) fprintf(dfp, "getting %ld %s to %s\n", i, buflist[i]->r_bname, tofile); get(i, tofile); nrecovered += 1; } printf("Recovered %d buffers.\n", nrecovered); } private void dump_file proto((long which, FILE *out)); private void get(src, dest) long src; char *dest; { FILE *volatile outfile; /* "volatile" to preserve outfile across setjmp */ if (src < 0 || src > Header.Nbuffers || src >= maxbufs || dest == NULL) { const char *pdest = dest ? dest : "(NULL)"; fprintf(stderr, "internal error: get: src %ld nbuf %ld maxbuf %ld dest %s\n", src, Header.Nbuffers, maxbufs, pdest); return; } if (dest == tty) { outfile = stdout; } else { if ((outfile = fopen(dest, "wb")) == NULL) { fprintf(stderr, "%s: cannot create %s: %s\n", progname, dest, strerror(errno)); (void) signal(SIGINT, SIG_DFL); return; } printf("\"%s\"", dest); } if (setjmp(int_env) == 0) { (void) signal(SIGINT, catch); dump_file(src, outfile); } else { printf("\nAborted!\n"); } (void) signal(SIGINT, SIG_DFL); if (dest != tty) { if (fflush(outfile) == EOF || ferror(outfile) || #ifdef USE_FSYNC fsync(fileno(outfile)) < 0 || #endif fclose(outfile) == EOF) { fprintf(stderr, "Error flushing/closing %s: %s\n", dest, strerror(errno)); } printf(" %ld lines, %ld characters.\n", Nlines, Nchars); } fflush(stdout); if (nshort) { fprintf(stderr, "%ld missing lines (short reads of data file)\n", nshort); nshort = 0; } } private jbool isopt(args, str, needval) register char **args, *str; jbool needval; { char *cp = *args; if (Debug) fprintf(dfp, "isopt \"%s\" \"%s\" %d\n", *args, str, needval); if (*cp++ != '-') return NO; if (*cp == '-') cp++; /* accept either single or double dash */ if (strcmp(cp, str) == 0) { if (Debug) fprintf(dfp, "found option \"%s\" needval %d args[1] \"%s\"\n", str, needval, args[1] ? args[1] : "!NULL!"); /* XXX for error checking, we sacrifice ability to provide option values starting with - since those are very unlikely */ if (needval && (args[1] == NULL || args[1][0] == '-')) { fprintf(stderr, "need value after option %s\n", str); exit(1); } return YES; } return NO; } private void read_rec(recptr) struct rec_entry *recptr; { if (fread((UnivPtr) recptr, sizeof *recptr, (size_t)1, ptrs_fp) != 1) fprintf(stderr, "%s: cannot read record. %s\n", progname, strerror(errno)); } private void seekto(which) long which; { long offset, i; offset = sizeof (Header) + (Header.Nbuffers * sizeof (struct rec_entry)); for (i = 1; i < which; i++) offset += buflist[i]->r_nlines * sizeof (daddr); fseek(ptrs_fp, offset, L_SET); } private void freeblist() { long i; for (i = 0; i < maxbufs; i++) { if (buflist[i]) { free((UnivPtr) buflist[i]); buflist[i] = NULL; } } free((UnivPtr) buflist); buflist = NULL; maxbufs = 0; } private void makblist() { long i, nmax; fseek(ptrs_fp, (long) sizeof (Header), L_SET); /* resize buflist up to multiple of BUFCHUNK */ nmax = ( (Header.Nbuffers+1)/BUFCHUNK + 1 ) * BUFCHUNK; if (Debug) fprintf(dfp, "maxbufs %ld nmax %ld\n", maxbufs, nmax); if (maxbufs < nmax) { buflist = (struct rec_entry **) erealloc(buflist, nmax*sizeof(struct rec_entry *)); for (i = maxbufs; i < nmax; i++) buflist[i] = NULL; maxbufs = nmax; } for (i = 1; i <= Header.Nbuffers; i++) { if (Debug) { /* XXX may end up truncating addr if unsigned long smaller than DADDR */ printf("i %ld 0x%lx\n",i, (unsigned long)((DADDR)buflist[i])); } if (buflist[i] == NULL) buflist[i] = (struct rec_entry *) emalloc (sizeof (struct rec_entry)); read_rec(buflist[i]); } /* * just for safety, unset any remaining buflist * entries. since we should always be using * Header.Nbuffers as a limit, we should never touch these. */ while (i < maxbufs) { if (buflist[i]) { buflist[i]->r_bname[0] = buflist[i]->r_fname[0] = '\0'; buflist[i]->r_nlines = buflist[i]->r_dotline = buflist[i]->r_dotchar = 0; } i++; } } private daddr getaddr(fp) register FILE *fp; { register int nchars = sizeof (daddr); daddr addr; register char *cp = (char *) &addr; while (--nchars >= 0) *cp++ = getc(fp); return addr & ~DDIRTY; } private void dump_file(which, out) long which; FILE *out; { register long nlines; /* XXX lnum_t */ register daddr addr; char buf[JBUFSIZ]; seekto(which); nlines = buflist[which]->r_nlines; Nchars = Nlines = 0L; while (--nlines >= 0) { addr = getaddr(ptrs_fp); if (Debug) { /* XXX may end up truncating addr if unsigned long smaller than DADDR */ fprintf(dfp, "line %ld addr %lu\n", nlines, (unsigned long)((DADDR)addr)); } jgetline(addr, buf); Nlines += 1; Nchars += 1 + strlen(buf); fputs(buf, out); if (nlines > 0) { #ifdef USE_CRLF fputc('\r', out); #endif fputc(EOL, out); } } } /* List all the buffers. */ private void list() { long i; for (i = 1; i <= Header.Nbuffers; i++) printf("%ld) buffer %s \"%s\" (%ld lines)\n", i, buflist[i]->r_bname, buflist[i]->r_fname, buflist[i]->r_nlines); } private void ask_del proto((const char *prompt, struct file_pair *fp)); private int doit(fp) struct file_pair *fp; { char answer[SMALLSTRSIZE]; char *datafile = fp->file_data, *pntrfile = fp->file_rec; time_t tupd; ptrs_fp = fopen(pntrfile, "rb"); if (ptrs_fp == NULL) { fprintf(stderr, "%s: cannot read rec file (%s).\n", progname, pntrfile); return 0; } if (Debug) fprintf(dfp, "opened %s\n", pntrfile); if (fread((UnivPtr) &Header, sizeof Header, (size_t)1, ptrs_fp) != 1) { fprintf(stderr, "%s: cannot read header from rec file (%s).\n", progname, pntrfile); return 0; } if (Debug) fprintf(dfp, "read header from %s, uid %ld, pid %ld, %ld bufs, %s\n", pntrfile, Header.Uid, Header.Pid, Header.Nbuffers, Header.TmpFileName); if (Header.Uid != (long)UserID) { if (Debug) fprintf(dfp, "different user %ld != %ld\n", (long)Header.Uid, (long)UserID); return 0; } /* Ask about JOVE's that are still running ... */ if (kill((pid_t)Header.Pid, 0) == 0) { if (Debug) fprintf(dfp, "still running pid %ld\n", Header.Pid); return 0; } if (Header.Nbuffers == 0) { printf("There are no modified buffers in %s; should I delete the tmp file?", pntrfile); ask_del(" ", fp); return 1; } if (Header.Nbuffers < 0) { fprintf(stderr, "%s: %s doesn't look like a jove recovery file.\n", progname, pntrfile); ask_del("Should I delete it? ", fp); return 1; /* We'll, we sort of found something. */ } tupd = (time_t)Header.UpdTime; printf("Found %ld buffer%s last updated: %s", Header.Nbuffers, Header.Nbuffers != 1 ? "s" : "", ctime(&tupd)); data_fd = open(datafile, O_RDONLY | O_BINARY | O_CLOEXEC); if (data_fd == -1) { fprintf(stderr, "%s: but I can't read the data file (%s).\n", progname, datafile); ask_del("Should I delete the tmp files? ", fp); return 1; } if (Debug) fprintf(dfp, "opened fd %d data file %s\n", data_fd, datafile); makblist(); list(); for (;;) { long src; tellme("(Type '?' for options): ", answer, sizeof(answer)); switch (answer[0]) { case '\0': continue; case '?': options(); break; case 'l': list(); break; case 'p': if ((src = getsrc()) < 0) break; if (Debug) fprintf(dfp, "getting %ld %s to %s\n", src, buflist[src]->r_bname, tty); get(src, tty); break; case 'q': ask_del("Shall I delete the tmp files? ", fp); return 1; case 'g': { /* So it asks for src first. */ char *dest; if ((src = getsrc()) < 0) break; dest = getdest(); if (Debug) fprintf(dfp, "getting %ld %s to %s\n", src, buflist[src]->r_bname, dest); get(src, dest); break; } case 'r': restore(); break; default: printf("I don't know how to \"%s\"!\n", answer); break; } } } private void del_files proto((struct file_pair *fp)); private void ask_del(prompt, fp) const char *prompt; struct file_pair *fp; { char yorn[SMALLSTRSIZE]; tellme(prompt, yorn, sizeof(yorn)); if (yorn[0] == 'y') del_files(fp); } private void del_files(fp) struct file_pair *fp; { (void) unlink(fp->file_data); (void) unlink(fp->file_rec); } #ifdef UNIX private const char * hname() { const char *p = "unknown"; #ifdef USE_UNAME static struct utsname mach; if (uname(&mach) >= 0) p = mach.nodename; #endif #ifdef USE_GETHOSTNAME static char mach[BUFSIZ]; if (gethostname(mach, sizeof(mach)) >= 0) p = mach; #endif return p; } private void MailUser(rec) struct rec_head *rec; { char *last_update, *mail_cmd; const char *buf_string, *mail_prog; FILE *mail_pipe; struct passwd *pw; int r; time_t tupd; if ((pw = getpwuid((uid_t)rec->Uid))== NULL) return; tupd = (time_t)(rec->UpdTime); last_update = ctime(&tupd); /* Start up mail */ if ((mail_prog = getenv("JOVEMAILER")) == NULL) mail_prog = "/bin/mail"; mail_cmd = copystrs(mail_prog, pw->pw_name); if ((r = setuid(getuid())) < 0) { fprintf(stderr, "WARNING: %s: setuid(getuid()) failed: %s\n", progname, strerror(errno)); /* * used to continue without checking return value, * so let that behaviour continue, I guess? */ } if ((mail_pipe = popen(mail_cmd, "w")) == NULL) { fprintf(stderr, "%s: failed to popen mail command \"%s\": %s\n", progname, mail_cmd, strerror(errno)); free(mail_cmd); return; } /* Let's be grammatically correct! */ buf_string = rec->Nbuffers == 1? "buffer" : "buffers"; fprintf(mail_pipe, "Subject: Jove saved %ld %s after \"%s\" crashed\n", rec->Nbuffers, buf_string, hname()); fprintf(mail_pipe, " \n"); fprintf(mail_pipe, "Jove saved %ld %s when the system \"%s\"\n", rec->Nbuffers, buf_string, hname()); fprintf(mail_pipe, "crashed on %s\n\n", last_update); fprintf(mail_pipe, "You can retrieve the %s using Jove's -r\n", buf_string); fprintf(mail_pipe, "(recover option) i.e. give the command.\n"); fprintf(mail_pipe, "\tjove -r\n"); fprintf(mail_pipe, "See the Jove manual for more details\n"); pclose(mail_pipe); free(mail_cmd); } private void savetmps() { struct file_pair *fp; wait_status_t status; pid_t pid; int fd, rc; struct rec_head header; char buf[PATHBUFSIZE]; char *fname; struct stat stbuf; if (strcmp(tmp_dir, RecDir) == 0) return; /* Files are moved to the same place. */ /* sanity check on RecDir */ if (strlen(RecDir) > MAXRECDIRSIZE) { fprintf(stderr, "%s: recovery directory len is %u, must be smaller than %u\n", progname, (unsigned)strlen(RecDir), MAXRECDIRSIZE); exit(2); } sprintf(buf, "%s/jv%06u", RecDir, (unsigned)getpid()); /* dummy name */ stbuf.st_mode = stbuf.st_uid = 0; if ((rc = stat(RecDir, &stbuf)) < 0) if ((rc = mkdir(RecDir, 0755)) == 0) rc = stat(RecDir, &stbuf); if (rc < 0 || (stbuf.st_mode & S_IFMT) != S_IFDIR || stbuf.st_uid != getuid() /*|| access(buf, W_OK) != 0*/) { fprintf(stderr, "%s: need writable directory \"%s\" owned by %u: got mode 0%o uid %u rc %d: %s\n", progname, RecDir, getuid(), (unsigned)stbuf.st_mode, (unsigned)stbuf.st_uid, rc, rc < 0 ? strerror(errno) : ""); exit(2); } printf("Recovering jove files ... "); get_files(tmp_dir); for (fp = First; fp != NULL; fp = fp->file_next) { if (Debug) fprintf(dfp, "Recovering: %s, %s\n", fp->file_data, fp->file_rec); if (stat(fp->file_data, &stbuf) < 0) { fprintf(stderr, "%s: stat data %s failed, rec %s: %s\n", progname, fp->file_data, fp->file_rec, strerror(errno)); continue; } switch (pid = fork()) { case -1: fprintf(stderr, "%s: can't fork. %s\n!", progname, strerror(errno)); exit(-1); /*NOTREACHED*/ case 0: if ((fd = open(fp->file_rec, O_RDONLY | O_BINARY | O_CLOEXEC)) != -1) { if ((read(fd, (UnivPtr) &header, sizeof header) != sizeof header)) { close(fd); return; } else close(fd); } MailUser(&header); execl("/bin/mv", "mv", fp->file_data, fp->file_rec, RecDir, (char *)NULL); fprintf(stderr, "%s: cannot execl /bin/mv. %s\n", progname, strerror(errno)); exit(-1); /*NOTREACHED*/ default: do {} while (wait(&status) != pid); if (WIFSIGNALED(status)) fprintf(stderr, "%s: copy terminated by signal %d\n.\n", progname, WTERMSIG(status)); if (WIFEXITED(status)) fprintf(stderr, "%s: copy exited with %d.\n", progname, WEXITSTATUS(status)); fname = fp->file_data + strlen(tmp_dir); if (strlen(fname)+1 > MAXFILENAMESIZE) { fprintf(stderr, "%s: filename \"%s\" len %u, must be smaller than %u\n", progname, fname, (unsigned)strlen(fname), MAXFILENAMESIZE-1); exit(2); } strcpy(buf, RecDir); strcat(buf, fname); if (chown(buf, stbuf.st_uid, stbuf.st_gid) != 0) { fprintf(stderr, "%s: chown data %s to %u.%u failed: %s", progname, buf, (unsigned)stbuf.st_uid, (unsigned)stbuf.st_gid, strerror(errno)); } fname = fp->file_rec + strlen(tmp_dir); if (strlen(fname)+1 > MAXFILENAMESIZE) { fprintf(stderr, "%s: filename \"%s\" len %u, must be smaller than %u\n", progname, fname, (unsigned)strlen(fname), MAXFILENAMESIZE-1); exit(2); } strcpy(buf, RecDir); strcat(buf, fname); if (chown(buf, stbuf.st_uid, stbuf.st_gid) != 0) { fprintf(stderr, "%s: chown rec %s to %u.%u failed: %s", progname, buf, (unsigned)stbuf.st_uid, (unsigned)stbuf.st_gid, strerror(errno)); } fputc('.', stdout); } } free_files(); printf("Done.\n"); } #endif /* UNIX */ private int lookup(dir) const char *dir; { struct file_pair *fp; int nfound = 0; printf("Checking %s ...\n", dir); get_files(dir); for (fp = First; fp != NULL; fp = fp->file_next) { nfound += doit(fp); if (ptrs_fp) { (void) fclose(ptrs_fp); ptrs_fp = NULL; } if (data_fd > 0) { (void) close(data_fd); data_fd = -1; } } free_files(); return nfound; } int main(argc, argv) int UNUSED(argc); char *argv[]; { int nfound; char **argvp; progname = argv[0]; UserID = getuid(); setbuf(stdout, NULL); dfp = stdout; /* override tmp_dir with $TMPDIR, RecDir with $JOVERECDIR if any */ { char *cp = getenv("TMPDIR"); if (cp != NULL) tmp_dir = cp; cp = getenv("JOVERECDIR"); if (cp != NULL) RecDir = cp; } for (argvp = argv + 1; *argvp; argvp++) { if (isopt(argvp, "v", NO)) { Verbose = YES; continue; } if (isopt(argvp, "D", YES)) { time_t t; Debug = YES; dfp = fopen(*++argvp, "wc"); (void) time(&t); fprintf(dfp, "debugfile \"%s\" %s", *argvp, ctime(&t)); continue; } if (isopt(argvp, "d", YES)) { tmp_dir = *++argvp; continue; } if (isopt(argvp, "r", YES)) { RecDir = *++argvp; continue; } if (isopt(argvp, "uid", YES)) { UserID = atoi(*++argvp); continue; } #ifdef UNIX if (isopt(argvp, "syscrash", NO)) { savetmps(); exit(0); } #endif fprintf(stderr, "Usage: %s [-v] [-d TMPDIR] [-D DEBUGFILE] [-r RecDir] [-uid UID] [-syscrash]\n\n", progname); fprintf(stderr, "Use \"jove -r\" to interactively recover saved state\n"); fprintf(stderr, "\tafter JOVE has died for some unknown reason.\n\n"); fprintf(stderr, "Use \"%s/recover -syscrash\"\n", LIBDIR); fprintf(stderr, "\tin reboot scripts to copy JOVE saved state to\n"); fprintf(stderr, "\t%s before temporary files in %s are cleared.\n\n", RecDir, tmp_dir); fprintf(stderr, "Use \"recover -d TMPDIR\"\n"); fprintf(stderr, "\twhen the tmp files are stored in directory TMPDIR\n"); fprintf(stderr, "\tinstead of in the default one (%s).\n\n", tmp_dir); exit(1); } /* Check default directory */ nfound = lookup(tmp_dir); /* Check whether anything was saved when system died? */ if (strcmp(tmp_dir, RecDir) != 0) nfound += lookup(RecDir); if (nfound == 0) printf("There's nothing to recover.\n"); freeblist(); return 0; } #endif /* RECOVER */ jove-4.17.5.5/recover.h000066400000000000000000000055061501102521500145320ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef RECOVER /* the body is the rest of this file */ #include "temp.h" #ifndef UNIX # define getuid() 0 #endif /* Format of records within the jrec file: information to allow * recovery from a crash. * * Note: the recovery info is * (1) architecture dependent -- it contains longs, among other things * (2) version dependent -- format 1 started in 4.15.16, version 2 in 4.17.2.8 * (3) configuration dependent -- affected by any change to FILESIZE * RECMAGIC tries to encode all those things so we can at least detect * mismatches (and perhaps, down the road, at least recover different * configurations. * Even though this uses long, which might be 64bits, we keep RECMAGIC * to fit in 32bits, so that it can fit on most machines. Similarly, * we only use long as a field width, to make this more uniform; * wastes bits on 64bit machines (which can afford it) but is nice * for 32bit machines (or even 16bit, since their long is usually 32bits) * The bulk of any jrec file is the daddr pointers anyway. */ #define LG_JBUFSIZMIN 7 #if LG_JBUFSIZ < LG_JBUFSIZMIN || (LG_JBUFSIZ-LG_JBUFSIZMIN) > 15 Error will not be able to encode recovery header LG_JBUFSIZ safely #endif #define LG_FILESIZEMIN 6 #if LG_FILESIZE < LG_FILESIZEMIN || (LG_FILESIZE-LG_FILESIZEMIN) > 15 Error will not be able to encode recovery header LG_FILESIZE safely #endif #if LG_CHNK_CHARS > 15 Error will not be able to encode recovery header LG_CHNK_CHARS safely #endif # define RECVER 2 /* JOVE recovery file, version 2 */ # define RECMAGIC (((((((((((((long)'J' << 4) | \ RECVER) << 4) | \ (LG_JBUFSIZ-LG_JBUFSIZMIN)) << 4) | \ sizeof(long)) << 4) | \ sizeof(daddr)) << 4) | \ (LG_FILESIZE-LG_FILESIZEMIN)) << 4) | \ LG_CHNK_CHARS) struct rec_head { long RecMagic; /* (partial) compatibility check */ long Uid; /* uid of owner */ long Pid; /* pid of jove process */ long UpdTime; /* last time this was updated */ long Nbuffers; /* number of buffers */ daddr FreePtr; /* position of DFree */ char TmpFileName[FILESIZE]; /* name of corresponding tempfile */ }; struct rec_entry { char r_bname[FILESIZE], r_fname[FILESIZE]; long r_nlines, r_dotline, /* so we can really save the context */ r_dotchar; }; #endif /* RECOVER */ jove-4.17.5.5/scandir.c000066400000000000000000000154231501102521500145020ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* * This file is used as a compiled module by Jove and also included as * source in recover.c */ #ifndef TUNED # include "jove.h" #endif #include "scandir.h" #ifdef F_COMPLETION /* the body is the rest of this file */ #ifdef MAC # include "mac.h" #else # include #endif #ifdef UNIX # if defined(M_XENIX) && !defined(M_UNIX) /* XENIX, but not SCO UNIX, which pretends to be XENIX! */ # include # ifndef dirent # define dirent direct # endif # endif # ifdef BSD_DIR # include # ifndef dirent # define dirent direct # endif # endif /* default to dirent.h */ # if !defined(dirent) && !defined(DIRENT_EMULATE) # include # endif # ifdef DIRENT_EMULATE typedef struct { int d_fd; /* File descriptor for this directory */ } DIR; private int closedir(dp) DIR *dp; { (void) close(dp->d_fd); free((UnivPtr) dp); return 0; /* don't know how to fail */ } private DIR * opendir(dir) const char *dir; { int fd; if ((fd = open(dir, O_RDONLY | O_BINARY | O_CLOEXEC)) != -1) { struct stat stbuf; if ((fstat(fd, &stbuf) != -1) && (stbuf.st_mode & S_IFMT) == S_IFDIR) { /* Success! */ DIR *dp = (DIR *) emalloc(sizeof *dp); dp->d_fd = fd; return dp; } /* this isn't a directory! */ (void) close(fd); } return NULL; } private dirent * readdir(dp) DIR *dp; { static dirent dir; do { if (read(dp->d_fd, (UnivPtr) &dir, sizeof dir) != sizeof dir) return NULL; } while (dir.d_ino == 0); return &dir; } #endif /* DIRENT_EMULATE */ /* jscandir returns the number of entries or -1 if the directory cannot * be opened or malloc fails. */ int jscandir(dir, nmptr, qualify, sorter) const char *dir; char ***nmptr; jbool (*qualify) ptrproto((char *)); int (*sorter) ptrproto((UnivConstPtr, UnivConstPtr)); { DIR *dirp; struct dirent *entry; char **ourarray; unsigned int nalloc = 10; size_t nentries = 0; if ((dirp = opendir(dir)) == NULL) return -1; ourarray = (char **) emalloc(nalloc * sizeof (char *)); while ((entry = readdir(dirp)) != NULL) { if (qualify != NULL && !(*qualify)(entry->d_name)) continue; /* note: test ensures one space left in ourarray for NULL */ if (nentries+1 == nalloc) ourarray = (char **) erealloc((UnivPtr) ourarray, (nalloc += 10) * sizeof (char *)); ourarray[nentries++] = copystr(entry->d_name); } closedir(dirp); ourarray[nentries] = NULL; if (sorter != NULL) qsort((UnivPtr) ourarray, nentries, sizeof (char **), sorter); *nmptr = ourarray; return nentries; } #endif /* UNIX */ #ifdef MSFILESYSTEM /* NOTE: MatchDir affects any call to jscandir! * Currently, the only calls to jscandir are from: * - the recover program (which never touches MatchDir) * - descendants of ask_file or ask_dir (which always set it) */ jbool MatchDir = NO; #endif #ifdef MSDOS # include # ifndef ZTCDOS # include # endif /* Scandir returns the number of entries or -1 if the directory cannot * be opened or malloc fails. */ int jscandir(dir, nmptr, qualify, sorter) const char *dir; char ***nmptr; jbool (*qualify) ptrproto((char *)); int (*sorter) ptrproto((UnivConstPtr, UnivConstPtr)); { struct find_t entry; char **ourarray; unsigned int nalloc = 10, nentries = 0; { char dirname[FILESIZE]; char *ptr; strcpy(dirname, dir); ptr = &dirname[strlen(dirname)-1]; if (!((dirname[1] == ':' && dirname[2] == '\0') || *ptr == '/' || *ptr == '\\')) *++ptr = '/'; strcpy(ptr+1, "*.*"); if (_dos_findfirst(dirname, _A_NORMAL|_A_RDONLY|_A_HIDDEN|_A_SUBDIR, &entry)) return -1; } ourarray = (char **) emalloc(nalloc * sizeof (char *)); do { char filename[FILESIZE]; if (MatchDir && (entry.attrib&_A_SUBDIR) == 0) continue; strlwr(entry.name); if (qualify != NULL && !(*qualify)(entry.name)) continue; /* note: test ensures one space left in ourarray for NULL */ if (nentries+1 == nalloc) ourarray = (char **) erealloc((char *) ourarray, (nalloc += 10) * sizeof (char *)); strcpy(filename, entry.name); #ifdef DIRECTORY_ADD_SLASH if ((entry.attrib&_A_SUBDIR) != 0) strcat(filename, "/"); #endif ourarray[nentries++] = copystr(filename); } while (_dos_findnext(&entry) == 0); ourarray[nentries] = NULL; if (sorter != (int (*) ptrproto((UnivConstPtr, UnivConstPtr)))NULL) qsort((char *) ourarray, nentries, sizeof (char **), sorter); *nmptr = ourarray; return nentries; } #endif /* MSDOS */ #ifdef WIN32 # undef Fill /* sigh, used as a field name in some windows header! */ # undef CR /* sigh, used as a field name in some windows header! */ # include /* Scandir returns the number of entries or -1 if the directory cannot * be opened or malloc fails. */ int jscandir(dir, nmptr, qualify, sorter) const char *dir; char ***nmptr; jbool (*qualify) ptrproto((char *)); int (*sorter) ptrproto((UnivConstPtr, UnivConstPtr)); { WIN32_FIND_DATA entry; HANDLE findHand; char **ourarray; unsigned int nalloc = 10, nentries = 0; { char dirname[_MAX_PATH]; char *ptr; strcpy(dirname, dir); ptr = &dirname[strlen(dirname)-1]; if (!((dirname[1] == ':' && dirname[2] == '\0') || *ptr == '/' || *ptr == '\\')) *++ptr = '/'; strcpy(ptr+1, "*.*"); if ((findHand = FindFirstFile(dirname, &entry)) == INVALID_HANDLE_VALUE) return -1; } ourarray = (char **) emalloc(nalloc * sizeof (char *)); do { char filename[_MAX_PATH]; if (MatchDir && (entry.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) == 0) continue; strcpy(filename, entry.cFileName); strlwr(entry.cFileName); if (qualify != NULL && !(*qualify)(entry.cFileName)) continue; /* note: test ensures one space left in ourarray for NULL */ if (nentries+1 == nalloc) ourarray = (char **) erealloc((char *) ourarray, (nalloc += 10) * sizeof (char *)); #ifdef DIRECTORY_ADD_SLASH if ((entry.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY) != 0) strcat(filename, "/"); #endif ourarray[nentries++] = copystr(filename); } while (FindNextFile(findHand, &entry)); FindClose(findHand); ourarray[nentries] = NULL; if (sorter != (int (*)ptrproto((UnivConstPtr, UnivConstPtr)))NULL) qsort((char *) ourarray, nentries, sizeof (char **), sorter); *nmptr = ourarray; return nentries; } #endif /* WIN32 */ void freedir(nmptr, nentries) char ***nmptr; int nentries; { char **ourarray = *nmptr; while (--nentries >= 0) free((UnivPtr) *ourarray++); free((UnivPtr) *nmptr); *nmptr = NULL; } #endif /* F_COMPLETION */ jove-4.17.5.5/scandir.h000066400000000000000000000014071501102521500145040ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ extern int jscandir proto((const char *dir, char ***nmptr, jbool (*qualify) ptrproto((char *)), int (*sorter) ptrproto((UnivConstPtr, UnivConstPtr)))); extern void freedir proto((char ***nmptr,int nentries)); #ifdef MSFILESYSTEM /* NOTE: MatchDir affects any call to jscandir */ extern jbool MatchDir; #endif jove-4.17.5.5/screen.c000066400000000000000000000557151501102521500143460ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "fp.h" #include "chars.h" #include "jctype.h" #include "disp.h" #include "extend.h" #include "fmt.h" #include "term.h" #include "mac.h" #include "screen.h" #include "wind.h" int AbortCnt, tabstop = 8; /* VAR: expand tabs to this number of spaces */ struct scrimage *DesiredScreen = NULL, *PhysScreen = NULL; private struct screenline *Savelines = NULL; /* scratch entries (LI of them) */ private void LEclear proto((struct screenline *)); /* free s_effects component */ private char *cursor; /* offset into current Line */ char *cursend; /* Position in tercap screen. INFINITY means "don't know". */ int CapCol, CapLine; private int i_line, i_col; void make_scr() { register int i; register struct screenline *ns; register char *nsp; static char *screenchars = NULL; static volatile int oldLI = 0; /* In case we are RESHAPING the window! */ if (DesiredScreen != NULL) free((UnivPtr) DesiredScreen); if (PhysScreen != NULL) free((UnivPtr) PhysScreen); i = oldLI; oldLI = 0; if (Savelines != NULL) { /* Note: each screenline in Savelines has a null s_effects * (or is uninitialized). LEclear must not be applied. */ free((UnivPtr) Savelines); } if (Screen != NULL) { #ifdef HIGHLIGHTING for (ns = Screen; ns != &Screen[i]; ns++) LEclear(ns); #endif free((UnivPtr) Screen); } if (screenchars != NULL) free((UnivPtr) screenchars); /* free all the screen data */ DesiredScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage)); PhysScreen = (struct scrimage *) malloc((unsigned) LI * sizeof (struct scrimage)); Savelines = (struct screenline *) malloc((unsigned) LI * sizeof(struct screenline)); ns = Screen = (struct screenline *) malloc((unsigned) LI * sizeof(struct screenline)); nsp = screenchars = (char *) malloc((size_t)CO * LI); if (DesiredScreen == NULL || PhysScreen == NULL || Savelines == NULL || ns == NULL || nsp == NULL) { writef("\n\rCannot malloc screen!\n"); finish(-1); /* die! */ } for (i = 0; i < LI; i++) { ns->s_line = nsp; /* End of Line (nsp[CO-1] is never used) */ ns->s_roof = nsp + CO - 1; ns->s_effects = NOEFFECT; nsp += CO; ns += 1; /* ??? The following is a fudge to placate Purify. * There is a real bug here, so we squash it with * a sledge hammer. What is the correct fix? */ { register struct scrimage *p; p = &PhysScreen[i]; p->s_offset = 0; p->s_flags = 0; p->s_vln = 0; p->s_id = NULL_DADDR; p->s_lp = NULL; p->s_window = NULL; p = &DesiredScreen[i]; p->s_offset = 0; p->s_flags = 0; p->s_vln = 0; p->s_id = NULL_DADDR; p->s_lp = NULL; p->s_window = NULL; } } oldLI = LI; SO_off(); #ifdef HIGHLIGHTING US_effect(NO); #endif cl_scr(NO); } void clrline(cp1, cp2) register char *cp1, *cp2; { while (cp1 < cp2) *cp1++ = ' '; } /* Output one character (if necessary) at the current position */ #ifdef MAC /* Character output to bit-mapped screen is very expensive. It makes * much more sense to write the entire line at once. So, we print all * the characters, whether already there or not, once the line is * complete. */ private unsigned char sput_buf[255]; private size_t sput_len = 0; private void sput_start() { /* if (i_line != CapLine || i_col != CapCol) */ NPlacur(i_line, i_col); sput_len = 0; } private void sput_end() { if (sput_len != 0) { writetext(sput_buf, sput_len); sput_len = 0; } } private void sputc(c) register char c; { /* if line gets too long for sput_buf, ignore subsequent chars */ if (sput_len < sizeof(sput_buf)) { *cursor++ = c; sput_buf[sput_len++] = (c == '0')? 0xAF /* slashed zero */ : c; CapCol++; i_col++; } } #else /* !MAC */ # ifdef HIGHLIGHTING # define CharChanged(c) (*cursor != (char) (c)) # else /* !HIGHLIGHTING */ private jbool ChangeEffect = NO; # define CharChanged(c) (ChangeEffect || *cursor != (char) (c)) # endif /* !HIGHLIGHTING */ # ifdef IBMPCDOS /* On PC, we think that trying to avoid painting the character * is slower than just doing it. I wonder if this is true. */ # define sputc(c) do_sputc(c) # else /* !IBMPCDOS */ # define sputc(c) { \ if (CharChanged(c)) { \ do_sputc(c); \ } else { \ cursor += 1; \ i_col += 1; \ } \ } # endif /* !IBMPCDOS */ private void do_sputc(c) register char c; { if (CharChanged(c)) { # ifdef ID_CHAR INSmode(NO); # endif if (i_line != CapLine || i_col != CapCol) Placur(i_line, i_col); *cursor++ = c; # ifdef TERMCAP if (UL && c == '_' && *cursor != ' ') putstr(" \b"); /* Erase so '_' looks right. */ # endif scr_putchar(c); AbortCnt -= 1; CapCol += 1; } else { cursor += 1; } i_col += 1; } #endif /* !MAC */ #ifdef HIGHLIGHTING private void (*real_effect) ptrproto((jbool)); private void do_hlsputc(hl, oldhl, c) register const struct LErange *hl; /* desired highlighting */ register const struct LErange *oldhl; /* previous highlighting */ char c; { /* assert: hl != NULL && oldhl != NULL * In other words, hl and oldhl must point to real LErange structs. */ /* The following two initializing expressions use the peculiar * properties of unsigneds to make an efficient range test. */ void (*virtual_effect) ptrproto((jbool)) = (unsigned)i_col - hl->start < hl->width? hl->high : hl->norm, (*underlying_effect) ptrproto((jbool)) = (unsigned)i_col - oldhl->start < oldhl->width? oldhl->high : oldhl->norm; if (*cursor != c || virtual_effect != underlying_effect) { # ifdef ID_CHAR INSmode(NO); # endif if (i_line != CapLine || i_col != CapCol) Placur(i_line, i_col); if (virtual_effect != real_effect) { if (real_effect != NULL) real_effect(NO); /* instantaneously in neutral state */ if (virtual_effect != NULL) virtual_effect(YES); real_effect = virtual_effect; } # ifdef TERMCAP if (UL && c == '_' && *cursor != ' ') putstr(" \b"); /* Erase so '_' looks right. */ # endif *cursor++ = c; scr_putchar(c); AbortCnt -= 1; CapCol += 1; } else { cursor += 1; } i_col += 1; } #endif /* HIGHLIGHTING */ void cl_eol() { if (cursor == Curline->s_line) LEclear(Curline); /* in case swrite was not called (hack!) */ if (cursor < Curline->s_roof) { #ifdef TERMCAP if (CE) { Placur(i_line, i_col); putpad(CE, 1); clrline(cursor, Curline->s_roof); } else { /* Ugh. The slow way for dumb terminals. */ register char *savecp = cursor; while (cursor < Curline->s_roof) sputc(' '); cursor = savecp; } #else /* !TERMCAP */ Placur(i_line, i_col); clr_eoln(); /* MAC and PCSCR define this */ clrline(cursor, Curline->s_roof); #endif /* !TERMCAP */ Curline->s_roof = cursor; } } void cl_scr(doit) jbool doit; { register int i; register struct screenline *sp = Screen; for (i = 0; i < LI; i++, sp++) { LEclear(sp); clrline(sp->s_line, sp->s_roof); sp->s_roof = sp->s_line; PhysScreen[i].s_id = NULL_DADDR; } if (doit) { clr_page(); CapCol = CapLine = 0; UpdMesg = YES; } } /* routines to manage a pool of LErange structs */ #ifdef HIGHLIGHTING union LEspace { struct LErange le; union LEspace *next; }; private union LEspace *LEfreeHead = NULL; private struct LErange * LEnew() { struct LErange *ret; if (LEfreeHead == NULL) { LEfreeHead = (union LEspace *) emalloc(sizeof(union LEspace)); LEfreeHead->next = NULL; } ret = &LEfreeHead->le; LEfreeHead = LEfreeHead->next; return ret; } #endif /* HIGHLIGHTING */ private void LEclear(sl) struct screenline *sl; { #ifdef HIGHLIGHTING if (sl->s_effects != NOEFFECT) { ((union LEspace *) sl->s_effects)->next = LEfreeHead; LEfreeHead = (union LEspace *) sl->s_effects; } #endif /* HIGHLIGHTING */ sl->s_effects = NOEFFECT; } /* Write `line' at the current position of `cursor'. Stop when we * reach the end of the screen. Aborts if there is a character * waiting. * * Note: All callers must have "DeTabed" "line", or processed * it equivalently -- it is presumed that line contains only * displayable characters. */ jbool swrite(line, hl, abortable) register char *line; LineEffects hl; jbool abortable; { register int n = cursend - cursor; jbool aborted = NO; /* Unfortunately, neither of our LineEffects representation * is suitable for representing the state of a partially * updated line. Consequently, this routine unconditionally * replaces the old hl with the new. To ensure that the new * hl is correct, we compute MinCol to indicate how far in * the line we must get, and will not abort until we have * reached at least that column. * * This is unacceptably ugly. We really must switch to a better * representation */ int MinCol = 0; #ifdef HIGHLIGHTING /* If either the old line or the new line has effects, * we know that some effects processing is necessary. * If so, we ensure that the old line has an effect * by adding a no-op effect if necessary: this is needed * to ensure Placur does not get into trouble. (UGLY!) */ struct LErange *oldhl = Curline->s_effects; static const struct LErange nohl = { 0, 0, LENULLPROC, LENULLPROC }; if (oldhl != NOEFFECT) { int w = Curline->s_roof - Curline->s_line; if (oldhl->norm != NULL) MinCol = w; if (oldhl->high != NULL && w > (int)oldhl->start) MinCol = jmax(MinCol, jmin(w, (int) (oldhl->start + oldhl->width))); } /* If either the old line or the new line has effects, * we know that some effects processing is necessary. * If so, we ensure that the old line has an effect * by adding a no-op effect if necessary: this is needed * to ensure Placur does not get into trouble. (UGLY!) */ if (hl != NOEFFECT) { if (hl->high != NULL) MinCol = jmax(MinCol, (int) (hl->start + hl->width)); if (oldhl == NOEFFECT) { oldhl = Curline->s_effects = LEnew(); /* keep Placur on-track */ *oldhl = nohl; } } real_effect = LENULLPROC; #else /* !HIGHLIGHTING */ if (Curline->s_effects != hl) MinCol = Curline->s_roof - Curline->s_line; /* must obliterate old */ #endif /* !HIGHLIGHTING */ if (n > 0) { register ZXchar c; #ifdef HIGHLIGHTING /* nnhl: non-NULL version of hl (possibly * a no-op) to reduce the cases handled. */ const struct LErange *nnhl = hl == NOEFFECT? &nohl : hl; # define spit(c) { if (oldhl != NULL) do_hlsputc(nnhl,oldhl,c); else sputc(c); } #else /* !HIGHLIGHTING */ # define spit(c) sputc(c) # ifdef MAC sput_start(); /* Okay, because no interruption possible */ # else /* !MAC */ if (hl != Curline->s_effects) ChangeEffect = YES; # endif /* !MAC */ if (hl != NOEFFECT) SO_effect(YES); #endif /* !HIGHLIGHTING */ while ((c = ZXC(*line++)) != '\0') { if (abortable && i_col >= MinCol && AbortCnt < 0) { AbortCnt = ScrBufSize; if (PreEmptOutput()) { aborted = YES; break; } } #ifdef TERMCAP if (Hazeltine && c == '~') c = '`'; #endif #ifdef CODEPAGE437 /* ??? Some archane mapping of IBM PC characters. * According to the appendix of the Microsoft MSDOS * Operating System 5.0 User's Guide and Reference, * in Code Page 437 (USA English) ' ', 0x00, and 0xFF are * blank and 0x01 is a face. */ if (c == 0xFF) c = 1; else if (c == ' ' && hl != NOEFFECT) c = 0xFF; #endif /* CODEPAGE437 */ if (--n <= 0) { /* We've got one more column -- how will we spend it? * ??? This is probably redundant -- callers do truncation. */ if (*line != '\0') c = '!'; spit(c); break; } spit(c); } #ifdef HIGHLIGHTING if (real_effect != NULL) real_effect(NO); #else /* !HIGHLIGHTING */ # ifdef MAC sput_end(); /* flush before reverting SO */ # else /* !MAC */ ChangeEffect = NO; # endif /* !MAC */ if (hl != NOEFFECT) SO_off(); #endif /* !HIGHLIGHTING */ if (cursor > Curline->s_roof) Curline->s_roof = cursor; # undef spit } #ifdef HIGHLIGHTING if (hl == NOEFFECT) LEclear(Curline); else *(Curline->s_effects) = *hl; #else /* !HIGHLIGHTING */ Curline->s_effects = hl; #endif /* !HIGHLIGHTING */ return !aborted; } void i_set(nline, ncol) register int nline, ncol; { Curline = &Screen[nline]; cursor = Curline->s_line + ncol; cursend = &Curline->s_line[CO - 1]; i_line = nline; i_col = ncol; } void SO_off() { SO_effect(NO); } #ifdef TERMCAP void SO_effect(on) jbool on; { /* If there are magic cookies, then WHERE the SO string is * printed decides where the SO actually starts on the screen. * So it's important to make sure the cursor is positioned there * anyway. I think this is right. */ if (SG != 0) { Placur(i_line, i_col); i_col += SG; CapCol += SG; cursor += SG; } putpad(on? SO : SE, 1); } # ifdef HIGHLIGHTING void US_effect(on) jbool on; { if (UG == 0) /* not used if magic cookies */ putpad(on? US : UE, 1); } # endif /* HIGHLIGHTING */ #endif /* TERMCAP */ /* Insert `num' lines at top, but leave all the lines BELOW `bottom' * alone (at least they won't look any different when we are done). * This changes the screen array AND does the physical changes. */ void v_ins_line(num, top, bottom) int num, top, bottom; { register int i; /* assert(num <= bottom-top+1) */ /* Blank and save the screen pointers that will fall off the end. */ for(i = 0; i < num; i++) { struct screenline *sp = &Screen[bottom - i]; clrline(sp->s_line, sp->s_roof); sp->s_roof = sp->s_line; LEclear(sp); Savelines[i] = *sp; } /* Num number of bottom lines will be lost. * Copy everything down num number of times. */ for (i = bottom-num; i >= top; i--) Screen[i + num] = Screen[i]; /* Insert the now-blank saved ones at the top. */ for (i = 0; i < num; i++) Screen[top + i] = Savelines[i]; i_lines(top, bottom, num); } /* Delete `num' lines starting at `top' leaving the lines below `bottom' * alone. This updates the internal image as well as the physical image. */ void v_del_line(num, top, bottom) int num, top, bottom; { register int i; /* assert(num <= bottom-top+1) */ /* Blank and save the lines to be deleted from the top. */ for (i = 0; i < num; i++) { struct screenline *sp = &Screen[top + i]; clrline(sp->s_line, sp->s_roof); sp->s_roof = sp->s_line; LEclear(sp); Savelines[i] = *sp; } /* Copy everything up num number of lines. */ for (i = top; i + num <= bottom; i++) Screen[i] = Screen[i + num]; /* Restore the now-blank lost lines */ for (i = 0; i < num; i++) Screen[bottom - i] = Savelines[i]; d_lines(top, bottom, num); } #ifdef TERMCAP /* remainder of this file */ /* The cursor optimization happens here. You may decide that this * is going too far with cursor optimization, or perhaps it should * limit the amount of checking to when the output speed is slow. * What ever turns you on ... */ struct cursaddr { int cm_numchars; void (*cm_proc) (); }; private char *Cmstr; private struct cursaddr *HorMin, *VertMin, *DirectMin; private void ForTab proto((int)), RetTab proto((int)), DownMotion proto((int)), UpMotion proto((int)), GoDirect proto((int, int)), HomeGo proto((int, int)), BottomUp proto((int, int)); private struct cursaddr WarpHor[] = { { 0, ForTab }, { 0, RetTab } }; private struct cursaddr WarpVert[] = { { 0, DownMotion }, { 0, UpMotion } }; private struct cursaddr WarpDirect[] = { { 0, GoDirect }, { 0, HomeGo }, { 0, BottomUp } }; # define FORTAB 0 /* Forward using tabs */ # define RETFORTAB 1 /* Beginning of line and then tabs */ # define NUMHOR 2 # define DOWN 0 /* Move down */ # define UPMOVE 1 /* Move up */ # define NUMVERT 2 # define DIRECT 0 /* Using CM */ # define HOME 1 /* HOME */ # define LOWER 2 /* Lower Line */ # define NUMDIRECT 3 # define home() Placur(0, 0) # define LowLine() { putpad(LL, 1); CapLine = ILI; CapCol = 0; } # define PrintHo() { putpad(HO, 1); CapLine = CapCol = 0; } private void GoDirect(line, col) register int line, col; { putpad(Cmstr, 1); CapLine = line; CapCol = col; } private void RetTab(col) register int col; { scr_putchar('\r'); CapCol = 0; ForTab(col); } private void HomeGo(line, col) int line, col; { PrintHo(); DownMotion(line); ForTab(col); } private void BottomUp(line, col) register int line, col; { LowLine(); UpMotion(line); ForTab(col); } /* Tries to move forward using tabs (if possible). It tabs to the * closest tabstop which means it may go past 'destcol' and backspace * to it. * Note: changes to this routine must be matched by changes in ForNum. */ private void ForTab(to) int to; { if ((to > CapCol+1) && TABS && (phystab > 0)) { register int tabgoal, ntabs, pts = phystab; tabgoal = to + (pts / 2); tabgoal -= (tabgoal % pts); /* Don't tab to last place or else it is likely to screw up. */ if (tabgoal >= CO) tabgoal -= pts; ntabs = (tabgoal / pts) - (CapCol / pts); /* If tabbing moves past goal, and goal is more cols back * than we would have had to move forward from our original * position, tab is counterproductive. Notice that if our * original motion would have been backwards, tab loses too, * so we need not write abs(to-CapCol). */ if (tabgoal > to && tabgoal-to >= to-CapCol) ntabs = 0; while (--ntabs >= 0) { scr_putchar('\t'); CapCol = tabgoal; /* idempotent */ } } if (to > CapCol) { register char *cp = &Screen[CapLine].s_line[CapCol]; # ifdef ID_CHAR INSmode(NO); /* we're not just a motion */ # endif while (to > CapCol) { scr_putchar(*cp++); CapCol++; } } while (to < CapCol) { putpad(BC, 1); CapCol--; } } private void DownMotion(destline) register int destline; { register int nlines = destline - CapLine; while (--nlines >= 0) { putpad(DO, 1); CapLine = destline; /* idempotent */ } } private void UpMotion(destline) register int destline; { register int nchars = CapLine - destline; while (--nchars >= 0) { putpad(UP, 1); CapLine = destline; /* idempotent */ } } private int ForNum proto((int from, int to)); void Placur(line, col) int line, col; { # define CursMin(which,addrs,max) { \ register int best = 0, \ i; \ register struct cursaddr *cp; \ for (cp = &(addrs)[1], i = 1; i < (max); i++, cp++) \ if (cp->cm_numchars < (addrs)[best].cm_numchars) \ best = i; \ (which) = &(addrs)[best]; \ } if (line == CapLine && col == CapCol) return; /* We are already there. */ /* Number of characters to move horizontally for each case. * 1: Try tabbing to the correct place. * 2: Try going to the beginning of the line, and then tab. */ { int dcol = col - CapCol; /* Number of columns to move */ int xtracost = 0; /* Misc addition to cost. */ # ifdef ID_CHAR if (IN_INSmode && MI) xtracost = IMEIlen; /* If we're already in insert mode, it is likely that we will * want to be in insert mode again, after the insert. */ # endif if (dcol == 1 || dcol == 0) { /* Most common case. */ HorMin = &WarpHor[FORTAB]; HorMin->cm_numchars = dcol + xtracost; } else { /* if CapCol is unknown, FORTAB is impossible */ WarpHor[FORTAB].cm_numchars = CapCol == INFINITY? INFINITY : xtracost + ForNum(CapCol, col); WarpHor[RETFORTAB].cm_numchars = xtracost + 1 + ForNum(0, col); /* Which is the shortest of the bunch */ CursMin(HorMin, WarpHor, NUMHOR); } } /* Moving vertically is more simple. */ { int dline = line - CapLine; /* Number of lines to move */ WarpVert[DOWN].cm_numchars = dline >= 0 ? dline : INFINITY; WarpVert[UPMOVE].cm_numchars = dline < 0 ? ((-dline) * UPlen) : INFINITY; } /* Which of these is simpler */ CursMin(VertMin, WarpVert, NUMVERT); /* Homing first and lowering first are considered * direct motions. * Homing first's total is the sum of the cost of homing * and the sum of tabbing (if possible) to the right. */ if (Screen[line].s_effects != NOEFFECT && CM != NULL) { /* We are going to a line with inversion or underlining; * Don't try any clever stuff */ DirectMin = &WarpDirect[DIRECT]; DirectMin->cm_numchars = 0; Cmstr = targ2(CM, col, line); } else if (VertMin->cm_numchars + HorMin->cm_numchars <= 3) { /* Since no direct method is ever shorter than 3 chars, don't try it. */ DirectMin = &WarpDirect[DIRECT]; /* A dummy ... */ DirectMin->cm_numchars = INFINITY; } else { WarpDirect[DIRECT].cm_numchars = CM != NULL ? strlen(Cmstr = targ2(CM, col, line)) : INFINITY; WarpDirect[HOME].cm_numchars = HOlen + line + WarpHor[RETFORTAB].cm_numchars; WarpDirect[LOWER].cm_numchars = LLlen + ((ILI - line) * UPlen) + WarpHor[RETFORTAB].cm_numchars; CursMin(DirectMin, WarpDirect, NUMDIRECT); } if (HorMin->cm_numchars + VertMin->cm_numchars < DirectMin->cm_numchars) { if (line != CapLine) (*(void (*)ptrproto((int)))VertMin->cm_proc)(line); if (col != CapCol) { # ifdef ID_CHAR INSmode(NO); /* We may use real characters ... */ # endif (*(void (*)ptrproto((int)))HorMin->cm_proc)(col); } } else { # ifdef ID_CHAR if (IN_INSmode && !MI) INSmode(NO); # endif (*(void (*)ptrproto((int, int)))DirectMin->cm_proc)(line, col); } } /* Figures out how many characters ForTab() would use to move forward * using tabs (if possible). * Note: changes to this routine must be matched by changes in ForTab. * An exception is that any cost for leaving insert mode has been * accounted for by our caller. */ private int ForNum(from, to) register int from; int to; { register int tabgoal, pts = phystab; int ntabs = 0; if ((to > from+1) && TABS && (pts > 0)) { tabgoal = to + (pts / 2); tabgoal -= (tabgoal % pts); if (tabgoal >= CO) tabgoal -= pts; ntabs = (tabgoal / pts) - (from / pts); /* If tabbing moves past goal, and goal is more cols back * than we would have had to move forward from our original * position, tab is counterproductive. Notice that if our * original motion would have been backwards, tab loses too, * so we need not write abs(to-from). */ if (tabgoal > to && tabgoal-to >= to-from) ntabs = 0; if (ntabs != 0) from = tabgoal; } return ntabs + (from>to? from-to : to-from); } void i_lines(top, bottom, num) int top, bottom, num; { if (CS) { putpad(targ2(CS, bottom, top), 1); CapCol = CapLine = INFINITY; /* actually: unknown */ Placur(top, 0); putmulti(SR, M_SR, num, bottom - top); putpad(targ2(CS, ILI, 0), 1); CapCol = CapLine = INFINITY; /* actually: unknown */ } else { Placur(bottom - num + 1, 0); putmulti(DL, M_DL, num, ILI - CapLine); Placur(top, 0); putmulti(AL, M_AL, num, ILI - CapLine); } } void d_lines(top, bottom, num) int top, bottom, num; { if (CS) { putpad(targ2(CS, bottom, top), 1); CapCol = CapLine = INFINITY; /* actually: unknown */ Placur(bottom, 0); putmulti(SF, M_SF, num, bottom - top); putpad(targ2(CS, ILI, 0), 1); CapCol = CapLine = INFINITY; /* actually: unknown */ } else { Placur(top, 0); putmulti(DL, M_DL, num, ILI - top); Placur(bottom + 1 - num, 0); putmulti(AL, M_AL, num, ILI - CapLine); } } #endif /* TERMCAP */ jove-4.17.5.5/screen.h000066400000000000000000000034611501102521500143420ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef HIGHLIGHTING typedef void(*LEproc) ptrproto((jbool)); #define LENULLPROC (LEproc)0 typedef struct LErange { unsigned start, /* starting column for highlighting */ width; /* width of highlighting */ LEproc norm, high; } *LineEffects; #define NOEFFECT ((LineEffects) NULL) extern void US_effect proto((jbool)); #else /* !HIGHLIGHTING */ typedef jbool LineEffects; /* standout or not */ #define NOEFFECT NO #endif /* !HIGHLIGHTING */ struct screenline { char *s_line, *s_roof; /* character after last */ LineEffects s_effects; }; extern struct screenline *Screen, *Curline; extern char *cursend; extern int AbortCnt, CapLine, /* cursor line and cursor column */ CapCol; extern jbool BufSwrite proto((int linenum)), swrite proto((char *line, LineEffects hl, jbool abortable)); extern LineEffects WindowRange proto((Window *w)); extern void Placur proto((int line,int col)), cl_eol proto((void)), cl_scr proto((jbool doit)), clrline proto((char *cp1,char *cp2)), i_set proto((int nline,int ncol)), make_scr proto((void)), v_ins_line proto ((int num, int top, int bottom)), v_del_line proto ((int num, int top, int bottom)), SO_effect proto((jbool)), SO_off proto((void)); #define TABDIST(col) (tabstop - (col)%tabstop) /* cols to next tabstop */ /* Variables: */ extern int tabstop; /* VAR: expand tabs to this number of spaces */ jove-4.17.5.5/select.h000066400000000000000000000023401501102521500143350ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef USE_SELECT_H # include #endif #ifndef FD_SET /* usually set in sys/types.h (AIX: sys/select.h) */ typedef long fd_set; # ifndef FD_SETSIZE # define FD_SETSIZE 32 # endif # define FD_SET(fd, fdset) (*(fdset) |= (1L << (fd))) # define FD_CLR(fd, fdset) (*(fdset) &= ~(1L << (fd)) # define FD_ISSET(fd, fdset) (*(fdset) & (1L << (fd))) # define FD_ZERO(fdset) (*(fdset) = 0) #endif /* FD_SET */ #ifndef FULL_UNISTD # ifdef USE_PROTOTYPES struct timeval; /* forward declaration preventing prototype scoping */ # endif extern int UNMACRO(select) proto((int /*width*/, fd_set * /*readfds*/, fd_set * /*writefds*/, fd_set * /*exceptfds*/, struct timeval * /*timeout*/)); #endif #ifdef USE_SELECT extern fd_set global_fd; extern int global_maxfd; #endif jove-4.17.5.5/setmaps.c000066400000000000000000000165311501102521500145340ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* * Setmaps runs at build time, which makes life hard for * cross-compilers: we need the tune.h/sysdep.h definitions * for the target machine, i.e. whatever SYSDEFS the makefile * provides, but those may not be appropriate for the host, * which, might be a very different compiler. */ #define USE_STDIO_H 1 #define NO_EXTERNS 1 #include "jove.h" #include "chars.h" #include "commands.h" #include "vars.h" extern void exit proto((int)); #define LINESIZE 100 /* hope this is big enough */ #define STACKLIMIT 10 /* max conditional depth */ #define PROC(p) (cmdproc_t)0 /* discard function pointers */ #include "commands.tab" #define VAR(v) NULL, (size_t)0 /* discard variable pointers */ #include "vars.tab" private int matchcmd(choices, what) register const struct cmd choices[]; register char *what; { register int i; for (i = 0; choices[i].Name != NULL; i++) { if (what[0] == choices[i].Name[0] && strcmp(what, choices[i].Name) == 0) return i; } return -1; } #ifdef MAC matchvar(choices, what) register const struct variable choices[]; register char *what; { register int len; int i; len = strlen(what); for (i = 0; choices[i].Name != NULL; i++) { if (what[0] == choices[i].Name[0] && strcmp(what, choices[i].Name) == 0) return i; } return -1; } #endif private int StartsWith(s, pre) const char *s, *pre; { return strncmp(s, pre, strlen(pre)) == 0; } private char * PPkey(c) int c; { static char str[16]; char *cp = str; if (c & METABIT) { c &= ~METABIT; strcpy(cp, "M-"); cp += 2; } if (c == ESC) { strcpy(cp, "ESC"); } else if (c < ' ') { *cp++ = '^'; *cp++ = c + '@'; *cp = '\0'; } else if (c == DEL) { strcpy(cp, "^?"); } else { *cp++ = c; *cp = '\0'; } return str; } private void extract(into, from) char *into, *from; { from += 2; /* Past tab and first double quote. */ while ((*into = *from++) != '"') into += 1; *into = '\0'; } int main() { FILE *ifile, *of; char line[LINESIZE], comname[LINESIZE]; int comnum, lino, ch; struct { int first; int last; char condition[LINESIZE]; } stackspace[STACKLIMIT], /* first entry not used */ *sp = stackspace; #ifdef MAC char *which; int filecnt = 0; jbool inmenu = NO; struct fname { char *in, *out; }; static const struct fname fnt[] = { { "keys.txt", "keys.c" }, { "menumaps.txt", "menumaps.c" }, { NULL, NULL } }; const struct fname *fnp; #endif /* MAC */ static int cmdidx[IDXSZ], varidx[IDXSZ]; int lastidx = -1, ic; for (comnum = 0; commands[comnum+1].Name != NULL; comnum++) { ic = IDX(commands[comnum].Name[0]); if (ic < 0 || ic >= IDXSZ) { fprintf(stderr, "command %s idx %d is out of range, must be 0..%d\n", commands[comnum].Name, ic, IDXSZ); exit(1); } if (lastidx != ic) { cmdidx[ic] = comnum; lastidx = ic; } if (strcmp(commands[comnum].Name, commands[comnum+1].Name) >= 0) { fprintf(stderr, "command %s is out of order\n", commands[comnum].Name); exit(1); } } lastidx = -1; for (comnum = 0; variables[comnum+1].Name != NULL; comnum++) { ic = IDX(variables[comnum].Name[0]); if (ic < 0 || ic >= IDXSZ) { fprintf(stderr, "variable %s idx %d is out of range, must be 0..%d\n", variables[comnum].Name, ic, IDXSZ); exit(1); } if (lastidx != ic) { varidx[ic] = comnum; lastidx = ic; } if (strcmp(variables[comnum].Name, variables[comnum+1].Name) >= 0) { fprintf(stderr, "variable %s is out of order\n", variables[comnum].Name); exit(1); } } #ifdef MAC /* don't know how to redirect, so we do tricks */ for (fnp = fnt; fnp->in != NULL; fnp++) { printf("setmaps <%s >%s\n", fnp->in, fnp->out); ifile = fopen(fnp->in, "r"); if (ifile == NULL) { perror(fnp->in); exit(1); } of = fopen(fnp->out, "w"); if (of == NULL) { perror(fnp->out); exit(1); } #else /* !MAC */ ifile = stdin; of = stdout; if (ifile == NULL || of == NULL) { fprintf(stderr, "Cannot read input or write output.\n"); exit(1); } #endif /* !MAC */ lino = 0; ch = 0; for (;;) { if (fgets(line, (int)sizeof(line), ifile) == NULL) { if (sp != stackspace) { fprintf(stderr, "EOF inside #if\n"); exit(1); } fclose(of); fclose(ifile); break; } lino += 1; if (StartsWith(line, "/* IDX_TAG")) { int i, idx; fputs("const struct cmd *cmdidx[IDXSZ] = {\n", of); for (i = 0; i < IDXSZ; i++) { if (i == 0 || cmdidx[i] != 0) { idx = cmdidx[i]; fprintf(of, "\t&commands[%d], /* %s */\n", idx, commands[idx].Name); } else { fputs("\tNULL,\n", of); } } fputs("};\nconst struct variable *varidx[IDXSZ] = {\n", of); for (i = 0; i < IDXSZ; i++) { if (i == 0 || varidx[i] != 0) { idx = varidx[i]; fprintf(of, "\t&variables[%d], /* %s */\n", idx, variables[idx].Name); } else { fputs("\tNULL,\n", of); } } fputs("};", of); } else if (StartsWith(line, "#if")) { sp += 1; if (sp == &stackspace[STACKLIMIT]) { fprintf(stderr, "conditionals nested too deeply at line %d\n", lino); exit(1); } sp->first = ch; sp->last = -1; strcpy(sp->condition, line); fputs(line, of); } else if (StartsWith(line, "#else")) { if (sp == stackspace || sp->last != -1) { fprintf(stderr, "ifdef/endif mismatch at line %d!\n", lino); exit(1); } sp->last = ch; ch = sp->first; fputs(line, of); } else if (StartsWith(line, "#endif")) { if (sp == stackspace) { fprintf(stderr, "ifdef/endif mismatch at line %d!\n", lino); exit(1); } if (sp->last != -1 && ch != sp->last) { fprintf(stderr, "warning: unbalanced number of entries in #if ending at line %d", lino); } sp -= 1; fputs(line, of); #ifdef MAC } else if (StartsWith(line, "#MENU")) { inmenu = YES; #endif } else if (StartsWith(line, "\t\"")) { extract(comname, line); if (strcmp(comname, "unbound") == 0) { comnum = -1; } else { comnum = matchcmd(commands, comname); #ifdef MAC which = "commands"; if (comnum < 0 && inmenu) { comnum = matchvar(variables, comname); which = "variables"; } #endif if (comnum < 0) { fprintf(stderr, "warning: cannot find \"%s\", line %d", comname, lino); if (sp == stackspace) { fprintf(stderr, ".\n"); } else { /* Note: condition ends with \n */ fprintf(stderr, ", inside%s %s", sp->last == -1? "" : " else of", sp->condition); } } } #ifdef MAC if (inmenu) { if (comnum < 0) fprintf(of, "\t(data_obj *) NULL,\n"); else fprintf(of, "\t(data_obj *) &%s[%d],\n",which, comnum); } else /*...*/ #endif { if (comnum < 0) fprintf(of, "\t(data_obj *) NULL,\t\t/* %s %s */\n", PPkey(ch), comname); else fprintf(of, "\t(data_obj *) &commands[%d],\t/* %s %s */\n", comnum, PPkey(ch), comname); ch += 1; } } else { /* If unrecognized, pass and prepare to start new table */ fputs(line, of); ch = 0; } } #ifdef MAC } #endif return 0; } jove-4.17.5.5/style.txt000066400000000000000000000051531501102521500146130ustar00rootroot00000000000000This is a catalogue of coding conventions used in JOVE. It is incomplete -- we only list ones that are surprising or needed to be corrected in contributions. Much can be inferred by reading the code. Consistency is valued. Bugs in an editor are very bad. Top priority is given to correctness. We try to code in a way that lets the compiler detect problems (lint). One consequence is that we try to eliminate things that cause warnings, even if they are correct. Misbehaving on bad input counts as a bug -- buffer overruns are to be protected against. Indentation is done by tabs. Since 8 columns per indentation level is excessive, we recommend setting the "tab-width" variable to 4. You are using JOVE to edit JOVE, right? C allows you to increment or decrement a variable using ++ or --. If the expression's value is not going to be used, we avoid these operators. Instead of the statement i++; write i += 1; Jon felt strongly about this. JOVE is intended to be highly portable. It supports many ancient systems. We cannot assume anything beyond K&R C. We cannot assume POSIX. Some features of each are valuable enough that we use conditional compilation to let us exploit them. Many odd parts of JOVE are scar tissue from portability battles. We try to document these. Don't assume that odd code is pointless. All functions (except ones with a variable number of arguments) are defined in the old style; all other declarations include prototypes using the proto and ptrproto macros. All functions are declared before use. Remember that a definition is a kind of declaration. All extern functions that we define are also declared in a header. There are no other declarations of this function. The header is included in the file defining the function so that the compiler can check that the two declarations are consistent. Use "const" and "void" wherever appropriate. Use "NULL" wherever appropriate. Use '\0' as the NUL character (not 0). We define and use "bool", "YES", and "NO". In a switch statement, if a case is meant to fall through into another, add the comment /*FALLTHROUGH*/. This tells the reader (and a certain C compiler) that the lack of "break;" is intentional. The comment /*NOTREACHED*/ specifies that control will not reach this point. JOVE tries to be small and simple, but not too simple. Historically, it could run on a PDP-11 with only 64K of memory for code and 64K for data. Simplicity means that it can be understood completely. JOVE does not use stdio. Historically, stdio didn't provide facilities that were worth the cost. This may no longer be the right tradeoff, but changing would be disruptive. jove-4.17.5.5/sysdep.h000066400000000000000000000343171501102521500143760ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* * System Feature Selection: describe OS and C system to JOVE. See sysdep.txt * for a better description of what the different #define feature symbols * mean. If you add new ones, please keep the syntax of the first #ifdef, so * that "grep System: sysdep.h" catches the first line of all symbols. * See old/sysdep.h for historical symbols for untested systems that once * worked. */ /* The modern *BSD family all have slightly different quirks */ #ifdef NetBSD /* System: modern NetBSD, sigh, TIOCREMOTE does not work, see iproc.c comment */ # define XBSD 1 # define NO_TIOCREMOTE 1 # define PNAME_SYSCTL_OID {CTL_KERN,KERN_PROC_ARGS,-1,KERN_PROC_PATHNAME} #endif #if defined(FreeBSD) || defined(DragonFly) /* System: modern FreeBSD, needs HAVE_LIBUTIL_H */ # define XBSD 1 # define HAVE_LIBUTIL_H 1 # define SPELL "aspell list < %s | sort -u" # define PNAME_SYSCTL_OID {CTL_KERN,KERN_PROC,KERN_PROC_PATHNAME,-1} #endif #if defined(OpenBSD) || defined(Darwin) || defined (XBSD) /* System: modern OpenBSD, Darwin Mac OSX */ # define BSDPOSIX_STDC 1 # define USE_OPENPTY 1 #endif #if defined(SunOS) /* System: SunOS 5.1 aka Solaris 2.1 onwards, including Illumos/Joyent/OpenSolaris/OpenIndiana */ # define SYSVR4 1 # define PNAME_GETEXECNAME 1 #endif #if defined(XLINUX) /* * System: Some Linux e.g. Debian 9 and earlier. Very old Linux (e.g. before * RedHat6) used BSD-compatible pty handling so BSDPOSIX_STDC is better for * those. Middle-aged Linux (e.g. upto Debian 9) seemed to work better with * SYSVR4 and _XOPEN_SOURCE defined. Modern Linux (e.g. Debian 10 on) works * better with GLIBCPTY, since they have openpty in libutil, and pty.h. */ # define SYSVR4 1 # ifndef _XOPEN_SOURCE # define _XOPEN_SOURCE 500 # endif # define SPELL "aspell list < %s | sort -u" # define PNAME_PROC_SELF 1 #endif #if defined(CYGWIN) || defined(CYGWIN32) /* System: Cygwin POSIX-like environment on Windows (see README.cyg) */ # define FILENAME_CASEINSENSITIVE 1 # define GLIBCPTY 1 # define O_TRUNC_BROKEN 1 /* see fp.c */ # define SPELL "aspell list < %s | sort -u" # define JTC 1 /* no real point using curses for Cygwin, surely?! */ #endif #if defined(Linux) || defined(GNU) || defined(GLIBCPTY) /* * modern glibc e.g. Linux, Cygwin) provides openpty and pty.h * so this is also Linux alternative. Also GNU Debian Hurd. */ # define USE_OPENPTY 1 /* older Cygwin may not have openpty? */ # define HAVE_PTY_H 1 # define BSDPOSIX_STDC 1 # define PNAME_PROC_SELF 1 #endif #ifdef MINGW /* System: MinGW cross-compilation for Windows WIN32 (see README.w32) */ # define WIN32 1 # define POSIX_UNISTD 1 # define NO_MKSTEMP 1 /* MKSTEMP on Windows unlinks the filename, which Jove uses for filters */ #endif #ifdef OWCDOS /* System: Open Watcom C 1.9 for x86 running MSDOS (see README.dos) */ # define IBMPCDOS 1 # define REALSTDC 1 /* close enough for us, but ZTCDOS doesn't define __STDC__ */ # define FULL_UNISTD 1 #endif #ifdef _MSC_VER /* System: Microsoft C for the IBM-PC under MSDOS or WIN32 (see README.dos or README.w32) */ /* 4.16.0.38 tested under VC++ 5.0 / VS 97 */ /* 4.16.0.62 tested under Visual C++ 6.0 SP5 */ /* 4.17.x.x tested under Visual Studio 2019 Community Edition */ # if defined(_WIN32) && !defined(WIN32) # define WIN32 _WIN32 # endif # ifndef WIN32 /* ! WIN32 => MSDOS, worked pre-MSVC 7.x */ # define IBMPCDOS 1 # endif # define NO_MKSTEMP 1 # define _POSIX_ 1 /* suppresses MS's min and max in VC++ 5.0 */ # define jmode_t int /* no mode_t on WIN32 */ #endif /**************************************************************************/ /* Some very common collectons of capabilities, used by many defs above */ #ifdef BSDPOSIX_STDC /* Same as BSDPOSIX, but with a Standard enough C */ /* System: BSDI, 386BSD, BSD4.4, NetBSD -- BSDPOSIX_STDC */ /* System: Old LINUX (MCC-Interim release) -- BSDPOSIX_STDC */ # define REALSTDC 1 # define BSDPOSIX 1 #endif #ifdef BSDPOSIX /* System: Posix system with BSD flavouring for ptys */ /* System: SunOS4.1.3, DEC Ultrix 4.2 -- BSDPOSIX */ /* System: DEC OSF/1 V1.3 -- BSDPOSIX + NO_TIOCREMOTE + NO_TIOCSIGNAL */ # define TERMIOS 1 # define USE_GETCWD 1 # define FULL_UNISTD 1 # define USE_SELECT 1 # if !defined(PIPEPROCS) && !defined(NO_IPROCS) /* useful to test PIPEPROCS even on pty platforms */ # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # endif # define POSIX_PROCS 1 # define POSIX_SIGS 1 # define JOB_CONTROL 1 # define BSD_SETPGRP 1 # define USE_KILLPG 1 # define USE_GETPWNAM 1 # define USE_GETHOSTNAME 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 # ifndef ISO_8859_1 /* fudge for __convex__ (see above) */ # define USE_CTYPE 1 # endif #endif #ifdef SYSVR4 /* System: System V, Release 4 and derivatives */ /* System: Consensys V4 -- use SYSVR4 and GRANTPT_BUG */ /* System: DEC OSF/1 V2.0 or later -- use SYSVR4 */ /* System: DEC OSF R1.3MK -- use SYSVR4 */ /* System: Digital UNIX V4.0 and later -- use SYSVR4 and GRANTPT_BUG */ /* System: Solaris 2.0, SunOS 5.0 -- use SYSVR4 and GRANTPT_BUG */ /* System: Solaris 2.x onwards, SunOS 5.x, OpenIndiana/Illumos/Joyent -- use SYSVR4 */ /* Note: some versions of System V Release 4 have a bug in that affects * interactive processes. Examples include Consensys V4 and SunOS 5.0 * also known as Solaris 5.0. See the description of GRANTPT_BUG in * sysdep.txt. It turns out that this bug is documented as a feature * in "The Single UNIX Specification", Version 2! */ # define TERMIOS 1 # define USE_GETCWD 1 # define FULL_UNISTD 1 # define USE_SELECT 1 # if !defined(PIPEPROCS) && !defined(NO_IPROCS) /* useful to test PIPEPROCS even on pty platforms */ # define PTYPROCS 1 # define SVR4_PTYS 1 # endif # define POSIX_PROCS 1 # define POSIX_SIGS 1 # define JOB_CONTROL 1 # define USE_UNAME 1 # define USE_GETPWNAM 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define HAS_SYMLINKS 1 # define REALSTDC 1 # define USE_CTYPE 1 #endif #ifdef BSD4 /* System: Berkeley BSD4.x, 2.x, MIPS RiscOS 4.x */ /* MIPS needs -systype bsd43, older releases (before 4.50?) may need * MIPS_CC_BUG defined as well. */ # define SGTTY 1 # define USE_GETWD 1 # define USE_SELECT 1 # define PTYPROCS 1 # define BSD_PTYS 1 /* beware security flaw! */ # define BSD_WAIT 1 # define WAIT3 1 # define BSD_SIGS 1 # define JOB_CONTROL 1 # define USE_VFORK 1 # define BSD_SETPGRP 1 # define USE_KILLPG 1 # define BSD_DIR 1 # define HAS_SYMLINKS 1 # define SIGRESTYPE int # define SIGRESVALUE 0 # define USE_GETHOSTNAME 1 # define NO_STRERROR 1 # define USE_FSYNC 1 # define USE_FSTAT 1 # define USE_FCHMOD 1 # define USE_BCOPY 1 # define USE_INDEX 1 # define jmode_t int #endif /**************** Common Characteristics ****************/ #ifdef pdp11 /* On the PDP-11, UNIX allocates at least 8K for the stack. * In order not to waste this space, we allocate * a bunch of buffers as autos. */ # define AUTO_BUFS 1 #endif #ifdef IBMPCDOS /* Common characteristics for IBM-PC MS-DOS systems. */ # ifndef MSDOS # define MSDOS 1 # endif # define PCNONASCII 0xFF /* prefix for peculiar IBM PC key codes */ # define NO_JSTDOUT 1 /* don't use jstdout */ # define CODEPAGE437 1 /* Code Page 437 English display characters */ # define PCSCRATTR 1 /* exploit IBMPC screen attributes */ # define HIGHLIGHTING 1 /* highlighting is used for mark and scrollbar */ # define MALLOC_CACHE 1 /* DGROUP gets full otherwise */ # define JSMALL 1 /* less than 64K lines fit in memory anyway */ # define FAR_LINES 1 /* to squeeze larger files, use far line pointers */ # if defined(M_I86SM) || defined(__SMALL__) || defined(M_I86CM) || defined(__COMPACT__) /* try small or compact memory model: currently 20K over the 64K code+data limit, so not really viable */ # define BAREBONES 1 # endif # if defined(M_I86LM) || defined(__LARGE__) /* large memory model */ # define LG_JBUFSIZ 11 /* so JBUFSIZ (and max line len) 2048 chars */ # define NBUF 30 /* NBUF*JBUFSIZ must be less than 64K. Is this true even if MALLOC_CACHE is set? */ # endif #endif #ifdef MSDOS /* Common characteristics for MS-DOS systems. */ # define MSDOS_PROCS 1 /* spawn et al */ # define FILENAME_CASEINSENSITIVE 1 # define USE_CRLF 1 # define DIRECTORY_ADD_SLASH 1 # define MSFILESYSTEM 1 #endif #ifdef WIN32 /* Common characteristics for WIN32 systems. */ # define REALSTDC 1 /* MS C only defines __STDC__ if you use /Za */ # define WINRESIZE 1 # define PCNONASCII ((unsigned char)0xFF) /* prefix for peculiar IBM PC key codes */ # define NO_JSTDOUT 1 /* don't use jstdout */ # define CODEPAGE437 1 /* Code Page 437 English display characters */ # define PCSCRATTR 1 /* exploit IBMPC screen attributes */ # define HIGHLIGHTING 1 /* highlighting is used for mark and scrollbar */ # define MSDOS_PROCS 1 /* spawn et al */ # define FILENAME_CASEINSENSITIVE 1 # define USE_CRLF 1 # define DIRECTORY_ADD_SLASH 1 # define MSFILESYSTEM 1 # ifdef _WIN64 /* the only 64bit arch where unsigned long != unsigned long long */ # define DADDR unsigned long long # endif #endif /* The operating system (MSDOS, WIN32, or MAC) must be defined by this point. */ #if !(defined(MSDOS) || defined(WIN32) || defined(MAC)) # define UNIX 1 /* default to UNIX */ #endif #ifdef UNIX /* Common characteristics for UNIX systems. */ /* Our defaults tend to be conservative and lean towards pure SYSV */ # define USE_INO 1 # define TERMCAP 1 # define NCURSES_BUG 1 /* almost certainly safe anyway */ # define WINRESIZE 1 # define MOUSE 1 # define MALLOC_CACHE 1 # if !(defined(USE_PWD) || defined(USE_GETCWD) || defined(USE_GETWD)) # define USE_GETWD 1 # endif # if !(defined(NO_IPROCS) || defined(PIPEPROCS) || defined(PTYPROCS)) # define PIPEPROCS 1 /* use pipes */ # endif # if !defined(TERMIOS) && !defined(SGTTY) # define TERMIO 1 /* uses termio struct for terminal modes */ # endif /* At the moment, the PTY code mandates having select(). One day, this might * change. */ # if defined(PTYPROCS) && !defined(USE_SELECT) sysdep.h: Sorry, PTYPROCS requires the select() system call. You must either define USE_SELECT or undefine PTYPROCS. # endif # if defined(SIGCLD) && !defined(SIGCHLD) # define SIGCHLD SIGCLD # endif # ifndef USE_EXIT # define EXIT _exit /* so linker does not drag in all of stdio for static linking */ # endif #endif /* UNIX */ #ifndef EXIT # define EXIT exit #endif /* lint suppression macros; GCC requires use of extensions! Clang mimics. */ #if !defined(GCC_LINT) && (defined(__GNUC__) || defined(__clang__)) # define GCC_LINT #endif #ifdef GCC_LINT # define UNUSED(x) x __attribute__ ((unused)) # define NEVER_RETURNS __attribute__ ((noreturn)) #else /* !GCC_LINT */ # define UNUSED(x) x # define NEVER_RETURNS #endif /* !GCC_LINT */ /************************************************************************* * * The things below here aren't meant to be tuned, but are included here * because they're dependent on the things defined earlier in the file. */ #ifdef USE_BCOPY # define byte_copy(from, to, len) bcopy((UnivConstPtr)(from), (UnivPtr)(to), (size_t)(len)) # define byte_move(from, to, len) byte_copy(from, to, len) # define byte_zero(s, n) bzero((UnivPtr)(s), (size_t)(n)) #endif #ifndef byte_copy # ifdef USE_MEMORY_H # include # endif # define byte_copy(from, to, count) memcpy((UnivPtr)(to), (UnivConstPtr)(from), (size_t)(count)) # define byte_move(from, to, count) memmove((UnivPtr)(to), (UnivConstPtr)(from), (size_t)(count)) # define byte_zero(s, n) memset((UnivPtr)(s), 0, (size_t)(n)) #endif #ifdef USE_INDEX # define strchr index # define strrchr rindex #endif #ifdef FULL_UNISTD # define POSIX_UNISTD 1 #endif /* JSSIZE_T: result type of read() and write() */ #ifdef FULL_UNISTD # define JSSIZE_T ssize_t #endif #ifndef JSSIZE_T # define JSSIZE_T int #endif /* jmode_t: the type for file modes * Really old systems might use "int" or perhaps "unsigned". */ #ifndef jmode_t # define jmode_t mode_t #endif /* Determine if really ANSI C */ #ifdef __STDC__ # if __STDC__ > 0 # define REALSTDC 1 # endif #endif #ifndef SIGRESTYPE /* default to void, correct for most modern systems */ # define SIGRESTYPE void # define SIGRESVALUE /*void!*/ #endif #ifndef EOL # define EOL '\n' /* end-of-line character for files */ #endif #ifdef JSMALL /* * On small memory/no-VM machines, save as much data space * as we can. Going to hit either Out of lines, Tmp file * too large, or Out of memory (for open files) at some * point, alas. */ # ifndef DADDR # define DADDR unsigned short # endif # define LG_FILESIZE 7 /* log2 maximum path length (including '\0'): currently, 2+1+64+3+1+3+1 == 80 ought to be OK */ # define MAXCOLS 132 /* maximum number of columns */ # define MAXTTYBUF 512 /* maximum size of output terminal buffer */ # ifndef LG_JBUFSIZ # define LG_JBUFSIZ 9 /* temp file block size, also maximum line length. 512 bytes is the traditional UNIX block size */ # endif # ifndef NBUF # define NBUF 3 /* number of temp file blocks to cache in memory, NBUF*JBUFSIZ is big part of JOVE memory footprint */ # endif #else /* * On most modern machines (VM, or lots of memory), use * slightly more generous buffer sizes to improve speed * and/or convenience. */ # ifndef DADDR # define DADDR unsigned long # endif # define LG_FILESIZE 9 /* log2 maximum path length (including '\0') */ # define MAXCOLS 1024 /* maximum number of columns */ # define MAXTTYBUF 4096 /* maximum size of output terminal buffer */ # ifndef LG_JBUFSIZ # define LG_JBUFSIZ 15 /* temp file block size, also maximum line length, 32K seems better for modern VM machines */ # endif # ifndef NBUF # define NBUF 64 /* number of temp file blocks to cache in memory, NBUF*JBUFSIZ is big part of JOVE memory footprint */ # endif #endif /* !JSMALL */ /* DADDR must be >= sizeof(void *), wish everyone had stdint and intptr_t */ typedef DADDR daddr; /* index of line contents in tmp file, see temp.h and disp.h. */ #define JBUFSIZ (1 << LG_JBUFSIZ) #define FILESIZE (1 << LG_FILESIZE) jove-4.17.5.5/sysdep.txt000066400000000000000000000570101501102521500147610ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## Jove has two classes of ifdefs. Some are used to select system-dependent features, others are to select Jove features. The former are defined in sysdep.h, the latter in tune.h. This file describes the ones in sysdep.h. sysdep.h is structured as a set of #ifdefs for different systems, each system being identified by some unique symbol, recently, the result of the uname command on an OS, for convenience. (e.g. Linux, Darwin, FreeBSD etc, but previously, SYSVR4 for various System V Release 4 machines). old/sysdep.h, not used by any Jove code, is a historical archive of definitions that were once tested on various machines, but have not been tested for the recent release, so it is entirely possible that changes for other systems have caused those older definitions to stop working. We usually avoid symbols pre-defined by the compilers, they're too hard to predict and often do not provide the granularity that's necessary to differentiate between system versions or types. There's also sometimes a variety of compilers with different pre-defined symbols. If the system you run is included in sysdep.h, just use it. If not, select a symbol to define your system (e.g. SOMEOS) and choose the appropriate system-dependent options that characterize your systems terminal handling, process handling, header files, etc from the list below. Using an existing system, or common group of characteristics (XBSD, BSDPOSIX_REALSTDC, etc) is often a good start. NOTE: We've removed almost all the "#ifdef system-type" ifdefs from the body of Jove code, replacing those with the feature ifdefs documented below. This sort of approach is necessary in this day & age of hybrid systems. If you're porting Jove to a new system, please follow the feature-based approach and don't put "#ifdef system-type" ifdefs in the code. For terminal handling under Unix, define one of the following, in decreasing order of preference. TERMIOS Have "struct termios" and termios.h. POSIX systems, most modern UNIXes. SGTTY Have stty() and gtty() for tty characteristics. BSD4.3 and precursors, including V7. TERMIO Have "struct termio" and termio.h for tty characteristics. System V derivatives. Warning: if your system supports BSD-style Job Control, don't use TERMIO: it cannot suppress the action of some magic characters. SunOS4 sys/ioctl.h conflicts seriously with termios.h, so it needs NO_IOCTL_H_TTY Jove needs to know the current working directory for pathname optimization and the directory functions that it provides ("cd", "pushd", etc). Define one of the following, in order of decreasing preference: USE_GETCWD have the getcwd() routine for the name of the current directory. POSIX. USE_GETWD have the getwd() routine for the name of the current dir. BSD4.2 and derivatives (SunOS3, old Ultrix) USE_PWD Run the 'pwd' program to find the name of the current directory. Old UNIXes. When Jove is tries to make file pathnames canonical. Handling of a .. component must take account of symbolic links. All modern UNIXes have symlinks. We don't yet know how to support MAC or WIN32 aliases. HAS_SYMLINKS use readlink(2) to handle symlinks In order to canonicalize SHAREDIR and LIBDIR paths relative to the executable directory, Jove needs to figure out where the exectutable ran from. PNAME_PROC_SELF should be defined on Linux-like machines (or Debian Hurd) since they have /proc/self/exe as a symlink to the running executable path. PNAME_GETEXECNAME should be defined on Solaris-like machines which have the getexecname() function to return the running executable path. PNAME_SYSCTL_OID should be defined on FreeBSD or NetBSD, with the oid array that can be given to sysctl() to return the path to the running executable. If the above do not exist, it will use argv[0] and hope for the best. Jove needs to make a number of temporary files. The traditional ways of creating temp files are subject to race conditions allowing security to be compromised on multi-user systems. The mkstemp library routine avoids this problem, but isn't available on all systems. In its place, Jove will make do by using mktemp. If this isn't available, Jove will use an even poorer technique. The mktemp form is safe if the open system call supports O_EXCL just right (it must balk at symlinks). NO_MKSTEMP work around lack of mkstemp NO_MKTEMP work around lack of mktemp If the compiler is ANSI C, then prototyping will be supported automatically (this is determined by checking that __STDC__ is defined (by the system), and it is greater than 0). For other systems, you may define: USE_PROTOTYPES for non-ANSI systems that nevertheless support prototypes NO_PTRPROTO for systems that botch prototypes in function pointer decls. STDARGS for non-ANSI systems that nevertheless support stdargs.h, as opposed to varargs.h MIPS_CC_BUG avoid function definition syntax that provokes a MIPS cc bug. This bug manifests itself as compiler complaints around the extern declarations that have parentheses around them. (e.g. select). One version of the error looks like this: externs.h, line 145: ccom: Internal: compiler takes size of function MIPS-based Ultrix upto 4.2 at least, RiscOS and IRIX (upto 3.3 at least) need this. Newer systems tend to have header files with more system calls defined, sometimes with prototypes. Choose one of the following, depending on your system. If neither of the following is defined, then the declarations in externs.h are used. POSIX_UNISTD Have POSIX P1003.1 compliant unistd.h with declarations. FULL_UNISTD Have fully-prototyped header files, superset of POSIX P1003.1 Some really old systems may not have a header . To stop JOVE trying to #include it, define NO_FCNTL no header provided by system Usually, the result type returned by read() and write() is int. POSIX carefully defines a type name for this type: ssize_t (it logically is a size_t, but it must be signed because -1 is a possible value). We use SSIZE_T which defaults to ssize_t if FULL_UNISTD, otherwise int. This can be overridden by defining SSIZE_T. In modern systems, the type mode_t is used for permission bits (in creat(2), stat(2), and open(2)). In ancient systems, this was just int; unsigned would have been better. Jove uses the macro jmode_t. If you don't provide a definition, it defaults to mode_t. Different environments have different memory and address space limitations. Generally, these controls default appropriately. NBUF Number of memory blocks allocated to cache for buffers. LG_JBUFSIZ log-base-2(sizeof buffer block). Generally 9 or 10, yielding blocks of size 512 or 1024 bytes. Each text line in Jove is restricted to fit within a single block, so larger is better. Also, larger blocks should reduce the number of blocks transferred between the temp file and RAM. Smaller blocks reduce the number of bytes transferred and more efficiently use cache memory (there would be more blocks in an identically sized cache). JSMALL Intended for machines with small address spaces, for example the PDP-11 and DOS 8086/8088. It drastically reduces NBUF, cuts down LG_JBUFSIZ, and makes daddr an unsigned short. MALLOC_CACHE Causes the in-core cache for disk blocks to be malloced rather than allocated as a static variable. This helps environments where statically allocated things are placed in one limited segment, but malloced things are placed in separate segments. Examples include MAC and large model x86. Remember that NBUF * ((1< instead of (FreeBSD) HAVE_PTY_H use instead of (Cygwin, glibc, Interix, OSF/1 4 and 5) Certain early SVR4 systems have a buggy grantpt library routine that is used if PTYPROCS is defined. A symptom is that the "shell" command will always fail with a [grantpt failed] message. System V Release 4.0, and Solaris 2.0 (but not Solaris 2.3) and Digital UNIX 4.0 have this bug. It turns out that this bug is documented as a feature in "The Single UNIX Specification", Version 2! GRANTPT_BUG Define this to enable a work-around. Certain systems, for example NetBSD (at least 7.x and 8.x), IRIX 4 and IRIX 5.3, define the symbol TIOCREMOTE but don't implement this ioctl correctly. A symptom is that the eof-process command will not work. NO_TIOCREMOTE Define this to avoid using TIOCREMOTE even if the system defines it. Certain systems, for example IRIX 5.3, define the symbol TIOCSIGNAL but don't implement this ioctl correctly. A symptom is that the interrupt-process command will not work. NO_TIOCSIGNAL Define this to avoid using TIOCSIGNAL and TIOCSIG even if system defines them. Certain systems, for example HP/UX 9, don't seem to send EOF to the master side of the pty when the slave side shuts down. On these systems, Jove should be told not to wait for EOF: NO_EOF_FROM_PTY Define this if your system fails to signal EOF to pty master To deal with SUBSHELL and IPROCS (both in tune.h), define one of the following: POSIX_PROCS Supports POSIX processes, waitpid() BSD_WAIT Has sys/wait.h and "union wait". If neither POSIX_PROCS nor BSD_WAIT is defined, Jove uses wait(). (old UNIXes) If BSD_WAIT was defined, also consider defining WAIT3 use wait3() on systems that have it. (BSD4.2 and modern non-POSIX UNIXes). If this is not defined, we try wait2(). Signal handling varies between systems. The original UNIX signal mechanism is unsafe -- if a second signal is received soon enough, the program will crash. Furthermore, there is no mechanism for a process to request that signal delivery be held temporarily. BSD, System V, and POSIX have each provided better but different facilities. Without safe signals, Jove might crash, although this is not common. Jove will use signal holding to more gracefully handle SIGINTs while starting processes; otherwise those SIGINTs will be ignored. The feature select macros, in decreasing order of preference are: POSIX_SIGS Use POSIX's safe sigaction(); use sigprocmask() for signal holding. USE_SIGSET Use sigset(), 4.2BSD's safe signal mechanism. Use sighold() and sigrelse() for signal holding. BSD_SIGS Use 4.x BSD's safe signal(); use for sigsetmask() for holding. If none of these symbols is defined, unsafe normal signals are used (except on BSD systems, where the normally unsafe signal() is in fact safe). JOB_CONTROL System supports job control (SIGTSTP, ^Z etc. for pause-jove) USE_VFORK system has a vfork that is much faster than fork. This capability should be nuked (any modern copy-on-write memory implementation should be able to do fork almost as fast as vfork)! It is only believed to be useful for architectures without an MMU (we welcome test reports) The following are only needed for IPROCS. BSD_SETPGRP setpgrp takes two arguments. If this is not defined, assume System V setpgrp with no arguments. USE_KILLPG Uses the BSD killpg() system call. If this is not defined, Jove assumes that kill(-pid, ...) is equivalent (SysV). If F_COMPLETION is defined, then Jove needs to be able to scan directories. By default, Jove assumes the system has "struct dirent" and "dirent.h". If not, define one of the following BSD_DIR has "struct direct" and "sys/dir.h". BSD4.2. (maybe 4.1?) DIRENT_EMULATE emulate dirent routines by open()ing and read()ing the directory. M_XENIX Support for some versions of XENIX, dealing with peculiarities of directory handling. Not recently tested. If F_COMPLETION is defined, and you want ~username to be expanded, then you may need to define the following, especially on systems running YP/NIS, or using a database form of the password file. USE_GETPWNAM has the getpwnam() system call. Just about every modern Unix. Choose the type of signal handler. If you don't define these, Jove defaults to "void" and "/*void!*/". SIGRESTYPE the return type of signal handlers. "void" on most modern systems, "int" on older systems. SIGRESVALUE the return value of signal handlers. "/*void!*/" on systems where SIGRESTYPE is "void", usually 0 on systems where SIGRESTYPE is "int". Either of following two is useful to the "recover" program, but not both. USE_UNAME has the uname() system call. True on System V and POSIX and most hybrids. USE_GETHOSTNAME has gethostname() system call. True on most BSD machines. NO_STRERROR If you do not have the strerror() routine. Needed for pre-ANSI systems (SunOS older than 4.1, BSD, older UNIXes) With this defined, Jove provides an emulation using sys_errlist, which should work on most UNIXes. USE_FSYNC Have the fsync() system call. True on just about all modern UNIXes. Used to ask the OS to really flush the file to disk. If BIFF is defined, you can usefully define either or both of the following: USE_FSTAT Have the fstat() call. Just about every modern Unix does. USE_FCHMOD Have the fchmod() call. Again, true on most modern UNIXes after BSD4.2. Jove supports 7-bit or 8-bit character sets. It has a wired-in notion of what each kind of character is, but it can use the system's classification of control characters. NCHARS the number of distinct character codes. This defaults to 256 but can be set to 128 for 7-bit character sets. USE_CTYPE use the system's functions. If this is defined and these functions only work for 7-bit characters, be sure to define NCHARS to be 128 NO_SETLOCALE define if you wish to define USE_CTYPE but the system has no setlocale routine. ISO_8859_1 use wired-in tables reflecting the characteristics of the ISO 8859-1 character set (Latin1) (USE_CTYPE is better if it works). For the IBM PC under MSDOS, look below for the description of CODEPAGE437. There is a wired-in table for the Macintosh used if MAC is defined. DEBUGCRASH Do not trap on SEGV, BUS signals, useful for running Jove under a debugger (e.g. gdb, dbx) DEFINE_PC_BC_UP_OSPEED Certain variables used by termcap/terminfo are declared in the library on almost all systems. For those systems that don't define them, this macro enables declarations within Jove. Needed for HPUX and possibly other SysV Rel.2 machines. If you get messages like "ospeed undefined" when linking, try this. USE_MEMORY_H include memory.h for declarations of memcpy() et al. Older SysV, IBMPCs, XENIX. USE_BCOPY use bcopy in place of missing memcpy. BSD4.2 and precursors from Berkeley. USE_INDEX use index in place of missing strchr. BSD4.2 and precursors, including V7. USE_INO use the inode number (and device number) to tell if two paths refer to the same file or directory. Automatically defined for UNIX. Supported for MAC too. USE_EXIT Normally, Jove exits by calling _exit, to avoid stdio. When this symbol is defined, exit() is used instead. This is needed when profiling Jove or running it under debugging tools like purify. UNIX This is automatically defined if we're none of MAC, MSDOS or WIN32. TERMCAP Support display diversity via termcap database. This is automatically defined for UNIX. TERMINFO Support for System V variant of TERMCAP. TERMCAP must also be defined. This differentiates between tparm and tgoto. JTC Simple builtin-termcap emulation, avoids need for external library dependency on termcap/terminfo/*curses*. TERMCAP must also be defined. The OS must support select(), which is used for timing delays. Only works on vt[123]NN or compatible terminals, or emulators like xterm/rxvt/st/vte etc. The environment variable JOVEVT can be set to the level of emulation, the number of the DEC terminal (e.g. 100 for vt100, 102 for vt102, etc, and 999 or "alt" for xterm-like emulators that support the alternate screen. 99 means ordinary minimal ANSI X3.64/ECMA-48 emulation, the minimal cursor movement and screen clearing capabilities needed for a screen editor. Even most ancient vt100-clones and half-hearted emulators should be able to support this. 100 and above have visible bell, scrolling region, arrow keys. 102 and above have insert and delete chars and lines. 125 adds a meta-key. 320 adds multi-line scroll or pan forward/backward (SU/SD) 999 (aka alt) have alternate screens. NCURSES_BUG Work around the non-standard meaning of insert character capabilities in the termcap and terminfo databases distributed with ncurses. Probably needed for FreeBSD, NetBSD, and LINUX. Probably safe for all others (except if you use a Datamedia 2500 terminal). We automatically define this for UNIX. Jove has been built and tested on PC-compatible computers under a couple of compilers and environments, but is neither developed nor regression tested on them, so it might be in active use there. The following defines are primarily used to tailor the characteristics of various PC environments and/or differentiate them from the Unix or MAC variants of Jove. WIN32 indicates Jove running as a Console app under the WIN32 (Windows NT, 95, 98, 2000, XP, etc) Tested on Windows 7 for 4.17. OWCDOS Open Watcom compiler for MSDOS. This has been tested for 4.17 MSDOS MSDOS or MSDOS-like system. Only tested on IBMPCDOS in recent memory, but worked on the DEC Rainbow ant Atari ST once. IBMPCDOS Indicates MSDOS on an IBM PC-Compatible hardware platform. This enables hardware-specific characteristics of Jove on this platform, such as the screen and keyboard interface. The following characteristics are currently enabled only in the MSDOS and WIN32 environments but could be enabled in other environments if it made sense to do so. FILENAME_CASEINSENSITIVE indicates that Jove should ignore case when comparing filenames. This should only be defined when building Jove in an environment with this characteristic, e.g. MSDOS or WIN32. Note: this does not imply that filenames are monocase; they may be (as for MSDOS) but may not be (e.g. for WIN32). DIRECT0RY_ADD_SLASH indicates that Jove will display a slash at the end of directory names when browsing for a file (i.e. when a ? is entered during Jove's prompt for a file name). Define this only if it can be done cheaply in the jscandir implementation (and also set up jscandir to do so). It is presently defined for MAC, MSDOS, and WIN32. MSFILESYSTEM enables certain filename parsing features in Jove to support Microsoft's manner of organizing a filesystem. This includes one-letter device names, use of backslash as a directory separator, and avoidance of a "dot" as the first character of a filename (as in .joverc). EOL character to recognize and use as end-of-line when loading or saving text files. Defaults to '\n'. USE_CRLF tells Jove to recognize and use CR/LF as end-of-line when loading or saving text files. A bare LF will still be recognized on input. EOL should be left as the default '\n'. PCNONASCII The IBM PC keyboards have a number of keys that don't generate ASCII characters (for example, function keys). Other systems use escape sequences or control characters to encode these keys. For the PC, we use a special code (0xFF) as a prefix for the scan-code generated by the key. PCNONASCII is both the feature selector, and, if defined, it has the value of this prefix. NO_JSTDOUT This suppresses stdio-style buffering for screen output or the use of file descriptor 0 or /dev/tty. CODEPAGE437 This is the name of the "ordinary" character set supported by IBM PC displays. It is described in the appendix of "Microsoft MSDOS Operating System 5.0 User's Guide and Reference" as supporting USA English. PCSCRATTR Exploit IBMPC screen attributes. Enables variables text-attribute, mode-line-attribute, and highlight-attribute. Jove was once ported to the old (pre OS X) has not been well tested, nor does it follow Mac conventions. Perhaps it should be considered a proof of portability. MAC Select all the Macintosh-specific code. jove-4.17.5.5/sysprocs.h000066400000000000000000000075171501102521500147560ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* The diversity of process management is complicated and difficult to handle. * - In some systems (noteably POSIX), a process id has type "pid_t" * - V7 only has wait. POSIX has waitpid (with options). BSD has * wait3. Someone has wait2. * - The status result set by wait and used by WIF* has type * "union wait" in BSD, but "int" everywhere else. * - The WIF* functions are defined in by BSD and POSIX. * - WTERMSIG seems to be a creation of POSIX * - Some systems have vfork(1) and perform better if it is used * in place of fork(1). * * This header attempts to span this diversity. We provide: * - POSIX pid_t * - wait_opt, to accept options (and use them, if possible). * - wait_status_t * - WIF* * - WTERMSIG */ #ifdef MSDOS_PROCS # include #endif #ifdef POSIX_PROCS # include /* defines pid_t */ # include typedef int wait_status_t; # define wait_opt(stat_loc, options) waitpid(-1, stat_loc, options) #else /*!POSIX_PROCS*/ # ifndef _PID_T_ /* MINGW, maybe WIN32 has sys/types.h with pid_t, it seems */ typedef int pid_t; # endif # ifdef BSD_WAIT # include typedef union wait wait_status_t; # ifndef WEXITSTATUS # define WEXITSTATUS(w) ((w).w_retcode) # endif # ifndef WTERMSIG # define WTERMSIG(w) ((w).w_termsig) # endif # ifndef WAIT3 # define wait_opt(stat_loc, options) wait2(stat_loc, options) # else # define wait_opt(stat_loc, options) wait3(stat_loc, options, (struct rusage *)NULL) # endif # else /*!BSD_WAIT*/ typedef int wait_status_t; # ifdef UNIX # ifndef WIFSTOPPED # define WIFSTOPPED(w) ((w & 0377) == 0177) # define WIFEXITED(w) ((w & 0377) == 0) # define WIFSIGNALED(w) (((w >> 8) & 0377) == 0) # define WEXITSTATUS(w) ((w >> 8) & 0377) # define WTERMSIG(w) (w & 0177) # endif # define wait_opt(stat_loc, options) wait(stat_loc) /* should be correct if all preceding typedefs or includes worked out */ extern pid_t wait proto((wait_status_t *)); # endif /* UNIX */ # endif /*!BSD_WAIT*/ #endif /*!POSIX_PROCS*/ #ifndef FULL_UNISTD # ifndef POSIX_UNISTD /* ??? pid_t may be changed by default argument promotions. * If so, this prototype might be wrong. */ extern int kill proto((pid_t /*pid*/, int /*sig*/)); /* signal.h */ extern pid_t fork proto((void)); extern pid_t getpid proto((void)); extern int getuid proto((void)); extern int setuid proto((int)); # endif /* !POSIX_UNISTD */ # ifdef USE_VFORK extern int UNMACRO(vfork) proto((void)); # endif #endif /* !FULL_UNISTD */ /* This nest of #ifdefs is simply to define NEWPG() which makes * the current process a process group leader of a new process group. * ??? pid_t may be changed by default argument promotions. * If so, this prototype might be wrong. */ #ifdef POSIX_PROCS # ifndef FULL_UNISTD extern int UNMACRO(setpgid) proto((pid_t /*pid*/, pid_t /*pgid*/)); extern pid_t UNMACRO(setsid) proto((void)); # endif # define NEWPG() setpgid(0, getpid()) #else /* !POSIX_PROCS */ # ifdef BSD_SETPGRP # ifndef FULL_UNISTD extern int UNMACRO(setpgrp) proto((pid_t /*pid*/, pid_t /*pgrp*/)); # endif # define NEWPG() setpgrp(0, getpid()) # else /* !(defined(BSD_SETPGRP) || defined(POSIX_PROCS)) */ # ifndef FULL_UNISTD extern int UNMACRO(setpgrp) proto((void)); # endif # define NEWPG() setpgrp() # endif /* !(defined(BSD_SETPGRP) || defined(POSIX_PROCS)) */ #endif /* !POSIX_PROCS */ jove-4.17.5.5/teachjove000077500000000000000000000002421501102521500146020ustar00rootroot00000000000000#!/bin/sh # teachjove used to be a binary, but now is just a script that # invokes Jove with the -T option (triggering the teach-jove command) exec jove "$@" -T jove-4.17.5.5/temp.h000066400000000000000000000144621501102521500140330ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* The tmp file stores lines of text for JOVE buffers as contiguous * sequences of chars, terminated by NUL. New lines are added to * the end of the tmp file. The file is not garbage collected * because that would be too painful. As a result, commands like * Yank and Kill are really easy; basically all we do is make copies * of the disk addresses of the lines (as opposed to the contents). * So, jputline(char *buf) writes buf to the disk and returns a new * disk address. jgetline(daddr addr, char *buf) is the opposite of * jputline(). f_getputl(LinePtr line, File fp) reads from open fp * directly into the tmp file (into the buffer cache (see below)) * and stores the address in line. This is used during read_file to * minimize copying. * * To reduce the size of a tmp file disk address, each disk address * is limited to point to positions that are the start of a chunk. * A chunk has exactly CHNK_CHARS characters, so that an disk * address can be reduced by log2(CHNK_CHARS) bits. These extra * bits allow for a larger tmp file. This is exploited on machines * where the disk address (daddr) is stored in a 16-bit type (for other * machines, a chunk is simply one character). Using chunks wastes * some tmp file (and b_cache) space since lines must be aligned on * CHNK_CHARS boundaries. A CHNK_CHARS value large enough to hold * the vast majority of lines inside a single chunk means that each * unique daddr value refers to a chunk/line, making best use of * precious daddr bits (lines larger than CHNK_CHARS mean that daddr * values are skipped, which is not a big deal for 32bit or 64it * machines but really cuts into the max# of lines on PCDOS, for example. * Tmp file space, on the other hand, is relatively cheap, and wasting * b_cache only causes a lot more I/O slowness, but is not as painful * as running out of lines. As a point of reference, JOVE 4.17 compiled * for large model on PCDOS with Open Watcom 1.9 (space-optimized -os) * can fit around 32000 lines in memory from a 1.4MB text file before * starting to hit limits, and/or it can hold about 30 JOVE source files * simultaenously before running out of memory. * * The tmp file is accessed by blocks of size JBUFSIZ (typically * 512 bytes or larger). Lines do NOT cross block boundaries in the * tmp file so that accessing the contents of lines can be much * faster. Pointers into the interior of disk buffers are returned * instead of copying the contents into local arrays and then using * them. This cuts down on the amount of copying a great deal, at * the expense of space efficiency. * * The high bit of each disk address is used for marking the line as * needing redisplay (DDIRTY). In theory, this has nothing to do * with a disk address, but it is the cheapest place to hide a bit * in struct line (this is important since instances of this struct * are the major consumer of memory). * * The type daddr is used to represent the disk address of a line. * It is an integer containing three packed fields: the dirty bit, * the block number (within the tmp file), and the chunk number * (within the block). Many of the following definitions are for * packing and unpacking daddr values. * On a system which limits JOVE to a very small data segment, * it may be worthwhile limiting daddr to a short. This reduces * the size of a Line descriptor (so more line references fit in memory), * but reduces the addressable size of the temp file (so fewer * line contents can be stored on disk), which is reasonable * on 16-bit or very-small-memory machines (e.g. PDP-11 and iAPX 8088/8086). * NOTE: logically, daddr is unsigned, but a signed type will work * if you cannot use an unsigned type. * * There is a buffer cache of NBUF buffers (3 on SMALL machine, * and some larger value (e.g. 64) on !SMALL machines. For 8086 * memory models, NBUF*buffersize must be less than 64K). The * blocks are stored in LRU order and each block is also stored * in a hash table by block #. When a block is requested, * it can quickly be looked up in the hash table. If it's not there the * LRU block is assigned the new block #. If it finds that the LRU block * is dirty (i.e., has pending IO) it syncs the WHOLE tmp file, i.e., * does all the pending writes. This works much better on floppy disk * systems, like the IBM PC, if the blocks are sorted before sync'ing. * */ #ifndef LG_CHNK_CHARS # ifdef JSMALL # define LG_CHNK_CHARS 7 /* save bits in daddr at cost of space in tempfile */ # else # define LG_CHNK_CHARS 0 # endif #endif /* MAX_BLOCKS is the number of distinct block numbers that * can be represented in a daddr (a power of two!). * In fact, we don't allow block number MAX_BLOCKS-1 to be * used because NOWHERE_DADDR and UNSAVED_CURLINE_DADDR (disp.c) must not * be valid disk references, and we want to prevent space overflow * from being undetected through arithmetic overflow. * * MAX_BLOCKS is based on the number of bits remaining in daddr to * represent it, after space for the offset (in chunks) and the * DDIRTY bit is accounted for. */ #define MAX_BLOCKS ((daddr) 1 << (sizeof(daddr)*CHAR_BIT - LG_JBUFSIZ + LG_CHNK_CHARS - 1)) /* CHNK_CHARS is how big each chunk is. For each 1 the DFree pointer * is incremented we extend the tmp file by CHNK_CHARS characters. * BLK_CHNKS is the # of chunks per block. * * NOTE: It's pretty important that these numbers be powers of 2. * Be careful if you change things. */ #define CHNK_CHARS ((daddr)1 << LG_CHNK_CHARS) #define REQ_CHNKS(chars) (((daddr)(chars) + (CHNK_CHARS - 1)) >> LG_CHNK_CHARS) #define BLK_CHNKS ((daddr)JBUFSIZ / CHNK_CHARS) #define blk_chop(addr) ((daddr)(addr) & ~(BLK_CHNKS - 1)) #define da_to_bno(addr) (((daddr)(addr) >> (LG_JBUFSIZ - LG_CHNK_CHARS)) & (MAX_BLOCKS - 1)) #define da_to_off(addr) (((daddr)(addr) << LG_CHNK_CHARS) & ((daddr)JBUFSIZ - 1)) #define bno_to_seek_off(bno) (((off_t)bno) << LG_JBUFSIZ) jove-4.17.5.5/term.c000066400000000000000000000020251501102521500140200ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "term.h" #include "fp.h" /* universal termcap-like definitions (declared in jove.h) */ int SG = 0, /* number of magic cookies left by SO and SE */ LI, /* number of lines */ ILI, /* number of internal lines (LI - 1) */ CO; /* number of columns (CO <= MAXCOLS) */ jbool TABS = NO; /* terminal supports tabs */ #ifndef UNIX void settout() { # ifndef NO_JSTDOUT flushscreen(); /* flush the one character buffer */ ScrBufSize = MAXTTYBUF; jstdout = fd_open("/dev/tty", F_WRITE|F_LOCKED, 1, (char *)NULL, ScrBufSize); # endif } #endif /* !UNIX */ jove-4.17.5.5/term.h000066400000000000000000000102611501102521500140260ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Notes: * - pervasive exports are declared in jove.h * - some of the things declared here are defined in system-specific * files (unix.c, termcap.c, ibmpcdos.c, win32.c, etc). */ extern void ttysetattr proto((jbool n)), ttsize proto((void)), getTERM proto((void)), settout proto((void)), dobell proto((int x)), clr_page proto((void)), i_lines proto((int, int, int)), d_lines proto((int, int, int)); /* MSDOS keyboard routines */ #ifdef MSDOS # ifdef IBMPCDOS extern void pcSetTerm proto((void)), pcUnsetTerm proto((void)); extern jbool enhanced_keybrd; /* VAR: exploit "enhanced" keyboard? */ # endif /* IBMPCDOS */ extern ZXchar getrawinchar proto((void)); extern jbool rawkey_ready proto((void)); #endif /* MSDOS */ /* Win32 keyboard routines */ #ifdef WIN32 int getInputEvents proto((char *bp, int size)); int inputEventWaiting proto((int nsecs)); int FatalErrorMessage proto((char* str)); #endif /* WIN32 */ #ifdef PCSCRATTR extern int Txattr, /* VAR: text-attribute (white on black) */ Mlattr, /* VAR: mode-line-attribute (black on white) */ Hlattr; /* VAR: highlight-attribute */ #endif /* PCSCRATTR */ #ifndef TERMCAP extern void clr_eoln proto((void)); #else /* TERMCAP */ /* the body is the rest of this file */ /* termcap declarations */ extern const char *CS, /* change scrolling region */ *SO, /* Start standout */ *SE, /* End standout */ *US, /* Start underlining */ *UE, /* End underlining */ *CM, /* The cursor motion string */ *CL, /* Clear screen */ *CE, /* Clear to end of line */ *HO, /* Home cursor */ *AL, /* Addline (insert line) */ *DL, /* Delete line */ *VS, /* Visual start */ *VE, /* Visual end */ *KS, /* Keypad mode start */ *KE, /* Keypad mode end */ *TI, /* Cursor addressing start */ *TE, /* Cursor addressing end */ *LL, /* Last line, first column */ *SF, /* Scroll forward (defaults to \n) */ *SR, /* Scroll reverse */ *VB, /* visible bell */ *BL, /* audible bell (defaults to BEL) */ *lPC, /* pad character (as a string!) */ *NL, /* newline character (defaults to \n) */ *DO, /* down one line (defaults to \n capability) */ *M_AL, /* Insert line with arg */ *M_DL, /* Delete line with arg */ *M_SF, /* Scroll forward with arg */ *M_SR; /* Scroll back with arg */ # define INFINITY 10000 /* cost too high to afford */ extern int UPlen, /* length of the UP string */ HOlen, /* length of Home string */ LLlen, /* length of last line string */ phystab, /* ("it") terminal's tabstop settings */ UG; /* number of magic cookies left by US and UE */ extern jbool Hazeltine, /* Hazeltine tilde kludge */ UL, /* underscores don't replace chars already on screen */ NP; /* there is No Pad character */ extern char PC; /* pad character, as a char (set from lPC; defaults to NUL) */ extern const char *BC, /* back space (defaults to BS) */ *UP; /* Scroll reverse, or up */ extern short ospeed; extern jbool CanScroll; /* can this terminal scroll? */ # ifdef ID_CHAR extern const char *IC, /* Insert char */ *DC, /* Delete char */ *IM, /* Insert mode */ *EI, /* End insert mode */ *IP, /* insert pad after character inserted */ *M_IC, /* Insert char with arg */ *M_DC; /* Delete char with arg */ extern jbool UseIC; /* VAR: whether or not to use i/d char processesing */ extern int IMEIlen, /* length of insert mode + end insert mode strings */ IClen, /* length of insert char */ MIClen, /* length of insert char with arg */ DClen, /* length of delete char */ MDClen, /* length of delete char with arg */ CElen; /* length of clear to end of line */ extern jbool MI; /* okay to move while in insert mode */ # endif /* ID_CHAR */ extern void putpad proto((const char *str, int lines)), putmulti proto((const char *ss, const char *ms, int num, int lines)); #endif /* TERMCAP */ jove-4.17.5.5/termcap.c000066400000000000000000000222321501102521500145060ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #ifdef TERMCAP /* the body is the rest of the file */ #include "term.h" #include "disp.h" #include "fmt.h" #include "fp.h" #include "jctype.h" #include "screen.h" extern int UNMACRO(tgetent) proto((char */*buf*/, const char */*name*/)); extern int UNMACRO(tgetflag) proto((const char */*id*/)); extern int UNMACRO(tgetnum) proto((const char */*id*/)); extern char *UNMACRO(tgetstr) proto((const char */*id*/, char **/*area*/)); extern void UNMACRO(tputs) proto((const char *, int, void (*) proto((int)))); /* Termcap definitions */ const char *CS, /* change scrolling region */ *SO, /* Start standout */ *SE, /* End standout */ *US, /* Start underlining */ *UE, /* End underlining */ *CM, /* The cursor motion string */ *CL, /* Clear screen */ *CE, /* Clear to end of line */ *HO, /* Home cursor */ *AL, /* Addline (insert line) */ *DL, /* Delete line */ *VS, /* Visual start */ *VE, /* Visual end */ *KS, /* Keypad mode start */ *KE, /* Keypad mode end */ *TI, /* Cursor addressing start */ *TE, /* Cursor addressing end */ *LL, /* Last line, first column */ *SF = "\n", /* Scroll forward (defaults to \n) */ *SR, /* Scroll reverse */ *VB, /* visible bell */ *BL = "\007", /* audible bell (defaults to BEL) */ *lPC, /* pad character (as a string!) */ *NL = "\n", /* newline character (defaults to \n) */ *DO = "\n", /* down one line (defaults to \n capability) */ *M_AL, /* Insert line with arg */ *M_DL, /* Delete line with arg */ *M_SF, /* Scroll forward with arg */ *M_SR; /* Scroll back with arg */ int UPlen = INFINITY, /* length of the UP string */ HOlen = INFINITY, /* length of Home string */ LLlen = INFINITY, /* length of last line string */ phystab = 8, /* ("it") terminal's tabstop settings */ UG; /* number of magic cookies left by US and UE */ jbool Hazeltine, /* Hazeltine tilde kludge */ UL, /* underscores don't replace chars already on screen */ NP; /* there is No Pad character */ # ifdef DEFINE_PC_BC_UP_OSPEED /* This is needed for HP-UX, possibly for other SYSVR2 systems */ char PC; /* pad character, as a char (set from lPC; defaults to NUL) */ const char *BC, /* back space (defaults to BS) */ *UP; /* Scroll reverse, or up */ short ospeed; # endif /* DEFINE_PC_BC_UP_OSPEED */ jbool CanScroll; /* can this terminal scroll? */ # ifdef ID_CHAR const char *IC, /* Insert char */ *DC, /* Delete char */ *IM, /* Insert mode */ *EI, /* End insert mode */ *IP, /* insert pad after character inserted */ *M_IC, /* Insert char with arg */ *M_DC; /* Delete char with arg */ jbool UseIC = NO; /* VAR: whether or not to use i/d char processesing */ int # ifdef NCURSES_BUG IMEIlen = INFINITY, /* length of insert mode + end insert mode strings */ # else IMEIlen = 0, /* length of insert mode + end insert mode strings */ # endif IClen = INFINITY, /* length of insert char */ MIClen = INFINITY, /* length of insert char with arg */ DClen = INFINITY, /* length of delete char */ MDClen = INFINITY, /* length of delete char with arg */ CElen = INFINITY; /* length of clear to end of line */ jbool MI; /* okay to move while in insert mode */ # endif /* ID_CHAR */ /* as of 20200104, xterm-new is 254 bytes and guru-nctxt is 289 bytes! */ private char tspace[320]; /* space for termcap strings */ /* The ordering of ts and meas must agree !! */ private const char ts[] = # ifdef ID_CHAR /* | | | | */ "vsvealdlcssoseusuecmclcehoupbcllsfsrvbksketitepcblnldoALDLSFSRicimdceiipICDC"; # else "vsvealdlcssoseusuecmclcehoupbcllsfsrvbksketitepcblnldoALDLSFSR"; # endif private const char **const meas[] = { &VS, &VE, &AL, &DL, &CS, &SO, &SE, &US, &UE, &CM, &CL, &CE, &HO, &UP, &BC, &LL, &SF, &SR, &VB, &KS, &KE, &TI, &TE, &lPC, &BL, &NL, &DO, &M_AL, &M_DL, &M_SF, &M_SR, # ifdef ID_CHAR &IC, &IM, &DC, &EI, &IP, &M_IC, &M_DC, # endif NULL }; struct CapLen { const char **cap_var; int *len_var; }; private const struct CapLen CapLenTab[] = { { &HO, &HOlen }, { &LL, &LLlen }, { &UP, &UPlen }, # ifdef ID_CHAR { &IC, &IClen }, { &DC, &DClen }, { &M_IC, &MIClen }, { &M_DC, &MDClen }, { &CE, &CElen }, # endif { NULL, NULL } }; private void tcbad(termname, why) const char *termname, *why; { writef("You can't run JOVE on a %s terminal: %s\n", termname, why); flushscreen(); _exit(1); } void getTERM() { char termnmbuf[13], *termname = getenv("TERM"), *termp = tspace, tbuff[2048]; /* Good grief! */ if (termname == NULL || *termname == '\0' || strcmp(termname, "dumb") == 0 || strcmp(termname, "unknown") == 0 || strcmp(termname, "network") == 0) { int len; putstr("Enter terminal type (e.g, vt100): "); flushscreen(); len = read(0, (UnivPtr) termnmbuf, sizeof(termnmbuf)); termnmbuf[len > 1? len - 1 : 0] = '\0'; termname = termnmbuf; } if (tgetent(tbuff, termname) < 1) tcbad(termname, "type unknown"); /* get numeric capabilities */ if ((CO = tgetnum("co")) == -1) tcbad(termname, "co unknown (width)"); if (CO > MAXCOLS) CO = MAXCOLS; if ((LI = tgetnum("li")) == -1) tcbad(termname, "li unknown (height)"); if ((phystab = tgetnum("it")) == -1 || phystab <= 0) phystab = 8; if ((SG = tgetnum("sg")) == -1) SG = 0; /* Used for mode line only */ if ((UG = tgetnum("ug")) == -1) UG = 0; /* We shan't bother if != 0 */ /* get string capabilities */ { const char *tsp = ts; const char **const *measp; for (measp = meas; *measp != NULL; measp++) { static char nm[3] = "xx"; char *val; nm[0] = *tsp++; nm[1] = *tsp++; val = tgetstr(nm, &termp); if (val != NULL) **measp = val; if (termp > tspace + sizeof(tspace)) tcbad(termname, "too many bytes of termcap strings"); } } if (lPC) PC = *lPC; /* convert lPC string attribute to char PC */ /* get boolean capabilities */ Hazeltine = tgetflag("hz")==YES; /* Hazeltine tilde kludge */ NP = tgetflag("NP")==YES; /* there is No Pad character */ UL = tgetflag("ul")==YES; /* underscores don't replace chars already on screen */ /* adjust capabilities */ if (tgetflag("km") == YES # if defined(USE_CTYPE) && !defined(NO_SETLOCALE) && strcmp(LcCtype, "C") == 0 # endif ) MetaKey = YES; /* has meta-key and default locale */ if (tgetflag("xs") == YES) { SO = SE = NULL; /* don't use braindamaged standout mode */ SG = 0; } if (SR == NULL && M_SR == NULL) CS = NULL; /* don't use scrolling region without way of reverse scrolling */ /* Note: the way termcap/terminfo is defined, we must use *both* * IC and IM to insert, but normally only one will be defined. * See terminfo(5), under the heading "Insert/Delete Character". * Because of this, IM might be defined as a null string. * * The freely redistributable termcap/terminfo database associated * with ncurses breaks this rule. This is unfortunate, but we * cannot seem to get them to fix this bug. Apparently no currently * supported terminal needed this feature anyway, so we might * as well go with the flow. */ # ifdef ID_CHAR if (IM == NULL || *IM == '\0' || EI == NULL || *EI == '\0') IM = EI = NULL; /* If IM or EI is empty, supress both. */ # ifndef NCURSES_BUG if (IC == NULL || *IC == '\0') M_IC = NULL; /* don't know how to use this */ # endif UseIC = (IC != NULL || IM != NULL || M_IC != NULL); MI = tgetflag("mi")==YES; /* okay to move while in insert mode */ # endif /* ID_CHAR */ /* strip stupid padding information */ while ('0' <= *NL && *NL <= '9') NL += 1; if (*NL == '*') NL += 1; if (BC == NULL) BC = "\b"; /* default back space to BS */ CanScroll = (AL != NULL && DL != NULL) || CS != NULL; /* calculate lengths */ { static const struct CapLen *p; for (p = CapLenTab; p->cap_var != NULL; p++) if (*p->cap_var != NULL) *p->len_var = strlen(*p->cap_var); #ifdef ID_CHAR if (IM != NULL) IMEIlen = strlen(IM) + strlen(EI); #endif } if (!(CM != NULL || HO != NULL)) tcbad(termname, "JOVE needs either cm or ho termcap/terminfo capability"); } /* Put multi-unit or multiple single-unit strings, as appropriate. */ private void tputc(c) char c; { scr_putchar(c); } void putmulti(ss, ms, num, lines) const char *ss, /* single line */ *ms; /* multiline */ int num, /* number of iterations */ lines; /* lines affected (for padding) */ { if (ms && (num > 1 || !ss)) { /* use the multi string */ tputs(targ1(ms, num), lines, tputc); } else { /* repeatedly use single string */ while (num--) putpad(ss, lines); } } /* put a string with padding */ void putpad(str, lines) const char *str; int lines; { if (str != NULL) tputs(str, lines, tputc); } void dobell(n) /* declared in term.h */ int n; { while (--n >= 0) { if (VisBell && VB) putpad(VB, 1); else putpad(BL, 1); } flushscreen(); } void clr_page() { putpad(CL, LI); } #endif /* TERMCAP */ jove-4.17.5.5/testbuild.sh000077500000000000000000000200211501102521500152370ustar00rootroot00000000000000#!/bin/sh # Automated builds with various configs, should work on # range of Linux, SunOS (OpenIndiana), *BSD, Darwin(MacOS). # Used in github actions workflow for automated builds, # see .github/workflows/testbuild.yml # Author: Mark Moraes PATH=/bin:/usr/bin:/usr/gnu/bin:/opt/SUNWspro/bin:/usr/sfw/bin:/usr/local/bin:/opt/homebrew/bin:/usr/local/sbin:/usr/sbin:/sbin:/bin export PATH : ${TB_MACH=$(uname -m)} : ${TB_OS=$(uname)} : ${TB_REV=$(uname -r)} : ${TB_NODE=$(uname -n)} : ${TB_OPTFLAGS=-Os} : ${TB_MINGW=i686-w64-mingw32 x86_64-w64-mingw32} dist=$TB_OS-$TB_MACH if test -e /etc/os-release; then . /etc/os-release dist=$dist-${ID-$NAME}-${VERSION_ID-} elif test -e /etc/release; then read ID VERSION_CODENAME VERSION_ID junk < /etc/release dist=$dist-$ID-${VERSION_CODENAME}${VERSION_ID} fi dist="$dist-$TB_REV-$TB_NODE" dist=DIST/$(echo "$dist" | tr '() /*#$?^!~`;<>"'\''' '_') mkdir -p "$dist" (echo TB_MACH=$TB_MACH TB_OS=$TB_OS TB_REV=$TB_REV echo for f in /etc/*release; do if test -e "$f"; then echo ">>> $f"; cat "$f"; echo; fi; done set ) | tee $dist/TBINFO : ${SUDO=sudo} user=$(ls -l $dist/TBINFO|awk '{print $3}') case "$user" in root) SUDO=;; esac set -eux case $# in 0) ;; *) case "$1" in --preinstall*) ;; *) echo "Usage: $0 --preinstall|--preinstall-only" >&2 exit 1 ;; esac if type apt-get 2> /dev/null; then if ! $SUDO apt-get update; then # might be because debian moved these to archive sed -i '/-updates/d;s/deb.debian/archive.debian/;s/security.debian/archive.debian/' /etc/apt/sources.list for key in $(apt-key list | awk -v FS='[ /:]+' '/expired/ {print $3}'); do echo $key; apt-key adv --recv-keys --keyserver keyserver.ubuntu.com $key; done # might still fail because of KEYEXPIRED etc so we ignore failure and hope for best in apt-get install $SUDO apt-get update || true fi $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y --force-yes gcc make pkg-config ncurses-dev groff exuberant-ctags zip dpkg-dev bzip2 case "$TB_MACH" in x86_64) $SUDO env DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y --force-yes mingw-w64;; esac # similar OPTFLAGS to what Cord uses for debian packaging TB_OPTFLAGS="-g -O2 -fstack-protector-strong -Wformat -Werror=format-security -Wdate-time -D_FORTIFY_SOURCE=2" elif type apk 2> /dev/null; then $SUDO apk update && apk add gcc make pkgconfig musl-dev ncurses-dev groff ctags zip mingwapk="$($SUDO apk list mingw-w64-gcc)" case "$mingwapk" in '') ;; *) apk add mingw-w64-gcc;; esac elif type yum 2> /dev/null; then ctags=ctags case "$ID" in rocky) ctags=;; centos) sed -i -e 's/mirror.centos.org/vault.centos.org/g' \ -e 's/^#.*baseurl=http/baseurl=http/g' \ -e 's/^mirrorlist=http/#mirrorlist=http/g' \ /etc/yum.repos.d/CentOS-*.repo ;; esac $SUDO yum install -y make gcc ncurses-devel groff $ctags zip rpm-build elif type brew 2> /dev/null; then brew install make ncurses ctags zip groff elif type pacman 2> /dev/null; then $SUDO pacman -Sy --noconfirm gcc make pkgconf ncurses groff ctags zip elif type nix-shell 2> /dev/null; then $SUDO nix-shell -p gnumake else # not a packaging system we know, hope it already has minimal testbuild needs type cc make mktemp TB_OPTFLAGS=-O fi cc --version || true case "$1" in *only) exit 0;; esac ;; esac # directory for artifacts make .version ver=$(cat .version) # note: older *BSD, OSX, Solaris require a template td=$(mktemp -d "${TMPDIR:-/tmp}/jvt.XXXXXXXX") dd="DESTDIR=$td" u=$(uname) o=${TB_OPTFLAGS} e= d= x= d=-DTERMIOS t=-ltermcap lib= jv=NPROCESSORS_ONLN # Some logic below is replicated in/from jmake.sh, needed here because # of the extra non-typical builds that are tested. case $TB_OS in SunOS) x="NROFF=nroff TROFF=troff" d="-DREALSTDC -DPOSIX_PROCS" case "$TB_REV" in 5.0) d="-DSYSVR4 -DGRANTPT_BUG";; # really, just do not run this version, it was so so so problematic! 5.*) ;; *) echo "$0: Not set up for testing $TB_OS $TB_REV" >&2; exit 1;; esac xi=/usr/gnu/bin/install if test ! -x $xi; then xi=cp fi x="$x XINSTALL=$xi TINSTALL=$xi" ;; GNU|Linux) t=-lncurses if test -e /etc/alpine-release; then d="$d -DUSE_GETCWD"; lib=MUSL; elif test -e /etc/gentoo-release; then t="-ltinfo"; lib=GLIBC; else lib=GLIBC; fi jv=_NPROCESSORS_ONLN ;; esac # awful hack to turn off warnings for old-style K&R definitions in # newish versions of gcc/clang # TO-DO: remove this for jove 5.x when we move to c89-style prototypes skipwarn="-Wno-unknown-warning -Wno-unknown-warning-option -Wno-old-style-definition -Wno-strict-prototypes -Wno-deprecated-non-prototype -Wno-incompatible-pointer-types" case "$o" in -O) w= ;; *) o="$o $skipwarn" w="$skipwarn" ;; esac if test -x /usr/bin/getconf; then j=-j$(getconf $jv); else j=; fi # other than the first "make install" with $TB_OS, some of the others # (e.g. PIPEPROCS, TERMINFO) may produce warnings (e.g. no declaration for # ioctl) because we are just testing somewhat abnormal non-POSIX sysdefs. # Try using either old-style TERMCAPLIB, EXTRALIBS or new-style LDLIBS make clean && JMAKE_OPTS=$j ./jmake.sh $dd/t10-$TB_OS install OPTFLAGS="$o" LOCALCFLAGS="$w" && make clean && make $j OPTFLAGS="$o" LOCALCFLAGS="$w" PORTSRVINST=1 SYSDEFS="-DPIPEPROCS $d" TERMCAPLIB=$t EXTRALIBS= $x $dd/t20-pipeprocs install && make clean && make $j OPTFLAGS="$o" LOCALCFLAGS="$w" SYSDEFS="-DBSDPOSIX $d" LDLIBS=$t $x $dd/t30-bsdposix install && make clean && make $j OPTFLAGS="$o" LOCALCFLAGS="$w" SYSDEFS="-DBAREBONES -DSMALL -DJTC $d" LDLIBS= $x $dd/t60-small install && make clean && case "$lib" in GLIBC) make $j OPTFLAGS="$o" LOCALCFLAGS="$w" SYSDEFS="-DXLINUX" TERMCAPLIB=$t EXTRALIBS= $x $dd/t40-xlinux install && make clean && make $j OPTFLAGS="$o" LOCALCFLAGS="$w" SYSDEFS="-DTERMINFO -DUSE_VFORK" TERMCAPLIB=$t $x $dd/t50-vfork && make clean ;; esac && make $x tgz && mv jove-*.tgz $dist && if type zip 2> /dev/null; then make $x zip && mv jove*s.zip $dist fi && if test -e /etc/redhat-release; then # build and perhaps install RPM joverpm=$(rpm -qa | grep jove) case "$joverpm" in "") ;; *) rpm -e $joverpm; esac rm -f $HOME/rpmbuild/*RPMS/$TB_MACH/jove*.rpm make rpm && cp -av $HOME/rpmbuild/*RPMS/$TB_MACH/jove-[4-9]*.rpm $dist && case "${1-}" in *install) rpm -i $HOME/rpmbuild/RPMS/$TB_MACH/jove-[4-9]*.rpm;; esac && rm -f $HOME/rpmbuild/*RPMS/$TB_MACH/jove-[4-9]*.rpm elif test -e /etc/alpine-release; then # build statically compiled versions using native alpine x86_64 # and musl-cross-make i486 to get very generic 32- and 64-bit x86 # tarballs that should run on just about on any Linux PC hardware for tag in i486-linux-musl x86_64-alpine-linux-musl; do if type ${tag}-gcc 2> /dev/null ; then r=jove-$ver-$tag-static && if test ! -d $dist/$r; then mkdir $dist/$r; fi && make clobber && JMAKE_UNAME=$tag ./jmake.sh OPTFLAGS="$o" LOCALCFLAGS="$w" all && strip jjove recover && mv jjove $dist/$r/jove && mv recover $dist/$r && cp -pr README ChangeLog teachjove paths.h doc $dist/$r/ && tar -c -z -v -f $dist/$r.tar.gz -C $dist $r && rm -r $dist/$r fi done fi && for tag in ${TB_MINGW}; do if type ${tag}-gcc 2> /dev/null ; then # build a cross-compiled version for Windows r=jove-$ver-$tag && if test ! -d $dist/$r; then mkdir $dist/$r; fi && make clobber && make XEXT=.exe clobber && JMAKE_UNAME=$tag ./jmake.sh $j OPTFLAGS="$o" LOCALCFLAGS="$w" all && ${tag}-strip jjove.exe recover.exe && mv jjove.exe $dist/$r/jove.exe && mv recover.exe $dist/$r && cp -pr README* paths.h ChangeLog doc $dist/$r && (cd $dist && zip -rm $r.zip $r) && make XEXT=.exe clobber fi done && if type pbuilder 2> /dev/null; then # if a developer has pbuilder, test debian package builds $SUDO make $j deb cp -av /var/cache/pbuilder/result/*$(cat .version)*.deb $dist/ fi ret=$? # portable for older Unix/SunOS! (cd "$td" && tar cf - .) | gzip > $dist/$ver-builds.tar.gz rm -rf "$td" exit $ret jove-4.17.5.5/testmailer.sh000077500000000000000000000001641501102521500154170ustar00rootroot00000000000000#!/bin/sh # Use to test recover JOVEMAILER echo ">>> $0 with $# args" for i; do echo ">>> '$i' "; done sed 's/^/ /' jove-4.17.5.5/ttystate.h000066400000000000000000000057121501102521500147450ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #ifdef UNIX /* Various tty state structures. * Each is an array, subscripted by one of "NO" or "YES". * YES is set suitably for JOVE. * NO is reset back to initial state. */ # ifdef SGTTY # include extern struct sgttyb sg[2]; # ifdef TIOCSLTC # define USE_TIOCSLTC 1 # endif # endif # ifdef TERMIO # include extern struct termio sg[2]; # endif # ifdef TERMIOS # include extern struct termios sg[2]; # endif # if defined(TERMIO) || defined(TERMIOS) /* JOVE needs to know about tab expansion to infer whether it should * use tabs to optimize output (jove.c). * It also must be able to turn tab expansion off for a pty (iproc.c). * The "normal" way of signifying tab expansion in a termio or termios * struct is to set the bits in c_oflag masked by TABDLY to TAB3. * Instead, some systems (eg. 386BSD) have a single bit named OXTABS, * from which we synthesize fake definitions of TABDLY and TAB3. * Some other systems have no bit, so we must presume that tabs don't * work and that we needn't change the setting. */ # ifndef TABDLY # ifdef OXTABS # define TABDLY OXTABS # define TAB3 TABDLY # else # define TABDLY 0 /* tab expansion is unknown and uncontrollable */ # endif # endif # endif # ifdef USE_BSDTTYINCLUDE # include # ifdef TIOCSLTC # define USE_TIOCSLTC 1 # endif # endif # ifdef USE_TIOCSLTC extern struct ltchars ls[2]; # endif /* USE_TIOCSLTC */ # ifdef SGTTY # ifdef TIOCGETC extern struct tchars tc[2]; # endif # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */ extern int lmword[2]; /* local mode word */ # endif # endif /* SGTTY */ # ifndef NO_IOCTL_H_TTY /* In an attempt to get a definition for TIOCGWINSZ, * we include . In a perfect world, we could always * include it, but at least SunOS 4.[01] * conflicts seriously with . Some systems require it * to define TIOCGWINSZ (e.g. BSDI), or TIOCSCTTY (OSF, other * POSIX?). */ # include # endif # ifdef BTL_BLIT # include /* get BTL window resizing definitions */ # endif # ifdef SCO_ODT3 # undef TIOCGWINSZ /* SCO ODT 3 defines this but does not implement it!!! */ # endif /* Variables: */ extern jbool OKXonXoff; /* VAR: XON/XOFF can be used as ordinary chars */ extern ZXchar IntChar; /* VAR: ttysetattr sets this to generate QUIT */ #endif /* UNIX */ #ifdef BIFF extern jbool DisBiff; /* VAR: turn off/on biff with entering/exiting jove */ #endif jove-4.17.5.5/tune.h000066400000000000000000000055011501102521500140330ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Tuning: configure JOVE to installer's taste */ #define TUNED 1 /* don't touch this */ #include "sysdep.h" /* * Select or comment out as many of the following features of Jove as you'd * like. In general, most of them are useful or pleasant, but many of them * are non-portable, or make Jove larger. * * By default, most are included if appropriate. BAREBONES suppresses most * of them. With BAREBONES defined, Jove should compile on a lot of systems. * It should be considered the starting point for any port of Jove to a new * system. An advantage of BAREBONES is that it shrinks JOVE's already * modest size. */ #ifndef BAREBONES # define ABBREV 1 /* word abbreviation mode */ # define BACKUPFILES 1 /* enable the backup files code */ # ifdef UNIX # define BIFF 1 /* if you have biff (or the equivalent) */ # endif # define CMT_FMT 1 /* include the comment formatting routines */ # define F_COMPLETION 1 /* filename completion */ /* Include code to IDchar (optimize for terminals with character * insert/delete modes */ # ifdef TERMCAP # define ID_CHAR 1 # endif # ifdef TERMCAP # define HIGHLIGHTING 1 /* highlighting is used for mark and scrollbar */ # endif # if !defined(NO_IPROCS) && (defined(PIPEPROCS) || defined(PTYPROCS)) # define IPROCS 1 /* interactive processes */ # endif # define LISP 1 /* include the code for Lisp Mode */ # ifndef MAC # define SUBSHELL 1 /* enable various uses of subshells */ # endif # if defined(SUBSHELL) && !defined(SPELL) # define SPELL "spell %s" /* spell words and buffer commands (requires SUBSHELL) */ # endif /* NOTE that invoking recover via jove -r requires SUBSHELL */ # define RECOVER 1 /* include code to attempt recovery from JOVE crashes */ #endif /* !BAREBONES */ #ifndef SUBSHELL # undef IPROCS /* probably does not work */ # undef SPELL /* probably cannot execute spell checker */ #endif #ifndef IPROCS # undef PIPEPROCS /* defined only if IPROCS is */ # undef PTYPROCS /* defined only if IPROCS is */ #endif #ifndef MSDOS # define DFLT_MODE 0666 /* file will be created with this mode */ #endif /* If the compiler does not support void, use -Dvoid=int or * typedef int void; */ /* * USE_PROTOTYPE must be defined for compilers that support prototypes but are * NOT ANSI C, i.e. do not have __STDC__ == 1. USE_PROTOTYPE will be * automatically defined for ANSI compilers. */ /* #define USE_PROTOTYPES 1 */ jove-4.17.5.5/tune.txt000066400000000000000000000051721501102521500144270ustar00rootroot00000000000000########################################################################## # This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is # # provided by Jonathan and Jovehacks without charge and without # # warranty. You may copy, modify, and/or distribute JOVE, provided that # # this notice is included in all the source files and documentation. # ########################################################################## Here's a list of the compile time options and what they mean. All options are turned ON in the distributed version of Jove. ABBREV Enables word-abbrev-mode which again is nice for paper writers. BACKUPFILES This enables backing up files on write. I guess lots of people like this feature. It enables the feature but you can still control whether files are backed up with the make-backup-files variable. BIFF This enables turning on and off BIFF so your screen doesn't get messed up with messages from BIFF. CMT_FMT This enables code to format and indent C comments. F_COMPLETION Enables filename completion. This requires that your system have reasonable directory scanning capabilities. It's a really handy feature, so it's worth turning on. ID_CHAR Enables support for Insert/Delete character on terminals that have those capabilities. Couple of problems with this code: it's large, takes up lots of I space which is a problem for the smaller computers (pdp11). Also, it isn't particularly smart and sometimes does really stupid things. It sometimes uses insert/delete character when simply redrawing would have been faster. And if you look at code you'll understand why I don't like it all that much. IPROCS Nice feature which lets you run interactive UNIX commands in windows. In particular, there is a shell command built in which starts up an interactive shell in a window. Porting this one is hard even within Unix systems -- non-Unix systems may not want to even try supporting this. LISP Enables Lisp Mode. This includes code to indent "properly" for Lisp code and new routines to move over s-expressions. You probably won't want (or need) this on PDP-11's. RECOVER Enables code to support recovery of data from crashed JOVE sessions. SPELL Enables the spell-buffer and parse-spelling-errors commands. They are nice especially if you have lots of paper writers. Requires SUBSHELL (to run spell program). SUBSHELL Enables various uses of sub-shells (eg. push-shell, filter-region, shell-command-to-buffer, compile-it, spell-buffer, ...) Somewhat easier to port than IPROCS. If SUBSHELL is not defined, jove -r (for recovery) will not work. jove-4.17.5.5/unix.c000066400000000000000000000312751501102521500140450ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #ifdef UNIX /* the body is the rest of the file */ #include "fp.h" #ifdef BIFF # include #endif #include "chars.h" #include "term.h" /* ospeed */ #include "ttystate.h" #ifdef SGTTY struct sgttyb sg[2]; #endif #ifdef TERMIO struct termio sg[2]; #endif #ifdef TERMIOS struct termios sg[2]; #endif #ifdef USE_TIOCSLTC struct ltchars ls[2]; #endif /* USE_TIOCSLTC */ #ifdef SGTTY # ifdef TIOCGETC struct tchars tc[2]; # endif # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */ int lmword[2]; /* local mode word */ # endif #endif /* SGTTY */ /* Set tty to original (if !n) or JOVE (if n) modes. * This is designed to be idempotent: it can be called * several times with the same argument without damage. * * If STICKY_TTYSTATE is defined, the "original" state is sampled only once. * Normally, this is also sampled each time ttysetattr re-enters JOVE mode. * STICKY_TTYSTATE is useful if processes run while JOVE is suspended * cannot be trusted to leave the tty in a good state. * ConvexOS is currently an example: some of its programs turn on ISTRIP * without provocation. */ /* * Modern terminals (which are almost always terminal * emulators) are generally fine with ^S and ^Q, so follow GNU * Emacs lead and assume that by default. */ jbool OKXonXoff = YES; /* VAR: XON/XOFF can be used as ordinary chars */ ZXchar IntChar = CTL(']'); /* VAR: ttysetattr sets this to generate SIGINT */ #ifdef BIFF /* * Ancient UNIXes can mess up the screen with biff when mail * arrives, and it does no harm to turn this on anyway. */ jbool DisBiff = YES; /* VAR: turn off/on biff with entering/exiting jove */ #endif /* BIFF */ void ttysetattr(n) jbool n; /* also used as subscript! */ { static jbool keep_saved = NO; if (!keep_saved) { /* Save the current tty settings: * do the ioctls or whatever to fill in NO half * of each appropriate tty state pair. * NOTE: previously, the tty was not in JOVE mode. * NOTE: the nested tangle of ifdefs is intended to follow * the structure of the definitions in ttystate.c. */ #ifdef SGTTY (void) gtty(0, &sg[NO]); #endif #ifdef TERMIO (void) ioctl(0, TCGETA, (UnivPtr) &sg[NO]); #endif #ifdef TERMIOS (void) tcgetattr(0, &sg[NO]); #endif #ifdef USE_TIOCSLTC (void) ioctl(0, TIOCGLTC, (UnivPtr) &ls[NO]); #endif /* USE_TIOCSLTC */ #ifdef SGTTY # ifdef TIOCGETC (void) ioctl(0, TIOCGETC, (UnivPtr) &tc[NO]); # endif # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */ (void) ioctl(0, TIOCLGET, (UnivPtr) &lmword[NO]); # endif #endif /* SGTTY */ /* extract some info from results */ #if defined(TERMIO) || defined(TERMIOS) # ifdef TAB3 TABS = (sg[NO].c_oflag & TABDLY) != TAB3; # endif # ifdef TERMIOS ospeed = cfgetospeed(&sg[NO]); # else /* ! TERMIOS */ # ifdef CBAUD ospeed = sg[NO].c_cflag & CBAUD; # else /* ! CBAUD */ ospeed = B9600; /* XXX */ # endif /* CBAUD */ # endif /* TERMIOS */ #endif /* defined(TERMIO) || defined(TERMIOS) */ #ifdef SGTTY TABS = !(sg[NO].sg_flags & XTABS); ospeed = sg[NO].sg_ospeed; #endif /* SGTTY */ #ifdef STICKY_TTYSTATE /* keep saved copy of ttystate until JOVE quits */ keep_saved = YES; #endif } #ifndef STICKY_TTYSTATE /* Keep saved copy of ttystate next time iff we are switching to JOVE mode. * In other words, don't replace saved copy next time if we will * be in JOVE mode -- the wrong mode to save. */ keep_saved = n; #endif /* Fill in YES half of each appropriate tty state pair. * They are filled in as late as possible so that each will * reflect the latest settings of controling variables. * NOTE: the nested tangle of ifdefs is intended to follow * the structure of the definitions in ttystate.c. */ sg[YES] = sg[NO]; #ifdef SGTTY sg[YES].sg_flags &= ~(XTABS|ECHO|CRMOD); # ifdef LPASS8 sg[YES].sg_flags |= CBREAK; # else sg[YES].sg_flags |= (MetaKey ? RAW : CBREAK); # endif #endif #if defined(TERMIO) || defined(TERMIOS) if (OKXonXoff) sg[YES].c_iflag &= ~(IXON | IXOFF); sg[YES].c_iflag &= ~(INLCR|ICRNL|IGNCR | (MetaKey? ISTRIP : 0)); sg[YES].c_lflag &= ~(ICANON|ECHO); sg[YES].c_oflag &= ~(OPOST); /* Set all those c_cc elements that we must. * For peculiar systems, one might wish to predefine JVDISABLE * in the configuration. For example, on some unnamed * versions of the Convex OS, it would be good to * define it as (sg[YES].c_cc[VDISABLE]), saving a system call. * Note that the only uses of JDISABLE are in this block, * so the macro may safely refer to things in this context. */ { # ifndef JVDISABLE # ifdef _POSIX_VDISABLE # define JVDISABLE _POSIX_VDISABLE # else /* !_POSIX_VDISABLE */ # ifdef _PC_VDISABLE /* Cache the result of fpathconf to reduce the number of syscalls. * We don't handle the error return (-1) because there isn't * anything better to do with it. */ cc_t jvd = fpathconf(0, _PC_VDISABLE); # define JVDISABLE jvd # else /* !_PC_VDISABLE */ # define JVDISABLE 0 # endif /* !_PC_VDISABLE */ # endif /* !_POSIX_VDISABLE */ # endif /* JVDISABLE */ sg[YES].c_cc[VINTR] = IntChar; # ifdef VQUIT sg[YES].c_cc[VQUIT] = JVDISABLE; # endif /* VERASE, VKILL, VEOL2 irrelevant */ /* Beware aliasing! VMIN is VEOF and VTIME is VEOL */ # ifdef VSWTCH sg[YES].c_cc[VSWTCH] = JVDISABLE; # endif /* Under at least one system (SunOS 4.0), * mistakenly defines the extra V symbols of * without extending the c_cc array in struct termio * to hold them! This is why the following goo is doubly * ifdefed. It turns out that we don't use * on SunOS 4.0, so the problem may be moot. */ # ifdef TERMIOS # ifdef VSUSP sg[YES].c_cc[VSUSP] = JVDISABLE; # endif # ifdef VDSUSP sg[YES].c_cc[VDSUSP] = JVDISABLE; # endif # ifdef VDISCARD /* ??? Under Solaris 2.1 needs VDISCARD disabled, or it will * be processed by the tty driver, but not under SysVR4! */ sg[YES].c_cc[VDISCARD] = JVDISABLE; /* flush output */ # endif # ifdef VLNEXT sg[YES].c_cc[VLNEXT] = JVDISABLE; /* literal next char */ # endif # endif /* TERMIOS */ sg[YES].c_cc[VMIN] = 1; sg[YES].c_cc[VTIME] = 1; } #endif /* defined(TERMIO) || defined(TERMIOS) */ #ifdef USE_TIOCSLTC ls[YES] = ls[NO]; ls[YES].t_suspc = (char) -1; ls[YES].t_dsuspc = (char) -1; ls[YES].t_flushc = (char) -1; ls[YES].t_lnextc = (char) -1; #endif /* USE_TIOCSLTC */ #ifdef SGTTY # ifdef TIOCGETC tc[YES] = tc[NO]; tc[YES].t_intrc = IntChar; tc[YES].t_quitc = (char) -1; if (OKXonXoff) { tc[YES].t_stopc = (char) -1; tc[YES].t_startc = (char) -1; } # endif # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */ lmword[YES] = lmword[NO]; if (MetaKey) lmword[YES] |= LPASS8; # ifdef LLITOUT /* ??? under what conditions should we turn on LLITOUT flag? */ # endif /* LLITOUT */ # ifdef LTILDE if (Hazeltine) lmword[YES] &= ~LTILDE; # endif /* LTILDE */ # endif /* LPASS8 */ #endif /* SGTTY */ /* Set tty state according to appropriate entry of each state pair. * NOTE: the nested tangle of ifdefs is intended to follow * the structure of the definitions in ttystate.c. */ #ifdef SGTTY # ifdef TIOCSETN (void) ioctl(0, TIOCSETN, (UnivPtr) &sg[n]); # else (void) stty(0, &sg[n]); # endif #endif #ifdef TERMIO do {} while (ioctl(0, TCSETAW, (UnivPtr) &sg[n]) < 0 && errno == EINTR); #endif #ifdef TERMIOS do {} while (tcsetattr(0, TCSADRAIN, &sg[n]) < 0 && errno == EINTR); #endif #ifdef USE_TIOCSLTC (void) ioctl(0, TIOCSLTC, (UnivPtr) &ls[n]); #endif /* USE_TIOCSLTC */ #ifdef SGTTY # ifdef TIOCGETC (void) ioctl(0, TIOCSETC, (UnivPtr) &tc[n]); # endif # ifdef LPASS8 /* use 4.3BSD's LPASS8 instead of raw for meta-key */ (void) ioctl(0, TIOCLSET, (UnivPtr) &lmword[n]); /* local mode word */ # endif #endif /* SGTTY */ #ifdef BIFF # ifdef S_IXUSR # define BIFF_BIT ((jmode_t)S_IXUSR) /* POSIX name */ # else # define BIFF_BIT ((jmode_t)S_IEXEC) /* BSD name */ # endif /* biff state is an honorary part of the tty state. * On the other hand, it is different from the rest of the state * since we only want to examine the setting if DisBiff * has been set by the user. For this reason, the code is * somewhat more intricate. */ { # define BS_UNEXAMINED 0 /* we don't know if biff is enabled */ # define BS_DISABLED 1 /* we have disabled biff */ # define BS_UNCHANGED 2 /* we didn't disable biff */ static int biff_state = BS_UNEXAMINED; static struct stat tt_stat; # if !defined(USE_FSTAT) || !defined(USE_FCHMOD) static char *tt_name = NULL; /* name of the control tty */ extern char *ttyname proto((int)); /* for systems w/o fstat */ # endif if (n && DisBiff) { /* biff supression is our business */ if (biff_state == BS_UNEXAMINED) { /* and we haven't looked after it */ biff_state = BS_UNCHANGED; /* at least so far */ if ( # ifdef USE_FSTAT fstat(0, &tt_stat) != -1 # else ((tt_name != NULL) || (tt_name = ttyname(0)) != NULL) && stat(tt_name, &tt_stat) != -1 # endif && (tt_stat.st_mode & BIFF_BIT)) { /* so let's suppress it */ # ifdef USE_FCHMOD (void) fchmod(0, tt_stat.st_mode & ~BIFF_BIT); biff_state = BS_DISABLED; # else if ((tt_name != NULL || (tt_name = ttyname(0)) != NULL) && chmod(tt_name, tt_stat.st_mode & ~BIFF_BIT) != -1) { /* Note: only change biff_state if we were able to * get the tt_name -- this prevents the other * chmod from blowing up. */ biff_state = BS_DISABLED; } # endif } } } else { /* any biff suppression should be undone */ if (biff_state == BS_DISABLED) { /* and we did suppress it, so we enable it */ # ifdef USE_FCHMOD (void) fchmod(0, tt_stat.st_mode); # else (void) chmod(tt_name, tt_stat.st_mode); # endif } biff_state = BS_UNEXAMINED; /* it's out of our hands */ } # undef BS_UNEXAMINED # undef BS_DISABLED # undef BS_UNCHANGED } # undef BIFF_BIT #endif /* BIFF */ } /* Determine the number of characters to buffer at each baud rate. The * lower the number, the quicker the response when new input arrives. Of * course the lower the number, the more prone the program is to stop in * output. Decide what matters most to you. This sets ScrBufSize to the right * number or chars, and initializes `jstdout'. */ void settout() { int speed_chars; static const struct { unsigned int bsize; unsigned int brate; } speeds[] = { #ifdef B0 { 1, B0 }, #endif #ifdef B50 { 1, B50 }, #endif #ifdef B75 { 1, B75 }, #endif #ifdef B110 { 1, B110 }, #endif #ifdef B134 { 1, B134 }, #endif #ifdef B150 { 1, B150 }, #endif #ifdef B200 { 1, B200 }, #endif #ifdef B300 { 2, B300 }, #endif #ifdef B600 { 4, B600 }, #endif #ifdef B900 { 6, B900 }, #endif #ifdef B1200 { 8, B1200 }, #endif #ifdef B1800 { 16, B1800 }, #endif #ifdef B2400 { 32, B2400 }, #endif #ifdef B3600 { 64, B3600 }, #endif #ifdef B4800 { 128, B4800 }, #endif #ifdef B7200 { 256, B7200 }, #endif #ifdef B9600 { 256, B9600 }, #endif #ifdef EXTA { 512, EXTA }, #endif #ifdef B19200 { 512, B19200 }, #endif #ifdef EXTB { 1024, EXTB }, #endif #ifdef B38400 { 1024, B38400 }, #endif #ifdef EXT { 1024, EXT } #endif }; int i; for (i = 0; ; i++) { if (i == elemsof(speeds)) { speed_chars = 512; ospeed = B9600; /* XXX */ break; } if (speeds[i].brate == (unsigned short) ospeed) { speed_chars = speeds[i].bsize; break; } } flushscreen(); /* flush the one character buffer */ ScrBufSize = jmin(MAXTTYBUF, speed_chars * jmax(LI / 24, 1)); #ifndef NO_JSTDOUT jstdout = fd_open("/dev/tty", F_WRITE|F_LOCKED, 1, (char *)NULL, ScrBufSize); #endif } void ttsize() { /* ??? We really ought to wait until the screen is big enough: * at least three lines high (one line each for buffer, mode, * and message) and at least twelve columns wide (eight for * line number, one for content, two for overflow indicators, * and one blank at end). */ #ifdef TIOCGWINSZ struct winsize win; if (ioctl(0, TIOCGWINSZ, (UnivPtr) &win) == 0 && win.ws_col >= 12 && win.ws_row >= 3) { CO = jmin(win.ws_col, MAXCOLS); LI = win.ws_row; } #else /* !TIOCGWINSZ */ # ifdef BTL_BLIT struct jwinsize jwin; if (ioctl(0, JWINSIZE, (UnivPtr) &jwin) == 0 && jwin.bytesx >= 12 && jwin.bytesy >= 3) { CO = jmin(jwin.bytesx, MAXCOLS); LI = jwin.bytesy; } # endif /* BTL_BLIT */ #endif /* !TIOCGWINSZ */ ILI = LI - 1; } #endif /* UNIX */ jove-4.17.5.5/util.c000066400000000000000000000376321501102521500140420ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "jctype.h" #include "disp.h" #include "fp.h" #include "ask.h" #include "chars.h" #include "fmt.h" #include "insert.h" #include "macros.h" #include "marks.h" #include "move.h" #include "rec.h" #ifdef MAC # include "mac.h" #endif jbool blnkp(buf) register char *buf; { register char c; do { c = *buf++; } while (jiswhite(c)); return c == '\0'; /* It's NUL if we got to the end of the Line */ } jbool within_indent() { register int i; i = curchar; for (;;) { if (--i < 0) return YES; if (!jiswhite(linebuf[i])) return NO; } } void DotTo(line, col) LinePtr line; int col; { Bufpos bp; bp.p_line = line; bp.p_char = col; SetDot(&bp); } /* If bp->p_line is != current line, then save current line. Then set dot * to bp->p_line, and if they weren't equal get that line into linebuf. */ void SetDot(bp) register Bufpos *bp; { register jbool notequal; if (bp == NULL) return; notequal = bp->p_line != curline; if (notequal) lsave(); if (bp->p_line != NULL) curline = bp->p_line; if (notequal) getDOT(); curchar = bp->p_char; if (curchar > length(curline)) curchar = length(curline); } void ToLast() { SetLine(curbuf->b_last); Eol(); } int MarkThresh = 22; /* VAR: moves greater than MarkThresh will SetMark (avg screen size) */ private long line_diff; long inorder(nextp, char1, endp, char2) register LinePtr nextp, endp; int char1, char2; { register LinePtr prevp = nextp; line_diff = 0; if (nextp == endp) return char1 < char2; while (nextp && prevp) { nextp = nextp->l_next; prevp = prevp->l_prev; line_diff += 1; if (nextp == endp) return YES; if (prevp == endp) return NO; } while (nextp!=NULL) { nextp = nextp->l_next; line_diff += 1; if (nextp == endp) return YES; } while (prevp!=NULL) { prevp = prevp->l_prev; line_diff += 1; if (prevp == endp) return NO; } /* the lines are not ordered */ return -1; } /* Number of lines (forward OR back) from nextp to endp. * Note: if they are not related, returns 0. */ long LineDist(nextp, endp) LinePtr nextp, endp; { return inorder(nextp, 0, endp, 0) == -1? 0 : line_diff; } /* Number of lines forward from "from" to "to"; -1 if not found. * Note: if "to" is (LinePtr)NULL, returns number of lines to end + 1 */ long LinesTo(from, to) register LinePtr from, to; { long n = 0; for (;;) { if (from == to) return n; if (from == NULL) return -1; n += 1; from = from->l_next; } } void PushPntp(line) register LinePtr line; { if (LineDist(curline, line) >= MarkThresh) set_mark(); } void ToFirst() { SetLine(curbuf->b_first); } int length(line) LinePtr line; { return strlen(lcontents(line)); } void to_word(dir) register int dir; { if (dir == FORWARD) { for(;;) { register ZXchar c = ZXC(linebuf[curchar]); if (c == '\0') { if (curline->l_next == NULL) break; /* failure: out of buffer */ SetLine(curline->l_next); } else if (jisword(c)) { break; /* success */ } else { curchar += 1; } } } else { for (;;) { if (bolp()) { if (curline->l_prev == NULL) break; /* failure: out of buffer */ SetLine(curline->l_prev); Eol(); } else if (jisword(linebuf[curchar - 1])) { break; /* success */ } else { curchar -= 1; } } } } /* Are there any modified buffers? Allp means include B_PROCESS * buffers in the check. */ jbool ModBufs(allp) jbool allp; { register Buffer *b; for (b = world; b != NULL; b = b->b_next) if (b->b_type != B_SCRATCH && (b->b_type == B_FILE || allp) && IsModified(b)) return YES; return NO; } const char * filename(b) register const Buffer *b; { return b->b_fname ? pr_name(b->b_fname, YES) : "[No file]"; } int jmin(a, b) register int a, b; { return (a < b) ? a : b; } int jmax(a, b) register int a, b; { return (a > b) ? a : b; } char * lcontents(line) register LinePtr line; { return line == curline? linebuf : lbptr(line); } char * ltobuf(line, buf) LinePtr line; char *buf; { if (line == curline) { if (buf != linebuf) strcpy(buf, linebuf); Jr_Len = strlen(linebuf); } else { jgetline(line->l_dline, buf); } return buf; } void DOTsave(buf) Bufpos *buf; { buf->p_line = curline; buf->p_char = curchar; } /* Return YES iff we had to rearrange the order. */ jbool fixorder(line1, char1, line2, char2) register LinePtr *line1, *line2; register int *char1, *char2; { LinePtr tline; int tchar; if (inorder(*line1, *char1, *line2, *char2)) return NO; tline = *line1; tchar = *char1; *line1 = *line2; *char1 = *char2; *line2 = tline; *char2 = tchar; return YES; } jbool inlist(first, what) LinePtr first, what; { return LinesTo(first, what) != -1; } /* Make curbuf (un)modified and tell the redisplay code to update the modeline * if it will need to be changed. */ void modify() { if (!curbuf->b_modified) { UpdModLine = YES; curbuf->b_modified = YES; } DOLsave = YES; #ifdef RECOVER if (curbuf->b_type != B_SCRATCH) ModCount += 1; #endif } void unmodify() { if (curbuf->b_modified) { UpdModLine = YES; curbuf->b_modified = NO; #ifdef RECOVER /* * When a buffer transitions to unmodified * (most likely because it was saved, or if * the user invoked NotModified), then it * seems right to force a SyncRec (on the next * getch) so that any subsequent crash/recover * does not suggest recovery of this buffer. */ if (curbuf->b_type != B_SCRATCH) ModCount = SyncFreq; #endif } } /* Set or clear the divergence flag for `buf'. * A buffer that contains a file is considered to have diverged * if the file in the filesystem appears to have changed since the * last time the buffer was loaded from or saved to that file. * If the flag has changed, tell the redisplay code to update the * modeline. */ void diverge(buf, d) Buffer *buf; jbool d; { if (buf->b_diverged != d) { UpdModLine = YES; buf->b_diverged = d; } } int numcomp(s1, s2) register const char *s1, *s2; { register int count = 0; while (*s1 != '\0' && *s1++ == *s2++) count += 1; return count; } #ifdef FILENAME_CASEINSENSITIVE int numcompcase(s1, s2) register const char *s1, *s2; { register int count = 0; while (*s1 != '\0' && CharDowncase(*s1++) == CharDowncase(*s2++)) count += 1; return count; } #endif char * copystr(str) const char *str; { return str == NULL? (char *) NULL : strcpy(emalloc(strlen(str) + 1), str); } #ifndef byte_copy void byte_copy(from, to, count) UnivConstPtr *from; UnivPtr *to; register size_t count; { register const char *p = from; register char *q = to; if (count != 0) { do *q++ = *p++; while (--count != 0); } } #endif void len_error(flag) int flag; { static const char mesg[] = "[line too long]"; if (flag == JMP_COMPLAIN) { complain(mesg); /* NOTREACHED */ } else { error(mesg); /* NOTREACHED */ } } /* Insert num copies of character c at offset atchar in buffer buf of size max */ void ins_c(c, buf, atchar, num, max) DAPchar c; char *buf; int atchar, num, max; { /* hint to reader: all copying and filling is done right to left */ register char *from, *to; int taillen; if (num <= 0) return; from = &buf[atchar]; taillen = *from == '\0'? 1 : strlen(from) + 1; /* include NUL */ if (atchar + taillen + num > max) { len_error(JMP_COMPLAIN); /* NOTREACHED */ } from += taillen; to = from + num; do { *--to = *--from; } while (--taillen != 0); while (to != from) *--to = c; } jbool TwoBlank() { register LinePtr next = curline->l_next; return (next != NULL && *(lcontents(next)) == '\0' && next->l_next != NULL && *(lcontents(next->l_next)) == '\0'); } void linecopy(onto, atchar, from) register char *onto, *from; int atchar; { register char *endp = &onto[LBSIZE]; onto += atchar; do { if (onto >= endp) { len_error(JMP_ERROR); /* NOTREACHED */ } } while ((*onto++ = *from++) != '\0'); } char * IOerr(err, file) const char *err, *file; { return sprint("Couldn't %s \"%s\".", err, file); } #ifdef UNIX void dopipe(p) int *p; { if (pipe(p) == -1) { complain("[Pipe failed: %s]", strerror(errno)); /* NOTREACHED */ } } void pipeclose(p) int *p; { (void) close(p[0]); (void) close(p[1]); } #endif /* UNIX */ /* NOSTRICT */ UnivPtr emalloc(size) size_t size; { register UnivPtr ptr; if ((ptr = malloc(size)) == NULL) { /* Try garbage collecting lines */ GCchunks(); if ((ptr = malloc(size)) == NULL) { /* Uh ... Oh screw it! */ error("[Out of memory]"); /* NOTREACHED */ } } return ptr; } UnivPtr erealloc(ptr, size) UnivPtr ptr; size_t size; { if (ptr == NULL) { ptr = emalloc(size); } else if ((ptr = realloc(ptr, size)) == NULL) { /* no second chance for realloc! */ error("[out of memory]"); /* NOTREACHED */ } return ptr; } /* Return the basename of pathname F. * * - System V release 4 includes a function named "basename" in libgen. * It is incompatible with ours: * + it strips trailing "/" characters (does this matter?) * + although not clearly documented, this stripping modifies the argument! * + it handles the NULL pointer and the null string as "." * * - LINUX also provides a basename * + at least one version of Slackware puts the prototype in * so it cannot be ignored. * + This LINUX prototype declares the parameter to be of const char * * type. This is incompatible with ours and with SVR4's. * + The fact that the argument is a pointer to const implies that * the source string cannot be modified. Therefore trailing "/" * characters are not stripped from the source. * + Either stripping isn't done to the result OR the result must be * placed in a distinct chunk of memory. How is this memory managed? * * To avoid conflict, we have renamed ours to "jbasename". */ const char * jbasename(f) register const char *f; { register char *cp; #ifdef MSFILESYSTEM if (f[0] != '\0' && f[1] == ':') f += 2; if ((cp = strrchr(f, '\\')) != NULL) f = cp + 1; #endif /* MSFILESYSTEM */ if ((cp = strrchr(f, '/')) != NULL) f = cp + 1; return f; } void push_env(savejmp) jmp_buf savejmp; { byte_copy((UnivPtr) mainjmp, (UnivPtr) savejmp, sizeof (jmp_buf)); } void pop_env(savejmp) jmp_buf savejmp; { byte_copy((UnivPtr) savejmp, (UnivPtr) mainjmp, sizeof (jmp_buf)); } /* get the time buf, designated by *timep, from FROM to TO. */ char * get_time(timep, buf, from, to) time_t *timep; char *buf; int from, to; { time_t now; char *cp; if (timep != NULL) now = *timep; else (void) time(&now); cp = ctime(&now) + from; if (to == -1) cp[strlen(cp) - 1] = '\0'; /* Get rid of \n */ else cp[to - from] = '\0'; if (buf) { strcpy(buf, cp); return buf; } else { return cp; } } /* Are s1 and s2 equal, at least for the first n chars, ignoring case? */ jbool caseeqn(s1, s2, n) register const char *s1, *s2; register size_t n; { if (s1==NULL || s2==NULL) return NO; for (;;) { if (n == 0) return YES; n--; if (!cind_eq(*s1, *s2++)) return NO; if (*s1++ == '\0') return YES; } } /* copy a string into buffer; truncate silently if too large; NUL-pad. * Note: buffer must be 1 larger than n to fit NUL! * Duplicated in recover.c: needed by scandir.c */ void null_ncpy(to, from, n) char *to; const char *from; size_t n; { (void) strncpy(to, from, n); to[n] = '\0'; } /* Copy a string into a buffer; truncate silently if string is too large */ void truncstrsub(buf, str, bufsz) char *buf; size_t bufsz; const char *str; { size_t strsz = strlen(str); if (bufsz == 0) { complain("internal error in truncstrsub"); /* cannot even fit NUL */ /* NOTREACHED */ } else { size_t sz = strsz < bufsz ? strsz : bufsz - 1; byte_move(str, buf, sz); buf[sz] = '\0'; } } /* Copy a string into a buffer; complain if string is too large */ void jamstrsub(buf, str, bufsz) char *buf; const char *str; size_t bufsz; { size_t strsz = strlen(str); if (strsz < bufsz) { byte_move(str, buf, strsz); buf[strsz] = '\0'; } else { complain("string too long"); /* NOTREACHED */ } } /* Concatenate a string onto a buffer; complain if buffer not large enough */ void jamstrcat(buf, str, bufsz) char *buf; const char *str; size_t bufsz; { size_t bstrsz = strlen(buf); if (bstrsz >= bufsz) { complain("base string too long!"); /* NOTREACHED */ } jamstrsub(buf + bstrsz, str, bufsz - bstrsz); } jbool sindex(pattern, string) register const char *pattern, *string; { register size_t len = strlen(pattern); if (len == 0) return YES; while (*string != '\0') { if (*pattern == *string && strncmp(pattern, string, len) == 0) return YES; string += 1; } return NO; } /* Free, then allocate a block. * Like erealloc, except that the previous contents of the block are lost. */ UnivPtr freealloc(obj, size) register UnivPtr obj; size_t size; { if (obj != NULL) obj = realloc(obj, size); if (obj == NULL) obj = emalloc(size); return obj; } /* order file names (parameter for qsort) */ int fnamecomp(a, b) UnivConstPtr a, b; { return strcmp(*(const char **)a, *(const char **)b); } #ifdef NO_STRERROR extern int sys_nerr; extern char *sys_errlist[]; /* * Unix version of strerror - map error number to descriptive string. * ANSI systems have this. */ char * strerror(errnum) int errnum; { return 0 < errnum && errnum < sys_nerr ? sys_errlist[errnum] : sprint("Error number %d", errnum); } #endif /* NO_STRERROR */ /* decode a pair of characters representing \x or ^x */ ZXchar DecodePair(first, second) ZXchar first, second; { if (second == EOF || second == '\n') { complain("unexpected end of file after %p", first); /* NOTREACHED */ } if (first == '^') { if (second == '?') { second = DEL; } else { ZXchar us = CharUpcase(second); if (us < '@' || '_' < us) { complain("unknown control character %p", second); /* NOTREACHED */ } second = CTL(us); } } return second; } #if defined(IPROCS) || defined(SUBSHELL) /* Convenience routine, initializes envp properly if it is null, * hides a bit of the abstraction and some duplicated code */ const char ** jenvdata(envp) Env *envp; { if (envp->e_data == NULL) { envp->e_data = (const char **) environ; /* avoid gcc warning */ envp->e_malloced = NO; envp->e_headroom = 0; } return envp->e_data; } /* Put a definition into the environment. * Same as putenv(3) in SVID 3, POSIX, and BSD 4.3. */ void jputenv(envp, def) Env *envp; const char *def; { const char **p, **e; const char *eq; if ((eq = strchr(def, '=')) == NULL) return; for (p = e = jenvdata(envp); ; p++) { if (*p == NULL) { if (envp->e_headroom == 0) { # define JENV_INCR 5 size_t sz = ((p-e) + 1) * sizeof(char *); const char **ne = (const char **) malloc(sz + JENV_INCR*sizeof(char *)); if (ne == NULL) break; /* malloc failed: give up -- doesn't matter much */ byte_copy(envp->e_data, ne, sz); p = ne + (p-e); if (envp->e_malloced) free((UnivPtr)envp->e_data); envp->e_data = e = ne; envp->e_malloced = YES; envp->e_headroom = JENV_INCR; # undef JENV_INCR } envp->e_headroom -= 1; *p++ = copystr(def); *p = NULL; break; } if (strncmp(*p, def, (size_t) (eq - def + 1)) == 0) { *p = copystr(def); break; } } } /* Remove any definitions of name from the environment. * Same as 4.3BSD's unsetenv(3). */ void junsetenv(envp, name) Env *envp; const char *name; { const char **p, **q; size_t l = strlen(name); for (p = q = jenvdata(envp);;) { const char *e = *p++; *q = e; if (e == NULL) break; if (strncmp(e, name, l) == 0 && e[l] == '=') { /* unset this one by not advancing q */ envp->e_headroom += 1; } else { q += 1; } } } #endif /* defined(IPROCS) */ jove-4.17.5.5/util.h000066400000000000000000000105451501102521500140410ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* some utility functions, as macros, to be included by jove.h */ extern int fnamecomp proto((UnivConstPtr, UnivConstPtr)); /* order file names */ #define IsModified(b) ((b)->b_modified) #define SavLine(a, b) ((a)->l_dline = jputline((b))) #define SetLine(line) DotTo((line), 0) #define bobp() (firstp(curline) && bolp()) #define bolp() (curchar == 0) #define eobp() (lastp(curline) && eolp()) #define eolp() (linebuf[curchar] == '\0') #define firstp(line) ((line) == curbuf->b_first) #define getDOT() jgetline(curline->l_dline, linebuf) #define lastp(line) ((line) == curbuf->b_last) extern UnivPtr emalloc proto((size_t size)), erealloc proto((UnivPtr ptr, size_t size)); extern char *IOerr proto((const char *err, const char *file)), *copystr proto((const char *str)), *get_time proto((time_t *timep,char *buf,int from,int to)), *lcontents proto((LinePtr line)), *ltobuf proto((LinePtr line,char *buf)); extern const char *jbasename proto((const char *f)), *filename proto((const Buffer *b)); extern long inorder proto((LinePtr nextp,int char1,LinePtr endp,int char2)), LineDist proto((LinePtr nextp,LinePtr endp)), LinesTo proto((LinePtr from, LinePtr to)); extern int length proto((LinePtr line)), jmax proto((int a,int b)), jmin proto((int a,int b)), numcomp proto((const char *s1, const char *s2)), numcompcase proto((const char *s1, const char *s2)); extern ZXchar DecodePair proto((ZXchar first, ZXchar second)); extern jbool caseeqn proto((const char *s1, const char *s2, size_t n)), TwoBlank proto((void)), blnkp proto((char *buf)), within_indent proto((void)), fixorder proto((LinePtr *line1,int *char1,LinePtr *line2,int *char2)), inlist proto((LinePtr first,LinePtr what)), sindex proto((const char *pattern, const char *string)), ModBufs proto((jbool allp)); extern void DOTsave proto((Bufpos *buf)), DotTo proto((LinePtr line,int col)), PushPntp proto((LinePtr line)), SetDot proto((Bufpos *bp)), ToFirst proto((void)), ToLast proto((void)), ins_c proto((DAPchar c,char *buf,int atchar,int num,int max)), len_error proto((int flag)) NEVER_RETURNS, linecopy proto((char *onto,int atchar,char *from)), modify proto((void)), diverge proto((Buffer *buf, jbool d)), null_ncpy proto((char *to, const char *from, size_t n)), #ifdef UNIX dopipe proto((int *p)), pipeclose proto((int *p)), #endif pop_env proto((jmp_buf)), push_env proto((jmp_buf)), to_word proto((int dir)), unmodify proto((void)); extern UnivPtr freealloc proto((UnivPtr obj, size_t size)); #if defined(IPROCS) || defined(SUBSHELL) # ifndef OWCDOS /* * The Open Watcom C declaration of environ has some macro * decorations that do not match with this, so we skip this, * their declaration works and is available. * Linux only provides this in unistd.h if _GNU_SOURCE is defined, * which we do not. * *BSD and OpenIndiana (Solaris) and probably most other * systems do not provide it, since it is not part of POSIX, * but environ seems remarkably portable, nonetheless! */ extern char **environ; /* */ # endif typedef struct { const char **e_data; jbool e_malloced; int e_headroom; /* remaining room in e_data array */ } Env; extern const char ** jenvdata proto((Env *envp)); extern void jputenv proto((Env *envp, const char *def)), junsetenv proto((Env *envp, const char *name)); #endif /* defined(IPROCS) */ /* copy a string into a possibly-too-small buffer * trunc* silently truncates a too-large string. * jam* complain if the string is too large. */ #define truncstr(buf, str) truncstrsub(buf, str, sizeof(buf)) #define jamstr(buf, str) jamstrsub(buf, str, sizeof(buf)) extern void truncstrsub proto((char *buf, const char *str, size_t bufsz)), jamstrsub proto((char *buf, const char *str, size_t bufsz)), jamstrcat proto((char *buf, const char *str, size_t bufsz)); /* Variables: */ extern int MarkThresh; /* VAR: moves greater than MarkThresh will SetMark */ /* externs.h: * strerror (ifdef NO_STRERROR) */ jove-4.17.5.5/vars.c000066400000000000000000000044121501102521500140260ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ #include "jove.h" #include "extend.h" #include "vars.h" /* included for variable declarations */ #include "abbrev.h" #include "ask.h" #include "c.h" #include "jctype.h" #include "disp.h" #include "insert.h" /* #include "io.h" */ #include "sysprocs.h" /* needed for iproc.h */ #include "iproc.h" /* #include "jove.h" */ #include "mac.h" #include "mouse.h" #include "para.h" #include "proc.h" #include "re.h" #include "reapp.h" #include "rec.h" #include "screen.h" #include "term.h" #include "ttystate.h" /* #include "util.h" */ #include "wind.h" #define VAR(v) (UnivPtr)(v), sizeof(v) #include "vars.tab" const char * getvar(name, vbuf, vbufsize) const char *name; char *vbuf; size_t vbufsize; { register ZXchar c; const struct variable *vp, *which = NULL; size_t vlen = strlen(name); int ic; vbuf[0] = '\0'; /* look it up (in the reduced search space) */ c = ZXC(name[0]); ic = IDX(c); if (ic >= 0 && ic <= IDXSZ && (vp = varidx[ic]) != NULL) { for (; vp->Name != NULL && vp->Name[0] == name[0]; vp++) { if (strncmp(vp->Name, name, vlen) == 0) { if (vp->Name[vlen] != '\0' && which != NULL) { complain("[\"%s\" ambiguous]", name); /* NOTREACHED */ } which = vp; if (vp->Name[vlen] == '\0') break; } } } if (which == NULL) { complain("[variable \"%s\" unknown]", name); /* NOTREACHED */ } vpr_aux(vp, vbuf, vbufsize); return vbuf; } const data_obj * findvar(prompt) const char *prompt; { static const char *strings[elemsof(variables)]; static int last = -1; if (strings[0] == NULL) { register const char **strs = strings; register const struct variable *v = variables; for (; v->Name; v++) *strs++ = v->Name; *strs = NULL; } last = complete(strings, last >= 0? strings[last] : (char *)NULL, prompt, ALLOW_OLD); return (data_obj *) &variables[last]; } jove-4.17.5.5/vars.h000066400000000000000000000034171501102521500140370ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ struct variable { /* Type and Name must match data_obj */ int Type; /* in this case a variable */ const char *Name; /* name is always second */ UnivPtr v_value; size_t v_size; int v_flags; /* type and attributes */ }; #define V_TYPEMASK 017 /* mask for type part */ /* variable types (choose one) * Note: V_INT through V_NAT are used as subscripts in vset_aux. */ #define V_INT 001 /* integer */ #define V_WHOLEX 002 /* whole numbers, extended with -1 */ #define V_WHOLE 003 /* whole number */ #define V_NAT 004 /* natural number */ #define V_BOOL 005 /* is a boolean */ #define V_STRING 006 /* is a string */ #define V_CHAR 007 /* is a character */ #define V_FILENAME 010 /* a file name */ /* variable attributes (choose any set) */ #define V_FMODE 00020 /* number is a file mode: base 8 */ #define V_MODELINE 00040 /* update modeline */ #define V_CLRSCREEN 00100 /* clear and redraw screen */ #define V_TTY_RESET 00200 /* redo the tty modes */ #define V_LOCALE 00400 /* locale has changed -- do a setlocale */ #define V_UPDFREQ 01000 /* update-time-frequency -- reset alarm */ #define V_READONLY 02000 /* not user-modifiable, set by Jove */ extern const struct variable variables[]; extern const struct variable *varidx[IDXSZ]; extern const char *getvar proto((const char * /*name*/, char * /*vbuf*/, size_t /*vbufsize*/)); jove-4.17.5.5/vars.tab000066400000000000000000000135251501102521500143570ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* This file is #included by vars.c and setmaps.c * Each defines VAR differently! */ /* Table of variables * * Note: must be kept in alphabetical order (setmaps does a check). */ const struct variable variables[] = { { VARIABLE, "abort-char", VAR(&AbortChar), V_CHAR }, #ifdef UNIX { VARIABLE, "allow-^S-and-^Q", VAR(&OKXonXoff), V_BOOL|V_TTY_RESET }, #endif { VARIABLE, "allow-bad-characters-in-filenames", VAR(&OkayBadChars), V_BOOL }, #ifdef ABBREV { VARIABLE, "auto-case-abbrev", VAR(&AutoCaseAbbrev), V_BOOL }, #endif #ifdef F_COMPLETION { VARIABLE, "bad-filename-extensions", VAR(BadExtensions), V_STRING }, #endif { VARIABLE, "c-argument-indentation", VAR(&CArgIndent), V_WHOLEX }, { VARIABLE, "c-indentation-increment", VAR(&CIndIncrmt), V_WHOLE }, { VARIABLE, "case-ignore-search", VAR(&CaseIgnore), V_BOOL }, #ifdef CMT_FMT { VARIABLE, "comment-format", VAR(CmtFmt), V_STRING }, #endif #ifdef IPROCS { VARIABLE, "dbx-format-string", VAR(dbx_parse_fmt), V_STRING }, #endif #ifdef BIFF { VARIABLE, "disable-biff", VAR(&DisBiff), V_BOOL|V_TTY_RESET }, #endif { VARIABLE, "display-default-filenames", VAR(&DispDefFs), V_BOOL }, #ifdef F_COMPLETION { VARIABLE, "display-filenames-with-bad-extensions", VAR(&DispBadFs), V_BOOL }, #endif #ifdef IBMPCDOS { VARIABLE, "enhanced-keyboard", VAR(&enhanced_keybrd), V_BOOL }, #endif { VARIABLE, "error-format-string", VAR(ErrFmtStr), V_STRING }, { VARIABLE, "error-window-size", VAR(&EWSize), V_NAT }, #ifdef F_COMPLETION # ifndef MAC /* no environment in MacOS */ { VARIABLE, "expand-environment-variables", VAR(&DoEVexpand), V_BOOL }, # endif #endif #ifdef UNIX { VARIABLE, "file-creation-mode", VAR(&CreatMode), V_WHOLE|V_FMODE }, #endif { VARIABLE, "files-should-end-with-newline", VAR(&EndWNewline), V_BOOL }, #ifdef HIGHLIGHTING # ifdef PCSCRATTR { VARIABLE, "highlight-attribute", VAR(&Hlattr), V_WHOLE|V_CLRSCREEN }, # endif { VARIABLE, "highlight-mark", VAR(&MarkHighlighting), V_BOOL|V_CLRSCREEN }, #endif /* HIGHLIGHTING */ #ifdef UNIX { VARIABLE, "interrupt-character", VAR(&IntChar), V_CHAR|V_TTY_RESET }, #endif #if defined(UNIX) || defined(MINGW) { VARIABLE, "jove-compiled-with", VAR(JoveCompiled), V_STRING|V_READONLY}, #endif { VARIABLE, "jove-features", VAR(JoveFeatures), V_STRING|V_READONLY}, #if defined(UNIX) || defined(MINGW) { VARIABLE, "jove-linked-with", VAR(JoveLinked), V_STRING|V_READONLY}, #endif #if defined(USE_CTYPE) && !defined(NO_SETLOCALE) { VARIABLE, "lc-ctype", VAR(LcCtype), V_STRING|V_LOCALE }, #endif { VARIABLE, "left-margin", VAR(&LMargin), V_WHOLE }, #if defined(SUBSHELL) || defined(PIPEPROCS) || defined(RECOVER) { VARIABLE, "lib-dir-pathname", VAR(LibDir), V_FILENAME }, #endif #ifdef MAC { VARIABLE, "macify", VAR(&Macmode), V_BOOL }, #endif #ifdef UNIX { VARIABLE, "mail-check-frequency", VAR(&MailInt), V_WHOLE }, { VARIABLE, "mailbox", VAR(Mailbox), V_FILENAME }, #endif /* UNIX */ #ifdef BACKUPFILES { VARIABLE, "make-backup-files", VAR(&BkupOnWrite), V_BOOL }, #endif { VARIABLE, "mark-threshold", VAR(&MarkThresh), V_WHOLEX }, { VARIABLE, "match-regular-expressions", VAR(&UseRE), V_BOOL }, { VARIABLE, "meta-key", VAR(&MetaKey), V_BOOL|V_TTY_RESET }, { VARIABLE, "mode-line", VAR(ModeFmt), V_STRING|V_MODELINE }, #ifdef PCSCRATTR { VARIABLE, "mode-line-attribute", VAR(&Mlattr), V_WHOLE|V_CLRSCREEN }, #endif { VARIABLE, "mode-line-should-standout", VAR(&BriteMode), V_BOOL|V_MODELINE }, { VARIABLE, "one-key-confirmation", VAR(&OneKeyConfirmation), V_BOOL }, { VARIABLE, "paragraph-delimiter-pattern", VAR(ParaDelim), V_STRING }, { VARIABLE, "paren-flash-delay", VAR(&PDelay), V_WHOLE }, #ifdef IPROCS { VARIABLE, "process-prompt", VAR(proc_prompt), V_STRING }, #endif { VARIABLE, "right-margin", VAR(&RMargin), V_NAT }, { VARIABLE, "save-on-exit", VAR(&SaveOnExit), V_BOOL }, { VARIABLE, "scroll-all-lines", VAR(&ScrollAll), V_BOOL }, #ifdef HIGHLIGHTING { VARIABLE, "scroll-bar", VAR(&ScrollBar), V_BOOL|V_MODELINE }, #endif { VARIABLE, "scroll-step", VAR(&ScrollStep), V_INT }, { VARIABLE, "scroll-width", VAR(&ScrollWidth), V_WHOLE }, { VARIABLE, "search-exit-char", VAR(&SExitChar), V_CHAR }, { VARIABLE, "send-typeout-to-buffer", VAR(&UseBuffers), V_BOOL }, { VARIABLE, "share-dir-pathname", VAR(ShareDir), V_FILENAME }, #ifdef SUBSHELL { VARIABLE, "shell", VAR(Shell), V_FILENAME }, { VARIABLE, "shell-flags", VAR(ShFlags), V_STRING }, #endif { VARIABLE, "space-sentence-2", VAR(&SpaceSent2), V_BOOL }, #ifdef SPELL { VARIABLE, "spell-command-format", VAR(SpellCmdFmt), V_STRING }, #endif #ifdef RECOVER { VARIABLE, "sync-frequency", VAR(&SyncFreq), V_WHOLE }, #endif { VARIABLE, "tab-width", VAR(&tabstop), V_WHOLE|V_CLRSCREEN }, { VARIABLE, "tag-file", VAR(TagFile), V_FILENAME }, #ifdef PCSCRATTR { VARIABLE, "text-attribute", VAR(&Txattr), V_WHOLE|V_CLRSCREEN }, #endif { VARIABLE, "tmp-file-pathname", VAR(TmpDir), V_FILENAME }, #ifdef UNIX { VARIABLE, "update-time-frequency", VAR(&UpdFreq), V_WHOLE|V_UPDFREQ }, #endif #ifdef ID_CHAR { VARIABLE, "use-i/d-char", VAR(&UseIC), V_BOOL }, #endif { VARIABLE, "visible-bell", VAR(&VisBell), V_BOOL }, #if defined(SUBSHELL) || defined(IPROCS) { VARIABLE, "wrap-process-lines", VAR(&WrapProcessLines), V_BOOL }, #endif { VARIABLE, "wrap-search", VAR(&WrapScan), V_BOOL }, #ifdef SUBSHELL { VARIABLE, "write-files-on-make", VAR(&WtOnMk), V_BOOL }, #endif #ifdef MOUSE { VARIABLE, "xt-mouse", VAR(&XtermMouse), V_BOOL|V_TTY_RESET }, #endif { VARIABLE, NULL, NULL, (size_t)0, 0 }, }; jove-4.17.5.5/version.h000066400000000000000000000012371501102521500145470ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* NOTE: use only spaces, no TABS below to ensure "make .version" works */ #define jversion "4.17.5.5" /* make .version uses sed to extract this */ #define jversion_lnum 4,17,5,5 /* for windows jjove.rc file */ jove-4.17.5.5/win32.c000066400000000000000000000530441501102521500140220ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* Win32 support routines for Jove Keyboard and Screen */ #include "jove.h" #ifdef WIN32 /* the body is the rest of this file */ #include "fp.h" /* scr_putchar */ #include "chars.h" #include "screen.h" #include "disp.h" /* for redisplay() */ # undef Fill /* sigh, used as a field name in some windows header! */ # undef CR /* sigh, used as a field name in some windows header! */ #include INPUT_RECORD in_event[NCHARS], *eventp = in_event; /* Input events e.g. keyboard, mouse-click */ DWORD nevents; private HANDLE conin, conout, conerr; /* Console handles */ private COORD curpos; private COORD maxpos; private HANDLE old_stdout, old_stderr; private WORD old_attributes; private BOOL WINAPI ctrlHandler proto((DWORD type)); /* Control handler */ #define CHECK(fn) { if (!(fn)) ConsoleFail(#fn); } private void ConsoleFail(char *fdef); void getTERM() { } void ttysetattr(n) jbool n; /* also used as subscript! */ { CONSOLE_SCREEN_BUFFER_INFO info; COORD bufsize; if (n) { if (conout == NULL) { /* Create our own console buffer so we can easily restore * the startup environment. This also allows us to resize * it to eliminate the scroll bars, at least where the * full Console API is implemented (i.e. on Windows NT). * (Windows 95 seems to ignore whatever we do to the window). */ old_stdout = GetStdHandle(STD_OUTPUT_HANDLE); old_stderr = GetStdHandle(STD_ERROR_HANDLE); CHECK(GetConsoleScreenBufferInfo(old_stdout, &info)); old_attributes = info.wAttributes; conout = CreateConsoleScreenBuffer(GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, CONSOLE_TEXTMODE_BUFFER, NULL); CHECK(DuplicateHandle(GetCurrentProcess(), conout, GetCurrentProcess(), &conerr, 0, TRUE, DUPLICATE_SAME_ACCESS)); bufsize.X = info.srWindow.Right-info.srWindow.Left+1; bufsize.Y = info.srWindow.Bottom-info.srWindow.Top+1; CHECK(SetConsoleScreenBufferSize(conout, bufsize)); #ifdef DEBUG { char tracebuf[100]; DWORD version = GetVersion(); wsprintf(tracebuf, "%s Windows %d.%d Build %d\n", (version > 0 ? "MS-DOS" : "NT"), LOBYTE(LOWORD(version)), HIBYTE(LOWORD(version)), HIWORD(version)&0x7FFF); OutputDebugString(tracebuf); wsprintf(tracebuf, "Console Size=(%d,%d), Window=(%d,%d) to (%d,%d)\n", info.dwSize.X, info.dwSize.Y, info.srWindow.Left, info.srWindow.Top, info.srWindow.Right, info.srWindow.Bottom); OutputDebugString(tracebuf); } #endif CHECK(SetStdHandle(STD_OUTPUT_HANDLE, conout)); CHECK(SetStdHandle(STD_ERROR_HANDLE, conerr)); CHECK(SetConsoleActiveScreenBuffer(conout)); } CHECK(SetConsoleTitle("Jove for Win32")); conin = GetStdHandle(STD_INPUT_HANDLE); /* conout = GetStdHandle(STD_OUTPUT_HANDLE); */ # ifdef MOUSE SetConsoleMode(conin, ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT); MouseOn(); # else SetConsoleMode(conin, ENABLE_WINDOW_INPUT); # endif /* !MOUSE */ SetConsoleMode(conout, ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT); SetFileApisToOEM(); SetConsoleCtrlHandler(ctrlHandler, TRUE); } else { CHECK(SetStdHandle(STD_OUTPUT_HANDLE, old_stdout)); CHECK(SetStdHandle(STD_ERROR_HANDLE, old_stderr)); CHECK(SetConsoleActiveScreenBuffer(old_stdout)); CloseHandle(conout); CloseHandle(conerr); SetConsoleTextAttribute(old_stdout, old_attributes); conin = conout = conerr = NULL; # ifdef MOUSE MouseOff(); # endif SetConsoleCtrlHandler(ctrlHandler, FALSE); } } void ttsize() { /* ??? We really ought to wait until the screen is big enough: * at least three lines high (one line each for buffer, mode, * and message) and at least twelve columns wide (eight for * line number, one for content, two for overflow indicators, * and one blank at end). */ CONSOLE_SCREEN_BUFFER_INFO info; GetConsoleScreenBufferInfo(conout, &info); maxpos.X = info.srWindow.Right-info.srWindow.Left+1; maxpos.Y = info.srWindow.Bottom-info.srWindow.Top+1; if (maxpos.X != info.dwSize.X || maxpos.Y != info.dwSize.Y) { CHECK(SetConsoleScreenBufferSize(conout, maxpos)); curpos.X = curpos.Y = 0; } else { curpos = info.dwCursorPosition; } CO = maxpos.X; if (CO > MAXCOLS) CO = MAXCOLS; LI = maxpos.Y; ILI = LI - 1; } #ifdef DEBUG private char * formatChar(char c) { static char cbuf[6]; if (c >= ' ' && c <= '~') wsprintf(cbuf, "%c", c); else wsprintf(cbuf, "\\%03o", (unsigned char)c); return cbuf; } private char * formatEvent(INPUT_RECORD* event) { static char buffer[128]; switch (event->EventType) { case KEY_EVENT: wsprintf(buffer, "KEY%s '%s%s%s%s'[%d times] Scan=%d Keycode=%d\n", event->Event.KeyEvent.bKeyDown?"DOWN":"UP", (event->Event.KeyEvent.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED) ? "ALT-" : ""), (event->Event.KeyEvent.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED) ? "CTRL-" : ""), (event->Event.KeyEvent.dwControlKeyState & (SHIFT_PRESSED) ? "SHIFT-" : ""), formatChar(event->Event.KeyEvent.uChar.AsciiChar), event->Event.KeyEvent.wRepeatCount, event->Event.KeyEvent.wVirtualScanCode, event->Event.KeyEvent.wVirtualKeyCode ); break; case MOUSE_EVENT: wsprintf(buffer, "MOUSE%s%s %s%s%s%s%s%s (%d,%d)\n", (event->Event.MouseEvent.dwEventFlags&MOUSE_MOVED ? " MOVED" : ""), (event->Event.MouseEvent.dwEventFlags&DOUBLE_CLICK? " DOUBLE_CLICK" : ""), (event->Event.MouseEvent.dwButtonState&1 ? "LEFT" : ""), (event->Event.MouseEvent.dwButtonState&2 ? "RIGHT" : ""), (event->Event.MouseEvent.dwButtonState&4 ? "MIDDLE" : ""), (event->Event.MouseEvent.dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED) ? "ALT-" : ""), (event->Event.MouseEvent.dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED) ? "CTRL-" : ""), (event->Event.MouseEvent.dwControlKeyState & (SHIFT_PRESSED) ? "SHIFT-" : ""), event->Event.MouseEvent.dwMousePosition.X, event->Event.MouseEvent.dwMousePosition.Y ); break; case WINDOW_BUFFER_SIZE_EVENT: wsprintf(buffer, "RESIZE (%d,%d)\n", eventp->Event.WindowBufferSizeEvent.dwSize.Y, eventp->Event.WindowBufferSizeEvent.dwSize.X); break; case MENU_EVENT: wsprintf(buffer, "MENU %d\n", eventp->Event.MenuEvent.dwCommandId); break; case FOCUS_EVENT: wsprintf(buffer, "FOCUS %d\n", eventp->Event.FocusEvent.bSetFocus); break; default: wsprintf(buffer, "UNKNOWN %d\n", eventp->EventType); break; } return buffer; } #endif /* DEBUG */ /* MapKeyEventToChars maps Console KEY_RECORDs into a string of characters. * The mapping rules are basically those of the IBM AT BIOS as modified for * use by JOVE (i.e. the result should agree with what a JOVE user would see * running the MS-DOS version of Jove). */ private int MapKeyEventToChars(KEY_EVENT_RECORD* key, char *bptr) { int cnt = 0; if (key->bKeyDown) { if (key->uChar.AsciiChar) { if ((key->dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) && key->uChar.AsciiChar == ' ') { bptr[cnt++] = '\0'; } else if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { bptr[cnt++] = PCNONASCII; if (key->wVirtualScanCode >= 2 && key->wVirtualScanCode <= 13) { /* Top row (numeric keys) */ bptr[cnt++] = key->wVirtualScanCode + 118; } else { bptr[cnt++] = key->wVirtualScanCode; } } else { bptr[cnt++] = key->uChar.AsciiChar; } } else { # define ShiftSelect(plain, shifted, ctrled, alted) ( \ (key->dwControlKeyState & SHIFT_PRESSED) \ ? (shifted) \ : (key->dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) \ ? (ctrled) \ : (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) \ ? (alted) \ : (plain)) switch (key->wVirtualKeyCode) { case VK_F1: case VK_F2: case VK_F3: case VK_F4: case VK_F5: case VK_F6: case VK_F7: case VK_F8: case VK_F9: case VK_F10: bptr[cnt++] = PCNONASCII; bptr[cnt++] = key->wVirtualKeyCode - VK_F1 + ShiftSelect(59, 84, 94, 104); break; case VK_F11: case VK_F12: bptr[cnt++] = PCNONASCII; bptr[cnt++] = key->wVirtualKeyCode - VK_F11 + ShiftSelect(133, 135, 137, 139); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '0': bptr[cnt++] = PCNONASCII; bptr[cnt++] = key->wVirtualScanCode + 118; break; case VK_HOME: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(71, 171, 119, 151); break; case VK_UP: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(72, 171, 141, 152); break; case VK_PRIOR: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(73, 172, 132, 153); break; case VK_SUBTRACT: /* KEYPAD- */ bptr[cnt++] = PCNONASCII; if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { if (key->dwControlKeyState & SHIFT_PRESSED) { bptr[cnt++] = (unsigned char)174; } else { bptr[cnt++] = 74; } } else { bptr[cnt++] = (unsigned char)142; } break; case VK_LEFT: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(75, 175, 115, 155); break; case VK_RIGHT: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(77, 177, 116, 157); break; case VK_ADD: /* KEYPAD+ */ bptr[cnt++] = PCNONASCII; if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { if (key->dwControlKeyState & SHIFT_PRESSED) { bptr[cnt++] = (unsigned char)178; } else { bptr[cnt++] = 78; } } else { bptr[cnt++] = (unsigned char)144; } break; case VK_END: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(79, 179, 117, 159); break; case VK_DOWN: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(80, 180, 145, 160); break; case VK_NEXT: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(81, 181, 118, 161); break; case VK_INSERT: bptr[cnt++] = PCNONASCII; bptr[cnt++] = ShiftSelect(82, 182, 146, 162); break; case VK_DELETE: if (key->dwControlKeyState & SHIFT_PRESSED) { bptr[cnt++] = PCNONASCII; bptr[cnt++] = (unsigned char)183; } else if (key->dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) { bptr[cnt++] = PCNONASCII; bptr[cnt++] = (unsigned char)147; } else if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { bptr[cnt++] = PCNONASCII; bptr[cnt++] = (unsigned char)163; } else { bptr[cnt++] = '\177'; /* Mapped to ASCII DEL */ } break; case VK_DIVIDE: /* KEYPAD/ */ bptr[cnt++] = PCNONASCII; if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { bptr[cnt++] = (unsigned char)164; } else { bptr[cnt++] = (unsigned char)149; } break; case VK_MULTIPLY: /* KEYPAD* */ bptr[cnt++] = PCNONASCII; if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { bptr[cnt++] = 55; } else { bptr[cnt++] = (unsigned char)150; } break; case VK_NUMPAD5: bptr[cnt++] = PCNONASCII; bptr[cnt++] = (unsigned char)143; break; case VK_PRINT: /* PRINT SCREEN */ bptr[cnt++] = PCNONASCII; bptr[cnt++] = 113; break; case VK_ESCAPE: if (key->dwControlKeyState & (RIGHT_ALT_PRESSED|LEFT_ALT_PRESSED)) { bptr[cnt++] = PCNONASCII; bptr[cnt++] = key->wVirtualScanCode; } else { bptr[cnt++] = '\033'; /* ASCII ESC */ } break; case 'C': /* PRINT SCREEN */ if (key->dwControlKeyState & (RIGHT_CTRL_PRESSED|LEFT_CTRL_PRESSED)) { bptr[cnt++] = '\003'; /* Ctrl-C : remapped in Windows 95 */ } else { bptr[cnt++] = PCNONASCII; bptr[cnt++] = key->wVirtualScanCode; } break; case VK_CAPITAL: case VK_SHIFT: case VK_CONTROL: case VK_MENU: case VK_NUMLOCK: case VK_SCROLL: /* Modifiers - ignore them. */ break; default: bptr[cnt++] = PCNONASCII; bptr[cnt++] = key->wVirtualScanCode; break; } # undef ShiftSelect } } return cnt; } int getInputEvents(char *bp, int size) { int nchars = 0; if (eventp >= in_event+nevents) { if (!ReadConsoleInput(conin, in_event, NCHARS, &nevents)) { complain("ReadConsole failed (shouldn't happen)"); /* NOTREACHED */ } eventp = in_event; } while (eventp < in_event+nevents) { switch (eventp->EventType) { case KEY_EVENT: nchars += MapKeyEventToChars(&eventp->Event.KeyEvent, bp+nchars); if (--eventp->Event.KeyEvent.wRepeatCount == 0) eventp += 1; break; case MOUSE_EVENT: #ifdef MOUSE /* We are only interested in hits */ if (eventp->Event.MouseEvent.dwButtonState != 0) { bp[nchars++] = PCNONASCII; bp[nchars++] = '\xb0'+((char)eventp->Event.MouseEvent.dwButtonState&017); bp[nchars++] = (char)eventp->Event.MouseEvent.dwMousePosition.X; bp[nchars++] = (char)eventp->Event.MouseEvent.dwMousePosition.Y; } #endif eventp += 1; break; case WINDOW_BUFFER_SIZE_EVENT: maxpos = eventp->Event.WindowBufferSizeEvent.dwSize; eventp += 1; ResizePending = YES; break; default: eventp += 1; break; } if (nchars >= size - 5) break; } return nchars; } BOOL inputEventWaiting(int period) { #ifdef IPROCS return wait_for_any_input(period) == WAIT_OBJECT_0; #else INPUT_RECORD evnt[10]; PINPUT_RECORD pEvnt; DWORD cnt; static BOOL first=TRUE; if (first) return first=FALSE; /* Force display on first call */ if (eventp < in_event+nevents) return TRUE; /* Already something in the queue */ while (WaitForSingleObject(conin, period) == WAIT_OBJECT_0) { if (!PeekConsoleInput(conin, evnt , sizeof(evnt)/sizeof(evnt[0]), &cnt)) break; /* Check if the waiting event is of interest. */ for (pEvnt=evnt; pEvntEventType == KEY_EVENT && pEvnt->Event.KeyEvent.bKeyDown) || pEvnt->EventType == WINDOW_BUFFER_SIZE_EVENT || pEvnt->EventType == MOUSE_EVENT) return TRUE; } /* If we reach here, the event(s) are uninteresting - chuck them. */ if (!ReadConsoleInput(conin, evnt, cnt, &cnt)) break; } return FALSE; #endif } private void SaveBufferFile(Buffer *b) { Buffer *save_buf = curbuf; char title[80]; if (b->b_fname) { wsprintf(title, "Save Jove buffer `%s'?", b->b_name); if (MessageBox(NULL, b->b_fname, title, MB_YESNO) != IDYES) return; } else { OPENFILENAME ofn; /* common dialog box structure */ char szFile[_MAX_PATH]; /* filename string */ char szDirPath[_MAX_PATH]; /* filename string */ /* Set the members of the OPENFILENAME structure. */ memset(&ofn, 0, sizeof(ofn)); ofn.lStructSize = sizeof(OPENFILENAME); szFile[0] = '\0'; ofn.lpstrFile = szFile; ofn.nMaxFile = _MAX_PATH;; ofn.lpstrFilter = "All (*.*)\0*.*\0" "C source (*.c;*.cpp;*.cxx)\0*.c;*.cpp;*,cxx\0" "C header (*.h;*.hpp;*.hxx)\0*.h;*.hpp;*.hxx\0"; ofn.lpstrInitialDir = szDirPath; ofn.lpstrTitle = title; wsprintf(title, "Save Jove buffer `%s' as:", b->b_name); getcwd(szDirPath, _MAX_PATH-1); ofn.Flags = OFN_SHOWHELP | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST; if (!GetSaveFileName(&ofn)) return; setfname(b, ofn.lpstrFile); } /* Still here? Save the file, then. */ SetBuf(b); SaveFile(); SetBuf(save_buf); } private void MessageCloseFiles() { /* We use a static buffer pointer so that we can detect if we * have been re-entered. If so, we do nothing. This can happen * if the user takes too long to respond). */ static Buffer *b; if (b == NULL) for (b = world; b != NULL; b = b->b_next) if (b->b_type != B_SCRATCH && b->b_type == B_FILE && IsModified(b)) SaveBufferFile(b); } /* Control interrupt handler deals with CTRL-BREAK and exit requests */ private BOOL WINAPI ctrlHandler(DWORD type) { switch(type) { case CTRL_C_EVENT: return TRUE; /* Ignore, keyboard handler will see it. */ case CTRL_BREAK_EVENT: return FALSE; case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: MessageCloseFiles(); break; } return FALSE; /* Carry on */ } private WORD c_attr = 0x07; /* current attribute white on black */ int Txattr = 0x07, /* VAR: text-attribute (white on black) */ Mlattr = 0x70, /* VAR: mode-line-attribute (black on white) */ Hlattr = 0x10; /* VAR: highlight-attribute */ #define c_row curpos.Y /* current row */ #define c_col curpos.X /* current column */ #define cur_mov(r, c) { \ curpos.X = (c); curpos.Y = (r); \ CHECK(SetConsoleCursorPosition(conout, curpos)); \ } #define setcolor(c) { \ c_attr = (c); \ CHECK(SetConsoleTextAttribute(conout, c_attr)); \ } /* WIN32 calls aren't cheap, so we buffer output */ private char displaybuf[1024]; private DWORD bufpos = 0; /* getLastErrorString is a WIN32 helper function that returns a description * of the error code that GetLastError() returns. * Implementation note: we use a mode of operation whereby FormatMessage allocates * a string large enough; the returned value will be valid until the function is * called again. */ private char *reason; private void freeReason(void) { if (reason) { VirtualFree((PVOID)reason, 0, MEM_RELEASE); reason = NULL; } } char * getLastErrorString() { static BOOL cleanupRegistered; char *ptr; if (!cleanupRegistered) { atexit(freeReason); cleanupRegistered = TRUE; } freeReason(); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_ALLOCATE_BUFFER, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), (char*)&reason, 0, NULL); if (((ptr = strchr(reason, '\r')) != NULL) || ((ptr = strchr(reason, '\n')) != NULL)) *ptr = '\0'; /* Trim off carriage control */ return reason; } private void ConsoleFail(char *fdef) { char why[200]; char *reason = getLastErrorString(); wsprintf(why, "Console function \"%s\" failed: %s", fdef, reason); if (MessageBox(NULL, getLastErrorString(), why, MB_OKCANCEL) == IDCANCEL) abort(); } private void scr_win(int no, int ulr, int ulc, int lrr, int lrc) { SMALL_RECT r, clip; COORD whereto; CHAR_INFO charinfo; clip.Top = ulr; clip.Left = ulc; clip.Bottom = lrr; clip.Right = lrc; whereto.X = ulc; r.Left = ulc; r.Right = lrc; if (no > 0) { r.Top = ulr + no; r.Bottom = lrr; whereto.Y = ulr; } else { r.Top = ulr; r.Bottom = lrr + no; whereto.Y = ulr - no; } charinfo.Char.AsciiChar = ' '; charinfo.Attributes = c_attr; CHECK(ScrollConsoleScreenBuffer(conout, &r, &clip, whereto, &charinfo)); /* If the scrolled region is less than half of the clip area, there will * be an unscrolled area in the middle - it must be filled with space. */ if (no > 0) { whereto.Y += (r.Bottom - r.Top + 1); while (whereto.Y < r.Top) { DWORD written; CHECK(FillConsoleOutputCharacter(conout, ' ', lrc-ulc+1, whereto, &written)); whereto.Y += 1; } } else { while (--whereto.Y > r.Bottom) { DWORD written; CHECK(FillConsoleOutputCharacter(conout, ' ', lrc-ulc+1, whereto, &written)); } } } void i_lines(top, bottom, num) int top, bottom, num; { scr_win(-num, top, 0, bottom, CO-1); } void d_lines(top, bottom, num) int top, bottom, num; { scr_win(num, top, 0, bottom, CO-1); } void clr_page() { DWORD written; SO_off(); cur_mov(0, 0); CHECK(FillConsoleOutputCharacter(conout, ' ', maxpos.X*maxpos.Y, curpos, &written)); CHECK(FillConsoleOutputAttribute(conout, c_attr, maxpos.X*maxpos.Y, curpos, &written)); } void flushscreen() { if (bufpos != 0) { DWORD written; CHECK(WriteConsole(conout, displaybuf, bufpos, &written, NULL)); if (written != bufpos) { byte_move(displaybuf + written, displaybuf, bufpos - written); } bufpos = 0; } } void clr_eoln() { DWORD written; CHECK(FillConsoleOutputCharacter(conout, ' ', CO-c_col, curpos, &written)); CHECK(FillConsoleOutputAttribute(conout, c_attr, CO-c_col, curpos, &written)); } void dobell(n) /* declared in term.h */ int n; { MessageBeep(n); } void ResizeWindow() { /* Must update window size to eliminate those ugly scroll bars */ SMALL_RECT newsize; newsize.Top = newsize.Left = 0; newsize.Right = maxpos.X-1; newsize.Bottom = maxpos.Y-1; /* Note: the following fails with "invalid address". If you can figure out why, please fix it. */ SetConsoleWindowInfo(conout, TRUE, &newsize); } /* scr_putchar: put char on screen. Declared in fp.h */ /* char is subject to default argument promotions */ void scr_putchar(char c) { if (bufpos >= sizeof(displaybuf)) flushscreen(); displaybuf[bufpos++] = c; switch (c) { case LF: c_row += 1; break; case CTL('M'): /* CR */ c_col = 0; break; case BS: if (c_col > 0) c_col -= 1; break; case CTL('G'): /* ??? is this ever used? */ dobell(1); break; default: if (++c_col > CO-1) { c_col = 0; c_row += 1; } break; } } /* No cursor optimization on an WIN32, this simplifies things a lot. * Think about it: it would be silly! */ void Placur(line, col) int line, col; { flushscreen(); cur_mov(line, col); CapCol = col; CapLine = line; } private jbool doing_so = NO, doing_us = NO; private void doattr() { flushscreen(); setcolor((doing_so? Mlattr : Txattr) ^ (doing_us? Hlattr : 0)); } void SO_effect(f) jbool f; { doing_so = f; doattr(); } void US_effect(f) jbool f; { doing_us = f; doattr(); } int FatalErrorMessage(char* str) { return MessageBox(NULL, str, NULL, MB_YESNO) == IDYES? 'y' : 'n'; } #endif /* WIN32 */ jove-4.17.5.5/wind.c000066400000000000000000000330641501102521500140210ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* This creates/deletes/divides/grows/shrinks windows. */ #include "jove.h" #include "chars.h" #include "disp.h" #include "ask.h" #include "extend.h" #include "commands.h" /* for FindCmd and ExecCmd */ #include "mac.h" #include "reapp.h" #include "wind.h" #include "screen.h" private const char onlyone[] = "You only have one window!", toosmall[] = "Resulting window would be too small."; #ifdef HIGHLIGHTING jbool ScrollBar = NO; /* VAR: whether the scrollbar is used */ #endif Window *curwind, *fwind = NULL; /* First line in a Window */ private int FLine(w) register Window *w; { register Window *wp = fwind; register int lineno = -1; while (wp != w) { lineno += wp->w_height; wp = wp->w_next; if (wp == fwind) { complain("window?"); /* NOTREACHED */ } } return lineno + 1; } /* Delete `wp' from the screen. If it is the only window left * on the screen, then complain. It gives its body * to the next window if there is one, otherwise the previous * window gets the body. */ void del_wind(wp) register Window *wp; { register Window *prev = wp->w_prev, *heir = prev; /* default: previous window inherits space */ if (one_windp()) { complain(onlyone); /* NOTREACHED */ } prev->w_next = wp->w_next; wp->w_next->w_prev = prev; if (fwind == wp) { heir = fwind = wp->w_next; /* no window above: next inherits */ /* Here try to do something intelligent for redisplay() */ SetTop(fwind, prev_line(fwind->w_top, wp->w_height)); } heir->w_height += wp->w_height; if (curwind == wp) SetWind(heir); #ifdef MAC RemoveScrollBar(wp); Windchange = YES; #endif free((UnivPtr) wp); } /* Divide the window WP N times, or at least once. Complains if WP is too * small to be split into that many pieces. It returns the new window. */ Window * div_wind(wp, n) register Window *wp; int n; { Window *latest = wp; int amt; if (n < 1) n = 1; amt = wp->w_height / (n + 1); if (amt < 2) { complain(toosmall); /* NOTREACHED */ } do { register Window *new = (Window *) emalloc(sizeof (Window)); new->w_flags = 0; new->w_LRscroll = 0; new->w_height = amt; wp->w_height -= amt; /* set the lines such that w_line is the center in * each Window */ new->w_line = wp->w_line; new->w_char = wp->w_char; new->w_bufp = wp->w_bufp; new->w_top = prev_line(new->w_line, WSIZE(new)/2); /* Link the new window into the list */ new->w_prev = latest; new->w_next = latest->w_next; new->w_next->w_prev = latest->w_next = new; latest = new; #ifdef MAC new->w_control = NULL; #endif } while (--n > 0); #ifdef MAC Windchange = YES; #endif return latest; } /* Initialze the first window setting the bounds to the size of the * screen. There is no buffer with this window. See parse for the * setting of this window. */ void winit() { register Window *w; w = curwind = fwind = (Window *) emalloc(sizeof (Window)); w->w_line = w->w_top = NULL; w->w_LRscroll = 0; w->w_flags = 0; w->w_char = 0; w->w_next = w->w_prev = fwind; w->w_height = ILI; w->w_bufp = NULL; #ifdef MAC w->w_control = NULL; Windchange = YES; #endif } void tiewind(w, bp) register Window *w; register Buffer *bp; { jbool not_tied = (w->w_bufp != bp); UpdModLine = YES; /* kludge ... but speeds things up considerably */ w->w_line = bp->b_dot; w->w_char = bp->b_char; w->w_bufp = bp; if (not_tied) CalcWind(w); /* ah, this has been missing since the beginning of time! */ } /* Change to previous window. */ void PrevWindow() { register Window *new = curwind->w_prev; if (Asking) { complain((char *)NULL); /* NOTREACHED */ } if (one_windp()) { complain(onlyone); /* NOTREACHED */ } SetWind(new); } /* Make NEW the current Window */ void SetWind(new) register Window *new; { if (!Asking && curbuf!=NULL) { /* can you say kludge? */ curwind->w_line = curline; curwind->w_char = curchar; curwind->w_bufp = curbuf; } if (new == curwind) return; SetBuf(new->w_bufp); if (!inlist(new->w_bufp->b_first, new->w_line)) { new->w_line = curline; new->w_char = curchar; } DotTo(new->w_line, new->w_char); if (curchar > (int)strlen(linebuf)) new->w_char = curchar = strlen(linebuf); curwind = new; } /* delete the current window if it isn't the only one left */ void DelCurWindow() { SetABuf(curwind->w_bufp); del_wind(curwind); } /* put the current line of `w' in the middle of the window */ void CentWind(w) register Window *w; { SetTop(w, prev_line(w->w_line, WSIZE(w)/2)); } int ScrollStep = 0; /* VAR: how should we scroll (full scrolling) */ /* Calculate the new topline of the window. If ScrollStep == 0 * it means we should center the current line in the window. */ void CalcWind(w) register Window *w; { register int up; int scr_step; LinePtr newtop; if (ScrollStep == 0) { /* Means just center it */ CentWind(w); } else { up = inorder(w->w_line, 0, w->w_top, 0); if (up == -1) { CentWind(w); return; } scr_step = (ScrollStep < 0) ? WSIZE(w) + ScrollStep : ScrollStep - 1; /* up: point is above the screen */ newtop = prev_line(w->w_line, up? scr_step : (WSIZE(w) - 1 - scr_step)); if (LineDist(newtop, w->w_top) >= WSIZE(w) - 1) CentWind(w); else SetTop(w, newtop); } } /* This is bound to ^X 4 [BTF]. To make the screen stay the * same we have to remember various things, like the current * top line in the current window. It's sorta gross, but it's * necessary because of the way this is implemented (i.e., in * terms of do_find(), do_select() which manipulate the windows. */ void WindFind() { register Buffer *obuf = curbuf, *nbuf; LinePtr ltop = curwind->w_top; Bufpos odot, ndot; cmdproc_t cmd; DOTsave(&odot); switch (waitchar()) { case 't': case 'T': cmd = FindTag; break; case CTL('T'): cmd = FDotTag; break; case 'b': case 'B': cmd = BufSelect; break; case 'f': case 'F': cmd = FindFile; break; default: cmd = (cmdproc_t)0; /* avoid uninitialized complaint from gcc -W */ complain("T: find-tag, ^T: find-tag-at-point, F: find-file, B: select-buffer."); /*NOTREACHED*/ } ExecCmd((data_obj *) FindCmd(cmd)); nbuf = curbuf; DOTsave(&ndot); SetBuf(obuf); SetDot(&odot); SetTop(curwind, ltop); /* there! it's as if we did nothing */ if (one_windp()) (void) div_wind(curwind, 1); tiewind(curwind->w_next, nbuf); SetWind(curwind->w_next); SetDot(&ndot); } /* Go into one window mode by deleting all the other windows */ void OneWindow() { while (curwind->w_next != curwind) del_wind(curwind->w_next); } Window * windbp(bp) register Buffer *bp; { register Window *wp = fwind; if (bp == NULL) return NULL; do { if (wp->w_bufp == bp) return wp; wp = wp->w_next; } while (wp != fwind); return NULL; } /* Change window into the next window. Curwind becomes the new window. */ void NextWindow() { register Window *new = curwind->w_next; if (Asking) { complain((char *)NULL); /* NOTREACHED */ } if (one_windp()) { complain(onlyone); /* NOTREACHED */ } SetWind(new); } /* Scroll the next Window */ void PageNWind() { if (one_windp()) { complain(onlyone); /* NOTREACHED */ } NextWindow(); NextPage(); PrevWindow(); } private Window * w_nam_typ(name, type) register const char *name; int type; { register Window *w; register Buffer *b; b = buf_exists(name); w = fwind; if (b != NULL) { do { if (w->w_bufp == b) return w; } while ((w = w->w_next) != fwind); } w = fwind; do { if (w->w_bufp->b_type == type) return w; } while ((w = w->w_next) != fwind); return NULL; } /* Put a window with the buffer `name' in it. Erase the buffer if * `clobber' is YES. */ void pop_wind(name, clobber, btype) register const char *name; jbool clobber; int btype; { register Window *wp; register Buffer *newb; if ((newb = buf_exists(name)) != NULL) btype = -1; /* if the buffer exists, don't change it's type */ if ((wp = w_nam_typ(name, btype)) == NULL) { if (one_windp()) SetWind(div_wind(curwind, 1)); else PrevWindow(); } else SetWind(wp); newb = do_select((Window *)NULL, name); if (clobber) buf_clear(newb); tiewind(curwind, newb); if (btype != -1) newb->b_type = btype; SetBuf(newb); } void GrowWindowCmd() { WindSize(curwind, abs((int)arg_value())); } void ShrWindow() { WindSize(curwind, -abs((int)arg_value())); } /* Change the size of the window by inc. First arg is the window, * second is the increment. */ void WindSize(w, inc) register Window *w; register int inc; { if (one_windp()) { complain(onlyone); /* NOTREACHED */ } if (inc == 0) return; else if (inc < 0) { /* Shrinking this Window. */ if (w->w_height + inc < 2) { complain(toosmall); /* NOTREACHED */ } w->w_height += inc; w->w_prev->w_height -= inc; } else { /* Growing the window. */ /* Change made from original code so that growing a window * exactly offsets effect of shrinking a window, i.e. * doing either followed by the other restores original * sizes of all affected windows. */ if (w->w_prev->w_height - inc < 2) { complain(toosmall); /* NOTREACHED */ } w->w_height += inc; w->w_prev->w_height -= inc; } #ifdef MAC Windchange = YES; #endif } /* Set the topline of the window, calculating its number in the buffer. * This is for numbering the lines only. */ void SetTop(w, line) Window *w; register LinePtr line; { #ifdef HIGHLIGHTING if (ScrollBar) UpdModLine = YES; #endif w->w_top = line; if (w->w_flags & W_NUMLINES) w->w_topnum = LinesTo(w->w_bufp->b_first, line) + 1; } void WNumLines() { curwind->w_flags ^= W_NUMLINES; SetTop(curwind, curwind->w_top); } void WVisSpace() { curwind->w_flags ^= W_VISSPACE; ClAndRedraw(); } /* If `line' is in `windes', return its screen line number; * otherwise return -1. */ int in_window(windes, line) register Window *windes; register LinePtr line; { register int i; register LinePtr lp = windes->w_top; for (i = 0; lp != NULL && i < windes->w_height - 1; i++, lp = lp->l_next) if (lp == line) return FLine(windes) + i; return -1; } void SplitWind() { SetWind(div_wind(curwind, arg_or_default(2) - 1)); } /* Goto the window with the named buffer. If no such window * exists, pop one and attach the buffer to it. */ void GotoWind() { const char *bname = ask_buf(lastbuf, ALLOW_OLD | ALLOW_INDEX | ALLOW_NEW); Window *w; w = curwind->w_next; do { if (w->w_bufp->b_name == bname) { SetABuf(curbuf); SetWind(w); return; } w = w->w_next; } while (w != curwind); SetABuf(curbuf); pop_wind(bname, NO, -1); } void ScrollRight() { int amt = arg_or_default(ScrollWidth); if (curwind->w_LRscroll - amt < 0) curwind->w_LRscroll = 0; else curwind->w_LRscroll -= amt; UpdModLine = YES; } void ScrollLeft() { int amt = arg_or_default(ScrollWidth); curwind->w_LRscroll += amt; UpdModLine = YES; } LineEffects WindowRange(w) Window *w; { #ifdef HIGHLIGHTING static struct LErange range = {0-0, 0-0, SO_effect, US_effect}; range.start = range.width = 0; /* default: no highlighting */ if (ScrollBar) { register int /* line counts of various portions -- slow! */ above = LinesTo(w->w_bufp->b_first, w->w_top), below = LinesTo(w->w_top, (LinePtr)NULL), total = above + below, in = jmin(below, WSIZE(w)); if (above == -1 || below == -1) return ⦥ /* something fishy */ below -= in; /* correction */ if (in != total) { /* Window shows only part of the buffer: highlight "thumb". * * Required properties: * - proportionality of "below", "in", and "above" segments * - monotonicity and smoothness of representation * - a segment vanishes iff it is empty (but "in" is never empty) * - extreme L & R ends of modeline must indicate presence/absence * of first/last line of buffer; hence some non-linearity * thereabouts. * * Implementation: * - Use unsigned long to prevent overflow. * - Allocate space to "above" and "below", rounding to nearest * for best proportionality. * - Allocate the rest to "in". * - Ensure "in" not empty by ensuring total space allocated * to above and below must leave at least one col. This * is done fiddling the rounding term when "in" is small. * * - The first (last) char in the modeline represents the * first (last) line in the buffer. * * - That leaves the rest of the modeline to represent * (linearly) the remaining (total-2) lines of the buffer, * of which (above-1) should be represented by highlighting * from char position 2 onwards and (below-1) should be * represented by highlighting from (totalcols-1) backwards. * * - Rounding is applied in this region, and is fiddled to * ensure that the white bit in the middle never shrinks to * zero. */ int totalcols_2 = CO - 1 - (4 * SG) - 2, total_2 = total - 2, rounding = (in < total_2/totalcols_2) ? (totalcols_2*in)/2 : total_2/2, abovecols = (above == 0) ? 0 : 1 + ((long)(above-1)*totalcols_2 + rounding) / total_2, belowcols = (below == 0) ? 0 : 1 + ((long)(below-1)*totalcols_2 + rounding) / total_2; range.start = abovecols; range.width = totalcols_2 + 2 - abovecols - belowcols; } } return ⦥ #else /* !HIGHLIGHTING */ return YES; /* modeline always stands out */ #endif /* !HIGHLIGHTING */ } jove-4.17.5.5/wind.h000066400000000000000000000054141501102521500140240ustar00rootroot00000000000000/************************************************************************** * This program is Copyright (C) 1986-2002 by Jonathan Payne. JOVE is * * provided by Jonathan and Jovehacks without charge and without * * warranty. You may copy, modify, and/or distribute JOVE, provided that * * this notice is included in all the source files and documentation. * **************************************************************************/ /* typedef struct window Window in jove.h */ struct window { Window *w_prev, /* circular list */ *w_next; Buffer *w_bufp; /* buffer associated with this window */ LinePtr w_top, /* top line */ w_line; /* current line */ long w_topnum; /* buffer line number of the topline */ int w_char, w_height, /* window height (including mode line) */ w_dotcol, /* screen column of w_line (set by UpdWindow) */ w_dotline, /* screen line number of w_line (set by UpdWindow) */ w_flags, #define W_TOPGONE 01 #define W_CURGONE 02 /* topline (curline) of window has been deleted since the last time a redisplay was called */ #define W_VISSPACE 04 #define W_NUMLINES 010 w_LRscroll; /* amount of LeftRight scrolling in window */ #ifdef MAC int w_topline; /* row number of top line in window */ /* Note: "ControlHandle w_control" would require more includes */ struct ControlRecord **w_control; /* scroll bar for window */ #endif }; #define W_NUMWIDTH(w) (((w)->w_flags & W_NUMLINES)? 8 : 0) #define SIWIDTH(off) ((off) != 0? 1 : 0) /* width of shift indicator, if any */ extern Window *fwind, /* first window in list */ *curwind; /* current window */ #define one_windp() (fwind->w_next == fwind) #define WSIZE(wp) ((wp)->w_height - 1) /* window lines, without modeline */ extern int in_window proto((Window *windes,LinePtr line)); extern Window *div_wind proto((Window *wp,int n)), *windbp proto((Buffer *bp)); extern void CalcWind proto((Window *w)), CentWind proto((Window *w)), SetTop proto((Window *w,LinePtr line)), SetWind proto((Window *new)), WindSize proto((Window *w,int inc)), del_wind proto((Window *wp)), pop_wind proto((const char *name, jbool clobber, int btype)), tiewind proto((Window *w, Buffer *bp)), /* util.c!! */ winit proto((void)); /* Commands: */ extern void DelCurWindow proto((void)), GotoWind proto((void)), GrowWindowCmd proto((void)), NextWindow proto((void)), OneWindow proto((void)), PageNWind proto((void)), PrevWindow proto((void)), ScrollLeft proto((void)), ScrollRight proto((void)), ShrWindow proto((void)), SplitWind proto((void)), WNumLines proto((void)), WVisSpace proto((void)), WindFind proto((void)); /* Variables: */ extern int ScrollStep; /* VAR: how should we scroll */ #ifdef HIGHLIGHTING extern jbool ScrollBar; /* VAR: whether the scrollbar is used */ #endif jove-4.17.5.5/xjove/000077500000000000000000000000001501102521500140415ustar00rootroot00000000000000jove-4.17.5.5/xjove/Makefile000066400000000000000000000073111501102521500155030ustar00rootroot00000000000000########################################################################### # This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of # # Manchester. (X)JOVETOOL is provided to you without charge, and with no # # warranty. You may copy, modify, and/or distribute (X)JOVETOOL, # # provided that this notice is included in all the files, except insofar # # as a more specific copyright notices attaches to the file (x)jovetool.c # ########################################################################### # Makefile for xjove (XView) and jovetool (SunView) # # This makefile may be invoked directly, or by the main JOVE Makefile. # A number of macros may need to be adjusted for any particular environment. # If the Makefile is invoked by the main JOVE Makefile, most # customization will be inherited from that Makefile automatically: # DEFINES, CC, OPTFLAGS, SYSDEFS, XINSTALL, BINDIR, and INSTALLFLAGS. # The remaining macros that may need attention are XJLDFLAGS and XJCFLAGS. # Under Solaris 2, make sure that your OPENWINHOME environment variable # is set. # Select optimization level (flags passed to compiling and linking steps). # On most systems, -g for debugging, -O for optimization. # On the official Sun ANSI C compiler and the standard System V Release 4 # compiler, adding -Xa -v will increase compiler checking. OPTFLAGS = -O # For SunView: # DEFINES=-DSUNVIEW DEFINES= # for Solaris 2.x: SYSDEFS=-DSYSVR4 # -i: ignore any LD_LIBRARY_PATH setting # -L: add to library search path # -R: specify library search directories to dynamic linker XJLDFLAGS= -i -L$$OPENWINHOME/lib -R$$OPENWINHOME/lib # for Sun0s4.x: # XJLDFLAGS=-L$$OPENWINHOME/lib # SYSDEFS=-DSUNOS41 CFLAGS = $(OPTFLAGS) -I.. $(SYSDEFS) $(DEFINES) XJCFLAGS = -I$$OPENWINHOME/include BINDIR = /usr/local/bin # The install commands of BSD and System V differ in unpleasant ways: # -c: copy (BSD); -c dir: destination directory (SysV) # -s: strip (BSD); -s: suppress messages (SysV) # Also, the destination specification is very different. # The result is that the System V install command must not be used. # If you know that /bin/install is the BSD program, you can use it. # "cp" will work reasonably well, but be aware that any links continue # referencing the old file with new contents. INSTALLFLAGS = # -g bin -o root # to install executable files XINSTALL=cp #XINSTALL=/usr/ucb/install $(INSTALLFLAGS) -c -m 755 # -s C_SRC = jovetool.c xjove.c jovewindows.c xjovewindows.c jovemenu.c \ exts.h jovewindows.h mousemsg.h xjovewindows.h ICONS = jove.icon jove.cursor copy.cursor cut.cursor paste.cursor MISC = Makefile README BACKUPS = $(C_SRC) $(ICONS) $(MISC) default: xjove install: installxjove FLIST=.filelist $(FLIST): $(BACKUPS) @ls $(BACKUPS) > $(FLIST) installxjove: xjove $(XINSTALL) xjove $(BINDIR)/xjove installjovetool: jovetool $(XINSTALL) jovetool $(BINDIR)/jovetool jovetool: jovetool.o jovewindows.o $(CC) $(OPTFLAGS) $(LDFLAGS) -o jovetool jovetool.o jovewindows.o -lsuntool -lsunwindow -lpixrect jovetool.o: jovetool.c exts.h mousemsg.h $(ICONS) jovewindows.o: jovewindows.c jovemenu.c exts.h jovewindows.h ../tune.h xjove: xjove.o xjovewindows.o $(CC) $(OPTFLAGS) $(LDFLAGS) $(XJLDFLAGS) -o xjove xjove.o xjovewindows.o -lxview -lX11 xjove.o: xjove.c exts.h mousemsg.h $(ICONS) $(CC) $(CFLAGS) $(XJCFLAGS) -c xjove.c xjovewindows.o: xjovewindows.c jovemenu.c exts.h xjovewindows.h ../tune.h $(CC) $(CFLAGS) $(XJCFLAGS) -c xjovewindows.c tags: $(C_SRC) ctags -w $(C_SRC) # override CIFLAGS with something like: # CIFLAGS = -m'some reason for change' -u4.14.10.n -q ciall: ci $(CIFLAGS) $(BACKUPS) clean: rm -f a.out core *.o jovetool xjove '#'*~ .filelist clobber: clean rm -f *.orig *.rej jove-4.17.5.5/xjove/README000066400000000000000000000176031501102521500147300ustar00rootroot00000000000000########################################################################### # This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of # # Manchester. (X)JOVETOOL is provided to you without charge, and with no # # warranty. You may copy, modify, and/or distribute (X)JOVETOOL, # # provided that this notice is included in all the files, except insofar # # as a more specific copyright notices attaches to the file (x)jovetool.c # ########################################################################### The two programs in this directory 'xjove' and 'jovetool' are front ends for the 'jove' editor to enable it to be controlled by the mouse in windowing environments. 'Jovetool' is for use with Sunview. 'Xjove' is for use with X-windows. Both programs were originally based on the 'emacstool' program (although there is now little resemblance left), and for this reason their Copyright notices are GNU-like, as opposed to the Copyright notices in the rest of the 'jove' system. The full goodies provided by these programs are described in the manual page {jove}/doc/xjove.nr. Briefly, it is possible to change windows and to set the point and the mark by pressing mouse buttons over the appropriate places. It is also possible to do copy/cut/paste (i.e. copy-region, kill-region, yank) by using the CTRL and SHIFT keys at the same time. The third mouse button brings up a menu from which any 'jove' command can be activated or any 'jove' variable set. This menu is rather large and complex, so it is suggested that its use will mainly be for browsing through when searching for the more obscure 'jove' commands. Where a particular command is in fact bound to some key, that is indicated in the menu, so you can see how to access it more quickly the next time it is needed. It is also possible to scroll to any arbitrary point within the file by clicking the mouse at a proportional position in the modeline below the particular window. If the 'scrollbar' variable is on (which it always should be when using 'xjove') the portion of the total buffer visible within the window has its highlighting reversed. To compile 'jovetool' you need a Sun running OS4.x. You also need to set the DEFINES and SYSDEFS macros in the Makefile. If you build it through the makejovetool or installjovetool targets of the JOVE Makefile, these will be set automatically. To compile 'xjove' you need the XView toolkit which is normally supplied as part of the Openwindows package on Suns and some other machines. If you do not have XView, then it may be obtained from the MIT X-distribution. You need to set the SYSDEFS macro in the Makefile (it is only used to distinguish SYSVR4 (which includes SunOS 5, also known as Solaris 2) from any other system). There is also a difference in the 'LDFLAGS' for SunOS 5. It is also necessary for the OPENWINHOME environment variable to be set correctly. If you are are a user rather than a hacker of the system, you may wish to replace the '-g' in the OPTFLAGS macro by '-O'. If you build xjove through the makexjove or installxjove targets of the main JOVE Makefile, most of these settings will be inherited (check xjove/Makefile for details). In the menus brought up by pressing the third mouse button under 'xjove', the key bindings shown against each command use the function keys (of which there are an awful lot on the Sun keyboard) as set in the file {jove}/doc/jove.rc.sun-cmd. If you are not using this binding, or if you have modified it in any way, then you will need to edit the file jovemenu.c accordingly. This file consists mostly of preprocessor macros, structured in a reasonably obvious way. Note that 'xjove' automatically sets the TERM environment variable of 'jove' to 'sun-cmd'. There is nothing that can be done to change this, because it is a "feature" of XView. Note that anyone who has a private TERMCAP database will have to ensure that this includes sun-cmd, or else write a wrapper to disable it. All the keys on the keyboard are bound to something accessible, even those not normally useable under shelltool (e.g. the Help key and the keys around the edge of the keypad). The one exception is the keypad decimal point, also marked Del. Under normal, default, conditions pressing this is indistinguishable from pressing the official Delete key. To overcome this, the following line may usefully be kept in your .xinitrc file xmodmap -e 'keycode 57 = KP_Decimal' xjove will then catch it and send a sequence which can be bound to some suitable command in a jove.rc file (see jove.rc.sun-cmd). 'Xjove' should understand all of the command line options and X-resources mentioned in the Sun manual page for 'xview' (in particular -font, -Ww, -Wh), but do not expect it to work with a proportional font. 'Xjove' is in essence a terminal emulator rather like 'shelltool'. Indeed you can run a shell in it by saying 'xjove -rc sh', and I regularly run the 'nn' newsreader in it so that I can then use 'jove' to generate postings and email in reply to articles. If you call 'jove' from within such a shell (or newsreader), the mouse facilities will immediately become available. Similarly, it is possible to call up another machine from the shell (or use 'xjove -rc rsh other_machine') and then use 'jove' on that other machine, with full benefit of the mouse. Most usually, however, and by default, xjove immediately calls jove and passes the remaining parameters to it (you can even run the recover program by typing 'xjove -r'). Because 'xjove' is just a fancy terminal emulator, and because 'jove' itself is still fundamentally a terminal-based editor, the communication between 'xjove' and 'jove' is only one-way. Information about mouse events can be passed to 'jove', but there is no feedback from 'jove' to 'xjove'. This is why such a crude "scrollbar" had to be employed, rather than a more conventional scrollbar at the side as normally provided by windowing systems. Someday, someone should write a really good windows-based editor, but it will be an entirely differently structured program from the 'xjove/jove' combination. Unusually for an X-Application, xjove normally forks a separate process to run its window, so that the shell which issued the xjove command can immediately accept other commands. This was done on the grounds that it is what most users will require most of the time. Some people, however, complain that this is not the X or UNIX tradition (they expect you to type xjove filename &). To avoid religious wars on this issue, command line flags -f and -nf (fork/no fork) have been provided, and the default state is taken from the resource xjove.forking (in jovetool, only the -nf flag is provided). Within 'jove' itself, mouse events passed to it by 'xjove' are acted upon by code within the file mouse.c. To be sure that this code is included, the preprocessor variable MOUSE must be defined in sysdep.h. This is done automatically for any UNIX system. If you use the 'xterm' terminal emulator, a simplified subset of the facilities provided by 'xjove' is provided, using a rather similar mechanism to that used by 'xjove'. 'Xjove' and 'jovetool' were written by Charles Lindsey. Comments, bug reports, and whatever may be sent to chl@clw.cs.man.ac.uk (or alternatively to hugh@mimosa.com along with reports on the rest of jove). KNOWN XVIEW BUG: xjove terminal emulation is described by the "sun-cmd" termcap and terminfo entries. Due to an XView bug, the environment variable TERMCAP is set to "sun-cmd:te=\E[>4h:ti=\E[>4l:tc=sun:". (This may be fixed some day.) To be correct, the tc capability should be replaced by the contents of the /etc/termcap entry for "sun". Any program that uses the termcap-based library will fail. If a program uses terminfo, it will avoid this problem. Solaris programs normally use terminfo. At least some Linux systems use terminfo. One workaround would be to write a shell script wrapper to unset TERMCAP before invoking the "real" program. Use the xjove -rc flag to specify which program to run. jove-4.17.5.5/xjove/copy.cursor000066400000000000000000000003361501102521500162540ustar00rootroot00000000000000/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 */ 0x1F00, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x1F00, jove-4.17.5.5/xjove/cut.cursor000066400000000000000000000003361501102521500160750ustar00rootroot00000000000000/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 */ 0x0820, 0x0440, 0x0440, 0x0280, 0x0280, 0x0280, 0x0100, 0x0100, 0x0100, 0x0280, 0x06C0, 0x0AA0, 0x1290, 0x1450, 0x1450, 0x0C60, jove-4.17.5.5/xjove/exts.h000066400000000000000000000023121501102521500151730ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ /* proto: macro to allow us to prototype any function declaration * without upsetting old compilers. */ #ifdef __STDC__ # define REALSTDC 1 #else #define const /*const*/ #endif #ifdef REALSTDC # define USE_PROTOTYPES 1 #endif #ifdef USE_PROTOTYPES # define proto(x) x # ifdef NO_PTRPROTO /* on these systems, a prototype cannot be used for a pointer to function */ # define ptrproto(x) () # else # define ptrproto(x) x # endif #else # define proto(x) () # define ptrproto(x) () #endif #define private static extern Tty ttysw; extern Menu main_menu; #ifndef SUNVIEW extern Xv_Font font; /* ??? not in sunview */ #endif extern void menu_init proto((void)); jove-4.17.5.5/xjove/jove.cursor000066400000000000000000000003361501102521500162450ustar00rootroot00000000000000/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 */ 0x0060, 0x00C0, 0x0180, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0180, 0x00C0, 0x0060, jove-4.17.5.5/xjove/jove.icon000066400000000000000000000036151501102521500156630ustar00rootroot00000000000000/* Format_version=1, Width=64, Height=64, Depth=1, Valid_bits_per_item=16 */ 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF, 0xC444,0x4444,0x4444,0x4447,0xD7FF,0xFFFF,0xF111,0x1113, 0xCC00,0x0000,0x1888,0x888B,0xE400,0x0000,0x1222,0x2223, 0xC400,0x0000,0x1444,0x4447,0xD7FF,0xE1FF,0xF111,0x1113, 0xC888,0xA188,0x8888,0x888B,0xE222,0x2122,0x2222,0x2223, 0xC444,0x6144,0x4444,0x4447,0xD111,0x2111,0x1111,0x1113, 0xC888,0xA188,0x8888,0x888B,0xE222,0x2122,0x2222,0x2223, 0xC444,0x6144,0x4444,0x4447,0xD111,0x2111,0x1111,0x1113, 0xC888,0xA188,0x8888,0x888B,0xE222,0x2122,0x2222,0x2223, 0xC444,0x6144,0x4444,0x4447,0xD111,0x2111,0x1111,0x1113, 0xC888,0xA188,0x8888,0x888B,0xE222,0x2122,0x2222,0x2223, 0xC444,0x6144,0x4444,0x4447,0xD111,0x2111,0x1111,0x1113, 0xC888,0xA188,0x8888,0x888B,0xE222,0x2122,0x2222,0x2223, 0xC444,0x6144,0x4444,0x4447,0xD111,0x2111,0x1111,0x1113, 0xC888,0xA188,0xFFFF,0xFF8B,0xE222,0x2122,0x7FFF,0xFF23, 0xC444,0x6144,0x7FFF,0xFF47,0xD111,0x2111,0x7FFF,0xFF13, 0xC888,0xA188,0xF1DD,0xC78B,0xE222,0x2122,0x6EDD,0xBB23, 0xC5FC,0x6144,0x6EDD,0xBB47,0xD109,0x2111,0x6EEB,0x8313, 0xC908,0xA188,0xEEEB,0xBF8B,0xE306,0x6122,0x6EF7,0xBB23, 0xC507,0xC144,0x71F7,0xC747,0xD080,0x0111,0x7FFF,0xFF13, 0xC880,0x0288,0xFFFF,0xFF8B,0xE240,0x0222,0x7FFF,0xFF23, 0xC460,0x0E44,0x4444,0x4447,0xD110,0x1911,0x1111,0x1113, 0xC88F,0xE888,0x8888,0x888B,0xE222,0x2222,0x2222,0x2223, 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xC000,0x0000,0x0000,0x0003,0xC000,0x0000,0x0000,0x0003, 0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF,0xFFFF jove-4.17.5.5/xjove/jovemenu.c000066400000000000000000000506261501102521500160460ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ /* * Note that the key bindings shown in the various menus below include some * for the Sun function keys. These presuppose that the provided jove.rc.sun * or jove.rc.sun-cmd (or even jove.rc.xterm) is being used. If some other * conventional binding is in use locally, this file should be ammended * accordingly. * * The following commands are not given menu items. * - because they involve some kind of self-insertion: * digit-[0-9] * digit-minus * paren-flash * self-insert * * - because it is not usefully executed: * unbound * * - because they are mouse actions: * xj-mouse-copy-cut * xj-mouse-line * xj-mouse-mark * xj-mouse-point * xj-mouse-word * xj-mouse-yank * xt-mouse-mark * xt-mouse-point * xt-mouse-up * * * The "xt-mouse" variable is not supported because it doesn't * apply to this "terminal". */ VARPROC(var_variables_proc, variables_menu) VARPROC(var_files_proc, var_files_menu) VARPROC(var_modes_proc, var_modes_menu) VARPROC(var_move_proc, var_move_menu) VARPROC(var_search_proc, var_search_menu) VARPROC(var_process_proc, var_process_menu) VARPROC(var_compile_proc, var_compile_menu) VARPROC(var_format_proc, var_format_menu) VARPROC(var_misc_proc, var_misc_menu) void menu_init() { describing = printing = 0; empty_menu_item = menu_create_item( MENU_STRING, "", MENU_CLIENT_DATA, "", MENU_NOTIFY_PROC, print_client_data, 0 ); empty_menu = menu_create( MENU_APPEND_ITEM, empty_menu_item, 0); on_off_menu = menu_create( MENU_NOTIFY_PROC, menu_return_item, MENU_APPEND_ITEM, empty_menu_item, MENU_ITEM, MENU_STRING, "on", MENU_CLIENT_DATA, "on", MENU_ACTION_PROC, sp_printit, 0, MENU_ITEM, MENU_STRING, "off", MENU_CLIENT_DATA, "off", MENU_ACTION_PROC, sp_printit, 0, 0); VARGROUP(var_files_menu) VARIBOOL("allow-bad-characters-in-filenames") #ifdef F_COMPLETION VARIABLE("bad-filename-extensions") VARIBOOL("display-filenames-with-bad-extensions") VARIBOOL("expand-environment-variables") #endif #ifndef MSDOS VARIABLE("file-creation-mode") #endif VARIBOOL("files-should-end-with-newline") #ifdef BACKUPFILES VARIBOOL("make-backup-files") #endif VARIABLE("tag-file") 0); VARGROUP(var_modes_menu) VARIABLE("c-argument-indentation") VARIABLE("c-indentation-increment") VARIABLE("paren-flash-delay") 0); VARGROUP(var_move_menu) VARIABLE("mark-threshold") VARIBOOL("scroll-all-lines") #ifdef HIGHLIGHTING VARIBOOL("scroll-bar") #endif VARIABLE("scroll-step") 0); VARGROUP(var_search_menu) VARIBOOL("case-ignore-search") VARIBOOL("match-regular-expressions") VARIABLE("search-exit-char") VARIBOOL("wrap-search") 0); VARGROUP(var_process_menu) #ifdef IPROCS VARIABLE("dbx-format-string") #endif #ifdef IPROCS VARIABLE("process-prompt") #endif #ifdef SUBSHELL VARIABLE("shell") VARIABLE("shell-flags") #endif VARIBOOL("send-typeout-to-buffer") #if defined(SUBSHELL) || defined(IPROCS) VARIBOOL("wrap-process-lines") #endif 0); VARGROUP(var_compile_menu) VARIABLE("error-format-string") VARIABLE("error-window-size") #ifdef SUBSHELL VARIBOOL("write-files-on-make") #endif 0); VARGROUP(var_format_menu) #ifdef CMT_FMT VARIABLE("comment-format") #endif VARIABLE("left-margin") VARIABLE("paragraph-delimiter-pattern") VARIABLE("right-margin") VARIBOOL("space-sentence-2") VARIABLE("tab-width") 0); VARGROUP(var_abbrev_menu) #ifdef ABBREV VARIBOOL("auto-case-abbrev") #endif 0); VARGROUP(var_misc_menu) VARIABLE("abort-char") #ifdef UNIX VARIBOOL("allow-^S-and-^Q") #endif /* UNIX */ #ifdef BIFF VARIBOOL("disable-biff") #endif #ifdef IBMPCDOS VARIBOOL("enhanced-keyboard") #endif #ifdef HIGHLIGHTING # ifdef IBMPCDOS VARIABLE("highlight-attribute") # endif VARIABLE("highlight-mark") #endif /* HIGHLIGHTING */ #ifdef UNIX VARIABLE("interrupt-character") #endif /* UNIX */ #if defined(USE_CTYPE) && !defined(NO_SETLOCALE) VARIABLE("lc-ctype") #endif #ifdef MAC VARIBOOL("macify") #endif #ifdef UNIX VARIABLE("mailbox") VARIABLE("mail-check-frequency") #endif /* UNIX */ VARIBOOL("meta-key") VARIABLE("mode-line") #ifdef IBMPCDOS VARIABLE("mode-line-attribute") #endif VARIBOOL("mode-line-should-standout") VARIBOOL("one-key-confirmation") #ifdef RECOVER VARIABLE("sync-frequency") #endif /* RECOVER */ #ifdef IBMPCDOS VARIABLE("text-attribute") #endif /* IBMPCDOS */ VARIABLE("tmp-file-pathname") #ifdef UNIX VARIABLE("update-time-frequency") #endif /* UNIX */ #ifdef ID_CHAR VARIBOOL("use-i/d-char") #endif VARIBOOL("visible-bell") 0); variables_menu = menu_create( MENU_NOTIFY_PROC, print_client_data, MENU_APPEND_ITEM, empty_menu_item, GROUPNAME(var_files_menu, "Files") GROUPNAME(var_modes_menu, "Modes") GROUPNAME(var_move_menu, "Movement") GROUPNAME(var_search_menu, "Search/Replace") GROUPNAME(var_process_menu, "Processes/Shell") GROUPNAME(var_compile_menu, "Compiling") GROUPNAME(var_format_menu, "Formatting") #if defined(ABBREV) GROUPNAME(var_abbrev_menu, "Abbreviations") #endif GROUPNAME(var_misc_menu, "Miscellaneous") 0); GROUP(help_menu) MENU_GEN_PROC, do_describing_proc, FUNCPULLPROC(" E ? describe-command", "describe-command", commands_proc) FUNCPULL(" describe-variable", "describe-variable", variables_menu) FUNCTION("^X ? describe-key", "describe-key") FUNCTION(" describe-bindings", "describe-bindings") FUNCTION(" apropos", "apropos") FUNCTION("Help keychart (mac)", "execute-macro keychart") 0); GROUP(file_menu) FUNCTION(" append-region", "append-region") FUNCTION(" auto-execute-command", "auto-execute-command") FUNCTION(" auto-execute-macro", "auto-execute-macro") FUNCTION("F12 find-file", "find-file") FUNCTION("^X T find-tag", "find-tag") FUNCTION(" find-tag-at-point", "find-tag-at-point") FUNCTION("^X^I insert-file", "insert-file") FUNCTION("^X^S save-file", "save-file") FUNCTION("^X^V visit-file", "visit-file") FUNCTION("^X^W write-file", "write-file") FUNCTION("^X^M write-modified-files", "write-modified-files") FUNCTION(" write-region", "write-region") FUNCPULLPROC("VARS print", "print", var_files_proc) FUNCPULLPROC("VARS set", "set", var_files_proc) 0); GROUP(mode_menu) #if defined(LISP) FUNCTION(" add-lisp-special", "add-lisp-special") #endif FUNCTION(" auto-fill-mode", "auto-fill-mode") FUNCTION(" auto-indent-mode", "auto-indent-mode") FUNCTION(" c-mode", "c-mode") FUNCTION(" fundamental-mode", "fundamental-mode") #if defined(LISP) FUNCTION(" lisp-mode", "lisp-mode") #endif FUNCTION("L1 over-write-mode", "over-write-mode") #if defined(IPROCS) FUNCTION(" dbx-mode", "dbx-mode") #endif FUNCTION(" read-only-mode", "read-only-mode") FUNCTION(" show-match-mode", "show-match-mode") FUNCTION(" text-mode", "text-mode") FUNCPULLPROC("VARS print", "print", var_modes_proc) FUNCPULLPROC("VARS set", "set", var_modes_proc) 0); GROUP(move_menu) FUNCTION("<- backward-character", "backward-character") FUNCTION("R2 backward-list", "backward-list") FUNCTION(" backward-paragraph", "backward-paragraph") FUNCTION(" E^B backward-s-expression", "backward-s-expression") FUNCTION(" E A backward-sentence", "backward-sentence") FUNCTION(" E^U backward-up-list", "backward-up-list") FUNCTION("R6 backward-word", "backward-word") FUNCTION("R7 beginning-of-file", "beginning-of-file") FUNCTION("R1 beginning-of-line", "beginning-of-line") FUNCTION(" E , beginning-of-window", "beginning-of-window") FUNCTION(" E^D down-list", "down-list") FUNCTION("R13 end-of-file", "end-of-file") FUNCTION("R4 end-of-line", "end-of-line") FUNCTION(" E . end-of-window", "end-of-window") FUNCTION(" E M first-non-blank", "first-non-blank") FUNCTION("-> forward-character", "forward-character") FUNCTION("R5 forward-list", "forward-list") FUNCTION(" E ] forward-paragraph", "forward-paragraph") FUNCTION(" E^F forward-s-expression", "forward-s-expression") FUNCTION(" E E forward-sentence", "forward-sentence") FUNCTION("R6 forward-word", "forward-word") FUNCTION(" E G goto-line", "goto-line") FUNCTION("DOWN next-line", "next-line") FUNCTION("R15 next-page", "next-page") FUNCTION("UP previous-line", "previous-line") FUNCTION("R9 previous-page", "previous-page") FUNCTION("KP_- scroll-down", "scroll-down") FUNCTION(" scroll-left", "scroll-left") FUNCTION(" scroll-right", "scroll-right") FUNCTION("KP_+ scroll-up", "scroll-up") FUNCTION(" shift-region-left", "shift-region-left") FUNCTION(" shift-region-right", "shift-region-right") FUNCPULLPROC("VARS print", "print", var_move_proc) FUNCPULLPROC("VARS set", "set", var_move_proc) 0); GROUP(bind_menu) FUNCTION(" bind-keymap-to-key", "bind-keymap-to-key") FUNCTION(" bind-macro-to-key", "bind-macro-to-key") #if defined(ABBREV) FUNCTION(" bind-macro-to-word-abbrev", "bind-macro-to-word-abbrev") #endif FUNCTION(" bind-to-key", "bind-to-key") FUNCTION(" local-bind-keymap-to-key", "local-bind-keymap-to-key") FUNCTION(" local-bind-macro-to-key", "local-bind-macro-to-key") FUNCTION(" local-bind-to-key", "local-bind-to-key") FUNCTION(" process-bind-keymap-to-key", "process-bind-keymap-to-key") FUNCTION(" process-bind-macro-to-key", "process-bind-macro-to-key") FUNCTION(" process-bind-to-key", "process-bind-to-key") 0); GROUP(macro_menu) FUNCTION("^X ( begin-kbd-macro", "begin-kbd-macro") FUNCTION(" define-macro", "define-macro") FUNCTION("^X ) end-kbd-macro", "end-kbd-macro") FUNCTION("^X E execute-kbd-macro", "execute-kbd-macro") FUNCTION(" execute-macro", "execute-macro") FUNCTION(" E I make-macro-interactive", "make-macro-interactive") FUNCTION(" name-kbd-macro", "name-kbd-macro") FUNCTION(" start-remembering", "start-remembering") FUNCTION(" stop-remembering", "stop-remembering") FUNCTION(" write-macros-to-file", "write-macros-to-file") 0); GROUP(buffer_menu) FUNCTION(" buffer-position", "buffer-position") FUNCTION("^X K delete-buffer", "delete-buffer") FUNCTION(" erase-buffer", "erase-buffer") FUNCTION(" kill-some-buffers", "kill-some-buffers") FUNCTION("F10 list-buffers", "list-buffers") FUNCTION(" make-buffer-unmodified", "make-buffer-unmodified") FUNCTION(" rename-buffer", "rename-buffer") FUNCTION("F11 select-buffer", "select-buffer") FUNCTION(" select-buffer-1", "select-buffer-1") FUNCTION(" select-buffer-2", "select-buffer-2") FUNCTION(" select-buffer-3", "select-buffer-3") FUNCTION(" select-buffer-4", "select-buffer-4") FUNCTION(" select-buffer-5", "select-buffer-5") FUNCTION(" select-buffer-6", "select-buffer-6") FUNCTION(" select-buffer-7", "select-buffer-7") FUNCTION(" select-buffer-8", "select-buffer-8") FUNCTION(" select-buffer-9", "select-buffer-9") FUNCTION(" select-buffer-10", "select-buffer-10") 0); GROUP(window_menu) FUNCTION("F4 delete-other-windows", "delete-other-windows") FUNCTION("F5 delete-current-window", "delete-current-window") FUNCTION(" goto-window-with-buffer", "goto-window-with-buffer") FUNCTION("F6 grow-window", "grow-window") FUNCTION("F3 next-window", "next-window") FUNCTION(" number-lines-in-window", "number-lines-in-window") FUNCTION(" E^V page-next-window", "page-next-window") FUNCTION("^X P previous-window", "previous-window") FUNCTION(" shrink-window", "shrink-window") FUNCTION("F2 split-current-window", "split-current-window") FUNCTION(" visible-spaces-in-window", "visible-spaces-in-window") FUNCTION("^X 4 window-find", "window-find") 0); GROUP(mark_menu) FUNCTION(" case-region-lower", "case-region-lower") FUNCTION(" case-region-upper", "case-region-upper") FUNCTION("L6 copy-region", "copy-region") FUNCTION("L4 exchange-point-and-mark", "exchange-point-and-mark") #if defined(SUBSHELL) FUNCTION(" filter-region", "filter-region") #endif FUNCTION("L10 kill-region", "kill-region") FUNCTION(" pop-mark", "pop-mark") FUNCTION(" replace-in-region", "replace-in-region") FUNCTION("L3 set-mark", "set-mark") FUNCTION("L8 yank", "yank") FUNCTION(" E Y yank-pop", "yank-pop") 0); GROUP(edit_menu) FUNCTION(" case-character-capitalize", "case-character-capitalize") FUNCTION(" case-region-lower", "case-region-lower") FUNCTION(" case-region-upper", "case-region-upper") FUNCTION(" E C case-word-capitalize", "case-word-capitalize") FUNCTION(" E L case-word-lower", "case-word-lower") FUNCTION(" E U case-word-upper", "case-word-upper") FUNCTION(" character-to-octal-insert", "character-to-octal-insert") FUNCTION("^X^O delete-blank-lines", "delete-blank-lines") FUNCTION("KP_. kill-line (mac)", "execute-macro kill-line") FUNCTION(" ^D delete-next-character", "delete-next-character") FUNCTION("DEL delete-previous-character", "delete-previous-character") FUNCTION(" E \\ delete-white-space", "delete-white-space") FUNCTION(" E D kill-next-word", "kill-next-word") FUNCTION(" EDL kill-previous-word", "kill-previous-word") FUNCTION(" E^K kill-s-expression", "kill-s-expression") FUNCTION("^XDL kill-to-beginning-of-sentence", "kill-to-beginning-of-sentence") FUNCTION(" ^K kill-to-end-of-line", "kill-to-end-of-line") FUNCTION(" E K kill-to-end-of-sentence", "kill-to-end-of-sentence") FUNCTION("RET newline", "newline") FUNCTION("KP_0 newline-and-backup", "newline-and-backup") FUNCTION("LF newline-and-indent", "newline-and-indent") FUNCTION(" ^Q quoted-insert", "quoted-insert") FUNCTION(" ^T transpose-characters", "transpose-characters") FUNCTION("^X^T transpose-lines", "transpose-lines") 0); GROUP(directory_menu) FUNCTION(" cd", "cd") FUNCTION(" dirs", "dirs") FUNCTION(" popd", "popd") FUNCTION(" pushd", "pushd") FUNCTION(" pushlibd", "pushlibd") FUNCTION(" pwd", "pwd") 0); GROUP(compile_menu) #if defined(SUBSHELL) FUNCTION("^X^E compile-it", "compile-it") #endif FUNCTION(" current-error", "current-error") FUNCTION("^X^N next-error", "next-error") FUNCTION(" parse-errors", "parse-errors") #if defined(SPELL) FUNCTION(" parse-spelling-errors-in-buffer", "parse-spelling-errors-in-buffer") #endif FUNCTION("^X^P previous-error", "previous-error") #if defined(SPELL) FUNCTION("F7 spell-buffer", "spell-buffer") FUNCPULLPROC("VARS print", "print", var_compile_proc) FUNCPULLPROC("VARS set", "set", var_compile_proc) 0); GROUP(format_menu) #if defined(CMT_FMT) FUNCTION("F8 fill-comment", "fill-comment") #endif /* CMT_FMT */ FUNCTION("F9 fill-paragraph", "fill-paragraph") FUNCTION(" fill-region", "fill-region") #if defined(LISP) FUNCTION(" grind-s-expr", "grind-s-expr") #endif FUNCTION("TAB handle-tab", "handle-tab") FUNCTION(" left-margin-here", "left-margin-here") FUNCTION(" right-margin-here", "right-margin-here") #endif FUNCPULLPROC("VARS print", "print", var_format_proc) FUNCPULLPROC("VARS set", "set", var_format_proc) 0); GROUP(search_menu) FUNCTION(" i-search-forward", "i-search-forward") FUNCTION(" i-search-reverse", "i-search-reverse") FUNCTION(" E Q query-replace-string", "query-replace-string") FUNCTION(" replace-in-region", "replace-in-region") FUNCTION(" E R replace-string", "replace-string") FUNCTION("L9 search-forward", "search-forward") FUNCTION(" search-forward-nd", "search-forward-nd") FUNCTION("EL9 search-reverse", "search-reverse") FUNCTION(" search-reverse-nd", "search-reverse-nd") FUNCPULLPROC("VARS print", "print", var_search_proc) FUNCPULLPROC("VARS set", "set", var_search_proc) 0); GROUP(process_menu) #if defined(PTYPROCS) FUNCTION(" continue-process", "continue-process") FUNCTION("^C^Y dstop-process", "dstop-process") FUNCTION("^C^D eof-process", "eof-process") #endif #if defined(IPROCS) FUNCTION(" i-shell-command", "i-shell-command") FUNCTION("^C^C interrupt-process", "interrupt-process") FUNCTION(" kill-process", "kill-process") FUNCTION(" list-processes", "list-processes") FUNCTION("CR process-newline", "process-newline") FUNCTION(" process-send-data-no-return", "process-send-data-no-return") #endif #if defined(SUBSHELL) FUNCTION(" push-shell", "push-shell") #endif #if defined(IPROCS) FUNCTION("^C^\\ quit-process", "quit-process") #endif #if defined(IPROCS) /* for GNU compatibility */ FUNCTION("Ent shell", "shell") #endif #if defined(SUBSHELL) FUNCTION("^X ! shell-command", "shell-command") FUNCTION(" shell-command-no-buffer", "shell-command-no-buffer") FUNCTION(" shell-command-to-buffer", "shell-command-to-buffer") FUNCTION(" shell-command-with-typeout", "shell-command-with-typeout") #endif #if defined(PTYPROCS) FUNCTION("^C^Z stop-process", "stop-process") #endif FUNCPULLPROC("VARS print", "print", var_process_proc) FUNCPULLPROC("VARS set", "set", var_process_proc) 0); GROUP(abbrev_menu) #if defined(ABBREV) FUNCTION(" define-global-word-abbrev", "define-global-word-abbrev") FUNCTION(" define-mode-word-abbrev", "define-mode-word-abbrev") FUNCTION(" edit-word-abbrevs", "edit-word-abbrevs") FUNCTION(" read-word-abbrev-file", "read-word-abbrev-file") FUNCTION(" word-abbrev-mode", "word-abbrev-mode") FUNCTION(" write-word-abbrev-file", "write-word-abbrev-file") #endif 0); GROUP(misc_menu) FUNCTION(" E^L clear-and-redraw", "clear-and-redraw") FUNCTION(" date", "date") FUNCTION(" execute-named-command", "execute-named-command") FUNCTION("^X^C exit-jove", "exit-jove") FUNCTION(" ^U gather-numeric-argument", "gather-numeric-argument") #if defined(JOB_CONTROL) FUNCTION(" E S pause-jove", "pause-jove") #else # ifndef MAC FUNCTION(" E S pause-jove", "pause-jove") # endif #endif FUNCTION(" recursive-edit", "recursive-edit") FUNCTION(" ^L redraw-display", "redraw-display") FUNCTION(" source", "source") FUNCTION(" string-length", "string-length") #if defined(JOB_CONTROL) FUNCTION(" suspend-jove", "suspend-jove") #endif FUNCTION(" version", "version") FUNCPULLPROC("VARS print", "print", var_misc_proc) FUNCPULLPROC("VARS set", "set", var_misc_proc) 0); main_menu = menu_create( #ifndef SUNVIEW XV_FONT, font, /* not in SunView */ #endif MENU_NOTIFY_PROC, main_notify, GROUPNAME(help_menu, "Help") GROUPNAME(file_menu, "Files") GROUPNAME(directory_menu, "Directories") GROUPNAME(mode_menu, "Modes") GROUPNAME(move_menu, "Movement") GROUPNAME(edit_menu, "Editing") GROUPNAME(search_menu, "Search/Replace") GROUPNAME(buffer_menu, "Buffers") GROUPNAME(window_menu, "Windows") GROUPNAME(mark_menu, "Mark/Region") GROUPNAME(process_menu, "Processes/Shell") GROUPNAME(compile_menu, "Compiling/Spell") GROUPNAME(format_menu, "Formatting") GROUPNAME(macro_menu, "Macros") #if defined(ABBREV) GROUPNAME(abbrev_menu, "Abbreviations") #endif GROUPNAME(bind_menu, "Binding") GROUPNAME(misc_menu, "Miscellaneous") FUNCPULLPROC("VARS print", "print", var_variables_proc) FUNCPULLPROC("VARS set", "set", var_variables_proc) 0); GROUP(another_help_menu) FUNCTION(" E ? describe-command", "describe-command") FUNCTION(" describe-variable", "describe-variable") FUNCTION("^X ? describe-key", "describe-key") FUNCTION(" describe-bindings", "describe-bindings") FUNCTION(" apropos", "apropos") 0); commands_menu = menu_create( MENU_NOTIFY_PROC, sp_printit, MENU_APPEND_ITEM, empty_menu_item, GROUPNAME(another_help_menu, "Help") GROUPNAME(file_menu, "Files") GROUPNAME(directory_menu, "Directories") GROUPNAME(mode_menu, "Modes") GROUPNAME(move_menu, "Movement") GROUPNAME(edit_menu, "Editing") GROUPNAME(search_menu, "Search/Replace") GROUPNAME(buffer_menu, "Buffers") GROUPNAME(window_menu, "Windows") GROUPNAME(mark_menu, "Mark/Region") GROUPNAME(process_menu, "Processes/Shell") GROUPNAME(compile_menu, "Compiling/Spell") GROUPNAME(format_menu, "Formatting") GROUPNAME(macro_menu, "Macros") #if defined(ABBREV) GROUPNAME(abbrev_menu, "Abbreviations") #endif GROUPNAME(bind_menu, "Binding") GROUPNAME(misc_menu, "Miscellaneous") FUNCTION("VARS print", "print") FUNCTION("VARS set", "set") 0); } jove-4.17.5.5/xjove/jovetool.c000066400000000000000000000434251501102521500160560ustar00rootroot00000000000000/* * Copyright (C) 1986 Free Software Foundation, Inc. * Copyright (C) 1991-1999 C.H.Lindsey, University of Manchester * * This file is derived from the program emacstool, which is itself part of the * GNU Emacs system. * * In the same way as GNU Emacs itself, this file is distributed in the hope * that it will be useful, but without any warranty. No author or * distributor accepts responsibility to anyone for the consequences of using * it or for whether it serves any particular purpose or works at all, unless * he says so in writing. * * Everyone is granted permission to copy, modify and redistribute this file, * but only under the conditions described in the document "GNU Emacs copying * permission notice". A copy of that document is distributed along with * GNU Emacs and other GNU Products so that you can know how you may * redistribute it all. In particular and among other things, this copyright * notice must be preserved on all copies of this file and of files derived * from it. * * * For Jove in SunView/Sun-Windows: (supported by Sun Unix) Insert a notifier * filter-function to convert all useful input to "key" sequences that jove * can understand. See: Jovetool(1). * * Author (of Jovetool): C. H. Lindsey, University of Manchester * * Author (of Emacstool): Jeff Peck, Sun Microsystems, Inc. * * Original Idea: Ian Batten * */ #include #include #include #include #include #ifdef __STDC__ #include #endif #include #include "exts.h" #include "mousemsg.h" #define BUFFER_SIZE 128 /* Size of all the buffers */ #define CLICK 400 /* max time in ms for click, or gap between * double click */ /* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */ /* #define WANT_CAPS_LOCK */ private const char mouse_prefix[] = "\030m"; /* ^x m */ private const char key_prefix[] = "\033["; /* ESC-[ */ private char jove_name[] = "jove"; /* default run command */ private char buffer[BUFFER_SIZE]; /* send to ttysw_input */ private const char title[] = "Jovetool - "; /* initial title */ private Frame frame; /* Base frame for system */ Tty ttysw; /* Where jove is */ private int font_width, font_height; /* For translating pixels to * chars */ private FILE *console = NULL; /* for debugging: setenv DEBUGJOVETOOL */ private Icon frame_icon; /* make an icon_image */ private unsigned short default_image[] = { #include "jove.icon" }; mpr_static_static(icon_image, 64, 64, 1, default_image); private Cursor current_cursor, jove_cursor, cut_cursor, copy_cursor, paste_cursor, default_cursor; private short cursor_image[] = { #include "jove.cursor" }; mpr_static_static(cursor_pix, 16, 16, 1, cursor_image); private unsigned short cut_image[] = { #include "cut.cursor" }; mpr_static_static(cut_pix, 16, 16, 1, cut_image); private unsigned short copy_image[] = { #include "copy.cursor" }; mpr_static_static(copy_pix, 16, 16, 1, copy_image); private unsigned short paste_image[] = { #include "paste.cursor" }; mpr_static_static(paste_pix, 16, 16, 1, paste_image); private void set_cursor(cursor) Cursor cursor; { if (current_cursor != cursor) { window_set(ttysw, WIN_CURSOR, cursor, 0); current_cursor = cursor; } } /* * button_value: encode mouse event into a jovetool event code (the return * value) and a button state (stored in last_but). If the event ought to be * ignored due to error, -1 is returned in place of the event code. If it is * to be ignored silently, -2 is returned. */ private int last_but = JT_UPEVENT, /* button state */ event_shift; /* shift state */ private char last_event_string[7]; /* string from last F-key down event, * 6 being the longest string * expected from an F-key */ private int button_value(event) Event *event; { static struct timeval mouse_time = {0, 0}, prev_mouse_time; static int multiclick_state = 0; int this_but = event_shift, /* button state, after this * event */ mouse_code; /* event code for this event */ switch (event_id(event)) { case LOC_MOVEWHILEBUTDOWN: if (last_but & JT_UPEVENT) return -1; else if (multiclick_state) return -2; last_but |= JT_DRAGEVENT; { /* * Generate event code for leftmost depressed button. * Currently, only one bit will be on, so this is * overkill. */ static short DragCode[8] = { -1, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT, JTEC_RIGHT, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT}; return DragCode[last_but & JT_BUTMASK] + JTEC_DRAG; } case MS_LEFT: this_but |= JT_LEFT; mouse_code = JTEC_LEFT; break; case MS_MIDDLE: this_but |= JT_MIDDLE; mouse_code = JTEC_MIDDLE; break; case MS_RIGHT: this_but |= JT_RIGHT; mouse_code = JTEC_RIGHT; break; default: return -1; } /* * Clicking too fast can sometimes beat the system. Also, a user * might manage to get two buttons down at the same time. The * following tests detect such situations. Note that up events after * JT_RIGHT are absorbed by the menu software. */ if (event_is_up(event)) { /* ignore up not following a down or up of a different button */ if ((last_but & JT_UPEVENT) != 0 || ((last_but ^ this_but) & JT_BUTMASK) != 0) return -1; this_but |= JT_UPEVENT; mouse_code += JTEC_UP; } else if (event_is_down(event)) { if ((last_but & (JT_UPEVENT | JT_RIGHT)) == 0) { /* down event not preceded by an up event */ return -1; } } else { /* drag event */ if ((last_but & (JT_DOWNEVENT | JT_DRAGEVENT)) == 0) { /* drag event not preceded by a down or drag event */ return -1; } } /* * The only way to get back into sync is to supply whatever up or * down event it was waiting for. Thus jove should always see a * consistent picture. ??? Good theory. How is this implemented? -- * DHR */ /* * Detect and encode multi-clicks. * * - a multiclick is a train of alternating mouse-down and mouse-up * events - the first must be a mouse-down - Each mouse up and down * must be of the same button - each of which happens within CLICK * milliseconds of its predecessor - Drags are not taken into * consideration. */ prev_mouse_time = mouse_time; mouse_time = event_time(event); multiclick_state += 1; if (((multiclick_state & 1) == 0) == ((this_but & JT_UPEVENT) == 0) && ((last_but ^ this_but) & JT_BUTMASK) == 0 && (mouse_time.tv_sec - prev_mouse_time.tv_sec) * 1000 + (mouse_time.tv_usec - prev_mouse_time.tv_usec) / 1000 <= CLICK) { switch (multiclick_state) { case 1: /* first up */ break; case 2: /* second down */ mouse_code += JTEC_CLICK2; /* FALLTHROUGH */ case 3: /* second up */ this_but |= JT_CLICK2; break; case 4: /* third down */ mouse_code += JTEC_CLICK3; /* FALLTHROUGH */ case 5: /* third up */ this_but |= JT_CLICK3; break; default: /* too many multi-clicks */ multiclick_state = 0; break; } } else { multiclick_state = 0; } last_but = this_but; return mouse_code; } /* * Filter function to translate selected input events for jove Mouse button * events become ^XmC(button-state x-col y-line font-width) . - C is an * eventcode (explained in mousemsg.h) - button-state is as described in * mousemsg.h for this_but - x-col is horizontal column, in pixels (for * smooth scrollbar working) - y-col is height, in characters - font-width * allows conversion of x-col to characters Sun function keys (left, top, and * right) are converted to the ANSI sequence ESC [ P z, where P is a number * above 192 */ private Notify_value input_event_filter_function(window, event, arg, type) Window window; Event *event; Notify_arg arg; Notify_event_type type; { #ifdef WANT_CAPS_LOCK static int caps_lock = 0; /* toggle indicater for f-key T1 caps * lock */ #endif int id = event_id(event); int mouse_code = -3; /* not -1 and not -2 and not * >=0 */ int fkey; event_shift &= ~JT_CSMASK; if (event_shift_is_down(event)) event_shift |= JT_SHIFT; if (event_ctrl_is_down(event)) event_shift |= JT_CONTROL; if (event_action(event) == ACTION_PASTE || event_action(event) == ACTION_CUT) { if (event_is_up(event)) event_shift &= ~(event_action(event) == ACTION_PASTE ? JT_PASTE : JT_CUT); else event_shift |= (event_action(event) == ACTION_PASTE ? JT_PASTE : JT_CUT); } if (console != NULL) { fprintf(console, "Event %d", id); if (event_shift != 0) fprintf(console, "; shift %d", event_shift); if (event_is_up(event)) fprintf(console, "; up"); if (event_is_button(event)) fprintf(console, "; button %d", id - BUT(0)); fprintf(console, "\n"); } switch (id) { case LOC_MOVEWHILEBUTDOWN: mouse_code = button_value(event); /* no need to set cursor */ break; case MS_LEFT: case MS_MIDDLE: case MS_RIGHT: mouse_code = button_value(event); if (last_but & JT_PASTEMASK) last_event_string[0] = 0; /* * We do not wish to see Left keys (esp. PASTE & CUT) * associated with buttons */ /* FALLTHROUGH */ case SHIFT_LEFT: case SHIFT_RIGHT: case SHIFT_CTRL: /* set cursor appropriately */ if (event_shift == JT_SHIFT) { set_cursor(default_cursor); } else { switch (event_shift | (last_but & (JT_UPEVENT | JT_BUTMASK))) { case JT_SHIFT | JT_CONTROL | JT_MIDDLE: set_cursor(cut_cursor); break; case JT_CONTROL | JT_MIDDLE: set_cursor(copy_cursor); break; case JT_CONTROL | JT_LEFT: set_cursor(paste_cursor); break; default: set_cursor(jove_cursor); break; } } break; case KEY_LEFT(5): /* EXPOSE key */ case KEY_LEFT(7): /* OPEN key */ /* * UP L5 & L7 is Expose & Open, let them pass to SunView. ??? * Apparently it only cares about up events. */ return event_is_up(event) ? notify_next_event_func(window, event, arg, type) : NOTIFY_IGNORED; } /* * Treat shifted events as normal Shelltool events. This includes * shifted characters which is a bit naughty (xjove must deal with * them separately because it needs to clear the shiftmask for * non-characters). */ if (event_shift == JT_SHIFT) { /* * NOTE: at least under SunOS4.0.3, the shelltool routine * turns off LOC_MOVEWHILEBUTDOWN, so we must restore it. */ Notify_value result = notify_next_event_func(window, event, arg, type); window_set(ttysw, WIN_CONSUME_PICK_EVENT, LOC_MOVEWHILEBUTDOWN, 0); return result; } /* do Mouse Button events */ if (mouse_code >= 0) { int this_x = event_x(event), this_y = event_y(event) / font_height; static int last_x, last_y; if (last_but & JT_RIGHT) { /* * ??? avoid passing up-event, if we catch it -- * would cause deadlock. */ if (last_but == JT_RIGHT) menu_show(main_menu, window, event, 0); } else { if (this_x == last_x && this_y == last_y) { if (id == LOC_MOVEWHILEBUTDOWN) return NOTIFY_IGNORED; sprintf(buffer, "%s%d(%d)\015", mouse_prefix, mouse_code, last_but); } else { sprintf(buffer, "%s%d(%d %d %d %d)\015", mouse_prefix, mouse_code, last_but, this_x, this_y, font_width); last_x = this_x; last_y = this_y; } ttysw_input(ttysw, buffer, strlen(buffer)); } return NOTIFY_IGNORED; } else if (mouse_code == -1) { ttysw_output(ttysw, "\007", 1); /* beep */ return NOTIFY_IGNORED; } else if (mouse_code == -2) { return NOTIFY_IGNORED; } /* process event if it was a function key stroke */ fkey = 0; /* In JoveTool, WIN_STOP is handled separately, as a synonym for L1. */ if (id == WIN_STOP) fkey = 192; else if (event_is_key_left(event)) fkey = id - KEY_LEFT(1) + 192; else if (event_is_key_right(event)) fkey = id - KEY_RIGHT(1) + 208; else if (event_is_key_top(event)) fkey = id - KEY_TOP(1) + 224; if (fkey != 0) { if (event_is_down(event) || id == WIN_STOP) sprintf(last_event_string, "%s%dz", key_prefix, fkey); /* test should be !event_button_is_down(event) */ if (last_but & JT_UPEVENT) { /* * we don't want any function keys (esp PASTE & CUT) * seen when a button is down */ if (event_action(event) == ACTION_PASTE || event_action(event) == ACTION_CUT || id == WIN_STOP) { if (event_is_down(event)) { /* * we see PASTE and CUT and WIN_STOP * when they come up */ return NOTIFY_IGNORED; } } else if (event_is_up(event)) { /* we see other F-keys when they go down */ return NOTIFY_IGNORED; } #ifdef WANT_CAPS_LOCK /* * set a toggle and relabel window so T1 can act like * caps-lock */ if (id == KEY_TOP(1)) { /* make a frame label with and without CAPS */ static const char Caps[] = "[CAPS] "; char *p = (char *) window_get(frame, FRAME_LABEL); strcpy(buffer, Caps); strncpy(buffer + sizeof(Caps) - 1, strncmp(p, Caps, sizeof(Caps) - 1) == 0 ? p + sizeof(Caps) - 1 : p, BUFFERSIZE - (sizeof(Caps))); buffer[BUFFER_SIZE - 1] = '\0'; caps_lock = !caps_lock; window_set(frame, FRAME_LABEL, buffer + (caps_lock ? 0 : sizeof(Caps) - 1), 0); return NOTIFY_IGNORED; } #endif ttysw_input(ttysw, last_event_string, strlen(last_event_string)); } return NOTIFY_IGNORED; } /* Discard key-up ascii or meta events */ /* * ??? is this needed? Will the someone down the line not do this? * We aren't even catching ascii up-events. */ if ((event_is_ascii(event) || event_is_meta(event)) && event_is_up(event)) return NOTIFY_IGNORED; #ifdef WANT_CAPS_LOCK /* shift alpha chars to upper case if capslock is set */ if (caps_lock && event_is_ascii(event) && isupper(id)) event_set_id(event, tolower(id)); #endif if (event_is_ascii(event)) { /* * Force bit 8 if meta key is down. But it will only be * noticed by the controlled process if it does a stty * -istrip, or equivalent. */ if (event_shiftmask(event) & META_SHIFT_MASK) event->ie_code |= META_FIRST; /* ??? META_KEY_MASK not * in SunView */ } /* If we get here, pass event off to next handler */ return notify_next_event_func(window, event, arg, type); } extern char *getenv proto((const char *)); /* fudge -- must be in some * header */ int main(argc, argv) int argc; char **argv; { int error_code; /* Error codes */ int forking; char *debug; if ((debug = getenv("DEBUGJOVETOOL")) != NULL) { /* * DEBUGJOVETOOL specifies the file or device to receive * debugging output, if any. The null name signifies stderr. */ console = *debug == '\0' ? stderr : fopen(debug, "w"); forking = 0; } else { forking = isatty(0); } if (argc>1 && (!strcmp("-f", argv[1]) || !strcmp("-nf", argv[1]))) { char **p = &argv[1]; forking = strcmp("-f", *p) == 0; do ; while ((p[0] = p[1]) != NULL); } if (forking) { switch (fork()) { case -1: fprintf(stderr, "fork failed"); exit(1); /* NOTREACHED */ case 0: /* the child */ setpgrp(0, 0); /* so it doesn't get killed when * parent dies */ break; default: /* the parent */ exit(0); /* NOTREACHED */ } } putenv("IN_JOVETOOL=t");/* notify subprocess that it is in jovetool */ putenv("TERMCAP="); putenv("TERM=sun"); /* the TTYSW will be a sun terminal to * override these, try % jovetool -rc script */ if ((argv[0] = getenv("JOVETOOL")) == NULL) /* Set jove command name */ argv[0] = jove_name; for (argc = 1; argv[argc]; argc++) /* Use last one on line */ if (!(strcmp("-rc", argv[argc]))) { /* Override if -rc given */ int i = argc; argv[argc--] = 0; /* kill the -rc argument */ if (argv[i + 1]) { /* move to argv[0] and * squeeze the rest */ argv[0] = argv[i + 1]; for (; argv[i + 2]; (argv[i] = argv[i + 2], argv[++i] = 0)); } } frame_icon = icon_create(ICON_LABEL, argv[0], ICON_IMAGE, &icon_image, 0); strcpy(buffer, title); strncat(buffer, argv[0],/* append run command name */ (BUFFER_SIZE - (strlen(buffer)) - (strlen(argv[0]))) - 1); /* Build a frame to run in */ frame = window_create((Window) NULL, FRAME, FRAME_LABEL, buffer, FRAME_ICON, frame_icon, FRAME_ARGC_PTR_ARGV, &argc, argv, 0); /* Create a tty with jove in it */ ttysw = window_create(frame, TTY, TTY_QUIT_ON_CHILD_DEATH, TRUE, /* TTY_BOLDSTYLE, 4, */ TTY_ARGV, argv, 0); window_set(ttysw, WIN_CONSUME_PICK_EVENTS, WIN_STOP, WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, /* LOC_WINENTER, LOC_WINEXIT, LOC_MOVE, */ LOC_MOVEWHILEBUTDOWN, 0, WIN_CONSUME_KBD_EVENTS, WIN_STOP, SHIFT_LEFT, SHIFT_RIGHT, SHIFT_CTRL, WIN_ASCII_EVENTS, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, /* WIN_UP_ASCII_EVENTS, */ 0, 0); default_cursor = window_get(ttysw, WIN_CURSOR); jove_cursor = cursor_create( CURSOR_IMAGE, &cursor_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); cut_cursor = cursor_create( CURSOR_IMAGE, &cut_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); copy_cursor = cursor_create( CURSOR_IMAGE, ©_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); paste_cursor = cursor_create( CURSOR_IMAGE, &paste_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); set_cursor(jove_cursor); font_height = (int) window_get(ttysw, WIN_ROW_HEIGHT); font_width = (int) window_get(ttysw, WIN_COLUMN_WIDTH); /* Interpose my event function */ error_code = (int) notify_interpose_event_func (ttysw, input_event_filter_function, NOTIFY_SAFE); if (error_code != 0) { /* Barf */ fprintf(stderr, "notify_interpose_event_func got %d.\n", error_code); exit(1); } menu_init(); window_main_loop(frame);/* And away we go */ exit(0); /* if this is ever reached */ /* NOTREACHED */ } jove-4.17.5.5/xjove/jovewindows.c000066400000000000000000000102141501102521500165610ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ #include #include #include #include #include "exts.h" #include "jovewindows.h" private char command_prefix[] = "\033X"; /* ESC-X */ #define command_prefix_length (sizeof(command_prefix) - 1) Menu main_menu; private Menu file_menu, mode_menu, help_menu, move_menu, bind_menu, macro_menu, buffer_menu, window_menu, mark_menu, edit_menu, directory_menu, compile_menu, format_menu, search_menu, process_menu, abbrev_menu, misc_menu, variables_menu, another_help_menu, commands_menu, var_files_menu, var_modes_menu, var_move_menu, var_search_menu, var_process_menu, var_compile_menu, var_format_menu, var_misc_menu, var_abbrev_menu, empty_menu, on_off_menu; private Menu_item empty_menu_item; private int describing, printing; private caddr_t print_client_data(m, mi) Menu m; Menu_item mi; { char *menu_string; menu_string = (char *)menu_get(mi, MENU_CLIENT_DATA); ttysw_input(ttysw, menu_string, strlen(menu_string)); /* ??? What value ought to be returned? This is a guess -- DHR */ return menu_get(mi, MENU_VALUE); } private caddr_t main_notify(m, mi) Menu m; Menu_item mi; { ttysw_input (ttysw, command_prefix, command_prefix_length); print_client_data(m, mi); ttysw_input (ttysw, "\n", 1); /* ??? What value ought to be returned? This is a guess -- DHR */ return NULL; } private caddr_t sp_printit(m, mi) Menu m; Menu_item mi; { char *menu_string; menu_string = (char *)menu_get(mi, MENU_CLIENT_DATA); if (mi != empty_menu_item) ttysw_input(ttysw, " ", 1); ttysw_input(ttysw, menu_string, strlen(menu_string)); /* ??? What value ought to be returned? This is a guess -- DHR */ return menu_get(mi, MENU_VALUE); } private Menu_item commands_proc(item, operation) Menu_item item; Menu_generate operation; { return commands_menu; } #ifdef NEVER /* ??? seems to be unused */ Menu_item var_proc(item, operation, menu) Menu_item item; Menu_generate operation; Menu menu; { switch (operation) { case MENU_DISPLAY: if (!describing) menu_set(item, MENU_PULLRIGHT, menu, 0); break; case MENU_DISPLAY_DONE: menu_set(item, MENU_PULLRIGHT, 0, 0); break; case MENU_NOTIFY: break; case MENU_NOTIFY_DONE: break; } return item; } #endif private Menu_item on_off_proc(item, operation) Menu_item item; Menu_generate operation; { switch (operation) { case MENU_DISPLAY: if (!describing & !printing) { menu_set(item, MENU_PULLRIGHT, on_off_menu, 0); } else { menu_set(item, MENU_PULLRIGHT, 0, 0); } break; case MENU_DISPLAY_DONE: case MENU_NOTIFY: case MENU_NOTIFY_DONE: break; } return item; } private Menu do_set_proc(mi, operation, menu) Menu_item mi; Menu_generate operation; Menu menu; { static Menu displayed; if (!describing) { switch (operation) { case MENU_DISPLAY: if (!strcmp(menu_get(mi, MENU_CLIENT_DATA), "print")) printing = 1; displayed = menu; menu_set(menu, MENU_SELECTED, 0, 0); break; case MENU_DISPLAY_DONE: printing = 0; break; case MENU_NOTIFY: case MENU_NOTIFY_DONE: if (!(displayed == menu) || !menu_get(menu, MENU_SELECTED)) { displayed = NULL; return empty_menu; } displayed = NULL; break; } return menu; } else return empty_menu; } private Menu do_describing_proc(m, operation) Menu m; Menu_generate operation; { switch (operation) { case MENU_DISPLAY: describing = 1; break; case MENU_DISPLAY_DONE: describing = 0; break; case MENU_NOTIFY: describing = 1; break; case MENU_NOTIFY_DONE: describing = 0; break; } return m; } #include "jovemenu.c" jove-4.17.5.5/xjove/jovewindows.h000066400000000000000000000030411501102521500165660ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ #include "tune.h" #define FUNCTION(key_string, string) MENU_ITEM, \ MENU_STRING, key_string, \ MENU_CLIENT_DATA, string, 0, #define GROUP(menu) menu = menu_create(MENU_NOTIFY_PROC, print_client_data, #define GROUPNAME(menu, name) MENU_ITEM, \ MENU_STRING, name, \ MENU_CLIENT_DATA, "", \ MENU_PULLRIGHT, menu, 0, #define FUNCPULL(key_string, string, menu) MENU_ITEM, \ MENU_STRING, key_string, \ MENU_CLIENT_DATA, string, \ MENU_PULLRIGHT, menu, 0, #define FUNCPULLPROC(key_string, string, menu_proc) MENU_ITEM, \ MENU_STRING, key_string, \ MENU_CLIENT_DATA, string, \ MENU_GEN_PULLRIGHT, menu_proc, 0, #define VARIABLE(string) FUNCTION(string, string) #define VARIBOOL(string) MENU_ITEM, \ MENU_STRING, string, \ MENU_CLIENT_DATA, string, \ MENU_GEN_PROC, on_off_proc, 0, #define VARGROUP(menu) menu = menu_create(MENU_NOTIFY_PROC, sp_printit, #define VARPROC(proc, menu) Menu_item \ proc(item, operation) \ Menu_item item; \ Menu_generate operation; \ { return do_set_proc(item, operation, menu); } jove-4.17.5.5/xjove/mousemsg.h000066400000000000000000000065141501102521500160570ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ /* JoveTool/XJove Mouse Message Format * * Mouse button events become: * ^XmC(button-state x-col y-line font-width) * or (if the mouse has not moved): * ^XmC(button-state) * * - C is an eventcode, a single character describing what has just * happened to the mouse. * - button-state is a decimal numeral (mostly) describing the current * state of the buttons and shifts. * - x-col is a decimal numeral reporting the horizontal PIXEL column * containing the mouse pointer. The leftmost column is numbered 0. * - y-col is a decimal numeral reporting the vertical CHARACTER row * containing the mouse pointer. The top row is numbered 1. * - font-width is a decimal numeral reporting the width of each character * in pixels (the font must be fixed pitch). This allows the conversion * of x-col to characters. */ /* Event Code * * Code for the current event in mouse_code (left/middle/right). * It is encoded as a single decimal digit, in ASCII. * Note: right-button events won't get passed to child, so there * is no need to encode the digits 10 to 14. * This code is intended to be used to select the desired JOVE command, * via the key-binding mechanism. * * 0/5/10 down * 1/6/11 double-click down * 2/7/12 triple-click down * 3/8/13 release * 4/9/14 drag with button down */ #define JTEC_LEFT 0 #define JTEC_MIDDLE 5 #define JTEC_RIGHT 10 #define JTEC_DOWN 0 #define JTEC_CLICK2 1 #define JTEC_CLICK3 2 #define JTEC_UP 3 #define JTEC_DRAG 4 /* Button State * * The JT_LEFT, JT_MIDDLE, and JT_RIGHT are mutually exclusive, * and indicate the last button that changed state. Note that JT_RIGHT * will not be seen by a client program since the right button is * used internally for menu selection. * * JT_SHIFT and JT_CONTROL indicate the state of these shift keys * at the time of the event. * * JT_CLICK2 and JT_CLICK3 indicate whether a button up or button down * is part of a double or triple click. Note that a multiclick down * might be followed by a non-multiclick up (if the release is slow). * * JT_UPEVENT and JT_DRAGEVENT together indicate what kind of event * just occurred: button down (neither on), button up, or a mouse * movement while a button was depressed. * * JT_PASTE and JT_CUT indicate whether these keys were down * at the time of the event. */ #define JT_LEFT 00001 #define JT_MIDDLE 00002 #define JT_RIGHT 00004 #define JT_BUTMASK (JT_LEFT | JT_MIDDLE | JT_RIGHT) #define JT_SHIFT 00010 #define JT_CONTROL 00020 #define JT_CSMASK (JT_SHIFT | JT_CONTROL) #define JT_CLICK2 00040 #define JT_CLICK3 00100 #define JT_CLICKMASK (JT_CLICK2 | JT_CLICK3) #define JT_DOWNEVENT 00000 #define JT_UPEVENT 00200 #define JT_DRAGEVENT 00400 #define JT_EVENTMASK (JT_UPEVENT | JT_DRAGEVENT) #define JT_PASTE 01000 #define JT_CUT 02000 #define JT_PASTEMASK (JT_PASTE | JT_CUT) jove-4.17.5.5/xjove/paste.cursor000066400000000000000000000003361501102521500164160ustar00rootroot00000000000000/* Format_version=1, Width=16, Height=16, Depth=1, Valid_bits_per_item=16 */ 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0100, 0x0380, 0x0380, 0x07C0, 0x06C0, 0x0AA0, 0x0AA0, 0x0AA0, jove-4.17.5.5/xjove/xjove.c000066400000000000000000000526741501102521500153560ustar00rootroot00000000000000/* * Copyright (C) 1986 Free Software Foundation, Inc. * Copyright (C) 1991-1999 C.H.Lindsey, University of Manchester * * This file is derived from the program emacstool, which is itself part of the * GNU Emacs system. * * In the same way as GNU Emacs itself, this file is distributed in the hope * that it will be useful, but without any warranty. No author or * distributor accepts responsibility to anyone for the consequences of using * it or for whether it serves any particular purpose or works at all, unless * he says so in writing. * * Everyone is granted permission to copy, modify and redistribute this file, * but only under the conditions described in the document "GNU Emacs copying * permission notice". A copy of that document is distributed along with * GNU Emacs and other GNU Products so that you can know how you may * redistribute it all. In particular and among other things, this copyright * notice must be preserved on all copies of this file and of files derived * from it. * * * For Jove in SunView/Sun-Windows: (supported by Sun Unix v3.2) Insert a * notifier filter-function to convert all useful input to "key" sequences * that jove can understand. See: Xjove(1). * * Author (of Jovetool/Xjove): C. H. Lindsey, University of Manchester * * Author (of Emacstool): Jeff Peck, Sun Microsystems, Inc. * * Original Idea: Ian Batten * */ #include #include #include #include /* is this missing on some systems? */ #include #include #include #include #include #include /* for Suns only */ #include #include #include #include #include /* is this missing on some systems? */ #include #include #include "exts.h" #include "mousemsg.h" #define BUFFER_SIZE 256 /* Size of all the buffers */ #define CLICK 400 /* max time in ms for click, or gap between * double click */ /* define WANT_CAPS_LOCK to make f-key T1 (aka F1) behave as CapsLock */ /* #define WANT_CAPS_LOCK */ private const char mouse_prefix[] = "\030m"; /* ^x m */ private const char key_prefix[] = "\033["; /* ESC-[ */ private char *jove_name = "jove"; /* default run command */ private char buffer[BUFFER_SIZE]; /* send to ttysw_input */ private const char title[] = "XJove - "; /* initial title */ private Frame frame; /* Base frame for system */ Tty ttysw; /* Where jove is */ private Tty ttyview; private int font_width, font_height; /* For translating pixels to * chars */ private int left_margin, right_margin; private FILE *console = NULL; /* for debugging: setenv DEBUGJOVETOOL */ private Icon frame_icon; /* make an icon_image */ private unsigned short default_image[] = { #include "jove.icon" }; mpr_static_static(icon_image, 64, 64, 1, default_image); private Xv_Cursor current_cursor, jove_cursor, cut_cursor, copy_cursor, paste_cursor, default_cursor; private unsigned short cursor_image[] = { #include "jove.cursor" }; mpr_static_static(cursor_pix, 16, 16, 1, cursor_image); private unsigned short cut_image[] = { #include "cut.cursor" }; mpr_static_static(cut_pix, 16, 16, 1, cut_image); private unsigned short copy_image[] = { #include "copy.cursor" }; mpr_static_static(copy_pix, 16, 16, 1, copy_image); private unsigned short paste_image[] = { #include "paste.cursor" }; mpr_static_static(paste_pix, 16, 16, 1, paste_image); Xv_Font font; private void set_cursor(cursor) Xv_Cursor cursor; { if (current_cursor != cursor) { xv_set(ttyview, WIN_CURSOR, cursor, 0); current_cursor = cursor; } } /* * button_value: encode mouse event into an xjove event code (the return * value) and a button state (stored in last_but). If the event ought to be * ignored due to error, -1 is returned in place of the event code. If it is * to be ignored silently, -2 is returned. */ private int last_but = JT_UPEVENT, /* button state */ event_shift, /* shift state */ next_kdb_event_should_be_up; private char last_event_string[7]; /* string from last F-key down event, * 6 being the longest string * expected from an F-key */ private int button_value(event) Event *event; { static struct timeval mouse_time = {0, 0}, prev_mouse_time; static int multiclick_state = 0; int this_but = event_shift, /* button state, after this * event */ mouse_code; /* event code for this event */ switch (event_id(event)) { case LOC_DRAG: if (last_but & JT_UPEVENT) return -1; else if (multiclick_state) return -2; last_but |= JT_DRAGEVENT; { /* * Generate event code for leftmost depressed button. * Currently, only one bit will be on, so this is * overkill. */ static short DragCode[8] = { -1, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT, JTEC_RIGHT, JTEC_LEFT, JTEC_MIDDLE, JTEC_LEFT}; return DragCode[last_but & JT_BUTMASK] + JTEC_DRAG; } case MS_LEFT: this_but |= JT_LEFT; mouse_code = JTEC_LEFT; break; case MS_MIDDLE: this_but |= JT_MIDDLE; mouse_code = JTEC_MIDDLE; break; case MS_RIGHT: this_but |= JT_RIGHT; mouse_code = JTEC_RIGHT; break; default: return -1; } /* * Clicking too fast can sometimes beat the system. Also, a user * might manage to get two buttons down at the same time. The * following tests detect such situations. Note that up events after * JT_RIGHT are absorbed by the menu software. */ if (event_is_up(event)) { /* ignore up not following a down or up of a different button */ if ((last_but & (JT_UPEVENT | JT_RIGHT)) == JT_UPEVENT || ((last_but ^ this_but) & JT_BUTMASK) != 0) return -1; this_but |= JT_UPEVENT; mouse_code += JTEC_UP; } else if (event_is_down(event)) { if ((last_but & (JT_UPEVENT | JT_RIGHT)) == 0) { /* down event not preceded by an up or right event */ return -1; } } else { /* drag event */ if ((last_but & (JT_DOWNEVENT | JT_DRAGEVENT)) == 0) { /* drag event not preceded by a down or drag event */ return -1; } } /* * The only way to get back into sync is to supply whatever up or * down event it was waiting for. Thus jove should always see a * consistent picture */ /*-- Detect and encode multi-clicks. * * - a multiclick is a train of alternating mouse-down and mouse-up events * - the first must be a mouse-down * - Each mouse up and down must be of the same button * - each of which happens within CLICK milliseconds of its predecessor * - Drags are not taken into consideration. */ prev_mouse_time = mouse_time; mouse_time = event_time(event); multiclick_state += 1; if (((multiclick_state & 1) == 0) == ((this_but & JT_UPEVENT) == 0) && ((last_but ^ this_but) & JT_BUTMASK) == 0 && (mouse_time.tv_sec - prev_mouse_time.tv_sec) * 1000 + (mouse_time.tv_usec - prev_mouse_time.tv_usec) / 1000 <= CLICK) { switch (multiclick_state) { case 1: /* first up */ break; case 2: /* second down */ mouse_code += JTEC_CLICK2; /* FALLTHROUGH */ case 3: /* second up */ this_but |= JT_CLICK2; break; case 4: /* third down */ mouse_code += JTEC_CLICK3; /* FALLTHROUGH */ case 5: /* third up */ this_but |= JT_CLICK3; break; default: /* too many multi-clicks */ multiclick_state = 0; break; } } else { multiclick_state = 0; } last_but = this_but; return mouse_code; } /* * Filter function to translate selected input events for jove Mouse button * events become ^XmC(button-state x-col y-line font-width) . - C is an * eventcode (explained in mousemsg.h) - button-state is as described * mousemsg.h for this_but - x-col is horizontal column, in pixels (for * smooth scrollbar working) - y-col is height, in characters - font-width * allows conversion of x-col to characters Sun function keys (left, top, and * right) are converted to the ANSI sequence ESC [ P z, where P is a number * above 192 */ private Notify_value input_event_filter_function(window, event, arg, type) Xv_Window window; Event *event; Notify_arg arg; Notify_event_type type; { int id = event_id(event); int mouse_code = -3; /* not -1 and not -2 and not * >=0 */ int fkey; event_shift &= ~JT_CSMASK; if (event_shift_is_down(event)) event_shift |= JT_SHIFT; if (event_ctrl_is_down(event)) event_shift |= JT_CONTROL; /* * Under Xview (but not SunView) the answers to the above queries do * not reflect the effect of the current event! */ { int delta = 0; switch (event_action(event)) { case SHIFT_LEFT: case SHIFT_RIGHT: delta = JT_SHIFT; break; case SHIFT_CTRL: delta = JT_CONTROL; break; case ACTION_PASTE: delta = JT_PASTE; break; case ACTION_CUT: delta = JT_CUT; break; } if (event_is_up(event)) event_shift &= ~delta; else event_shift |= delta; } if (console != NULL) { fprintf(console, "Ttyview Event %d", id); if (event_shift != 0) fprintf(console, "; shift %d", event_shift); if (event_is_up(event)) fprintf(console, "; up"); if (event_is_button(event)) fprintf(console, "; button %d", id - BUT(0)); fprintf(console, "\n"); } switch (id) { case LOC_DRAG: mouse_code = button_value(event); /* no need to set cursor */ break; case MS_LEFT: case MS_MIDDLE: case MS_RIGHT: mouse_code = button_value(event); if (last_but & JT_PASTEMASK) last_event_string[0] = 0; /* * We do not wish to see Left keys (esp. PASTE & CUT) * associated with buttons */ /* FALLTHROUGH */ case SHIFT_LEFT: case SHIFT_RIGHT: case SHIFT_CTRL: /* set cursor appropriately */ if (event_shift == JT_SHIFT) { set_cursor(default_cursor); } else { switch (event_shift | (last_but & (JT_UPEVENT | JT_BUTMASK))) { case JT_SHIFT | JT_CONTROL | JT_MIDDLE: set_cursor(cut_cursor); break; case JT_CONTROL | JT_MIDDLE: set_cursor(copy_cursor); break; case JT_CONTROL | JT_LEFT: set_cursor(paste_cursor); break; default: set_cursor(jove_cursor); break; } } break; case KEY_LEFT(5): /* EXPOSE or FRONT key */ case KEY_LEFT(7): /* OPEN key */ /* * UP L5 & L7 are Expose & Open, let them pass to SunView. * Apparently it only cares about up events. Actually, the * down event never gets this far, but the up event seems to * be needed to force a refresh. */ return event_is_up(event) ? notify_next_event_func(window, (Notify_event) event, arg, type) : NOTIFY_IGNORED; } /* Treat shifted events as normal Shelltool events. */ if (event_shift == JT_SHIFT && id >= ISO_LAST) { Notify_value result; /* Translate well-known left keys. */ switch (id) { case KEY_LEFT(6): event->action = ACTION_COPY; break; case KEY_LEFT(8): event->action = ACTION_PASTE; break; case KEY_LEFT(10): event->action = ACTION_COPY; /* CUT is censored */ break; } event_shiftmask(event) &= ~SHIFTMASK; /* get rid of shift */ event_set_string(event, NULL); /* later versions of xview * seem to output this string * even when they have already * interpreted the event as a * copy/paste/cut */ result = notify_next_event_func(window, (Notify_event) event, arg, type); return result; } /* do Mouse Button events */ if (mouse_code >= 0) { int this_x = event_x(event) - left_margin, this_y = event_y(event) / font_height; static int last_x, last_y; if (last_but & JT_RIGHT) { /* * ??? avoid passing up-event, if we catch it -- * would cause deadlock. */ if (last_but == JT_RIGHT) menu_show(main_menu, window, event, 0); } else { if (this_x == last_x && this_y == last_y) { if (id == LOC_DRAG) return NOTIFY_IGNORED; sprintf(buffer, "%s%d(%d)\015", mouse_prefix, mouse_code, last_but); } else { sprintf(buffer, "%s%d(%d %d %d %d)\015", mouse_prefix, mouse_code, last_but, this_x, this_y, font_width); last_x = this_x; last_y = this_y; } ttysw_input(ttysw, buffer, strlen(buffer)); } return NOTIFY_IGNORED; } else if (mouse_code == -1) { ttysw_output(ttysw, "\007", 1); /* beep */ return NOTIFY_IGNORED; } else if (mouse_code == -2) { return NOTIFY_IGNORED; } if (next_kdb_event_should_be_up && event_is_down(event) && event_is_iso(event)) { ttysw_output(ttysw, "\007", 1); /* beep */ return NOTIFY_IGNORED; } next_kdb_event_should_be_up = 0; if (event_is_string(event) /* it has been rebound with * XRebindKeysym */ ||event_is_key_left(event)) { /* For some reason, up events * of PASTE and CUT do not * appear as string events, * but they must be caught * here */ if (event_is_down(event)) { if (event_is_string(event)) { strcpy(last_event_string, event_string(event)); /* * because XView does not seem to provide * these strings on the up event */ } else { last_event_string[0] = '\0'; /* * Sometimes, even the down event of PASTE is * not a string, as when Caps Lock is down. * Forget it! */ } } if (!event_button_is_down(event)) { /* * we don't want any function keys (esp PASTE & CUT) * seen when a button is down */ if (event_action(event) == ACTION_PASTE || event_action(event) == ACTION_CUT) { if (event_is_down(event)) { /* * we see PASTE and CUT when they * come up */ next_kdb_event_should_be_up = 1; return NOTIFY_IGNORED; } } else if (event_is_up(event)) { /* we see other F-keys when they go down */ return NOTIFY_IGNORED; } ttysw_input(ttysw, last_event_string, strlen(last_event_string)); } return NOTIFY_IGNORED; } if (ISO_FIRST <= id && id <= ISO_LAST) { /* * Force bit 8 if meta key is down. But it will only be * noticed by the controlled process if it does a stty * -istrip, or equivalent. */ if (event_shiftmask(event) & META_SHIFT_MASK) event->ie_code |= META_KEY_MASK; } /* If we get here, pass event off to next handler */ return notify_next_event_func(window, (Notify_event) event, arg, type); } private Notify_value tty_event_filter_function(window, event, arg, type) Xv_Window window; Event *event; Notify_arg arg; Notify_event_type type; { if (console != NULL) fprintf(console, "Ttysw Event: %d\n", event_id(event)); if (event_id(event) == KBD_USE) { win_set_kbd_focus(ttyview, xv_get(ttyview, XV_XID)); return NOTIFY_IGNORED; } else { return notify_next_event_func(window, (Notify_event) event, arg, type); } } void bind_key(ksym, string) KeySym ksym; char *string; { Display *dpy; static KeySym shift_list[] = {XK_Shift_L, XK_Control_L, XK_Meta_L, XK_Alt_L, XK_Mode_switch}; int i; dpy = (Display *) xv_get(frame, XV_DISPLAY); XRebindKeysym(dpy, ksym, NULL, 0, (unsigned char *) string, strlen(string)); for (i = 0; i != sizeof(shift_list) / sizeof(*shift_list); i++) XRebindKeysym(dpy, ksym, &shift_list[i], 1, (unsigned char *) string, strlen(string)); } void bind_function_keys(first, count, number) KeySym first; unsigned int count, number; { int i; char buffer[6]; for (i = 0; i < count; i++) { sprintf(buffer, "%s%3dz", key_prefix, number + i); bind_key(first + i, buffer); } } int main(argc, argv) int argc; char **argv; { int error_code; /* Error codes */ int forking; int argstart = 1; char *debug; int child_argc, i; char **child_argv; char *icon_label; int tty_fd; struct termios tty; xv_init(XV_INIT_ARGC_PTR_ARGV, &argc, argv, 0); if ((debug = getenv("DEBUGJOVETOOL")) != NULL) { /* * DEBUGJOVETOOL specifies the file or device to receive * debugging output, if any. The null name signifies stderr. */ console = *debug == '\0' ? stderr : fopen(debug, "w"); forking = 0; } else if (!isatty(0)) { forking = 0; } else { forking = defaults_get_boolean("xjove.forking", "Xjove.Forking", 0); } if (argc>1 && !strcmp("-nf", argv[1])) { forking = 0; argstart = 2; } else if (argc>1 && !strcmp("-f", argv[1])) { forking = 1; argstart = 2; } if (forking) { switch (fork()) { case -1: fprintf(stderr, "fork failed"); exit(1); /* NOTREACHED */ case 0: /* the child */ #ifdef SYSVR4 setsid(); /* so it doesn't get killed when * parent dies */ #else setpgid(0, 0); /* For some reason, setsid() hinders * passing of SIGWINCH events to the * controlled process in SUNOS4 */ #endif break; default: /* the parent */ exit(0); /* NOTREACHED */ } } putenv("IN_JOVETOOL=t");/* notify subprocess that it is in jovetool */ font = (Xv_font) xv_find(ttysw, FONT, FONT_NAME, defaults_get_string("xjove.font.name", "Xjove.Font.Name", "lucidasanstypewriter-12"), 0); child_argv = (char **) malloc((argc + 1) * sizeof(char *)); if (!(child_argv[0] = (char *) getenv("JOVETOOL"))) /* Set jove command name */ child_argv[0] = jove_name; for (child_argc = 1, i = argstart; i < argc; i++) { if (!strcmp("-rc", argv[i])) { child_argv[0] = argv[++i]; child_argc = 1; } else { child_argv[child_argc++] = argv[i]; } } child_argv[child_argc] = NULL; /* * choose a "sensible" parameter to put in the icon label, preferably * the file to be edited */ icon_label = child_argv[0]; for (i = 1; i < child_argc; i++) if (child_argv[i][0] != '-') icon_label = child_argv[i]; frame_icon = icon_create(XV_LABEL, icon_label, ICON_IMAGE, &icon_image, 0); /* construct the title of the window */ strcpy(buffer, title); strncat(buffer, child_argv[0], /* append run command name */ (BUFFER_SIZE - (strlen(buffer)) - (strlen(argv[0]))) - 1); /* Build a frame to run in */ frame = xv_create(XV_NULL, FRAME, XV_LABEL, buffer, FRAME_ICON, frame_icon, 0); /* construct the command parameters to be shown to Save Workspace */ buffer[0] = '\0'; for (i = 1; i < argc; i++) sprintf(&buffer[strlen(buffer)], "%s ", argv[i]); xv_set(frame, WIN_CMD_LINE, buffer, 0); /* Create a tty with jove in it */ ttysw = xv_create(frame, TERMSW, TTY_ARGV, TTY_ARGV_DO_NOT_FORK, XV_LEFT_MARGIN, defaults_get_integer( "text.margin.left", "Text.Margin.Left", 4), XV_RIGHT_MARGIN, defaults_get_integer( "text.margin.right", "Text.Margin.Right", 0), /* 0 because jove never uses the last column anyway */ TEXTSW_FONT, font, 0); ttyview = xv_get(ttysw, OPENWIN_NTH_VIEW, 0); left_margin = xv_get(ttysw, XV_LEFT_MARGIN); right_margin = xv_get(ttysw, XV_RIGHT_MARGIN); font_height = (int) xv_get(ttysw, WIN_ROW_HEIGHT); font_width = (int) xv_get(ttysw, WIN_COLUMN_WIDTH); tty_fd = (int) xv_get(ttysw, TTY_TTY_FD); tcgetattr(tty_fd, &tty); tty.c_iflag &= ~ISTRIP; tcsetattr(tty_fd, TCSANOW, &tty); /* "TTY_ARGV, child_argv" must not be set going before that tcsetattr */ xv_set(ttysw, TERMSW_MODE, TTYSW_MODE_TYPE, TTY_QUIT_ON_CHILD_DEATH, TRUE, TTY_ARGV, child_argv, OPENWIN_ADJUST_FOR_VERTICAL_SCROLLBAR, 0, XV_WIDTH, defaults_get_integer( "window.columns", "Window.Columns", 80) * font_width + left_margin + right_margin + 2, /* * WIN_COLUMNS was not used here because it gets confused by the * non-existent scrollbar; the '+ 2' is one pixel for each border */ WIN_ROWS, defaults_get_integer( "window.rows", "Window.Rows", 35), 0); xv_set(ttyview, WIN_CONSUME_EVENTS, WIN_ASCII_EVENTS, WIN_META_EVENTS, WIN_MOUSE_BUTTONS, WIN_UP_EVENTS, LOC_DRAG, SHIFT_LEFT, SHIFT_RIGHT, SHIFT_CTRL, SHIFT_META, WIN_LEFT_KEYS, WIN_TOP_KEYS, WIN_RIGHT_KEYS, 0, WIN_COLLAPSE_EXPOSURES, FALSE, 0); default_cursor = xv_get(ttyview, WIN_CURSOR); jove_cursor = xv_create(XV_NULL, CURSOR, CURSOR_IMAGE, &cursor_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); cut_cursor = xv_create(XV_NULL, CURSOR, CURSOR_IMAGE, &cut_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); copy_cursor = xv_create(XV_NULL, CURSOR, CURSOR_IMAGE, ©_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); paste_cursor = xv_create(XV_NULL, CURSOR, CURSOR_IMAGE, &paste_pix, CURSOR_XHOT, 8, CURSOR_YHOT, 8, 0); set_cursor(jove_cursor); /* Interpose my event function */ error_code = (int) notify_interpose_event_func (ttyview, input_event_filter_function, NOTIFY_SAFE) + (int) notify_interpose_event_func (ttysw, tty_event_filter_function, NOTIFY_SAFE); if (error_code != 0) { /* Barf */ fprintf(stderr, "notify_interpose_event_func got %d.\n", error_code); exit(1); } menu_init(); bind_function_keys((KeySym)XK_L1, 10, 192); bind_function_keys((KeySym)XK_Help, 1, 202); bind_function_keys((KeySym)XK_F1, 10, 224); #ifdef SunXK_F36 bind_function_keys((KeySym)SunXK_F36, 2, 234); /* for Suns only */ #endif bind_function_keys((KeySym)XK_R1, 15, 208); /* * But note that the keys R7-R15 are intercepted by XView which * imposes its own bindings */ bind_function_keys((KeySym)XK_Insert, 1, 247); bind_function_keys((KeySym)XK_KP_0, 1, 247); bind_function_keys((KeySym)XK_KP_Decimal, 1, 249); bind_function_keys((KeySym)XK_KP_Enter, 1, 250); bind_function_keys((KeySym)XK_KP_Add, 1, 253); bind_function_keys((KeySym)XK_KP_Subtract, 1, 254); window_fit(frame); window_main_loop(frame);/* And away we go */ return 0; /* if this is ever reached */ } jove-4.17.5.5/xjove/xjovewindows.c000066400000000000000000000113421501102521500167540ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ #include #include #include #include /* is this missing on some systems? */ #include #include "exts.h" #include "xjovewindows.h" private char command_prefix[] = "\033X"; /* ESC-X */ #define command_prefix_length (sizeof(command_prefix) - 1) Menu main_menu; private Menu file_menu, mode_menu, help_menu, move_menu, bind_menu, macro_menu, buffer_menu, window_menu, mark_menu, edit_menu, directory_menu, compile_menu, format_menu, search_menu, process_menu, abbrev_menu, misc_menu, print_variables_menu, set_variables_menu, variables_menu, another_help_menu, commands_menu, var_files_menu, var_modes_menu, var_move_menu, var_search_menu, var_process_menu, var_compile_menu, var_format_menu, var_misc_menu, var_abbrev_menu, empty_menu, on_off_menu; private Menu_item empty_menu_item; private int describing, printing, climbing, falling; private void do_ancestor(m, mi) Menu m; Menu_item mi; { Menu parent_menu; Menu_item parent_item; caddr_t (*proc)(); parent_item = xv_get(m, MENU_PARENT); if (parent_item != XV_NULL) { parent_menu = xv_get(parent_item, MENU_PARENT); proc = (caddr_t (*)())xv_get(parent_item, MENU_NOTIFY_PROC); if (proc == NULL) proc = (caddr_t (*)())xv_get(parent_menu, MENU_NOTIFY_PROC); if (proc == NULL) do_ancestor(parent_menu, parent_item); else (*proc)(parent_menu, parent_item); } } private void do_notify(m, mi, p) Menu m; Menu_item mi; void (*p)(); { Menu pull; Menu_item deft; caddr_t (*proc)(); int local_climbing, local_falling; if (!(local_climbing = climbing)) ttysw_input (ttysw, command_prefix, command_prefix_length); climbing = 1; if (!(local_falling = falling)) do_ancestor(m, mi); (*p)(m, mi); if (!local_climbing && (pull = xv_get(mi, MENU_PULLRIGHT)) != XV_NULL) { falling = 1; deft = xv_get(pull, MENU_DEFAULT_ITEM); proc = (caddr_t (*)())xv_get(deft, MENU_NOTIFY_PROC); if (proc == NULL) proc = (caddr_t (*)())xv_get(pull, MENU_NOTIFY_PROC); (*proc)(pull, deft); falling = local_falling; } climbing = local_climbing; if (!climbing) ttysw_input (ttysw, "\n", 1); } void do_print_client_data(m, mi) Menu m; Menu_item mi; { char *menu_string; menu_string = (char *)xv_get(mi, MENU_CLIENT_DATA); ttysw_input(ttysw, menu_string, strlen(menu_string)); } private void print_client_data(m, mi) Menu m; Menu_item mi; { do_notify(m, mi, do_print_client_data); } private void main_notify(m, mi) Menu m; Menu_item mi; { char *menu_string; print_client_data(m, mi); } void do_sp_printit(m, mi) Menu m; Menu_item mi; { char *menu_string; menu_string = (char *)xv_get(mi, MENU_CLIENT_DATA); if (mi != empty_menu_item) ttysw_input(ttysw, " ", 1); ttysw_input(ttysw, menu_string, strlen(menu_string)); } private void sp_printit(m, mi) Menu m; Menu_item mi; { do_notify(m, mi, do_sp_printit); } private Menu_item commands_proc(item, operation) Menu_item item; Menu_generate operation; { return commands_menu; } private Menu_item on_off_proc(item, operation) Menu_item item; Menu_generate operation; { switch (operation) { case MENU_DISPLAY: if (!describing & !printing) { xv_set(item, MENU_PULLRIGHT, on_off_menu, 0); } else { xv_set(item, MENU_PULLRIGHT, XV_NULL, 0); } break; case MENU_DISPLAY_DONE: case MENU_NOTIFY: case MENU_NOTIFY_DONE: break; } return item; } private Menu do_set_proc(mi, operation, menu) Menu_item mi; Menu_generate operation; Menu menu; { if (!describing) { switch (operation) { case MENU_DISPLAY: if (!strcmp((char *)xv_get(mi, MENU_CLIENT_DATA), "print")) printing = 1; return menu; case MENU_DISPLAY_DONE: printing = 0; /*FALLTHROUGH*/ case MENU_NOTIFY: case MENU_NOTIFY_DONE: return empty_menu; } return empty_menu; /* ??? what should this function return */ } else return empty_menu; } private Menu do_describing_proc(m, operation) Menu m; Menu_generate operation; { switch (operation) { case MENU_DISPLAY: describing = 1; break; case MENU_DISPLAY_DONE: describing = 0; break; case MENU_NOTIFY: case MENU_NOTIFY_DONE: break; } return m; } #define X #include "jovemenu.c" jove-4.17.5.5/xjove/xjovewindows.h000066400000000000000000000031031501102521500167550ustar00rootroot00000000000000/*************************************************************************** * This program is Copyright (C) 1991-1999 by C.H.Lindsey, University of * * Manchester. (X)JOVETOOL is provided to you without charge, and with no * * warranty. You may copy, modify, and/or distribute (X)JOVETOOL, * * provided that this notice is included in all the files, except insofar * * as a more specific copyright notices attaches to the file (x)jovetool.c * ***************************************************************************/ #include "tune.h" #define FUNCTION(key_string, string) MENU_ITEM, MENU_STRING, key_string, \ MENU_CLIENT_DATA, string, 0, #define GROUP(menu) menu = menu_create( \ MENU_NOTIFY_PROC, print_client_data, #define GROUPNAME(menu, name) MENU_ITEM, MENU_STRING, name, \ MENU_CLIENT_DATA, "", \ MENU_PULLRIGHT, menu, 0, #define FUNCPULL(key_string, string, menu) \ MENU_ITEM, MENU_STRING, key_string, \ MENU_CLIENT_DATA, string, \ MENU_PULLRIGHT, menu, 0, #define FUNCPULLPROC(key_string, string, menu_proc) \ MENU_ITEM, MENU_STRING, key_string, \ MENU_CLIENT_DATA, string, \ MENU_GEN_PULLRIGHT, menu_proc, 0, #define VARIABLE(string) FUNCTION(string, string) #define VARIBOOL(string) MENU_ITEM, MENU_STRING, string, \ MENU_CLIENT_DATA, string, \ MENU_GEN_PROC, on_off_proc, 0, #define VARGROUP(menu) menu = menu_create( \ MENU_NOTIFY_PROC, sp_printit, #define VARPROC(proc, menu) Menu_item \ proc(item, operation) \ Menu_item item; \ Menu_generate operation; \ { return do_set_proc(item, operation, menu); }