Category : Batch File Utilities - mostly for DOS
Archive   : CWD.ZIP
Filename : CWD.C

 
Output of file : CWD.C contained in archive : CWD.ZIP
/* I N C L U D E S */

#include
#include
#include
#include
#include

/* D E F I N E S */

#define TRUE 1
#define FALSE 0
#define NO_ERROR 0
#define VAR_IN_USE 503 /* Any numbers will do as long as they */
#define NO_VAR 504 /* don't conflict with one another. */
#define GENERAL_ERROR 505
#define NO_ARG 506

/* F U N C T I O N P R O T O T Y P E S

Type Function Name
-----------------------------------------------------*/
int cwd( char *varname );
void del_env( char *env_var );
unsigned int env_size( int pid );
unsigned int get_env_pointer( int pid );
unsigned int get_parent_pid( int pid );
int put_env( char *env_var, char *env_text );
void quit( int error );
void set_env_pointer( void );


/* G L O B A L V A R I A B L E S */

char far *environment; /* Pointer to parent environment */
unsigned int env_space; /* Length of parent environment */

/****************************************************/
/* */
/* M A I N: Program entry point */
/* */
/****************************************************/

void main( int argc, char *argv[] )
{

if( argc > 1 )
{
set_env_pointer(); /* set the environment pointer to
the address of the parent process */
quit( cwd( argv[1] ) ); /* exit with whatever value the cwd
function returns */
}
quit( NO_ARG );
}


/*------------------------------------------------------------------------

Return the pathname of the current working directory

-------------------------------------------------------------------------*/

int cwd( char *varname )
{
char path[_MAX_PATH]; /* _MAX_PATH is defined in one of the
standard include files that comes
from Microsoft */

if( getenv( strupr( varname ) ) == NULL ) /* make sure that no
other environment
variable has the same
name. */
{
sprintf( path, "%s", getcwd( path, _MAX_PATH ) );
put_env( strupr( varname ), path ); /* modify the environment */
return( NO_ERROR );
}
else
return( VAR_IN_USE );
}

/*------------------------------------------------------------------------

Delete a name/value pair from the environment to which the
global variable 'environment' points

-------------------------------------------------------------------------*/

void del_env( char *env_var )
{
char far *far1; /* Beginning of next variable */
char far *far2; /* Beginning of the variable */
char *str; /* env_var ptr used in search */
int found = FALSE; /* End of search flag */
far1 = environment;

while( *far1 && !found ) /* Find start of variable to delete */
{
str = env_var;
far2 = far1;

for( ; ( *far1 == *str ) && ( *far1 != '=' ) && *far1 && *str; ++far1, ++str )
;

if( ( !*str ) && ( *far1 == '=' ) )
found = TRUE; /* We found it! */

for( ; *far1; ++far1 )
;

++far1;
}

if( !*far1 && !found ) /* Find env_var? */
return; /* No, we didn't */

/* Shift environment down, to cover env_var */

for( ; !( !*far1 && !*( far1+1 ) ); *far2++ = *far1++ )
;

/* Make sure that two nulls terminate */

*far2 = 0;
++far2;
*far2 = 0;
}


/*------------------------------------------------------------------------

Return the size of the environment for a PID (PSP)

-------------------------------------------------------------------------*/
unsigned int env_size( int pid )
{
unsigned int return_val;

_asm \
{
mov ax,pid
sub ax,1 /* pid points to the segment address of the
environment. pid-1 points to the memory
control block that allocates the space
for the environment. */
mov es,ax
mov ax,es:[3] /* word at offset 3 contains # of paragraphs
(16-byte chunks) of memory allocated */
mov cl,4 /* so multiply by 16 (using an assembler
shortcut to get the number of bytes used */
shl ax,cl
mov return_val,ax
}
return( return_val );
}

/*------------------------------------------------------------------------

Get the segment address of the environment belonging to a
PID (PSP)

Versions of DOS prior to 3.3 don't follow an orderly use of the value
at offset 2Ch in the PSP. This points to the segment of the environment,
which begins at offset 0 of the segment. When 2Ch is 0, you have to
find the environment by following the trail left in the memory
control blocks (MCB). Fortunately, DOS is orderly enough about this for
it to work. The word value at offset 3 of the MCB shows how many
paragraphs (16-byte chunks) were allocated. Here is how DOS is orderly:
this MCB points you to where the parent program's memory ends, and the
environment always follows immediately after. The use of an
environment pointer in DOS 3.3 points to the same place, but gives a
hint that as DOS grows up, it may in the future put the environment
anywhere there's space. Since most of the PSP is not formally documented,
Microsoft can change it without notice. All versions up to this point
work this way (including DOS 4), though. We'll see with DOS 5.

-------------------------------------------------------------------------*/
unsigned int get_env_pointer( int pid )
{


unsigned int return_val;

_asm \
{
mov es,pid
mov ax,es:[2ch] /* Address of environment block */
cmp ax,0 /* no pointer! version < 3.3 */
jne done
mov ax,es /* point to MCB of parent PSP */
dec ax
mov es,ax
mov ax,es:[3] /* number of paragraphs to next MCB */
mov bx,es
add ax,bx /* environment will follow next MCB */
inc ax
inc ax
done:
mov return_val,ax
}
return( return_val );
}

/*------------------------------------------------------------------------

Get the segment address of the parent PID (PSP). Offset 16h of
the PSP contains the segment address of the parent PSP. If you
can find the parent PSP, and with this pointer you have, you
can find the parent's environment.

-------------------------------------------------------------------------*/
unsigned int get_parent_pid( int pid )
{
unsigned int return_val;

_asm \
{
mov es,pid
mov ax,es:[16h] /* Address of parent PSP */
mov return_val,ax
}
return( return_val );
}


/*------------------------------------------------------------------------

Store a name/value pair in the environment to which the global
variable 'environment' points

-------------------------------------------------------------------------*/
int put_env( char *env_var, char *env_text )
{
char far *far0;
unsigned int len;
char env_str[256];
char *str;

strcpy( env_str, env_var ); /* Create environment string */
strcat( env_str, "=" );
strcat( env_str, env_text );
strupr( env_str );

del_env( env_var ); /* Delete the old variable */

/* Find end of environment by looking for 2 NULLS */

for( far0 = environment, len = 0; !( !*far0 && !*( far0+1 )); ++far0, ++len)
;
len = env_space - ( len + 2 ); /* Get free space in environment */


if( len < strlen( env_str ) + 1 ) /* If out of room, return error */
{
printf( "\nOut of environment space\n" );
return( -1 );
}

str = env_str;

/* Copy the new variable into the environment */

for( ++far0; *str; *far0++ = *str++ )
;

/* Make sure that two nulls terminate */

*far0 = 0;
++far0;
*far0 = 0;
}


/*------------------------------------------------------------------------

Program exit point.

-------------------------------------------------------------------------*/
void quit( int error )
{
switch( error )
{
case NO_ARG:
printf( "\nUsage: CWD varname\n" );
break;

case VAR_IN_USE:
printf( "\nVariable in use\n" );
break;
}
exit( error );
}


/*------------------------------------------------------------------------

Set the global variable 'environment' to point to the
environment of the parent process. The starting point is the
system variable _psp which the compiler recognizes as the
segment of the current program's Program Segment Prefix. This
routine is simple. Get the process ID (PID) of the program that
that called this one-------------------+
and read the environment pointer |
into the variable | |
called "env_pointer" | |
| | |
| | |
\ / \ / \ /
env_pointer = get_env_pointer( get_parent_pid( _psp ) );

-------------------------------------------------------------------------*/
void set_env_pointer( void )
{
unsigned int env_pointer;

env_pointer = get_env_pointer( get_parent_pid( _psp ) );
env_space = env_size( env_pointer );
FP_SEG( environment ) = env_pointer;
FP_OFF( environment ) = 0;
}




  3 Responses to “Category : Batch File Utilities - mostly for DOS
Archive   : CWD.ZIP
Filename : CWD.C

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/