/* - - - - - - - - - - N O T I C E ! ! ! Things that need to be added!!! Technical() needs to calculate how much room is left. Need a Zap all but... command. Need a test var for substring - - - - - - - - - - */ /* Strategy for direct access of master system environment variables */ /* Call int 21 function 52 this returns Sysvars, at negative offset 2 the */ /* segment address of the first memory arena header is found. The memory */ /* arena headers are the filing system that MSDOS uses to set aside memory */ /* for uses of all kinds. At offset 3 these headers hold an integer that */ /* specifies the size of the data that has been set aside. The memory */ /* arena header itself is one paragraph in length, I.E. 16 bytes, the data */ /* follows immediately, at the beginning of the next paragraph boundary. */ /* Since the data begins at the next paragraph, and ends size paragraphs */ /* later, this size integer plus 1 points to the next memory arena header. */ /* If one walks through the memory block chain sooner or later they will */ /* encounter the master environment variables, and they will also know the */ /* size of that block of memory, so they may safely make sane alterations. */ #include #include #include #include #define TRUE -1 #define FALSE 0 #define YES -1 #define NO 0 #define ST_MAX 252 char le_buf[0x8000]; /* Local Environment variable Buffer, I.E. work area */ struct envar { unsigned our, mast, size, evars, largest, mast_buf_size, links; }; /* struct envar: */ /* our = segment ptr to our environment variable memory */ /* mast = segment ptr to master environment variable memory */ /* size = number of bytes including double terminator found in */ /* our own environment variables */ /* evars = number of environment variables found in our own area */ /* largest = size of the largest environment variable */ /* mast_buf_size = num of bytes allocated to master environment buffer */ /* links = number of links away on the allocation chain our */ /* enviornment variable buffer is from master env buffer */ struct edit { unsigned eob, bob, evar_loc, strn_loc, next_loc, oper; char *name, *orig_st, *new_st; }; /* struct edit: */ /* eob = end of bubble */ /* bob = beginning of bubble */ /* evar_loc = offset to beginning of specified enviornment variable */ /* strn_loc = offset to beginning of specified substring */ /* next_loc = offset to first byte following specified substring */ /* oper = type of operation for edit to perform */ /* 0 = Rep, 1 = Left, 2 = Right, 3 = Zap, 4 = create */ /* 0 = Replace: overwrites substring */ /* 1 = inserts left of substring or variable data */ /* 2 = inserts right of substring or variable data */ /* 3 = Removes, I.E. erases whole system variable */ /* 4 = Creates, I.E. add new sys var on the end of vars */ /* name = environment variable name */ /* orig_st = substring to locate */ /* new_st = replacement substring */ char *prgm_name; main(argc, argv) int argc; char *argv[]; { /* Since get_envar() returns string pointers (the default is int) the */ /* compiler needs to be told about this unusual type of return, hence */ /* the following prototype is needed. */ char* get_envar(struct envar *ev); /* prototype */ char *error, td[100]; double secs; unsigned eob, bob; struct envar ev; struct edit ed; /* argc = 5; argv[1] = "/ZapSubString"; argv[2] = "path"; argv[3] = "j:\\onieda;"; argv[4] = "time"; */ prgm_name = "Environment Variable Utility"; error = get_envar(&ev); if (error != NULL) { printf("WARNING %s cannot proceed because of\n", prgm_name); printf("%s\n", error); return 255; /* Send an error signal to the DOS ERRORLEVEL */ } fill_local_buffer(&ev, le_buf); if (argc < 2) { usage(); return 0; } if (strcmpi(argv[1], "/debug") == 0) { printf("%s technical report.\n", prgm_name); technical(&ev); return 0; } if (strcmpi(argv[1], "/help") == 0) { printf("%s help system.\n", prgm_name); help(); return 0; } if (argc < 3) { usage(); return 0; } if ((argc == 3) && (strcmpi(argv[1], "/time") == 0)) { td_stamp(&td); ed.name = argv[2]; ed.orig_st = ""; ed.new_st = td; ed.oper = 4; return ee_finis(&ev, &ed, le_buf); } if ((argc == 3) && (stristr(argv[1], "/elapsed") == argv[1])) { error = since_sense(argv[1], argv[2]); if (*error <= 250) return error[0]; printf("%s", error + 1); return error[0]; } if (strcmpi(argv[1], "/test") == 0) { if ((argc == 3) || (argc == 4)) { ed.name = argv[2]; ed.orig_st = ""; ed.oper = 0; ed.new_st = ""; if (argc == 4) ed.orig_st = argv[3]; return test_evar(&ed, le_buf); } } if (strcmpi(argv[1], "/edit") == 0) { if ((argc == 4) || (argc == 5)) { ed.name = argv[2]; ed.orig_st = argv[3]; ed.oper = 0; ed.new_st = ""; if (argc == 5) ed.new_st = argv[4]; return ee_finis(&ev, &ed, le_buf); } } } /* Pass this funct a pointer to an empty 20 byte (char) buffer and it will */ /* fill it with the current system date and time */ td_stamp(td) char *td; { struct date db; struct time tb; getdate(&db); gettime(&tb); sprintf(td, "%.2d/%.2d/%.2d_%.2d:%.2d:%.2d", db.da_mon, db.da_day, db.da_year - 1900, tb.ti_hour, tb.ti_min, tb.ti_sec); } /* Pass this funct to (char) pointers, the first; cntrl, is a string */ /* containing "/elapsedmonths"... to ... "/elapsedseconds" The second is */ /* a string containing the name of a system variable, that is presumed to */ /* hold a td_stamp() style time and date stamp... since_sense() processes */ /* the elapsed time or date whatever and limits the result to a single byte */ /* code between 0 - 250 and returns the pointer to a null terminated string */ /* consisting of that one byte code and the terminator, if all went ok. If */ /* an error occurred that first byte will be an error code in the range of */ /* 251 - 255 followed by a printable string of bytes indicating the type of */ /* error encountered. */ since_sense(cntrl, varn) char *cntrl, *varn; { double sys_secs, var_secs, rtn; char rtn_str[3], *ctrl, *err, *var_dta; struct edit ed_lcl; int xx; since_bot(&sys_secs); xx = 0; while ((*(cntrl + xx) | 0x20) == *("/elapsed" + xx)) xx++; ctrl = cntrl + xx; ed_lcl.name = varn; err = "\xfcEnvironment variable not present"; if (locate_evnam(&ed_lcl, le_buf) == 0) return err; var_dta = le_buf + ed_lcl.evar_loc + strlen(ed_lcl.name) + 1; err = numerate_ts(&var_secs, var_dta); if (*err != 0x00) return err; rtn = sys_secs - var_secs; if (sys_secs < var_secs) rtn = 0; rtn_str[0] = 0; rtn_str[1] = 0; rtn_str[2] = 0; if (strcmpi(ctrl, "months") == 0) { rtn = rtn / 2635200.0; rtn_str[0] = 1; } if (strcmpi(ctrl, "weeks") == 0) { rtn = rtn / 604800.0; rtn_str[0] = 1; } if (strcmpi(ctrl, "days") == 0) { rtn = rtn / 86400.0; rtn_str[0] = 1; } if (strcmpi(ctrl, "hours") == 0) { rtn = rtn / 3600.0; rtn_str[0] = 1; } if (strcmpi(ctrl, "minutes") == 0) { rtn = rtn / 60.0; rtn_str[0] = 1; } if (strcmpi(ctrl, "seconds") == 0) { rtn_str[0] = 1; } if (rtn_str[0] == 0) return "\xfcappearent syntax error."; rtn = floor(rtn); if (rtn > 250) rtn = 250; rtn_str[0] = (char) rtn; return rtn_str; } /* since_bot() Since Beginning Of Time: You pass this funct a pointer to */ /* an as yet unused variable of type double, It uses the address to write */ /* back into your variable the number of seconds since the beginning of the */ /* gregorian calendar system */ since_bot(secs) double *secs; { char tsb[20]; td_stamp(&tsb); numerate_ts(secs, &tsb); } /* numerate_ts() Numerate Time String pass this funct two pointers to first */ /* an as yet unused variable of type double, It uses the address to write */ /* back into your variable the number of seconds from the beginning of time */ /* in the gregorian calendar system, to the time in the time string, */ /* presumed to be in mm/dd/yy_hh:mm:ss format. */ /* If all goes well I.E. no errors, a pointer to a null string is returned */ /* If an error occurred the first byte will be an error code in the range */ /* of 251 - 255 followed by a printable string of bytes indicating the type */ /* of error encountered. */ numerate_ts(secs, str) double *secs; char *str; { double fmod(); double julday(); double jdr; int nums[6], xx, nn; char *err; err = "\xfdTime string invalid must be mm/dd/yy_hh:mm:ss"; for (xx=0; xx < 6; xx++) { nn = *(str + (3 * xx)) - 0x30; if ((nn < 0) || (nn > 9)) return err; nums[xx] = nn * 10; nn = *(str + (3 * xx) + 1) - 0x30; if ((nn < 0) || (nn > 9)) return err; nums[xx] += nn; if (*(str + (3 * xx) + 2) != *("//_::" + xx)) return err; } err = "\xfdTime string invalid mm/dd/yy out of range"; if ((nums[0] < 1) || (nums[0] > 12)) return err; if ((nums[1] < 1) || (nums[1] > 31)) return err; if ((nums[2] < 0) || (nums[2] > 99)) return err; if (nums[2] >= 80) nums[2] += 1900; else nums[2] += 2000; jdr = julday(nums[0], nums[1], nums[2]); err = "\xfdTime string invalid hh:mm:ss out of range"; if ((nums[3] < 0) || (nums[3] > 24)) return err; if ((nums[4] < 0) || (nums[4] > 59)) return err; if ((nums[5] < 0) || (nums[5] > 59)) return err; *secs = (double)nums[5]+((double)nums[4]*60.0)+((double)nums[3]*3600.0); *secs += (jdr * 86400.0); return ""; } /* Warning comments for this funct are fuzzy */ double julday(mon,date,year) /* calculates julian date */ int mon,date,year; { double fmod(); double mo,da,yr,yv; /* yv = year vernier */ double w,x,y,z,fx,fy; /* intermidiate data holders */ mo = (double) mon; da = (double) date; yr = (double) year; yv = yr + ((mo - 2.85) / 12.0); /* Setup Year Vernier */ w = 367.0 * yv; /* W = Days of Year vernier */ x = w - fmod(w,1.0); /* Round to nearest whole number */ w = yv; /* Setup Year Vernier for rounding */ y = w - fmod(w,1.0); /* round to nearest whole */ z = y * 0.75; /* Attenuate for leap year */ w = x - y - z + da; /* Mix together and simmer slowly */ fx = w - fmod(w,1.0); /* round to nearest whole */ w = yv / 100.0; /* Grab hundreds of years */ fy = w - fmod(w,1.0); /* Round to nearest whole */ fy = fy * 0.75; /* Attenuate for leap century */ w = fx - fy; /* Glue in that result */ fx = w - fmod(w,1.0); /* round to nearest whole */ return fx; } ee_finis (ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { char *error; int rtn; char* edit_evar(); /* prototype type of return */ rtn = 0; error = edit_evar(ev, ed, vars); if (*error == *"") { write_local_buffer(ev, vars); } else { printf("%s\n", error + 1); rtn = *error; } return rtn; } /* struct envar: */ /* our = segment ptr to our environment variable memory */ /* mast = segment ptr to master environment variable memory */ /* size = number of bytes including double terminator found in */ /* our own environment variables */ /* evars = number of environment variables found in our own area */ /* largest = size of the largest environment variable */ /* mast_buf_size = num of bytes allocated to master environment buffer */ /* links = number of links away on the allocation chain our */ /* enviornment variable buffer is from master env buffer */ /* struct edit: */ /* eob = end of bubble */ /* bob = beginning of bubble */ /* evar_loc = offset to beginning of specified enviornment variable */ /* strn_loc = offset to beginning of specified substring */ /* next_loc = offset to first byte following specified substring */ /* oper = 0 = Replace, 1 = Left, 2 = Right, 3 = Zap, 4 = create */ /* name = environment variable name */ /* orig_st = substring to locate */ /* new_st = replacement substring */ /* Simply test for the presents or absents of a varaiable and an optional */ /* substring it may be carrying. Returns ERRORLEVEL signal value */ test_evar(ed, vars) struct edit *ed; char *vars; { unsigned rtn_stat; if (locate_evnam(ed, vars)) { if (strlen((*ed).orig_st)) { if (locate_substr(ed, vars) == FALSE) { return 251; } else return 0; } else return 0; } else return 251; } /* edit_evar() This function makes fairly high level decisions about how to */ /* edit an environment variable bassed on results from calls made to helper */ /* routines that carry out a miriad of duties. It assumes the grunt work */ /* of retrieving the master enviornment variable block into a local buffer */ /* has allready been performed. */ char* edit_evar(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { unsigned rtn_stat; char* modify_evar(); /* prototype type of retrun */ if (locate_evnam(ed, vars)) { if ((*ed).oper == 4) return "\xfcerror Variable already exists. See edit_evar()"; if (strlen((*ed).orig_st)) { if (locate_substr(ed, vars)) { if ((*ed).oper == 3) return "\xfcstrings have no meaning. See edit_evar()"; if (((*ed).oper >= 0) && ((*ed).oper <= 2)) { /* use new_st to modify substring */ return modify_evar(ev, ed, vars); } } } else /* if no orig string then this is an apend or Zap oper */ { if ((*ed).oper == 0) return "\xfcmatch string reqd. for modify. See edit_evar()"; if ((*ed).oper == 3) { if (strlen((*ed).new_st)) return "\xfcstring not valid with Zap. See edit_evar()"; return zap_evar(ev, ed, vars); } if ((*ed).oper == 1) { /* insert new_st at head of variable, I.E. 'left' of it */ } if ((*ed).oper == 2) { /* insert new_st at tail of variable, I.E. 'right' of it */ } return "\xfdInternal error. Bad logic in edit_evar()"; } } else { if (strlen((*ed).orig_st)) return "\xfcappearent syntax error. See edit_evar()"; if (strlen((*ed).new_st) == 0) return "\xfcappearent syntax error. See edit_evar()"; if ((*ed).oper == 0) return "\xfcerror nothing to overwrite. See edit_evar()"; if ((*ed).oper == 3) return "\xfcerror nothing to Zap!. See edit_evar()"; return create_evar(ev, ed, vars); } } /* This is a fairly high level helper routine for edit_evar() It handles */ /* inserting a substring into an environment variable according to the oper */ /* code, I.E. 0 = Replace, 1 = insert Left of, or 2 = insert to Right of. */ char* modify_evar(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { int new_len, orig_len; orig_len = strlen((*ed).orig_st); new_len = strlen((*ed).new_st); if (((*ed).oper == 0) && (((*ev).size + new_len - orig_len) >= (*ev).mast_buf_size)) return "\xfbOut of environment space"; if (((*ed).oper >= 1) && ((*ed).oper <= 2) && (((*ev).size + new_len) >= (*ev).mast_buf_size)) return "\xfbOut of environment space"; if ((*ed).oper > 2) return "\xfdInternal error. Bad arg in modify_evar"; /* this replaces orig_st with new_st, preserving the rest of the variable */ if ((*ed).oper == 0) { (*ed).eob = (*ed).next_loc; (*ed).bob = (*ed).next_loc; blow_bubble(ev, ed, vars); (char) *(vars + (*ed).strn_loc) = 0; /* place terminator */ strcat(vars + (*ed).evar_loc, (*ed).new_st); (*ed).bob = (*ed).strn_loc + strlen((*ed).new_st); pop_bubble(ev, ed, vars); zap_trash(ev, vars); return ""; } /* this inserts new_st at left of orig_st preserving the rest of variable */ if ((*ed).oper == 1) { (*ed).eob = (*ed).strn_loc; (*ed).bob = (*ed).strn_loc; blow_bubble(ev, ed, vars); (char) *(vars + (*ed).strn_loc) = 0; /* place terminator */ strcat(vars + (*ed).evar_loc, (*ed).new_st); (*ed).bob = (*ed).strn_loc + strlen((*ed).new_st); pop_bubble(ev, ed, vars); zap_trash(ev, vars); return ""; } /* this inserts new_st at right of orig_st preserving the rest of variable */ if ((*ed).oper == 2) { (*ed).eob = (*ed).next_loc; (*ed).bob = (*ed).next_loc; blow_bubble(ev, ed, vars); (char) *(vars + (*ed).strn_loc + orig_len) = 0; /* place terminator */ strcat(vars + (*ed).evar_loc, (*ed).new_st); (*ed).bob = orig_len + (*ed).strn_loc + strlen((*ed).new_st); pop_bubble(ev, ed, vars); zap_trash(ev, vars); return ""; } } zap_evar(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { (*ed).eob = (*ed).evar_loc + strlen(vars + (*ed).evar_loc); (*ed).bob = (*ed).evar_loc + strlen(vars + (*ed).evar_loc); blow_bubble(ev, ed, vars); (*ed).bob = (*ed).evar_loc - 1; pop_bubble(ev, ed, vars); zap_trash(ev, vars); } /* create_evar() Attempts to create an environment variable based on info */ /* in the two structs passed to it, if successfull it returns true, if */ /* there wasn't enough room if reports failure. */ create_evar(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { if (((*ev).mast_buf_size - (*ed).evar_loc) < (strlen((*ed).name) + strlen((*ed).new_st) + 3)) return "\xfbOut of environment space"; strupr((*ed).name); strcpy(vars + (*ed).evar_loc, (*ed).name); strcat(vars + (*ed).evar_loc, "="); strcat(vars + (*ed).evar_loc, (*ed).new_st); *(vars + (*ed).evar_loc + strlen(vars + (*ed).evar_loc) + 1) = 0; return ""; } /* locate_substr() attempts to locate a substring within an environment var */ /* returns true/flase to indicate sucess/failure */ locate_substr(ed, vars) struct edit *ed; char *vars; { unsigned tmp; (*ed).strn_loc = (*ed).evar_loc + strlen((*ed).name); (*ed).next_loc = (*ed).strn_loc; if (*(vars + (*ed).strn_loc) != '=') return FALSE; tmp = stristr(vars + (*ed).strn_loc, (*ed).orig_st); if (tmp != 0) { (*ed).strn_loc = tmp - (unsigned) vars; (*ed).next_loc = (*ed).strn_loc + strlen((*ed).orig_st); return TRUE; } return FALSE; } /* locate_evnam(ed, vars) attempts to locate a given environment var */ /* returns true/flase to indicate sucess/failure */ /* failure here means we searched to the end and found no match */ locate_evnam(ed, vars) struct edit *ed; char *vars; { unsigned name_len, tmp; (*ed).evar_loc = 0; name_len = strlen((*ed).name); while ((memicmp((*ed).name, vars + (*ed).evar_loc, name_len - 1) != 0) || (*(vars + (*ed).evar_loc + name_len) != '=')) { tmp = nextstr(vars, &(*ed).evar_loc); if (tmp == 0) return tmp; /* zero if this is a new name */ } return tmp; } /* nextstr() attempts to advance to the next environment var */ /* returns true/flase to indicate sucess/failure */ nextstr(base, off) char *base; unsigned *off; { int hst; hst = FALSE; while (*(base + (*off)) != 0) { hst = TRUE; (*off)++; } if (hst) (*off)++; return hst; } trash_trash(ev, vars) struct envar *ev; char *vars; { int xx; for (xx=(*ev).size; xx < (*ev).mast_buf_size; xx++) *(vars + xx) = 'T'; } zap_trash(ev, vars) struct envar *ev; char *vars; { int xx; for (xx=(*ev).size; xx < (*ev).mast_buf_size; xx++) *(vars + xx) = 0x00; } /* Blow Bubble is passed addr of struct "edit" to access eob End Of Bubble */ /* an offset into the buffer where we intend create an air bubble as we */ /* scoot the rest of the "live" data down to the end of the mast_buf_size */ /* buffer. We use mast_buf_size here even though our buffer is potentially */ /* much larger, it doesn't matter because we ultimately have to write it */ /* all back into the origonal place anyway, I.E. write_local_buffer() */ /* After we move data down, we write back into EOB so that EOB continues */ /* to point to the true End Of Bubble. This will later be used to restore */ /* the buffer to one contiguous piece of environment variable data. */ blow_bubble(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { int xx; memmove(vars + (*ev).mast_buf_size - ((*ev).size - (*ed).eob), vars + (*ed).eob, (*ev).size - (*ed).eob); (*ed).eob = (*ev).mast_buf_size - ((*ev).size - (*ed).eob); } /* Pop Bubble is passed addr of struct "edit" to access bob Beginning Of */ /* Bubble and eob End Of Bubble These two variables contain the offsets */ /* that define the walls of the air bubble that we intend to deflate by */ /* scooting the rest of the live data back to the end of the edited data. */ /* As before we use mast_buf_size even though our buffer is potentially */ /* much larger, it doesn't matter because we ultimately have to write it */ /* all back into the origonal place anyway using write_local_buffer() */ /* After we move the data down, we write back into EOB so that EOB now */ /* equals BOB, I.E. bubble size is zero. */ pop_bubble(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { int xx; memmove(vars + (*ed).bob, vars + (*ed).eob, (*ev).mast_buf_size - (*ed).eob); (*ev).size = (*ed).bob + ((*ev).mast_buf_size - (*ed).eob); (*ed).eob = (*ed).bob; } /* Note: the following 2 functions fill_local_buffer() write_local_buffer() */ /* perform no bounds checking, and rely on envar to be properly setup */ /* Since Environment variables can be as large as 0x8000 the receptical */ /* buffer must be aleast that large to accomodate the worst case scenario. */ /* This function is passed the addr of a structure contaning the envar info */ /* which it uses to retrieve the master environment variables and place */ /* them into a local buffer pointed to by an addr passed to us in vars */ fill_local_buffer(ev, vars) struct envar *ev; char *vars; { unsigned far *mstr_idx, *local_idx; mstr_idx = MK_FP((*ev).mast, 0); local_idx = MK_FP(getdseg(), vars); farmemcpy(local_idx, mstr_idx, (*ev).mast_buf_size); } /* This function is passed the addr of a structure contaning the envar info */ /* which it uses to write the local buffer pointed to by an addr passed to */ /* us in vars, into the master environment variables known to envar */ write_local_buffer(ev, vars) struct envar *ev; char *vars; { unsigned far *mstr_idx, *local_idx; mstr_idx = MK_FP((*ev).mast, 0); local_idx = MK_FP(getdseg(), vars); farmemcpy(mstr_idx, local_idx, (*ev).mast_buf_size); } /* This function is passed the addr of a structure contaning place holders */ /* of 7 unsigned integers that this function will write info back through. */ /* If successfull it returns zero, I.E. no errors, and fills in all the */ /* blanks in the envar struct, if unsuccessfull it returns a nonzero value */ /* the pointer to an error message string and the information if any in the */ /* envar struct is unreliable and should be ignored. */ char* get_envar(ev) struct envar *ev; { unsigned loop_cnt, arena_ut, arena_tmp; envar_blk_size(ev); if ((*ev).largest > ST_MAX) { return "unexpectedly large envionment variable"; } arena_ut = fma(); while ((envar_cmpar((*ev).our, (arena_ut + 1), (*ev).size) != 0) && arena_ut < 0xa000) { nma(&arena_ut); } arena_tmp = arena_ut; (*ev).mast_buf_size = nma(&arena_tmp) * 16; /* use nma to compute size */ (*ev).mast = arena_ut + 1; if ((arena_ut + 1) == (*ev).our) { return "unable to locate master envionment variables"; } loop_cnt = 0; while (((*ev).our != (arena_ut + 1)) && (arena_ut < 0xff00) && (loop_cnt < 0x4000)) { nma(&arena_ut); loop_cnt++; } if (((*ev).our != (arena_ut + 1)) || (arena_ut >= 0xff00) || (loop_cnt >= 0x4000)) { return "unreasonable or damaged memory arena chain"; } (*ev).links = loop_cnt; return NULL; } /* returns the First Memory Arena header segment value */ fma() { unsigned far *mah; long mal; union REGS inregs, outregs; struct SREGS segregs; inregs.x.ax = 0x5200; intdosx(&inregs, &outregs, &segregs); mah = MK_FP(segregs.es, outregs.x.bx); mal = fartol(mah); mal -= 2L; mah = ltofar(mal); return *mah; } /* Next Memory Arena: This function is passed the addr of an unsigned */ /* integer, that holds the segment value of the current memory arena */ /* header. This function calculates the segment value of the next one */ /* in the chain, and writes that value back through that address passed */ /* to this function. It returns the size of the associated data block */ nma(prev) unsigned *prev; { unsigned far *mah_idx, *local_idx; char mah[16]; mah_idx = MK_FP(*prev, 0); local_idx = MK_FP(getdseg(), &mah); farmemcpy(local_idx, mah_idx,16); *prev += ((mah[0x03] + (0x100 * mah[0x04])) + 1); return mah[0x03] + (0x100 * mah[0x04]); } /* This function is passed the addr of a structure contaning place holders */ /* of 4 unsigned integers that this function will write info back through. */ /* It scans the environment variables of this child process, to measure the */ /* total length of those environment vars currently set, and writes back to */ /* the function that called it, through the addresses of variables passed to*/ /* it the segment prefix, of those aformentioned environment variables their*/ /* total size in bytes, how many of them, and the size of the largest one */ envar_blk_size(ev) struct envar *ev; { char psp[256]; unsigned next; unsigned far *own; cpypsps(&psp, 0); (*ev).our = psp[0x2c] + (0x100 * psp[0x2d]); own = MK_FP((*ev).our, 0); (*ev).size = 0; next = 0; (*ev).evars = 0; (*ev).largest = 0; do { (*ev).size += next; own = MK_FP((*ev).our, (*ev).size); next = 1 + farstrlen(own); (*ev).evars += 1; if ((*ev).largest < (next - 1)) (*ev).largest = next - 1; } while (next != 1); (*ev).size++; /* allow for end of string block terminator */ } /* Environment Variable Comparison, returns true / flase */ envar_cmpar(owner, master, size) unsigned owner, master, size; { unsigned far *own, far *mst; own = MK_FP(owner, 0); mst = MK_FP(master, 0); return farmemcmp(own, mst, size); } /* Copy PSPS: Call this function and pass it the address of an array whose */ /* size is at least 256 bytes long, and a control/non-zero value integer that*/ /* determines whither the function copies the PSP (the zero case) or a */ /* previous PSP farther up the chain. The function will either copy the PSP */ /* into into the array or if the operating system is too old fill it with */ /* zeros. This function RETURNS nothing. An example follows. */ /* char psparray[256]; */ /* main() */ /* { cpypsps(&psparray,cntrl); } */ cpypsps(psp,cntrl) char *psp; int cntrl; { unsigned long int lpsp; char far *fpsp, far *npsp; int xx; if (_osmajor >= 3) { if (cntrl == 0) { lpsp = ((unsigned long int) getpsp()) * 16; }else { lpsp = ((unsigned long int) cntrl) * 16; } fpsp = ltofar(lpsp); lpsp = (((unsigned long int) getdseg()) * 16) + ((unsigned long int) psp); npsp = ltofar(lpsp); farmemcpy(npsp,fpsp,256); } else for(xx = 0; xx < 0x100; xx++) *(psp + xx) = 0; } /* The following will print a technical report for debugging batch files */ technical(ev) struct envar *ev; { printf("There are %d environment variables in %d bytes \n", (*ev).evars, (*ev).size); printf("The largest of which is %d bytes long.\n", (*ev).largest); printf("Ours were %d memory allocations away from DOSs \n", (*ev).links); printf("DOSs = %4X Ours = %4X \n", (*ev).mast, (*ev).our); printf("DOSs enviornment buffer size is = %d bytes \n", (*ev).mast_buf_size); } /* - - - - - - - - - - W A R N I N G ! ! ! while optimizes out the call to nextstr() and thus produces an endless loop locate_evnam(ev, ed, vars) struct envar *ev; struct edit *ed; char *vars; { unsigned name_len, off, tmp; off = 0; name_len = strlen((*ed).name); while ((memicmp((*ed).name, vars + off, name_len - 1) != 0) || (*(vars + off + name_len) != '=') && (tmp = nextstr(vars, &off))) ; return tmp; } - - - - - - - - - - */ /* The following is ALL trash it was in main() locate_evnam(&ed, le_buf); locate_substr(&ed, le_buf); trash_trash(&ev, le_buf); blow_bubble(&ev, &ed, le_buf); pop_bubble(&ev, &ed, le_buf); zap_trash(&ev, le_buf); technical(&ev); write_local_buffer(&ev, le_buf); return ST_MAX; */ usage() { clrscrn(); printf("Copyright Jim Phillips 1997 I disclaim everything, this is not\n"); printf("an official release of this program, use at your own risk!\n\n"); printf("USAGE: EVU version (negative zero) very beta!\n\n\n"); printf("Environment Variable Utility\n\n"); help_screen(0); } help() { int page, ch, rtn; page = 1; ch = '+'; while ((ch == '-') || (ch == '+')) { clrscrn(); rtn = help_screen(page); printf("page %d. Press (+) or (-) to view ", page); printf("next or previous page, any other key exits"); ch = getch(); if ((ch == '-') && (page > 0)) page--; if (ch == '+') page++; if ((rtn == -1) && (page > 0)) page--; } } help_screen(req_pg) int req_pg; { char *ptr; int xx, line, page; page = 0; line = 0; while (page < req_pg) { ptr = hlp_list(line); while (*ptr != 0) {line++; ptr=hlp_list(line);} line++; ptr = hlp_list(line); if (*ptr == 0) return -1; page++; } ptr = hlp_list(line); while (*ptr != 0) {printf("%s\n",ptr); line++; ptr=hlp_list(line);} return 0; } hlp_list(line) unsigned line; { char *data[] = { "evu /command var_name orig_data replacement_data", " oper1 oper2 oper3 oper4\n", "COMMANDS:\n", "usage screen: no opers", "/help 1 oper", "/debug 1 oper", "/edit 3 or 4 opers", "/test 2 or 3 opers", "/time 2 opers", "/elapsedmonths weeks days hours minutes are all 2 opers", "elapsed commands do not alter environment variables, instead they", "return an ERRORLEVEL signal 0 - 250 if all is well. If an error", "occurrs 251 to 255 indicate severity of error.", "", "evu /command var_name orig_data replacement_data", " oper1 oper2 oper3 oper4\n", "COMMANDS:\n", "usage screen: no opers", "/debug: 1 oper", "/edit: 3 or 4 opers", "/test: 2 or 3 opers", "/time: 2 opers", "/elapsedmonths 2 opers", "/elapsedweeks 2 opers", "/elapseddays 2 opers", "/elapsedhours 2 opers", "/elapsedminutes 2 opers", "2 opers", "elapsed commands do not alter environment variables, instead they", "return an ERRORLEVEL signal 0 - 250 if all is well. If an error", "occurrs 251 to 255 indicate severity of error.", "", "The /debug command produces a technical report about the enviornment variables", "Example: evu /debug", " It is used to identify sources of trouble, one of the most common problems", " is not placing a SHELL=COMMAND.COM /E:xxxx line in your config sys file, or", " having /E:xxxx set to too small of a value, it can be as large as 32K see", " your DOS manual for more info on this subject.", " Another source of trouble is the potential of misidentifying the 'true'", " environment variable set that is currently active during a system shell.", " This problem can be minimized by setting a 'dummy' variable to make the", " current set of environment variables unique, and thus identifiable.", " Such a use of environment space is automatically recovered when you exit", " the shell, note: to preserve your large environment space don't forget", " the /E:xxxx and never use /P in a secondary shell or you won't be able to", " exit!", " ", " ", "", "The /edit command allows you to search and destroy or search and replace.", "Example: evu /edit path c:\\word3; d:\\w-procs\\word4;", " The above example would remove substring c:\\word3; from the enviornment", " variable path and replace it with d:\\w-procs\\word4;", " Have you ever wanted to put a directory to be searched in the middle of the", " of the path, without disturbing the rest of the path string. Suppose you", " know that the c:\\batch directory is in the middle and you want to place", " the Norton directory just before it, here's how ya do it", " evu /edit path c:\\batch; c:\\norton;c:\\batch;", " then afterward you want to remove the Norton directory form the path, you", " evu /edit path c:\\norton;", " Notice the last argument is missing... I call this use of /edit search ", " and destroy.", " ", " ", "", "The /test command allows batch files to test for the existance of a specific", "environment variable and or an expected substring it might contain. ", "Example: evu /test path c:\\batch;", " No environment variables are modified here, but the path is tested for", " the presents of a substring c:\\batch; if it is found the ERRORLEVEL is ", " set to zero, if it is not found the ERRORLEVEL is set to 251.", " The substring is optional", " evu /test path ", " Would simply check for the presents of the path reguardless what it's", " contents was.", " ", " ", "", "The /time command creates a new environment variable that is set to the", "current system date and time in the following format mm/dd/yy_hh:mm:ss", "Example: evu /time appstart", " If after you executed the above example you did a 'set' command at the ", " DOS prompt you would see a variable named APPSTART=12/05/96_23:41:00", " With a date and time stamp on it something like that shown above.", " By itself it can be used in conjunction with 'echo' redirected to a file", " To provide an historical record of processes started ended etc. I.E.", "Example: echo %appstart% starting tape backup>>c:\\logfiles\\back.log", " However there are some other uses for it, see /elapsed time commands", " ", " ", "", "The series of commands /elapsedmonths through /elapsedseconds rely on an", "environment variable being formatted in the exact format shown in the /time", "command. These series of commands do not alter the environment but instead ", "return an ERRORLEVEL to DOS for the benifit of batch files to analyze.", "The ERRORLEVEL signal returned by this command if not signalling a real error", "will be between zero and 250, the remaining five codes are for signalling ", "real errors 251 is the mildest error, 255 the most serious", "Example: evu /elapsedminutes appstart", " The above example would return a signal of how many minutes have elapsed", " since the /time command created it. If the properly formatted time stamp", " is actually set to a time in the future, I.E. ahead of the system clock", " zero is returned. If it was to to a time a week ago the highest value", " returned is never more than 250 so if you detect 250 you should re-test", " using one of the other /elapsed commands in the series, they are...", " /elapsedmonths ", " /elapsedweeks ", " /elapseddays ", " /elapsedhours ", " /elapsedminutes ", " /elapsedseconds ", " ", " ", "", "", "", "HELP SYSTEM FAILURE!", "", ""}; return data[line]; }