[net.micro.pc] Program Segment Prefix address

phil@kcl-cs.UUCP (Phil Thompson) (08/08/85)

<>

Is there any way that I can find out the address of the PSP from within
a C program using the DeSmet compiler? The initialisation code throws away
the segment registers. (I'm actually trying to write getenv() so if
somebody has already done it.....)

Thanks,
Phil Thompson

bet@ecsvax.UUCP (Bennett E. Todd III) (08/12/85)

In article <192@westo.kcl-cs.UUCP> phil@kcl-cs.UUCP (Phil Thompson) writes:
>Is there any way that I can find out the address of the PSP from within
>a C program using the DeSmet compiler? The initialization code throws away
>the segment registers. (I'm actually trying to write getenv() so if
>somebody has already done it.....)
DeSmet's startup leaves the CS where it starts up -- right after the
PSP. The PSP is 100H bytes long, so subtract 10H from the CS and you
have the offset of the PSP. It works; I've used it.
Here follows getenv.c; those of you not using DeSmet will need to find
some way to get the segment address of the PSP (I used DeSmet's builtin
_showcs() which returns the value of CS, and subtracted 0x10) and write
_peek(), whose definition should be obvious.
------------- start of getenv.c -----------------
#include <stdio.h>

char *getenv(name)
char *name;
{
	char *found, *malloc();
	char *offset, *tmp, _peek(), toupper();
	int i;
	unsigned segment, _showcs();

	/* PSP is at CS-10H */
	segment = _showcs() - 0x10;

	/*
	** The environment is stored starting at a segment whose segment address
	** can be found 2Ch into the PSP -- a word address...
	*/
	segment = _peek(0x2c, segment) + 256*_peek(0x2d, segment);

	/* Look for the string NAME= in the environment */
	for (offset=NULL; _peek(offset, segment) != NULL; offset++) {
		i = 0; /* i scans through name */
		while (name[i] != NULL &&
			   toupper(_peek(offset, segment)) == toupper(name[i])) {
			i++;
			offset++;
		}
		if (name[i] == NULL && _peek(offset, segment) == '=') {
			/* then we found it -- get it and return it */
			tmp = ++offset;
			while (_peek(tmp, segment) != NULL)
				tmp++;
			found = malloc(1 + tmp-offset);
			if (found == NULL) {
				fprintf(stderr, "getenv: malloc failed. Bye....\n");
				exit(1);
			}
			tmp = found;
			while ((*tmp++ = _peek(offset++, segment)) !=NULL)
				/* NULL BODY */;
			return(found);
		}
		/* We didn't found it -- clean up and try next entry */
		while (_peek(offset, segment) != NULL)
			offset++;
	}
	/* Ain't no sech beastie. Sorry, boss... */
	return((char *) NULL);
}
---------------- end of getenv.c ------------
Note: the code is indented with tabstops every 4 columns.

This routine is obviously nonportable. That's life in the
rewriting-system-calls business. It isn't pretty. Sorry, I never wrote
this for public consumption, just so I could understand it. Here is a
Q&D driver I used to exercise it -- printenv. Usage is like

	A>printenv comspec
	comspec=A:\COMMAND.COM

It's even uglier than getenv. I didn't even care if *I* could understand
it! (throwaway test drivers, and like that).
------------- start of printenv.c ----------------
#include <stdio.h>
extern char *getenv();
main(argc, argv)
int argc;
char **argv;
{
	for (argc--, argv++; argc; argc--, argv++)
		printf("%s=%s\n", *argv, getenv(*argv));
}
---------------- end of printenv.c -----------------
Hope this helps someone, somewhere. I would be delighted to hear any bug
reports (I use this occasionally myself) but I might not do anything
about them.

-Bennett
-- 

"Some people are lucky; the rest of us have to work at it."

Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695
 ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!bet or dbtodd@tucc.BITNET

broehl@watdcsu.UUCP (Bernie Roehl) (08/13/85)

No problem.

The program segment prefix is at _showcs() - 0x10 (since the CS register is
offset by 100 hex from the PSP).  I used this in writing a getenv(); I'd post
it if I had it handy... may yet do it, if I get a chance.