diff --git a/BUGS b/BUGS index b2b7722..237bfe9 100644 --- a/BUGS +++ b/BUGS @@ -11,7 +11,69 @@ NOTE: Not all of these are truly bugs. This file also serves as my "to do" list, so some items are just unimplemented features that sounded like a good idea at one time or another. -* There appears to be a bug in scanning -- a scanned block is not necessarily +----------------------------------------------------------------------------- +Fixed (or not) in version 2.1_4: + +* Nested font changes don't always work correctly. For example, + "FOO! bar?" displays "bar?" in the + strong font. "Foo!" works though. + +/ The built-in calculator's shell() function gives an ugly error message + if the safer option is set. It fails correctly; it simply looks ugly. + +/ POSIX says that ^F/^B should leave two lines overlapping, not just one + +/ POSIX says that $ should accept a count, and move forward (count-1) lines. + +/ Executing ":do source somefile", where somefile contains an inner :while + loop, messes up the condition for the outer loop. + +? The text-mode version of elvis sometimes has problems drawing characters + near the left edge of the window. Apparently it gets confused about where + the cursor is located. + + I've seen this on some occasions, but I not recently. I've never + been able to reproduce it reliably. Perhaps it was a side-effect + of some other bug? + +/ Under MS-DOS with TERM=nansi (and NANSI.SYS installed, of course) the screen + is shifted up one line. TERM=ansi works, but doesn't use nansi efficiently. + +/ For gui="x11", if a window scrolls while some other window has pointer + focus, then the cursor isn't drawn. This is important when, e.g., you + use a dialog to search for text. + +/ When the same buffer is shown in two windows, inserting text into one + window can cause the other to scroll. This seems to occur only when + the location of the change is above the top line of the other window. + + Apparently what's happening is this: In a series of blank lines, + (i.e., lines which contain only a newline character), after any + character is inserted before line n, line n-1 has the same offset + than line n used to have, so the window update functions assume + that line n-1 is really still line n, so it shows line n-1 at the + top of the window instead of line n. + + Probably the win->di->topline variable, which is currently a long + which stores an offset, should be replaced with a MARK. Since + MARKs are updated when a buffer changes, this should fix it. + +* Given a URL such as "../untar.c", referenced from "/pub/elvis/unreleased", + elvis 2.1_3 tries to fetch "/pub/elvis/unreleased/../untar.c", but it *MUST* + be normalized as "/pub/elvis/untar.c" -- i.e., delete instances of "dir/../". + Some web servers depend on this. + +? In "html" mode, if a single displayed line contains more than one link, + elvis always seems to follow the *last* link regardless of which one you + click on. This is bad for some menu bars. + + Actually, this only seems to occur when multiple images appear + on a line, and you want to download one of the images. For + real links, elvis works correctly. + + I took a stab at fixing this one. It seems better now. + +? There appears to be a bug in scanning -- a scanned block is not necessarily being locked for the whole time that it should be, which means that it may be removed from the block cache, in which case NULL may be returned by some of the blkXXXX() functions. Also, on at least one occasion elvis appeared @@ -21,15 +83,60 @@ idea at one time or another. recent attempts to make searches run faster by keeping at least one scan context for the current location at all times. -/ One user reported crashes in WinElvis when the "Options->syntax" menu item - is activated while in "syntax" display mode. + The FEATURE_LITRE bug is fixed; hopefully that fixes this too. + +* There are still problems with running external programs under Win32. + The :make command doesn't work. Also, the screen is sometimes messed up + after running a program. + + I switched back to the older, more complex version of oswin32/osprg.c. + The only problem it has is that sometimes 16-bit filter programs don't + work correctly... but I just tested it again and that seems to work + now. Anyway, 16-bit filters are less important than :make, so I'm + keeping the older version. + +/ When viewing an HTML document at a URL such as "http://foo/bar.html?boo/far", + containing a link to "zot.html", elvis will resolve that link to be to + "http://foo/bar.html?boo/zot.html", but it should be "http://foo/zot.html". + + Similarly, I suspect that fileext() fails on URLs like that. -* One user reported that elvis was sensitive to keystrokes during quitting. +/ Hitting ^] on an operator doesn't search for an "operatorXX" tag? I + thought it did. + + It appears to work now. I don't know why it didn't work before. + +/ The alias.c program (which is compiled as vi.exe, ex.exe, and view.exe) + has been reported to cause problems under WindowsNT, and more recently + under Windows98 as well. + + It appears that a Microsoft has introduced a bug into their versions + of the "exec" system calls. I switched to "spawn", which waits a + little RAM but seems to work correctly. + +/ Under Windows95/98/NT, the "Terminal" font has funny spacing and sometimes + characters overlap each other. + + This is a bug in the font, not in elvis. Elvis only supports + fixed-pitch fonts, and although "Terminal" claims to be fixed-pitch, + it is really a variable-pitch font. + +/ Control chars in an alias aren't displayed in a printable form by the + :alias command. ":alias clean s/.^H//g" looks like "alias clean s///g". + +/ Add VIM's "smarttab" option -- keys at the beginning of a line act + like ^T, so they indent by the shiftwidth amount using a combination of + tabs and spaces. keys elsewhere in a line are real tabs. + +/ One user reported that elvis was sensitive to keystrokes during quitting. I suspect that gui->poll was being called while the file was being written (possibly just when written via FTP). That write should not be quittable. -* Under MS-DOS with TERM=nansi (and NANSI.SYS installed, of course) the screen - is shifted up one line. TERM=ansi works, but doesn't use nansi efficiently. +------------------------------------------------------------------------------ +Fixed in 2.1_3 + +/ One user reported crashes in WinElvis when the "Options->syntax" menu item + is activated while in "syntax" display mode. / Can't identify tags whose whose contains a new-style comment. Apparently the tag-selector can't parse \/\/ in an regular expression. @@ -318,58 +425,9 @@ Fixed in 2.1j-beta.... / Make elvis.arf strip off the perl version number from #!/usr/bin/perl-XXXX lines. This makes syntax easier to recognize. ------------- -* Under X11, the XV button doesn't work. It reports that the temporary - file is empty. - - The XV button does ":w !xv - >/dev/null 2>&1 &". The "x11" user - interface runs xv as a filter, so it can show the program's output - in the elvis window. Since xv doesn't output anything useful, I - tried to avoid that by running it in the background. However, - since pipes can fill up, elvis uses a temporary file for the filter's - stdin, and a pipe to read its stdout. Running a program in the - background like this causes elvis to read EOF from the filter's - stdout immediately, so elvis immediately clobbers the temp file. - The filter (xv) sees no data on its stdin. (Actually this is a - little surprising since elvis doesn't truncate the file; it deletes - it. A deleted file is *supposed* to remain allocated until the - last file descriptor on it is closed.) - - The short-term fix is to avoid running filters in the background. - - The long-term fix is to make the "x11" interface smarter about - running programs in the background, so it can use a pipe for stdin; - This would also allow the removal of ">/dev/null 2>&1". - * If xcurses exists, it should probably be used in preference to curses. (This would be a change to the "configure" script.) -* In "html" mode, if a single displayed line contains more than one link, - elvis always seems to follow the *last* link regardless of which one you - click on. This is bad for some menu bars. - - Actually, this only seems to occur when multiple images appear - on a line, and you want to download one of the images. For - real links, elvis works correctly. This bug can wait until - after 2.1 is done. - -* For gui="x11", if a window scrolls while some other window has pointer - focus, then the cursor isn't drawn. This is important when, e.g., you - use a dialog to search for text. - -* When the same buffer is shown in two windows, inserting text into one - window can cause the other to scroll. This seems to occur only when - the location of the change is above the top line of the other window. - - Apparently what's happening is this: In a series of blank lines, - (i.e., lines which contain only a newline character), after any - character is inserted before line n, line n-1 has the same offset - than line n used to have, so the window update functions assume - that line n-1 is really still line n, so it shows line n-1 at the - top of the window instead of line n. - -* Hitting ^] on an operator doesn't search for an "operatorXX" tag? I - thought it did. - ? Elvis gets confused if you load a URL which has no filename component, such as "http://www.yahoo.com". Adding a trailing slash avoids that. @@ -680,7 +738,7 @@ Fixed in 2.1j-beta.... > like deducing them. What do you want to be done? Apparently elvis needs to inspect the session's low-level buffers more - carefully before I restore them. In your session file, there is a + carefully before restoring them. In your session file, there is a low-level buffer (at block 52) which contains a reference to a bogus block number, and that's preventing you from restarting elvis to recover the other buffers in that session file. @@ -760,7 +818,7 @@ Fixed in 2.1j-beta.... In addition, a potential bug in the termcap interface was fixed. -* Some crashes/hangs have been reported under Linux. These may have something +? Some crashes/hangs have been reported under Linux. These may have something to do with and commands. Usually there are no clues, but at least twice the buffer filled with ^@ characters. Reported by Steve Woodard, woodard@kodakr.kodak.com @@ -872,9 +930,6 @@ Fixed in 2.1j-beta.... * In the installation routine, create links named "vi", "ex", and "view". Similarly, supply .BAT files or something for Win32. -* Some problems have been reported while trying to recover files. Either - there's a bug, or I need to improve the documentation. - * Ctags doesn't produce "Mfilename" tags for main() functions in filename.c * Sometimes text changes as you move the cursor over it in HTML mode. This diff --git a/COPYING b/COPYING index e6998a5..3434a88 100644 --- a/COPYING +++ b/COPYING @@ -1,4 +1,4 @@ -Elvis 2.1 Copyright 1996 by Steve Kirkendall +Elvis 2.1 Copyright 1999 by Steve Kirkendall Elvis 2.1 is copyrighted freeware. It is provided in the hope that it will be useful, but with no warranty. diff --git a/INSTALL b/INSTALL index 2d5ee04..0612595 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -HOW TO COMPILE & INSTALL ELVIS 2.1 +HOW TO COMPILE & INSTALL ELVIS 2.1_4 Separate sets of instructions are provided below for UNIX, Windows-NT, MS-DOS, and OS/2. @@ -10,13 +10,24 @@ development environment if you prefer. Separate instructions are given for both compilation methods, for both operating systems. All of these instructions assume that you have already unpacked the files -from the source code archive, "elvis-2.1.tar.gz". That's a gzipped tar +from the source code archive, "elvis-2.1_4.tar.gz". That's a gzipped tar archive. If you don't have the gzip and tar utilities, then the easiest way for you to unpack them is to compile the "untar.c" program (available via anonymous FTP from ftp://ftp.cs.pdx.edu/pub/elvis/untar.c). The files -will be placed in a subdirectory named "elvis-2.1". The MS-DOS *.MAK files +will be placed in a subdirectory named "elvis-2.1_4". The MS-DOS *.MAK files assume that you've unpacked them while in C:\MSVC, so the files themselves -should end up in C:\MSVC\elvis-2.1. +should end up in C:\MSVC\elvis-2.1_4. + +Under MS-DOS, the name of the archive will be mangled. It will probably +be "elvis-~1.gz", but it may be something else; the exact name depends on +how you downloaded it, and whether you already had an old version of that +archive in the same directory. The MS-DOS version of the "untar" program +needs to be passed the mangled name, whatever that turns out to be. The +Win32 version, on the other hand, can handle the full "elvis-2.1_4.tar.gz" +file name. + +Also under MS-DOS, you may see complaints about some OS/2 files. You can +ignore that; you don't need those files to compile elvis for MS-DOS. ================================================================================ @@ -126,17 +137,7 @@ UNIX ================================================================================ -NOTE FOR WINDOWS/NT: The "vi.exe", "ex.exe", and "view.exe" programs have been -reported to cause problems under NT. If they don't work on your system, then -I suggest you replace them with the equivalent batch files. Each batch file -would be just one line long: - - vi.bat: elvis %1 %2 %3 %4 %4 %5 %6 %7 %8 %9 - ex.bat: elvis -e %1 %2 %3 %4 %4 %5 %6 %7 %8 %9 - view.bat: elvis -R %1 %2 %3 %4 %4 %5 %6 %7 %8 %9 - - -MS-Windows/NT (or Windows95?), with Visual C++ 2.0 (Method #1): +MS-Windows/NT (or Windows95?), with Visual C++ 2.0 or later (Method #1): 1) Run the "makwin32.bat" file. makwin32 @@ -153,7 +154,7 @@ MS-Windows/NT (or Windows95?), with Visual C++ 2.0 (Method #1): copy lib\*.* \localbin\lib -MS-Windows/NT (or Windows95?), with Visual C++ 2.0 (Method #2): +MS-Windows/NT (or Windows95?), with Visual C++ 2.0 or later (Method #2): 1) Copy all of the "*.mak" files from files from the oswin32 subdirectory. copy oswin32\*.mak @@ -191,11 +192,11 @@ MS-Windows/NT (or Windows95?), with Visual C++ 2.0 (Method #2): MS-DOS, using Visual C++ 1.5 (Method #1): REMINDER: MSVC++ 1.5 always puts the complete pathnames of all files into its NMAKE files. Because of this, you *MUST* install the - source code into a directory named "C:\MSVC\elvis-2.1". The - "elvis-2.1" component of that directory name is stored in the - "elvis-2.1.tar.gz" archive file, so you should be in the C:\MSVC + source code into a directory named "C:\MSVC\elvis-2.1_4". The + "elvis-2.1_4" component of that directory name is stored in the + "elvis-2.1_4.tar.gz" archive file, so you should be in the C:\MSVC directory when you extract the files. After extracting the files, - do a "cd elvis-2.1" + do a "cd elvis-2.1_4" 1) Run the "makmsdos.bat" file @@ -215,19 +216,19 @@ MS-DOS, using Visual C++ 1.5 (Method #1): MS-DOS, using Visual C++ 1.5 (Method #2): REMINDER: MSVC++ 1.5 always puts the complete pathnames of all files into its NMAKE files. Because of this, you *MUST* install the - source code into a directory named "C:\MSVC\elvis-2.1". The - "elvis-2.1" component of that directory name is stored in the - "elvis-2.1.tar.gz" archive file, so you should be in the C:\MSVC + source code into a directory named "C:\MSVC\elvis-2.1_4". The + "elvis-2.1_4" component of that directory name is stored in the + "elvis-2.1_4.tar.gz" archive file, so you should be in the C:\MSVC directory when you extract the files. - 1) Copy all of the "C:\MSVC\elvis-2.1\OSMSDOS\*.MAK" files into the - "C:\MSVC\elvis-2.1" directory. + 1) Copy all of the "C:\MSVC\elvis-2.1_4\OSMSDOS\*.MAK" files into the + "C:\MSVC\elvis-2.1_4" directory. c: - cd \msvc\elvis-2.1 + cd \msvc\elvis-2.1_4 copy osmsdos\*.mak - 2) Copy the "\MSVC\elvis-2.1\OSMSDOS\OSCONFIG.H" file to + 2) Copy the "\MSVC\elvis-2.1_4\OSMSDOS\OSCONFIG.H" file to "\MSVC\elvis-2.1\CONFIG.H" Note that the "OS" is dropped from the filename. diff --git a/Makefile.in b/Makefile.in index ecd6cac..7b1e395 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1,5 +1,5 @@ # Makefile.in -# $Id: Makefile.in,v 2.62 1999/06/19 01:06:23 steve Exp $ +# $Id: Makefile.in,v 2.65 1999/10/20 18:30:01 steve Exp $ # # Makefile.in should not be modified! The "configure" script reads Makefile.in # and writes a customized Makefile by editing the values of the following @@ -150,8 +150,8 @@ CFLAGS= $(FLAGI)os$(OS) EVERY= $(ALL) verify$(EXE) elvdump$(EXE) calc$(EXE) SHELL= /bin/sh -DISTRIB=elvis-2.1_3 -DOSEXE=exedos +DISTRIB=elvis-2.1_4 +MSDOSEXE=exemsdos WIN32EXE=exewin32 OS2EXE=exeos2 @@ -249,6 +249,9 @@ clean.unix: $(RM) verify.elv $(RM) $(DISTRIB).tar.gz $(RM) lib/elvtags.man + $(RM) $(MSDOSEXE)/* + $(RM) $(WIN32EXE)/* + $(RM) $(OS2EXE)/* clean.msdos: $(RM) *$(OBJ) @@ -294,6 +297,9 @@ $(DISTRIB).tar.gz: cp lib/* $(DISTRIB)/lib for i in os*/*.c os*/*.h os*/*.mak os*/*.lib os*/*.ICO osos2/*.def osos2/*os2*; do cp $$i $(DISTRIB)/$$i; done for i in gui*/*; do if [ -f $$i ]; then cp $$i $(DISTRIB)/$$i; fi; done + mkdir $(DISTRIB)/osos2/manual + mkdir $(DISTRIB)/osos2/manual/org + cp osos2/manual/*.ed osos2/manual/*.cmd $(DISTRIB)/osos2/manual/ rm -f $(DISTRIB)/osunix/osconfig.h rm -f $(DISTRIB)/config.h rm -f $(DISTRIB)/Makefile @@ -302,6 +308,7 @@ $(DISTRIB).tar.gz: rm -rf $(DISTRIB) $(DISTRIB)-win32.tar.gz: $(WIN32EXE) + @[ -f $(WIN32EXE)/elvis.exe ] || (echo "You need to copy the *.exe files into $(WIN32EXE)"; exit 2) rm -rf bin-win32 mkdir bin-win32 cp $(WIN32EXE)/*.exe bin-win32 @@ -313,11 +320,13 @@ $(DISTRIB)-win32.tar.gz: $(WIN32EXE) sed 's/$$/ /' bin-win32/lib/printdoc.bat sed 's/$$/ /' bin-win32/lib/license (cd bin-win32; tar czf ../$(DISTRIB)-win32.tar.gz *) + rm -rf bin-win32 -$(DISTRIB)-msdos.tar.gz: $(DOSEXE) +$(DISTRIB)-msdos.tar.gz: $(MSDOSEXE) + @[ -f $(MSDOSEXE)/elvis.exe ] || (echo "You need to copy the *.exe files into $(MSDOSEXE)"; exit 2) rm -rf bin-msdos mkdir bin-msdos - cp $(DOSEXE)/*.exe bin-msdos + cp $(MSDOSEXE)/*.exe bin-msdos sed 's/$$/ /' bin-msdos/README.html sed 's/$$/ /' bin-msdos/BUGS sed 's/$$/ /' bin-msdos/COPYING @@ -326,8 +335,10 @@ $(DISTRIB)-msdos.tar.gz: $(DOSEXE) sed 's/$$/ /' bin-msdos/lib/printdoc.bat sed 's/$$/ /' bin-msdos/lib/license (cd bin-msdos; tar czf ../$(DISTRIB)-msdos.tar.gz *) + rm -rf bin-msdos $(DISTRIB)-os2.tar.gz: $(OS2EXE) + @[ -f $(OS2EXE)/elvis.exe ] || (echo "You need to copy the *.exe files into $(OS2EXE)"; exit 2) rm -rf bin-os2 mkdir bin-os2 cp $(OS2EXE)/*.exe bin-os2 @@ -343,6 +354,7 @@ $(DISTRIB)-os2.tar.gz: $(OS2EXE) mkdir bin-os2/osos2 cp osos2/README.os2 bin-os2/osos2/ (cd bin-os2; tar czf ../$(DISTRIB)-os2.tar.gz *) + rm -rf bin-os2 lib$(SLASH)elvistrs.msg: $(SRCS) sed -n '/%[cds]/d; s/\[[a-zA-Z]*\]//; s/\\\\/\\/g; s/.*msg(MSG_[A-Z]*, "\([^ "][^"]*\)".*/\1/p' *.c os*$(SLASH)*.c gui*$(SLASH)*.c | sort -u >lib$(SLASH)elvistrs.msg diff --git a/README.html b/README.html index 1cc63e5..c4e4187 100644 --- a/README.html +++ b/README.html @@ -19,18 +19,24 @@

Quick intro to elvis 2.1, with links to source code and binaries

  • 3.3 New functions
  • 3.4 New ports and GUI features
  • 3.5 Miscellany -
  • 3.6 Revisions since the original 2.1 release +
  • 3.6 Differences between 2.1_3 and the original 2.1 release +
  • 3.7 Differences between 2.1_4 and 2.1_3
  • 4. The future of elvis
  • 5. Links to related files +
    +.---------------------------------------------------------------.
    +| This is not elvis' user manual!  The real documentation for   |
    +| elvis is located in its online help facility.  While running  |
    +| elvis, enter the command ":help" to see the table of contents.|
    +^---------------------------------------------------------------^
     
    -

    1. About this file

    This file is written in the HTML markup language. You can view it with any WWW viewer, such as Netscape. -You can also use elvis 2.1i-beta to view it; this version of elvis +You can also use elvis 2.1 to view it; this version of elvis has the ability to view HTML documents, and print them.

    This file has many hypertext links. @@ -159,7 +165,7 @@

    3.1 New ex commands

    any pending macros or aliases are aborted.
     	:alias togglecase {
    -		try !% s/.*/\U&
    +		try !% s/.*[a-z].*/\U&
     		else !% s/.*/\L&
     	}
     
    @@ -176,6 +182,22 @@

    3.1 New ex commands

    }
    +
    :switch +
    :case +
    :default +
    This is a multi-way branch. +The :switch command evaluates an expression, and stores the +result in an internal variable. +Each :case command compares the switch value to a literal string; +if it matches then the remainder of the line is executed an an ex command. +If none of the cases match, then :default will run its ex command. +
    +	:switch os
    +	:case unix echo LF
    +	:case mac echo CR
    +	:default echo CR-LF
    +
    +

    3.2 Options

    @@ -315,8 +337,7 @@

    3.2 Options

    expression.
    tagprg, tp -
    tagprgonce, tpo -
    These allow you to use an external program to perform tag searches. +
    This allows you to use an external program to perform tag searches.
    blkhit, bh
    blkmiss, bm @@ -333,7 +354,7 @@

    3.2 Options

    These affect the way text is printed. Setting lpnumber causes line numbers to be printed, just as number causes line number to be shown on the screen. -For the "normal" or "syntax" display modes, lpheader +Setting the lpheader option causes pages to have a header showing the file name, page number, and date.
    previousdir, pdir @@ -341,6 +362,11 @@

    3.2 Options

    You can use "~-" (tilde minus) at the start of a file name as a shorthand for the previous directory name. +
    smarttab, sta +
    If set, this causes the <Tab> key to act like +^T when in the indentation area of a line. +Elsewhere in a line, <Tab> will act normally. +

    3.3 New functions

    @@ -391,6 +417,16 @@

    3.3 New functions

    alias(name)
    Test for the existence of a given alias. +
    shell(command) +
    Executes the command via a shell, and returns the text that +the program wrote to stdout. + +
    line(buffer, line) +
    Returns a single line from a buffer. +If buffer is omitted, then the current buffer is assumed. +If both buffer and line are omitted, then the current +line of the current buffer is returned. +

    3.4 New ports, and new GUI features

    @@ -428,7 +464,6 @@

    3.5 Miscellany

    and "~-" for the previous directory. Also, under Unix you can use "~user" for the home directory of user. -~name, ~+, ~-
    Network protocols
    Elvis can read via HTTP, and read or write via FTP. @@ -468,14 +503,9 @@

    3.5 Miscellany

    -

    3.6 Revisions since the first 2.1 release

    +

    3.6 Differences between 2.1_3 and the original 2.1 release

    -This version of elvis is 2.1_3 (pronounced "two point one patch-level 3"). -It may also be written as 2.1.3; however, the "2.1_3" notation was chosen for a reason: -the directory name "elvis-2.1_3" is a valid MS-DOS directory name, but -"elvis-2.1.3" is not. - -

    Many bugs and annoyances have been fixed since the first 2.1 release +Many bugs and annoyances have been fixed since the first 2.1 release a couple months ago. The highlights are:

    @@ -683,6 +713,191 @@

    3.6 Revisions since the first 2.1 release

    +

    3.7 Differences between 2.1_4 and 2.1_3

    + +This version of elvis is 2.1_4 (pronounced "two point one patch-level 4"). +It may also be written as 2.1.4; +however, the "2.1_4" notation was chosen for a reason: +the directory name "elvis-2.1_4" is a valid MS-DOS directory name, but +"elvis-2.1.4" is not. + +

    This is primarily a bug-fix update. +There are some big changes that I'd like to make to elvis, but +they'll all have to wait until version 2.2. +This bug-fix version is simply intended to make waiting for 2.2 a little +easier. + +

    Some of the main areas of bug fixes are: + +

    + +
    Buffer bugs +
    Several people reported that elvis complained about the '#' being used +in initialization scripts (even though '#' doesn't appear anywhere in those +scripts), or that sometimes a buffer would get scrambled. +These problems have now been fixed, thanks mostly to William Plant. +He tracked the problem down to the use of FEATURE_LITRE in scan.c. + +

    This was a significant bug! +The '#' thing was only one manifestation of a dangerous bug. +Other manifestations could mangle buffers, cause core dumps, etc. +This bug fix alone is probably enough to justify downloading 2.1_4. + +

    Cygwin support +
    The Win32 version of elvis 2.1_3 (or earlier) didn't work very well +under Cygwin's bash shell. +elvis 2.1_4 should fix that. Specifically... +
      +
    • Cygwin sets the TERM environment variable to "cygwin", +which elvis will now recognize as a synonym for "console". +
    • Elvis now supports the mount table produced by the Cygwin +mount utility. + +
      Windows98 chokes on vi.exe, etc. +
      An apparent bug in recent versions of Windows causes the +vi.exe, view.exe, and ex.exe programs +to run in the background. +(Those programs worked in Windows95, but choked in Windows98 and NT.) +To work around this, I replaced the execvp() call with a spawnvp() call +followed by an exit() call. +It'll waste a little RAM now, but at least it works. + +

      This bug also hit Cygwin's bash shell, when run under Windows98 +or NT. +I've tested 2.1_4 under bash, and it works now. + +

      Running external programs under Win32 +
      There were two bugs which, together, caused elvis to act weird after +running an external command such as ":!dir". +This was particularly acute in the text-mode version, but now both versions +seem to work as intended. + +
      Screen glitch in MS-DOS with NANSI.SYS +
      The screen wasn't always drawn correctly when using one of the better +ANSI drivers, and setting TERM=nansi (or whatever). +This was due to a bug in the nansi termcap entry in tinytcap.c; +it should be fixed now. + +
      Scrolling after :split +
      Previously there was a bug which showed up when you have two windows +open on the same buffer. +Inserting text in one window could cause the other window to scroll after +each keystroke. +This has been fixed. + +
      Name completion with spaces +
      There were some problems when attempting filename completion on +files whose names contain spaces. +The bug responsible for this has been fixed. + +
      Ctags/elvtags +
      Some bugs in the ctags/elvtags program have been fixed. +Mostly these only occured when you're using long lines. + +
      Display modes +
      The "tex" and "syntax" display modes should work a little better now. +I added some TeX markups, and enhanced the "syntax" display mode to handle +PERL slightly better. +Also, some users have contributed syntax descriptions for new languages. + +
      :make +
      The :make, :cc, and :errlist +commands were treating any alphanumeric word as a filename, without +checking to see if it even exists. +It was supposed to verify that the name was an existing, +readable/writable (or just readable if noanyerror), +non-binary file... and now it will. + +
      POSIX compatibility tweaks +
      The := command, when invoked without line number, should +display the total number of lines in the buffer. Previous versions of elvis +didn't do that correctly, but 2.1_3 did. +Unfortunately, that fix broke the :.= command, which is supposed +to display the current line number. +Version 2.1_4 should both of those right, finally. + +

      The ^F and ^B paging commands are supposed to leave +two lines of overlap, but previous versions of elvis have only kept one line +of overlap. +(NOTE: I considered adding an option to control the overlap, because if you +have a 24-line screen and 66-line pages, then then it would be nice to leave +1 line of overlap because three ^Fs or ^Bs would equal +one page. +If you believe an option would be useful, please let me know.) + +

      The $ command accepts a count argument, and moves +forward (count-1) lines before moving to the end. + +

    + +
    +

    The only new features (since 2.1_3) are... +

    + +
    :switch/:case/:default commands +
    Elvis now has a :switch command for doing a multi-way branch in a readable +way. +I believe this is justified, since the current :if/:then/:else commands would +require you to use deeper and deeper nested braces to achieve the same effect. +The old way: +
    +	if os=="unix"
    +	then echo Unix
    +	else {
    +	 if os=="win32"
    +	 then echo Windows95/98/NT/2000
    +	 else {
    +	  if os=="msdos"
    +	  then echo MS-DOS
    +	  else {
    +	   if os=="os2"
    +	   then echo OS/2
    +	   else echo Who?
    +	  }
    +	 }
    +	}
    +
    +The new way: +
    +	switch os
    +	case unix echo Unix
    +	case win32 echo Windows95/98/NT/2000
    +	case msdos echo MS-DOS
    +	case os2 echo OS/2
    +	default echo Who?
    +
    + +
    "html" printer type +
    Setting the lptype option to "html" causes the +:lpr command to write HTML output, instead of normal printer +control sequences. +This give a good way to generate WYSIWYG HTML code from any of elvis' +display modes. +It required minimal changes to the code, too -- basically, I just created +a new printer type that uses "<b>" to start bold font, "<i>" to +start italics, and so on, instead of some printer-dependent escape sequence. + +
    "makehtml" alias +
    There is a new :makehtml alias which attempts to convert plain text to HTML. +It works pretty well, though you'll still need to hand-edit the results in +many cases. You might want to compare the output of :makehtml to +that of the "html" lptype, to see which one fits your needs better. + +
    "smarttab" option +
    I added VIM's "smarttab" alias. +When set, this causes the <Tab> key to act like ^T +when pressed in the indentation area of a line. +Elsewhere in the line, <Tab> is treated normally. +Now you can do things like ":set smarttab shiftwidth=4" +to change your indentation levels while leaving the tabstop +option unchanged. + +

    The current implementation is a little half-assed though -- +you can't backspace over the indentation. +Instead, you must hit ^D to reduce the indentation level. + +

    +

    4. The future of elvis

    One of the biggest tasks on my list is to rewrite the ctags program @@ -715,6 +930,26 @@

    4. The future of elvis

    That way, you could create your own markups to display nroff -ms, RTF, SGML, and MIME "rich text" documents. +

    I'd like to redesign the way elvis assigns assigns buffer names. +I'd like to make it always use the full pathname of a file as the buffer name. +In addition, I'd like for elvis to store a "current working directory" for +each window, and use that to convert a relative buffer name into a the absolute +pathname. +A similar trick would be used for filenames. +When running an external program, elvis would change the real current +directory to that window's directory. +The benefits of all this: +

      +
    • If you're editing "foo" and "./foo", they'll both use the same buffer. +This sounds contrived, but a similar thing happens with tag files fairly often. +
    • If you do a :cd command, then the old buffers will still write out to +their old directories. +
    • Different windows could have different directories. +
    • The X-windows "-client" flag would behave in a more reasonable manner. +
    • The "current directory" could be something other than a local directory. +For example, there's no reason you shouldn't be able to ":cd ftp://ftp.sunsite.unc.edu/pub/incoming". +
    +

    5. Links to related files

    If the main site (ftp.cs.pdx.edu) is too slow, try the mirror site at @@ -755,29 +990,29 @@

    5. Links to related files

    So if you extract the files under Windows95, DOS programs won't be able to find them with their expected names, and vice versa. Consequently, you must use untardos.exe to unpack -elvis-2.1-msdos.tar.gz, and untarw32.exe to unpack -elvis-2.1-win32.tar.gz. +elvis-2.1_4-msdos.tar.gz, and untarw32.exe to unpack +elvis-2.1_4-win32.tar.gz.
    untaros2.exe
    This is an OS/2 executable, produced from the above "untar.c" file. For brief instructions on how to use untaros2, run it with no arguments. -
    elvis-2.1_3.tar.gz +
    elvis-2.1_4.tar.gz
    This is a gzipped tar archive of the source code and documentation for Elvis 2.1 and its related programs. -
    elvis-2.1_3-msdos.tar.gz +
    elvis-2.1_4-msdos.tar.gz
    This archive contains the documentation and MS-DOS executables for Elvis 2.1. -
    elvis-2.1_3-win32.tar.gz +
    elvis-2.1_4-win32.tar.gz
    This archive contains the documentation and Win32 executables for Elvis 2.1. These were compiled and tested under Windows95, but should work under WindowsNT 3.51 (or later) as well. -
    elvis-2.1_3-os2.tar.gz +
    elvis-2.1_4-os2.tar.gz
    This archive contains the documentation and OS/2 executables for Elvis 2.1. @@ -785,7 +1020,7 @@

    5. Links to related files

    ftp://ftp.fh-wedel.de/pub/fh-wedel/staff/herbert/elvis/00-index.html
    This is where the OS/2 maintainer stores his most up-to-date versions. -It may be better than the elvis-2.1-os2.tar.gz file, above. +It may be better than the elvis-2.1_4-os2.tar.gz file, above. diff --git a/alias.c b/alias.c index b191638..8a2f7d0 100644 --- a/alias.c +++ b/alias.c @@ -47,6 +47,18 @@ # define ARGV0 VI #endif +/* Win32 seems to have developed an inability to exec() correctly. The shell + * thinks the program has exited when in fact it has merely exec'ed some + * other function. This messes up the ex/vi/view aliases for elvis. To work + * around it, we SPAWN elvis and wait for it to return before the alias exits. + * This wastes a little memory, but at least it works. + */ +#if _MSC_VER >= 900 /* 32-bit compiler for Windows */ +# define execvp(p,a) (i = _spawnvp(_P_WAIT, p,a)); if (i >= 0) exit(i); +#endif + + + main(argc, argv) int argc; char *argv[]; diff --git a/buffer.c b/buffer.c index a62d351..1435d5e 100644 --- a/buffer.c +++ b/buffer.c @@ -1,7 +1,7 @@ /* buffer.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_buffer[] = "$Id: buffer.c,v 2.94 1999/06/15 04:21:43 steve Exp $"; +char id_buffer[] = "$Id: buffer.c,v 2.95 1999/10/08 18:03:03 steve Exp $"; #include "elvis.h" @@ -622,7 +622,7 @@ BUFFER bufload(bufname, filename, reload) MARKBUF top; MARKBUF end; BUFFER initbuf; /* buffer containing the initialization script */ - BOOLEAN oldthen; + EXCTLSTATE oldctlstate; int i; void *locals; @@ -684,14 +684,14 @@ BUFFER bufload(bufname, filename, reload) /* execute the script */ locals = optlocal(NULL); - oldthen = exthenflag; + exctlsave(oldctlstate); if (experform(windefault, marktmp(top, initbuf, 0), marktmp(end, initbuf, o_bufchars(initbuf))) != RESULT_COMPLETE) { - exthenflag = oldthen; + exctlrestore(oldctlstate); return buf; } - exthenflag = oldthen; + exctlrestore(oldctlstate); (void)optlocal(locals); } } @@ -765,10 +765,10 @@ BUFFER bufload(bufname, filename, reload) /* Execute the script's contents. */ locals = optlocal(NULL); - oldthen = exthenflag; + exctlsave(oldctlstate); (void)experform(windefault, marktmp(top, initbuf, 0), marktmp(end, initbuf, o_bufchars(initbuf))); - exthenflag = oldthen; + exctlrestore(oldctlstate); (void)optlocal(locals); } } @@ -1097,7 +1097,7 @@ BOOLEAN bufwrite(from, to, wfile, force) BOOLEAN filter; /* If True, we're writing to a filter */ BOOLEAN wholebuf; /* if True, we're writing the whole buffer */ BOOLEAN samefile; /* If True, we're writing the buffer to its original file */ - BOOLEAN oldthen; + EXCTLSTATE oldctlstate; int bytes; void *locals; @@ -1159,15 +1159,15 @@ BOOLEAN bufwrite(from, to, wfile, force) /* execute the script */ locals = optlocal(NULL); - oldthen = exthenflag; + exctlsave(oldctlstate); if (experform(windefault, marktmp(top, initbuf, 0), marktmp(next, initbuf, o_bufchars(initbuf))) != RESULT_COMPLETE && !force) { - exthenflag = oldthen; + exctlrestore(oldctlstate); return False; } - exthenflag = oldthen; + exctlrestore(oldctlstate); (void)optlocal(locals); } } @@ -1264,10 +1264,10 @@ BOOLEAN bufwrite(from, to, wfile, force) /* execute the script */ locals = optlocal(NULL); - oldthen = exthenflag; + exctlsave(oldctlstate); (void)experform(windefault, marktmp(top, initbuf, 0), marktmp(next, initbuf, o_bufchars(initbuf))); - exthenflag = oldthen; + exctlrestore(oldctlstate); (void)optlocal(locals); } } diff --git a/calc.c b/calc.c index 5fdbb0d..1018822 100644 --- a/calc.c +++ b/calc.c @@ -1,7 +1,7 @@ /* calc.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_calc[] = "$Id: calc.c,v 2.65 1999/04/08 22:09:25 steve Exp $"; +char id_calc[] = "$Id: calc.c,v 2.68 1999/10/12 22:43:30 steve Exp $"; #include "elvis.h" #include @@ -396,6 +396,14 @@ static BOOLEAN func(name, arg) } else if (!CHARcmp(name, toCHAR("dirext"))) { + /* if this is a URL, and it contains a '#' or '?' character, + * then truncate it there. + */ + if ((arg[3] == ':' || arg[4] == ':') + && ((tmp = CHARchr(arg, '#')) != NULL + || (tmp = CHARchr(arg, '?')) != NULL)) + *tmp = '\0'; + /* find the last '.' in the name */ for (tmp = arg + CHARlen(arg); --tmp >= arg && isalnum(*tmp); ) { @@ -782,17 +790,19 @@ static BOOLEAN func(name, arg) *--arg = '!'; /* Run the command and read its output */ - if (ioopen(tochar8(arg), 'r', False, False, 't')) + if (!ioopen(tochar8(arg), 'r', False, False, 't')) + return False; + arg = name; + while ((i = ioread(arg,RESULT_AVAIL(name))) > 0) { - arg = name; - while ((i = ioread(arg,RESULT_AVAIL(name))) > 0) + if (RESULT_OVERFLOW(arg, i + 1)) { - if (RESULT_OVERFLOW(arg, i + 1)) - goto Overflow; - arg += i; + ioclose(); + goto Overflow; } - ioclose(); + arg += i; } + ioclose(); /* Remove the last newline */ if (arg != name && arg[-1] == '\n') @@ -1536,6 +1546,16 @@ void main(int argc, char **argv) { case '?': fprintf(stderr, "usage: %s [-m] [-e expr] [arg]...\n", argv[0]); + fprintf(stderr, "This program is meant to be used primarily for testing elvis' built-in\n"); + fprintf(stderr, "calculator. It may also be useful for systems that don't have \"bc\".\n"); + fprintf(stderr, "The -m flag causes the expression to be evaluated using elvis' simpler\n"); + fprintf(stderr, "syntax, which is used mostly for outputing messages; otherwise it uses\n"); + fprintf(stderr, "the normal syntax. The -eexpr flag causes it to evaluate expr and quit;\n"); + fprintf(stderr, "otherwise it reads expressions from stdin until EOF. Any remaining\n"); + fprintf(stderr, "arguments are used as parameters which are accessible as $1 through $9\n"); + fprintf(stderr, "in the expression. See the elvis manual for more information.\n"); + fprintf(stderr, "\n"); + fprintf(stderr, "This program is unsupported and carries no guarantees.\n"); exit(0); break; @@ -1560,7 +1580,7 @@ void main(int argc, char **argv) } else { - while (gets(tochar8(expr))) + while (fgets(tochar8(expr), sizeof expr, stdin)) { result = calculate(expr, (CHAR **)&argv[optind], msg); if (result) diff --git a/configure b/configure index 9b1a9a2..918c28e 100755 --- a/configure +++ b/configure @@ -31,7 +31,8 @@ # xenix ancient SCO Xenix-386 systems # sco SCO UNIX or Open Desktop systems # bsd typical BSD implementations -# freebsd freebsd is a specific BSD implementation +# freebsd FreeBSD is a specific BSD implementation +# openbsd OpenBSD is a specific BSD implementation # posix generic POSIX implementations # cygwin GNU utilities under Windows95/98/NT # (anything else) generic UNIX, including SysV @@ -43,7 +44,7 @@ # Set some defaults XINCPATH="/usr/include /usr/include/X11 /usr/X11/include /usr/local/X11/include /usr/openwin/include /usr/X11R6/include" -XLIBPATH="/lib /usr/lib /usr/X11/lib /usr/local/X11/lib /usr/openwin/lib /usr/X11R6/lib "`echo "$LD_LIBRARY_PATH" | tr ':' ' '` +XLIBPATH="/lib /usr/lib /usr/X11/lib /usr/local/X11/lib /usr/openwin/lib /usr/X11R6/lib /usr/ucblib /usr/ccs/lib /usr/local/lib "`echo "$LD_LIBRARY_PATH" | tr ':' ' '` GNUPATH=`echo "$PATH" | tr ':' ' '` BINDIR=/usr/local/bin LIBDIR=/usr/local/lib/elvis @@ -55,6 +56,7 @@ WHY="" # Initialize some variables. These aren't merely defaults; don't change them! args="" XLIBS="" +NLIBS="" # Ultrix has a broken /bin/sh; it doesn't support shell functions. Try to be # clever about running bash instead of /bin/sh there. @@ -71,7 +73,7 @@ fi # This function echoes its arguments, but only if the --verbose flag is given why() { - if [ $WHY ] + if [ "$WHY" ] then echo "$@" fi @@ -109,8 +111,9 @@ usage() echo " --libs=STRING non-X11 part of the LIBS= string in Makefile" echo " --ioctl=VARIETY type of tty ioctl to use: termios, termio, or sgtty" echo " --verbose explain any decisions made during configuration" - echo "system: linux, sunos, solaris, solaris2, freebsd, bsd, posix, aix, osf-1, hp-ux" - echo " ultrix, qnx, irix, cygwin, xenix, sco (meaning SCO Unix or OpenDesktop)" + echo "system: linux, sunos, solaris, solaris2, freebsd, openbsd, bsd, posix," + echo " aix, osf-1, hp-ux, ultrix, qnx, irix, cygwin, xenix," + echo " sco (meaning SCO Unix or OpenDesktop)" if [ "$*" ] then echo "$*" @@ -210,7 +213,7 @@ then why " This is really '$SYS'" ;; - linux|solaris|solaris2|aix|osf-1|ultrix|hp-ux|qnx|irix|xenix|sco|bsd|freebsd|posix|cygwin*) + linux|solaris|solaris2|aix|osf-1|ultrix|hp-ux|qnx|irix*|xenix|sco|bsd|freebsd|openbsd|posix|cygwin*) why " I know '$SYS' -- This should be easy!" ;; @@ -403,7 +406,11 @@ fi if [ $PROTOCOL_HTTP = define -o $PROTOCOL_FTP = define ] then why "Does this system support inet_aton()?" - if fgrep inet_aton /usr/include/arpa/inet.h /dev/null + if [ "$SYS" = sunos -o "$SYS" = solaris -o "$SYS" = solaris2 ] + then + why " Assuming no, because this is a Sun system." + NEED_INET_ATON=define + elif fgrep inet_aton /usr/include/arpa/inet.h /dev/null then why " Assuming yes, because it is declared in " NEED_INET_ATON=undef @@ -412,6 +419,17 @@ then NEED_INET_ATON=define fi fi +if [ $NEED_INET_ATON = undef ] +then + why "Does this system require -lresolv to use inet_aton()?" + if [ "`searchpath libresolv.a $XLIBPATH`" = "" ] + then + why " Assuming no, because I couldn't find libresolv.a" + else + why " Assuming yes, because I found libresolv.a" + NLIBS="$NLIBS -lresolv" + fi +fi why "Does this system support memmove()?" if fgrep memmove /usr/include/string*.h /dev/null then @@ -521,7 +539,7 @@ case "$SYS" in fi if [ -f /usr/ccs/lib/libtermcap.a ] then - why "For Solaris2, -ltermcap is usually not necessary but since you have and and" + why "For Solaris2, -ltermcap is usually not necessary but since you have one and" why " it is harmless, I'll add it." TLIBS="$TLIBS -ltermcap" fi @@ -573,6 +591,11 @@ case "$SYS" in why "For FreeBSD, we ignore the file" NEED_SELECT_H="undef" ;; + *openbsd*) + why "For OpenBSD, we ignore the file" + NEED_SELECT_H="undef" + TLIBS="-lcurses" + ;; *bsd*) why "For BSD we like to use shlicc2 because it supports shared libraries" tmp=`searchpath shlicc2 $GNUPATH` @@ -666,7 +689,7 @@ then fi if [ "$LIBS" = "" ] then - LIBS=${TLIBS:--ltermcap} + LIBS="${TLIBS:--ltermcap} $NLIBS" fi case "$LIBS" in *ncurses*) NEED_BC=undef;; @@ -868,7 +891,7 @@ sed -f $tmp Makefile.in >Makefile && rm $tmp # Some parting advice case "$SYS" in *solaris*|*sunos*) - if [ "$GUI_X11" = "define" ] + if [ "$GUI_X11" = "define" -a "$WHY" = y ] then xlibdir=`dirname "$xlib"` case "$LD_LIBRARY_PATH" in diff --git a/ctags.c b/ctags.c index 8f878a0..f4f74ee 100644 --- a/ctags.c +++ b/ctags.c @@ -1,6 +1,6 @@ /* ctags.c */ -char id_ctags[] = "$Id: ctags.c,v 2.23 1999/02/26 21:31:41 steve Exp $"; +char id_ctags[] = "$Id: ctags.c,v 2.25 1999/10/06 19:10:45 steve Exp $"; /* This is a reimplementation of the ctags(1) program. It supports ANSI C, * and has heaps o' flags. It is meant to be distributed with elvis. @@ -49,7 +49,7 @@ char id_ctags[] = "$Id: ctags.c,v 2.23 1999/02/26 21:31:41 steve Exp $"; extern void file_open P_((char *)); extern int file_getc P_((void)); extern void file_ungetc P_((int)); -extern void file_copyline P_((long, FILE *, char *)); +extern int file_copyline P_((long, FILE *, char *)); extern void cpp_open P_((char *)); extern void cpp_echo P_((int)); extern int cpp_getc P_((void)); @@ -58,7 +58,7 @@ extern int lex_gettoken P_((void)); extern void maketag P_((int, char *, long, long, int, char *)); extern void ctags P_((char *)); extern void usage P_((void)); -extern void main P_((int, char **)); +extern int main P_((int, char **)); #if defined (GUI_WIN32) @@ -102,7 +102,7 @@ char hint_class[200];/* class name, for tags preceeded by a name and :: */ /* -------------------------------------------------------------------------- */ /* display a fatal error message from safe.c */ -#ifdef USE_PROTOTYPES +#if USE_PROTOTYPES void msg(MSGIMP type, char *msg, ...) #else void msg(type, msg) @@ -214,7 +214,7 @@ void file_ungetc(ch) * * This is meant to be used when generating a tag line. */ -void file_copyline(seek, fp, buf) +int file_copyline(seek, fp, buf) long seek; /* where the lines starts in the source file */ FILE *fp; /* the output stream to copy it to if buf==NULL */ char *buf; /* line buffer, or NULL to write to fp */ @@ -222,41 +222,54 @@ void file_copyline(seek, fp, buf) long oldseek;/* where the file's pointer was before we messed it up */ char ch; /* a single character from the file */ char next; /* the next character from this file */ + char *build; /* where to store the next character */ /* go to the start of the line */ oldseek = ftell(file_fp); fseek(file_fp, seek, 0); /* write everything up to, but not including, the newline */ - for (ch = getc(file_fp); ch != '\n' && ch != EOF; ch = next) + for (ch = getc(file_fp), build = buf; ch != '\n' && ch != EOF; ch = next) { + /* if too many chars have been written already, then stop */ + if (build && build >= &buf[160]) + { + break; + } + /* preread the next character from this file */ next = getc(file_fp); /* if character is '\', or a terminal '$', then quote it */ - if (buf && (ch == '\\' + if (build && (ch == '\\' || ch == (backward ? '?' : '/') || (ch == '$' && next == '\n'))) { - *buf++ = '\\'; + *build++ = '\\'; } /* copy the character, unless it is a terminal '\r' */ if (ch != '\r' || next != '\n') { - if (buf) - *buf++ = ch; + if (build) + *build++ = ch; else putc(ch, fp); } } /* mark the end of the line */ - if (buf) - *buf = '\0'; + if (build) + *build = '\0'; /* seek back to the old position */ fseek(file_fp, oldseek, 0); + + /* return 1 if it fit, 0 if it was truncated */ + if (build && build >= &buf[160]) + return 0; + else + return 1; } /* -------------------------------------------------------------------------- */ @@ -772,7 +785,7 @@ void maketag(scope, name, lnum, seek, number, kind) char *kind; /* token type of the tag: "f" for function, etc. */ { TAG tag; /* structure for storing tag info */ - char buf[200]; + char buf[300]; char lnbuf[20]; @@ -801,8 +814,9 @@ void maketag(scope, name, lnum, seek, number, kind) else { strcpy(buf, backward ? "?^" : "/^"); - file_copyline(seek, NULL, buf + 2); - strcat(buf, backward ? "$?" : "$/"); + if (file_copyline(seek, NULL, buf + 2)) + strcat(buf, "$"); + strcat(buf, backward ? "?" : "/"); } tag.TAGADDR = buf; @@ -1022,7 +1036,7 @@ void usage() -void main(argc, argv) +int main(argc, argv) int argc; char **argv; { diff --git a/dmmarkup.c b/dmmarkup.c index 5d8e135..ffa4510 100644 --- a/dmmarkup.c +++ b/dmmarkup.c @@ -1,7 +1,7 @@ /* dmmarkup.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_dmmarkup[] = "$Id: dmmarkup.c,v 2.85 1999/06/15 04:18:16 steve Exp $"; +char id_dmmarkup[] = "$Id: dmmarkup.c,v 2.87 1999/10/05 19:14:08 steve Exp $"; /* This file contains some fairly generic text formatting code -- generic * in the sense that it can be easily tweaked to format a variety of types @@ -1170,7 +1170,8 @@ static CHAR *htmltagatcursor(win, cursor) { scanalloc(&p, marktmp(tmp, markbuffer(cursor), mui->line[i].offset)); anyviz = False; - while ((token = htmlget(&p)) != NULL && (!anyviz || token->offset[0] < endoffset)) + while ((token = htmlget(&p)) != NULL + && (!anyviz || token->offset[0] < endoffset)) { if (!token->markup) { @@ -1183,7 +1184,8 @@ static CHAR *htmltagatcursor(win, cursor) || !CHARncmp(token->text, toCHAR("text, toCHAR("text, toCHAR("text, toCHAR("text, toCHAR("line[i].offset; +#endif } while (anchor.text[0] == 0 && --i >= 0); /* If we found an tag, then generate a dynamically-allocated @@ -1336,7 +1340,20 @@ static MARK htmltagload(tagname, from) || urllocal(tochar8(o_filename(markbuffer(from)))) != tochar8(o_filename(markbuffer(from))) )) { + /* get the directory part of the origin name */ inherit = dirdir(tochar8(o_filename(markbuffer(from)))); + + /* if it contains '?' or '#' then lop that off and try again */ + if ((tmp = strchr(inherit, '?')) != NULL + || (tmp = strchr(inherit, '#')) != NULL) + { + *tmp = '\0'; + inherit = dirdir(inherit); + } + + /* if the inherit string contains a pathname, and the new URL + * doesn't, then combine the new URL with the inherit pathname. + */ if (strlen(inherit) > 2 && inherit[strlen(inherit) - 1] == '/' && !urllocal(tochar8(o_filename(markbuffer(from))))) @@ -2548,8 +2565,8 @@ static twrap_t textitle(token) font = 'b'; break; - case 't': /* \secTion{} */ - center = False; + case 't': /* \secTion{} or \parT{} */ + center = (BOOLEAN)(token->text[1] == 'p'); /* part */ indent = 0; font = 'b'; break; @@ -2717,15 +2734,17 @@ static TOKEN *texget(refp) { "title", "-22-NY-", textitle }, #define TEX_AUTHOR &markups[10] { "author", "-12-NY-", textitle }, -#define TEX_CHAPTER &markups[11] +#define TEX_PART &markups[11] + { "part", "-c2NNYS", textitle }, +#define TEX_CHAPTER &markups[12] { "chapter", "-c2NNYS", textitle }, -#define TEX_SECTION &markups[12] +#define TEX_SECTION &markups[13] { "section", "-c2NNYS", textitle }, -#define TEX_SUBSECTION &markups[13] +#define TEX_SUBSECTION &markups[14] { "subsection", "-12NNYS", textitle }, -#define TEX_DIGRAPH &markups[14] +#define TEX_DIGRAPH &markups[15] { "digraph", "-------", texdigraph }, -#define TEX_HFIL &markups[15] +#define TEX_HFIL &markups[16] { "hfil", "--=----" }, { "hfill", "--=----" }, { "hline", "-02--Y-", htmlhr }, /* reuse HTML! */ @@ -2846,6 +2865,7 @@ static TOKEN *texget(refp) || !CHARcmp(rettok.text, "\\footnote") || !CHARcmp(rettok.text, "\\title") || !CHARcmp(rettok.text, "\\author") + || !CHARcmp(rettok.text, "\\part") || !CHARcmp(rettok.text, "\\chapter") || !CHARcmp(rettok.text, "\\section") || !CHARcmp(rettok.text, "\\subsection") @@ -2867,6 +2887,11 @@ static TOKEN *texget(refp) rettok.markup = TEX_AUTHOR; goto End; } + if (!CHARncmp(rettok.text, "\\part", 5)) + { + rettok.markup = TEX_PART; + goto End; + } if (!CHARncmp(rettok.text, "\\chapter", 8)) { rettok.markup = TEX_CHAPTER; @@ -2888,7 +2913,8 @@ static TOKEN *texget(refp) * doesn't become the default font. */ if ((!CHARncmp(rettok.text, "\\text", 4) - || !CHARcmp(rettok.text, "\\code")) + || !CHARcmp(rettok.text, "\\code") + || !CHARcmp(rettok.text, "\\emph")) && *refp && **refp == '{') { diff --git a/dmsyntax.c b/dmsyntax.c index dad95ce..ee81d0f 100644 --- a/dmsyntax.c +++ b/dmsyntax.c @@ -1,7 +1,7 @@ /* dmsyntax.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_dmsyntax[] = "$Id: dmsyntax.c,v 2.49 1998/11/14 01:38:08 steve Exp $"; +char id_dmsyntax[] = "$Id: dmsyntax.c,v 2.50 1999/09/30 18:23:02 steve Exp $"; #include "elvis.h" #ifdef DISPLAY_SYNTAX @@ -1064,6 +1064,21 @@ static MARK image(w, line, info, draw) if (!cfont[COMMENT2]) cfont[COMMENT2] = o_commentfont; } + else if (!undec[2]) + { + /* two-char keyword, parse it + * like two-punct keyword. This + * intended to support Perl's + * $# keyword, where $ is legal + * as the start of a word so it + * wouldn't hit the standard + * freaky-keyword code below. + */ + sinfo->token = FIRSTPUNCT; + cfont[FIRSTPUNCT] = cfont[SECONDPUNCT] = wordfont(kp); + if (!cfont[FIRSTPUNCT]) + cfont[FIRSTPUNCT] = cfont[SECONDPUNCT] = o_keywordfont; + } else { sinfo->token = KEYWORD; diff --git a/draw.c b/draw.c index 880d74e..c1f8484 100644 --- a/draw.c +++ b/draw.c @@ -1,7 +1,7 @@ /* draw.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_draw[] = "$Id: draw.c,v 2.73 1997/12/24 03:12:52 steve Exp $"; +char id_draw[] = "$Id: draw.c,v 2.75 1999/10/08 18:04:29 steve Exp $"; #include "elvis.h" @@ -26,9 +26,10 @@ static void openmove(WINDOW win, long oldcol, long newcol, CHAR *image, long len #endif /* allocate a drawinfo struct, including the related arrays */ -DRAWINFO *drawalloc(rows, columns) +DRAWINFO *drawalloc(rows, columns, top) int rows; /* height of new window image */ int columns;/* width of new window image */ + MARK top; /* top of screen */ { DRAWINFO *newp; int i; @@ -43,6 +44,8 @@ DRAWINFO *drawalloc(rows, columns) newp->curchar = (CHAR *)safealloc(rows * columns, sizeof(CHAR)); newp->curfont = (char *)safealloc(rows * columns, sizeof(char)); newp->offsets = (long *)safealloc(rows * columns, sizeof(long)); + newp->topmark = markdup(top); + newp->bottommark = markdup(top); /* clear the current image and the "new" image */ for (i = rows * columns; --i >= 0; ) @@ -73,6 +76,8 @@ void drawfree(di) safefree(di->curchar); safefree(di->curfont); safefree(di->offsets); + markfree(di->topmark); + markfree(di->bottommark); if (di->openimage) { safefree(di->openimage); @@ -98,7 +103,6 @@ void drawexpose(win, top, left, bottom, right) int right; /* right edge to be redrawn */ { int row, column, same, base, nonblank; - MARKBUF m; long firstline, lastline; assert(win != NULL && top >= 0 && left >= 0 && bottom < o_lines(win) @@ -159,10 +163,10 @@ void drawexpose(win, top, left, bottom, right) if (win->md->move == dmnormal.move) { /* find line numbers of first and last lines shown */ - firstline = markline(marktmp(m, markbuffer(win->cursor), win->di->topline)) - 1; - lastline = markline(marktmp(m, markbuffer(win->cursor), win->di->bottomline)) - 1; + firstline = markline(win->di->topmark) - 1; + lastline = markline(win->di->bottommark) - 1; - /* Some scrolling commands temporarily set bottomline + /* Some scrolling commands temporarily set bottommark * to the end of the buffer. Ordinarily this causes * no problems, but if an expose event occurs before * the screen is redrawn, the the scrollbar's "thumb" @@ -181,8 +185,8 @@ void drawexpose(win, top, left, bottom, right) } else { - (*gui->scrollbar)(win->gw, win->di->topline, - win->di->bottomline, win->di->curnbytes); + (*gui->scrollbar)(win->gw, markoffset(win->di->topmark), + markoffset(win->di->bottommark), win->di->curnbytes); } } guiflush(); @@ -1224,9 +1228,10 @@ static BOOLEAN drawquick(win) !win->md->canopt || /* display mode doesn't support optimization */ di->logic != DRAW_NORMAL || /* last command made a subtle change */ di->drawstate != DRAW_VISUAL || /* screen doesn't already show image */ + markbuffer(win->cursor)!=markbuffer(di->topmark) || /* cursor is in different buffer */ di->curchgs != markbuffer(win->cursor)->changes || /* last command made a normal change */ - cursoff < di->topline || /* cursor off top of screen */ - cursoff >= di->bottomline || /* cursor off bottom of screen */ + cursoff < markoffset(di->topmark) || /* cursor off top of screen */ + cursoff >= markoffset(di->bottommark) || /* cursor off bottom of screen */ col < 0 || /* cursor off left edge of screen */ col >= di->columns || /* cursor off right edge of screen */ win->seltop) /* visually selecting text */ @@ -1312,8 +1317,9 @@ void drawimage(win) if (win->di->curbuf != markbuffer(win->cursor)) { /* place the cursor's line at the center of the screen */ - win->di->topline = markoffset(dispmove(win, -(o_lines(win) / 2), 0)); - win->di->bottomline = o_bufchars(markbuffer(win->cursor)); + markset(win->di->topmark, dispmove(win, -(o_lines(win) / 2), 0)); + marksetbuffer(win->di->bottommark, markbuffer(win->cursor)); + marksetoffset(win->di->bottommark, o_bufchars(markbuffer(win->cursor))); win->di->logic = DRAW_CENTER; win->di->curbuf = markbuffer(win->cursor); } @@ -1325,8 +1331,8 @@ void drawimage(win) } /* setup, and choose a starting point for the drawing */ - next = (*win->md->setup)(win, marktmp(first, markbuffer(win->cursor), win->di->topline), - markoffset(win->cursor), marktmp(last, markbuffer(win->cursor), win->di->bottomline), win->mi); + next = (*win->md->setup)(win, win->di->topmark, + markoffset(win->cursor), win->di->bottommark, win->mi); thiswin = win; thiscell = 0; thiscol = 0; @@ -1390,7 +1396,7 @@ void drawimage(win) wantcurs = win->di->rows; /* draw each line until we reach the last row */ - win->di->topline = markoffset(next); + markset(win->di->topmark, next); for (row = 0; thiscell < maxcell || win->di->cursrow < 0 || (win->di->cursrow > wantcurs && markoffset(next) < o_bufchars(markbuffer(win->cursor))); ) { /* set column limits, taking o_sidescroll into consideration */ @@ -1462,7 +1468,7 @@ void drawimage(win) } } } - win->di->bottomline = markoffset(next); + markset(win->di->bottommark, next); assert(linesshown > 0 && linesshown <= maxrow); /* update the scrollbar */ @@ -1496,8 +1502,8 @@ void drawimage(win) * efficiently next time. */ win->di->logic = nextlogic; - win->di->topline = win->di->newline[0].start; - win->di->bottomline = markoffset(next); + marksetoffset(win->di->topmark, win->di->newline[0].start); + markset(win->di->bottommark, next); win->di->nlines = linesshown; win->di->curnbytes = o_bufchars(markbuffer(next)); win->di->curchgs = markbuffer(next)->changes; @@ -2052,3 +2058,38 @@ void drawextext(win, text, len) } } } + +/* This is like drawextext, except that here we're careful about making + * control characters (other than newline) visible. + */ +void drawexlist(win, text, len) + WINDOW win; /* window where ex output should be drawn */ + CHAR *text; /* text to be output */ + int len; /* length of text */ +{ + CHAR buf[2]; + int from, to; + + /* divide the text into segments of all-printable characters, or + * or individual non-printable characters. + */ + for (from = to = 0; to < len; to++) + { + if (text[to] != '\n' && iscntrl(text[to])) + { + /* draw the last printable segment, if any */ + if (from < to) + drawextext(win, &text[from], to - from); + from = to + 1; + + /* draw this control char in a printable format */ + buf[0] = '^'; + buf[1] = text[to] ^ '@'; + drawextext(win, buf, 2); + } + } + + /* if we ended with a printable segment, then draw it now */ + if (from < to) + drawextext(win, &text[from], to - from); +} diff --git a/draw.h b/draw.h index 4655715..cfd9b79 100644 --- a/draw.h +++ b/draw.h @@ -45,8 +45,8 @@ typedef struct CHAR *curchar; /* characters of current image */ char *curfont; /* fonts of current image */ long *offsets; /* buffer offsets of each individual cell */ - long topline; /* offset of first line drawn */ - long bottomline; /* offset of line after last drawn */ + MARK topmark; /* first line drawn */ + MARK bottommark; /* line after last drawn */ BUFFER curbuf; /* current buffer */ long curnbytes; /* size of buffer when current image drawn */ long curchgs; /* buffer's "changes" counter when image drawn */ diff --git a/draw2.h b/draw2.h index d254b51..daaf385 100644 --- a/draw2.h +++ b/draw2.h @@ -5,7 +5,7 @@ #define drawscratch(di) ((di)->mustredraw = True) BEGIN_EXTERNC -extern DRAWINFO *drawalloc P_((int rows, int columns)); +extern DRAWINFO *drawalloc P_((int rows, int columns, MARK top)); extern void drawfree P_((DRAWINFO *di)); extern void drawimage P_((WINDOW win)); extern void drawexpose P_((WINDOW win, int top, int left, int bottom, int right)); @@ -15,4 +15,5 @@ extern void drawfinish P_((WINDOW win)); extern void drawopenedit P_((WINDOW win)); extern void drawopencomplete P_((WINDOW win)); extern void drawextext P_((WINDOW win, CHAR *text, int len)); +extern void drawexlist P_((WINDOW win, CHAR *text, int len)); END_EXTERNC diff --git a/elvis.lsm b/elvis.lsm index 77d8159..cb4385f 100644 --- a/elvis.lsm +++ b/elvis.lsm @@ -1,8 +1,8 @@ Begin3 Title: elvis, a clone of the vi text editor Version: 2.1 -Release: 3 -Entered-date: 1APR99 +Release: 4 +Entered-date: 15OCT99 Description: Clone of vi editor, with added support for multiple edit buffers, multiple windows, a variety of user interfaces (including X-windows), several display modes (including @@ -11,12 +11,12 @@ Description: Clone of vi editor, with added support for multiple edit improvements to the X-windows interface, a new graphical interface for Win32, OS/2 ports, enhanced tags, and an :alias command. Many other small changes, and bug fixes. -Keywords: vi editor HTML syntax-coloring X11 +Keywords: vi editor HTML FTP HTTP syntax-coloring X11 Author: kirkenda@cs.pdx.edu (Steve Kirkendall) Maintained-by: Primary-site: ftp.cs.pdx.edu /pub/elvis - 991k elvis-2.1_3.tgz - 976 elvis.lsm + 1012k elvis-2.1_4.tar.gz + 999 elvis.lsm Alternate-site: sunsite.unc.edu /pub/Linux/apps/editors ftp.false.com /pub/elvis Original-site: diff --git a/ex.c b/ex.c index bfd44a0..fbe6518 100644 --- a/ex.c +++ b/ex.c @@ -1,7 +1,7 @@ /* ex.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_ex[] = "$Id: ex.c,v 2.151 1999/03/11 17:53:08 steve Exp $"; +char id_ex[] = "$Id: ex.c,v 2.153 1999/10/08 18:03:03 steve Exp $"; #include "elvis.h" @@ -122,12 +122,14 @@ static struct /*c */{"change", EX_CHANGE, ex_append, a_Range | a_Bang | a_Count | a_Text | q_Undo | q_Ex }, /*cha */{"chdir", EX_CD, ex_cd, a_Bang | a_File | q_Exrc | q_Unsafe }, /*ca */{"calculate", EX_CALC, ex_comment, a_Cmds | q_Exrc }, +/*cas */{"case", EX_CASE, ex_case, a_Lhs | a_Cmds | q_Exrc }, /*cc */{"cc", EX_CC, ex_make, a_Bang | a_Rhs | q_Unsafe | q_SwitchB }, /*cd */{"cd", EX_CD, ex_cd, a_Bang | a_File | q_Exrc | q_Unsafe }, /*cl */{"close", EX_CLOSE, ex_xit, a_Bang | q_MayQuit }, /*co */{"copy", EX_COPY, ex_move, a_Range | a_Target | a_Pflag | q_Autop | q_Undo }, /*col */{"color", EX_COLOR, ex_color, a_Rhs | q_Exrc | q_Custom }, /*d */{"delete", EX_DELETE, ex_delete, a_Range | a_Buffer | a_Count | a_Pflag | q_Undo | q_Autop }, +/*de */{"default", EX_DEFAULT, ex_case, a_Cmds | q_Exrc }, /*di */{"display", EX_DISPLAY, ex_display, a_Rhs }, /*dig */{"digraph", EX_DIGRAPH, ex_digraph, a_Bang | a_Rhs | q_Exrc | q_Custom }, /*do */{"do", EX_DO, ex_do, a_Cmds | q_Exrc }, @@ -192,6 +194,7 @@ static struct /*sta */{"stag", EX_STAG, ex_tag, a_Rhs }, /*stac*/{"stack", EX_STACK, ex_stack, d_None }, /*su */{"suspend", EX_SUSPEND, ex_suspend, a_Bang | q_Unsafe }, +/*sw */{"switch", EX_SWITCH, ex_switch, a_Cmds | q_Exrc }, /*t */{"to", EX_COPY, ex_move, a_Range | a_Target | a_Pflag | q_Autop | q_Undo }, /*ta */{"tag", EX_TAG, ex_tag, a_Bang | a_Rhs | q_Unsafe | q_SwitchB }, /*th */{"then", EX_THEN, ex_then, a_Cmds | q_Exrc }, @@ -1848,8 +1851,8 @@ static RESULT parse(win, refp, xinf) CHAR *logstr;/* start of string command, or NULL if from buffer */ int i; - /* if verbose, then display this line on stderr */ - if (o_verbose >= 3 && !win) + /* if verbose, then display this line in window, or on stderr */ + if (o_verbose >= (win ? 5 : 3)) { lntext = NULL; for (scandup(&p2, refp); p2 && *p2 != '\n'; scannext(&p2)) @@ -2609,15 +2612,12 @@ RESULT exstring(win, str, name) { EXINFO xinfb; /* buffer, holds info about command being parsed */ CHAR *p; /* pointer used for scanning command line */ - BOOLEAN oldthenflag; - CHAR *olddotest; + EXCTLSTATE oldctlstate; RESULT result; void *locals; - /* commands run this way don't affect the :if or :while expressions */ - oldthenflag = exthenflag; - olddotest = exdotest; - exdotest = NULL; + /* commands run this way don't affect :if/:while/:switch expressions */ + exctlsave(oldctlstate); locals = optlocal(NULL); /* start reading commands */ @@ -2648,8 +2648,7 @@ RESULT exstring(win, str, name) Done: (void)optlocal(locals); - exthenflag = oldthenflag; - exdotest = olddotest; + exctlrestore(oldctlstate); return result; } diff --git a/ex.h b/ex.h index bdae7e9..ed712a5 100644 --- a/ex.h +++ b/ex.h @@ -15,9 +15,9 @@ typedef enum { EX_ABBR, EX_ALIAS, EX_ALL, EX_APPEND, EX_ARGS, EX_AT, EX_BANG, EX_BBROWSE, EX_BREAK, EX_BROWSE, EX_BUFFER, - EX_CALC, EX_CC, EX_CD, EX_CHANGE, EX_CLOSE, EX_COLOR, EX_COMMENT, - EX_COPY, - EX_DELETE, EX_DIGRAPH, EX_DISPLAY, EX_DO, EX_DOALIAS, + EX_CALC, EX_CASE, EX_CC, EX_CD, EX_CHANGE, EX_CLOSE, EX_COLOR, + EX_COMMENT, EX_COPY, + EX_DEFAULT, EX_DELETE, EX_DIGRAPH, EX_DISPLAY, EX_DO, EX_DOALIAS, EX_ECHO, EX_EDIT, EX_ELSE, EX_EQUAL, EX_ERRLIST, EX_ERROR, EX_EVAL, EX_FILE, EX_GOTO, EX_GLOBAL, EX_GUI, @@ -33,7 +33,7 @@ typedef enum EX_SALL, EX_SAFER, EX_SBBROWSE, EX_SBROWSE, EX_SET, EX_SHELL, EX_SHIFTL, EX_SHIFTR, EX_SLAST, EX_SNEW, EX_SNEXT, EX_SOURCE, EX_SPLIT, EX_SPREVIOUS, EX_SREWIND, EX_STAG, EX_STACK, EX_STOP, - EX_SUBAGAIN, EX_SUBRECENT, EX_SUBSTITUTE, EX_SUSPEND, + EX_SUBAGAIN, EX_SUBRECENT, EX_SUBSTITUTE, EX_SUSPEND, EX_SWITCH, EX_TAG, EX_THEN, EX_TRY, EX_UNABBR, EX_UNALIAS, EX_UNBREAK, EX_UNDO, EX_UNMAP, EX_VERSION, EX_VGLOBAL, EX_VISUAL, @@ -74,9 +74,24 @@ typedef struct } EXINFO; +/* This stores the current state of ex's control structures */ +typedef struct +{ + BOOLEAN thenflag; /* result of an :if */ + BOOLEAN switchcarry; /* falling through to next :case? */ + CHAR *switchvalue; /* result of :switch, compare to :case value */ + CHAR *dotest; /* expression to be evaluated by :do */ +} EXCTLSTATE; + + /* defined in exconfig.c */ -extern BOOLEAN exthenflag; -extern CHAR *exdotest; +extern EXCTLSTATE exctlstate; + +/* macros for saving & restoring the control state in a local variable */ +#define exctlsave(v) {(v) = exctlstate; memset(&exctlstate, 0, sizeof exctlstate);} +#define exctlrestore(v) {if (exctlstate.switchvalue) safefree(exctlstate.switchvalue);\ + if (exctlstate.dotest) safefree(exctlstate.dotest);\ + exctlstate = (v);} /* defined in exmake.c */ extern BOOLEAN makeflag; @@ -103,6 +118,7 @@ extern RESULT ex_at P_((EXINFO *xinf)); extern RESULT ex_bang P_((EXINFO *xinf)); extern RESULT ex_browse P_((EXINFO *xinf)); extern RESULT ex_buffer P_((EXINFO *xinf)); +extern RESULT ex_case P_((EXINFO *xinf)); extern RESULT ex_cd P_((EXINFO *xinf)); extern RESULT ex_color P_((EXINFO *xinf)); extern RESULT ex_comment P_((EXINFO *xinf)); @@ -138,6 +154,7 @@ extern RESULT ex_source P_((EXINFO *xinf)); extern RESULT ex_stack P_((EXINFO *xinf)); extern RESULT ex_substitute P_((EXINFO *xinf)); extern RESULT ex_suspend P_((EXINFO *xinf)); +extern RESULT ex_switch P_((EXINFO *xinf)); extern RESULT ex_tag P_((EXINFO *xinf)); extern RESULT ex_then P_((EXINFO *xinf)); extern RESULT ex_undo P_((EXINFO *xinf)); diff --git a/exaction.c b/exaction.c index 38a993e..6ce1c7d 100644 --- a/exaction.c +++ b/exaction.c @@ -1,7 +1,7 @@ /* exaction.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_exaction[] = "$Id: exaction.c,v 2.86 1999/02/26 21:27:08 steve Exp $"; +char id_exaction[] = "$Id: exaction.c,v 2.88 1999/10/07 16:23:58 steve Exp $"; #include "elvis.h" @@ -533,10 +533,13 @@ RESULT ex_file(xinf) switch (xinf->command) { case EX_EQUAL: - if (xinf->from != xinf->to) + if (xinf->anyaddr) { - msg(MSG_INFO, "[ddd]$1,$2 = $3 lines", - xinf->from, xinf->to, xinf->to - xinf->from + 1); + if (xinf->from != xinf->to) + msg(MSG_INFO, "[dd]$1,$2 = ($2-$1+1) lines", + xinf->from, xinf->to); + else + msg(MSG_INFO, "[d]$1", xinf->from); } else { @@ -962,7 +965,7 @@ RESULT ex_bang(xinf) /* clean up & exit */ markfree(mark); - return (prgclose() == 0) ? RESULT_COMPLETE : RESULT_ERROR; + return (gui->prgclose ? (*gui->prgclose)() : prgclose()) == 0 ? RESULT_COMPLETE : RESULT_ERROR; } diff --git a/exconfig.c b/exconfig.c index bd33d0a..ac50944 100644 --- a/exconfig.c +++ b/exconfig.c @@ -1,14 +1,14 @@ /* exconfig.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_exconfig[] = "$Id: exconfig.c,v 2.84 1999/03/11 17:55:46 steve Exp $"; +char id_exconfig[] = "$Id: exconfig.c,v 2.87 1999/10/08 18:03:03 steve Exp $"; #include "elvis.h" -BOOLEAN exthenflag; /* set by ":if", tested by ":then" & ":else" */ -CHAR *exdotest; /* set by ":while", tested by ":do" */ +/* This variable stores the current state of ex's control structures. */ +EXCTLSTATE exctlstate; @@ -33,7 +33,6 @@ static alias_t *aliases; /* This is the head of a list of aliases */ /* look up a name in the alias list. The name can be terminated with any * non-alphanumeric character, not just '\0'. Return its name if alias, * or NULL otherwise. Optionally ignore if already in use. - i */ char *exisalias(name, inuse) char *name; /* name of a command, maybe an alias */ @@ -59,29 +58,29 @@ static void listalias(win, alias, shortformat) CHAR *start; int len; - drawextext(win, toCHAR(alias->name), strlen(alias->name)); + drawexlist(win, toCHAR(alias->name), strlen(alias->name)); if (CHARchr(alias->command, '\n') == alias->command + CHARlen(alias->command) - 1) { /* single-line command simply follows the alias name */ - drawextext(win, blanks, 10 - (CHARlen(alias->name) % 10)); - drawextext(win, alias->command, CHARlen(alias->command)); + drawexlist(win, blanks, 10 - (CHARlen(alias->name) % 10)); + drawexlist(win, alias->command, CHARlen(alias->command)); } else if (shortformat) { /* multi-line command, but only show first line */ - drawextext(win, blanks, 10 - (CHARlen(alias->name) % 10)); + drawexlist(win, blanks, 10 - (CHARlen(alias->name) % 10)); ch[0] = '{'; ch[1] = ' '; - drawextext(win, ch, 2); + drawexlist(win, ch, 2); for (start = alias->command, len = 0; *start++ != '\n' && len < o_columns(win) - 16; len++) { } - drawextext(win, alias->command, len); + drawexlist(win, alias->command, len); ch[0] = ch[1] = ch[2] = '.'; ch[3] = '\n'; - drawextext(win, ch, 4); + drawexlist(win, ch, 4); } else { @@ -89,22 +88,22 @@ static void listalias(win, alias, shortformat) ch[0] = ' '; ch[1] = '{'; ch[2] = '\n'; - drawextext(win, ch, 3); + drawexlist(win, ch, 3); for (start = alias->command, len = 0; *start; len++) { if (start[len] == '\n') { - drawextext(win, blanks, 10); - drawextext(win, start, len); + drawexlist(win, blanks, 10); + drawexlist(win, start, len); ch[0] = '\n'; - drawextext(win, ch, 1); + drawexlist(win, ch, 1); start += len + 1; len = -1; /* will be incremented to 0 by for()*/ } } ch[0] = '}'; ch[1] = '\n'; - drawextext(win, ch, 2); + drawexlist(win, ch, 2); } } @@ -499,26 +498,26 @@ RESULT ex_args(xinf) ; /* no space is needed */ else if (col + len + 4 > o_columns(xinf->window)) { - drawextext(xinf->window, toCHAR("\n"), 1); + drawexlist(xinf->window, toCHAR("\n"), 1); col = 0; } else { - drawextext(xinf->window, toCHAR(" "), 1); + drawexlist(xinf->window, toCHAR(" "), 1); col++; } /* Output the arg. If current, enclose in '[' */ if (i == argnext - 1) - drawextext(xinf->window, toCHAR("["), 1); - drawextext(xinf->window, toCHAR(arglist[i]), len); + drawexlist(xinf->window, toCHAR("["), 1); + drawexlist(xinf->window, toCHAR(arglist[i]), len); if (i == argnext - 1) - drawextext(xinf->window, toCHAR("]"), 1); + drawexlist(xinf->window, toCHAR("]"), 1); col += len; } /* the final newline */ - drawextext(xinf->window, toCHAR("\n"), 1); + drawexlist(xinf->window, toCHAR("\n"), 1); } return RESULT_COMPLETE; } @@ -997,7 +996,7 @@ RESULT ex_if(xinf) if (xinf->command == EX_IF) { /* set "exthenflag" based on result of evaluation */ - exthenflag = calctrue(result); + exctlstate.thenflag = calctrue(result); return RESULT_COMPLETE; } else /* command == EX_EVAL */ @@ -1021,17 +1020,17 @@ RESULT ex_then(xinf) return result; /* For :try, execute the commands unconditionally and then set the - * "exthenflag" to indicatge whether the command succeeded. Otherwise + * "exthenflag" to indicate whether the command succeeded. Otherwise * (for :then and :else) execute the commands if "exthenflag" is set * appropriately */ if (xinf->command == EX_TRY) { washiding = msghide(True); - exthenflag = (BOOLEAN)(exstring(xinf->window, xinf->rhs, NULL) == RESULT_COMPLETE); + exctlstate.thenflag = (BOOLEAN)(exstring(xinf->window, xinf->rhs, NULL) == RESULT_COMPLETE); (void)msghide(washiding); } - else if (xinf->command == EX_THEN ? exthenflag : !exthenflag) + else if (xinf->command == EX_THEN ? exctlstate.thenflag : !exctlstate.thenflag) { result = exstring(xinf->window, xinf->rhs, NULL); } @@ -1043,6 +1042,11 @@ RESULT ex_then(xinf) RESULT ex_while(xinf) EXINFO *xinf; { + /* If there was some other, unused test lying around, then free it. */ + if (exctlstate.dotest) + safefree(exctlstate.dotest); + exctlstate.dotest = NULL; + /* expression is required */ if (!xinf->rhs) { @@ -1050,17 +1054,8 @@ RESULT ex_while(xinf) return RESULT_ERROR; } - /* If there was some other, unused test lying around, then free it. - * - * NOTE: while/do loops can be nested in certain circumstances. Any - * code which pushes an older while test onto the stack also sets - * exdotest to NULL so this test won't free those tests. - */ - if (exdotest) - safefree(exdotest); - /* store the new test */ - exdotest = xinf->rhs; + exctlstate.dotest = xinf->rhs; xinf->rhs = NULL; return RESULT_COMPLETE; } @@ -1073,14 +1068,14 @@ RESULT ex_do(xinf) RESULT result = RESULT_COMPLETE; /* if no :while was executed before this, then fail */ - if (!exdotest) + if (!exctlstate.dotest) { msg(MSG_ERROR, "missing :while"); return RESULT_ERROR; } /* while the expression is true and valid... */ - while ((value = calculate(exdotest, NULL, False)) != NULL + while ((value = calculate(exctlstate.dotest, NULL, False)) != NULL && calctrue(value)) { /* Run the command. If no command, then display result */ @@ -1098,8 +1093,8 @@ RESULT ex_do(xinf) } /* free the exdotest expression */ - safefree(exdotest); - exdotest = NULL; + safefree(exctlstate.dotest); + exctlstate.dotest = NULL; /* if test could not be evaluated, then this command fails */ if (!value) @@ -1108,6 +1103,92 @@ RESULT ex_do(xinf) } +/* Implements the :switch command -- evaluate an expression, and store the + * result for use in later :case statements. + */ +RESULT ex_switch(xinf) + EXINFO *xinf; +{ + /* free the old switch value, if any */ + if (exctlstate.switchvalue) + safefree(exctlstate.switchvalue); + exctlstate.switchvalue = NULL; + exctlstate.switchcarry = False; + + /* verify that we were given an expression */ + if (!xinf->rhs) + { + msg(MSG_ERROR, "missing rhs"); + return RESULT_ERROR; + } + + /* compute a new value */ + exctlstate.switchvalue = calculate(xinf->rhs, NULL, False); + if (exctlstate.switchvalue) + { + exctlstate.switchvalue = CHARdup(exctlstate.switchvalue); + return RESULT_COMPLETE; + } + return RESULT_ERROR; +} + + +/* This implements the :case and :default commands. It tests the value from + * a previous :switch command, and conditionally executes a command. + */ +RESULT ex_case(xinf) + EXINFO *xinf; +{ + /* check syntax */ + if (xinf->command == EX_CASE && !xinf->lhs) + { + msg(MSG_ERROR, "missing lhs"); + return RESULT_ERROR; + } + if (xinf->command == EX_DEFAULT && !xinf->rhs) + { + msg(MSG_ERROR, "missing ex command"); + return RESULT_ERROR; + } + + /* if a previous case matched, then do nothing here... unless the + * previous match had no ex command line, and is therefor trying to + * execute this case's command line. + */ + if (!exctlstate.switchvalue && !exctlstate.switchcarry) + return RESULT_COMPLETE; + + /* The :default command doesn't care about values, and we don't care + * when a previous match had no ex command line eithe. Otherwise we + * need to check the :switch value against this case's value. + */ + if (!exctlstate.switchcarry && xinf->command != EX_DEFAULT) + { + if (CHARcmp(exctlstate.switchvalue, xinf->lhs)) + /* no match, so skip this case */ + return RESULT_COMPLETE; + } + + /* It *DOES* match. Clobber the exswitchvalue so each :switch will + * only match (at most) one case. This also allows is to detect + * the default condition later. + */ + if (exctlstate.switchvalue) + { + safefree(exctlstate.switchvalue); + exctlstate.switchvalue = NULL; + } + exctlstate.switchcarry = False; + + /* Execute the command for this case. If there is no command, then + * set a flag to indicate that the next case should match. + */ + if (xinf->rhs) + return exstring(xinf->window, xinf->rhs, NULL); + exctlstate.switchcarry = True; + return RESULT_COMPLETE; +} + /* This implemented :map, :unmap, :abbr, :unabbr, :break, and :unbreak */ @@ -1256,7 +1337,7 @@ RESULT ex_set(xinf) } if (*outbuf) { - drawextext(windefault, outbuf, (int)CHARlen(outbuf)); + drawexlist(windefault, outbuf, (int)CHARlen(outbuf)); } } return RESULT_COMPLETE; diff --git a/exmake.c b/exmake.c index 4f36acb..85ea870 100644 --- a/exmake.c +++ b/exmake.c @@ -1,7 +1,7 @@ /* exmake.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_make[] = "$Id: exmake.c,v 2.29 1999/03/11 18:37:39 steve Exp $"; +char id_make[] = "$Id: exmake.c,v 2.30 1999/09/30 18:21:36 steve Exp $"; #include "elvis.h" @@ -123,8 +123,8 @@ static BOOLEAN parse_errmsg() * name of an existing, writable text file? */ if (!errfile - && (isalnum(*word) - || (perms = dirperm(tochar8(word))) == DIR_READWRITE + && isalnum(*word) + && ((perms = dirperm(tochar8(word))) == DIR_READWRITE || (o_anyerror && perms == DIR_READONLY)) && *ioeol(tochar8(word)) != 'b') { diff --git a/gui.c b/gui.c index e0058da..2494325 100644 --- a/gui.c +++ b/gui.c @@ -1,7 +1,7 @@ /* gui.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_gui[] = "$Id: gui.c,v 2.13 1997/12/24 03:12:52 steve Exp $"; +char id_gui[] = "$Id: gui.c,v 2.14 1999/10/05 19:09:20 steve Exp $"; #include "elvis.h" @@ -165,11 +165,12 @@ BOOLEAN guipoll(reset) return False; } - /* if there is no poll() function, or pollfrequency indicates that - * poll() shouldn't be called yet, then return False so the current - * operation will continue. + /* if no GUI has been chosen yet, or there is no poll() function, or + * we're quitting, or pollfrequency indicates that poll() shouldn't + * be called yet, then return False so the current operation will + * continue. */ - if (!gui || !gui->poll || ++pollctr < o_pollfrequency) + if (!gui || !gui->poll || windows || ++pollctr < o_pollfrequency) { return False; } diff --git a/guiwin32/WinElvis.rc b/guiwin32/WinElvis.rc index c98c865..be009b9 100755 --- a/guiwin32/WinElvis.rc +++ b/guiwin32/WinElvis.rc @@ -577,6 +577,7 @@ END // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. IDI_ELVIS ICON DISCARDABLE "elvis.ico" +IDI_ICON2 ICON DISCARDABLE "elvisold.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -748,12 +749,12 @@ BEGIN BEGIN VALUE "CompanyName", "\0" VALUE "FileDescription", "WinElvis\0" - VALUE "FileVersion", "2.1d-alpha\0" + VALUE "FileVersion", "2.1_4\0" VALUE "InternalName", "WinElvis\0" - VALUE "LegalCopyright", "Copyright © 1996 Steve Kirkendall & Serge Pirotte\0" + VALUE "LegalCopyright", "Copyright © 1999 Steve Kirkendall & Serge Pirotte\0" VALUE "OriginalFilename", "WinElvis.exe\0" VALUE "ProductName", " WinElvis\0" - VALUE "ProductVersion", "2.0\0" + VALUE "ProductVersion", "2.1_4\0" END END BLOCK "VarFileInfo" diff --git a/guiwin32/elvis.ico b/guiwin32/elvis.ico index abcff55..a571ddc 100755 Binary files a/guiwin32/elvis.ico and b/guiwin32/elvis.ico differ diff --git a/guiwin32/elvisres.h b/guiwin32/elvisres.h index 49d1bc7..ad2459c 100644 --- a/guiwin32/elvisres.h +++ b/guiwin32/elvisres.h @@ -23,6 +23,7 @@ #define IDD_OPT_SYNTAX 120 #define IDD_OPT_GLOBAL 121 #define IDD_OPT_GUI 122 +#define IDI_ICON2 126 #define IDAB_PHYS_MEM 1000 #define IDAB_DISK_SPACE 1001 #define IDBL_BUFFERS 1002 @@ -215,7 +216,7 @@ // #ifdef APSTUDIO_INVOKED #ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 125 +#define _APS_NEXT_RESOURCE_VALUE 127 #define _APS_NEXT_COMMAND_VALUE 40050 #define _APS_NEXT_CONTROL_VALUE 1132 #define _APS_NEXT_SYMED_VALUE 101 diff --git a/guiwin32/gwmsg.c b/guiwin32/gwmsg.c index 803655a..dae82ee 100755 --- a/guiwin32/gwmsg.c +++ b/guiwin32/gwmsg.c @@ -522,12 +522,13 @@ LONG gwclient_WM_MOUSEMOVE (GUI_WINDOW *gwp, UINT wParam, LONG lParam) LONG gwclient_WM_MOUSEWHEEL (GUI_WINDOW *gwp, UINT wParam, LONG lParam) { - long delta = (HIWORD (wParam) / WHEEL_DELTA) * 4; + short delta = HIWORD (wParam); + delta = (delta / WHEEL_DELTA) * 4; if (delta > 0) - eventscroll ((GUIWIN *)gwp, SCROLL_FWDLN, delta, 0L); + eventscroll ((GUIWIN *)gwp, SCROLL_BACKLN, delta, 0L); else - eventscroll ((GUIWIN *)gwp, SCROLL_BACKLN, -delta, 0L); + eventscroll ((GUIWIN *)gwp, SCROLL_FWDLN, -delta, 0L); gw_redraw_win (gwp); return 0; diff --git a/guix11/guix11.c b/guix11/guix11.c index 58b47fc..0f99b32 100644 --- a/guix11/guix11.c +++ b/guix11/guix11.c @@ -2,7 +2,7 @@ /* Copyright 1995 by Steve Kirkendall */ -char id_guix11[] = "$Id: guix11.c,v 2.37 1999/03/11 17:54:44 steve Exp $"; +char id_guix11[] = "$Id: guix11.c,v 2.39 1999/10/06 19:11:37 steve Exp $"; #include "elvis.h" #ifdef GUI_X11 @@ -152,16 +152,27 @@ static struct } keys[] = { { "", XK_Up, "k", MAP_ALL }, + { "", XK_KP_Up, "k", MAP_ALL }, { "", XK_Down, "j", MAP_ALL }, + { "", XK_KP_Down, "j", MAP_ALL }, { "", XK_Left, "h", MAP_ALL }, + { "", XK_KP_Left, "h", MAP_ALL }, { "", XK_Right, "l", MAP_ALL }, + { "", XK_KP_Right, "l", MAP_ALL }, { "", XK_Prior, "\002", MAP_ALL_VISUAL }, + { "", XK_KP_Prior, "\002", MAP_ALL_VISUAL }, { "", XK_Next, "\006", MAP_ALL_VISUAL }, + { "", XK_KP_Next, "\006", MAP_ALL_VISUAL }, { "", XK_Home, "^", MAP_ALL }, + { "", XK_KP_Home, "^", MAP_ALL }, { "", XK_Begin, "^", MAP_ALL }, + { "", XK_KP_Begin, "^", MAP_ALL }, { "", XK_End, "$", MAP_ALL }, + { "", XK_KP_End, "$", MAP_ALL }, { "", XK_Insert, "i", MAP_ALL }, + { "",XK_KP_Insert, "i", MAP_ALL }, { "", XK_Delete, "x", MAP_ALL }, + { "",XK_KP_Delete, "x", MAP_ALL }, { "", XK_Undo, "u", MAP_ALL_VISUAL }, { "", XK_Help, ":help\r",MAP_ALL_VISUAL }, { "",XK_Multi_key, "\013", MAP_INPUT|MAP_OPEN } @@ -199,6 +210,8 @@ static OPTDESC x11desc[] = {"underline", "uln", NULL, NULL }, {"outlinemono", "om", optnstring, optisnumber, "0:3"}, {"borderwidth", "xbw", optnstring, xoptisnumber, "0:5"}, + {"xrootwidth", "xrw", optnstring, optisnumber, "320:4096"}, + {"xrootheight", "xrh", optnstring, optisnumber, "200:4096"}, {"submit", "Submit", optsstring, optisstring }, {"cancel", "Cancel", optsstring, optisstring }, {"help", "Help", optsstring, optisstring } @@ -988,6 +1001,8 @@ static int init(argc, argv) optpreset(o_underline, True, OPT_HIDE|OPT_SCRATCH); optpreset(o_outlinemono, DEFAULT_OUTLINEMONO, OPT_HIDE); optpreset(o_borderwidth, DEFAULT_BORDERWIDTH, OPT_HIDE); + optpreset(o_xrootwidth, rootwidth, OPT_HIDE|OPT_LOCK); + optpreset(o_xrootheight, rootheight, OPT_HIDE|OPT_LOCK); optinsert("x11", QTY(x11desc), x11desc, (OPTVAL *)&x_optvals); /* initialize the colors */ @@ -1144,7 +1159,8 @@ static void destroygw(gw, force) x_st_destroy(xw); XFreeGC(x_display, xw->gc); #ifndef NO_XLOCALE - XDestroyIC(xw->ic); + if (xw->ic) + XDestroyIC(xw->ic); #endif if (xw->win) { diff --git a/guix11/guix11.h b/guix11/guix11.h index 0b87ea1..6fba1db 100644 --- a/guix11/guix11.h +++ b/guix11/guix11.h @@ -95,7 +95,8 @@ extern struct x_optvals_s statusbar, dblclicktime, blinktime, xrows, xcolumns, firstx, firsty, icon, iconic, stopshell, autoiconify, altkey, stagger, warpback, warpto, focusnew, textcursor, - underline, outlinemono, borderwidth, submit, cancel, help; + underline, outlinemono, borderwidth, xrootwidth, xrootheight, + submit, cancel, help; } x_optvals; #define o_normalfont x_optvals.normalfont.value.string #define o_boldfont x_optvals.boldfont.value.string @@ -126,6 +127,8 @@ extern struct x_optvals_s #define o_underline x_optvals.underline.value.boolean #define o_outlinemono x_optvals.outlinemono.value.number #define o_borderwidth x_optvals.borderwidth.value.number +#define o_xrootwidth x_optvals.xrootwidth.value.number +#define o_xrootheight x_optvals.xrootheight.value.number #define o_submit x_optvals.submit.value.string #define o_cancel x_optvals.cancel.value.string #define o_help x_optvals.help.value.string diff --git a/guix11/xdialog.c b/guix11/xdialog.c index abd1e74..35c5b33 100644 --- a/guix11/xdialog.c +++ b/guix11/xdialog.c @@ -1,6 +1,6 @@ /* xdialog.c */ -char id_xdialog[] = "$Id: xdialog.c,v 2.18 1999/02/26 21:33:52 steve Exp $"; +char id_xdialog[] = "$Id: xdialog.c,v 2.19 1999/10/06 19:11:37 steve Exp $"; #include "elvis.h" #ifdef GUI_X11 @@ -802,7 +802,9 @@ static CHAR *keyoneof(dia, key) switch (key) { case XK_Left: + case XK_KP_Left: case XK_Right: + case XK_KP_Right: /* find the current value */ val = dia->field[dia->current].value; i = CHARlen(val); @@ -813,7 +815,7 @@ static CHAR *keyoneof(dia, key) } /* move left or right */ - if (key == XK_Left) + if (key == XK_Left || key == XK_KP_Left) this--; else this++; @@ -869,11 +871,13 @@ static CHAR *keystring(dia, key) switch (key) { case XK_Left: + case XK_KP_Left: if (dia->cursor > 0) dia->cursor--; break; case XK_Right: + case XK_KP_Right: if (dia->cursor < origlen) dia->cursor++; break; @@ -898,10 +902,12 @@ static CHAR *keystring(dia, key) break; case XK_Home: + case XK_KP_Home: dia->cursor = 0; break; case XK_End: + case XK_KP_End: dia->cursor = CHARlen(dia->field[dia->current].value); break; @@ -916,6 +922,7 @@ static CHAR *keystring(dia, key) case '\177': case XK_Delete: + case XK_KP_Delete: if (dia->cursor < origlen) CHARcpy(&orig[dia->cursor], &orig[dia->cursor + 1]); break; @@ -955,6 +962,7 @@ static void keystroke(dia, key) case '\n': case XK_Linefeed: case XK_Return: + case XK_KP_Enter: /* store the values of all options */ eventfocus((GUIWIN *)dia->xw); for (i = 0; i < dia->nfields; i++) @@ -991,10 +999,12 @@ static void keystroke(dia, key) break; case XK_Up: + case XK_KP_Up: makecurrent(dia, dia->current - 1); break; case XK_Down: + case XK_KP_Down: makecurrent(dia, dia->current + 1); break; diff --git a/guix11/xevent.c b/guix11/xevent.c index f059ee7..c2035fe 100644 --- a/guix11/xevent.c +++ b/guix11/xevent.c @@ -343,7 +343,8 @@ void x_ev_process(event) if (!IsModifierKey(mykey) && mykey != XK_Mode_switch) { /* function keys become a control sequence */ - sprintf(text, "%c%04x", ELVCTRL('K'), (int)mykey); + sprintf(text, "%c%04x", ELVCTRL('K'), + mykey ? (int)mykey : event->xkey.keycode); i = strlen(text); } } diff --git a/guix11/xtext.c b/guix11/xtext.c index 37998c3..b620a85 100644 --- a/guix11/xtext.c +++ b/guix11/xtext.c @@ -152,7 +152,7 @@ void x_ta_drawcursor(xw) { x_ta_erasecursor(xw); } - else /* save the image of the cursor where we'll draw the cursor */ + else /* save the image of the character where we'll draw the cursor */ { if (xw->grexpose) { @@ -542,7 +542,8 @@ void x_ta_event(xw, event) x2 = (event->xexpose.x + event->xexpose.width - 1) / xw->ta.cellw; y2 = (event->xexpose.y + event->xexpose.height - 1) / xw->ta.cellh; eventexpose((GUIWIN *)xw, y, x, y2, x2); - x_ta_drawcursor(xw); /*!!!*/ + if (xw->ta.nextcursor != CURSOR_NONE) + x_ta_drawcursor(xw); break; case GraphicsExpose: diff --git a/input.c b/input.c index 72ea079..6f4a8d9 100644 --- a/input.c +++ b/input.c @@ -1,7 +1,7 @@ /* input.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_input[] = "$Id: input.c,v 2.63 1999/02/06 22:30:00 steve Exp $"; +char id_input[] = "$Id: input.c,v 2.65 1999/10/05 19:13:34 steve Exp $"; #include "elvis.h" @@ -142,7 +142,7 @@ static void addchar(cursor, top, bottom, info) /* This function attempts to expand an abbreviation at the cursor location, * if there is one. If so, it deletes the short form, and pushes the long - * form an following character back onto the type-ahead buffer. Else it + * form and following character back onto the type-ahead buffer. Else it * returns False. */ static BOOLEAN tryabbr(win, nextc) @@ -287,6 +287,20 @@ static RESULT perform(win) marksetoffset(state->bottom, markoffset(state->cursor)); } + /* if the "smarttab" option is set, and the cursor is in the line's + * indentation area, then INP_TAB is treated like INP_SHIFTR. + */ + if (o_smarttab && ii->cmd == INP_TAB) + { + scanalloc(&cp, state->cursor); + while (scanprev(&cp) && (*cp == '\t' || *cp == ' ')) + { + } + if (!cp || *cp == '\n') + ii->cmd = INP_SHIFTR; + scanfree(&cp); + } + /* process the keystroke */ switch (ii->cmd) { @@ -505,7 +519,7 @@ static RESULT perform(win) markaddoffset(tmp, -1); /* if previous char can't be in name, fail */ - if (CHARchr(toCHAR(" \t\n()<>"), scanchar(tmp))) + if (CHARchr(toCHAR("\t\n()<>"), scanchar(tmp))) { markfree(tmp); guibeep(win); @@ -516,29 +530,24 @@ static RESULT perform(win) littlecp = &name.partial[QTY(name.partial)]; *--littlecp = '\0'; ch = scanchar(tmp); - do + markaddoffset(tmp, -1L); + peek = scanchar(tmp); + while (markoffset(tmp) > markoffset(state->top) + && ch != '\n' && ch && ch != '\t' && + (!(ch == ' ' || ch == '<' || ch == '>' || ch == '(' || ch == ')') + || peek == '\\')) { *--littlecp = ch; - markaddoffset(tmp, -1L); - ch = (markoffset(tmp) >= markoffset(state->top)) ? scanchar(tmp) : '\n'; - if (markoffset(tmp) - 1 >= markoffset(state->top)) - { - from = *tmp; - markaddoffset(&from, -1L); - peek = scanchar(&from); - } - else - peek = 'x'; /* not backslash */ - } while (ch != '\n' && ch && ch != '\t' && - (!(ch == ' ' || ch == '<' || ch == '>' || ch == '(' || ch == ')') - || peek == '\\')); - markaddoffset(tmp, 1); + ch = peek; + markaddoffset(tmp, -1); + if (markoffset(tmp) >= 0) + peek = scanchar(tmp); + } + markaddoffset(tmp, 2); /* try to expand the filename */ littlecp = iofilename(littlecp, - (ch == '(') ? ')' : - o_inputtab(markbuffer(cursor)) == 'e' ? ' ' : - '\t'); + (ch == '(') ? ')' : '\t'); if (!littlecp) { markfree(tmp); @@ -546,12 +555,24 @@ static RESULT perform(win) break; } - /* name found -- replace old word with expanded name */ + /* name found -- replace old word with expanded + * name. Note that we need to convert from + * char[] to CHAR[], and add backslashes before + * certain characters. + */ for (cp = name.full, col = 0; - (*cp++ = *littlecp++) != '\0'; /* yes, ASSIGNMENT! */ - col++) + *littlecp != '\0'; + littlecp++, col++) { + if (strchr(" <>#%", *littlecp) != NULL + || (littlecp[0] == '\\' && !isalnum(littlecp[1]) && littlecp[1] != '\0')) + *cp++ = '\\', col++; + if (*littlecp == '\t') + *cp++ = ' '; + else + *cp++ = *littlecp; } + *cp = '\0'; bufreplace(tmp, win->state->bottom, name.full, col); marksetoffset(cursor, markoffset(tmp) + col); marksetoffset(win->state->bottom, markoffset(cursor)); diff --git a/io.c b/io.c index 33c9293..8b327d1 100644 --- a/io.c +++ b/io.c @@ -1,7 +1,7 @@ /* io.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_io[] = "$Id: io.c,v 2.43 1998/11/25 01:27:09 steve Exp $"; +char id_io[] = "$Id: io.c,v 2.45 1999/10/12 21:33:09 steve Exp $"; #include "elvis.h" @@ -557,6 +557,11 @@ char *iopath(path, filename, usefile) strcpy(name, tochar8(o_home)); i = strlen(name); next++; + + /* bug in MS network, we don't want \\ in filename */ + if (i > 0 && (name[i-1] == '/' || name[i-1] == '\\') && + next != NULL && (*next == '/' || *next == '\\')) + i--; } /* else if path element starts with "./" then use the current * file's directory. (unless there is no current file) @@ -737,13 +742,6 @@ char *iofilename(partial, endchar) if (dirperm(match) == DIR_NOTFILE) endchar = (char)*slash; - /* quote the dangerous chars */ - match[matchlen] = '\0'; - str = addquotes(dangerous, toCHAR(match)); - strncpy(match, tochar8(str), QTY(match) - 1); - match[QTY(match) - 1] = '\0'; - matchlen = strlen(match); - /* append a tab or slash, and return it */ match[matchlen] = endchar; match[matchlen + 1] = '\0'; diff --git a/lib/elvis.ali b/lib/elvis.ali index 646717d..1978c42 100644 --- a/lib/elvis.ali +++ b/lib/elvis.ali @@ -1,6 +1,6 @@ -if os=="unix" -then alias lf !!ls -CF -else alias lf !!dir/w +switch os +case unix alias lf !!ls -CF +default alias lf !!dir/w alias pwd calc getcwd("!*") @@ -137,7 +137,7 @@ alias cbshow { local a b c i=1 l="!*" q u s if l == "" then let l = "abcdefghijklmnopqrstuvwxyz123456789" - echo Buf Size & Type Contents + echo Buf\| Size & Type \| Contents echo ---+-------------+---------------------------------------------------- while i <= strlen(l) do { @@ -149,7 +149,7 @@ alias cbshow { eval (a) let u = putstyle << 4; eval (a) let q = u=="char" ? bufchars - 1 : buflines let s = q; " "; u; (q == 1 ? " " : "s") - eval (a) calc " "; c; " |"; s >> 12; " |"line\(b,1\) << 52 + eval (a) calc " "; c; " |"; s >> 12; " | "line\(b,1\) << 52 } let i = i + 1 } @@ -270,6 +270,90 @@ alias wascii { !% lp!? !* } +alias makehtml { + "Convert plain text to HTML source + local report=0 m=text n=text b=false + " + " m is current line mode -- one of "text", "pre", "ol", or "ul" + " n is next line mode + " b is a flag for detecting series of blank lines. + " + " For each line... + !%g /^/ { + " Protect characters which are special to HTML + try s/&/\&/g + try s//\>/g + " + " Convert uppercase lines into headings + try s/^[A-Z0-9][A-Z0-9-.) ]*$/

    &<\/h1>/ + then set n=text + " + " Convert horizontal lines into
    tags + try s/^\s*[-=]\{10,}\s*$/
    / + then set n=text + " + " Try to be clever about finding links + try s/http:[^">, )]\+/
    &<\/a>/g + try s/ftp:[^">, )]\+/&<\/a>/g + try s/[a-zA-Z]\w*@[a-zA-Z][[:alnum:].-]\+/&<\/a>/g + " + " Convert asterisked lines into "ul" list items. + try s/^\s*\* */
  • / + then set n=ul + " + " Convert numbered lines (other than headings) into "ol" list items. + try s/^\s*\d\+[.)] \+/
  • + then set n=ol + " + " if in normal text, then assume indented text is preformatted. + if m=="text" + then { + try s/^\s/set n=pre/x + } + " + " if in preformatted text, then assume non-indented line ends
     block
    +  if m=="pre" && n=="pre"
    +  then {
    +   try s/^\S/set n=text/x
    +  }
    +  "
    +  " Any non-blank line turns off the "b" flag.
    +  try s/./set b=false/x
    +  "
    +  " if not in formatted text, then blank lines are paragraph breaks.  Avoid
    +  " consecutive 

    tags, though. + if m!="pre" && b=="false" + then { + try s/^$/

    / + then set b=true + } + " + " if mode switched, then add tags for that. + if m!=n + then { + if m!="text" + then eval i + if n!="text" + then eval i <(n)> + let m=n + set b=false + } + } + " + " If converting the whole file, then add ... + if "!%" == "" + then { + $a + eval 1i (htmlsafe(filename)) + " + " minor conveniences... + set bufdisplay=html + display html + eval file (dirdir(filename)/basename(filename)).html + } +} + """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " The following were contributed by Ian Utley (iu@apertus.uk.com) @@ -381,7 +465,7 @@ alias match { let a=current("word") if (a == "") then error Cursor is not on a word - while d=="" && x!="." + while b=="" && x!="." do { if a==dirfile(x) then { diff --git a/lib/elvis.arf b/lib/elvis.arf index f10d996..3249fc9 100644 --- a/lib/elvis.arf +++ b/lib/elvis.arf @@ -1,10 +1,8 @@ """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " SAVE THE CURRENT STATE OF THE "saveregexp" OPTION -let s=saveregexp -set nosaveregexp +local nosaveregexp """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " TAKE A GUESS AT THE BUFFER'S PREFERRED DISPLAY MODE -let e=tolower(dirext(filename)) if knownsyntax(filename) then set! bufdisplay=syntax if os=="unix" && buflines >= 1 @@ -19,28 +17,26 @@ if !newfile then { if readeol=="binary" && bufdisplay=="normal" then set! bufdisplay=hex - if e==".man" - then set! bufdisplay=man - if strlen(e)==2 && isnumber(e>>1) && buflines>=1 - then 1s/^\./set! bufdisplay=man/x - if e==".tex" - then set! bufdisplay=tex - if e<<4==".htm" || e==".shtml" || e==".dhtml" - then set! bufdisplay=html - if e<<4==".sgm" - then set! bufdisplay="html sgml" + switch tolower(dirext(filename)) + case .man set! bufdisplay=man + case .tex set! bufdisplay=tex + case .htm + case .html + case .shtml + case .dhtml set! bufdisplay=html if buflines >= 1 && bufdisplay=="hex" then 1s/^<[HIThit!]/set! bufdisplay=html/x - if (filename<<5=="http:" || filename<<4=="ftp:") && strlen(e)<4 && bd=="hex" + if (filename<<5=="http:" || filename<<4=="ftp:") && strlen(dirext(filename))<4 && bd=="hex" then set! bufdisplay=normal if bufdisplay=="normal" && buflines >= 1 then 1s/^From .*/set! bufdisplay="syntax email"/x if dirdir(filename)=="/tmp" || dirdir(filename)=="/var/tmp" then set! bufdisplay="syntax email" + if strlen(dirext(filename))==2 && isnumber(filename>>1) && buflines>=1 + then 1s/^\./set! bufdisplay=man/x } if bufdisplay=="html" && readonly then set locked -set e="" """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " Some messages if tolower(basename(program))!="elvis" && !ro && (bd=="html" || bd=="man" || bd="tex") @@ -56,8 +52,3 @@ then { eval 1,(modelines)s/[ev][xi]:\\\(.*\\\):/\1/x eval (buflines - modelines + 1),(buflines)s/[ev][xi]:\\\(.*\\\):/\1/x } -""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" -" RESTORE THE "saveregexp" OPTION -if s -then set saveregexp -set s="" diff --git a/lib/elvis.bwf b/lib/elvis.bwf index c1c9bce..1acf232 100644 --- a/lib/elvis.bwf +++ b/lib/elvis.bwf @@ -1,6 +1,6 @@ if backup && !newfile then { - if os=="unix" - then eval ! cp (filename) (filename).bak - else eval ! copy (filename) (basename(filename)).bak >NUL + switch os + case unix eval ! cp (filename) (filename).bak + default eval ! copy (filename) (dirname(filename) / basename(filename)).bak >NUL } diff --git a/lib/elvis.html b/lib/elvis.html index ec6a3c3..820005a 100644 --- a/lib/elvis.html +++ b/lib/elvis.html @@ -54,7 +54,8 @@

    TABLE OF CONTENTS

    ^--------------------------------------------------------------^
    -

    You can contact the author via e-mail at kirkenda@cs.pdx.edu, +

    You can contact the author via e-mail at +kirkenda@cs.pdx.edu, or via postal mail at:

    Steve Kirkendall
    @@ -63,6 +64,10 @@

    TABLE OF CONTENTS

    USA
    +

    If you require technical support, you may get a quicker response by +posting a message to the comp.editors +newsgroup. +

    1. WHAT IS ELVIS?

    Elvis is a clone of vi/ex, the standard UNIX editor. Elvis supports nearly all of the vi/ex commands, diff --git a/lib/elvis.ini b/lib/elvis.ini index fe8a4b6..b30e1e5 100644 --- a/lib/elvis.ini +++ b/lib/elvis.ini @@ -6,14 +6,12 @@ else source! (elvispath("elvis.lat")) " """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " CHOOSE SOME DEFAULT OPTION VALUES BASED ON THE INVOCATION NAME -let p=tolower(basename(program)) -if p == "ex" || p == "edit" -then set! initialstate=ex -if p == "view" -then set! defaultreadonly -if p == "edit" || p == "vedit" -then set! novice -set p="" +switch tolower(basename(program)) +case ex +case edit set! initialstate=ex +case view set! defaultreadonly +case edit +case vedit set! novice if home == "" then let home=dirdir(program) " @@ -25,10 +23,11 @@ then source! (elvispath("elvis.ali")) """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " SYSTEM TWEAKS GO HERE " -" The Linux console can't handle colors and underlining. +" The Linux console can't handle colors and underlining. Neither can MS-DOS +" with any of the ANSI drivers. if gui=="termcap" then { - if term=="linux" + if term=="linux" || (os=="msdos" && (term>>4)=="ansi") then set! nottyunderline } " @@ -41,6 +40,21 @@ then { color u blue color f red } +if os == "os2" && gui != "x11" +then { + if $TERM != "xterm" + then color n white + else color n black + color e green + color i magenta + color u blue + color f red + set ul=20 + set ruler + set showmatch + set showmode + set autoindent +} " """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" " X11 DEFAULT COLORS AND TOOLBAR GO HERE (may be overridden in .exrc file) @@ -53,7 +67,6 @@ let f=(os=="unix" ? ".elvisrc" : "elvis.rc") if $EXINIT then eval $EXINIT else source! (exists(home/f)?home/f:home/".exrc") -" ÷÷÷ PROCURA source! ~/.elvislib/elvis.rc if exrc && getcwd()!=home then safer! (exists(f)?f:".exrc") @@ -63,24 +76,23 @@ set f="" " X11 INTERFACE DEFAULT FONTS GO HERE if gui == "x11" then { + if normalfont == "" && xrootwidth >= 1024 + then { + set! normalfont="*-courier-medium-r-*-18-*" + set! boldfont="*-courier-bold-r-*-18-*" + set! italicfont="*-courier-medium-o-*-18-*" + } + if normalfont == "" && xrootwidth >= 800 + then { + set! normalfont="*-courier-medium-r-*-14-*" + set! boldfont="*-courier-bold-r-*-14-*" + set! italicfont="*-courier-medium-o-*-14-*" + } if normalfont == "" - then set! normalfont="*-courier-medium-r-*-18-*" - then set! boldfont="*-courier-bold-r-*-18-*" - then set! italicfont="*-courier-medium-o-*-18-*" + then { + set! normalfont="*-courier-medium-r-*-12-*" + set! boldfont="*-courier-bold-r-*-12-*" + set! italicfont="*-courier-medium-o-*-12-*" + } } " -if os == "os2" && gui != "x11" -then { - if $TERM != "xterm" - then color n white - else color n black - color e green - color i magenta - color u blue - color f red - set ul=20 - set ruler - set showmatch - set showmode - set autoindent -} diff --git a/lib/elvis.man b/lib/elvis.man index 6ff7fd7..a674388 100644 --- a/lib/elvis.man +++ b/lib/elvis.man @@ -9,8 +9,8 @@ elvis \- a clone of the ex/vi text editor .RB [ -R ] .RB [ -e ] .RB [ -i ] -.RB [ -s ] -.RB [ -S | - ] +.RB [ -S ] +.RB [ -s | - ] .RB [ -f .IR session ] .RB [ -o diff --git a/lib/elvis.syn b/lib/elvis.syn index 5e412c9..0ab6568 100644 --- a/lib/elvis.syn +++ b/lib/elvis.syn @@ -198,8 +198,8 @@ other allcaps initialcaps # line exists to prevent $# from being interpreted as a plain dollar sign # followed by a comment. language perl -extension .pl .pm -keyword BEGIN END CORE __END__ __FILE__ __LINE__ AUTOLOAD DESTROY +extension .pl .pm .PL +keyword BEGIN END CORE __END__ __FILE__ __LINE__ AUTOLOAD DESTROY INIT keyword abs accept alarm and atan2 bind binmode bless caller chdir chmod keyword chomp chop chown chr chroot close closedir cmp connect continue cos keyword crypt dbmclose dbmopen defined delete die do dump each else elsif @@ -220,22 +220,23 @@ keyword rmdir s scalar seek seekdir select semctl semget semop send setgrent keyword sethostent setnetent setpgrp setpriority setprotoent setpwent keyword setservent setsockopt shift shmctl shmget shmread shmwrite shutdown keyword sin sleep socket socketpair sort splice split sprintf sqrt srand -keyword stat study sub substr symlink syscall sysread system syswrite tell -keyword telldir tie time times tr truncate uc ucfirst umask undef unless +keyword stat study sub substr symlink syscall sysopen sysread system syswrite +keyword tell telldir tie time times tr truncate uc ucfirst umask undef unless keyword unlink unpack unshift untie until use utime values vec wait waitpid keyword wantarray warn while write x xor y comment # function ( startword &_@%$ -inword _'# +inword _' string " strnewline empty character ' regexp /?#: -useregexp if unless while until m qr (,~&| +useregexp if unless while until split m qr (,~&| useregsub s tr other allcaps -font e ( ) { } +font emphasized ( ) { } +font normal $" $# # TCL shell scripts. # Contributed by Jeff Wang (jeffw@advance.com) @@ -552,26 +553,27 @@ inword _ # enough. The particular variation shown here works okay for aliases. language ex extension .ex .exrc .elvisrc elvis.ini elvis.brf elvis.arf elvis.bwf elvis.awf elvis.ali -keyword a ab abbr abbreviate all alias append ar args b bb bbrowse br bre break -keyword browse buffer c ca calc calculate cc cd change chd chdir cl close -keyword co col color copy d delete di dig digraph dis display do e ec echo -keyword edit el else er err errlist erro error ev eval ex f file g global -keyword go goto gu gui h help i if insert j join k l la last le let list lo -keyword local lp lpr m ma mak make map mark me message mk mkexrc move n N new -keyword next Next no normal nu number o open p po pop pre previous print -keyword pu put q qa qall quit r read red redo rew rewind s sN sNext sa saf -keyword safer sall sb sbb sbbrowse sbr sbrowse se set sh shell sl slast sn -keyword sne snew snext so source sp split sre srew srewind st sta stac -keyword stack stag stop subst substitute sus susp suspend t ta tag th then -keyword to try u una unab unabbr unabbreviate unb unbreak undo unm unmap v -keyword ve version vglobal vi visual w wa warning wh while wi window wn +keyword a ab abbr abbreviate all alias append ar args b bb bbrowse br bre +keyword break browse buffer c ca calc calculate case cc cd change chd +keyword chdir cl close co col color copy d default delete di dig digraph +keyword dis display do e ec echo edit el else er err errlist erro error +keyword ev eval ex f file g global go goto gu gui h help i if insert j +keyword join k l la last le let list lo local lp lpr m ma mak make map +keyword mark me message mk mkexrc move n N new next Next no normal nu +keyword number o open p po pop pre previous print pu put q qa qall quit r +keyword read red redo rew rewind s sN sNext sa saf safer sall sb sbb +keyword sbbrowse sbr sbrowse se set sh shell sl slast sn sne snew snext +keyword so source sp split sre srew srewind st sta stac stack stag stop +keyword subst substitute sus susp suspend switch t ta tag th then to try +keyword u una unab unabbr unabbreviate unb unbreak undo unm unmap v ve +keyword version vglobal vi visual w wa warning wh while wi window wn keyword wnext wq wquit write x xit y yank z anchor ^ " # & ( < = > @ ~ # note that ! is not listed as a keyword because it interferes with alias args comment " -regexp /?;: +regexp /? useregsub s -useregexp , g v global vglobal +useregexp , ; g v global vglobal font fixed !0 !1 !2 !3 !4 !5 !6 !7 !8 !9 !^ !$ !* !< !> !% !! !? font fixed 'a 'b 'c 'd 'e 'f 'g 'h 'i 'j 'k 'l 'm 'n 'o 'p 'q 'r 's 't 'u 'v font fixed 'w 'x 'y 'z % $ @@ -730,7 +732,7 @@ keyword LIST_UPPER_BOUNDS LOCAL LOCATION LOCKED_IN_CACHE LOWER LOW_INTENSITY keyword MATRIX MENU_LABEL MULTI_VALUED keyword NEXT NEXT_FIELD NEXT_FORM NEXT_RECORD NO_CONSISTENCY NONE NOT NULL NUMBER_OF_ARRAYS NUMERIC keyword OCCURRENCES ON OPERATION OR ORDER ORDERED_BY OUTPUT -keyword PAGE PIPELINE PREVIOUS_FIELD PREV_FORM PREVIOUS_FORM PREVIOUS_RECORD PREVIOUS +keyword PAGE PIPELINE PREV_FIELD PREVIOUS_FIELD PREV_FORM PREVIOUS_FORM PREVIOUS_RECORD PREVIOUS keyword QUEUE keyword RECORD RECORD_CONSISTENCY REF REFERENCE REFRESH REJECT REPAINT REPEAT keyword REPEATED REQUIRED RESTART RESULT RETRIEVE RETRIEVE_VALUE RETURN REVERSE @@ -1105,3 +1107,68 @@ character &. startword :. inword string ' + +# GNU Texinfo -- FSF documentation system +# Contributed by Thomas Esken , 1999. +language texinfo +extension .texinfo .texi .txi +keyword { } @! @* @, @- @. @: @? @@ @{ @} @" @' @= @^ @` @~ +keyword @AA @aa @acronym @AE @ae @afourlatex @afourpaper @alias +keyword @anchor @appendix @appendixsec @appendixsection @appendixsubsec +keyword @appendixsubsubsec @asis @author +keyword @b @bullet @bye +keyword @c @cartouche @center @centerchap @chapheading @chapter @cindex +keyword @cite @clear @code @columnfractions @command @comment @contents +keyword @copyright @cropmarks +keyword @defcodeindex @defcv @deffn @deffnx @defindex @defivar @definfoenclose +keyword @defmac @defmethod @defop @defopt @defspec @deftp @deftypefn +keyword @deftypefun @deftypeivar @deftypeop @deftypevar @deftypevr @defun +keyword @defvar @defvr @dfn @dircategory @direntry @display @dmn +keyword @documentencoding @documentlanguage @dotaccent @dotless @dots +keyword @email @emph @end @enddots @enumerate @env @equiv @error @evenfooting +keyword @evenheading @everyfooting @everyheading @example @exampleindent +keyword @exclamdown @exdent @expansion +keyword @file @finalout @findex @flushleft @flushright +keyword @footnote @footnotestyle @format @ftable +keyword @group +keyword @H @heading @headings @html @hyphenation +keyword @i @ifclear @ifhtml @ifinfo @ifnothtml @ifnotinfo @ifnottex @ifset +keyword @iftex @ignore @image @include @inforef @item @itemize @itemx +keyword @kbd @kbdinputstyle @key @kindex @L @l @lisp @lowersections +keyword @macro @majorheading @math @menu @minus @multitable +keyword @need @node @noindent @novalidate +keyword @O @o @oddfooting @oddheading @OE @oe @option +keyword @page @pagesizes @paragraphindent @pindex +keyword @point @pounds @print @printindex @pxref +keyword @questiondown @quotation +keyword @r @raisesections @result @ref @refill @ringaccent @rmacro +keyword @samp @sc @section @set @setchapternewpage @setcontentsaftertitlepage +keyword @setfilename @setshortcontentsaftertitlepage @settitle @shortcontents +keyword @shorttitlepage @smallbook @smalldisplay @smallexample @smallformat +keyword @smalllisp @sp @ss @strong @subheading @subsection @subsubheading +keyword @subsubsection @subtitle @summarycontents @syncodeindex @synindex +keyword @t @tab @table @TeX @tex @thischapter @thischaptername +keyword @thisfile @thispage @thistitle @tieaccent @tindex @title +keyword @titlefont @titlepage @today @top +keyword @u @ubaraccent @udotaccent @unmacro @unnumbered @unnumberedsec +keyword @unnumberedsubsec @unnumberedsubsubsec @uref @url +keyword @v @value @var @vindex @vskip @vtable +keyword @w +keyword @xref +startword @ + +# GNU M4 macro processing language. +# Contributed by Thomas Esken , 1999. +language m4 +extension .m4 +comment # +keyword ( ) [ ] +keyword builtin changecom changequote debugfile decr define defn divert divnum +keyword dnl dumpdef errprint esyscmd eval format ifdef ifelse include incr +keyword index indir len m4exit m4wrap macro maketemp patsubst popdef pushdef +keyword regexp traceon traceoff shift sinclude substr syscmf sysval translit +keyword undefine undivert __file__ __line__ +function ( +string ` ' +startword _ +inword _ diff --git a/lib/elvisex.html b/lib/elvisex.html index 6b68969..e8bf341 100644 --- a/lib/elvisex.html +++ b/lib/elvisex.html @@ -1363,6 +1363,9 @@

    4.3.14 Configuration

    | | try | excmds | | | wh[ile] | expr | | | do | excmds | +| | switch | expr | +| | case | value [excmds] | +| | default | excmds | | | mk[exrc][!] | [file] | ^-------^-------------------^-----------------------------------^ @@ -1627,8 +1630,38 @@

    4.3.14 Configuration

    let i=i+1 } -

    Both the :if/:then/:else and :while/:do command -structures permit nesting. I.e., the commands in a :then command +

    +The :switch command evaluates an expression and stores the result. +The :case command compares that result to a given value, and executes +an ex command line if it matches. +If you omit the command line then it will carry forward to the next :case which does have an +ex command line; this allows multiple cases to share a single +ex command line. +The :default command executes its ex command line if no previous case +was matched. +Here's an example: +

    +	:switch os
    +	:case unix
    +	:case win32 echo Elvis has graphical and text-mode interfaces.
    +	:case os2 {
    +	 echo Elvis has been ported natively as a text-mode program.
    +	 echo You can also compile it to use the X11 interface from
    +	 echo Unix, but you need the EMX libraries to run it.
    +	}
    +	:case msdos echo Elvis is slow and ugly under DOS.
    +	:default echo How are you even running this?
    +
    + +Notice that there is no punctuation after the case value, and that there is +no "break" or "endswitch" command. +This example says "Elvis has graphical and text mode interfaces" for both +the "unix" and "win32" cases; the "unix" case has no command, so it falls +through to the "win32" case. + +

    The :if/:then/:else, :while/:do, and +:switch/:case/:default command structures all permit nesting. +I.e., the commands in a :then command can't affect the "if" variable to cause the :else command to also be executed. diff --git a/lib/elvisopt.html b/lib/elvisopt.html index 38ac4bf..fd008a5 100644 --- a/lib/elvisopt.html +++ b/lib/elvisopt.html @@ -362,6 +362,7 @@

    6.1.4 Options that affect input mode

    |---------------------|---------|--------|-----------------------------| | autoindent, ai | Boolean | buf | auto-indent new text | | inputtab, it | One-Of | buf | input mode's (Tab) key | +| smarttab, sta | Boolean | global | if indenting, (Tab) shifts | | completebinary, cob | Boolean | global | complete names of binaries? | | autotab, at | Boolean | buf | allow autoindent to use '\t'| | tabstop, ts | Number | buf | width of tabstop columns | @@ -400,6 +401,15 @@

    6.1.4 Options that affect input mode

    which is used for entering in ex commands. +

    The smarttab option only affects the +behavior of the Tab key in input mode, +when the cursor is in the indentation portion of a line +-- before the first nonwhitespace character. +If this option is true, then Tab is treated like ^T, +so the line is shifted rightward by one shiftwidth. +By default this option is false, so the Tab key is treated normally +(in accordance with the The completebinary option controls whether binary files are included in the list of possible filename completions. The default setting is nocompletebinary, so binary files are @@ -1789,6 +1799,7 @@

    6.1.20 Printing options

    | cr | Line printers, overtypes via carriage-return| | bs | Overtypes via backspace, like nroff | | dumb | Plain ASCII, no font control | + | html | HTML source code | |-- --- --|-- --- --- --- --- --- --- --- --- --- --- --| | windows | The Win32 print facility (in WinElvis only) | ^---------^---------------------------------------------^ @@ -2202,6 +2213,7 @@

    6.2 Alphabetical list of options

    | showstack, sstk | Boolean | win | display some debugging info | | showtag, st | Boolean | global | display tag on status line | | sidescroll, ss | Number | win | sideways scrolling amount | +| smarttab, sta | Boolean | global | if indenting, (Tab) shifts | | stagger | Number | x11 | offset for next new window | | statusbar, xstat | Boolean | x11 | enables the statusbar | | stringfont, sfont | One-Of | syntax | font used for strings | diff --git a/lib/elvisos.html b/lib/elvisos.html index 5ab32fc..54fbc73 100644 --- a/lib/elvisos.html +++ b/lib/elvisos.html @@ -224,7 +224,7 @@

    9.2 MS-Windows95/MS-WindowsNT

    The "TERM" environment variable
    The TERM environment variable tells elvis how to access the screen. -It should probably be left undefined, or set to "console". +It should probably be left undefined, or set to "console" or "cygwin". Other values have not been tested, but the following should work via terminal emulators or whatever: dosansi, nansi, vt100, vt100w, and vt52. @@ -284,6 +284,30 @@

    9.2 MS-Windows95/MS-WindowsNT

    When you switch back to full-screen mode again it will look exactly the same, but the mouse should be able to go where no mouse has gone before. +
    Cygwin +
    If you use Cygwin's mount +utility to define a mount table, then elvis will try to use it. +I say "try to" because that table is maintained in the Win32 registry, +and although elvis can handle the current version of Cygwin, later versions +may move the mount table to somewhere that elvis can't find. +Elvis doesn't use the normal Cygwin functions for mapping file names via +the mount table, because I didn't want to make elvis be dependant upon +the CYGWIN.DLL library; +instead, elvis uses standard Win32 registry functions to read the mount table. +use t + +

    Only elvis has been modified to use the mount table. +The other utilities (such as ctags, +fmt, and elvis' version of ls) +will ignore the mount table. +Also, even elvis will ignore it with respect to the names of the session +file and temporary files (the session, +sessionpath, +and directory options). +

    Some problems have been reported when running the text-mode version of +elvis via the bash shell. +I'm trying to fix that. +The graphical version of elvis works fine, though.

    9.3 OS/2

    diff --git a/lib/elvisses.html b/lib/elvisses.html index 44807c7..5131151 100644 --- a/lib/elvisses.html +++ b/lib/elvisses.html @@ -471,6 +471,8 @@

    10.4 Other files

    This contains a rough list of nearly all of elvis' terse messages. You can use this as a resource when constructing an elvis.msg file. +The idea here is that you'll copy a line from elvistrs.msg into elvis.msg, +and then append a ":" and the new message text.
    elvis.net
    This tells elvis which sites can be accessed directly, and which can diff --git a/lib/elvistip.html b/lib/elvistip.html index f3fc9e0..ad4c61f 100644 --- a/lib/elvistip.html +++ b/lib/elvistip.html @@ -130,10 +130,10 @@

    16.1 Information via the Web

    Sadly, it is one of those rare programs that doesn't handle tab characters correctly. -
    -http://www.cygnus.com/ -
    This is the home page for Cygnus, which makes the CygWin -tools -- ports of GNU utilities to Microsoft Windows. +
    +http://sourceware.cygnus.com/cygwin/ +
    This is the home page for the CygWin +tools -- ports of GNU utilities to Microsoft Windows, by Cygnus. If you're looking for more Unix utilities to go with elvis, this is the place.
    @@ -488,7 +488,7 @@

    16.4 Running your compiler from within elvis

    NOTE: You can't simply cut&paste the above perl script into a file, because it contains some HTML code which PERL wouldn't understand. (The diamond is written as "&lt;&gt;".) A better way -is to use the visually select those lines via the +is to visually select those lines via the shift-V command, and then use the :wascii alias to save the formatted text to a file as plain ASCII text. @@ -833,6 +833,15 @@

    16.6.1 Some example aliases

    It works by temporarily setting lptype to "dumb", and then writing the text via :lp. +
    :[range]makehtml +
    Convert plain text into HTML source. +By default it acts on the whole edit buffer, +but you can also tell it to convert only the lines in a given range. +Uppercase lines are assumed to be headings. +Lines which start with a number or asterisk are assumed to be list items. +Indented lines are assumed to be preformatted text. +It also attempts to create a link for each URL or email address in the text. +
    :[range]cfmt
    Adjust the line breaks in a C or C++ comment block. diff --git a/lib/elvisvi.html b/lib/elvisvi.html index 7295077..35ef834 100644 --- a/lib/elvisvi.html +++ b/lib/elvisvi.html @@ -799,10 +799,21 @@

    2.2.11 Scrolling commands

    z key
    -This command scrolls the current line to either the -top (if key is "+"), -middle (if key is "." or "z"), -or bottom (if key is "-") of the window. +This command scrolls to bring the current line to either the +top (for z+) +middle (for z.) +or bottom (for z-) of the window. +You can also precede this command with a line number, in which case the +cursor is moved to that line before the scrolling takes place; e.g., +98z+ will move the cursor to line 98 and then scroll as necessary +to bring 98 to the top of the window. + +

    Elvis also supports zH, zM, and zL +as synonyms for those commands. +These may be easier to remember, because they are somewhat analogous to +the H, M, and L commands. +In addition, zz is an easy-to-type synonym for scrolling a +line to middle of the window.

    count ^D
    count ^E diff --git a/lib/howto.html b/lib/howto.html index 597020f..eba25ea 100644 --- a/lib/howto.html +++ b/lib/howto.html @@ -21,6 +21,8 @@

    C. How to...

    - The "windows" user interface
  • Miscellany - Things that didn't fit anywhere else +
  • Contacts +- How to contact the authors

    If you're using elvis to view this file, you can search for a topic @@ -40,7 +42,7 @@

    C. How to...

    contains a "howto" alias which loads this file and searches for a given topic. The aliases from that file are loaded automatically, so you should be able to display any topic in a -a separate window with via a command such as this: +a separate window via a command such as this:
     	:howto spaces
    @@ -399,7 +401,7 @@

    C.5 X-Windows

    Run an interactive program under X11
    Sadly, this can't be done with elvis' "x11" user interface -Because elvis' windows don't have a built-in terminal emulator. +because elvis' windows don't have a built-in terminal emulator. This is expected to be added for elvis 2.2, but that doesn't help you now. @@ -433,6 +435,13 @@

    C.6 Windows95/98/NT

    Click the left mouse button there to begin marking lines; hold the button as you move the mouse to the other end of the range of lines and then release it. + +
    Change the icon for WinElvis +
    WinElvis contains two icons -- a low-color version of the Elvis Presley +postage stamp, and a tiny photo of elvis. +The stamp is closer to the Unix icon for elvis, so that's the default. +If you prefer the photo, you can use it by creating a link to WinElvis, +viewing the link's properties, and clicking the "Change Icon" button there.

    C.7 Miscellany

    @@ -540,6 +549,157 @@

    C.7 Miscellany

    to look into the nonascii option. Also, on Unix systems you should verify that your terminal is configured correctly (8 bits, not 7 -- and the Latin-1 character set is installed). + +
    Change the default address range for a command +
    This is sometimes desirable in an alias. +For example the :s alters only one line +by default. +You may want to write a macro that uses both of them with the same default, +or just one of them with a different default. + +

    The most straightforward way to do this is to use the +!{default}% notation. +Specifically, !{.}% will make any command in an alias default +to using just the current line, and !{%}% will make any +command default to using all lines. + +

    Here's a simple word-counting alias which uses this technique to count +the words in all lines by default... +

    +	alias wcw {
    +	 local w=0
    +	 !{%}% s/\w\+/let w=w+1/gx
    +	 calc w
    +	}
    +
    + +
    Execute a particular command separately for each line in a range +
    The :g command does this, but only for +the lines which contain a given regular expression. +You can trick it into executing the command for every line by making it look +for something that every line has. +Since every line has a beginning, you can use :g/^/command to execute the command for every line. + +

    Note that the :g command can be used with +an address range. +This is often convenient. + +

    Here's an alias which uses this technique to search for the longest line +(assuming all characters are of equal width -- no tabs or control characters)... +

    +	alias widest {
    +	 local w=0 l
    +	 !%g/^/ {
    +	  if strlen(line()) > w
    +	  then let w = strlen(line())
    +	  then let l = current("line")
    +	 }
    +	 calc "Line "l" is the longest, at "w" characters."
    +	}
    +
    + +
    Convert plain text to HTML source +
    Other than the obvious (a long series of manual edit commands), +there are two ways that you can convert text to HTML in elvis. + +

    The most straightforward method is to build an alias which performs a series +of substitutions. +The problem with this method is that it must be rewritten for each type of +input text. +Here's an example of a fairly simple alias that converts plain text to HTML. +(There is a more powerful version of this alias in the standard distribution's +elvis.ali file.) +

    +	alias makehtml {
    +	 "Convert plain text to HTML
    +	 local report=0
    +	 "
    +	 "Protect characters which are special to 
    +	 try !(%)%s/&/\&amp;/g
    +	 try !(%)%s/</\&lt;/g
    +	 try !(%)%s/>/\&gt;/g
    +	 "
    +	 "Convert blank lines to <p> tags
    +	 try !(%)s/^$/<p>/
    +	 "
    +	 "If converting the whole file, then add <html>...</html>
    +	 if "!%" == ""
    +	 then {
    +	  $a </body></html>
    +	  1i <html><body>
    +	 }
    +	}
    +
    + +

    The other way is simpler and more versatile, but it requires the use of +an external file. +It uses the :lpr command with +lptype=html. +Since elvis' print mechanism supports all of elvis' display modes, +you can use this technique to convert any type of text (or even a hex dump +of a binary file) into HTML. + +

    +	:set lptype=html lplines=0 nolpheader
    +	:lp foo.html
    +
    + +
    Add new text around highlighted text, via a macro. +
    The main trick is to use the visual c command +to change the highlighted text, and then use ^P as part of the +replacement text. +While typing the replacement text, ^P causes a copy of the original +text to be inserted. +So, for example, the following macro could be used to and HTML <strong> +and </strong> tags around the highlighted text. +
    +	:map B c<strong>^P</strong>^[
    +
    +(Note: When typing that :map command into elvis, you'll need to type +<Ctrl-V><Ctrl-P> to get the ^P, and +<Ctrl-V><Esc> to get the ^[ character.) +
    + + + +

    C.8 Contacts

    + +
    + +
    Request technical support +
    The best way to get technical support is by posting a question on the +comp.editors newsgroup. +Be sure to mention "elvis" in the subject line, and try to include a succinct +description of the problem there, too. +In the body of the message, be sure to mention the version of elvis you're +using (as reported by "elvis --version"), and your operating system. + +
    Inform the authors about a bug +
    Bugs should be reported via e-mail. +You may not always receive prompt confirmation, but your bug reports are +appreciated, and acted-upon. +For OS-specific bugs, you should contact the person who ported elvis to your +operating system; the author's names and e-mail addresses are listed in the +Operating Systems chapter. + +

    For general bug reports, you should contact the primary author, +Steve Kirkendall, +at kirkenda@cs.pdx.edu. + +

    Either way, be sure to mention the version of elvis you're using +(as reported by "elvis --version"), and your operating system. + +

    Suggest a new feature +
    Contact the authors as though you were reporting a bug. +See above. + +
    Get the latest version of elvis +
    See the "Information via the Web" section of the +Tips chapter. +It has links to various elvis-related sites. +
    + diff --git a/lowbuf.c b/lowbuf.c index 9a592c4..c875146 100644 --- a/lowbuf.c +++ b/lowbuf.c @@ -1,7 +1,7 @@ /* lowbuf.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_lowbuf[] = "$Id: lowbuf.c,v 2.31 1998/11/25 01:28:06 steve Exp $"; +char id_lowbuf[] = "$Id: lowbuf.c,v 2.32 1999/10/01 19:39:27 steve Exp $"; /* This file contains functions which divide the session file into several * buffers. These functions use session.c, and are used by buffer.c @@ -888,19 +888,21 @@ long lowline(bufinfo, lineno) * value will be 0. */ BLKNO lowoffset(bufinfo, offset, left, right, lptr, linenum) - _BLKNO_ bufinfo; /* BUFINFO of the lowbuf */ - long offset; /* offset into the buffer */ - COUNT *left; /* output: number of preceding bytes in CHARS block */ - COUNT *right; /* output: number of following bytes in CHARS block */ - LBLKNO *lptr; /* output: logical block number of CHARS block */ - long *linenum; /* output: line number */ + _BLKNO_ bufinfo; /* BUFINFO of the lowbuf */ + long offset; /* offset into the buffer */ + COUNT *left; /* output: number of preceding bytes in CHARS block */ + COUNT *right; /* output: number of following bytes in CHARS block */ + LBLKNO *lptr; /* output: logical block number of CHARS block */ + long *linenum;/* output: line number */ { BLKNO blklist;/* used for stepping from one blklist to next */ BLKNO next; /* the next blklist block, after this one */ LBLKNO lblkno; /* counts overall LBLKNO of the given offset */ long lnum; /* counts newlines */ + BLK *blk; /* contents of a bufinfo or blklist block */ register int i; /* used for scanning through blklist.blk[] */ - register BLK *blk; /* contents of a bufinfo or blklist block */ + register struct blki_s *blki; + BLKNO maxblklist = SES_MAXBLKLIST; /* treat negative offsets as 0 */ if (offset < 0) @@ -926,24 +928,26 @@ BLKNO lowoffset(bufinfo, offset, left, right, lptr, linenum) } /* for each blklist... */ - for (lblkno = 0, lnum = 1; ; lblkno += SES_MAXBLKLIST, blklist = next) + for (lblkno = 0, lnum = 1; ; lblkno += maxblklist, blklist = next) { assert(blklist != 0); /* for each element of blklist->blk[]... */ seslock(blklist, False, SES_BLKLIST); blk = sesblk(blklist); - for (i = 0; i < SES_MAXBLKLIST && blk->blklist.blk[i].blkno; lnum += blk->blklist.blk[i].nlines, i++) + for (i = 0, blki = blk->blklist.blk; + i < maxblklist && blki->blkno; + lnum += blki->nlines, i++, blki++) { /* see if we've found it yet */ - offset -= blk->blklist.blk[i].nchars; + offset -= blki->nchars; if (offset < 0L) { - /* return the info */ - next = blk->blklist.blk[i].blkno; + /* Yes! Return the info */ + next = blki->blkno; sesunlock(blklist, False); if (lptr) *lptr = lblkno + i; - i = offset + blk->blklist.blk[i].nchars; + i = offset + blki->nchars; if (left) *left = i; if (right) *right = -offset; if (linenum) @@ -966,7 +970,7 @@ BLKNO lowoffset(bufinfo, offset, left, right, lptr, linenum) /* find the next blklist */ next = blk->blklist.next; - assert(!next || i == SES_MAXBLKLIST); + assert(!next || i == maxblklist); if (!next) { /* there is no next blklist block -- do the "*right = 0" * thing. */ diff --git a/lp.c b/lp.c index 569bab9..1f5f263 100644 --- a/lp.c +++ b/lp.c @@ -1,7 +1,7 @@ /* lp.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_lp[] = "$Id: lp.c,v 2.28 1997/11/02 18:54:45 steve Exp $"; +char id_lp[] = "$Id: lp.c,v 2.29 1999/09/30 18:17:56 steve Exp $"; /* This file contains generic printing code. */ @@ -19,7 +19,7 @@ static void draw(CHAR *p, long qty, _char_ font, long offset); /* This is a list of all known printer types. The first one is the default. */ -static LPTYPE *alltypes[] = {&lpepson, &lppana, &lpibm, &lphp, &lpdumb, &lpcr, &lpbs, &lpps, &lpps2, +static LPTYPE *alltypes[] = {&lpdumb, &lpepson, &lppana, &lpibm, &lphp, &lpcr, &lpbs, &lphtml, &lpps, &lpps2, #if defined (GUI_WIN32) &lpwindows, #endif diff --git a/lp.h b/lp.h index 18d743d..3057829 100644 --- a/lp.h +++ b/lp.h @@ -17,7 +17,7 @@ typedef struct BEGIN_EXTERNC extern RESULT lp P_((WINDOW win, MARK top, MARK bottom, BOOLEAN force)); END_EXTERNC -extern LPTYPE lpepson, lppana, lpibm, lphp, lpdumb; +extern LPTYPE lpepson, lppana, lpibm, lphp, lpdumb, lphtml; extern LPTYPE lpcr, lpbs; extern LPTYPE lpps, lpps2; #ifdef GUI_WIN32 diff --git a/lpescape.c b/lpescape.c index 9aaec70..21c6f39 100644 --- a/lpescape.c +++ b/lpescape.c @@ -1,7 +1,7 @@ /* lpescape.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_lpescape[] = "$Id: lpescape.c,v 2.14 1997/10/05 19:06:12 steve Exp $"; +char id_lpescape[] = "$Id: lpescape.c,v 2.16 1999/10/05 19:10:37 steve Exp $"; /* This file contains a driver for printer types which use escape sequences @@ -30,7 +30,8 @@ static char *codes[][9] = /*pana*/ {"E", "F", "-1", "-0", "4", "5", "\033t1", "\033t0", "\300\301\331\303\305\264\332\302\277\304\263\371"}, /*ibm*/ {"E", "F", "-1", "-0", "4", "5", NULL, NULL, "\300\301\331\303\305\264\332\302\277\304\263\371"}, /*hp*/ {"(s3B","(s0B","&d1D", "&d@", "(s1S", "(s0S", "\033(10U", NULL, "\300\301\331\303\305\264\332\302\277\304\263\371"}, -/*dumb*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "+++++++++-|*"} +/*dumb*/ {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "+++++++++-|*"}, +/*html*/ {"","", "", "", "", "", "
    ",	"
    \n", "+++++++++-|*"} }; /* This table is used for converting Latin-1 characters to PC-8 characters. @@ -81,7 +82,8 @@ static void endfont() } if (scan) { - (*prtchar)('\033'); + if (*scan != '<') + (*prtchar)('\033'); while (*scan) { (*prtchar)((_CHAR_)*scan); @@ -112,11 +114,15 @@ static void before(minorno, draw) (*prtchar)((_CHAR_)*scan); } - /* if the file appears to use Latin-1, and the lpconvert option is set, - * then set the convert pointer to point to the topc8[] array; else - * set the convert pointer to NULL. + /* If the file appears to use Latin-1, and the lpconvert option is set, + * and the printer type is a real printer (not "html") then set the + * convert pointer to point to the topc8[] array; else set the convert + * pointer to NULL. */ - if (o_lpconvert && digraph('A', 'E') == 0xc6) + if (o_lpconvert + && digraph('A', 'E') == 0xc6 + && *codes[ptype] + && **codes[ptype] != '<') { convert = topc8; } @@ -152,7 +158,8 @@ static void fontch(font, ch) } if (scan) { - (*prtchar)('\033'); + if (*scan != '<') + (*prtchar)('\033'); while (*scan) { (*prtchar)((_CHAR_)*scan); @@ -188,7 +195,24 @@ static void fontch(font, ch) ch = convert[ch - 0xa0]; } - /* output the character */ + /* Output the character. For HTML this may be tricky. */ + if (*codes[ptype] && **codes[ptype] == '<') + { + if (ch == '<') + scan = "<"; + else if (ch == '>') + scan = ">"; + else if (ch == '&') + scan = "&"; + else + scan = NULL; + if (scan) + { + while (*scan) + (*prtchar)(*scan++); + return; + } + } (*prtchar)(ch); } @@ -197,7 +221,8 @@ static void page(linesleft) int linesleft; /* number of lines remaining on page */ { /* output a formfeed character */ - (*prtchar)('\f'); + if (*codes[ptype] && **codes[ptype] != '<') + (*prtchar)('\f'); } /* This function is called at the end of the print job. It can output a @@ -216,7 +241,7 @@ static void after(linesleft) } /* and maybe output a formfeed, too */ - if (o_lpformfeed) + if (o_lpformfeed && *codes[ptype] && **codes[ptype] != '<') { (*prtchar)((_CHAR_)'\f'); } @@ -228,5 +253,6 @@ LPTYPE lppana = {"pana", 1, True, before, fontch, page, after}; LPTYPE lpibm = {"ibm", 2, True, before, fontch, page, after}; LPTYPE lphp = {"hp", 3, True, before, fontch, page, after}; LPTYPE lpdumb = {"dumb", 4, True, before, fontch, page, after}; +LPTYPE lphtml = {"html", 5, True, before, fontch, page, after}; #endif /* FEATURE_LPR */ diff --git a/makos2.cmd b/makos2.cmd index bff50be..419a448 100644 --- a/makos2.cmd +++ b/makos2.cmd @@ -1,19 +1,24 @@ @echo off if not exist osos2\config-with-tcp.h goto usage if "%1"=="" goto withtcp +if "%1"=="--with-tcp" goto withtcp if "%1"=="--no-tcp" goto notcp if "%1"=="--with-gcc" goto gcc if "%1"=="--with-emx" goto emx if "%1"=="--with-debug" goto debug if "%1"=="--with-x11" goto x11 +if "%1"=="--with-all" goto all +if "%1"=="package" goto package :usage -echo usage: makos2 [--no-tcp, --with-emx, --with-gcc] +echo usage: makos2 [--with-tcp --no-tcp --with-emx --with-x11 --with-gcc --with-all] echo the option "--no-tcp" will produce binaries not using the OS/2 TCP/IP APIs. echo the option "--with-gcc" is like "--no-tcp", but gcc is used instead of icc. echo the option "--with-emx" will use EMX including TCP/IP and Termcap. echo the option "--with-x11" will use EMX including TCP/IP, X11 and Termcap. -echo else the standard executables with http/ftp abilities will be built. +echo the option "--with-all" will run all of the above plus the INF docs. +echo else the standard executables with http/ftp abilities will be built, +echo like if "--with-tcp" was specified. echo this batch file must be started from within the elvis-2.1 directory. goto done @@ -23,42 +28,74 @@ copy osos2\config-no-tcp.h config.h echo deleting some object files, don't worry if they do not exist... del calc.obj dmmarkup.obj ex.obj http.obj io.obj osnet.obj url.obj ftp.obj buffer.obj echo building non-tcp/ip elvis... -make -f osos2\makefile.os2 ALL="elvis-no-tcp.exe ref.exe ctags.exe fmt.exe +make -f osos2\Makefile.os2 ALL="elvis-no-tcp.exe ref.exe ctags.exe fmt.exe goto done :gcc echo copying config file for non tcp/ip compile using gcc... copy osos2\config-no-tcp.h config.h echo building non-tcp/ip elvis with emx/gcc... -make -f osos2\makefile.os2 gcc +make -f osos2\Makefile.os2 gcc goto done :emx echo copying config file for emx version... copy osos2\config-with-tcp.h config.h echo building emx elvis with emx/gcc... -make -f osos2\makefile.os2 emx +make -f osos2\Makefile.os2 emx goto done :debug echo copying config file for debug version... copy osos2\config-with-tcp.h config.h echo building x11 elvis with emx/gcc... -make -f osos2\makefile.os2 debug +make -f osos2\Makefile.os2 debug goto done :x11 echo copying config file for x11 version... copy osos2\config-with-tcp.h config.h echo building x11 elvis with emx/gcc... -make -f osos2\makefile.os2 x11 +make -f osos2\Makefile.os2 x11 goto done :withtcp echo copying config file for tcp/ip compile... copy osos2\config-with-tcp.h config.h echo building elvis and misc programs... -make -f osos2\makefile.os2 all +make -f osos2\Makefile.os2 all goto done +:package +cd exeos2 +del *gcc.exe +cd .. +make -f osos2/Makefile.os2 elvis-2.1_4-os2.tar.gz +goto done + +:all +del *.obj *.o >nul +call makos2.cmd --with-tcp +if errorlevel 1 goto error +del *.obj >nul +call makos2.cmd --no-tcp +if errorlevel 1 goto error +del *.obj >nul +call makos2.cmd --with-gcc +if errorlevel 1 goto error +del *.obj >nul +call makos2.cmd --with-emx +if errorlevel 1 goto error +del *.o >nul +call makos2.cmd --with-x11 +if errorlevel 1 goto error +del *.o >nul +make -f osos2\Makefile.os2 lib\\elvis.INF +if errorlevel 1 goto error +echo success. +goto done + +:error +echo build failed, aborted. + :done diff --git a/mark.c b/mark.c index c045267..0e9d605 100644 --- a/mark.c +++ b/mark.c @@ -1,7 +1,7 @@ /* mark.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_mark[] = "$Id: mark.c,v 2.13 1998/11/21 01:34:45 steve Exp $"; +char id_mark[] = "$Id: mark.c,v 2.14 1999/10/08 18:04:29 steve Exp $"; #include "elvis.h" @@ -147,13 +147,28 @@ void markadjust(from, to, delta) /* Find the line number of a mark. This is defined as being the number of * newlines preceding the mark, plus 1. Note that this is not necessarily - * how the edit mode defines lines. + * how the display mode defines lines. */ long markline(mark) MARK mark; /* mark to be converted */ { +#if 1 + static long lnum; + static MARKBUF prevmark; + static long prevchanges; + + /* try to avoid calling lowoffset(), since that function is slow */ + if (markbuffer(mark) == markbuffer(&prevmark) + && markoffset(mark) == markoffset(&prevmark) + && markbuffer(mark)->changes == prevchanges) + return lnum; + + /* remember info so we can maybe optimize the next call */ + prevmark = *mark; + prevchanges = markbuffer(mark)->changes; +#else long lnum; - +#endif (void)lowoffset(bufbufinfo(markbuffer(mark)), markoffset(mark), NULL, NULL, NULL, &lnum); return lnum; } diff --git a/mark.h b/mark.h index d32811c..85e3792 100644 --- a/mark.h +++ b/mark.h @@ -15,6 +15,7 @@ typedef struct mark_s #define markaddoffset(mark,o) ((mark)->offset += (o)) #define markdup(mark) markalloc(markbuffer(mark), markoffset(mark)) #define marktmp(mbuf, buf, off) ((mbuf).buffer = (buf), (mbuf).offset = (off), &(mbuf)) +#define markset(mark,newmark) (marksetbuffer(mark, markbuffer(newmark)), marksetoffset(mark, markoffset(newmark))) extern MARK namedmark[26]; diff --git a/move.c b/move.c index e42c9cd..d626ae3 100644 --- a/move.c +++ b/move.c @@ -1,7 +1,7 @@ /* move.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_move[] = "$Id: move.c,v 2.43 1997/10/05 17:26:01 steve Exp $"; +char id_move[] = "$Id: move.c,v 2.48 1999/10/20 17:33:49 steve Exp $"; #include "elvis.h" @@ -805,8 +805,6 @@ RESULT m_scroll(win, vinf) WINDOW win; /* window where command was typed */ VIINFO *vinf; /* information about the command */ { - MARKBUF tmp; - assert(!win->state->acton); assert(!(win->state->flags & ELVIS_BOTTOM) || vinf->command == ELVCTRL('D')); @@ -835,53 +833,65 @@ RESULT m_scroll(win, vinf) switch (vinf->command) { case ELVCTRL('U'): - win->di->topline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->topline), -vinf->count, 0, True)); - win->di->bottomline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->bottomline), -vinf->count, 0, True)); + markset(win->di->topmark, (*win->md->move)(win, win->di->topmark, -vinf->count, 0, True)); + markset(win->di->bottommark, (*win->md->move)(win, win->di->bottommark, -vinf->count, 0, True)); marksetoffset(win->cursor, markoffset(dispmove(win, -vinf->count, 0))); break; case ELVCTRL('D'): - win->di->topline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->topline), vinf->count, 0, True)); - win->di->bottomline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->bottomline), vinf->count, 0, True)); + markset(win->di->topmark, (*win->md->move)(win, win->di->topmark, vinf->count, 0, True)); + markset(win->di->bottommark, (*win->md->move)(win, win->di->bottommark, vinf->count, 0, True)); marksetoffset(win->cursor, markoffset(dispmove(win, vinf->count, 0))); break; case ELVCTRL('Y'): - win->di->topline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->topline), -vinf->count, 0, True)); - win->di->bottomline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->bottomline), -vinf->count, 0, True)); + markset(win->di->topmark, (*win->md->move)(win, win->di->topmark, -vinf->count, 0, True)); + markset(win->di->bottommark, (*win->md->move)(win, win->di->bottommark, -vinf->count, 0, True)); marksetoffset(win->cursor, markoffset(dispmove(win, 0, win->wantcol))); - if (markoffset(win->cursor) >= win->di->bottomline) + if (markoffset(win->cursor) >= markoffset(win->di->bottommark)) { - marksetoffset(win->cursor, win->di->bottomline); + marksetoffset(win->cursor, markoffset(win->di->bottommark)); marksetoffset(win->cursor, markoffset(dispmove(win, -1, win->wantcol))); } break; case ELVCTRL('E'): - win->di->topline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->topline), vinf->count, 0, True)); - win->di->bottomline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->bottomline), vinf->count, 0, True)); - if (markoffset(win->cursor) < win->di->topline) + markset(win->di->topmark, (*win->md->move)(win, win->di->topmark, vinf->count, 0, True)); + markset(win->di->bottommark, (*win->md->move)(win, win->di->bottommark, vinf->count, 0, True)); + if (markoffset(win->cursor) < markoffset(win->di->topmark)) { - marksetoffset(win->cursor, win->di->topline); + marksetoffset(win->cursor, markoffset(win->di->topmark)); marksetoffset(win->cursor, markoffset(dispmove(win, 0, win->wantcol))); } break; case ELVCTRL('F'): - marksetoffset(win->cursor, win->di->bottomline); - win->di->topline = markoffset(dispmove(win, -1, 0)); - marksetoffset(win->cursor, win->di->topline); - win->di->bottomline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->topline), o_lines(win), 0, True)); + if (o_bufchars(markbuffer(win->di->bottommark)) > 0 + && markoffset(win->di->bottommark) == o_bufchars(markbuffer(win->di->bottommark))) + { + marksetoffset(win->cursor, markoffset(win->di->bottommark) - 1L); + } + else + { + marksetoffset(win->cursor, markoffset(win->di->bottommark)); + markset(win->di->topmark, dispmove(win, -2L, 0)); + marksetoffset(win->cursor, markoffset(win->di->topmark)); + markset(win->di->bottommark, (*win->md->move)(win, win->di->topmark, o_lines(win), 0, True)); + } break; case ELVCTRL('B'): - /* note: this adjustment of topline can be sloppy, because - * the drawimage() function will perform slop scrolling, if - * necessary, to keep the cursor in the screen. - */ - marksetoffset(win->cursor, win->di->topline); - win->di->topline = markoffset(dispmove(win, -o_lines(win), 0)); - win->di->bottomline = markoffset((*win->md->move)(win, marktmp(tmp, markbuffer(win->cursor), win->di->topline), o_lines(win), 0, True)); + if (markoffset(win->di->topmark) == 0) + { + marksetoffset(win->cursor, 0L); + } + else + { + marksetoffset(win->cursor, markoffset(win->di->topmark)); + markset(win->di->topmark, dispmove(win, 3L - o_lines(win), 0)); + markset(win->di->bottommark, (*win->md->move)(win, win->di->topmark, o_lines(win), 0, True)); + markset(win->cursor, dispmove(win, 1L, 0)); + } break; } @@ -902,6 +912,7 @@ RESULT m_column(win, vinf) VIINFO *vinf; /* information about the command */ { MARK dest; + long row = 0L; /* choose a column number */ switch (vinf->command) @@ -917,12 +928,14 @@ RESULT m_column(win, vinf) break; case '$': + if (vinf->count > 0) + row = vinf->count - 1; vinf->count = INFINITY; break; } /* move to the requested column (or as close as possible). */ - dest = dispmove(win, 0L, vinf->count - 1); + dest = dispmove(win, row, vinf->count - 1); marksetoffset(win->state->cursor, markoffset(dest)); /* if the window is editing the main buffer, set wantcol... @@ -1399,20 +1412,22 @@ RESULT m_z(win, vinf) case '\n': case '\r': case '+': + case 'H': /* The current line should appear at the top of the screen. - * We'll tweak the top & bottom so they both refer to this - * line. When the window is redrawn, the redrawing logic - * will cause this line to be output first, and then it'll - * just continue showing lines until the bottom of the - * screen. + * We'll tweak the top mark so it refers to this line. The + * bottom mark will be set to the end of the file. When the + * window is redrawn, the redrawing logic will cause this line + * to be output first, and then it'll just continue showing + * lines until the bottom of the screen. */ - win->di->topline = markoffset(dispmove(win, 0L, 0)); - win->di->bottomline = o_bufchars(markbuffer(win->cursor)); + markset(win->di->topmark, dispmove(win, 0L, 0)); + marksetoffset(win->di->bottommark, o_bufchars(markbuffer(win->cursor))); win->di->logic = DRAW_CHANGED; break; case '.': case 'z': + case 'M': /* The current line should appear in the middle of the screen. * To do this, we'll set the top half a screenful's number of * lines back, and the bottom some point after the cursor. @@ -1421,12 +1436,13 @@ RESULT m_z(win, vinf) * case the lines at the top of the screen fill more than one * row. */ - win->di->topline = markoffset(dispmove(win, -(o_lines(win) / 2), 0)); - win->di->bottomline = o_bufchars(markbuffer(win->cursor)); + markset(win->di->topmark, dispmove(win, -(o_lines(win) / 2), 0)); + marksetoffset(win->di->bottommark, o_bufchars(markbuffer(win->cursor))); win->di->logic = DRAW_CENTER; break; case '-': + case 'L': /* The current line should appear at the bottom of the screen. * To do this, we'll set the top back a whole screenload's * number of lines before the cursor line, and the bottom @@ -1435,8 +1451,8 @@ RESULT m_z(win, vinf) * computed top, and then scroll the window if necessary to * bring the current line onto the screen. */ - win->di->topline = markoffset(dispmove(win, -o_lines(win), 0)); - win->di->bottomline = markoffset(win->cursor) + 1; + markset(win->di->topmark, dispmove(win, -o_lines(win), 0)); + marksetoffset(win->di->bottommark, markoffset(win->cursor) + 1); win->di->logic = DRAW_CHANGED; break; } diff --git a/operator.c b/operator.c index 9471069..ab9a5ce 100644 --- a/operator.c +++ b/operator.c @@ -1,7 +1,7 @@ /* operator.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_operator[] = "$Id: operator.c,v 2.39 1997/12/22 20:09:37 steve Exp $"; +char id_operator[] = "$Id: operator.c,v 2.40 1999/10/07 16:23:58 steve Exp $"; #include "elvis.h" @@ -84,7 +84,7 @@ RESULT opfilter(from, to, prog) * non-zero exit status then return RESULT_ERROR (but still leave * the effects of the attempted filter run in the edit buffer). */ - return prgclose() == 0 ? RESULT_COMPLETE : RESULT_ERROR; + return (gui->prgclose ? (*gui->prgclose)() : prgclose()) == 0 ? RESULT_COMPLETE : RESULT_ERROR; } diff --git a/optglob.c b/optglob.c index 0e8c820..8b9167a 100644 --- a/optglob.c +++ b/optglob.c @@ -1,7 +1,7 @@ /* optglob.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_optglob[] = "$Id: optglob.c,v 2.66 1999/02/06 22:31:24 steve Exp $"; +char id_optglob[] = "$Id: optglob.c,v 2.67 1999/10/05 19:13:34 steve Exp $"; /* This file contains gobal options for the portable parts of elvis. */ @@ -95,8 +95,9 @@ static OPTDESC ogdesc[] = {"true", "True", optsstring, optisstring }, {"false", "False", optsstring, optisstring }, {"animation", "anim", optnstring, optisnumber, "1:100"}, - {"completebinary", "cob", NULL, NULL, "15:100"}, + {"completebinary", "cob", NULL, NULL }, {"optionwidth", "ow", optnstring, optisnumber, }, + {"smarttab", "sta", NULL, NULL }, /* added these for the sake of backward compatibility : */ {"more", "mo", NULL, NULL }, {"timeout", "to", NULL, NULL }, diff --git a/optglob.h b/optglob.h index b5b8242..4617fd7 100644 --- a/optglob.h +++ b/optglob.h @@ -96,12 +96,13 @@ extern OPTVAL lpval[]; #define o_animation optglob[84].value.number #define o_completebinary optglob[85].value.boolean #define o_optionwidth optglob[86].value.number +#define o_smarttab optglob[87].value.boolean /* For backward compatibility with older releases of elvis : */ -#define o_more optglob[87].value.boolean -#define o_timeout optglob[88].value.boolean -#define o_hardtabs optglob[89].value.number -#define o_redraw optglob[90].value.boolean -#define QTY_GLOBAL_OPTS 91 +#define o_more optglob[88].value.boolean +#define o_timeout optglob[89].value.boolean +#define o_hardtabs optglob[90].value.number +#define o_redraw optglob[91].value.boolean +#define QTY_GLOBAL_OPTS 92 #ifdef FEATURE_LPR # define o_lptype lpval[0].value.string diff --git a/osos2/Makefile.os2 b/osos2/Makefile.os2 index c1db206..45abc03 100644 --- a/osos2/Makefile.os2 +++ b/osos2/Makefile.os2 @@ -50,7 +50,6 @@ EXE=.exe ################################################################################ # This is the shell command which is used for deleting a file if it exists. -# The "-f" causes "rm" to be silent if the file doesn't exist. RM=del ################################################################################ @@ -77,6 +76,11 @@ FLAGI=-I # system which requires the EXE macro to be something like ".exe". ALL=elvis$(EXE) vi$(EXE) ex$(EXE) ref$(EXE) ctags$(EXE) fmt$(EXE) +################################################################################ +# The Elvis manual in INF format. This is done by a number of batch files +# in the manual subdirectory. +MANUAL=lib\\elvis.INF + ################################################################################ # This is the directory where "make install" will place the executable programs BINDIR=e:\usr\bin @@ -163,7 +167,7 @@ CFLAGS= $(FLAGI)os$(OS) EVERY= $(ALL) elvdump$(EXE) calc$(EXE) verify$(EXE) # Herbert 1998: SHELL needs to be blanked out under OS/2 if using GNU make. #SHELL= /bin/sh -DISTRIB=elvis-2.1_3 +DISTRIB=elvis-2.1_4 DOSEXE=exedos WIN32EXE=exewin32 OS2EXE=exeos2 @@ -172,6 +176,11 @@ all: $(ALL) every: $(EVERY) +# The manual converted from the HTML documentation to OS/2's INF... +$(MANUAL): + cd osos2\\manual && h2i-guide.cmd + $(CP) osos2\\manual\\elvis.INF $(MANUAL) + # Elvis compiled for a.out format and linked against emx.dll... emx: ; $(MAKE) elvisemx.exe -f osos2\\Makefile.os2 "OBJ=.o" "EXE=emx.exe" \ "CC=gcc -Wall -DOS2 -D__WITH_TERMCAP -O3 \ @@ -182,7 +191,7 @@ emx: ; $(MAKE) elvisemx.exe -f osos2\\Makefile.os2 "OBJ=.o" "EXE=emx.exe" \ # Elvis compiled for a.out format and linked against emx.dll with x11... debug: ; $(MAKE) -f osos2\\Makefile.os2 "OBJ=.o" "EXE=x11.exe" \ "CC=gcc -g -Wall -DOS2 -D__WITH_TERMCAP -O3 \ - -Zmtd -D__D_ST_MT_ERRNO__ -D__WITH_X11 \ + -Zmtd -D__D_ST_MT_ERRNO__ -D__WITH_X11" \ "FLAGO=-o " \ "LIBFILES=-L/usr/lib/x11 -lsocket -ltermcap -lx11" @@ -200,30 +209,44 @@ gcc: ; $(MAKE) -f osos2\\Makefile.os2 "EXE=gcc.exe" "FLAGO=-o " \ elvis$(EXE): $(HDRS) main$(OBJ) $(OBJS) $(GUIOBJS) $(LPOBJS) $(CC) $(CFLAGS) $(LDFLAGS) main$(OBJ) $(OBJS) $(GUIOBJS) $(LPOBJS) $(LIBFILES) $(DEFFILE) $(FLAGO)elvis$(EXE) + $(CP) elvis$(EXE) $(OS2EXE) + $(RM) elvis$(EXE) pmelvis$(EXE): $(HDRS) main$(OBJ) $(OBJS) $(GUIOBJS) $(LPOBJS) $(CC) $(CFLAGS) $(LDFLAGS) main$(OBJ) $(OBJS) $(GUIOBJS) $(LPOBJS) $(LIBFILES) $(PMDEFFILE) $(FLAGO)pmelvis$(EXE) elvis-no-tcp$(EXE): $(HDRS) main$(OBJ) $(OBJS) $(GUIOBJS) $(LPOBJS) $(CC) $(CFLAGS) $(LDFLAGS) main$(OBJ) $(OBJS) $(GUIOBJS) $(LPOBJS) $(DEFFILE) $(FLAGO)elvis-no-tcp$(EXE) + $(CP) elvis-no-tcp$(EXE) $(OS2EXE) + $(RM) elvis-no-tcp$(EXE) vi$(EXE): alias.c $(CC) $(CFLAGS) $(LDFLAGS) -DARGV0=VI alias.c $(FLAGO)vi$(EXE) + $(CP) vi$(EXE) $(OS2EXE) + $(RM) vi$(EXE) ex$(EXE): alias.c $(CC) $(CFLAGS) $(LDFLAGS) -DARGV0=EX alias.c $(FLAGO)ex$(EXE) + $(CP) ex$(EXE) $(OS2EXE) + $(RM) ex$(EXE) view$(EXE): alias.c $(CC) $(CFLAGS) $(LDFLAGS) -DARGV0=VIEW alias.c $(FLAGO)view$(EXE) ctags$(EXE): $(CTOBJS) $(CC) $(CFLAGS) $(LDFLAGS) $(CTOBJS) $(FLAGO)ctags$(EXE) + $(CP) ctags$(EXE) $(OS2EXE) + $(RM) ctags$(EXE) ref$(EXE): $(REFOBJS) $(CC) $(CFLAGS) $(LDFLAGS) $(REFOBJS) $(FLAGO)ref$(EXE) + $(CP) ref$(EXE) $(OS2EXE) + $(RM) ref$(EXE) fmt$(EXE): fmt.c os$(OS)$(SLASH)osdir.c $(CC) $(CFLAGS) $(LDFLAGS) fmt.c $(FLAGO)fmt$(EXE) + $(CP) fmt$(EXE) $(OS2EXE) + $(RM) fmt$(EXE) verify$(EXE): $(HDRS) verify$(OBJ) $(OBJ1) $(OBJ2) $(CC) $(CFLAGS) $(LDFLAGS) verify$(OBJ) $(OBJS) $(LIBFILES) $(FLAGO)verify$(EXE) @@ -367,7 +390,7 @@ $(DISTRIB)-win32.tar.gz: $(WIN32EXE) mkdir bin-win32/lib cp lib/* bin-win32/lib sed 's/$$/ /' bin-win32/lib/printdoc.bat - sed 's/$$/ /' bin-win32/lib/license.bat + sed 's/$$/ /' bin-win32/lib/license (cd bin-win32; tar czf ../$(DISTRIB)-win32.tar.gz *) $(DISTRIB)-msdos.tar.gz: $(DOSEXE) @@ -380,21 +403,21 @@ $(DISTRIB)-msdos.tar.gz: $(DOSEXE) mkdir bin-msdos/lib cp lib/* bin-msdos/lib sed 's/$$/ /' bin-msdos/lib/printdoc.bat - sed 's/$$/ /' bin-win32/lib/license.bat + sed 's/$$/ /' bin-win32/lib/license (cd bin-msdos; tar czf ../$(DISTRIB)-msdos.tar.gz *) $(DISTRIB)-os2.tar.gz: $(OS2EXE) rm -rf bin-os2 mkdir bin-os2 - cp $(DOSEXE)/*.exe bin-os2 - sed 's/$$/ /' bin-os2/README.html - sed 's/$$/ /' bin-os2/BUGS - sed 's/$$/ /' bin-os2/COPYING - mkdir bin-os2/lib - cp lib/* bin-os2/lib - sed 's/$$/ /' bin-os2/lib/printdoc.bat - sed 's/$$/ /' bin-win32/lib/license.bat - (cd bin-os2; tar czf ../$(DISTRIB)-os2.tar.gz *) + cp $(OS2EXE)\\*.exe bin-os2 + mkdir bin-os2\\lib + cp lib/* bin-os2\\lib + type README.html >bin-os2\\README.html + type BUGS >bin-os2\\BUGS + type COPYING >bin-os2\\COPYING + type lib\\printdoc.bat >bin-os2\\lib\\printdoc.bat + type lib\\license >bin-os2\\lib\\license + (cd bin-os2 && tar cvf ..\\$(DISTRIB)-os2.tar * && gzip ..\\$(DISTRIB)-os2.tar) lib$(SLASH)elvistrs.msg: $(SRCS) sed -n '/%[cds]/d; /[a-z]:/d; s/\[[a-zA-Z]*\]//; s/\\\\/\\/g; s/.*msg(MSG_[A-Z]*, "\([^ "][^"]*\)".*/\1/p' *.c os*$(SLASH)*.c | sort -u >lib$(SLASH)elvistrs.msg diff --git a/osos2/changes.os2 b/osos2/changes.os2 deleted file mode 100644 index 6264ec4..0000000 --- a/osos2/changes.os2 +++ /dev/null @@ -1,11 +0,0 @@ -Elvis 2.1j - -- Added support for FEATURE_RAM - - -Elvis 2.1i - -- Fixed filename completion. -- Fixed filetype (EOL-character) for new files. -- Fixed filetype (EOL-character) for sessions with no config files available. - diff --git a/osos2/config-with-tcp.h b/osos2/config-with-tcp.h index 6ecf981..b047f1f 100644 --- a/osos2/config-with-tcp.h +++ b/osos2/config-with-tcp.h @@ -16,6 +16,7 @@ # undef GUI_X11 /* simple X-windows interface */ #else # define GUI_X11 /* simple X-windows interface */ +# define NO_XLOCALE #endif #undef GUI_CURSES /* curses interface */ #ifndef __WITH_TERMCAP diff --git a/osos2/osdef.h b/osos2/osdef.h index 8f4539c..1be6973 100644 --- a/osos2/osdef.h +++ b/osos2/osdef.h @@ -69,7 +69,8 @@ /*============================================================================= * This is the default path that elvis searches through when looking for its - * support files. + * support files. This is *never* used, it gets overridden by code in osinit() + * on program startup. Call it `default for a default' :-) */ #define OSLIBPATH "e:\\usr\\lib\\elvis" diff --git a/osos2/osdir.c b/osos2/osdir.c index fa45ad2..561cc20 100644 --- a/osos2/osdir.c +++ b/osos2/osdir.c @@ -80,11 +80,15 @@ char *dirdir (pathname) char *slash; strncpy (dir, pathname, sizeof dir); + for (slash = &dir[strlen(dir)]; + --slash >= dir && *slash != '/' && *slash != '\\';) + { + } /* Convert slashes to backslashes. */ - fix_slashes (dir); +/* fix_slashes (dir); + slash = strrchr (dir, OSPATHSEP);*/ - slash = strrchr (dir, OSPATHSEP); if (slash == dir) { dir[1] = '\0'; diff --git a/osos2/osnet.c b/osos2/osnet.c index 1f38f95..93494db 100644 --- a/osos2/osnet.c +++ b/osos2/osnet.c @@ -77,7 +77,9 @@ static BOOLEAN site2addr (char *site, struct in_addr *address); # endif +#ifndef __EMX__ static BOOLEAN initialized; +#endif static int inet_aton (char *site, struct in_addr *addr) { @@ -96,21 +98,22 @@ static int inet_aton (char *site, struct in_addr *addr) * or a "numbers and dots" name. If successful, the address is stuffed into * address struct, and True is returned; otherwise False is returned. */ -static BOOLEAN site2addr (site, address) +static BOOLEAN site2addr(site, address) char *site; struct in_addr *address; { - struct hostent *siteinfo; + struct hostent *siteinfo; static char prevsite[100]; static struct in_addr prevaddr; + /* if the site name starts with a digit, then assume it is in the - * "numbers and dots" format. Else use the name server. + * "numbers and dots" format. */ - if (isdigit (site[0])) + if (isdigit(site[0])) { /* convert to binary address */ - if (!inet_aton (site, address)) + if (!inet_aton(site, address)) goto Error; } else @@ -123,15 +126,15 @@ static BOOLEAN site2addr (site, address) } /* look up the name */ - msg (MSG_STATUS, "[s]looking up site $1", site); - siteinfo = gethostbyname (site); + msg(MSG_STATUS, "[s]looking up site $1", site); /* !!!*/ + siteinfo = gethostbyname(site); if (!siteinfo) { goto Error; } /* use the primary address */ - memcpy (address, siteinfo->h_addr_list[0], siteinfo->h_length); + memcpy(address, siteinfo->h_addr_list[0], siteinfo->h_length); /* save the info about this site */ strncpy(prevsite, site, sizeof prevsite); @@ -141,12 +144,10 @@ static BOOLEAN site2addr (site, address) return True; Error: - msg (MSG_ERROR, "[s]unknown site $1", site); + msg(MSG_ERROR, "[s]unknown site $1", site); return False; } - - /* Open a connection to a given site and port. * Returns a sockbuf_t pointer if successful, or NULL for errors (in which * case it also gives an error message). @@ -161,14 +162,14 @@ sockbuf_t *netconnect (site_port, defport) char buf[150]; sockbuf_t *sb; +#ifndef __EMX__ /* If first time, then initialize OS/2 sockets */ if (!initialized) { -#ifndef __EMX__ (void)sock_init (); -#endif initialized = True; } +#endif /* if site_port contains a port number, then separate it from the site * name, and use the given port instead of the default port. @@ -189,23 +190,21 @@ sockbuf_t *netconnect (site_port, defport) msg (MSG_STATUS, "[s]connecting to $1", buf); /* create a socket, and a sockbuf_t to buffer it */ - sb = safealloc (1, sizeof(sockbuf_t)); - sb->fd = socket (AF_INET, SOCK_STREAM, IPPROTO_IP); + sb = safealloc(1, sizeof(sockbuf_t)); + sb->fd = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); if (sb->fd < 0) { - safefree (sb); - msg (MSG_ERROR, "could not create socket"); + safefree(sb); return NULL; } /* connect the socket to the remote machine */ destPort.sin_family = AF_INET; - destPort.sin_port = htons ((unsigned short)defport); + destPort.sin_port = htons((unsigned short)defport); destPort.sin_addr = serverAddress; if (connect(sb->fd, (struct sockaddr *)&destPort, sizeof(destPort))) { - netdisconnect (sb); - msg(MSG_ERROR, "could not connect"); + netdisconnect(sb); return NULL; } @@ -251,18 +250,16 @@ BOOLEAN netread (sockbuf_t *sb) if (sb->left > 0 && sb->right > sb->left) /* regions may overlap -- it is guaranteed to work */ memmove(sb->buf, &sb->buf[sb->left], sb->right - sb->left); - /* herbert: looks like a bug! - * memcpy(sb->buf, &sb->buf[sb->left], sb->right - sb->left); */ sb->right -= sb->left; sb->left = 0; /* Read as much data as is available */ - i = read (sb->fd, &sb->buf[sb->right], sizeof sb->buf - sb->right); + i = read(sb->fd, &sb->buf[sb->right], sizeof sb->buf - sb->right); if (i < 0) - i = read (sb->fd, &sb->buf[sb->right], sizeof sb->buf - sb->right); + i = read(sb->fd, &sb->buf[sb->right], sizeof sb->buf - sb->right); if (i < 0) { - msg (MSG_ERROR, "error reading from socket"); + msg(MSG_ERROR, "error reading from socket"); return False; } sb->right += i; @@ -272,9 +269,8 @@ BOOLEAN netread (sockbuf_t *sb) } - /* Read a line from a socket. Return the line if successful, NULL if error. */ -char *netgetline (sockbuf_t *sb) +char *netgetline(sockbuf_t *sb) { int i; char *ret; @@ -283,7 +279,7 @@ char *netgetline (sockbuf_t *sb) for (;;) { /* see if we have a whole line now */ - for (ret = netbuffer (sb), i = sb->left; i < sb->right; i++) + for (ret = netbuffer(sb), i = sb->left; i < sb->right; i++) { if (sb->buf[i] == '\n') { @@ -297,8 +293,8 @@ char *netgetline (sockbuf_t *sb) } /* read some more data */ - i = netbytes (sb); - if (!netread (sb) || i == netbytes (sb)) + i = netbytes(sb); + if (!netread(sb) || i == netbytes(sb)) return NULL; } /*NOTREACHED*/ @@ -308,23 +304,24 @@ char *netgetline (sockbuf_t *sb) /* Send data bytes through a socket. Returns True if successful, or False if * error (after giving an error message). */ -BOOLEAN netwrite (sb, data, len) +BOOLEAN netwrite(sb, data, len) sockbuf_t *sb; char *data; int len; { - if (write (sb->fd, data, len) == len) + if (write(sb->fd, data, len) == len) return True; - msg (MSG_ERROR, "transmission failed"); + msg(MSG_ERROR, "transmission failed"); return False; } + /* Send a line through a socket. This intended to be used for sending commands * to an FTP or HTTP server. The line should be a normal NUL-terminated string * with no newline; this function appends a CRLF. Returns True if successful, * or False if error (after giving an error message). */ -BOOLEAN netputline (sb, command, arg1, arg2) +BOOLEAN netputline(sb, command, arg1, arg2) sockbuf_t *sb; /* stream to write to */ char *command; /* command name */ char *arg1, *arg2; /* arguments, may be NULL if not used */ @@ -335,41 +332,42 @@ BOOLEAN netputline (sb, command, arg1, arg2) /* combine the command and arg into one string */ if (arg2) { - len = strlen (command) + strlen (arg1) + strlen (arg2) + 5; - buf = safealloc (len, sizeof (char)); - sprintf (buf, "%s %s %s\r\n", command, arg1, arg2); + len = strlen(command) + strlen(arg1) + strlen(arg2) + 5; + buf = safealloc(len, sizeof(char)); + sprintf(buf, "%s %s %s\r\n", command, arg1, arg2); } else if (arg1) { - len = strlen (command) + strlen (arg1) + 4; - buf = safealloc (len, sizeof (char)); - sprintf (buf, "%s %s\r\n", command, arg1); + len = strlen(command) + strlen(arg1) + 4; + buf = safealloc(len, sizeof(char)); + sprintf(buf, "%s %s\r\n", command, arg1); } else { - len = strlen (command) + 3; - buf = safealloc (len, sizeof (char)); - sprintf (buf, "%s\r\n", command); + len = strlen(command) + 3; + buf = safealloc(len, sizeof(char)); + sprintf(buf, "%s\r\n", command); } len--; /* <-- so the NUL terminator isn't sent */ /* send the command to the server */ - if (write (sb->fd, buf, len) != len && *command) + if (write(sb->fd, buf, len) != len && *command) { - msg (MSG_ERROR, "could not send request to server"); - safefree (buf); + msg(MSG_ERROR, "could not send request to server"); + safefree(buf); return False; } - safefree (buf); + safefree(buf); return True; } + char *netself P_((void)) { static char name[50]; - if (gethostname (name, sizeof(name))) - strcpy (name, "graceland.net"); + if (gethostname(name, sizeof(name))) + strcpy(name, "graceland"); return name; } diff --git a/osunix/osnet.c b/osunix/osnet.c index eb3102d..d59b269 100644 --- a/osunix/osnet.c +++ b/osunix/osnet.c @@ -53,6 +53,7 @@ # ifndef M_XENIX /* SCO can't mix with */ # include # endif +# include # include # else # include diff --git a/oswin32/osblock.c b/oswin32/osblock.c index 592185d..ea24f72 100644 --- a/oswin32/osblock.c +++ b/oswin32/osblock.c @@ -90,13 +90,13 @@ BOOLEAN blkopen(BOOLEAN force, BLK *buf) { if (errno == ENOENT) { - fd = _open(o_session, _O_RDWR|_O_CREAT|_O_EXCL|_O_BINARY, 0600); + fd = _open(tochar8(o_session), _O_RDWR|_O_CREAT|_O_EXCL|_O_BINARY, 0600); if (fd >= 0) { if (_write(fd, (char *)buf, (unsigned)o_blksize) < o_blksize) { _close(fd); - remove(o_session); + remove(tochar8(o_session)); fd = -1; errno = ENOENT; } diff --git a/oswin32/osdir.c b/oswin32/osdir.c index 85ccdc2..7284997 100644 --- a/oswin32/osdir.c +++ b/oswin32/osdir.c @@ -10,8 +10,14 @@ #if !defined(JUST_DIRFIRST) && !defined(JUST_DIRPATH) # include "elvis.h" +# define BOOLEAN winBOOLEAN +# define CHAR winCHAR +# include /* for registry functions */ +# undef BOOLEAN +# undef CHAR #endif #include +#include #include #include #include @@ -29,6 +35,15 @@ #ifndef JUST_DIRPATH +/* These are CygWin mount points */ +static struct mtab_s +{ + char native[MAX_PATH]; /* Windows name for a directory */ + char unix[MAX_PATH]; /* Unix name for a directory */ + int unixlen; /* length of unix[] */ +} mtab[10]; +static int nmtabs; /* number of used entries in mtab[] */ + /* These are used for communication between dirfirst() and dirnext() */ static char finddir[MAX_PATH]; static char findwild[MAX_PATH]; @@ -40,6 +55,33 @@ static struct _find_t FileData; #endif static long hSearch; +/* adjust a file path via the Cygwin mount table */ +char *dirnormalize(char *path) +{ + static char winp[MAX_PATH + 1]; + int i; + + /* convert slashes to backslashes */ + for (i = 0; path[i]; i++) + if (path[i] == '/') + winp[i] = '\\'; + else + winp[i] = path[i]; + winp[i] = '\0'; + + /* check it against Cygwin's mount table */ + for (i = 0; i < nmtabs; i++) + if (!strncmp(winp, mtab[i].unix, mtab[i].unixlen) + && (!winp[mtab[i].unixlen] || winp[mtab[i].unixlen] == '\\')) + break; + if (i < nmtabs) + { + strcpy(winp, mtab[i].native); + strcat(winp, path + mtab[i].unixlen); + } + return winp; +} + /* Return the first filename (in a static buffer) that matches * wildexpr, or wildexpr if none matches. If wildexpr has no contains * no wildcards, then just return wildexpr without checking for files. @@ -49,10 +91,10 @@ char *dirfirst(char *wildexpr, BOOLEAN ispartial) /* remember the directory name */ strcpy(finddir, dirdir(wildexpr)); - /* Copy the wildexpr into fildwild[]. If it is meant to be a partial + /* Copy the wildexpr into findwild[]. If it is meant to be a partial * name, then append "*" to it. */ - strcpy(findwild, wildexpr); + strcpy(findwild, dirnormalize(wildexpr)); if (ispartial) strcat(findwild, "*"); @@ -109,7 +151,7 @@ char *dirnext(void) /* Return True if wildexpr contains any wildcards; else False */ BOOLEAN diriswild(char *wildexpr) { - if (strchr(wildexpr, '*') || strchr(wildexpr, '?')) + if (nmtabs > 0 || strchr(wildexpr, '*') || strchr(wildexpr, '?')) { return True; } @@ -147,7 +189,7 @@ DIRPERM dirperm(char *filename) else if (i > 0) return DIR_READONLY; - if (_stat(filename, &statb) < 0) + if (_stat(dirnormalize(filename), &statb) < 0) { if (errno == ENOENT) return DIR_NEW; @@ -156,7 +198,8 @@ DIRPERM dirperm(char *filename) } if ((statb.st_mode & _S_IFMT) != _S_IFREG || !strcmp(filename, "nul") - || !strcmp(filename, "prn")) + || !strcmp(filename, "prn") + || !strncmp(filename, "lpt", 3)) return DIR_NOTFILE; if ((statb.st_mode & _S_IWRITE) == 0) return DIR_READONLY; @@ -256,19 +299,10 @@ char *dirpath(char *dir, char *file) { while (*dir) { -#if 0 - switch (*dir) - { - case '/': if (dir[1]) *build++ = '\\'; break; - case '\\': if (dir[1]) *build++ = *dir; break; - default: *build++ = *dir; break; - } -#else if (*dir == '/') *build++ = '\\'; else *build++ = *dir; -#endif dir++; } } @@ -286,6 +320,7 @@ char *dirpath(char *dir, char *file) *build++ = *file++; } *build = '\0'; + return path; } @@ -325,6 +360,13 @@ void osinit(argv0) { char *tmp; static char path[260]; + char name[200]; + char value[200]; + HKEY hCygnus, hMounts, hKey; + int i, j; + DWORD dw, dw2; + FILETIME when; + struct mtab_s swapper; /* if argv0 isn't a pathname, then try to locate "elvis.exe" in * the execution path. We need this when figuring out the default @@ -380,6 +422,67 @@ void osinit(argv0) tmp = dirdir(argv0); sprintf(path, "~\\elvislib;%s;%s", tmp, dirpath(tmp, "lib")); o_elvispath = toCHAR(path); + + /* Read the mounts for the latest Cygwin version */ + hCygnus = hMounts = hKey = 0; + if (RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\Cygnus Solutions\\CYGWIN.DLL setup", 0L, KEY_READ|KEY_EXECUTE, &hCygnus) == ERROR_SUCCESS) + { + /* there may be multiple versions. Use the most recent one */ + for (i = 0, dw = sizeof name, *value = '\0'; + RegEnumKeyEx(hCygnus, i, name, &dw, NULL, NULL, NULL, &when) == ERROR_SUCCESS; + i++, dw = sizeof name) + { + if (strcmp(*name=='b' ? name+1 : name, + *value=='b' ? value+1 : value) > 0) + strcpy(value, name); + } + strcpy(name, value); + strcat(name, "\\mounts"); + if (RegOpenKeyEx(hCygnus, name, 0L, KEY_READ|KEY_EXECUTE, &hMounts) == ERROR_SUCCESS) + { + for (i = nmtabs = 0, dw = sizeof name; + nmtabs < QTY(mtab) && RegEnumKeyEx(hMounts, i, name, &dw, NULL, NULL, NULL, &when) == ERROR_SUCCESS; + i++, dw = sizeof name) + { + /* print the mount table entry */ + if (RegOpenKeyEx(hMounts, name, 0L, KEY_READ|KEY_EXECUTE, &hKey) == ERROR_SUCCESS) + { + dw = sizeof mtab[nmtabs].native; + if (RegQueryValueEx(hKey, "native", NULL, &dw2, mtab[nmtabs].native, &dw) != ERROR_SUCCESS + || dw2 != REG_SZ + || !(dw = sizeof mtab[nmtabs].unix) /* yes, ASSIGNMENT! */ + || RegQueryValueEx(hKey, "unix", NULL, &dw2, mtab[nmtabs].unix, &dw) != ERROR_SUCCESS + || dw2 != REG_SZ) + msg(MSG_WARNING, "Cygwin mount table contains malformed entries"); + else + nmtabs++; + RegCloseKey(hKey); + } + } + RegCloseKey(hMounts); + } + RegCloseKey(hCygnus); + } + + /* convert forward slashes in mtab[] to backslashes */ + for (i = 0; i < nmtabs; i++) + { + while ((tmp = strchr(mtab[i].native, '/')) != NULL) + *tmp = '\\'; + while ((tmp = strchr(mtab[i].unix, '/')) != NULL) + *tmp = '\\'; + mtab[i].unixlen = strlen(mtab[i].unix); + } + + /* sort mtab[] by the length of the unix name (longest first) */ + for (i = 0; i < nmtabs - 1; i++) + for (j = i + 1; j < nmtabs; j++) + if (mtab[i].unixlen < mtab[j].unixlen) + { + swapper = mtab[i]; + mtab[i] = mtab[j]; + mtab[j] = swapper; + } } #endif /* !JUST_DIRPATH */ diff --git a/oswin32/osprg.c b/oswin32/osprg.c index 2ee6425..73a9be2 100644 --- a/oswin32/osprg.c +++ b/oswin32/osprg.c @@ -1,6 +1,6 @@ /* oswin32/osprg.c */ -char id_osprg[] = "$Id: osprg.c,v 2.13 1999/03/03 18:41:04 steve Exp $"; +char id_osprg[] = "$Id: osprg.c,v 2.15 1999/10/20 17:35:06 steve Exp $"; #include #include @@ -9,42 +9,908 @@ char id_osprg[] = "$Id: osprg.c,v 2.13 1999/03/03 18:41:04 steve Exp $"; #define BOOLEAN ElvisBOOLEAN #include "elvis.h" -/* NOTE: Previous versions of this program attempted to use pipes. But - * there are some undocumented problems with pipes, and I/O redirection - * in general, so I decided to "dumb it down" to the basics. It now - * creates batch file to run the command. - */ + +#undef DEBUGGING + #define TMPDIR (o_directory ? tochar8(o_directory) : ".") -static char namestdin[MAX_PATH];/* name of stdin temp file */ -static char namestdout[MAX_PATH];/* name of stdout/stderr file */ -static char namebatch[MAX_PATH];/* name of batch file */ -static DWORD status; /* exit status of program */ -static FILE *fp; -static int unique; +static char *command; /* the command to run */ +static ElvisBOOLEAN filter; /* redirecting both stdin and stdout? */ +static char tempfname[MAX_PATH]; /* name of temp file */ +static HANDLE writefd; /* handle used for writing to program's stdin */ +static HANDLE readfd; /* handle used for reading program's stdout */ +static HANDLE pid; /* process ID of program */ +static HANDLE tid; /* thread ID of program */ static SECURITY_ATTRIBUTES inherit = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; static STARTUPINFO start = {sizeof(STARTUPINFO)}; +static UINT unique; +static char pipefname[MAX_PATH]; /* name of pipe's temp file */ +static BOOL supports_pipes; /* can program write to a pipe? */ +static BOOL supports_detach;/* can program run without a console? */ +static DWORD status; /* exit status of program */ + +static BOOL classifyprog(char *prog); +static BOOL runcmd(char *cmd, ElvisBOOLEAN detached); +static BOOL MaybeCreatePipe(PHANDLE r, PHANDLE w); -static BOOLEAN runbatch(void) +#ifdef DEBUGGING +extern void ElvisError(char *where); +static FILE *tracelog; + +/* Display an error message */ +void ElvisError(where) + char *where; { - HANDLE pid, tid; - CHAR *cmdline; - PROCESS_INFORMATION proc; - BOOLEAN result; + char *what; + DWORD error = GetLastError(); + char errornum[20]; + + /* convert error code to text */ + switch (error & 0xffff) + { + case ERROR_SUCCESS: what = "SUCCESS"; break; + case ERROR_INVALID_FUNCTION: what = "INVALID_FUNCTION"; break; + case ERROR_FILE_NOT_FOUND: what = "FILE_NOT_FOUND"; break; + case ERROR_PATH_NOT_FOUND: what = "PATH_NOT_FOUND"; break; + case ERROR_TOO_MANY_OPEN_FILES: what = "TOO_MANY_OPEN_FILES"; break; + case ERROR_ACCESS_DENIED: what = "ACCESS_DENIED"; break; + case ERROR_INVALID_HANDLE: what = "INVALID_HANDLE"; break; + case ERROR_ARENA_TRASHED: what = "ARENA_TRASHED"; break; + case ERROR_NOT_ENOUGH_MEMORY: what = "NOT_ENOUGH_MEMORY"; break; + case ERROR_INVALID_BLOCK: what = "INVALID_BLOCK"; break; + case ERROR_BAD_ENVIRONMENT: what = "BAD_ENVIRONMENT"; break; + case ERROR_BAD_FORMAT: what = "BAD_FORMAT"; break; + case ERROR_INVALID_ACCESS: what = "INVALID_ACCESS"; break; + case ERROR_INVALID_DATA: what = "INVALID_DATA"; break; + case ERROR_OUTOFMEMORY: what = "OUTOFMEMORY"; break; + case ERROR_INVALID_DRIVE: what = "INVALID_DRIVE"; break; + case ERROR_CURRENT_DIRECTORY: what = "CURRENT_DIRECTORY"; break; + case ERROR_NOT_SAME_DEVICE: what = "NOT_SAME_DEVICE"; break; + case ERROR_NO_MORE_FILES: what = "NO_MORE_FILES"; break; + case ERROR_WRITE_PROTECT: what = "WRITE_PROTECT"; break; + case ERROR_BAD_UNIT: what = "BAD_UNIT"; break; + case ERROR_NOT_READY: what = "NOT_READY"; break; + case ERROR_BAD_COMMAND: what = "BAD_COMMAND"; break; + case ERROR_CRC: what = "CRC"; break; + case ERROR_BAD_LENGTH: what = "BAD_LENGTH"; break; + case ERROR_SEEK: what = "SEEK"; break; + case ERROR_NOT_DOS_DISK: what = "NOT_DOS_DISK"; break; + case ERROR_SECTOR_NOT_FOUND: what = "SECTOR_NOT_FOUND"; break; + case ERROR_OUT_OF_PAPER: what = "OUT_OF_PAPER"; break; + case ERROR_WRITE_FAULT: what = "WRITE_FAULT"; break; + case ERROR_READ_FAULT: what = "READ_FAULT"; break; + case ERROR_GEN_FAILURE: what = "GEN_FAILURE"; break; + case ERROR_SHARING_VIOLATION: what = "SHARING_VIOLATION"; break; + case ERROR_LOCK_VIOLATION: what = "LOCK_VIOLATION"; break; + case ERROR_WRONG_DISK: what = "WRONG_DISK"; break; + case ERROR_SHARING_BUFFER_EXCEEDED: what = "SHARING_BUFFER_EXCEEDED"; break; + case ERROR_HANDLE_EOF: what = "HANDLE_EOF"; break; + case ERROR_HANDLE_DISK_FULL: what = "HANDLE_DISK_FULL"; break; + case ERROR_NOT_SUPPORTED: what = "NOT_SUPPORTED"; break; + case ERROR_REM_NOT_LIST: what = "REM_NOT_LIST"; break; + case ERROR_DUP_NAME: what = "DUP_NAME"; break; + case ERROR_BAD_NETPATH: what = "BAD_NETPATH"; break; + case ERROR_NETWORK_BUSY: what = "NETWORK_BUSY"; break; + case ERROR_DEV_NOT_EXIST: what = "DEV_NOT_EXIST"; break; + case ERROR_TOO_MANY_CMDS: what = "TOO_MANY_CMDS"; break; + case ERROR_ADAP_HDW_ERR: what = "ADAP_HDW_ERR"; break; + case ERROR_BAD_NET_RESP: what = "BAD_NET_RESP"; break; + case ERROR_UNEXP_NET_ERR: what = "UNEXP_NET_ERR"; break; + case ERROR_BAD_REM_ADAP: what = "BAD_REM_ADAP"; break; + case ERROR_PRINTQ_FULL: what = "PRINTQ_FULL"; break; + case ERROR_NO_SPOOL_SPACE: what = "NO_SPOOL_SPACE"; break; + case ERROR_PRINT_CANCELLED: what = "PRINT_CANCELLED"; break; + case ERROR_NETNAME_DELETED: what = "NETNAME_DELETED"; break; + case ERROR_NETWORK_ACCESS_DENIED: what = "NETWORK_ACCESS_DENIED"; break; + case ERROR_BAD_DEV_TYPE: what = "BAD_DEV_TYPE"; break; + case ERROR_BAD_NET_NAME: what = "BAD_NET_NAME"; break; + case ERROR_TOO_MANY_NAMES: what = "TOO_MANY_NAMES"; break; + case ERROR_TOO_MANY_SESS: what = "TOO_MANY_SESS"; break; + case ERROR_SHARING_PAUSED: what = "SHARING_PAUSED"; break; + case ERROR_REQ_NOT_ACCEP: what = "REQ_NOT_ACCEP"; break; + case ERROR_REDIR_PAUSED: what = "REDIR_PAUSED"; break; + case ERROR_FILE_EXISTS: what = "FILE_EXISTS"; break; + case ERROR_CANNOT_MAKE: what = "CANNOT_MAKE"; break; + case ERROR_FAIL_I24: what = "FAIL_I24"; break; + case ERROR_OUT_OF_STRUCTURES: what = "OUT_OF_STRUCTURES"; break; + case ERROR_ALREADY_ASSIGNED: what = "ALREADY_ASSIGNED"; break; + case ERROR_INVALID_PASSWORD: what = "INVALID_PASSWORD"; break; + case ERROR_INVALID_PARAMETER: what = "INVALID_PARAMETER"; break; + case ERROR_NET_WRITE_FAULT: what = "NET_WRITE_FAULT"; break; + case ERROR_NO_PROC_SLOTS: what = "NO_PROC_SLOTS"; break; + case ERROR_TOO_MANY_SEMAPHORES: what = "TOO_MANY_SEMAPHORES"; break; + case ERROR_EXCL_SEM_ALREADY_OWNED: what = "EXCL_SEM_ALREADY_OWNED"; break; + case ERROR_SEM_IS_SET: what = "SEM_IS_SET"; break; + case ERROR_TOO_MANY_SEM_REQUESTS: what = "TOO_MANY_SEM_REQUESTS"; break; + case ERROR_INVALID_AT_INTERRUPT_TIME: what = "INVALID_AT_INTERRUPT_TIME"; break; + case ERROR_SEM_OWNER_DIED: what = "SEM_OWNER_DIED"; break; + case ERROR_SEM_USER_LIMIT: what = "SEM_USER_LIMIT"; break; + case ERROR_DISK_CHANGE: what = "DISK_CHANGE"; break; + case ERROR_DRIVE_LOCKED: what = "DRIVE_LOCKED"; break; + case ERROR_BROKEN_PIPE: what = "BROKEN_PIPE"; break; + case ERROR_OPEN_FAILED: what = "OPEN_FAILED"; break; + case ERROR_BUFFER_OVERFLOW: what = "BUFFER_OVERFLOW"; break; + case ERROR_DISK_FULL: what = "DISK_FULL"; break; + case ERROR_NO_MORE_SEARCH_HANDLES: what = "NO_MORE_SEARCH_HANDLES"; break; + case ERROR_INVALID_TARGET_HANDLE: what = "INVALID_TARGET_HANDLE"; break; + case ERROR_INVALID_CATEGORY: what = "INVALID_CATEGORY"; break; + case ERROR_INVALID_VERIFY_SWITCH: what = "INVALID_VERIFY_SWITCH"; break; + case ERROR_BAD_DRIVER_LEVEL: what = "BAD_DRIVER_LEVEL"; break; + case ERROR_CALL_NOT_IMPLEMENTED: what = "CALL_NOT_IMPLEMENTED"; break; + case ERROR_SEM_TIMEOUT: what = "SEM_TIMEOUT"; break; + case ERROR_INSUFFICIENT_BUFFER: what = "INSUFFICIENT_BUFFER"; break; + case ERROR_INVALID_NAME: what = "INVALID_NAME"; break; + case ERROR_INVALID_LEVEL: what = "INVALID_LEVEL"; break; + case ERROR_NO_VOLUME_LABEL: what = "NO_VOLUME_LABEL"; break; + case ERROR_MOD_NOT_FOUND: what = "MOD_NOT_FOUND"; break; + case ERROR_PROC_NOT_FOUND: what = "PROC_NOT_FOUND"; break; + case ERROR_WAIT_NO_CHILDREN: what = "WAIT_NO_CHILDREN"; break; + case ERROR_CHILD_NOT_COMPLETE: what = "CHILD_NOT_COMPLETE"; break; + case ERROR_DIRECT_ACCESS_HANDLE: what = "DIRECT_ACCESS_HANDLE"; break; + case ERROR_NEGATIVE_SEEK: what = "NEGATIVE_SEEK"; break; + case ERROR_SEEK_ON_DEVICE: what = "SEEK_ON_DEVICE"; break; + case ERROR_IS_JOIN_TARGET: what = "IS_JOIN_TARGET"; break; + case ERROR_IS_JOINED: what = "IS_JOINED"; break; + case ERROR_IS_SUBSTED: what = "IS_SUBSTED"; break; + case ERROR_NOT_JOINED: what = "NOT_JOINED"; break; + case ERROR_NOT_SUBSTED: what = "NOT_SUBSTED"; break; + case ERROR_JOIN_TO_JOIN: what = "JOIN_TO_JOIN"; break; + case ERROR_SUBST_TO_SUBST: what = "SUBST_TO_SUBST"; break; + case ERROR_JOIN_TO_SUBST: what = "JOIN_TO_SUBST"; break; + case ERROR_SUBST_TO_JOIN: what = "SUBST_TO_JOIN"; break; + case ERROR_BUSY_DRIVE: what = "BUSY_DRIVE"; break; + case ERROR_SAME_DRIVE: what = "SAME_DRIVE"; break; + case ERROR_DIR_NOT_ROOT: what = "DIR_NOT_ROOT"; break; + case ERROR_DIR_NOT_EMPTY: what = "DIR_NOT_EMPTY"; break; + case ERROR_IS_SUBST_PATH: what = "IS_SUBST_PATH"; break; + case ERROR_IS_JOIN_PATH: what = "IS_JOIN_PATH"; break; + case ERROR_PATH_BUSY: what = "PATH_BUSY"; break; + case ERROR_IS_SUBST_TARGET: what = "IS_SUBST_TARGET"; break; + case ERROR_SYSTEM_TRACE: what = "SYSTEM_TRACE"; break; + case ERROR_INVALID_EVENT_COUNT: what = "INVALID_EVENT_COUNT"; break; + case ERROR_TOO_MANY_MUXWAITERS: what = "TOO_MANY_MUXWAITERS"; break; + case ERROR_INVALID_LIST_FORMAT: what = "INVALID_LIST_FORMAT"; break; + case ERROR_LABEL_TOO_LONG: what = "LABEL_TOO_LONG"; break; + case ERROR_TOO_MANY_TCBS: what = "TOO_MANY_TCBS"; break; + case ERROR_SIGNAL_REFUSED: what = "SIGNAL_REFUSED"; break; + case ERROR_DISCARDED: what = "DISCARDED"; break; + case ERROR_NOT_LOCKED: what = "NOT_LOCKED"; break; + case ERROR_BAD_THREADID_ADDR: what = "BAD_THREADID_ADDR"; break; + case ERROR_BAD_ARGUMENTS: what = "BAD_ARGUMENTS"; break; + case ERROR_BAD_PATHNAME: what = "BAD_PATHNAME"; break; + case ERROR_SIGNAL_PENDING: what = "SIGNAL_PENDING"; break; + case ERROR_MAX_THRDS_REACHED: what = "MAX_THRDS_REACHED"; break; + case ERROR_LOCK_FAILED: what = "LOCK_FAILED"; break; + case ERROR_BUSY: what = "BUSY"; break; + case ERROR_CANCEL_VIOLATION: what = "CANCEL_VIOLATION"; break; + case ERROR_ATOMIC_LOCKS_NOT_SUPPORTED:what = "ATOMIC_LOCKS_NOT_SUPPORTED"; break; + case ERROR_INVALID_SEGMENT_NUMBER: what = "INVALID_SEGMENT_NUMBER"; break; + case ERROR_INVALID_ORDINAL: what = "INVALID_ORDINAL"; break; + case ERROR_ALREADY_EXISTS: what = "ALREADY_EXISTS"; break; + case ERROR_INVALID_FLAG_NUMBER: what = "INVALID_FLAG_NUMBER"; break; + case ERROR_SEM_NOT_FOUND: what = "SEM_NOT_FOUND"; break; + case ERROR_INVALID_STARTING_CODESEG: what = "INVALID_STARTING_CODESEG"; break; + case ERROR_INVALID_STACKSEG: what = "INVALID_STACKSEG"; break; + case ERROR_INVALID_MODULETYPE: what = "INVALID_MODULETYPE"; break; + case ERROR_INVALID_EXE_SIGNATURE: what = "INVALID_EXE_SIGNATURE"; break; + case ERROR_EXE_MARKED_INVALID: what = "EXE_MARKED_INVALID"; break; + case ERROR_BAD_EXE_FORMAT: what = "BAD_EXE_FORMAT"; break; + case ERROR_ITERATED_DATA_EXCEEDS_64k: what = "ITERATED_DATA_EXCEEDS_64k"; break; + case ERROR_INVALID_MINALLOCSIZE: what = "INVALID_MINALLOCSIZE"; break; + case ERROR_DYNLINK_FROM_INVALID_RING: what = "DYNLINK_FROM_INVALID_RING"; break; + case ERROR_IOPL_NOT_ENABLED: what = "IOPL_NOT_ENABLED"; break; + case ERROR_INVALID_SEGDPL: what = "INVALID_SEGDPL"; break; + case ERROR_AUTODATASEG_EXCEEDS_64k: what = "AUTODATASEG_EXCEEDS_64k"; break; + case ERROR_RING2SEG_MUST_BE_MOVABLE: what = "RING2SEG_MUST_BE_MOVABLE"; break; + case ERROR_RELOC_CHAIN_XEEDS_SEGLIM: what = "RELOC_CHAIN_XEEDS_SEGLIM"; break; + case ERROR_INFLOOP_IN_RELOC_CHAIN: what = "INFLOOP_IN_RELOC_CHAIN"; break; + case ERROR_ENVVAR_NOT_FOUND: what = "ENVVAR_NOT_FOUND"; break; + case ERROR_NO_SIGNAL_SENT: what = "NO_SIGNAL_SENT"; break; + case ERROR_FILENAME_EXCED_RANGE: what = "FILENAME_EXCED_RANGE"; break; + case ERROR_RING2_STACK_IN_USE: what = "RING2_STACK_IN_USE"; break; + case ERROR_META_EXPANSION_TOO_LONG: what = "META_EXPANSION_TOO_LONG"; break; + case ERROR_INVALID_SIGNAL_NUMBER: what = "INVALID_SIGNAL_NUMBER"; break; + case ERROR_THREAD_1_INACTIVE: what = "THREAD_1_INACTIVE"; break; + case ERROR_LOCKED: what = "LOCKED"; break; + case ERROR_TOO_MANY_MODULES: what = "TOO_MANY_MODULES"; break; + case ERROR_NESTING_NOT_ALLOWED: what = "NESTING_NOT_ALLOWED"; break; + case ERROR_BAD_PIPE: what = "BAD_PIPE"; break; + case ERROR_PIPE_BUSY: what = "PIPE_BUSY"; break; + case ERROR_NO_DATA: what = "NO_DATA"; break; + case ERROR_PIPE_NOT_CONNECTED: what = "PIPE_NOT_CONNECTED"; break; + case ERROR_MORE_DATA: what = "MORE_DATA"; break; + case ERROR_VC_DISCONNECTED: what = "VC_DISCONNECTED"; break; + case ERROR_INVALID_EA_NAME: what = "INVALID_EA_NAME"; break; + case ERROR_EA_LIST_INCONSISTENT: what = "EA_LIST_INCONSISTENT"; break; + case ERROR_NO_MORE_ITEMS: what = "NO_MORE_ITEMS"; break; + case ERROR_CANNOT_COPY: what = "CANNOT_COPY"; break; + case ERROR_DIRECTORY: what = "DIRECTORY"; break; + case ERROR_EAS_DIDNT_FIT: what = "EAS_DIDNT_FIT"; break; + case ERROR_EA_FILE_CORRUPT: what = "EA_FILE_CORRUPT"; break; + case ERROR_EA_TABLE_FULL: what = "EA_TABLE_FULL"; break; + case ERROR_INVALID_EA_HANDLE: what = "INVALID_EA_HANDLE"; break; + case ERROR_EAS_NOT_SUPPORTED: what = "EAS_NOT_SUPPORTED"; break; + case ERROR_NOT_OWNER: what = "NOT_OWNER"; break; + case ERROR_TOO_MANY_POSTS: what = "TOO_MANY_POSTS"; break; + case ERROR_PARTIAL_COPY: what = "PARTIAL_COPY"; break; + case ERROR_MR_MID_NOT_FOUND: what = "MR_MID_NOT_FOUND"; break; + case ERROR_INVALID_ADDRESS: what = "INVALID_ADDRESS"; break; + case ERROR_ARITHMETIC_OVERFLOW: what = "ARITHMETIC_OVERFLOW"; break; + case ERROR_PIPE_CONNECTED: what = "PIPE_CONNECTED"; break; + case ERROR_PIPE_LISTENING: what = "PIPE_LISTENING"; break; + case ERROR_EA_ACCESS_DENIED: what = "EA_ACCESS_DENIED"; break; + case ERROR_OPERATION_ABORTED: what = "OPERATION_ABORTED"; break; + case ERROR_IO_INCOMPLETE: what = "IO_INCOMPLETE"; break; + case ERROR_IO_PENDING: what = "IO_PENDING"; break; + case ERROR_NOACCESS: what = "NOACCESS"; break; + case ERROR_SWAPERROR: what = "SWAPERROR"; break; + case ERROR_STACK_OVERFLOW: what = "STACK_OVERFLOW"; break; + case ERROR_INVALID_MESSAGE: what = "INVALID_MESSAGE"; break; + case ERROR_CAN_NOT_COMPLETE: what = "CAN_NOT_COMPLETE"; break; + case ERROR_INVALID_FLAGS: what = "INVALID_FLAGS"; break; + case ERROR_UNRECOGNIZED_VOLUME: what = "UNRECOGNIZED_VOLUME"; break; + case ERROR_FILE_INVALID: what = "FILE_INVALID"; break; + case ERROR_FULLSCREEN_MODE: what = "FULLSCREEN_MODE"; break; + case ERROR_NO_TOKEN: what = "NO_TOKEN"; break; + case ERROR_BADDB: what = "BADDB"; break; + case ERROR_BADKEY: what = "BADKEY"; break; + case ERROR_CANTOPEN: what = "CANTOPEN"; break; + case ERROR_CANTREAD: what = "CANTREAD"; break; + case ERROR_CANTWRITE: what = "CANTWRITE"; break; + case ERROR_REGISTRY_RECOVERED: what = "REGISTRY_RECOVERED"; break; + case ERROR_REGISTRY_CORRUPT: what = "REGISTRY_CORRUPT"; break; + case ERROR_REGISTRY_IO_FAILED: what = "REGISTRY_IO_FAILED"; break; + case ERROR_NOT_REGISTRY_FILE: what = "NOT_REGISTRY_FILE"; break; + case ERROR_KEY_DELETED: what = "KEY_DELETED"; break; + case ERROR_NO_LOG_SPACE: what = "NO_LOG_SPACE"; break; + case ERROR_KEY_HAS_CHILDREN: what = "KEY_HAS_CHILDREN"; break; + case ERROR_CHILD_MUST_BE_VOLATILE: what = "CHILD_MUST_BE_VOLATILE"; break; + case ERROR_NOTIFY_ENUM_DIR: what = "NOTIFY_ENUM_DIR"; break; + case ERROR_DEPENDENT_SERVICES_RUNNING:what = "DEPENDENT_SERVICES_RUNNING"; break; + case ERROR_INVALID_SERVICE_CONTROL: what = "INVALID_SERVICE_CONTROL"; break; + case ERROR_SERVICE_REQUEST_TIMEOUT: what = "SERVICE_REQUEST_TIMEOUT"; break; + case ERROR_SERVICE_NO_THREAD: what = "SERVICE_NO_THREAD"; break; + case ERROR_SERVICE_DATABASE_LOCKED: what = "SERVICE_DATABASE_LOCKED"; break; + case ERROR_SERVICE_ALREADY_RUNNING: what = "SERVICE_ALREADY_RUNNING"; break; + case ERROR_INVALID_SERVICE_ACCOUNT: what = "INVALID_SERVICE_ACCOUNT"; break; + case ERROR_SERVICE_DISABLED: what = "SERVICE_DISABLED"; break; + case ERROR_CIRCULAR_DEPENDENCY: what = "CIRCULAR_DEPENDENCY"; break; + case ERROR_SERVICE_DOES_NOT_EXIST: what = "SERVICE_DOES_NOT_EXIST"; break; + case ERROR_SERVICE_CANNOT_ACCEPT_CTRL:what = "SERVICE_CANNOT_ACCEPT_CTRL"; break; + case ERROR_SERVICE_NOT_ACTIVE: what = "SERVICE_NOT_ACTIVE"; break; + case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT: what = "FAILED_SERVICE_CONTROLLER_CONNECT"; break; + case ERROR_EXCEPTION_IN_SERVICE: what = "EXCEPTION_IN_SERVICE"; break; + case ERROR_DATABASE_DOES_NOT_EXIST: what = "DATABASE_DOES_NOT_EXIST"; break; + case ERROR_SERVICE_SPECIFIC_ERROR: what = "SERVICE_SPECIFIC_ERROR"; break; + case ERROR_PROCESS_ABORTED: what = "PROCESS_ABORTED"; break; + case ERROR_SERVICE_DEPENDENCY_FAIL: what = "SERVICE_DEPENDENCY_FAIL"; break; + case ERROR_SERVICE_LOGON_FAILED: what = "SERVICE_LOGON_FAILED"; break; + case ERROR_SERVICE_START_HANG: what = "SERVICE_START_HANG"; break; + case ERROR_INVALID_SERVICE_LOCK: what = "INVALID_SERVICE_LOCK"; break; + case ERROR_SERVICE_MARKED_FOR_DELETE: what = "SERVICE_MARKED_FOR_DELETE"; break; + case ERROR_SERVICE_EXISTS: what = "SERVICE_EXISTS"; break; + case ERROR_ALREADY_RUNNING_LKG: what = "ALREADY_RUNNING_LKG"; break; + case ERROR_SERVICE_DEPENDENCY_DELETED:what = "SERVICE_DEPENDENCY_DELETED"; break; + case ERROR_BOOT_ALREADY_ACCEPTED: what = "BOOT_ALREADY_ACCEPTED"; break; + case ERROR_SERVICE_NEVER_STARTED: what = "SERVICE_NEVER_STARTED"; break; + case ERROR_DUPLICATE_SERVICE_NAME: what = "DUPLICATE_SERVICE_NAME"; break; + case ERROR_END_OF_MEDIA: what = "END_OF_MEDIA"; break; + case ERROR_FILEMARK_DETECTED: what = "FILEMARK_DETECTED"; break; + case ERROR_BEGINNING_OF_MEDIA: what = "BEGINNING_OF_MEDIA"; break; + case ERROR_SETMARK_DETECTED: what = "SETMARK_DETECTED"; break; + case ERROR_NO_DATA_DETECTED: what = "NO_DATA_DETECTED"; break; + case ERROR_PARTITION_FAILURE: what = "PARTITION_FAILURE"; break; + case ERROR_INVALID_BLOCK_LENGTH: what = "INVALID_BLOCK_LENGTH"; break; + case ERROR_DEVICE_NOT_PARTITIONED: what = "DEVICE_NOT_PARTITIONED"; break; + case ERROR_UNABLE_TO_LOCK_MEDIA: what = "UNABLE_TO_LOCK_MEDIA"; break; + case ERROR_UNABLE_TO_UNLOAD_MEDIA: what = "UNABLE_TO_UNLOAD_MEDIA"; break; + case ERROR_MEDIA_CHANGED: what = "MEDIA_CHANGED"; break; + case ERROR_BUS_RESET: what = "BUS_RESET"; break; + case ERROR_NO_MEDIA_IN_DRIVE: what = "NO_MEDIA_IN_DRIVE"; break; + case ERROR_NO_UNICODE_TRANSLATION: what = "NO_UNICODE_TRANSLATION"; break; + case ERROR_DLL_INIT_FAILED: what = "DLL_INIT_FAILED"; break; + case ERROR_SHUTDOWN_IN_PROGRESS: what = "SHUTDOWN_IN_PROGRESS"; break; + case ERROR_NO_SHUTDOWN_IN_PROGRESS: what = "NO_SHUTDOWN_IN_PROGRESS"; break; + case ERROR_IO_DEVICE: what = "IO_DEVICE"; break; + case ERROR_SERIAL_NO_DEVICE: what = "SERIAL_NO_DEVICE"; break; + case ERROR_IRQ_BUSY: what = "IRQ_BUSY"; break; + case ERROR_MORE_WRITES: what = "MORE_WRITES"; break; + case ERROR_COUNTER_TIMEOUT: what = "COUNTER_TIMEOUT"; break; + case ERROR_FLOPPY_ID_MARK_NOT_FOUND: what = "FLOPPY_ID_MARK_NOT_FOUND"; break; + case ERROR_FLOPPY_WRONG_CYLINDER: what = "FLOPPY_WRONG_CYLINDER"; break; + case ERROR_FLOPPY_UNKNOWN_ERROR: what = "FLOPPY_UNKNOWN_ERROR"; break; + case ERROR_FLOPPY_BAD_REGISTERS: what = "FLOPPY_BAD_REGISTERS"; break; + case ERROR_DISK_RECALIBRATE_FAILED: what = "DISK_RECALIBRATE_FAILED"; break; + case ERROR_DISK_OPERATION_FAILED: what = "DISK_OPERATION_FAILED"; break; + case ERROR_DISK_RESET_FAILED: what = "DISK_RESET_FAILED"; break; + case ERROR_EOM_OVERFLOW: what = "EOM_OVERFLOW"; break; + case ERROR_NOT_ENOUGH_SERVER_MEMORY: what = "NOT_ENOUGH_SERVER_MEMORY"; break; + case ERROR_POSSIBLE_DEADLOCK: what = "POSSIBLE_DEADLOCK"; break; + case ERROR_MAPPED_ALIGNMENT: what = "MAPPED_ALIGNMENT"; break; + case ERROR_BAD_USERNAME: what = "BAD_USERNAME"; break; + case ERROR_NOT_CONNECTED: what = "NOT_CONNECTED"; break; + case ERROR_OPEN_FILES: what = "OPEN_FILES"; break; + case ERROR_ACTIVE_CONNECTIONS: what = "ACTIVE_CONNECTIONS"; break; + case ERROR_DEVICE_IN_USE: what = "DEVICE_IN_USE"; break; + case ERROR_BAD_DEVICE: what = "BAD_DEVICE"; break; + case ERROR_CONNECTION_UNAVAIL: what = "CONNECTION_UNAVAIL"; break; + case ERROR_DEVICE_ALREADY_REMEMBERED: what = "DEVICE_ALREADY_REMEMBERED"; break; + case ERROR_NO_NET_OR_BAD_PATH: what = "NO_NET_OR_BAD_PATH"; break; + case ERROR_BAD_PROVIDER: what = "BAD_PROVIDER"; break; + case ERROR_CANNOT_OPEN_PROFILE: what = "CANNOT_OPEN_PROFILE"; break; + case ERROR_BAD_PROFILE: what = "BAD_PROFILE"; break; + case ERROR_NOT_CONTAINER: what = "NOT_CONTAINER"; break; + case ERROR_EXTENDED_ERROR: what = "EXTENDED_ERROR"; break; + case ERROR_INVALID_GROUPNAME: what = "INVALID_GROUPNAME"; break; + case ERROR_INVALID_COMPUTERNAME: what = "INVALID_COMPUTERNAME"; break; + case ERROR_INVALID_EVENTNAME: what = "INVALID_EVENTNAME"; break; + case ERROR_INVALID_DOMAINNAME: what = "INVALID_DOMAINNAME"; break; + case ERROR_INVALID_SERVICENAME: what = "INVALID_SERVICENAME"; break; + case ERROR_INVALID_NETNAME: what = "INVALID_NETNAME"; break; + case ERROR_INVALID_SHARENAME: what = "INVALID_SHARENAME"; break; + case ERROR_INVALID_PASSWORDNAME: what = "INVALID_PASSWORDNAME"; break; + case ERROR_INVALID_MESSAGENAME: what = "INVALID_MESSAGENAME"; break; + case ERROR_INVALID_MESSAGEDEST: what = "INVALID_MESSAGEDEST"; break; + case ERROR_SESSION_CREDENTIAL_CONFLICT: what = "SESSION_CREDENTIAL_CONFLICT"; break; + case ERROR_REMOTE_SESSION_LIMIT_EXCEEDED: what = "REMOTE_SESSION_LIMIT_EXCEEDED"; break; + case ERROR_DUP_DOMAINNAME: what = "DUP_DOMAINNAME"; break; + case ERROR_NO_NETWORK: what = "NO_NETWORK"; break; + case ERROR_CANCELLED: what = "CANCELLED"; break; + case ERROR_USER_MAPPED_FILE: what = "USER_MAPPED_FILE"; break; + case ERROR_CONNECTION_REFUSED: what = "CONNECTION_REFUSED"; break; + case ERROR_GRACEFUL_DISCONNECT: what = "GRACEFUL_DISCONNECT"; break; + case ERROR_ADDRESS_ALREADY_ASSOCIATED:what = "ADDRESS_ALREADY_ASSOCIATED"; break; + case ERROR_ADDRESS_NOT_ASSOCIATED: what = "ADDRESS_NOT_ASSOCIATED"; break; + case ERROR_CONNECTION_INVALID: what = "CONNECTION_INVALID"; break; + case ERROR_CONNECTION_ACTIVE: what = "CONNECTION_ACTIVE"; break; + case ERROR_NETWORK_UNREACHABLE: what = "NETWORK_UNREACHABLE"; break; + case ERROR_HOST_UNREACHABLE: what = "HOST_UNREACHABLE"; break; + case ERROR_PROTOCOL_UNREACHABLE: what = "PROTOCOL_UNREACHABLE"; break; + case ERROR_PORT_UNREACHABLE: what = "PORT_UNREACHABLE"; break; + case ERROR_REQUEST_ABORTED: what = "REQUEST_ABORTED"; break; + case ERROR_CONNECTION_ABORTED: what = "CONNECTION_ABORTED"; break; + case ERROR_RETRY: what = "RETRY"; break; + case ERROR_CONNECTION_COUNT_LIMIT: what = "CONNECTION_COUNT_LIMIT"; break; + case ERROR_LOGIN_TIME_RESTRICTION: what = "LOGIN_TIME_RESTRICTION"; break; + case ERROR_LOGIN_WKSTA_RESTRICTION: what = "LOGIN_WKSTA_RESTRICTION"; break; + case ERROR_INCORRECT_ADDRESS: what = "INCORRECT_ADDRESS"; break; + case ERROR_ALREADY_REGISTERED: what = "ALREADY_REGISTERED"; break; + case ERROR_SERVICE_NOT_FOUND: what = "SERVICE_NOT_FOUND"; break; + case ERROR_NOT_ALL_ASSIGNED: what = "NOT_ALL_ASSIGNED"; break; + case ERROR_SOME_NOT_MAPPED: what = "SOME_NOT_MAPPED"; break; + case ERROR_NO_QUOTAS_FOR_ACCOUNT: what = "NO_QUOTAS_FOR_ACCOUNT"; break; + case ERROR_LOCAL_USER_SESSION_KEY: what = "LOCAL_USER_SESSION_KEY"; break; + case ERROR_NULL_LM_PASSWORD: what = "NULL_LM_PASSWORD"; break; + case ERROR_UNKNOWN_REVISION: what = "UNKNOWN_REVISION"; break; + case ERROR_REVISION_MISMATCH: what = "REVISION_MISMATCH"; break; + case ERROR_INVALID_OWNER: what = "INVALID_OWNER"; break; + case ERROR_INVALID_PRIMARY_GROUP: what = "INVALID_PRIMARY_GROUP"; break; + case ERROR_NO_IMPERSONATION_TOKEN: what = "NO_IMPERSONATION_TOKEN"; break; + case ERROR_CANT_DISABLE_MANDATORY: what = "CANT_DISABLE_MANDATORY"; break; + case ERROR_NO_LOGON_SERVERS: what = "NO_LOGON_SERVERS"; break; + case ERROR_NO_SUCH_LOGON_SESSION: what = "NO_SUCH_LOGON_SESSION"; break; + case ERROR_NO_SUCH_PRIVILEGE: what = "NO_SUCH_PRIVILEGE"; break; + case ERROR_PRIVILEGE_NOT_HELD: what = "PRIVILEGE_NOT_HELD"; break; + case ERROR_INVALID_ACCOUNT_NAME: what = "INVALID_ACCOUNT_NAME"; break; + case ERROR_USER_EXISTS: what = "USER_EXISTS"; break; + case ERROR_NO_SUCH_USER: what = "NO_SUCH_USER"; break; + case ERROR_GROUP_EXISTS: what = "GROUP_EXISTS"; break; + case ERROR_NO_SUCH_GROUP: what = "NO_SUCH_GROUP"; break; + case ERROR_MEMBER_IN_GROUP: what = "MEMBER_IN_GROUP"; break; + case ERROR_MEMBER_NOT_IN_GROUP: what = "MEMBER_NOT_IN_GROUP"; break; + case ERROR_LAST_ADMIN: what = "LAST_ADMIN"; break; + case ERROR_WRONG_PASSWORD: what = "WRONG_PASSWORD"; break; + case ERROR_ILL_FORMED_PASSWORD: what = "ILL_FORMED_PASSWORD"; break; + case ERROR_PASSWORD_RESTRICTION: what = "PASSWORD_RESTRICTION"; break; + case ERROR_LOGON_FAILURE: what = "LOGON_FAILURE"; break; + case ERROR_ACCOUNT_RESTRICTION: what = "ACCOUNT_RESTRICTION"; break; + case ERROR_INVALID_LOGON_HOURS: what = "INVALID_LOGON_HOURS"; break; + case ERROR_INVALID_WORKSTATION: what = "INVALID_WORKSTATION"; break; + case ERROR_PASSWORD_EXPIRED: what = "PASSWORD_EXPIRED"; break; + case ERROR_ACCOUNT_DISABLED: what = "ACCOUNT_DISABLED"; break; + case ERROR_NONE_MAPPED: what = "NONE_MAPPED"; break; + case ERROR_TOO_MANY_LUIDS_REQUESTED: what = "TOO_MANY_LUIDS_REQUESTED"; break; + case ERROR_LUIDS_EXHAUSTED: what = "LUIDS_EXHAUSTED"; break; + case ERROR_INVALID_SUB_AUTHORITY: what = "INVALID_SUB_AUTHORITY"; break; + case ERROR_INVALID_ACL: what = "INVALID_ACL"; break; + case ERROR_INVALID_SID: what = "INVALID_SID"; break; + case ERROR_INVALID_SECURITY_DESCR: what = "INVALID_SECURITY_DESCR"; break; + case ERROR_BAD_INHERITANCE_ACL: what = "BAD_INHERITANCE_ACL"; break; + case ERROR_SERVER_DISABLED: what = "SERVER_DISABLED"; break; + case ERROR_SERVER_NOT_DISABLED: what = "SERVER_NOT_DISABLED"; break; + case ERROR_INVALID_ID_AUTHORITY: what = "INVALID_ID_AUTHORITY"; break; + case ERROR_ALLOTTED_SPACE_EXCEEDED: what = "ALLOTTED_SPACE_EXCEEDED"; break; + case ERROR_INVALID_GROUP_ATTRIBUTES: what = "INVALID_GROUP_ATTRIBUTES"; break; + case ERROR_BAD_IMPERSONATION_LEVEL: what = "BAD_IMPERSONATION_LEVEL"; break; + case ERROR_CANT_OPEN_ANONYMOUS: what = "CANT_OPEN_ANONYMOUS"; break; + case ERROR_BAD_VALIDATION_CLASS: what = "BAD_VALIDATION_CLASS"; break; + case ERROR_BAD_TOKEN_TYPE: what = "BAD_TOKEN_TYPE"; break; + case ERROR_NO_SECURITY_ON_OBJECT: what = "NO_SECURITY_ON_OBJECT"; break; + case ERROR_CANT_ACCESS_DOMAIN_INFO: what = "CANT_ACCESS_DOMAIN_INFO"; break; + case ERROR_INVALID_SERVER_STATE: what = "INVALID_SERVER_STATE"; break; + case ERROR_INVALID_DOMAIN_STATE: what = "INVALID_DOMAIN_STATE"; break; + case ERROR_INVALID_DOMAIN_ROLE: what = "INVALID_DOMAIN_ROLE"; break; + case ERROR_NO_SUCH_DOMAIN: what = "NO_SUCH_DOMAIN"; break; + case ERROR_DOMAIN_EXISTS: what = "DOMAIN_EXISTS"; break; + case ERROR_DOMAIN_LIMIT_EXCEEDED: what = "DOMAIN_LIMIT_EXCEEDED"; break; + case ERROR_INTERNAL_DB_CORRUPTION: what = "INTERNAL_DB_CORRUPTION"; break; + case ERROR_INTERNAL_ERROR: what = "INTERNAL_ERROR"; break; + case ERROR_GENERIC_NOT_MAPPED: what = "GENERIC_NOT_MAPPED"; break; + case ERROR_BAD_DESCRIPTOR_FORMAT: what = "BAD_DESCRIPTOR_FORMAT"; break; + case ERROR_NOT_LOGON_PROCESS: what = "NOT_LOGON_PROCESS"; break; + case ERROR_LOGON_SESSION_EXISTS: what = "LOGON_SESSION_EXISTS"; break; + case ERROR_NO_SUCH_PACKAGE: what = "NO_SUCH_PACKAGE"; break; + case ERROR_BAD_LOGON_SESSION_STATE: what = "BAD_LOGON_SESSION_STATE"; break; + case ERROR_LOGON_SESSION_COLLISION: what = "LOGON_SESSION_COLLISION"; break; + case ERROR_INVALID_LOGON_TYPE: what = "INVALID_LOGON_TYPE"; break; + case ERROR_CANNOT_IMPERSONATE: what = "CANNOT_IMPERSONATE"; break; + case ERROR_RXACT_INVALID_STATE: what = "RXACT_INVALID_STATE"; break; + case ERROR_RXACT_COMMIT_FAILURE: what = "RXACT_COMMIT_FAILURE"; break; + case ERROR_SPECIAL_ACCOUNT: what = "SPECIAL_ACCOUNT"; break; + case ERROR_SPECIAL_GROUP: what = "SPECIAL_GROUP"; break; + case ERROR_SPECIAL_USER: what = "SPECIAL_USER"; break; + case ERROR_MEMBERS_PRIMARY_GROUP: what = "MEMBERS_PRIMARY_GROUP"; break; + case ERROR_TOKEN_ALREADY_IN_USE: what = "TOKEN_ALREADY_IN_USE"; break; + case ERROR_NO_SUCH_ALIAS: what = "NO_SUCH_ALIAS"; break; + case ERROR_MEMBER_NOT_IN_ALIAS: what = "MEMBER_NOT_IN_ALIAS"; break; + case ERROR_MEMBER_IN_ALIAS: what = "MEMBER_IN_ALIAS"; break; + case ERROR_ALIAS_EXISTS: what = "ALIAS_EXISTS"; break; + case ERROR_LOGON_NOT_GRANTED: what = "LOGON_NOT_GRANTED"; break; + case ERROR_TOO_MANY_SECRETS: what = "TOO_MANY_SECRETS"; break; + case ERROR_SECRET_TOO_LONG: what = "SECRET_TOO_LONG"; break; + case ERROR_INTERNAL_DB_ERROR: what = "INTERNAL_DB_ERROR"; break; + case ERROR_TOO_MANY_CONTEXT_IDS: what = "TOO_MANY_CONTEXT_IDS"; break; + case ERROR_LOGON_TYPE_NOT_GRANTED: what = "LOGON_TYPE_NOT_GRANTED"; break; + case ERROR_NT_CROSS_ENCRYPTION_REQUIRED: what = "NT_CROSS_ENCRYPTION_REQUIRED"; break; + case ERROR_NO_SUCH_MEMBER: what = "NO_SUCH_MEMBER"; break; + case ERROR_INVALID_MEMBER: what = "INVALID_MEMBER"; break; + case ERROR_TOO_MANY_SIDS: what = "TOO_MANY_SIDS"; break; + case ERROR_LM_CROSS_ENCRYPTION_REQUIRED: what = "LM_CROSS_ENCRYPTION_REQUIRED"; break; + case ERROR_NO_INHERITANCE: what = "NO_INHERITANCE"; break; + case ERROR_FILE_CORRUPT: what = "FILE_CORRUPT"; break; + case ERROR_DISK_CORRUPT: what = "DISK_CORRUPT"; break; + case ERROR_NO_USER_SESSION_KEY: what = "NO_USER_SESSION_KEY"; break; + case ERROR_INVALID_WINDOW_HANDLE: what = "INVALID_WINDOW_HANDLE"; break; + case ERROR_INVALID_MENU_HANDLE: what = "INVALID_MENU_HANDLE"; break; + case ERROR_INVALID_CURSOR_HANDLE: what = "INVALID_CURSOR_HANDLE"; break; + case ERROR_INVALID_ACCEL_HANDLE: what = "INVALID_ACCEL_HANDLE"; break; + case ERROR_INVALID_HOOK_HANDLE: what = "INVALID_HOOK_HANDLE"; break; + case ERROR_INVALID_DWP_HANDLE: what = "INVALID_DWP_HANDLE"; break; + case ERROR_TLW_WITH_WSCHILD: what = "TLW_WITH_WSCHILD"; break; + case ERROR_CANNOT_FIND_WND_CLASS: what = "CANNOT_FIND_WND_CLASS"; break; + case ERROR_WINDOW_OF_OTHER_THREAD: what = "WINDOW_OF_OTHER_THREAD"; break; + case ERROR_HOTKEY_ALREADY_REGISTERED: what = "HOTKEY_ALREADY_REGISTERED"; break; + case ERROR_CLASS_ALREADY_EXISTS: what = "CLASS_ALREADY_EXISTS"; break; + case ERROR_CLASS_DOES_NOT_EXIST: what = "CLASS_DOES_NOT_EXIST"; break; + case ERROR_CLASS_HAS_WINDOWS: what = "CLASS_HAS_WINDOWS"; break; + case ERROR_INVALID_INDEX: what = "INVALID_INDEX"; break; + case ERROR_INVALID_ICON_HANDLE: what = "INVALID_ICON_HANDLE"; break; + case ERROR_PRIVATE_DIALOG_INDEX: what = "PRIVATE_DIALOG_INDEX"; break; + case ERROR_LISTBOX_ID_NOT_FOUND: what = "LISTBOX_ID_NOT_FOUND"; break; + case ERROR_NO_WILDCARD_CHARACTERS: what = "NO_WILDCARD_CHARACTERS"; break; + case ERROR_CLIPBOARD_NOT_OPEN: what = "CLIPBOARD_NOT_OPEN"; break; + case ERROR_HOTKEY_NOT_REGISTERED: what = "HOTKEY_NOT_REGISTERED"; break; + case ERROR_WINDOW_NOT_DIALOG: what = "WINDOW_NOT_DIALOG"; break; + case ERROR_CONTROL_ID_NOT_FOUND: what = "CONTROL_ID_NOT_FOUND"; break; + case ERROR_INVALID_COMBOBOX_MESSAGE: what = "INVALID_COMBOBOX_MESSAGE"; break; + case ERROR_WINDOW_NOT_COMBOBOX: what = "WINDOW_NOT_COMBOBOX"; break; + case ERROR_INVALID_EDIT_HEIGHT: what = "INVALID_EDIT_HEIGHT"; break; + case ERROR_DC_NOT_FOUND: what = "DC_NOT_FOUND"; break; + case ERROR_INVALID_HOOK_FILTER: what = "INVALID_HOOK_FILTER"; break; + case ERROR_INVALID_FILTER_PROC: what = "INVALID_FILTER_PROC"; break; + case ERROR_HOOK_NEEDS_HMOD: what = "HOOK_NEEDS_HMOD"; break; + case ERROR_GLOBAL_ONLY_HOOK: what = "GLOBAL_ONLY_HOOK"; break; + case ERROR_JOURNAL_HOOK_SET: what = "JOURNAL_HOOK_SET"; break; + case ERROR_HOOK_NOT_INSTALLED: what = "HOOK_NOT_INSTALLED"; break; + case ERROR_INVALID_LB_MESSAGE: what = "INVALID_LB_MESSAGE"; break; + case ERROR_SETCOUNT_ON_BAD_LB: what = "SETCOUNT_ON_BAD_LB"; break; + case ERROR_LB_WITHOUT_TABSTOPS: what = "LB_WITHOUT_TABSTOPS"; break; + case ERROR_DESTROY_OBJECT_OF_OTHER_THREAD: what = "DESTROY_OBJECT_OF_OTHER_THREAD"; break; + case ERROR_CHILD_WINDOW_MENU: what = "CHILD_WINDOW_MENU"; break; + case ERROR_NO_SYSTEM_MENU: what = "NO_SYSTEM_MENU"; break; + case ERROR_INVALID_MSGBOX_STYLE: what = "INVALID_MSGBOX_STYLE"; break; + case ERROR_INVALID_SPI_VALUE: what = "INVALID_SPI_VALUE"; break; + case ERROR_SCREEN_ALREADY_LOCKED: what = "SCREEN_ALREADY_LOCKED"; break; + case ERROR_HWNDS_HAVE_DIFF_PARENT: what = "HWNDS_HAVE_DIFF_PARENT"; break; + case ERROR_NOT_CHILD_WINDOW: what = "NOT_CHILD_WINDOW"; break; + case ERROR_INVALID_GW_COMMAND: what = "INVALID_GW_COMMAND"; break; + case ERROR_INVALID_THREAD_ID: what = "INVALID_THREAD_ID"; break; + case ERROR_NON_MDICHILD_WINDOW: what = "NON_MDICHILD_WINDOW"; break; + case ERROR_POPUP_ALREADY_ACTIVE: what = "POPUP_ALREADY_ACTIVE"; break; + case ERROR_NO_SCROLLBARS: what = "NO_SCROLLBARS"; break; + case ERROR_INVALID_SCROLLBAR_RANGE: what = "INVALID_SCROLLBAR_RANGE"; break; + case ERROR_INVALID_SHOWWIN_COMMAND: what = "INVALID_SHOWWIN_COMMAND"; break; + case ERROR_EVENTLOG_FILE_CORRUPT: what = "EVENTLOG_FILE_CORRUPT"; break; + case ERROR_EVENTLOG_CANT_START: what = "EVENTLOG_CANT_START"; break; + case ERROR_LOG_FILE_FULL: what = "LOG_FILE_FULL"; break; + case ERROR_EVENTLOG_FILE_CHANGED: what = "EVENTLOG_FILE_CHANGED"; break; + case RPC_S_INVALID_STRING_BINDING: what = "RPC_S_INVALID_STRING_BINDING"; break; + case RPC_S_WRONG_KIND_OF_BINDING: what = "RPC_S_WRONG_KIND_OF_BINDING"; break; + case RPC_S_INVALID_BINDING: what = "RPC_S_INVALID_BINDING"; break; + case RPC_S_PROTSEQ_NOT_SUPPORTED: what = "RPC_S_PROTSEQ_NOT_SUPPORTED"; break; + case RPC_S_INVALID_RPC_PROTSEQ: what = "RPC_S_INVALID_RPC_PROTSEQ"; break; + case RPC_S_INVALID_STRING_UUID: what = "RPC_S_INVALID_STRING_UUID"; break; + case RPC_S_INVALID_ENDPOINT_FORMAT: what = "RPC_S_INVALID_ENDPOINT_FORMAT"; break; + case RPC_S_INVALID_NET_ADDR: what = "RPC_S_INVALID_NET_ADDR"; break; + case RPC_S_NO_ENDPOINT_FOUND: what = "RPC_S_NO_ENDPOINT_FOUND"; break; + case RPC_S_INVALID_TIMEOUT: what = "RPC_S_INVALID_TIMEOUT"; break; + case RPC_S_OBJECT_NOT_FOUND: what = "RPC_S_OBJECT_NOT_FOUND"; break; + case RPC_S_ALREADY_REGISTERED: what = "RPC_S_ALREADY_REGISTERED"; break; + case RPC_S_TYPE_ALREADY_REGISTERED: what = "RPC_S_TYPE_ALREADY_REGISTERED"; break; + case RPC_S_ALREADY_LISTENING: what = "RPC_S_ALREADY_LISTENING"; break; + case RPC_S_NO_PROTSEQS_REGISTERED: what = "RPC_S_NO_PROTSEQS_REGISTERED"; break; + case RPC_S_NOT_LISTENING: what = "RPC_S_NOT_LISTENING"; break; + case RPC_S_UNKNOWN_MGR_TYPE: what = "RPC_S_UNKNOWN_MGR_TYPE"; break; + case RPC_S_UNKNOWN_IF: what = "RPC_S_UNKNOWN_IF"; break; + case RPC_S_NO_BINDINGS: what = "RPC_S_NO_BINDINGS"; break; + case RPC_S_NO_PROTSEQS: what = "RPC_S_NO_PROTSEQS"; break; + case RPC_S_CANT_CREATE_ENDPOINT: what = "RPC_S_CANT_CREATE_ENDPOINT"; break; + case RPC_S_OUT_OF_RESOURCES: what = "RPC_S_OUT_OF_RESOURCES"; break; + case RPC_S_SERVER_UNAVAILABLE: what = "RPC_S_SERVER_UNAVAILABLE"; break; + case RPC_S_SERVER_TOO_BUSY: what = "RPC_S_SERVER_TOO_BUSY"; break; + case RPC_S_INVALID_NETWORK_OPTIONS: what = "RPC_S_INVALID_NETWORK_OPTIONS"; break; + case RPC_S_NO_CALL_ACTIVE: what = "RPC_S_NO_CALL_ACTIVE"; break; + case RPC_S_CALL_FAILED: what = "RPC_S_CALL_FAILED"; break; + case RPC_S_CALL_FAILED_DNE: what = "RPC_S_CALL_FAILED_DNE"; break; + case RPC_S_PROTOCOL_ERROR: what = "RPC_S_PROTOCOL_ERROR"; break; + case RPC_S_UNSUPPORTED_TRANS_SYN: what = "RPC_S_UNSUPPORTED_TRANS_SYN"; break; + case RPC_S_UNSUPPORTED_TYPE: what = "RPC_S_UNSUPPORTED_TYPE"; break; + case RPC_S_INVALID_TAG: what = "RPC_S_INVALID_TAG"; break; + case RPC_S_INVALID_BOUND: what = "RPC_S_INVALID_BOUND"; break; + case RPC_S_NO_ENTRY_NAME: what = "RPC_S_NO_ENTRY_NAME"; break; + case RPC_S_INVALID_NAME_SYNTAX: what = "RPC_S_INVALID_NAME_SYNTAX"; break; + case RPC_S_UNSUPPORTED_NAME_SYNTAX: what = "RPC_S_UNSUPPORTED_NAME_SYNTAX"; break; + case RPC_S_UUID_NO_ADDRESS: what = "RPC_S_UUID_NO_ADDRESS"; break; + case RPC_S_DUPLICATE_ENDPOINT: what = "RPC_S_DUPLICATE_ENDPOINT"; break; + case RPC_S_UNKNOWN_AUTHN_TYPE: what = "RPC_S_UNKNOWN_AUTHN_TYPE"; break; + case RPC_S_MAX_CALLS_TOO_SMALL: what = "RPC_S_MAX_CALLS_TOO_SMALL"; break; + case RPC_S_STRING_TOO_LONG: what = "RPC_S_STRING_TOO_LONG"; break; + case RPC_S_PROTSEQ_NOT_FOUND: what = "RPC_S_PROTSEQ_NOT_FOUND"; break; + case RPC_S_PROCNUM_OUT_OF_RANGE: what = "RPC_S_PROCNUM_OUT_OF_RANGE"; break; + case RPC_S_BINDING_HAS_NO_AUTH: what = "RPC_S_BINDING_HAS_NO_AUTH"; break; + case RPC_S_UNKNOWN_AUTHN_SERVICE: what = "RPC_S_UNKNOWN_AUTHN_SERVICE"; break; + case RPC_S_UNKNOWN_AUTHN_LEVEL: what = "RPC_S_UNKNOWN_AUTHN_LEVEL"; break; + case RPC_S_INVALID_AUTH_IDENTITY: what = "RPC_S_INVALID_AUTH_IDENTITY"; break; + case RPC_S_UNKNOWN_AUTHZ_SERVICE: what = "RPC_S_UNKNOWN_AUTHZ_SERVICE"; break; + case EPT_S_INVALID_ENTRY: what = "EPT_S_INVALID_ENTRY"; break; + case EPT_S_CANT_PERFORM_OP: what = "EPT_S_CANT_PERFORM_OP"; break; + case EPT_S_NOT_REGISTERED: what = "EPT_S_NOT_REGISTERED"; break; + case RPC_S_NOTHING_TO_EXPORT: what = "RPC_S_NOTHING_TO_EXPORT"; break; + case RPC_S_INCOMPLETE_NAME: what = "RPC_S_INCOMPLETE_NAME"; break; + case RPC_S_INVALID_VERS_OPTION: what = "RPC_S_INVALID_VERS_OPTION"; break; + case RPC_S_NO_MORE_MEMBERS: what = "RPC_S_NO_MORE_MEMBERS"; break; + case RPC_S_NOT_ALL_OBJS_UNEXPORTED: what = "RPC_S_NOT_ALL_OBJS_UNEXPORTED"; break; + case RPC_S_INTERFACE_NOT_FOUND: what = "RPC_S_INTERFACE_NOT_FOUND"; break; + case RPC_S_ENTRY_ALREADY_EXISTS: what = "RPC_S_ENTRY_ALREADY_EXISTS"; break; + case RPC_S_ENTRY_NOT_FOUND: what = "RPC_S_ENTRY_NOT_FOUND"; break; + case RPC_S_NAME_SERVICE_UNAVAILABLE: what = "RPC_S_NAME_SERVICE_UNAVAILABLE"; break; + case RPC_S_INVALID_NAF_ID: what = "RPC_S_INVALID_NAF_ID"; break; + case RPC_S_CANNOT_SUPPORT: what = "RPC_S_CANNOT_SUPPORT"; break; + case RPC_S_NO_CONTEXT_AVAILABLE: what = "RPC_S_NO_CONTEXT_AVAILABLE"; break; + case RPC_S_INTERNAL_ERROR: what = "RPC_S_INTERNAL_ERROR"; break; + case RPC_S_ZERO_DIVIDE: what = "RPC_S_ZERO_DIVIDE"; break; + case RPC_S_ADDRESS_ERROR: what = "RPC_S_ADDRESS_ERROR"; break; + case RPC_S_FP_DIV_ZERO: what = "RPC_S_FP_DIV_ZERO"; break; + case RPC_S_FP_UNDERFLOW: what = "RPC_S_FP_UNDERFLOW"; break; + case RPC_S_FP_OVERFLOW: what = "RPC_S_FP_OVERFLOW"; break; + case RPC_X_NO_MORE_ENTRIES: what = "RPC_X_NO_MORE_ENTRIES"; break; + case RPC_X_SS_CHAR_TRANS_OPEN_FAIL: what = "RPC_X_SS_CHAR_TRANS_OPEN_FAIL"; break; + case RPC_X_SS_CHAR_TRANS_SHORT_FILE: what = "RPC_X_SS_CHAR_TRANS_SHORT_FILE"; break; + case RPC_X_SS_IN_NULL_CONTEXT: what = "RPC_X_SS_IN_NULL_CONTEXT"; break; + case RPC_X_SS_CONTEXT_DAMAGED: what = "RPC_X_SS_CONTEXT_DAMAGED"; break; + case RPC_X_SS_HANDLES_MISMATCH: what = "RPC_X_SS_HANDLES_MISMATCH"; break; + case RPC_X_SS_CANNOT_GET_CALL_HANDLE: what = "RPC_X_SS_CANNOT_GET_CALL_HANDLE"; break; + case RPC_X_NULL_REF_POINTER: what = "RPC_X_NULL_REF_POINTER"; break; + case RPC_X_ENUM_VALUE_OUT_OF_RANGE: what = "RPC_X_ENUM_VALUE_OUT_OF_RANGE"; break; + case RPC_X_BYTE_COUNT_TOO_SMALL: what = "RPC_X_BYTE_COUNT_TOO_SMALL"; break; + case RPC_X_BAD_STUB_DATA: what = "RPC_X_BAD_STUB_DATA"; break; + case ERROR_INVALID_USER_BUFFER: what = "INVALID_USER_BUFFER"; break; + case ERROR_UNRECOGNIZED_MEDIA: what = "UNRECOGNIZED_MEDIA"; break; + case ERROR_NO_TRUST_LSA_SECRET: what = "NO_TRUST_LSA_SECRET"; break; + case ERROR_NO_TRUST_SAM_ACCOUNT: what = "NO_TRUST_SAM_ACCOUNT"; break; + case ERROR_TRUSTED_DOMAIN_FAILURE: what = "TRUSTED_DOMAIN_FAILURE"; break; + case ERROR_TRUSTED_RELATIONSHIP_FAILURE: what = "TRUSTED_RELATIONSHIP_FAILURE"; break; + case ERROR_TRUST_FAILURE: what = "TRUST_FAILURE"; break; + case RPC_S_CALL_IN_PROGRESS: what = "RPC_S_CALL_IN_PROGRESS"; break; + case ERROR_NETLOGON_NOT_STARTED: what = "NETLOGON_NOT_STARTED"; break; + case ERROR_ACCOUNT_EXPIRED: what = "ACCOUNT_EXPIRED"; break; + case ERROR_REDIRECTOR_HAS_OPEN_HANDLES: what = "REDIRECTOR_HAS_OPEN_HANDLES"; break; + case ERROR_PRINTER_DRIVER_ALREADY_INSTALLED: what = "PRINTER_DRIVER_ALREADY_INSTALLED"; break; + case ERROR_UNKNOWN_PORT: what = "UNKNOWN_PORT"; break; + case ERROR_UNKNOWN_PRINTER_DRIVER: what = "UNKNOWN_PRINTER_DRIVER"; break; + case ERROR_UNKNOWN_PRINTPROCESSOR: what = "UNKNOWN_PRINTPROCESSOR"; break; + case ERROR_INVALID_SEPARATOR_FILE: what = "INVALID_SEPARATOR_FILE"; break; + case ERROR_INVALID_PRIORITY: what = "INVALID_PRIORITY"; break; + case ERROR_INVALID_PRINTER_NAME: what = "INVALID_PRINTER_NAME"; break; + case ERROR_PRINTER_ALREADY_EXISTS: what = "PRINTER_ALREADY_EXISTS"; break; + case ERROR_INVALID_PRINTER_COMMAND: what = "INVALID_PRINTER_COMMAND"; break; + case ERROR_INVALID_DATATYPE: what = "INVALID_DATATYPE"; break; + case ERROR_INVALID_ENVIRONMENT: what = "INVALID_ENVIRONMENT"; break; + case RPC_S_NO_MORE_BINDINGS: what = "RPC_S_NO_MORE_BINDINGS"; break; + case ERROR_NOLOGON_INTERDOMAIN_TRUST_ACCOUNT: what = "NOLOGON_INTERDOMAIN_TRUST_ACCOUNT"; break; + case ERROR_NOLOGON_WORKSTATION_TRUST_ACCOUNT: what = "NOLOGON_WORKSTATION_TRUST_ACCOUNT"; break; + case ERROR_NOLOGON_SERVER_TRUST_ACCOUNT: what = "NOLOGON_SERVER_TRUST_ACCOUNT"; break; + case ERROR_DOMAIN_TRUST_INCONSISTENT: what = "DOMAIN_TRUST_INCONSISTENT"; break; + case ERROR_SERVER_HAS_OPEN_HANDLES: what = "SERVER_HAS_OPEN_HANDLES"; break; + case ERROR_RESOURCE_DATA_NOT_FOUND: what = "RESOURCE_DATA_NOT_FOUND"; break; + case ERROR_RESOURCE_TYPE_NOT_FOUND: what = "RESOURCE_TYPE_NOT_FOUND"; break; + case ERROR_RESOURCE_NAME_NOT_FOUND: what = "RESOURCE_NAME_NOT_FOUND"; break; + case ERROR_RESOURCE_LANG_NOT_FOUND: what = "RESOURCE_LANG_NOT_FOUND"; break; + case ERROR_NOT_ENOUGH_QUOTA: what = "NOT_ENOUGH_QUOTA"; break; + case RPC_S_NO_INTERFACES: what = "RPC_S_NO_INTERFACES"; break; + case RPC_S_CALL_CANCELLED: what = "RPC_S_CALL_CANCELLED"; break; + case RPC_S_BINDING_INCOMPLETE: what = "RPC_S_BINDING_INCOMPLETE"; break; + case RPC_S_COMM_FAILURE: what = "RPC_S_COMM_FAILURE"; break; + case RPC_S_UNSUPPORTED_AUTHN_LEVEL: what = "RPC_S_UNSUPPORTED_AUTHN_LEVEL"; break; + case RPC_S_NO_PRINC_NAME: what = "RPC_S_NO_PRINC_NAME"; break; + case RPC_S_NOT_RPC_ERROR: what = "RPC_S_NOT_RPC_ERROR"; break; + case RPC_S_UUID_LOCAL_ONLY: what = "RPC_S_UUID_LOCAL_ONLY"; break; + case RPC_S_SEC_PKG_ERROR: what = "RPC_S_SEC_PKG_ERROR"; break; + case RPC_S_NOT_CANCELLED: what = "RPC_S_NOT_CANCELLED"; break; + case RPC_X_INVALID_ES_ACTION: what = "RPC_X_INVALID_ES_ACTION"; break; + case RPC_X_WRONG_ES_VERSION: what = "RPC_X_WRONG_ES_VERSION"; break; + case RPC_X_WRONG_STUB_VERSION: what = "RPC_X_WRONG_STUB_VERSION"; break; + case RPC_S_GROUP_MEMBER_NOT_FOUND: what = "RPC_S_GROUP_MEMBER_NOT_FOUND"; break; + case EPT_S_CANT_CREATE: what = "EPT_S_CANT_CREATE"; break; + case RPC_S_INVALID_OBJECT: what = "RPC_S_INVALID_OBJECT"; break; + case ERROR_INVALID_TIME: what = "INVALID_TIME"; break; + case ERROR_INVALID_FORM_NAME: what = "INVALID_FORM_NAME"; break; + case ERROR_INVALID_FORM_SIZE: what = "INVALID_FORM_SIZE"; break; + case ERROR_ALREADY_WAITING: what = "ALREADY_WAITING"; break; + case ERROR_PRINTER_DELETED: what = "PRINTER_DELETED"; break; + case ERROR_INVALID_PRINTER_STATE: what = "INVALID_PRINTER_STATE"; break; + case ERROR_PASSWORD_MUST_CHANGE: what = "PASSWORD_MUST_CHANGE"; break; + case ERROR_DOMAIN_CONTROLLER_NOT_FOUND: what = "DOMAIN_CONTROLLER_NOT_FOUND"; break; + case ERROR_ACCOUNT_LOCKED_OUT: what = "ACCOUNT_LOCKED_OUT"; break; + case ERROR_NO_BROWSER_SERVERS_FOUND: what = "NO_BROWSER_SERVERS_FOUND"; break; + case ERROR_INVALID_PIXEL_FORMAT: what = "INVALID_PIXEL_FORMAT"; break; + case ERROR_BAD_DRIVER: what = "BAD_DRIVER"; break; + case ERROR_INVALID_WINDOW_STYLE: what = "INVALID_WINDOW_STYLE"; break; + case ERROR_METAFILE_NOT_SUPPORTED: what = "METAFILE_NOT_SUPPORTED"; break; + case ERROR_TRANSFORM_NOT_SUPPORTED: what = "TRANSFORM_NOT_SUPPORTED"; break; + case ERROR_CLIPPING_NOT_SUPPORTED: what = "CLIPPING_NOT_SUPPORTED"; break; + case ERROR_UNKNOWN_PRINT_MONITOR: what = "UNKNOWN_PRINT_MONITOR"; break; + case ERROR_PRINTER_DRIVER_IN_USE: what = "PRINTER_DRIVER_IN_USE"; break; + case ERROR_SPOOL_FILE_NOT_FOUND: what = "SPOOL_FILE_NOT_FOUND"; break; + case ERROR_SPL_NO_STARTDOC: what = "SPL_NO_STARTDOC"; break; + case ERROR_SPL_NO_ADDJOB: what = "SPL_NO_ADDJOB"; break; + case ERROR_PRINT_PROCESSOR_ALREADY_INSTALLED: what = "PRINT_PROCESSOR_ALREADY_INSTALLED"; break; + case ERROR_PRINT_MONITOR_ALREADY_INSTALLED: what = "PRINT_MONITOR_ALREADY_INSTALLED"; break; + case ERROR_WINS_INTERNAL: what = "WINS_INTERNAL"; break; + case ERROR_CAN_NOT_DEL_LOCAL_WINS: what = "CAN_NOT_DEL_LOCAL_WINS"; break; + case ERROR_STATIC_INIT: what = "STATIC_INIT"; break; + case ERROR_INC_BACKUP: what = "INC_BACKUP"; break; + case ERROR_FULL_BACKUP: what = "FULL_BACKUP"; break; + case ERROR_REC_NON_EXISTENT: what = "REC_NON_EXISTENT"; break; + case ERROR_RPL_NOT_ALLOWED: what = "RPL_NOT_ALLOWED"; break; + default : + sprintf(errornum, "error #%ld", error & 0xffff); + what = errornum; + } + + /* display the message */ + msg(MSG_ERROR,"[ss]$1: $2", where, what); +} +# define TRACE(stmt) stmt +#else /* not DEBUGGING */ +# define ElvisError(where) +# define TRACE(stmt) +#endif + +/* Returns True if a program uses Win32 format, and false otherwise. + * This is significant because only Win32 programs support real pipes. + */ +static BOOL classifyprog(prog) + char *prog; /* a program to check, possibly followed by args */ +{ + char *freethis = NULL; + char *name; + char *cp; + long exetype; + + /* if command uses shell metacharacters, then also check shell. + * If pipes, then check to make sure other progs are win32 also. + */ + if ((strchr(prog, '<') != NULL || strchr(prog, '>') != NULL) + && (!o_shell || !classifyprog(tochar8(o_shell)))) + goto NotWin32; + cp = strchr(prog, '|'); + if (cp && !classifyprog(cp + 1)) + goto NotWin32; + + /* Isolate the program name within a COPY of the command string. + * Note that the copy has 5 extra chars, so we can append ".exe" and + * a NUL character. + */ + while (isspace(*prog)) + prog++; + freethis = name = safealloc(strlen(prog) + 5, sizeof(char)); + strcpy(name, prog); + for (cp = name; *cp && !isspace(*cp) && *cp != '/'; cp++) + { + } + *cp = '\0'; + if (!*name) + goto NotWin32; + + /* all win32 programs end with ".exe" */ + if (strlen(name) < 4 || name[strlen(name) - 4] != '.') + strcat(name, ".exe"); + /* look for the program in current dir, or in path */ + if (_access(name, 0) != 0) + { + cp = getenv("PATH"); + if (!cp) + goto NotWin32; + name = iopath(cp, name, False); + if (!name) + name = tochar8(o_shell); + if (!name) + goto NotWin32; + } +TRACE(fprintf(tracelog, "classifyprog(\"%s\"), name=\"%s\"\n", prog, name)); + + /* check the file's type */ + if (GetBinaryType(name, &exetype)) + { +TRACE(fprintf(tracelog, "GetBinaryType() succeeded, exetype=%d\n", exetype);) + if (exetype != SCS_32BIT_BINARY && exetype != SCS_WOW_BINARY) + { + supports_detach = FALSE; + } + if (exetype == SCS_32BIT_BINARY || exetype == SCS_POSIX_BINARY) + { + safefree(freethis); +TRACE(fprintf(tracelog, "...classifyprog()returning True\n", prog, name);) + return True; + } + } +TRACE(else fprintf(tracelog, "GetBinaryType() failed\n");) - /* build the shell invocation command, to run the batch file */ +#ifndef GUI_WIN32 + /* Windows95 apparently doesn't support GetBinaryType, but it *does* + * support pipes. Since GetBinaryType() failed, return True. + */ + safefree(freethis); + return True; +#endif + +NotWin32: + if (freethis != NULL) + safefree(freethis); +TRACE(fprintf(tracelog, "...classifyprog()returning False\n", prog, name);) + return False; +} + +/* This function either creates a pipe, or creates a temp file and opens + * two file descriptors which access it like a pipe. It is sensitive to the + * value of the "supports_pipes" variable, so it won't use pipes with a program + * which doesn't support them. + */ +static BOOL MaybeCreatePipe(PHANDLE r, PHANDLE w) +{ + /* use CreatePipe() if possible */ + if (supports_pipes && CreatePipe(r, w, &inherit, 0)) + { +TRACE(fprintf(tracelog, "MaybeCreatePipe() using pipe\n")); + return TRUE; + } + + /* create a temp file, and open a write fd to it. */ + do + { + if (unique == 0) + unique = (UINT)GetCurrentProcessId(); + else if (unique == 0xfffe) + unique = 1; + else + unique++; + GetTempFileName(TMPDIR, "elv", unique, pipefname); + *w = CreateFile(pipefname, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ|FILE_SHARE_WRITE, &inherit, + CREATE_NEW, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, + INVALID_HANDLE_VALUE); + } while (*w == INVALID_HANDLE_VALUE + && GetLastError() == ERROR_FILE_EXISTS); + if (*w == INVALID_HANDLE_VALUE) + { + ElvisError("CreateFile[1]"); + *pipefname = '\0'; + return FALSE; + } + + /* also open a file handle for reading */ + if (!DuplicateHandle(GetCurrentProcess(), *w, GetCurrentProcess(), r, 0, TRUE, DUPLICATE_SAME_ACCESS)) + { + ElvisError("DuplicateHandle[1]"); + CloseHandle(*w); + *w = INVALID_HANDLE_VALUE; + (void)DeleteFile(pipefname); + *pipefname = '\0'; + return FALSE; + } + + /* done! */ +TRACE(fprintf(tracelog, "MaybeCreatePipe() using file \"%s\"\n", pipefname)); + return TRUE; +} + +/* Run a command via the shell. If the command contains "$1", then replace + * $1 with the name of the temp file (if any). Uses the "start" variable. + * Returns TRUE if successful, or FALSE if error. (Note that these are the + * values of the Windows BOOLEAN data type, not elvis' BOOLEAN data type.) + * + * Note: We try to avoid using the shell to start the command. This is + * partly for the sake of efficiency, but mostly it is because the shell + * sometimes creates a console window when run from the MFC elvis and I'm + * trying to avoid that. + */ +static BOOLEAN runcmd(cmd, detached) + char *cmd; /* the command to run */ + ElvisBOOLEAN detached; /* doesn't use the console */ +{ + ElvisCHAR *scansh; + char *scan; + ElvisCHAR *cmdline; + BOOLEAN result; + PROCESS_INFORMATION proc; /* info about started process */ + int shlen; /* length of shell command */ + +#ifdef GUI_WIN32 +# define ElvisDETACHED (detached && supports_detach ? DETACHED_PROCESS : 0) +#else +# define ElvisDETACHED 0 +#endif + +TRACE(fprintf(tracelog, "runcmd(\"%s\", %sdetached, ...)\n", cmd, detached?"":"not ");) +TRACE(fprintf(tracelog, "GetStdHandle(STD_INPUT_HANDLE) = 0x%lx\n", (long)GetStdHandle(STD_INPUT_HANDLE));) +TRACE(fprintf(tracelog, "GetStdHandle(STD_OUTPUT_HANDLE) = 0x%lx\n", (long)GetStdHandle(STD_OUTPUT_HANDLE));) +TRACE(fprintf(tracelog, "GetStdHandle(STD_ERROR_HANDLE) = 0x%lx\n", (long)GetStdHandle(STD_ERROR_HANDLE));) +TRACE(fprintf(tracelog, "start.hStdInput() = 0x%lx\n", (long)start.hStdInput);) +TRACE(fprintf(tracelog, "start.hStdOutput() = 0x%lx\n", (long)start.hStdOutput);) +TRACE(fprintf(tracelog, "start.hStdError() = 0x%lx\n", (long)start.hStdError);) +TRACE(fprintf(tracelog, "readfd = 0x%lx\n", (long)readfd);) +TRACE(fprintf(tracelog, "writefd = 0x%lx\n", (long)writefd);) + + /* build the command line */ cmdline = NULL; + shlen = 0; if (o_shell && *o_shell) - buildstr(&cmdline, tochar8(o_shell)); - else - buildstr(&cmdline, "command.com"); - buildstr(&cmdline, " /c "); - buildstr(&cmdline, namebatch); + { + for (scansh = o_shell; *scansh; scansh++) + buildCHAR(&cmdline, *scansh); + for (scan = " /c "; *scan; scan++) + buildCHAR(&cmdline, (ElvisCHAR)*scan); + shlen = CHARlen(cmdline); + } - memset(&proc, 0, sizeof proc); + /* if any shell characters are used, then treat the shell command as + * part of the user's command line. I.e., don't try to avoid using + * the shell. + */ + if (shlen > 0 && strpbrk(cmd, "<>|") != NULL) + { + shlen = 0; + } + + /* append the user's command to the command line */ + for (; *cmd; cmd++) + { + if (cmd[0] == '$' && cmd[1] == '1') + { + for (scan = tempfname; *scan; scan++) + buildCHAR(&cmdline, (ElvisCHAR)*scan); + cmd++; + } + else + { + buildCHAR(&cmdline, (ElvisCHAR)*cmd); + } + } #ifdef GUI_WIN32 /* For the "win32" gui, any subprocesses will normally start out @@ -53,31 +919,28 @@ static BOOLEAN runbatch(void) * tired of fighting it. */ start.wShowWindow = SW_HIDE; - start.dwFlags = STARTF_USESHOWWINDOW; + start.dwFlags |= STARTF_USESHOWWINDOW; #endif /* run the command. First try to run it without a shell. If * that fails (probably because the command is built into the * shell) then try the same command with the shell. */ - result = CreateProcess(NULL, tochar8(cmdline), + result = (CreateProcess(NULL, tochar8(cmdline + shlen), NULL, NULL, TRUE, -#ifdef GUI_WIN32 - DETACHED_PROCESS | NORMAL_PRIORITY_CLASS, -#else - NORMAL_PRIORITY_CLASS, -#endif - NULL, NULL, &start, &proc); + ElvisDETACHED | NORMAL_PRIORITY_CLASS, + NULL, NULL, &start, &proc) + || (shlen > 0 && CreateProcess(NULL, tochar8(cmdline), + NULL, NULL, TRUE, + ElvisDETACHED | NORMAL_PRIORITY_CLASS, + NULL, NULL, &start, &proc))); +TRACE(fprintf(tracelog, "CreateProcess(\"%s\") returned %s\n", cmdline, result?"TRUE":"FALSE");) /* remember info about the process */ if (result) { pid = proc.hProcess; tid = proc.hThread; - (void)WaitForSingleObject(pid, INFINITE); - GetExitCodeProcess(pid, &status); - CloseHandle(pid); - CloseHandle(tid); } /* free the command line */ @@ -85,6 +948,8 @@ static BOOLEAN runbatch(void) /* return the result */ return result; + +#undef ElvisDETACHED } @@ -92,84 +957,140 @@ static BOOLEAN runbatch(void) * This function should return True if successful. If there is an error, * it should issue an error message via msg(), and return False. * - * For Win32, this creates a batch file, to be run by prggo(). + * For Win32, the behavior of this function depends on willwrite. + * If willwrite, then the command is saved and a temporary file is + * is created to store the data that will become the program's stdin, + * and the function succeeds if the temp file was created successfully. + * Else the program is forked (with stdout/stderr redirected to a pipe + * if willread) and the function succedes if pipe() and fork() + * succeed. */ ElvisBOOLEAN prgopen(cmd, willwrite, willread) char *cmd; /* command string */ ElvisBOOLEAN willwrite; /* if True, redirect command's stdin */ ElvisBOOLEAN willread; /* if True, redirect command's stdout */ { - HANDLE bfd; + HANDLE piper, pipew; /* read and write ends of pipe */ + HANDLE handle; /* temporary variable */ - /* choose a name for the batch file */ - do - { - if (unique == 0) - unique = (UINT)GetCurrentProcessId(); - else if (unique == 0xfffe) - unique = 1; - else - unique++; - sprintf(namebatch, "%s\\elv_%04x.bat", TMPDIR, unique); - bfd = CreateFile(namebatch, GENERIC_WRITE, 0, &inherit, - CREATE_NEW, FILE_FLAG_SEQUENTIAL_SCAN, - INVALID_HANDLE_VALUE); - } while (bfd == INVALID_HANDLE_VALUE - && GetLastError() == ERROR_FILE_EXISTS); +#ifdef DEBUGGING + if (!tracelog) tracelog = fopen("trace.log", "w"); + fprintf(tracelog, "\nprgopen(\"%s\"%s%s)\n", cmd, willwrite?", willwrite":"", willread?", willread":""); +#endif - /* Derive stdin and stdout names from the batch name */ - if (willwrite) - sprintf(namestdin, "%s\\elv_%04x.in", TMPDIR, unique); - else - *namestdin = '\0'; - if (willread) - sprintf(namestdout, "%s\\elv_%04x.out", TMPDIR, unique); - else - *namestdout = '\0'; - - /* create the batch file */ - WriteFile(bfd, "@echo off\r\n", (DWORD)11, &unique, NULL); + /* Determine whether this is a Win32 program. If not, then we can't + * use pipes. Also, check whether program can be run detached from a + * console. + */ + supports_detach = FALSE; /*!!!*/ + supports_pipes = classifyprog(cmd); +TRACE(fprintf(tracelog, "supports_detach=%s, supports_pipes=%s\n", supports_detach ? "TRUE" : "FALSE", supports_pipes ? "TRUE" : "FALSE");) + + /* Mark both fd's as being unused */ + writefd = readfd = pid = tid = INVALID_HANDLE_VALUE; + filter = (ElvisBOOLEAN)(willwrite && willread); + command = NULL; + + /* Next step depends on what I/O we expect to do with this program */ if (willwrite) { - WriteFile(bfd, "<\"", (DWORD)2, &unique, NULL); - unique = strlen(namestdin); - WriteFile(bfd, namestdin, (DWORD)unique, &unique, NULL); - WriteFile(bfd, "\" ", (DWORD)2, &unique, NULL); + /* Either we'll be filtering text through the external + * program, or we'll be writing to a program which can only + * read from a file. Either way, the program's input will + * come from a temporary file. + */ + + /* save the command; we'll need it in prggo()*/ + command = strdup(cmd); + + /* create a temporary file for feeding the program's stdin */ + do + { + if (unique == 0) + unique = (UINT)GetCurrentProcessId(); + else if (unique == 0xfffe) + unique = 1; + else + unique++; + GetTempFileName(TMPDIR, "elv", unique, tempfname); + writefd = CreateFile(tempfname, GENERIC_READ|GENERIC_WRITE, + FILE_SHARE_READ, &inherit, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN, + INVALID_HANDLE_VALUE); + } while (writefd == INVALID_HANDLE_VALUE + && GetLastError() == ERROR_FILE_EXISTS); + if (writefd == INVALID_HANDLE_VALUE) + { + ElvisError("CreateFile[3]"); + *tempfname = '\0'; + free(command); + return False; + } +TRACE(fprintf(tracelog, "%s(%d) tmpfile=0x%lx\n", __FILE__, __LINE__, (long)writefd);) } - unique = strlen(cmd); - WriteFile(bfd, cmd, (DWORD)unique, &unique, NULL); - if (willread) + else if (willread) /* but not willwrite */ { - WriteFile(bfd, " >\"", (DWORD)3, &unique, NULL); - unique = strlen(namestdout); - WriteFile(bfd, namestdout, (DWORD)unique, &unique, NULL); - WriteFile(bfd, "\"", (DWORD)1, &unique, NULL); - } - WriteFile(bfd, "\r\n", (DWORD)2, &unique, NULL); - CloseHandle(bfd); + /* We're reading the program's stdout and leaving its stdin + * unredirected. Use a pipe. + */ - /* Are we going to write to stdin? */ - if (willwrite) - { - /* Yes -- create the stdin file */ - fp = fopen(namestdin, "w"); - if (!fp) + /* create a pipe */ + if (!MaybeCreatePipe(&piper, &pipew)) + { + return False; + } +TRACE(fprintf(tracelog, "%s(%d) piper=0x%lx, pipew=0x%lx\n", __FILE__, __LINE__, (long)piper, (long)pipew);) + + /* set the child's stdio, so stdout/stderr are redirected */ +#ifdef GUI_WIN32 + start.hStdInput = pipew; +#else + start.hStdInput = GetStdHandle(STD_INPUT_HANDLE); +#endif + start.hStdOutput = pipew; + start.hStdError = pipew; + + /* make the read end of the pipe non-inheritable */ + if (!DuplicateHandle(GetCurrentProcess(), piper, GetCurrentProcess(), &handle, GENERIC_READ, FALSE, 0)) + { + ElvisError("DuplicateHandle[2]"); + CloseHandle(piper); + CloseHandle(pipew); + if (*pipefname) + (void)DeleteFile(pipefname); + return False; + } +TRACE(fprintf(tracelog, "%s(%d) piper=0x%lx (was 0x%lx)\n", __FILE__, __LINE__, (long)handle, (long)piper);) + CloseHandle(piper); + readfd = piper = handle; + + /* fork off the external program */ + start.dwFlags = STARTF_USESTDHANDLES; + if (!runcmd(cmd, True)) { - remove(namebatch); + ElvisError("runcmd[1]"); + CloseHandle(piper); + CloseHandle(pipew); + if (*pipefname) + (void)DeleteFile(pipefname); return False; } - return True; + + CloseHandle(pipew); } - else + else /* no redirection */ { - /* No -- run the batch now */ - if (runbatch()) - return True; - - /* if we get here, we couldn't run the batch file */ - DeleteFile(namebatch); - return False; + /* fork off the external program */ + start.dwFlags = 0; + if (!runcmd(cmd, False)) + { + ElvisError("runcmd[2]"); + return False; + } } + + /* if we get here, we must have succeeded */ + return True; } /* Write the contents of buf to the program's stdin, and return nbytes @@ -177,21 +1098,25 @@ ElvisBOOLEAN prgopen(cmd, willwrite, willread) * be subjected to the same kind of transformations as textwrite(). * In fact, it may use textwrite() internally. * - * For Win32, this is simply a fwrite() call. + * For Win32, this is simply a WriteFile() to the temp file or pipe. */ int prgwrite(buf, nbytes) ElvisCHAR *buf; /* buffer, contains text to be written */ int nbytes; /* number of characters in buf */ { - assert(*namestdin); - return fwrite(buf, sizeof(char), nbytes, fp); + DWORD written;/* number of characters actually written */ + + assert(writefd != INVALID_HANDLE_VALUE); + if (!WriteFile(writefd, buf, (DWORD)nbytes, &written, NULL)) + return -1; +TRACE(if ((DWORD)nbytes!=written)msg(MSG_INFO, "[dd]prgwrite(..., $1) returning $2", (long)nbytes, (long)written);) + return written; } /* Marks the end of writing. Returns True if all is okay, or False if * error. * - * For Win32, this closes the stdin temp file if necessary, runs the batch, - * and opens the + * For Win32, the temp file is closed, and the program is forked. * Returns True if the fork was successful, or False if it failed. */ ElvisBOOLEAN prggo() @@ -199,27 +1124,94 @@ ElvisBOOLEAN prggo() HANDLE piper, pipew; /* read & write ends of a pipe */ HANDLE handle; /* temporary variable */ - /* if stdin was redirected, then close stdin file and run the batch */ - if (*namestdin) +TRACE(fprintf(tracelog, "prggo(), readfd=%x, writefd=%x\n", readfd, writefd)); + + /* If we weren't writing, then there's nothing to be done here */ + if (writefd != INVALID_HANDLE_VALUE) { - /* close the stdin handle */ - fclose(fp); - - /* run the batch program */ - if (!runbatch()) + + /* If we're using a temp file, then rewind it, and then + * fork the program with its stdin redirected to come from file. + */ + if (command) { - DeleteFile(namebatch); - remove(namestdin); - return False; + /* rewind the temp file, and use it for stdin */ + start.hStdInput = writefd; + (void)SetFilePointer(writefd, 0L, NULL, FILE_BEGIN); + + piper = pipew = INVALID_HANDLE_VALUE; + if (filter) + { + /* make a pipe to use for reading stdout/stderr */ + if (!MaybeCreatePipe(&piper, &pipew)) + { + return False; + } + TRACE(fprintf(tracelog, "%s(%d) piper=0x%lx, pipew=0x%lx\n", __FILE__, __LINE__, (long)piper, (long)pipew);) + + /* make the read end be non-inheritable */ + if (!DuplicateHandle(GetCurrentProcess(), piper, GetCurrentProcess(), &handle, 0, FALSE, DUPLICATE_SAME_ACCESS)) + { + ElvisError("DuplicateHandle[3]"); + CloseHandle(piper); + CloseHandle(pipew); + if (*pipefname) + (void)DeleteFile(pipefname); + return False; + } + TRACE(fprintf(tracelog, "%s(%d) piper=0x%lx (was 0x%lx)\n", __FILE__, __LINE__, (long)handle, (long)piper);) + CloseHandle(piper); + readfd = piper = handle; + + /* use the pipe's write end for stdout/stderr */ + start.hStdOutput = start.hStdError = pipew; + } + else + { + /* don't redirect stdout/stderr */ + start.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); + start.hStdError = GetStdHandle(STD_ERROR_HANDLE); + } + + /* start the process */ + start.dwFlags = STARTF_USESTDHANDLES; + if (!runcmd(command, True)) + { + ElvisError("runcmd[3]"); + return False; + } + + /* close the write-end of the pipe */ + if (pipew != INVALID_HANDLE_VALUE) + CloseHandle(pipew); + + /* don't need the command string any more. */ + free(command); } + + /* close the writefd */ + CloseHandle(writefd); + writefd = INVALID_HANDLE_VALUE; } - /* if we're supposed to read output, then open stdout temp file */ - fp = fopen(namestdout, "r"); - if (!fp) + /* If we're using temp files to read stdout/stderr, then wait + * for the program to terminate, so we can be sure the temp + * file contains all the data it will ever contain, before the + * first prgread() call. (If we're using a pipe, then we don't + * need to worry about this.) + */ +TRACE(fprintf(tracelog, "pipefname=\"%s\", bytes=%ld\n", pipefname, *pipefname ? SetFilePointer(readfd, 0L, NULL, FILE_END) : 0L);) + if (*pipefname) { - DeleteFile(namebatch); - return False; + (void)WaitForSingleObject(pid, INFINITE); + GetExitCodeProcess(pid, &status); + CloseHandle(pid); + CloseHandle(tid); + pid = tid = INVALID_HANDLE_VALUE; + if (SetFilePointer(readfd, 0L, NULL, FILE_BEGIN) == 0xffffffff) + { + ElvisError("SetFilePointer"); + } } return True; @@ -231,14 +1223,37 @@ ElvisBOOLEAN prggo() * should be subjected to the same kinds of transformations as * textread(). * - * For Win32, we use fread() to read from a temp file. + * For Win32, we use ReadFile() to read from the pipe, and then perform + * newline conversion explicitly, since pipes are always binary. */ int prgread(buf, nbytes) ElvisCHAR *buf; /* buffer where text should be placed */ int nbytes; /* maximum number of characters to read */ { - assert(*namestdout); - return fread(buf, sizeof(char), nbytes, fp); + DWORD nread; + int i, j; + +TRACE(fprintf(tracelog, "prgread(buf, %d), readfd=%d\n", nbytes, readfd); fflush(tracelog);) + + assert(readfd != INVALID_HANDLE_VALUE); + if (!ReadFile(readfd, buf, (DWORD)nbytes, &nread, NULL)) + { +TRACE(fprintf(tracelog, "prgread() returning -1\n"); fflush(tracelog);) + return -1; + } + + /* Convert CR-LF to LF. This will fail if a CR/LF pair is split + * across two prgread() calls. (That's a bug!!!) + */ + for (i = j = 0; (DWORD)j < nread; j++) + { + if (buf[j] != '\r' || (DWORD)(j + 1) >= nread || buf[j + 1] != '\n') + buf[i++] = buf[j]; + } + nread = i; + +TRACE(fprintf(tracelog, "prgread() returning %d\n", nread); fflush(tracelog);) + return nread; } /* Clean up, and return the program's exit status. The exit status @@ -249,16 +1264,41 @@ int prgread(buf, nbytes) */ int prgclose() { - /* close the handle used for reading from stdout */ - if (*namestdout) - fclose(fp); + /* close the readfd, if necessary */ + if (readfd != INVALID_HANDLE_VALUE) + { + CloseHandle(readfd); + readfd = INVALID_HANDLE_VALUE; + } + + /* close the writefd, if necessary */ + if (writefd != INVALID_HANDLE_VALUE) + { + CloseHandle(writefd); + writefd = INVALID_HANDLE_VALUE; + } + + /* wait for the program to die */ + if (pid != INVALID_HANDLE_VALUE) + { +TRACE(fprintf(tracelog, "About to wait for program to die, pid=%d\n", pid); fflush(tracelog);) + (void)WaitForSingleObject(pid, INFINITE); + GetExitCodeProcess(pid, &status); + CloseHandle(pid); + CloseHandle(tid); + } /* delete the temp files, if there were any */ - DeleteFile(namebatch); - if (*namestdin) - remove(namestdin); - if (*namestdout) - remove(namestdout); + if (*tempfname) + { + (void)DeleteFile(tempfname); + *tempfname = '\0'; + } + if (*pipefname) + { + (void)DeleteFile(pipefname); + *pipefname = '\0'; + } return status; } diff --git a/oswin32/ostext.c b/oswin32/ostext.c index b702c1f..75d53ed 100644 --- a/oswin32/ostext.c +++ b/oswin32/ostext.c @@ -7,6 +7,9 @@ #include #include +/* the following is defined in oswin32\osdir.c */ +extern char *dirnormalize(char *path); + #ifdef GUI_WIN32 #ifndef O_BINARY #define O_BINARY _O_BINARY @@ -38,7 +41,7 @@ int txtopen(char *filename, _char_ rwa, BOOLEAN binary) case 'w': flags |= _O_WRONLY|_O_CREAT|_O_TRUNC; break; case 'a': flags |= _O_WRONLY|_O_APPEND; break; } - fd = _open(filename, flags, 0666); + fd = _open(dirnormalize(filename), flags, 0666); /* return a code indicating the success or reason for failure */ if (fd >= 0) diff --git a/oswin32/tcaphelp.c b/oswin32/tcaphelp.c index ca991e6..7b99d6d 100644 --- a/oswin32/tcaphelp.c +++ b/oswin32/tcaphelp.c @@ -1,6 +1,6 @@ /* oswin32/tcaphelp.c */ -char id_tcaphelp[] = "$Id: tcaphelp.c,v 2.26 1998/08/29 16:44:06 steve Exp $"; +char id_tcaphelp[] = "$Id: tcaphelp.c,v 2.27 1999/09/28 22:03:08 steve Exp $"; #include "elvis.h" #if defined(GUI_TERMCAP) || defined(GUI_OPEN) @@ -935,7 +935,7 @@ char *ttytermtype() type = TTY_DEFAULT; /* are we using the console? */ - useconsole = !strcmp(type, "console"); + useconsole = !strcmp(type, "console") || !strcmp(type, "cygwin"); if (useconsole) { inConsole = GetStdHandle(STD_INPUT_HANDLE); diff --git a/ref.c b/ref.c index a1fe132..cf8003b 100644 --- a/ref.c +++ b/ref.c @@ -287,6 +287,7 @@ static void lookup(tag) long taglnum;/* line number of number tag address, or 0 */ char *tagline;/* text form of regexp tag address */ LINECLS lc; /* line classification */ + int len; int i; /* open the file, or the "refs" file if the source file is unreadable */ @@ -321,6 +322,9 @@ static void lookup(tag) t++; *l++ = *t++; } + len = (int)(l - tagline); + if (*t == '$') + len++; *l = '\0'; } @@ -328,7 +332,7 @@ static void lookup(tag) for (lnum = 1, lc = LC_COMPLETE; (line = getline(fp)) != NULL; lnum++) { /* is this the tag definition? */ - if (taglnum > 0 ? taglnum == lnum : !strcmp(tagline, line)) + if (taglnum > 0 ? taglnum == lnum : !strncmp(tagline, line, len)) { /* output the tag location */ if (!omit_comment_lines) diff --git a/scan.c b/scan.c index 56aa058..f937a64 100644 --- a/scan.c +++ b/scan.c @@ -1,7 +1,7 @@ /* scan.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_scan[] = "$Id: scan.c,v 2.16 1998/11/28 20:17:56 steve Exp $"; +char id_scan[] = "$Id: scan.c,v 2.17 1999/09/30 18:18:34 steve Exp $"; #include "elvis.h" @@ -178,10 +178,10 @@ void scanfree(cp) #ifdef FEATURE_LITRE /* save info from this scan, to speed up later scans */ - if (scan__top->next && scan__top->buffer) + if (!scan__top->next && scan__top->buffer && scan__top->blkno != 0) { saved = *scan__top; - changes = scan__top->buffer->changes; + changes = saved.buffer->changes; } #endif /* FEATURE_LITRE */ diff --git a/session.h b/session.h index aa33fb2..2245fe7 100644 --- a/session.h +++ b/session.h @@ -73,7 +73,7 @@ typedef union struct { BLKNO next; /* ref to next block of BLKNO values */ - struct + struct blki_s { BLKNO blkno; /* which block stores next CHARs */ COUNT nchars; /* number of CHARs used in the block */ diff --git a/tinytcap.c b/tinytcap.c index a285ebb..ebcdd93 100644 --- a/tinytcap.c +++ b/tinytcap.c @@ -105,7 +105,7 @@ static char *termcap[] = "fansi", "nnansi", "nansi", -":al=\033[L:dl=\033[M:AL=\033[%dL:DL=\033[%dM:am:xn:bs:ce=\033[K:cl=\033[2J:\ +":al=\033[L:dl=\033[M:AL=\033[%dL:DL=\033[%dM:am:bs:ce=\033[K:cl=\033[2J:\ :cm=\033[%i%d;%dH:co#80:\ :k1=#;:k2=#<:k3=#=:k4=#>:k5=#?:k6=#@:k7=#A:k8=#B:k9=#C:k0=#D:\ :s1=#T:s2=#U:s3=#V:s4=#W:s5=#X:s6=#Y:s7=#Z:s8=#[:s9=#\\:s0=#]:\ @@ -114,7 +114,7 @@ static char *termcap[] = :kd=#P:kh=#G:kH=#O:kI=#R:kD=#S:kl=#K:kN=#Q:kP=#I:kr=#M:ku=#H:\ :KL=#s:KR=#t:\ :li#25:md=\033[1m:me=\033[m:nd=\033[C:se=\033[m:so=\033[7m:\ -:ue=\033[m:up=\033[A:us=\033[4m:\ +:ue=\033[m:up=\033[A:us=\033[4m:ti=\033[m:te=\033[m:\ :ac=q\304x\263m\300v\301j\331t\303n\305u\264l\332w\302k\277:", "pcbios", @@ -133,6 +133,7 @@ static char *termcap[] = #ifdef TERM_CONSOLE "console", +"cygwin", ":al=\033[L:dl=\033[M:AL=\033[%dL:DL=\033[%dM:am:xn:bs:ce=\033[K:cl=\033[2J:\ :cm=\033[%i%d;%dH:co#80:\ :k1=#;:k2=#<:k3=#=:k4=#>:k5=#?:k6=#@:k7=#A:k8=#B:k9=#C:k0=#D:\ @@ -158,7 +159,7 @@ static char *termcap[] = :kd=#P:kh=#G:kH=#O:kI=#R:kD=#S:kl=#K:kN=#Q:kP=#I:kr=#M:ku=#H:\ :KL=#s:KR=#t:\ :li#25:md=\033[1m:me=\033[m:nd=\033[C:se=\033[m:so=\033[7m:\ -:ue=\033[m:up=\033[A:us=\033[4m:\ +:ue=\033[m:up=\033[A:us=\033[4m:ti=\033[m:te=\033[m:\ :ac=q\304x\263m\300v\301j\331t\303n\305u\264l\332w\302k\277:", #endif diff --git a/verify.c b/verify.c index 882d237..d4b5043 100644 --- a/verify.c +++ b/verify.c @@ -1,7 +1,7 @@ /* verify.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_verify[] = "$Id: verify.c,v 1.8 1998/09/20 18:09:28 steve Exp $"; +char id_verify[] = "$Id: verify.c,v 1.9 1999/10/08 18:03:03 steve Exp $"; /* This file contains a replacement for elvis' main() function. The resulting * program will test each component of elvis. @@ -56,7 +56,7 @@ extern BUFFER cutbuffer(_CHAR_ cbname, BOOLEAN create); * Start of stub functions */ -BOOLEAN exthenflag; +EXCTLSTATE exctlstate; long eventcounter; GUI dummygui, *chosengui = &dummygui; diff --git a/version.h b/version.h index ab5b048..8270cff 100644 --- a/version.h +++ b/version.h @@ -2,7 +2,7 @@ /* Copyright 1996 by Steve Kirkendall */ -#define VERSION "2.1_3" +#define VERSION "2.1_4" #define COPY1 "Copyright (c) 1995-1999 by Steve Kirkendall" #if 1 # define COPY2 "Permission is granted to redistribute the source or binaries under the" diff --git a/window.c b/window.c index fde4698..91b6e72 100644 --- a/window.c +++ b/window.c @@ -1,7 +1,7 @@ /* window.c */ /* Copyright 1995 by Steve Kirkendall */ -char id_window[] = "$Id: window.c,v 2.49 1999/02/26 21:29:29 steve Exp $"; +char id_window[] = "$Id: window.c,v 2.50 1999/10/08 18:04:29 steve Exp $"; #include "elvis.h" @@ -187,7 +187,7 @@ WINDOW winalloc(gw, gvals, buf, rows, columns) newp->wrapmargin.value.pointer = (void *)newp; /* allocate storage space for the screen images */ - newp->di = (DRAWINFO *)drawalloc((int)rows, (int)columns); + newp->di = (DRAWINFO *)drawalloc((int)rows, (int)columns, newp->cursor); /* choose the default display mode */ if (!dispset(newp, tochar8(o_bufdisplay(buf)))) @@ -362,7 +362,7 @@ void winresize(win, rows, columns) long rows; /* new height of the window */ long columns;/* new width of the window */ { - long oldtop; + MARKBUF oldtop; /* update the options */ o_lines(win) = rows; @@ -373,13 +373,9 @@ void winresize(win, rows, columns) } /* free the old screen image, and allocate a new one */ - oldtop = win->di->topline; + oldtop = *win->di->topmark; drawfree(win->di); - win->di = drawalloc((int)rows, (int)columns); - - /* try to keep the old top row for the next refresh */ - win->di->topline = oldtop; - win->di->bottomline = markoffset(win->cursor); + win->di = drawalloc((int)rows, (int)columns, &oldtop); } /* Cause a different buffer to be associated with this window. This function