diff options
Diffstat (limited to 'contrib/romid/setenvs.c')
-rw-r--r-- | contrib/romid/setenvs.c | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/contrib/romid/setenvs.c b/contrib/romid/setenvs.c new file mode 100644 index 00000000..e18e399e --- /dev/null +++ b/contrib/romid/setenvs.c @@ -0,0 +1,200 @@ +/* subroutine to put a value string into an environment symbol. + Uses the controling command.com environment, not the programs. + This means that the env variable is set so other routines in + a .BAT file may use it. + + call: settheenv (char * symbol, char * val); + symbol is an asciiz string containing the env variable name, + val is an asciiz string containing the value to assign to this vbl. + + returns: 0 = OK, + 1 = failure. + failure is not unlikely. The env block may be full. Or on some + systems the env block might not be found + + SETENVS.C was written by Richard Marks <rmarks@KSP.unisys.COM>. +*/ + + +#include <stdio.h> +#include <dos.h> +#include <string.h> +#include <stdlib.h> + +typedef struct { + char fill1[0x0A]; + int *prev_term_handler; + int *prev_ctrl_c; + int *prev_crit_error; + char fill2[0x16]; + int envir_seg; +} psp; + +typedef struct { + char type; + int psp_segment; + int num_segments; + char fill[11]; + char arena_data; +} arena; + + +#define NORMAL_ATYPE 0x4D +#define LAST_ATYPE 0x5A + + +static arena * get_next_arena (arena * ap) { + return( MK_FP( FP_SEG(ap)+1+ap->num_segments, 0) ); +} + +/* returns 0 if passed pointer is to an arena, else returns 1 */ +static int is_valid_arena (arena * ap) { + arena * ap1; + if (ap->type == NORMAL_ATYPE && + (ap1=get_next_arena(ap))->type == NORMAL_ATYPE && + ( (ap1=get_next_arena(ap1))->type == NORMAL_ATYPE || + ap1->type == LAST_ATYPE) ) + return(0); + return (1); +} + + +static arena * get_first_arena () { +/* return pointer to the first arena. + * scan memory for a 0x4D on a segment start, + * see if this points to another two levels of arena + */ + arena * ap, * ap1; + int * temp; + int segment; + + for (segment=0; segment<_CS; segment++) { + ap = MK_FP(segment, 0); + if ( is_valid_arena (ap) == 0) return (ap); + } + return(NULL); +} /* end get_first_arena */ + + +static int is_valid_env (char * ad, int num_segs) { + char * base_ad; + base_ad = ad; + while ( (*ad) && (((ad-base_ad)>>4) < num_segs) ) { + if (strnicmp(ad, "COMSPEC=", 8)==0) return(0); + ad += strlen(ad) + 1; + } + return (1); +} + + +static arena * get_arena_of_environment () { +/* to get the arena of first environment block: + First get segment of COMMAND.COM from segment of previous critical err code. + Then scan all the arenas for an environment block with a matching PSP + segment */ + +arena * ap; +psp * pspp, * pspc; +unsigned int i, ccseg; + +/* set pspp to psp of this program */ +pspp = MK_FP(_psp,0); + +#ifdef DEBUG +printf("prog psp=%p\n",pspp); +#endif + +/* set pspc to psp of COMMAND.COM, back up a bit to get it if needed */ +ccseg = FP_SEG (pspp->prev_crit_error); +if ( (i=ccseg-32) < 60) i=60; + +while (ccseg>i) { + pspc = MK_FP (ccseg, 0); + if ( is_valid_arena((arena *) pspc) == 0) goto L1; + ccseg--; +} +return (NULL); + +L1: pspc = MK_FP (++ccseg, 0); +#ifdef DEBUG +printf("comm.com=%p\n",pspc); +#endif + +/* first see if env seg in command.com points to valid env block + if env seg is in a valid arena, then arena must point to this command.com + else assume env block is fabricated like for 4DOS, use 128 bytes */ + +ap = MK_FP (pspc->envir_seg-1, 0); +i = ap->num_segments; + +if (is_valid_arena (ap) == 0) { + if (ap->psp_segment != FP_SEG(pspc)) goto L2; +} else { + i = 9; +} + +if ( is_valid_env (&ap->arena_data, i) == 0 ) + return (ap); + +/* command.com did not so point, search thru all env blocks */ + +L2: +if ( (ap=get_first_arena()) != NULL ) { + while (ap->type != LAST_ATYPE) { +#ifdef DEBUG + printf("%p\n",ap); +#endif + if (ap->psp_segment == FP_SEG(pspc) && + is_valid_env (&ap->arena_data, ap->num_segments)==0 ) + return (ap); + + ap = get_next_arena(ap); + } +} return(NULL); +} /* end get_arena_of_environment */ + +/*****************************************************************************/ + +int settheenv(char * symbol, char * val) { +int total_size, + needed_size=0, + strlength; +char * sp, *op, *envir; +char symb_len=strlen(symbol); +char found=0; +arena * ap; + +strupr(symbol); + +/* first, can COMMAND.COM's envir block be found ? */ +if ( (ap=get_arena_of_environment()) == NULL) + return(1); + +/* search to end of the envir block, get sizes */ +total_size = 16 * ap->num_segments; +envir = &ap->arena_data; +op=sp=envir; +while (*sp) { + strlength = strlen(sp)+1; + if ( *(sp+symb_len)=='=' && + strnicmp(sp,symbol,symb_len)==0 ) + found=1; + else { + needed_size += strlength; + if (found) strcpy(op,sp); + op = &op[strlength]; + } + sp += strlength; +} +*op=0; +if (strlen(val) > 0) { + needed_size += 3 + strlen(symbol) + strlen(val); + if (needed_size > total_size) + return(1); /* could mess with environment expansion here */ + + strcpy(op, symbol); strcat(op, "="); strcat(op, val); + op += strlen(op)+1; + *op = 0; +} +return(0); +} /* end setheenv subroutine */ |