[comp.sys.ibm.pc] Expanding Path in your Environment - A Solution

stan@ucla-an.UUCP (Stan Stead) (06/04/88)

Here is a solution for the problem of string length limitations within the
environment.  Enclosed are a set of source files for a program which will
change the PATH (or any) environment variable for you.  These have been
only moderately tested.  The code is in MSC 5.x and MASM 5.x.
Use and enjoy. Please let us know about any improvements and/or bug fixes.
	Stan Stead and Rich Wilton

Stanley W. Stead
UCLA School of Medicine / Dept of Anesthesiology
BELL: (213) 206-6238
ARPA: ucla-an!stan@ee.UCLA.EDU
UUCP:  {trwrb|ucla-cs|cepu}\
                            !ucla-an!stan
UUCP: {ihnp4|decvax}!hermix/

<-=-=-=-=-=-=-=-=CUT HERE=-=-=-=-=-=-=-=>

#! /bin/sh
# To extract, remove mail header lines and type "sh filename"
echo x - bigset.doc
sed -e 's/^X//' > bigset.doc << '!FaR!OuT!'
XBIGSET
X	Bigset is useful for expanding strings in the environment to any
Xdesired length within the constraints of the size of the environment.  The 
Xfiles listed contain a quick hack to modify the strings within the environment.
XBasically to invoke, do bigset < bigpath.pth.  Bigpath.pth contains the desired
Xstrings by name.  This routine works by searching the dos memory blocks for
Xthe initial environment and then does serial copies to insert the string in
Xthe environment block.  This does not contain any comprehensive checking, so
Xbe VERY careful.
X
X	Rich Wilton & Stan Stead 
X
XUCLA School of Medicine / Dept of Anesthesiology
XBELL: (213) 206-6238
XARPA: ucla-an!stan@ee.UCLA.EDU
XUUCP:  {trwrb|ucla-cs|cepu}\
X                            !ucla-an!stan
XUUCP: {ihnp4|decvax}!hermix/
!FaR!OuT!
echo x - bigset.mak
sed -e 's/^X//' > bigset.mak << '!FaR!OuT!'
Xmcbscan.obj:	mcbscan.asm
X	masm /mx /ml mcbscan;
X
Xstrncmpl.obj:	strncmpl.asm
X	masm /mx /ml strncmpl;
X
Xmemmovel.obj:	memmovel.asm
X	masm /mx /ml memmovel;
X
Xbigset.obj:	bigset.c
X	cl /Zp /c bigset.c
X
Xbigset.exe:	bigset.obj memmovel.obj strncmpl.obj mcbscan.obj
X	link /noi /map bigset memmovel strncmpl mcbscan;
!FaR!OuT!
echo x - bigpath.pth
sed -e 's/^X//' > bigpath.pth << '!FaR!OuT!'
Xpath=d:\aaaaaaaa\bbbbbbbb\cccccccc;d:\eeeeeeee\ffffffff\gggggggg;d:\hhhhhhhh\iiiiiiii\jjjjjjjj;d:\kkkkkkkk\llllllll\mmmmmmmm;d:\nnnnnnnn\oooooooo\pppppppp;d:\qqqqqqqq\rrrrrrrr\ssssssss;d:\tttttttt\uuuuuuuu\vvvvvvvv;d:\wwwwwwwwxxxxxxxx\yyyyyyyy;d:\dos;d:\utility
!FaR!OuT!
echo x - bigset.c
sed -e 's/^X//' > bigset.c << '!FaR!OuT!'
X/*****************************************************************************
X*                                                                            *
X* Name:         bigset.c                                                     *
X*                                                                            *
X* Function:     set an environment variable of arbitrary size                *
X*                                                                            *
X* Notes:        execute as a DOS command; the environment string comes from  *
X*                the standard input device                                   *
X*                                                                            *
X*               WARNING:  No syntax checking!                                *
X* Authors:                                                                   *
X*		Rich Wilton & Stan Stead                                     *
X*		Department of Anesthesiology                                 *
X*		UCLA School of Medicine                                      *
X*		Los Angeles, CA 90024-1778                                   *
X*                                                                            *
X* Bug Fixes or Modifications to:                                             *
X*		ucla-an!stan@ee.ucla.edu                                     *
X*                                                                            *
X* Revisions:    6/3/1988                                                     *
X*                                                                            *
X*****************************************************************************/
X
X#define		MAXSIZE		1024
X
X#include	<dos.h>
X#include	<stdio.h>
X#include	<string.h>
X#include	<ctype.h>
X
Xunsigned int	_psp;			/* in MS C 5.x runtime library */
Xunsigned char	NewEnvString[MAXSIZE];	/* buffer for new env string */
X
X
Xmain( int argc, char * argv[], char * envp[] )
X{
X	unsigned int	MCBScan();	/* returns 1st MCB segment */
X
X	struct				/* NOTE: use /Zp switch */
X	{
X	  char		IDbyte;
X	  unsigned int	PSPowner;
X	  unsigned int	BlockSize;
X	  char		Unused[11];
X	  char		Data[1];
X	}
X			far *MCB;
X
X
X	unsigned int far *	LocalEnv;
X	unsigned int	i,l,n;
X	unsigned char	c;
X
X
X	/* get environment string from standard input */
X
X	for( i=0; ((c=getchar())!=EOF) && (c!='\n'); i++ )
X	  NewEnvString[i] = c;
X
X	NewEnvString[i] = '\0';		/* make into ASCIIZ string */
X
X	if( i==0 )
X	{
X	  printf( "\nNull environment string:  environment unchanged" );
X	  exit( 1 );
X	}
X
X
X	/* make variable name uppercase */
X
X	for( i=0; NewEnvString[i] != '='; i++ )
X	  NewEnvString[i] = toupper( NewEnvString[i] );
X
X
X	/* get pointer to local environment */
X
X	FP_SEG( LocalEnv ) = _psp;	/* point to environment segment */
X	FP_OFF( LocalEnv ) = 0x2C;
X
X	FP_SEG( LocalEnv ) = *LocalEnv;	/* point to environment */
X	FP_OFF( LocalEnv ) = 0;
X
X
X	/* scan through allocated memory blocks for global environment */
X
X	FP_SEG( MCB ) = MCBScan();	/* point to first memory block */
X	FP_OFF( MCB ) = 0x10;
X
X	while( strncmpl( MCB, LocalEnv, 0x10 ) ) /* check 1st 16 bytes */
X	{
X	  FP_OFF( MCB ) = 0;
X	  FP_SEG( MCB ) += MCB->BlockSize + 1;
X	  FP_OFF( MCB ) = 0x10;
X	}
X
X	l =				/* length of env variable name */
X	 (int)strchr( NewEnvString, '=' ) - (int)NewEnvString;
X
X
X	/* update global environment */
X
X	for( i=0; envp[i]!=NULL; i++ )
X	{
X	  if( strncmp( envp[i], NewEnvString, l ) )	/* copy old strings */
X	  {
X	    n = strlen( envp[i] ) + 1;
X	    memmovel( MCB, (char far *)envp[i], n );
X	    FP_OFF( MCB ) += n;
X	  }
X	}
X
X	n = strlen( NewEnvString ) + 1;		/* copy new string */
X	memmovel( MCB, (char far *)NewEnvString, n );
X
X	FP_OFF( MCB ) += n;
X	MCB->IDbyte = '\0';		/* append one more null */
X}
!FaR!OuT!
echo x - mcbscan.asm
sed -e 's/^X//' > mcbscan.asm << '!FaR!OuT!'
X		TITLE	'scan DOS memory for memory control blocks'
X		NAME	mcbscan
X		PAGE	55,132
X;
X; Module name:	MCBScan
X;
X; Description:	unsigned int MCBScan();
X;
X; Notes:	returns paragraph addr of 1st DOS memory control block
X;		 (aka "arena header")
X
X; Authors:
X;		Rich Wilton & Stan Stead
X;		Department of Anesthesiology
X;		UCLA School of Medicine
X;		Los Angeles, CA 90024-1778
X;
X; Bug Fixes or Modifications to:
X;		ucla-an!stan@ee.ucla.edu
X;
X; Revisions:    6/3/1988
X;
X
XSTART		EQU	70h		; first paragraph to scan
X
X_TEXT		SEGMENT	byte public 'CODE'
X		ASSUME	cs:_TEXT
X
X		PUBLIC	_MCBScan
X_MCBScan	PROC	near
X
X		push	bp
X		mov	bp,sp
X		push	di
X		push	si
X		push	ds
X
X; 1st segment to search is START; last segment is this program's env block
X
X		mov	ah,51h
X		int	21h		; BX = PSP
X		mov	ds,bx
X		mov	cx,ds:[2ch]	; CX = environment segment
X		dec	cx		; CX = last paragraph to search
X
X		mov	ax,START
X
X; loop through memory, paragraph by paragraph
X
XL01:		mov	ds,ax		; DS:[0] -> first possible block
X		cmp	byte ptr ds:[0],'M'
X		je	L03
X
XL02:		inc	ax
X		cmp	ax,cx
X		jb	L01
X		jmp	short L05	; exit with this program's env block
X
XL03:		mov	bx,ax		; BX = possible "hit"
X
XL04:		add	bx,ds:[3]
X		inc	bx		; BX = possible next in chain
X		cmp	bx,cx
X		je	L05		; success
X
X		cmp	ax,bx
X		je	L02		; circular "chain" -- keep trying
X
X		mov	ds,bx
X		cmp	byte ptr ds:[0],'M'
X		je	L04		; 'M' found so continue chain
X		jmp	L02		; 'M' not found so keep trying
X
XL05:		pop	ds
X		pop	si
X		pop	di
X		pop	bp
X		ret
X
X_MCBScan	ENDP
X
X_TEXT		ENDS
X
X		END
!FaR!OuT!
echo x - memmovel.asm
sed -e 's/^X//' > memmovel.asm << '!FaR!OuT!'
X		TITLE	'string copy routine'
X		NAME	memmovel
X		PAGE	55,132
X;
X; Module name:  memmovel
X;
X; Description:  void * memmovel( char far * s1, char far * s2, unsigned int n );
X;
X; Notes:	like memmove but uses far pointers
X;
X
X; Authors:
X;		Rich Wilton & Stan Stead
X;		Department of Anesthesiology
X;		UCLA School of Medicine
X;		Los Angeles, CA 90024-1778
X;
X; Bug Fixes or Modifications to:
X;		ucla-an!stan@ee.ucla.edu
X;
X; Revisions:    6/3/1988
X;
X
XARG1		EQU	[bp+4]
XARG2		EQU	[bp+6]
XARG3		EQU	[bp+8]
XARG4		EQU	[bp+10]
XARG5		EQU	[bp+12]
X
X_TEXT		SEGMENT	byte public 'CODE'
X		ASSUME	cs:_TEXT
X
X		PUBLIC	_memmovel
X
X_memmovel	PROC	near
X
X		push	bp
X		mov	bp,sp
X		push	si
X		push	di
X		push	ds
X
X		mov	di,ARG1
X		mov	es,ARG2		; DS:SI -> s1 (destination)
X		mov	si,ARG3
X		mov	ds,ARG4		; ES:DI -> s2 (source)
X		mov	cx,ARG5		; CX = number of bytes to move
X
X		mov	ax,si
X		mov	dx,ds		; DX:AX -> source
X
X		cld			; set autoincrement
X		shr	cx,1		; CX = number of words to move
X					; cf = rightmost bit
X		rep	movsw		; move string
X		rcl	cx,1		; CX = rightmost bit
X		rep	movsb		; move last byte if needed
X
X		pop	ds
X		pop	di
X		pop	si
X		pop	bp
X		ret
X
X_memmovel	ENDP
X
X_TEXT		ENDS
X
X		END
!FaR!OuT!
echo x - strncmpl.asm
sed -e 's/^X//' > strncmpl.asm << '!FaR!OuT!'
X		TITLE	'string compare routine'
X		NAME	strncmpl
X		PAGE	55,132
X;
X; Module name:  strncmpl
X;
X; Description:  int strncmpl( char far * s1, char far * s2, unsigned int n );
X;
X; Notes:	works like strncmp but uses far pointers
X;
X; Authors:
X;		Rich Wilton & Stan Stead
X;		Department of Anesthesiology
X;		UCLA School of Medicine
X;		Los Angeles, CA 90024-1778
X;
X; Bug Fixes or Modifications to:
X;		ucla-an!stan@ee.ucla.edu
X;
X; Revisions:    6/3/1988
X;
X
XARG1		EQU	[bp+4]
XARG2		EQU	[bp+6]
XARG3		EQU	[bp+8]
XARG4		EQU	[bp+10]
XARG5		EQU	[bp+12]
X
X_TEXT		SEGMENT	byte public 'CODE'
X		ASSUME	cs:_TEXT
X
X		PUBLIC	_strncmpl
X
X_strncmpl	PROC	near
X
X		push	bp
X		mov	bp,sp
X		push	si
X		push	di
X		push	ds
X
X		mov	si,ARG1
X		mov	ds,ARG2		; DS:SI -> s1
X		mov	di,ARG3
X		mov	es,ARG4		; ES:DI -> s2
X		mov	cx,ARG5		; CX = number of bytes to compare
X		xor	ax,ax		; AX = 0
X
X		repz	cmpsb		; compare strings
X		jz	L01		; exit with AX=0 if strings are equal
X
X		mov	ax,1		; AX = 1
X		jnb	L01		; exit if s1 > s2
X
X		neg	ax		; AX = -1 (s1 < s2)
X
XL01:		pop	ds
X		pop	di
X		pop	si
X		pop	bp
X		ret
X
X_strncmpl	ENDP
X
X_TEXT		ENDS
X
X		END
!FaR!OuT!
exit