File Archive

Output of file : CHANGES.22 contained in archive : ME22.ZIP

Changes to ME 2.2

Swap entire editor out of memory for DOS commands
We are using a package written by Thomas Wagner of Germany to swap the
entire editor out to disk when we shell out to DOS. There is only a very
small portion of the editor left in memory after the swapping is done. This
will free up a lot more memory for those big compiles which you need to do
from within ME.

For those of you who are technically minded, we now need to use malloc() to
allocate a VM page buffer instead of allocating directly from DOS as we did
before. If you know that you are not going to shell out to DOS during an
editing session and you want the editor to allocate a page buffer directly
from DOS, invoke ME with the -a argument.

UNDO and REDO Command
The big addition to 2.2 is the UNDO/REDO capability. This is true UNDO - any
editing operation can be undone, even global substitution.

To invoke UNDO, press the key. You can then press the left arrow
key to undo an operation and the right arrow key to redo it. This function can
be referenced in the macro language as "new_undo".

un, ul and uc options in CONFIG.ME
un is 1 if you want UNDO, 0 if not. If un is not found in CONFIG.ME,
then UNDO will be enabled.
ul is the undo buffer length for each buffer (default = 4096)
uc is the depth of the undo stack (default = 64).

-ul and -uc are new command-line arguments. -ul8192 sets the
undo buffer to be 8192 bytes long, and -uc100 sets the undo stack to
100 operations.

State file
The state of your last editing session is now preserved in an external
state file. The editor will load a state file if you invoke ME without
any file names on the command line.

The STATE.ME file is an ASCII file which contains information about the
state of the last editing session. It is patterned after the state file
which the Microsoft C v6 compiler uses.

The MESTATE environment variable defines the path where you would like
the STATE.ME file to reside. If you do not define this variable, then
a STATE.ME file will be created in every subdirectory which you use the
editor in. If you choose to use the MESTATE environment variable, then
the editor will look for STATE.ME in the defined path, and will write the
new STATE.ME file to that path.

The "st" variable in both the options menu and in the CONFIG.ME file control
whether or not to read and write the state file. The default value is TRUE.

New Command Line Arguments
-s command line option for MaxPageSlots * 1K
ie: -s3 gives you 3K page slots

-p command line option for PageSize * 1K
ie: -p16 gives you a 16K VM page

New Environment Variables
1) MEFLAGS environment variable.
If you always want to start ME with certain
command-line options (such as -4, -lxxx, etc), you can place these options
in an environment variable called MEFLAGS. Each option must be separated by
a space. To use the MEFLAGS variable, you can place the following command in
your AUTOEXEC.BAT file :

set MEFLAGS=-[ -...]

For instance,

set MEFLAGS=-veverex3.drv -ul4096

will automatically load the everex3.drv video driver, and will set the undo
buffer length to 4K per buffer.
If you have the MEFLAGS variable set, and you start ME with command-line
arguments, the options specified in MEFLAGS will be acted on first followed
by the ones which you specified on the command line.

2) MEPATH environment variable and the "mp" option.
When you try to read a file, you usually specify the name of the file if you
want to access the current directory, and you usually specify a path plus
the file name if you want to access another directory. We have added a
convenience feature which makes accessing files in other directories
easier. The MEPATH environment variable can be set to a list of semi-colon
separated pathnames (like the DOS PATH environment variable) which ME will
search if the file is not in the current directory. For instance, if you
often want to view the C compiler's include files while editing, you might
put the following line in your AUTOEXEC.BAT file :

set MEPATH=d:\msc5\include;d:\msc5\include\sys

If you want to view the file STDIO.H while in an ME session, press the
key which corresponds to the open_window() command. When ME asks you for the
file to put in the other window, merely type "stdio.h". If STDIO.H is not
in your current directory, then all of the directories in MEPATH will be

There is an editor variable which you can set in either the CONFIG.ME file
or in the options menu which controls whether or not the MEPATH environment
variable should be used. The "mp" option should be set to 1 if the MEPATH
should be searched, and 0 if not.

Saving the Original Display
We now save the opening DOS/OS2 screen. There is a "ds" parameter in the
CONFIG.ME file (but not in the options menu) which should be 1 if you want
to save the DOS screen and 0 if not. (The default is 1.)
The user can view the opening screen by pressing or by invoking
the show_dos_screen() macro.

Command to Key Help
The key is now bound to the function name_to_key(string cmdname).
This command accepts the name of am editing command or a macro, and returns
the keystroke name(s) which invokes that command/macro.

Case change function added
There is a new command in the block menu. If you type the letter 'k', the
case of the letters in the block will be changed to either all upper case or
all lower case.

Regular Expressions Improved
We added '{' and '}' for parenthesized expressions.
{abc}+ searches for one or more occurences of "abc".

We have also improved alternation.

We added the following shortcuts:

"[a-zA-Z0-9]", 'a', /* :a => alphanumeric */
"[ \t]+", 'b', /* :b => whitespace */
"[a-zA-Z]", 'c', /* :c => alpha */
"[0-9]", 'd', /* :d => any digit */
"[0-9a-fA-F]+", 'h', /* :h => hex number */
"[0-9]+", 'i', /* :i => integer */
"[a-zA-Z_][a-zA-Z_0-9]+", 'l', /* :l => valid C identifier */
"[a-zA-Z]+", 'w', /* :w => word */

IMPORTANT - To search for a colon, you must prefix it with a backslash
(ie - \:). Your next-error macros will probably have to be altered slightly.

Simpler Access to Block Indent
Pressing TAB or BACKTAB in response to a pick command will
invoke block indent. These keys can be used in addition to the current
method of pressing 'i' and then pressing the arrow keys.

Percentage Indicator
ME now shows the percentage of the file currently being read. This does
not speed up reads, but will let you know how the editor is progressing
during longish file reads.

Embedded 0xFFs
ME can now read files with imbedded 0xFF bytes.

Support for > 32K lines
Buffers can now contain up to 2^31-1 lines. We changed the internal data
type of line numbers from int to long.

VGA support added
ME will now support VGA cards without the use of external video drivers.

Reading Sped Up
File reading speed has been improved on the order of 30%.

Default Page Size Increased
The default VM page size has been changed from 4K to 16K.


Macro file extension
The macro compiler will now compile files with a .m extension. You just need
to give the root name to the compiler. For instance, if you have a macro
file called linedraw.m, then all you need to do to compile it is give the
DOS command "maccomp linedraw".

Init macro for file extensions
When a buffer is created for the first time, the file extension of the
buffer is examined and a user-defined macro is called. ME looks for
a macro called _ext, where "ext" is the file extension in lower case.
For instance, for "C" files, ME will try to run a macro called _c(), and
for assembler files, ME will try to run _asm().

This facility can be used to set up some language-sensitive features, such
as keyword recognition and templeting.

If you edit files with different languages simultaneously, you may want
to think about using hook 28 (discussed below). Hook 28 is called when
a buffer becomes the "current" buffer.

Bit Twiddling Operators Added
We have added the following operators to the macro language:

>> right shift
<< left shift
& logical AND
| logical OR
^ logical XOR
~ logical NOT

Please note - we do not have augmented assigment operators which correspond
to these operators yet. In other words, the statement "a |= b" is not yet legal.

Faster insert() Function
The insert() function really slowed down in 2.1 due to the overhead of the
virtual memory manager and the addition of real tabs. We sped up the
insert() function by shoving the inserted string into the current buffer
without doing any kind of sophisticated checking. For compatability, you
can use the slow_insert() function; slow_insert() should be used only in
the case where you are inserting a tab AND the "rt" variable is set to 0.

Slow_insert() takes two arguments. The first arg is the string to insert.
The second arg is non-zero if you want the string inserted in front of
existing characters and zero if you want the string to overwrite existing

For example, you would use

slow_insert("abc", 1);

instead of


The new insert() will really speed some of your macros up, especially if
you are inserting long lines of text.

New error message format
In order to conform to Microsoft's format of error messages, the compiler
now puts out error messages in this format :

filename(line) : syntax error ......

If you are using the old COMPMAC macro to compile your macros from within ME,
you will need to change the regular expression used to parse errors.

New Return for Capture_Dos()
The capture_dos() function now returned the buffer id in which the DOS
output is saved in. You can then display it if you want by issuing a
show_buffer() call.

New Functions

We added a bunch of functions to the macro language. Most of these functions
are implemented using the ME feature of linking to external C routines. In
this case, most of these routines were things from the standard C run-time
library which we use anyway --- we just made them available to the macro


string abspath(fname)
string fname;

Returns the absolute path name corresponding to a file. The absolute
path name originates from the root directory.

Fname is the name of the file. It may contain a partial path specifier,
and may contain the directories '..' and '.'.

A string which represent the absolute path name of the file. The first
two characters of the path are the drive specifier.


If the file 'foo' is in the path c:\X\Y\Z\ME and the current directory is
c:\X\Y\Q\R, then abspath() will return C:\X\Y\Z\ME\FOO
true_path = abspath("..\\..\\ME\\foo");


int access(fname, mode)
string fname;
int mode;

If fname is the name of a file, access() checks whether the file exists and
can be accessed in 'mode'. If fname is the name of a directory, access()
only checks whether the directory exists.

Fname is the name of a file or directory.
Mode can be one of the following
0 checks for existence only
2 checks for write permission
4 checks for read permission
6 checks for read and write permission

0 is returned if the file can be accessed in the specified mode. -1 is
returned if the file either does not exist or cannot be accessed in that mode.


This function will return non-zero if a file exists
string fname;
if (access(fname, 0) == 0)
return 1;
return 0;


autoload(filename, macroname [, keys...])
string filename, macroname;
int or string keys;

Defers the loading and execution of macro 'macroname' from file 'filename'
only when the macro is accessed for the first time. This allows you to
conserve memory and cut startup time if you want to have access to a number
of infrequently loaded macros.

Filename is the name of the file which the macro is located in. The
ME rules for accessing a macro file are followed here.
Macroname is the name of the macro to load and execute.
Keys is the sequence of keystrokes which the macro is bound to.



/* Help is loaded only if and when the user presses ALT-H */
autoload("helpme", "help", "");

/* Compress is loaded and executed only when the user presses ALT-P and
specifies 'compress' as the macro to execute.
autoload("compress", "compress");


int chdir(dirname)
string dirname;

Changes the current working directory on any drive.

Dirname is the name of the directory to change to. If dirname contains
a drive specifier, the working directory on that drive will be changed,
however, the default drive is NOT changed.

0 if successful, -1 if not.


if (chdir("\\TMP") != 0)


string get_os()

This function is used in order to determine which operating system you
are currently running on.


"DOS" if the editor is running on MS-DOS, and "OS2" if the editor is
running under OS/2.


if (get_os() == "DOS")
get_tty_str("You are running under DOS");


int get_shiftstate()

Retrieves the current keyboard shift state.


The shift state is as follows :
0x01 Right SHIFT depressed 0x10 SCROLL LOCK on
0x02 Left SHIFT depressed 0x20 NUM LOCK on
0x04 CTRL key depressed 0x40 CAPS LOCK on
0x08 ALT key depressed 0x80 INSERT on


sh = get_shiftstate();
if (sh & 0x08)
message("ALT is on");


string getcwd()

Gets the name of the current working directory.


The name of the current directory.


szCWD = getcwd();
if (szCWD == "\\TMP")


int getdrive()

Returns the number of the current disk drive.


1 for drive A, 2 for drive B, 3 for drive C, 4 for drive D, etc.


string int_to_keyname(iKey)
int iKey;

Given a keycode, int_to_keyname() returns the corresponding keystroke

iKey is an integer which should be a valid keycode.

The key name.


szName = int_to_keyname(9);
/* szName will be the string "" */


int interrupt(intno, regs);
int intno;
unsigned regs[7];
'regs' is laid out as follows
regs[1] = ax regs[5] = si
regs[2] = bx regs[6] = di
regs[3] = cx regs[7] = cflag
regs[4] = dx

This function performs one of the interrupt routines. This corresponds to the
int86() functionion most C compilers.

Intno is the interrupt number.
Regs should contain parameters for the interrupt. After the interrupt is
finished, the possibly modified registers will be found in regs[].

Whatever the interrupt returns.


The following function retrieves the cursor position using Int 10H.
unsigned regs[8];

regs[1] = 0x0300;
regs[2] = 0x0000;
interrupt(0x10, ®s);
DH has the row and DL has the column position.
get_tty_str("The cursor is on row is %d and col is %d",
regs[4] / 256, regs[4] % 256);


int keyname_to_int(szName)
string szName;

This function takes a keystroke name and returns the corresponding key code.

szName should be a valid keystroke name.

An integer which represents the key code corresponding to the key name.
If a match is not found, 0 is returned.


key = keyname_to_int("");
/* key will be the value 9 */


int mkdir(dirname)
string dirname;

Creates a new directory.

Dirname is the name of the directory to create. It may contain a drive
specifier and a full path.

0 if successful, -1 if not.


if (mkdir("\\TMP"))
get_tty_str("Could not create \\TMP");
return -1;


int peekb(seg, offset)
int peekw(seg, offset)
Retrieves the word or byte at address segment:offset.

Seg is the segment to examine, and offset is the offset from the
beginning of the segment.

The word (peekw) or byte (peekb) at that memory location.


/* Retreive the BIOS video mode */
video_mode = peekb(0x40, 0x49);


int pokeb(seg, offset, byte)
int pokew(seg, offset, word)
int seg;
int off;
int byte, word;

Places a byte or word (2 bytes) of data at the specified memory location.

Seg is the segment to examine, and offset is the offset from the
beginning of the segment. Byte or Word is the data to put into that
memory location.

The old word (pokew) or byte (pokeb) at that memory location. This value
can be saved in case you want to restore the original contents of the
memory location at a later time.


int rmdir(dirname)
string dirname;

Removes the specified directory. The directory is deleted only if it is
empty and if it is not the current working directory.

Dirname is the name of the directory to remove. It may contain a drive
specifier and a full path.

0 if successful, -1 if not.


if (rmdir("\\TMP"))
get_tty_str("Could not remove \\TMP");
return -1;


int drive;

Changes the default disk drive to 'drive'.

1 for drive A, 2 for drive B, 3 for drive C, 4 for drive D, etc.



int millisecs;

Suspends the execution of the editor for the specified number of milliseconds.
While the editor is sleeping, the SLEEP hook (hook number 10) will be called
repeatedly. See the section on hooks for more details.

Millisecs is the number of milliseconds to sleep. 1000 milliseconds is
equal to 1 second.



message("You messed up!");

sleep(2000); /* suspends ME for 2 seconds to let the message soak in */


string strlower(s)
string strupper(s)
string s;

Transforms the passed string to either all upper or all lower case.

S is the string to transform. It may contain mixed case letters. Characters
which are non-alphabetic will not be transformed.

The transformed string.


s = strupper("AbcDef"); /* s will be "ABCDEF" */
s = strlower(s); /* s will be "abcdef" */


int unlink(fname)
string fname;

Deletes the specified file.

Fname is the name of the file to delete. It may contain a drive specifier
and a full path.

0 if successful, -1 if not.




CTYPE.H macros defined as ME macro functions
isalnum(c) TRUE if 'c' is alphanumeric, FALSE otherwise (a-z,A-Z,0-9)
isalpha(c) TRUE if 'c' is alphabetic, FALSE otherwise (a-z,A-Z)
isascii(c) TRUE if 'c' is an ASCII character, FALSE otherwise (c < 128)
iscntrl(c) TRUE if 'c' is control character, FALSE otherwise
isdigit(c) TRUE if 'c' is a digit, FALSE otherwise (0-9)
isgraph(c) TRUE if 'c' is a graphic character, FALSE otherwise (alnum or punct)
islower(c) TRUE if 'c' is a lower-case alpha, FALSE otherwise (a-z)
isprint(c) TRUE if 'c' is a printable character, FALSE otherwise (graph or blank)
ispunct(c) TRUE if 'c' is a punctuation mark, FALSE otherwise
isspace(c) TRUE if 'c' is a whitespace character, FALSE otherwise
isupper(c) TRUE if 'c' is an upper-case alpha, FALSE otherwise (A-Z)
isxdigit(c) TRUE if 'c' is a hex digit, FALSE otherwise (0-9,a-f,A-F)

toupper(c) converts character c to upper-case
tolower(c) converts character c to lower-case

New Hooks
First, there is a file called event.h which give English names to the
hook numbers. You may want to include this file in any macros which use

Hook 10 for sleeping.
While the editor is idle because of the sleep() function, event 10 is
continuously generated.

Hook 28 for changing to a buffer.
When you set the "input focus" to a buffer (ie - when you make a buffer
the current buffer), hook 28 will be run. This lets you do things like
implement buffer-specific or file-extension-specific macros.

For example, you can do the following

add_hook(28, "set_buffer_tabs");

if ((iExt = index(filename(), ".")) <= 0)
szExt = strlower(substr(filename(), iExt+1, 3));

switch (szExt)
case "c" :
set_tabs("2 4 6 8 10 12 14 16 18 20");
case "pas" :
set_tabs("4 8 12 16 20 24 28 32");
case "asm" :
set_tabs("5 10 15 20 25 30");

Hook 30 for status help.
If you press ALT-H while responding to a prompt, event 30 will be generated.
You can use this event to implement help for the user while he is responding
to certain commands (like a file-completion or a command-completion utility).

Hook 31 for idling.
While you are idle, event 31 will be generated. You can use this to implement
things like real-time clocks which appear on the status line, etc.

Key Names Now Supported
One of the bigger hassles in writing an ME macro is remembering the key
codes. This problem is particularly acute when you are doing a lot of
assign_key()'s in your macros. One solution is to include the file MEKEYS.H,
and to use the #define'd name as the second argument to assign key.

ME now supports keystroke names. If the second argument to assign_key() is
a string, ME will attempt to translate that string into a key code. For
example, you can now have this kind of statement in a macro :

assign_key("myfunc", "");

Here is a list of the key names we now support :

through , through , ,
and ^key

The following keys can be stand-along or prefixed with a SHIFT or CTRL.
For example, , , . Not all combinations
will produce valid key codes. Use ME's command to see which
combinations produce valid key codes.


There are two new macro functions related to key names. They are
int_to_keyname() and keyname_to_int(). Please see the above section on
the new macro functions for more details.


The following notes are from the new COMPILE.M macro. This macro is
designed to replace the old MSCCOMP macro, and provides a more general
way to compile. In addition, we think that it provides a more flexible
platform for integrating other compilers.

In order to use this macro, dearchive it from the MACROS.ARC file, compile
it with the command MACCOMP COMPILE, and load it in when you start the
editor (the manual discusses several ways to do this. You may want to
put it in your MEMACROS environment variable, since you have to create
an MECOMPILE environment variable anyway.

/* */
/* */
/* This function initializes the hot keys to enable one to compile */
/* a file from within ME. The program does several things you should */
/* be aware of: */
/* 1. It relies on the existance of the environment variable */
/* "MECOMPILE". This variable identifies the various file */
/* name extensions supported as well as the instructions for */
/* calling the appropriate compiler. */
/* set MECOMPILE=.ccl -c -AL -W3 -H31 ;.asmmasm ;.mmaccomp ; */
/* a. for any file with a ".c" extension, this program will */
/* use the instructions up to the ";" in order to compile */
/* the current file being edited. In this case */
/* "cl -c -AL -W3 ". In all cases a space and ";" must */
/* follow the command instruction. The currently */
/* supported extensions are: */
/* .m - for ME macros (I use .MAC as an extension for */
/* all macros). */
/* .c - for the 'C' language. */
/* .asm - for assembly language (.asm) */
/* 2. The error messages generated by the compiler as assumed to */
/* be in the following format: */
/* test.asm(124): error A2009: description */
/* This is necessary in order to consistently determine the */
/* line number on which the error exists. In the above case */
/* the line "124" is being reported as an error. */
/* 3. Currently this program is activated with the use of two */
/* hot-keys: */
/* CTRL_C - This key causes the current file to be */
/* compiled, and the errors are placed in a */
/* file with the same file name, but with an */
/* extension of ".err". After the file has */
/* been compiled, the first error, if there */
/* was one, is displayed at the bottom of the */
/* display. This program automatically places */
/* the cursor on the reported line number to */
/* facilitate quick editing. */
/* CTRL_N - This key causes all subsequent errors to be */
/* displayed on the screen, and the cursor */
/* moves to the offending line number for your */
/* editing. */
/* */
/* */
/* Created by Marc Adler of Magma Systems */
/* Modifications and cleanup performed by Marc Adler and Jon Herbold. */
/* */