Program and Environment Control

Technical Notes

Overview
DOS Environment Structure
Environment Types
Locating Environments
Reading and Writing Environment Variables
Miscellaneous Environment Functions
Parsing the Command Line
Specifying the Command Line Address
Setting the Command Line Parsing Syntax
Executing Child Programs
Miscellaneous Program Control Functions
Sample Program

Overview

This unit consists of functions which locate environments, read and write environment variables, return the length of environment strings, return the size of environment blocks, copy or create environment blocks, parse command lines, execute child programs or system functions, get the name and path of the executing program, exit to DOS, and get the segment address of the PSP.

DOS Environment Structure

Every DOS program is assigned an environment when it is executed. Each environment is made up of a series of ASCIIZ strings, the last of which is followed by an additional NULL character. Each ASCIIZ string is known as an environment variable string, and the entire double NULL terminated series of strings is known as the environment string. Beginning with DOS 3.0, the environment string is followed by a word count which indicates the number of trailing ASCIIZ strings. This count word and its associated ASCIIZ strings are known as the environment tail. The entire environment resides in the environment block, a DOS memory block allocated specifically for the environment.

An entire environment block appears as follows:

varstr1 , 0, varstr2 , 0, ..., varstrn , 0, 0, 1, 0, tailstr1 , 0, avail

where varstr1 through varstrn represent n ASCII environment variable strings, tailstr1 represents a single environment tail string, and avail represents available environment space. Note that the tail string count word in the sample above has a value of one. This value is undefined for versions of DOS below 3.0. From 3.0 to 4.01, this value is always set to one by DOS and the first and only tail string is the pathname of the program which owns the environment.

Each environment variable string appears as follows:

varname=value,0

where varname is the name of the environment variable and value is the value of that variable. The PATH and COMSPEC environment variables are common examples of this.

Environment Types

Spontaneous Assembly provides access to any environment in the system. Four key environments may be of interest to a program: the inherited environment, the parent environment, the active environment, and the root environment.

The root environment is the environment assigned to the primary copy of COMMAND.COM. It is the environment which is inherited by all programs executed by the primary copy of COMMAND.COM.

The active environment is the environment assigned to the active copy of COMMAND.COM. (The most recently executed copy of COMMAND.COM is the active copy.) The active environment is the environment which is inherited by all programs executed from the command line. Note that when there are no secondary copies of COMMAND.COM, the active environment and the root environment are one and the same.

The parent environment is the environment of the parent program which executed a given program. If a program is executed from the command line or from a batch file, the parent program is the active copy of COMMAND.COM and the parent environment and the active environment are one and the same.

The inherited environment is the immediate environment assigned to a given program. If a program is executed from the command line or from a batch file, the inherited environment is a copy of the active environment. If a program is executed from within another program, the inherited environment is either a copy of the parent environment or a copy of an environment defined by the parent. Note that the inherited environment is always a copy of some other environment. No two programs ever share the same environment. Inherited environments are always discarded when a program terminates.

Locating Environments

_get_envseg Returns the segment address of any program's environment. _get_curenvseg Returns the segment address of the current program's inherited environment. _get_parenvseg Returns the segment address of the current program's parent environment. _get_dosenvseg Returns the segment address of the active DOS environment. _get_rootenvseg Returns the segment address of the DOS root environment. These functions locate environments of all types anywhere in the system. Each of these functions returns the segment address of a specified environment. This makes it possible to manipulate any environment with any of the program control environment functions. A typedef for segaddr has been included in the PROGCTL.H header file for easier use of the environment functions.

The location of the environment assigned to a copy of COMMAND.COM varies from one version of DOS to another. It also depends on whether a particular copy of COMMAND.COM is a primary or secondary copy. These functions return the correct environment address in all cases.

Reading and Writing Environment Variables

_get_env Returns a pointer to the value of an environment variable. _set_env Sets the value of a variable string in an environment. These functions read and write environment variables in any environment.

_get_env searches a specified environment for a variable and returns a pointer to the value of that variable in the environment. The returned pointer should only be used to read the environment variable. Writing an environment variable directly (instead of using _set_env) may corrupt the environment.

_set_env searches a specified environment for a variable and sets the value of the variable to a specified string. If the variable does not exist in the environment, it is added. If it exists, its value is changed. If the specified value is a NULL string, the variable is deleted from the environment.

Miscellaneous Environment Functions

_environ_len Returns the length of an environment string. _environ_size Returns the size of an environment block. _copy_envblk Makes a copy of an environment block. _create_envblk Creates an empty environment block. These functions perform miscellaneous operations on environment blocks and strings.

_environ_len determines the length of the environment string in a specified environment. This length includes the double NULL termination but not the environment tail. The _environ_size function returns the size of the DOS memory block which has been allocated for a specified environment. These two functions are most commonly used when copying or creating environments for use with a child program.

The _copy_envblk and _create_envblk functions create simulated environment blocks. Simulated environment blocks act in all respects like true environment blocks, but they are not linked into the DOS memory chain and are not associated with any specific application. Simulated environments are useful for creating custom environments to be passed to child programs. Environments created by these two functions may be operated on by any of the program control environment functions.

Parsing the Command Line

_arg_count Returns the number of command line arguments. _arg_next Returns the next command line argument. _arg_nth Returns a specified command line argument. _arg_reset Resets the current command line argument pointer. These functions read, count, and select command line arguments using a default or custom parsing syntax. Parsing a command line does not alter the command line in any way.

_arg_count determines the number of arguments which are present on the command line. _arg_nth returns a specified command line argument, and _arg_next returns the argument which follows the last argument returned. If no arguments have been returned or if _arg_reset is called, _arg_next the first command line argument. Arguments may be read from the command line in sequential or random order.

Arguments are returned by copying them into a specified buffer in ASCIIZ format. In addition, the most significant character which terminates the argument is reported in the argument chr. (When the terminating character is reported, switch characters and significant separator characters take precedence over insignificant separator characters. See Setting the Command Line Parsing Syntax, below, for a discussion of the different types of separating characters.)

Specifying the Command Line Address

cmdln_start (Variable) Indicates the starting address of the command line. cmdln_next (Variable) Indicates the offset of the next command line argument. _set_cmdln Specifies the address of the command line. _reset_cmdln Resets the command line address to the default location. These functions and variables control the command line address for the command line parsing functions. This makes it possible to parse command line information in arbitrary locations. For example, these functions make it possible to read command line information from a file and parse the information in the input buffer. They also allow environment strings containing command line information to be parsed directly in the environment.

_set_cmdln sets the command line address to a specified location. _reset_cmdln resets the command line address to the default program command line location at offset 0x81 in the PSP. Both of these functions reset the command line pointer to the start of the command line when the new command line address is established. The use of these functions is optional. The default program command line is parsed if no other address is specified.

cmdln_start and cmdln_next are the actual variables used by the command line parsing functions to keep track of the current and starting command line positions. These variables may be read ormodified at any time. If they are modified, the new command line address takes effect immediately. These variables are usually used for processing nested command lines (i.e., for processing "@" files which contain additional command line information).

Setting the Command Line Parsing Syntax

_set_argtbls Installs custom parsing tables for use by the command line parser. _reset_argtbls Resets the command line parser to use the default parsing tables. These functions establish the addresses of the command line parsing tables. These tables determine the command line parsing syntax.

By default, the command line functions support the same command line syntax supported by most DOS commands. A custom parsing syntax may be specified by calling _set_argtbls. The parsing syntax may be changed at any time. _reset_argtbls resets the parsing syntax to the default syntax.

The command line parsing syntax is specified using three tables which identify switch characters and argument separators. Each table is an ASCIIZ string and must reside in DGROUP (global or static non-far data). These tables are used to parse the command line as follows:

Insignificant Separator Table. Command line characters found in this table are skipped when they appear before or after an argument. They also terminate an argument. They are not copied into the buffer.

Significant Separator Table. Command line characters found in this table terminate an argument. They are never skipped and they are not copied into the buffer.

Switch Character Table. Command line characters found in this table mark the beginning of a new argument and end any previous argument. They are copied into the buffer as the first character of an argument.

When a command line character is processed, these tables are searched in the following order: Switch Character Table, Significant Separator Table, Insignificant Separator Table. The character is then compared against CR and NULL to check for the end of the command line. The meaning of the CR character may be modified by placing CR in one of the three parsing tables. If the first character in a table is a NULL, that table is ignored.

The default parsing tables emulate the command line parsing syntax supported by most DOS commands. The default parsing tables are defined as follows:

char Insig_Sep_Table[] = " \t"; (Space, Tab)

char Sig_Sep_Table[] = ",;+"; (Comma, Semicolon, Plus)

char Switch_Char_Table[] = "/"; (Forward Slash)

If INHERIT_PTR is specified for any of the table pointers passed to the _set_argtbl function, the currently-installed table remains installed. INHERIT_PTR is defined in SA_DEF.H.

When a command line argument is returned by _arg_next or _arg_nth, the most significant terminating character is also reported in chr. If a command line argument is followed by insignificant separators as well as a switch or significant separator, then only the switch or significant separator is reported. This allows parsing logic to depend on the most significant characters used to separate arguments.

The following example demonstrates the use of custom parsing tables. This example installs a custom switch character table which includes the hyphen as well as the backslash character. The other two tables remain unchanged.

#include

#include

#include

static char custom_ssep[] = ",;+-"; /* new signif. sep. table */

char arg_buf[128]; /* command line argument buffer */

void main()

{

char chr;

int args;

_put_str("\n\rNumber of arguments: ");

_put_str(_i_to_dec(_arg_count(), arg_buf)); /* get number of arguments */

_put_str("\n\rSecond argument: ");

_put_str(_arg_nth(arg_buf, 2, &chr));

_put_str("\n\rTerminating character: "); _put_chr(chr);

_set_argtbls(INHERIT_PTR,custom_ssep,INHERIT_PTR);

_put_str("\n\n\rUsing Argument Tables...\n");

_put_str("\n\Rnumber of arguments: ");

_put_str(_i_to_dec(_arg_count(), arg_buf)); /* get number of arguments */

_put_str("\n\Rsecond argument: ");

_put_str(_arg_nth(arg_buf, 2, &chr));

_put_str("\n\Rterminating character: "); _put_chr(chr);

_reset_argtbls(); _put_newline(); /* restore default tables */

}

When the following command line is passed to the PROGNAME program:

progname file1 file2-file3 , file4;

then the above example parses this command line as follows:

  1. The call to _arg_count (using the default parsing tables) returns a value of three. The three arguments are: "file1", "file2-file3", and "file4".
  2. The first call to _arg_nth (using the default parsing tables) returns "file2-file3". The terminating character in chr is reported as ",". The comma is reported instead of the space because the space is not a significant terminating character or a switch character.
  3. The second call to _arg_count (using the custom significant separator table) returns a value of four. The four arguments are: "file1", "file2", "file3", and "file4".
  4. The second call to _arg_nth (using the custom significant separator table) returns "file2". The terminating character is reported as "-".
Determining the Name and Path of the Executing Program
_arg_progname
Returns the name and path of the executing program.
This function returns the name and path of the executing program. The returned pathname includes a drive specifier, full path, the program filename, and a terminal NULL. This information is retrieved from the end of the inherited environment and is usually available under DOS versions 3.0 and later. If the name and path cannot be retrieved from the environment for any reason, a NULL path is returned and -1 is returned.

Executing Child Programs

_exec_prog
Executes a program.
_exec_proge
Executes a program using a specified environment.
_exec_sys
Executes a DOS command, batch file, or program.
_exec_syse
Executes a DOS command, batch file, or program using a specified environment.
_exit_to_dos
Temporarily passes control to the DOS command processor.
These functions load and execute child programs, DOS commands, and batch files from within the current program.

_exec_prog and _exec_proge execute a specific child program with a specified command line. The child program is passed either an exact copy of the current program environment (_exec_prog) or an exact copy of a specified environment (_exec_proge). The child program must be either a .COM or .EXE file and it must reside in the directory which is specified by the name of the program. These functions return an exit a success or fail value and on success the termcode argument is modified to report the type of termination (normal termination, TSR, critical error, or ctrl-break) to the current program when the child program terminates.

_exec_sys and _exec_syse execute a system command (DOS command, batch file, or program) by invoking the command processor defined by the COMSPEC environment variable. The command processor is usually COMMAND.COM. The command processor is passed either an exact copy of the current program environment (_exec_sys) or an exact copy of a specified environment (_exec_syse). The system command is specified on a command line which is passed to the command processor. This command line may contain switches to control the command processor, the name of the system command, and any command line information required by the command. If a batch file or program is to be executed, it is located using the path specified in the environment. Control returns to the current program after the command is executed.

_exit_to_dos passes control to the command processor, displays a command prompt, and waits for input. Control returns to the calling program when "EXIT" is typed on the command line. This is equivalent to calling _exec_syse with a NULL command string.

All of these functions restore the state of the calling program when the child program is executed, including the Ctrl-Break state and DTA.

Miscellaneous Program Control Functions

_get_psp
Returns the segment address of the Program Segment Prefix.
psp
(Variable) Contains the segment address of the Program Segment Prefix (PSP).
_get_psp and _psp provide access to the address of the current program's Program Segment Prefix. _get_psp returns the address of the PSP in all memory models without issuing any DOS calls.

Sample Program

The sample program shown below uses of a number of program control functions and demonstrates the following program control features: defining and installing a custom parsing table, getting the first command line argument, getting the segment address of the DOS environment, using that environment address to search for a "PATH" variable string, and concatenating the command line argument to the current "PATH". The program is listed in its entirety.

#include 
#include 
#include 
#include 

void help_msg(void);
char near my_ssep_tbl[] = ",+";       /* new significant sep table (NEAR) */
char newpath[129];
char varname[] = "PATH";
char chr, *arg, far *var;
static char pathbuff[256];            /* initialize pathbuff to zero */
int len;
segaddr dos_seg;

void main()
{
   _chk_version2();

/* setup and install new separator tables note: ';' not to be as a significant separator */
   _set_argtbls(DEFAULT_TBL, my_ssep_tbl, DEFAULT_TBL);

/* process the command line */
   if((arg = _arg_next(newpath, &chr)) == NULL)     /* first argument */
      help_msg();
   len = _str_len(newpath);                         /* len = length of command line argument */
   _str_upr(newpath);                               /* convert path to uppercase */
   if((newpath[0] == '/') && (newpath[1] == 'H'))
      help_msg();                                   /* if help switch, display help message */
   dos_seg = _get_dosenvseg();                      /* get address of DOS environment */
   if((var =  _get_env(varname, dos_seg)) == NULL)
   {
      _put_str("\n\rThe PATH environment variable was not modified.\n\r");
      exit(0);
   }
   len += _fstr_len(var);                  /* len = command line string + "PATH" string */
   if (len > 256)
   {
      _put_str("\n\rPATH was not modified.");
      _put_str("\n\rThe resulting PATH variable would be longer than 255 bytes.\n\r");
      exit(0);
   }
   _str_cpy(pathbuff, varname);            /* copy "PATH" to pathbuff */
   pathbuff[0]+_str_len(varname) = '=';    /* create "PATH=" string */
   _fstr_cat(pathbuff, var);               /* concatenate current "PATH" variable string */
   _str_cat(pathbuff, newpath);            /* add new path string */
   _set_env(pathbuff, dos_seg);            /* set new "PATH=..." in DOS environment */
}

void help_msg(void)
{
   _put_str("Syntax:    PATHADD [/H] path_str\n\n\r");
   _put_str("Where:     /H gives this help message\n\r");
   _put_str("path_str is the path string to be appended to the current path\n\r");
   exit(0);
}
The sample program shown above (PATHADD.C) is provided on the distribution diskettes and may be compiled and linked using the following Microsoft C and Borland C command lines:

Microsoft C:


cl /c /I\msc\include /I\sa\include pathadd.c
link pathadd,pathadd,,\sa\lib\_sas \msc\lib\slibce
Borland C:

bcc /c /ms /I\bc\include /I\sa\include pathadd.c
tlink \bc\lib\c0s pathadd,pathadd,,\sa\lib\_sas \bc\lib\cs