Originally published on: Wed, 29 Apr 2009 00:25:05 +0000
I used to sell a command-line utility known as Envy. Envy was a single utility that made 37 new commands available to the MS-DOS batch programmer's repertoire. Most of these commands were able to modify the environment block of the parent process... the niche appeal of the utility. My intent was to augment the relatively spartan batch scripting system with some more rich extension commands.
Huge disclaimer: please do *NOT* try to compile and run this under any Windows version that has appeared since Windows ME; the MS-DOS subsystems are really not compatible with Envy. The command-prompt that you see in Win2K, XP, and Vista isn't the same as the one in the Win95/98/ME. ( Yes, I know there's a command.com present in many modern versions of Windows, but if you run Envy under it, the MCB chain will likely be corrupted. )
I am opening the source to those who may still have a use for MS-DOS and/or the Windows subsystems under which it still basically runs.
The full link to the Envy source code can be found here:
http://www.mailsend-online.com/envysrc.zip
Typing envy at an MS-DOS command-prompt yielded the following:
-checkenv number
-checkmax number
-clearenv
-compare num op num
-copy var srcvar
-ctime var
-date var
-dec var
-deletevar var
-eko str1 .. strN
-expr var term operator term
-filename var [drive path basename ext ] filenameandpath
-findinpath filename
Press ENTER to see more options...
-getdir var
-getxy varx vary
-gotoxy numberX numberY
-inc var
-index var str srchstr
-key var
-lcase var str
-length var str
-loadenv filename
-match str srchstr
-random var max+1
-readln var
-replace var str chr1 chr2
-saveenv filename
-seterrorlevel number
-sleep seconds
-sprintf var str1 .. strN
-substr var str start length
-time var
-ucase var str
-word var num str
-wordcount var str
-write var filename
-writeln var filename
Syntax:
ENVY option
Where option can be one of the following:
Many approaches to changing the parent or master MS-DOS environment block existed in the 90's. An undocumented INT 2EH call ... an undocumented INT 21H call that would find the root MS-DOS Program-Segment Prefix (PSP) ... strategies for walking up and down the Memory-Control-Block (MCB) chain. All were useful based on the context of the problem domain.
The philosophy that I used when manipulating the environment block with Envy was that I would locate the parent environment block ( which might've been the master environment block, in many situations ) and would manipulate the key/value pairs there. That way, the calling MS-DOS process would have the changes to the environment available for the next line in the batch file. This technique seemed to work well for those who used Envy.
To locate the parent environment, I first had to locate the parent PSP. The current PSP segment address ( yep ... this is back in the days of segment/offset 16-bit memory addressing ) of the executing Envy process could be found in the globally available _psp. This variable was set by the Microsoft C/C++ startup code. The offset address was always zero for a PSP.
Envy then probed offset 0x10 in the current PSP for the segment address of the parent PSP.
Once the parent PSP had been found, Envy then grabbed the segment address at offset 0x2C; this value held the segment address of the environment block. The offset address of this block was also zero.
Envy then looked at the MCB for the environment to see how much room ( in sixteen-byte paragraphs had been allocated by MS-DOS for the environment and stored it in the variable lMax. It was crucial to know this value as overrunning it would overwrite control information in the MCB chain and would cause all sorts of errors when MS-DOS or another process tried to dynamically allocate/free memory.
Note: In order to glue together segments and offsets into a far pointer, you'll see that I employ the following macro in the code:
The function findEnv() walks through the above process:
Once the block was found, all I needed was a function that could append or replace a key=value pair in the block as long as enough space was free.
The functions eSet() and the helper function deleteVar() function performed this task.
After building these core functions, it was a simple matter to begin implementing the actual helper functions that would perform some task and leave a result in the parent environment.
The one that probably was the most useful was -readln. -readln read in one line from the standard input device into an environment variable. This meant that other programs not connected to Envy could feed their output into a variable for manipulation by the batch file. In fact, prior to Envy, a number of other utilities could be found that only read a line from stdin as it was so useful.
Here is the code that handles -readln. I should note that in the function main(), the localized parameters argc and argv are preserved in the global counterparts _argc and _argv respectively.
I had pontificated the creation of Envy years before I ever decided to actually do so. By the time I wrote it, I had already written a few different utilities that would read one line into an environment variable using the variety of techniques available, so I pretty much knew the approach I wanted to take.
As I was going back through the code to pull out snippets for this post, I found this function:
The above function drops out of C temporarily and into 8086/8088 assembly-language to call an INT 10H BIOS ( Basic Input/Output Subsystem ) service to set the cursor location. Writing stuff like this was rather commonplace in the 16-bit days. I probably could've found a library routine specific to the Microsoft compiler I was using that would have done the same thing, but it wouldn't have been as pleasant as being able to talk to the lower-level reaches of the computer when I needed to.
I can't do that as much, nowadays. I'm kind of envious of the freedoms that I used to have. ;-)
Unless otherwise noted, all code and text entries are Copyright ©2009 by James K. Lawless. All code snippets related to Envy are covered in the MIT/X11 license in the full source code, available via the link at the top of the article.
Views expressed in this blog are those of the author and do not necessary reflect those of the author's employer. Views expressed in the comments are those of the responding individual.

Save to StumbleUpon
Digg it
Save to Reddit
Share on Facebook
Share on Twitter
More bookmarks
Click **here**
A JavaScript REPL for Android Devices
A Review of Kevin Mitnick's Book Ghost in the Wires
Play MP3 Files with Python on Windows
A Command-Line MP3 Player for Windows
Internet Protocols and Rhino JavaScript
A JavaScript REPL for Android Devices
Why Some Web Sites will go Dark on Jan 18th
Book Review : Paull Allen - Idea Man
A 90's Experiment in Online Systems - The U.S. West CommunityLink Service