[comp.sys.ibm.pc] "Documented" MS-DOS stuff

madd@bucsb.bu.edu.UUCP (Jim "Jack" Frost) (08/02/87)

In article <1013@vi.ri.cmu.edu> jfb@vi.ri.cmu.edu (John Brennen) writes:
>In article <1690@bellcore.bellcore.com>, tr@wind.bellcore.com (tom reingold) writes:
>> 
>> I just discovered an undocumented feature of the more recent
>> versions of DOS: it is at last possible to obtain argv[0].
>> 
>
>The method described is documented, quite clearly, in the PC-DOS 3.0 (3.1?)
>manual.  Maybe your documentation is missing it...  I can't even guess.
>
>Supposedly, this was considered a problem in DOS 2.0.  Personally, I've never
>had a real desire to know what argv[0] is.  MS-DOS doesn't support links
>(hard or symbolic), so each file has a unique name.  But I can see where
>you might want to be really friendly or something, and parse argv[0].

This is true, it is documented in the section discussing the Program
Segment Prefix in the PC-DOS Technical Reference Guide, at least for
versions 3.10 and up.

Anyone want to discuss other "documented" things?  I have a new
favorite "documented" thing that I found recently.

I am creating a program called "psh" (a csh workalike, generally)
that, by its very nature, must use the DOS Exec function.  In the
documentation for the Exec function, it clearly tells you how to give
the Exec function its parameter block, which includes a pointer to an
argument line.

Now, it never tells you about the parameter line, except that it
should be a string with a byte telling the length of the string in the
first position.  It does, however, tell you about it in the section on
the Program Segment Prefix.  The most interesting thing about this is
that the command line MUST BE IN A PARTICULAR FORMAT.  This is not
documented even once in the text, but instead in an oblique reference
in the map of the PSP.

The format REQUIRED by almost every MS-DOS utility is to have a space
preceeding every parameter in the line.  Even the first one.  The map
of the PSP tells you this as follows:

"parameter string with spaces preceeding each parameter"

or something very similar to this.  If you forget that space,
*nothing* works.  EDLIN won't.  CHKDSK will, but improperly (it won't
pick up the drive specifier).  Regular programs run fine, though,
since I presume whoever wrote them didn't make their code dependent on
that space (since it really isn't well documented).  I found it by
tracing the passing of everything to programs by both my program and
COMMAND.COM until I found a difference.

In addition, there is at least one mistake that is clearly documented
in the section dealing with invoking a command processor from a
program.  My manuals say that when invoking the command processor, you
should pass it the argument string FOLLOWED BY A CARRIAGE RETURN.
This will work, but is not DOS-standard.  There is no mention of the
leading space in this section, either, or even in the example
assembler code that they give you.  Note that COMMAND.COM does not
require the leading space, but it is about the only supplied program I
found that does not.

Another interesting note:

FORMAT will not work even with the space problem fixed.  Does anyone know
what they did when they made FORMAT?  I'd be very, very interested in
knowing.  I pass each program a perfect match for the command line and
also a good FCB if possible.  My FCB building routines fail in some
circumstances, but so do DOS's (although in a different manner) so I
don't worry about it.  It gets a perfect environment, too.  Yet it
gives me an "invalid parameter" error whenever I try to run FORMAT.
Tracing the COMMAND.COM parameters showed absolutely *no* differences
between my parameters and those passed by COMMAND.COM, yet FORMAT
works with COMMAND.COM and not with my program.  I suspect more
Microsoft assumptions on who is calling the program.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          Jim Frost * The Madd Hacker | UUCP: ..!harvard!bu-cs!bucsb!madd
  H H                                 | ARPA:           madd@bucsb.bu.edu
H-C-C-OH <- heehee          +---------+----------------------------------
  H H                       | "We are strangers in a world we never made"

ayac071@ut-ngp.UUCP (William T. Douglass) (08/04/87)

>FORMAT will not work even with the space problem fixed.  Does anyone know
>what they did when they made FORMAT?  I'd be very, very interested in
>knowing.  I pass each program a perfect match for the command line and
>also a good FCB if possible.  My FCB building routines fail in some
>circumstances, but so do DOS's (although in a different manner) so I
>don't worry about it.  It gets a perfect environment, too.  Yet it
>gives me an "invalid parameter" error whenever I try to run FORMAT.


I would suspect the FCB's.  My working with EXEC and format indicated
that the FORMAT command does indeed pull its parameters from the FCB
that DOS sets up before executing the program.  If there is a bug in
your FCB routine, that could kill the program right there.

I set up my call to EXEC to parse the FCB with the relevent DOS call
(don't have the function # right now), but will be glad to e-mail the
whole program to you if interested.

Bill Douglass
ayac071@ngp.UUCP

steve@gtuplab.UUCP (Steve Duncan) (08/04/87)

/ gtuplab:comp.sys.ibm.pc / madd@bucsb.bu.edu.UUCP (Jim "Jack" Frost) /  8:54 pm  Aug  1, 1987 /
In article <151@ivory.SanDiego.NCR.COM> mike@ivory.UUCP (Michael Lodman) writes:
>Could someone please email and tell me how to read the DOS environment
>variables with Turbo Pascal?
>
>Thanks.

This is easy.  Note that MS-DOS gives you a pointer to the environment
variable list at memw[cseg:$2C].  This simple program will print out
the environment; I suspect that anyone with a little knowledge can
expand it to a complete getenv() style function in just a few minutes.

[note -- I am just making this up now.  no flames if I screw it up a
little]

program printenv;
var eseg,           { segment of environment }
    p    : integer; { pointer within segment }
begin
  eseg:= memw[cseg:$2C];           { get pointer to env segment }
  p:= 0;                           { initialize pointer within segment }
  repeat                           { loop for all environment entries }
    while mem[eseg:p]<>0 do begin  { loop for chars in each entry }
      write(chr(mem[eseg:p]));     { display character in entry }
      p:= p+1                      { go to next character in entry }
    end;                           { end environment enty loop }
    writeln;                       { next line for next entry }
    p:= p+1                        { go to next environment entry }
  until mem[eseg:p]=0              { environment ends in a null byte }
end.

For those of you who don't know, MS-DOS defines the environment as a
series of null-terminated strings that ends in a null.  This means
that each entry in the environment ends in a null (chr(0), #0,
whatever), and the last entry has another null following the null of
the last string.  Pretty easy to program with that info and the
address of the segment!

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
          Jim Frost * The Madd Hacker | UUCP: ..!harvard!bu-cs!bucsb!madd
  H H                                 | ARPA:           madd@bucsb.bu.edu
H-C-C-OH <- heehee          +---------+----------------------------------
  H H                       | "We are strangers in a world we never made"
----------
)	conditional execution
	!else
	!endif
	!return		Return (terminating current macro)
	!goto <label>	Jump to a label in the current macro

	Line Labels begin with a "*" in column 1, like:

	*LBL01
*/

docmd(cline)

char *cline;	/* command line to execute */

{
	register int f;		/* default argument flag */
	register int n;		/* numeric repeat value */
	register int i;
	int (*fnc)();		/* function to execute */
	int status;		/* return status of function */
	int oldcle;		/* old contents of clexec flag */
	int llen;		/* length of cline */
	int force;		/* force TRUE result? */
	char *tmp;		/* tmp pointer into cline */
	struct LINE *lp;	/* a line pointer */
	char *oldestr;		/* original exec string */
	char token[NSTRING];	/* next token off of command line */
	int (*fncmatch())();
#if	DEBUGM
	/* if $debug == TRUE, every line to execute
	   gets echoed and a key needs to be pressed to continue
	   ^G will abort the command */
	register char *sp;	/* pointer into buf to expand %s */

	if (macbug) {
		strcpy(outline, "<<<");
#if	1	/* debug if levels */
		strcat(outline, itoa(execlevel));
		strcat(outline, ":");
#endif
		strcat(outline, cline);
		strcat(outline, ">>>");

		/* change all '%' to ':' so mlwrite won't expect arguments */
		sp = outline;
		while (*sp) {
			if (*sp++ == '%')
				*(sp-1) = ':';
		}

		/* write out the debug line */
		mlforce(outline);
		update(TRUE);

		/* and get the keystroke */
		if (tgetc() == 7) {
			mlwrite("[Macro aborted]");
			return(FALSE);
		}
	}
#endif
		
	/* dump comments here */
	if (*cline == ';')
		return(TRUE);

	/* eat leading spaces */
	while (*cline == ' ' || *cline == '\t')
		++cline;

	/* check to see if this line turns macro storage off */
	if (cline[0] == '!' && strncmp(&cline[1], "endm", 4) == 0) {
		mstore = FALSE;
		bstore = NULL;
		return(TRUE);
	}

	/* if macro store is on, just salt this away */
	if (mstore) {
		/* allocate the space for the line */
		llen = strlen(cline);
		if ((lp=lalloc(llen)) == NULL) {
			mlwrite("Out of memory while storing macro");
			return (FALSE);
		}

		/* copy the text into the new line */
		for (i=0; i<llen; ++i)
			lputc(lp, i, cline[i]);

		/* attach the line to the end of the buffer */
       		bstore->b_linep->l_bp->l_fp = lp;
		lp->l_bp = bstore->b_linep->l_bp;
		bstore->b_linep->l_bp = lp;
		lp->l_fp = bstore->b_linep;
		return (TRUE);
	}
	
	/* dump labels here */
	if (*cline == '*')
		return(TRUE);

	force = FALSE;
	oldestr = execstr;	/* save last ptr to string to execute */
	execstr = cline;	/* and set this one as current */

	/* process directives */
	if (*cline == '!') {
		/* save directive location and skip it */
		tmp = cline;
		while (*execstr && *execstr != ' ' && *execstr != '\t')
			++execstr;

		if (tmp[1] == 'f' && tmp[2] == 'o') {
			force = TRUE;
			goto do001;

		} else if (tmp[1] == 'i' && tmp[2] == 'f') {

			/* IF directive */
			/* grab the value of the logical exp */
			if (execlevel == 0) {
				if ((status = macarg(token)) != TRUE) {
					execstr = oldestr;
					return(status);
				}
				status = stol(token);
			} else
				status = TRUE;

			if (status) {

				/* IF (TRUE) */
				if (execlevel != 0)
					++execlevel;
			} else {

				/* IF (FALSE) */
				++execlevel;
			}

		} else if (tmp[1] == 'e' && tmp[2] == 'l') {

			/* ELSE directive */
			if (execlevel == 1)
				--execlevel;
			else if (execlevel == 0 )
				++execlevel;

		} else if (tmp[1] == 'e' && tmp[2] == 'n') {

			/* ENDIF directive */
			if (execlevel)
				--execlevel;

		} else if (tmp[1] == 'r' && tmp[2] == 'e') {

			/* RETURN directive */
			execstr = oldestr;
			if (execlevel)
				return(TRUE);
			else
				return(RET);

		} else if (tmp[1] == 'g' && tmp[2] == 'o') {

			/* GOTO directive */
			/* .....only if we are currently executing */
			if (execlevel) {
				execstr = oldestr;
				return(TRUE);
			}

			while (*execstr == ' ' || *execstr == '\t')
				++execstr;
			strncpy(golabel, execstr, NPAT - 1);
			return(GOLINE);

		} else {
			mlwrite("%%Unknown Directive");
			return(FALSE);
		}

		/* restore execstr and exit */
		execstr = oldestr;
		return(TRUE);
	}

do001:	/* if we are scanning and not executing..go back here */
	if (execlevel) {
		execstr = oldestr;
		return(TRUE);
	}

	/* first set up the default command values */
	f = FALSE;
	n = 1;
	lastflag = thisflag;
	thisflag = 0;

	if ((status = macarg(token)) != TRUE) {	/* and grab the first token */
		execstr = oldestr;
		return(status);
	}

	/* process leadin argument */
	if (gettyp(token) != TKCMD) {
		f = TRUE;
		strcpy(token, getval(token));
		n = atoi(token);

		/* and now get the command to execute */
		if ((status = macarg(token)) != TRUE) {
			execstr = oldestr;
			return(status);	
		}	
	}

	/* and match the token to see if it exists */
	if ((fnc = fncmatch(token)) == NULL) {
		mlwrite("[No such Function]");
		execstr = oldestr;
		return(FALSE);
	}
	
	/* save the arguments and go execute the command */
	oldcle = clexec;		/* save old clexec flag */
	clexec = TRUE;			/* in cline execution */
	status = (*fnc)(f, n);		/* call the function */
	cmdstatus = status;		/* save the status */
	if (force)			/* force the status */
		status = TRUE;
	clexec = oldcle;		/* restore clexec flag */
	execstr = oldestr;
	return(status);
}

/* token:	chop a token off a string
		return a pointer past the token
*/

char *token(src, tok)

char *src, *tok;	/* source string, destination token string */

{
	register int quotef;	/* is the current string quoted? */

	/* first scan past any whitespace in the source string */
	while (*src == ' ' || *src == '\t')
		++src;

	/* scan through the source string */
	quotef = FALSE;
	while (*src) {
		/* process special characters */
		if (*src == '~') {
			++src;
			if (*src == 0)
				break;
			switch (*src++) {
				case 'r':	*tok++ = 13; break;
				case 'n':	*tok++ = 10; break;
				case 't':	*tok++ = 9;  break;
				case 'b':	*tok++ = 8;  break;
				case 'f':	*tok++ = 12; break;
				default:	*tok++ = *(src-1);
			}
		} else {
			/* check for the end of the token */
			if (quotef) {
				if (*src == '"')
					break;
			} else {
				if (*src == ' ' || *src == '\t')
					break;
			}

			/* set quote mode if qoute found */
			if (*src == '"')
				quotef = TRUE;

			/* record the character */
			*tok++ = *src++;
		}
	}

	/* terminate the token and exit */
	if (*src)
		++src;
	*tok = 0;
	return(src);
}

macarg(tok)	/* get a macro line argument */

char *tok;	/* buffer to place argument */

{
	int savcle;	/* buffer to store original clexec */
	int status;

	savcle = clexec;	/* save execution mode */
	clexec = TRUE;		/* get the argument */
	status = nextarg("", tok, NSTRING, ctoec('\n'));
	clexec = savcle;	/* restore execution mode */
	return(status);
}

/*	nextarg:	get the next argument	*/

nextarg(prompt, buffer, size, terminator)

char *prompt;		/* prompt to use if we must be interactive */
char *buffer;		/* buffer to put token into */
char *size;		/* size of the buffer */
int terminator;		/* terminating char to be used on interactive fetch */

{
	/* if we are interactive, go get it! */
	if (clexec == FALSE)
		return(getstring(prompt, buffer, size, terminator));

	/* grab token and advance past */
	execstr = token(execstr, buffer);

	/* evaluate it */
	strcpy(buffer, getval(buffer));
	return(TRUE);
}

/*	storemac:	Set up a macro buffer and flag to store all
			executed command lines there			*/

storemac(f, n)

int f;		/* default flag */
int n;		/* macro number to use */

{
	register struct BUFFER *bp;	/* pointer to macro buffer */
	char bname[NBUFN];		/* name of buffer to use */

	/* must have a numeric argument to this function */
	if (f == FALSE) {
		mlwrite("No macro specified");
		return(FALSE);
	}

	/* range check the macro number */
	if (n < 1 || n > 40) {
		mlwrite("Macro number out of range");
		return(FALSE);
	}

	/* construct the macro buffer name */
	strcpy(bname, "[Macro xx]");
	bname[7] = '0' + (n / 10);
	bname[8] = '0' + (n % 10);

	/* set up the new macro buffer */
	if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
		mlwrite("Can not create macro");
		return(FALSE);
	}

	/* and make sure it is empty */
	bclear(bp);

	/* and set the macro store pointers to it */
	mstore = TRUE;
	bstore = bp;
	return(TRUE);
}

#if	PROC
/*	storeproc:	Set up a procedure buffer and flag to store all
			executed command lines there			*/

storeproc(f, n)

int f;		/* default flag */
int n;		/* macro number to use */

{
	register struct BUFFER *bp;	/* pointer to macro buffer */
	register int status;		/* return status */
	char bname[NBUFN];		/* name of buffer to use */

	/* a numeric argument means its a numbered macro */
	if (f == TRUE)
		return(storemac(f, n));

	/* get the name of the procedure */
        if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
                return(status);

	/* construct the macro buffer name */
	bname[0] = '[';
	strcat(bname, "]");

	/* set up the new macro buffer */
	if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
		mlwrite("Can not create macro");
		return(FALSE);
	}

	/* and make sure it is empty */
	bclear(bp);

	/* and set the macro store pointers to it */
	mstore = TRUE;
	bstore = bp;
	return(TRUE);
}

/*	execproc:	Execute a procedure				*/

execproc(f, n)

int f, n;	/* default flag and numeric arg */

{
        register BUFFER *bp;		/* ptr to buffer to execute */
        register int status;		/* status return */
        char bufn[NBUFN+2];		/* name of buffer to execute */

	/* find out what buffer the user wants to execute */
        if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
                return(status);

	/* construct the buffer name */
	bufn[0] = '[';
	strcat(bufn, "]");

	/* find the pointer to that buffer */
        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
		mlwrite("No such procedure");
                return(FALSE);
        }

	/* and now execute it as asked */
	while (n-- > 0)
		if ((status = dobuf(bp)) != TRUE)
			return(status);
	return(TRUE);
}
#endif

/*	execbuf:	Execute the contents of a buffer of commands	*/

execbuf(f, n)

int f, n;	/* default flag and numeric arg */

{
        register BUFFER *bp;		/* ptr to buffer to execute */
        register int status;		/* status return */
        char bufn[NBUFN];		/* name of buffer to execute */

	/* find out what buffer the user wants to execute */
        if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
                return(status);

	/* find the pointer to that buffer */
        if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
		mlwrite("No such buffer");
                return(FALSE);
        }

	/* and now execute it as asked */
	while (n-- > 0)
		if ((status = dobuf(bp)) != TRUE)
			return(status);
	return(TRUE);
}

/*	dobuf:	execute the contents of the buffer pointed to
		by the passed BP				*/

dobuf(bp)

BUFFER *bp;	/* buffer to execute */

{
        register int status;		/* status return */
	register LINE *lp;		/* pointer to line to execute */
	register LINE *hlp;		/* pointer to line header */
	register LINE *glp;		/* line to goto */
	register int linlen;		/* length of line to execute */
	register WINDOW *wp;		/* ptr to windows to scan */
	char *eline;			/* text of line to execute */

	/* clear IF level flags */
	execlevel = 0;

	/* starting at the beginning of the buffer */
	hlp = bp->b_linep;
	lp = hlp->l_fp;
	while (lp != hlp) {
		/* allocate eline and copy macro line to it */
		linlen = lp->l_used;
		if ((eline = malloc(linlen+1)) == NULL) {
			mlwrite("%%Out of Memory during macro execution");
			return(FALSE);
		}
		strncpy(eline, lp->l_text, linlen);
		eline[linlen] = 0;	/* make sure it ends */

		/* trim leading whitespace */
		while (eline[0] == ' ' || eline[0] == '\t')
			strcpy(eline, &eline[1]);

		/* if it is not a comment, execute it */
		if (eline[0] != 0 && eline[0] != ';') {
			status = docmd(eline);

			/* if it is a !GOTO directive, deal with it */
			if (status == GOLINE) {
				linlen = strlen(golabel);
				glp = hlp->l_fp;
				while (glp != hlp) {
					if (*glp->l_text == '*' &&
					    (strncmp(&glp->l_text[1], golabel,
					            linlen) == 0)) {
						lp = glp;
						status = TRUE;
					}
				glp = glp->l_fp;
				}
			}

			if (status == GOLINE) {
				mlwrite("%%No such label");
				return(FALSE);
			}

			/* if it is a !RETURN directive...do so */
			if (status == RET) {
				free(eline);
				break;
			}

			/* check for a command error */
			if (status != TRUE) {
				/* look if buffer is showing */
				wp = wheadp;
				while (wp != NULL) {
					if (wp->w_bufp == bp) {
						/* and point it */
						wp->w_dotp = lp;
						wp->w_doto = 0;
						wp->w_flag |= WFHARD;
					}
					wp = wp->w_wndp;
				}
				/* in any case set the buffer . */
				bp->b_dotp = lp;
				bp->b_doto = 0;
				free(eline);
				execlevel = 0;
				return(status);
			}
		}

		/* on to the next line */
		free(eline);
		lp = lp->l_fp;
	}

	/* exit the current function */
	execlevel = 0;
        return(TRUE);
}

execfile(f, n)	/* execute a series of commands in a file
*/

int f, n;	/* default flag and numeric arg to pass on to file */

{
	register int status;	/* return status of name query */
	char fname[NSTRING];	/* name of file to execute */

	if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
		return(status);

	/* otherwise, execute it */
	while (n-- > 0)
		if ((status=dofile(fname)) != TRUE)
			return(status);

	return(TRUE);
}

/*	dofile:	yank a file into a buffer and execute it
		if there are no errors, delete the buffer on exit */

dofile(fname)

char *fname;	/* file name to execute */

{
	register BUFFER *bp;	/* buffer to place file to exeute */
	register BUFFER *cb;	/* temp to hold current buf while we read */
	register int status;	/* results of various calls */
	char bname[NBUFN];	/* name of buffer */

	makename(bname, fname);		/* derive the name of the buffer */
	if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
		return(FALSE);

	bp->b_mode = MDVIEW;	/* mark the buffer as read only */
	cb = curbp;		/* save the old buffer */
	curbp = bp;		/* make this one current */
	/* and try to read in the file to execute */
	if ((status = readin(fname, FALSE)) != TRUE) {
		curbp = cb;	/* restore the current buffer */
		return(status);
	}

	/* go execute it! */
	curbp = cb;		/* restore the current buffer */
	if ((status = dobuf(bp)) != TRUE)
		return(status);

	/* if not displayed, remove the now unneeded buffer and exit */
	if (bp->b_nwnd == 0)
		zotbuf(bp);
	return(TRUE);
}

/*	cbuf:	Execute the contents of a numbered buffer	*/

cbuf(f, n, bufnum)

int f, n;	/* default flag and numeric arg */
int bufnum;	/* number of buffer to execute */

{
        register BUFFER *bp;		/* ptr to buffer to execute */
        register int status;		/* status return */
	static char bufname[] = "[Macro xx]";

	/* make the buffer name */
	bufname[7] = '0' + (bufnum / 10);
	bufname[8] = '0' + (bufnum % 10);

	/* find the pointer to that buffer */
        if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
        	mlwrite("Macro not defined");
                return(FALSE);
        }

	/* and now execute it as asked */
	while (n-- > 0)
		if ((status = dobuf(bp)) != TRUE)
			return(status);
	return(TRUE);
}

cbuf1(f, n)

{
	cbuf(f, n, 1);
}

cbuf2(f, n)

{
	cbuf(f, n, 2);
}

cbuf3(f, n)

{
	cbuf(f, n, 3);
}

cbuf4(f, n)

{
	cbuf(f, n, 4);
}

cbuf5(f, n)

{
	cbuf(f, n, 5);
}

cbuf6(f, n)

{
	cbuf(f, n, 6);
}

cbuf7(f, n)

{
	cbuf(f, n, 7);
}

cbuf8(f, n)

{
	cbuf(f, n, 8);
}

cbuf9(f, n)

{
	cbuf(f, n, 9);
}

cbuf10(f, n)

{
	cbuf(f, n, 10);
}

cbuf11(f, n)

{
	cbuf(f, n, 11);
}

cbuf12(f, n)

{
	cbuf(f, n, 12);
}

cbuf13(f, n)

{
	cbuf(f, n, 13);
}

cbuf14(f, n)

{
	cbuf(f, n, 14);
}

cbuf15(f, n)

{
	cbuf(f, n, 15);
}

cbuf16(f, n)

{
	cbuf(f, n, 16);
}

cbuf17(f, n)

{
	cbuf(f, n, 17);
}

cbuf18(f, n)

{
	cbuf(f, n, 18);
}

cbuf19(f, n)

{
	cbuf(f, n, 19);
}

cbuf20(f, n)

{
	cbuf(f, n, 20);
}

cbuf21(f, n)

{
	cbuf(f, n, 21);
}

cbuf22(f, n)

{
	cbuf(f, n, 22);
}

cbuf23(f, n)

{
	cbuf(f, n, 23);
}

cbuf24(f, n)

{
	cbuf(f, n, 24);
}

cbuf25(f, n)

{
	cbuf(f, n, 25);
}

cbuf26(f, n)

{
	cbuf(f, n, 26);
}

cbuf27(f, n)

{
	cbuf(f, n, 27);
}

cbuf28(f, n)

{
	cbuf(f, n, 28);
}

cbuf29(f, n)

{
	cbuf(f, n, 29);
}

cbuf30(f, n)

{
	cbuf(f, n, 30);
}

cbuf31(f, n)

{
	cbuf(f, n, 31);
}

cbuf32(f, n)

{
	cbuf(f, n, 32);
}

cbuf33(f, n)

{
	cbuf(f, n, 33);
}

cbuf34(f, n)

{
	cbuf(f, n, 34);
}

cbuf35(f, n)

{
	cbuf(f, n, 35);
}

cbuf36(f, n)

{
	cbuf(f, n, 36);
}

cbuf37(f, n)

{
	cbuf(f, n, 37);
}

cbuf38(f, n)

{
	cbuf(f, n, 38);
}

cbuf39(f, n)

{
	cbuf(f, n, 39);
}

cbuf40(f, n)

{
	cbuf(f, n, 40);
}


SHAR_EOF
chmod +x 'exec.c'
fi
echo shar: "extracting 'file.c'" '(0 character)'
if test -f 'file.c'
then
	echo shar: "will not over-write existing file 'file.c'"
else
cat << \SHAR_EOF > 'file.c'
/*	FILE.C:   for MicroEMACS

	The routines in this file handle the reading, writing
	and lookup of disk files.  All of details about the
	reading and writing of the disk are in "fileio.c".

*/

#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

/*
 * Read a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "read a file into the current buffer" code.
 * Bound to "C-X C-R".
 */
fileread(f, n)
{
        register int    s;
        char fname[NFILEN];

	if (restflag)		/* don't allow this command if restricted */
		return(resterr());
        if ((s=mlreply("Read file: ", fname, NFILEN)) != TRUE)
                return(s);
        return(readin(fname, TRUE));
}

/*
 * Insert a file into the current
 * buffer. This is really easy; all you do it
 * find the name of the file, and call the standard
 * "insert a file into the current buffer" code.
 * Bound to "C-X C-I".
 */
insfile(f, n)
{
        register int    s;
        char fname[NFILEN];

	if (restflag)		/* don't allow this command if restricted */
		return(resterr());
	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
        if ((s=mlreply("Insert file: ", fname, NFILEN)) != TRUE)
                return(s);
        return(ifile(fname));
}

/*
 * Select a file for editing.
 * Look around to see if you can find the
 * fine in another buffer; if you can find it
 * just switch to the buffer. If you cannot find
 * the file, create a new buffer, read in the
 * text, and switch to the new buffer.
 * Bound to C-X C-F.
 */
filefind(f, n)
{
        char fname[NFILEN];	/* file user wishes to find */
        register int s;		/* status return */

	if (restflag)		/* don't allow this command if restricted */
		return(resterr());
        if ((s=mlreply("Find file: ", fname, NFILEN)) != TRUE)
                return(s);
	return(getfile(fname, TRUE));
}

viewfile(f, n)	/* visit a file in VIEW mode */
{
        char fname[NFILEN];	/* file user wishes to find */
        register int s;		/* status return */
	register WINDOW *wp;	/* scan for windows that need updating */

	if (restflag)		/* don't allow this command if restricted */
		return(resterr());
        if ((s=mlreply("View file: ", fname, NFILEN)) != TRUE)
                return (s);
	s = getfile(fname, FALSE);
	if (s) {	/* if we succeed, put it in view mode */
		curwp->w_bufp->b_mode |= MDVIEW;

		/* scan through and update mode lines of all windows */
		wp = wheadp;
		while (wp != NULL) {
			wp->w_flag |= WFMODE;
			wp = wp->w_wndp;
		}
	}
	return(s);
}

#if	CRYPT
resetkey()	/* reset the encryption key if needed */

{
	register int s;	/* return status */

	/* turn off the encryption flag */
	cryptflag = FALSE;

	/* if we are in crypt mode */
	if (curbp->b_mode & MDCRYPT) {
		if (curbp->b_key[0] == 0) {
			s = setkey(FALSE, 0);
			if (s != TRUE)
				return(s);
		}

		/* let others know... */
		cryptflag = TRUE;

		/* and set up the key to be used! */
		/* de-encrypt it */
		crypt((char *)NULL, 0);
		crypt(curbp->b_key, strlen(curbp->b_key));

		/* re-encrypt it...seeding it to start */
		crypt((char *)NULL, 0);
		crypt(curbp->b_key, strlen(curbp->b_key));
	}

	return(TRUE);
}
#endif

getfile(fname, lockfl)

char fname[];		/* file name to find */
int lockfl;		/* check the file for locks? */

{
        register BUFFER *bp;
        register LINE   *lp;
        register int    i;
        register int    s;
        char bname[NBUFN];	/* buffer name to put file */

#if	MSDOS
	mklower(fname);		/* msdos isn't case sensitive */
#endif
        for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) {
                if ((bp->b_flag&BFINVS)==0 && strcmp(bp->b_fname, fname)==0) {
			swbuffer(bp);
                        lp = curwp->w_dotp;
                        i = curwp->w_ntrows/2;
                        while (i-- && lback(lp)!=curbp->b_linep)
                                lp = lback(lp);
                        curwp->w_linep = lp;
                        curwp->w_flag |= WFMODE|WFHARD;
                        mlwrite("[Old buffer]");
                        return (TRUE);
                }
        }
        makename(bname, fname);                 /* New buffer name.     */
        while ((bp=bfind(bname, FALSE, 0)) != NULL) {
		/* old buffer name conflict code */
                s = mlreply("Buffer name: ", bname, NBUFN);
                if (s == ABORT)                 /* ^G to just quit      */
                        return (s);
                if (s == FALSE) {               /* CR to clobber it     */
                        makename(bname, fname);
                        break;
                }
        }
        if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) {
                mlwrite("Cannot create buffer");
                return (FALSE);
        }
        if (--curbp->b_nwnd == 0) {             /* Undisplay.           */
                curbp->b_dotp = curwp->w_dotp;
                curbp->b_doto = curwp->w_doto;
                curbp->b_markp = curwp->w_markp;
                curbp->b_marko = curwp->w_marko;
        }
        curbp = bp;                             /* Switch to it.        */
        curwp->w_bufp = bp;
        curbp->b_nwnd++;
        return(readin(fname, lockfl));          /* Read it in.          */
}

/*
 * Read file "fname" into the current
 * buffer, blowing away any text found there. Called
 * by both the read and find commands. Return the final
 * status of the read. Also called by the mainline,
 * to read in a file specified on the command line as
 * an argument. If the filename ends in a ".c", CMODE is
 * set for the current buffer.
 */
readin(fname, lockfl)

char    fname[];	/* name of file to read */
int	lockfl;		/* check for file locks? */

{
        register LINE   *lp1;
        register LINE   *lp2;
        register int    i;
        register WINDOW *wp;
        register BUFFER *bp;
        register int    s;
        register int    nbytes;
        register int    nline;
	register char	*sptr;		/* pointer into filename string */
	int		lflag;		/* any lines longer than allowed? */
        char            line[NLINE];

#if	FILOCK
	if (lockfl && lockchk(fname) == ABORT)
		return(ABORT);
#endif
#if	CRYPT
	s = resetkey();
	if (s != TRUE)
		return(s);
#endif
        bp = curbp;                             /* Cheap.               */
        if ((s=bclear(bp)) != TRUE)             /* Might be old.        */
                return (s);
        bp->b_flag &= ~(BFINVS|BFCHG);
#if	ACMODE
	if (strlen(fname) > 1) {		/* check if a 'C' file	*/
		sptr = fname + strlen(fname) - 2;
		if (*sptr == '.' &&
		   (*(sptr + 1) == 'c' || *(sptr + 1) == 'h'))
			bp->b_mode |= MDCMOD;
	}
#endif
        strcpy(bp->b_fname, fname);

	/* turn off ALL keyboard translation in case we get a dos error */
	TTkclose();

        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
                goto out;
        if (s == FIOFNF) {                      /* File not found.      */
                mlwrite("[New file]");
                goto out;
        }
        mlwrite("[Reading file]");
        nline = 0;
	lflag = FALSE;
        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
            || s == FIOFUN) {
		if (s == FIOLNG) {
			lflag = TRUE;
			--nline;
		}
                nbytes = strlen(line);
                if ((lp1=lalloc(nbytes)) == NULL) {
                        s = FIOERR;             /* Keep message on the  */
                        break;                  /* display.             */
                }
                lp2 = lback(curbp->b_linep);
                lp2->l_fp = lp1;
                lp1->l_fp = curbp->b_linep;
                lp1->l_bp = lp2;
                curbp->b_linep->l_bp = lp1;
                for (i=0; i<nbytes; ++i)
                        lputc(lp1, i, line[i]);
                ++nline;
                if (s == FIOFUN)
                	break;
        }
        ffclose();                              /* Ignore errors.       */
	strcpy(line, "[");
	if (lflag)
		strcat(line, "Long lines wrapped, ");
	if (s == FIOFUN)
		strcat(line, "Funny line at EOF, ");
        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!   */
		sprintf(&line[strlen(line)], "Read %d line", nline);
                if (nline > 1)
			strcat(line, "s");
		strcat(line, "]");
        }
	if (s != FIOERR)
		mlwrite(line);

out:
	TTkopen();	/* open the keyboard again */
        for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) {
                if (wp->w_bufp == curbp) {
                        wp->w_linep = lforw(curbp->b_linep);
                        wp->w_dotp  = lforw(curbp->b_linep);
                        wp->w_doto  = 0;
                        wp->w_markp = NULL;
                        wp->w_marko = 0;
                        wp->w_flag |= WFMODE|WFHARD;
                }
        }
        if (s == FIOERR || s == FIOFNF)		/* False if error.      */
                return(FALSE);
        return (TRUE);
}

/*
 * Take a file name, and from it
 * fabricate a buffer name. This routine knows
 * about the syntax of file names on the target system.
 * I suppose that this information could be put in
 * a better place than a line of code.
 */
makename(bname, fname)
char    bname[];
char    fname[];
{
        register char *cp1;
        register char *cp2;

        cp1 = &fname[0];
        while (*cp1 != 0)
                ++cp1;

#if     AMIGA
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='/')
                --cp1;
#endif
#if     VMS
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
                --cp1;
#endif
#if     CPM
        while (cp1!=&fname[0] && cp1[-1]!=':')
                --cp1;
#endif
#if     MSDOS
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
                --cp1;
#endif
#if     ST520
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
                --cp1;
#endif
#if     FINDER
        while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\'&&cp1[-1]!='/')
                --cp1;
#endif
#if     V7 | USG | BSD
        while (cp1!=&fname[0] && cp1[-1]!='/')
                --cp1;
#endif
        cp2 = &bname[0];
        while (cp2!=&bname[NBUFN-1] && *cp1!=0 && *cp1!=';')
                *cp2++ = *cp1++;
        *cp2 = 0;
}

unqname(name)	/* make sure a buffer name is unique */

char *name;	/* name to check on */

{
	register char *sp;

	/* check to see if it is in the buffer list */
	while (bfind(name, 0, FALSE) != NULL) {

		/* go to the end of the name */
		sp = name;
		while (*sp)
			++sp;
		if (sp == name || (*(sp-1) <'0' || *(sp-1) > '8')) {
			*sp++ = '0';
			*sp = 0;
		} else
			*(--sp) += 1;
	}
}

/*
 * Ask for a file name, and write the
 * contents of the current buffer to that file.
 * Update the remembered file name and clear the
 * buffer changed flag. This handling of file names
 * is different from the earlier versions, and
 * is more compatable with Gosling EMACS than
 * with ITS EMACS. Bound to "C-X C-W".
 */
filewrite(f, n)
{
        register WINDOW *wp;
        register int    s;
        char            fname[NFILEN];

	if (restflag)		/* don't allow this command if restricted */
		return(resterr());
        if ((s=mlreply("Write file: ", fname, NFILEN)) != TRUE)
                return (s);
        if ((s=writeout(fname)) == TRUE) {
                strcpy(curbp->b_fname, fname);
                curbp->b_flag &= ~BFCHG;
                wp = wheadp;                    /* Update mode lines.   */
                while (wp != NULL) {
                        if (wp->w_bufp == curbp)
                                wp->w_flag |= WFMODE;
                        wp = wp->w_wndp;
                }
        }
        return (s);
}

/*
 * Save the contents of the current
 * buffer in its associatd file. No nothing
 * if nothing has changed (this may be a bug, not a
 * feature). Error if there is no remembered file
 * name for the buffer. Bound to "C-X C-S". May
 * get called by "C-Z".
 */
filesave(f, n)
{
        register WINDOW *wp;
        register int    s;

	if (curbp->b_mode&MDVIEW)	/* don't allow this command if	*/
		return(rdonly());	/* we are in read only mode	*/
        if ((curbp->b_flag&BFCHG) == 0)         /* Return, no changes.  */
                return (TRUE);
        if (curbp->b_fname[0] == 0) {           /* Must have a name.    */
                mlwrite("No file name");
                return (FALSE);
        }
        if ((s=writeout(curbp->b_fname)) == TRUE) {
                curbp->b_flag &= ~BFCHG;
                wp = wheadp;                    /* Update mode lines.   */
                while (wp != NULL) {
                        if (wp->w_bufp == curbp)
                                wp->w_flag |= WFMODE;
                        wp = wp->w_wndp;
                }
        }
        return (s);
}

/*
 * This function performs the details of file
 * writing. Uses the file management routines in the
 * "fileio.c" package. The number of lines written is
 * displayed. Sadly, it looks inside a LINE; provide
 * a macro for this. Most of the grief is error
 * checking of some sort.
 */
writeout(fn)
char    *fn;
{
        register int    s;
        register LINE   *lp;
        register int    nline;

#if	CRYPT
	s = resetkey();
	if (s != TRUE)
		return(s);
#endif
	/* turn off ALL keyboard translation in case we get a dos error */
	TTkclose();

        if ((s=ffwopen(fn)) != FIOSUC) {        /* Open writes message. */
		TTkopen();
                return (FALSE);
        }
	mlwrite("[Writing..]");			/* tell us were writing */
        lp = lforw(curbp->b_linep);             /* First line.          */
        nline = 0;                              /* Number of lines.     */
        while (lp != curbp->b_linep) {
                if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
                        break;
                ++nline;
                lp = lforw(lp);
        }
        if (s == FIOSUC) {                      /* No write error.      */
                s = ffclose();
                if (s == FIOSUC) {              /* No close error.      */
                        if (nline == 1)
                                mlwrite("[Wrote 1 line]");
                        else
                                mlwrite("[Wrote %d lines]", nline);
                }
        } else                                  /* Ignore close error   */
                ffclose();                      /* if a write error.    */
	TTkopen();
        if (s != FIOSUC)                        /* Some sort of error.  */
                return (FALSE);
        return (TRUE);
}

/*
 * The command allows the user
 * to modify the file name associated with
 * the current buffer. It is like the "f" command
 * in UNIX "ed". The operation is simple; just zap
 * the name in the BUFFER structure, and mark the windows
 * as needing an update. You can type a blank line at the
 * prompt if you wish.
 */
filename(f, n)
{
        register WINDOW *wp;
        register int    s;
        char            fname[NFILEN];

	if (restflag)		/* don't allow this command if restricted */
		return(resterr());
        if ((s=mlreply("Name: ", fname, NFILEN)) == ABORT)
                return (s);
        if (s == FALSE)
                strcpy(curbp->b_fname, "");
        else
                strcpy(curbp->b_fname, fname);
        wp = wheadp;                            /* Update mode lines.   */
        while (wp != NULL) {
                if (wp->w_bufp == curbp)
                        wp->w_flag |= WFMODE;
                wp = wp->w_wndp;
        }
	curbp->b_mode &= ~MDVIEW;	/* no longer read only mode */
        return (TRUE);
}

/*
 * Insert file "fname" into the current
 * buffer, Called by insert file command. Return the final
 * status of the read.
 */
ifile(fname)
char    fname[];
{
        register LINE   *lp0;
        register LINE   *lp1;
        register LINE   *lp2;
        register int    i;
        register BUFFER *bp;
        register int    s;
        register int    nbytes;
        register int    nline;
	int		lflag;		/* any lines longer than allowed? */
        char            line[NLINE];

        bp = curbp;                             /* Cheap.               */
        bp->b_flag |= BFCHG;			/* we have changed	*/
	bp->b_flag &= ~BFINVS;			/* and are not temporary*/
        if ((s=ffropen(fname)) == FIOERR)       /* Hard file open.      */
                goto out;
        if (s == FIOFNF) {                      /* File not found.      */
                mlwrite("[No such file]");
		return(FALSE);
        }
        mlwrite("[Inserting file]");

#if	CRYPT
	s = resetkey();
	if (s != TRUE)
		return(s);
#endif
	/* back up a line and save the mark here */
	curwp->w_dotp = lback(curwp->w_dotp);
	curwp->w_doto = 0;
	curwp->w_markp = curwp->w_dotp;
	curwp->w_marko = 0;

        nline = 0;
	lflag = FALSE;
        while ((s=ffgetline(line, NLINE)) == FIOSUC || s == FIOLNG
            || s == FIOFUN) {
		if (s == FIOLNG) {
			lflag = TRUE;
			--nline;
		}
                nbytes = strlen(line);
                if ((lp1=lalloc(nbytes)) == NULL) {
                        s = FIOERR;             /* Keep message on the  */
                        break;                  /* display.             */
                }
		lp0 = curwp->w_dotp;	/* line previous to insert */
		lp2 = lp0->l_fp;	/* line after insert */

		/* re-link new line between lp0 and lp2 */
		lp2->l_bp = lp1;
		lp0->l_fp = lp1;
		lp1->l_bp = lp0;
		lp1->l_fp = lp2;

		/* and advance and write out the current line */
		curwp->w_dotp = lp1;
                for (i=0; i<nbytes; ++i)
                        lputc(lp1, i, line[i]);
                ++nline;
                if (s == FIOFUN)
                	break;
        }
        ffclose();                              /* Ignore errors.       */
	curwp->w_markp = lforw(curwp->w_markp);
	strcpy(line, "[");
	if (lflag)
		strcat(line, "Long lines wrapped, ");
	if (s == FIOFUN)
		strcat(line, "Funny line at EOF, ");
        if (s == FIOEOF || s == FIOFUN) {        /* Don't zap message!   */
		sprintf(&line[strlen(line)], "Inserted %d line", nline);
                if (nline > 1)
			strcat(line, "s");
		strcat(line, "]");
        }
	if (s != FIOERR)
		mlwrite(line);
out:
	/* advance to the next line and mark the window for changes */
	curwp->w_dotp = lforw(curwp->w_dotp);
	curwp->w_flag |= WFHARD | WFMODE;

	/* copy window parameters back to the buffer structure */
	curbp->b_dotp = curwp->w_dotp;
	curbp->b_doto = curwp->w_doto;
	curbp->b_markp = curwp->w_markp;
	curbp->b_marko = curwp->w_marko;

        if (s == FIOERR)                        /* False if error.      */
                return (FALSE);
        return (TRUE);
}
SHAR_EOF
chmod +x 'file.c'
fi
echo shar: "extracting 'fileio.c'" '(0 character)'
if test -f 'fileio.c'
then
	echo shar: "will not over-write existing file 'fileio.c'"
else
cat << \SHAR_EOF > 'fileio.c'
/*
 * The routines in this file read and write ASCII files from the disk. All of
 * the knowledge about files are here. A better message writing scheme should
 * be used.
 */
#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

FILE    *ffp;                           /* File pointer, all functions. */

/*
 * Open a file for reading.
 */
ffropen(fn)
char    *fn;
{
        if ((ffp=fopen(fn, "r")) == NULL)
                return (FIOFNF);
        return (FIOSUC);
}

/*
 * Open a file for writing. Return TRUE if all is well, and FALSE on error
 * (cannot create).
 */
ffwopen(fn)
char    *fn;
{
#if     VMS
        register int    fd;

        if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
        || (ffp=fdopen(fd, "w")) == NULL) {
#else
        if ((ffp=fopen(fn, "w")) == NULL) {
#endif
                mlwrite("Cannot open file for writing");
                return (FIOERR);
        }
        return (FIOSUC);
}

/*
 * Close a file. Should look at the status in all systems.
 */
ffclose()
{
#if	MSDOS & CTRLZ
	fputc(26, ffp);		/* add a ^Z at the end of the file */
#endif
	
#if     V7 | USG | BSD | (MSDOS & (LATTICE | MSC))
        if (fclose(ffp) != FALSE) {
                mlwrite("Error closing file");
                return(FIOERR);
        }
        return(FIOSUC);
#else
        fclose(ffp);
        return (FIOSUC);
#endif
}

/*
 * Write a line to the already opened file. The "buf" points to the buffer,
 * and the "nbuf" is its length, less the free newline. Return the status.
 * Check only at the newline.
 */
ffputline(buf, nbuf)
char    buf[];
{
        register int    i;
#if	CRYPT
	char c;		/* character to translate */

	if (cryptflag) {
	        for (i = 0; i < nbuf; ++i) {
			c = buf[i] & 0xff;
			crypt(&c, 1);
			fputc(c, ffp);
		}
	} else
	        for (i = 0; i < nbuf; ++i)
        	        fputc(buf[i]&0xFF, ffp);
#else
        for (i = 0; i < nbuf; ++i)
                fputc(buf[i]&0xFF, ffp);
#endif

#if	ST520
        fputc('\r', ffp);
#endif        
        fputc('\n', ffp);

        if (ferror(ffp)) {
                mlwrite("Write I/O error");
                return (FIOERR);
        }

        return (FIOSUC);
}

/*
 * Read a line from a file, and store the bytes in the supplied buffer. The
 * "nbuf" is the length of the buffer. Complain about long lines and lines
 * at the end of the file that don't have a newline present. Check for I/O
 * errors too. Return status.
 */
ffgetline(buf, nbuf)
register char   buf[];
{
        register int    c;
        register int    i;

        i = 0;

        while ((c = fgetc(ffp)) != EOF && c != '\n') {
                if (i >= nbuf-2) {
			buf[nbuf - 2] = c;	/* store last char read */
			buf[nbuf - 1] = 0;	/* and terminate it */
                        mlwrite("File has long line");
#if	CRYPT
			if (cryptflag)
				crypt(buf, strlen(buf));
#endif
                        return (FIOLNG);
                }
                buf[i++] = c;
        }

#if	ST520
	if(buf[i-1] == '\r')
		i--;
#endif
        if (c == EOF) {
                if (ferror(ffp)) {
                        mlwrite("File read error");
                        return (FIOERR);
                }

                if (i != 0) {
                	buf[i] = 0;
                        return(FIOFUN);
                }

                return (FIOEOF);
        }

        buf[i] = 0;
#if	CRYPT
	if (cryptflag)
		crypt(buf, strlen(buf));
#endif
        return (FIOSUC);
}

#if	AZTEC & MSDOS
#undef	fgetc
/*	a1getc:		Get an ascii char from the file input stream
			but DO NOT strip the high bit
*/

int a1getc(fp)

FILE *fp;

{
	int c;		/* translated character */

	c = getc(fp);	/* get the character */

	/* if its a <LF> char, throw it out  */
	while (c == 10)
		c = getc(fp);

	/* if its a <RETURN> char, change it to a LF */
	if (c == '\r')
		c = '\n';

	/* if its a ^Z, its an EOF */
	if (c == 26)
		c = EOF;

	return(c);
}
#endif
SHAR_EOF
chmod +x 'fileio.c'
fi
echo shar: "extracting 'hp110.c'" '(0 character)'
if test -f 'hp110.c'
then
	echo shar: "will not over-write existing file 'hp110.c'"
else
cat << \SHAR_EOF > 'hp110.c'
/*
 *	HP110:	Hewlett Packard 110 Screen Driver
 */

#define	termdef	1			/* don't define "term" external */

#include        <stdio.h>
#include	"estruct.h"
#include        "edef.h"

#if     HP110

#define NROW    16                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#define	NPAUSE	100			/* # times thru update to pause */
#define	MARGIN	8			/* size of minimim margin and	*/
#define	SCRSIZ	64			/* scroll size for extended lines */
#define BEL     0x07                    /* BEL character.               */
#define ESC     0x1B                    /* ESC character.               */

extern  int     ttopen();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern  int     ttclose();
extern  int     h110move();
extern  int     h110eeol();
extern  int     h110eeop();
extern  int     h110beep();
extern  int     h110open();
extern	int	h110rev();
extern	int	h110cres();
extern	int	h110close();
extern	int	h110kopen();
extern	int	h110kclose();

#if	COLOR
extern	int	h110fcol();
extern	int	h110bcol();

int	cfcolor = -1;		/* current forground color */
int	cbcolor = -1;		/* current background color */
#endif

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM    term    = {
	NROW-1,
        NROW-1,
        NCOL,
        NCOL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
        h110open,
        h110close,
	h110kopen,
	h110kclose,
        ttgetc,
        ttputc,
        ttflush,
        h110move,
        h110eeol,
        h110eeop,
        h110beep,
	h110rev,
	h110cres
#if	COLOR
	, h110fcol,
	h110bcol
#endif
};

#if	COLOR
h110fcol(color)		/* set the current output color */

int color;	/* color to set */

{
	if (color == cfcolor)
		return;
	ttputc(ESC);
	ttputc('[');
	h110parm(color+30);
	ttputc('m');
	cfcolor = color;
}

h110bcol(color)		/* set the current background color */

int color;	/* color to set */

{
	if (color == cbcolor)
		return;
	ttputc(ESC);
	ttputc('[');
	h110parm(color+40);
	ttputc('m');
        cbcolor = color;
}
#endif

h110move(row, col)
{
        ttputc(ESC);
        ttputc('[');
        h110parm(row+1);
        ttputc(';');
        h110parm(col+1);
        ttputc('H');
}

h110eeol()
{
        ttputc(ESC);
        ttputc('[');
	ttputc('0');
        ttputc('K');
}

h110eeop()
{
#if	COLOR
	h110fcol(gfcolor);
	h110bcol(gbcolor);
#endif
        ttputc(ESC);
        ttputc('[');
	ttputc('0');
        ttputc('J');
}

h110rev(state)		/* change reverse video state */

int state;	/* TRUE = reverse, FALSE = normal */

{
#if	COLOR
	int ftmp, btmp;		/* temporaries for colors */
#endif

	ttputc(ESC);
	ttputc('[');
	ttputc(state ? '7': '0');
	ttputc('m');
#if	COLOR
	if (state == FALSE) {
		ftmp = cfcolor;
		btmp = cbcolor;
		cfcolor = -1;
		cbcolor = -1;
		h110fcol(ftmp);
		h110bcol(btmp);
	}
#endif
}

h110cres()	/* change screen resolution */

{
	return(TRUE);
}

spal()		/* change pallette register */

{
	/*   not here */
}

h110beep()
{
        ttputc(BEL);
        ttflush();
}

h110parm(n)
register int    n;
{
        register int q,r;

        q = n/10;
        if (q != 0) {
		r = q/10;
		if (r != 0) {
			ttputc((r%10)+'0');
		}
		ttputc((q%10) + '0');
        }
        ttputc((n%10) + '0');
}

h110open()
{
	strcpy(sres, "15LINE");
	revexist = TRUE;
        ttopen();
}

h110close()

{
#if	COLOR
	h110fcol(7);
	h110bcol(0);
#endif
	ttclose();
}

h110kopen()

{
}

h110kclose()

{
}

#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument [unused] */

{
	/* on machines with no function keys...don't bother */
	return(TRUE);
}
#endif
#else
h110hello()
{
}
#endif
SHAR_EOF
fi
echo shar: "extracting 'hp150.c'" '(0 character)'
if test -f 'hp150.c'
then
	echo shar: "will not over-write existing file 'hp150.c'"
else
cat << \SHAR_EOF > 'hp150.c'
/*
 * The routines in this file provide support for HP150 screens
 * and routines to access the Keyboard through KEYCODE mode.
 * It compiles into nothing if not an HP150 screen device.
 * added by Daniel Lawrence
 */

#define	termdef	1			/* don't define "term" external */

#include        <stdio.h>
#include        "estruct.h"
#include	"edef.h"

#if     HP150

#define NROW    24                      /* Screen size.                 */
#define NCOL    80                      /* Edit if you want to.         */
#define	MARGIN	8			/* size of minimim margin and	*/
#define	SCRSIZ	64			/* scroll size for extended lines */
#define	NPAUSE	15			/* # times thru update to pause */
#define BEL     0x07                    /* BEL character.               */
#define ESC     0x1B                    /* ESC character.               */

extern  int     openhp();               /* Forward references.          */
extern  int     ttgetc();
extern  int     ttputc();
extern  int     ttflush();
extern	int	hpflush();
extern  int     closehp();
extern	int	hp15kopen();
extern	int	hp15kclose();
extern  int     hp15move();
extern  int     hp15eeol();
extern  int     hp15eeop();
extern  int     hp15beep();
extern	int	gethpkey();
extern	int	hp15rev();
extern	int	hp15cres();
#if	COLOR
extern	int	hp15fcol();
extern	int	hp15bcol();
#endif

/* weird to ascii translation table */

char trans[][2] = {
	0x24,	9,	/* tab */
	0x25,	13,	/* ret */
	0x27,	8,	/* backspace */
	0x30,	48,	/* zero */
	0x31,	49,	/* one */
	0x32,	50,	/* two */
	0x33,	51,	/* three */
	0x34,	52,	/* four */
	0x35,	53,	/* five */
	0x36,	54,	/* six */
	0x37,	55,	/* seven */
	0x38,	56,	/* eight */
	0x39,	57,	/* nine */
	0x50,	13,	/* enter */
	0x54,	27,	/* break -> ESC */
	0x55,	27,	/* esc */
	0x58,	24,	/* stop -> ^X */
	0x70,	45,	/* N-minus */
	0x71,	42,	/* N-asterisk */
	0x72,	43,	/* N-plus */
	0x73,	47,	/* N-slash */
	0x74,	44,	/* N-comma */
	0x75,	13,	/* N-enter */
	0x76,	9,	/* N-tab */
	0x77,	46	/* N-period */
};

#define NTRANS	sizeof(trans) / 2

union REGS r;		/* register set for bios and dos (AGIOS) calls */
int capslock = 0;	/* caps lock flag */

/*
 * Standard terminal interface dispatch table. Most of the fields point into
 * "termio" code.
 */
TERM    term    = {
	NROW-1,
        NROW-1,
        NCOL,
        NCOL,
	MARGIN,
	SCRSIZ,
	NPAUSE,
	openhp,
        closehp,
	hp15kopen,
	hp15kclose,
	gethpkey,
        ttputc,
        hpflush,
        hp15move,
        hp15eeol,
        hp15eeop,
        hp15beep,
        hp15rev,
        hp15cres
#if	COLOR
	, hp15fcol,
	hp15bcol
#endif
};

hp15move(row, col)
{
        ttputc(ESC);
        ttputc('&');
        ttputc('a');
        hp15parm(col);
        ttputc('c');
        hp15parm(row);
        ttputc('R');
}

hpflush()

{

}

hp15eeol()
{
        ttputc(ESC);
        ttputc('K');
}

hp15eeop()
{
        ttputc(ESC);
        ttputc('J');
}

hp15rev(status)		/* change the reverse video status */

int status;	/* TRUE = on, FALSE = off */

{
	ttputc(ESC);
	ttputc('&');
	ttputc('d');
	ttputc((status != FALSE) ? 'B': '@');
}

hp15cres()	/* change screen resolution */

{
	return(TRUE);
}

spal()		/* change pallette register */

{
	/*   not here */
}

hp15beep()
{
        ttputc(BEL);
        ttflush();
}

hp15parm(n)
register int    n;
{
        register int    q;

        q = n/10;
        if (q != 0)
                hp15parm(q);
        ttputc((n%10) + '0');
}

#if	COLOR
hp15fcol()	/* we really can't do colors here, so just ignore it */
{
}

hp15bcol()	/* we really can't do colors here, so just ignore it */
{
}
#endif

gethpkey()	/* get a key from the HP keyboard while in keycode mode */

{
	static int keepflag = 0;	/* kept ahead char flag */
	static int keepchar = 0;	/* kept ehead flag */
	int c;
	int devid;			/* device ID */
	int ctype;			/* type of character gotten */
	int shiftb;			/* state of shift keys */
	int i;
	
	/* if we are in an extended char sequence, finish it */
	if (keepflag != 0) {
		keepflag = 0;
		return(keepchar);
	}

	/* grab the next 4 char sequence */
next:	shiftb = ttgetc();
	devid = ttgetc();
	c = ttgetc();
	ttgetc();		/* skip null byte */
	
	/* make sure we are from the keyboard */
	if (devid != 192)
		goto next;

	/* if normal ascii, return it */
	if ((shiftb & 0x80) == 0) {
		if (capslock && c >= 'a' && c <= 'z')
			c -= 32;
		return(c);
	}

	/* check specifically for the caps lock key */
	if (c == 0x56) {
		capslock = ~capslock;
		goto next;
	}

	/* check to see if it needs translation */
	for (i=0; i < NTRANS; i++)
		if (trans[i][0] == c)
			return((int)trans[i][1]);

	/* other wise, shove it in the keep char and return the leadin code */
	keepchar = c;
	keepflag = 1;
	return(0);
}

openhp()		/* open the HP150 screen for input */

{
	strcpy(sres, "NORMAL");
	revexist = TRUE;
}

closehp()		/* close the HP150 screen for input */

{
}

hp15kopen()		/* open the HP150 keyboard for input */

{
	/* define key charectoristics with AGIOS call (0, 40) */
	defkey();

	/* Turn on RAW mode with MSDOS call 44h */
	rawon();

	/* Turn off Control-C checking  MS-DOS 33h */
	ckeyoff();

	/* Turn on keycode mode with AGIOS call (0,43) */
	keycon();

	/* display the application softkey labels */
	dsplbls();
}

hp15kclose()		/* close the HP150 keyboard for input */

{
	/* define key charectoristics with AGIOS call (0, 40) */
	undefkey();
	
	/* Turn off RAW mode with MSDOS call 44h */
	rawoff();

	/* Turn on Control-C checking  MS-DOS 33h */
	ckeyon();

	/* Turn off keycode mode with AGIOS call (0,43) */
	keycoff();
}

rawon()		/* put the HP150 keyboard into RAW mode */

{
	/* get the IO control info */

	r.x.ax = 0x4400;	/* IO ctrl get device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r);		/* go fer it */

	r.h.dh = 0;		/* clear high byte for put */
	r.h.dl |= 0x20;		/* set raw bit */

	/* and put it back */

	r.x.ax = 0x4401;	/* IO ctrl put device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r);		/* go fer it */
}

rawoff()	/* put the HP150 keyboard into COOKED mode */

{
	/* get the IO control info */

	r.x.ax = 0x4400;	/* IO ctrl get device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r);		/* go fer it */

	r.h.dh = 0;		/* clear high byte for put */
	r.h.dl &= 0xdf;		/* set raw bit */

	/* and put it back */

	r.x.ax = 0x4401;	/* IO ctrl put device information */
	r.x.bx = 0x0001;	/* File handle; 1 for console */
	intdos(&r, &r);		/* go fer it */
}


ckeyoff()	/* turn control-C trapping off */

{
	r.h.ah = 0x33;	/* ctrl-break check */
	r.h.al = 1;	/* set the state of the ctrl-break check */
	r.h.dl = 0;	/* turn it off */
	intdos(&r, &r);
}

ckeyon()	/* turn control-C trapping on */

{
	r.h.ah = 0x33;	/* ctrl-break check */
	r.h.al = 1;	/* set the state of the ctrl-break check */
	r.h.dl = 1;	/* turn it on */
	intdos(&r, &r);
}

agios(buf, len)	/* perform an AGIOS call */

char *buf;	/* sequence of bytes in command */
int len;	/* length of command in bytes */

{
	r.x.ax = 0x4403;	/* I/O ctrl write */
	r.x.bx = 1;		/* console handle */
	r.x.cx = len;		/* buffer length */
	r.x.dx = (unsigned)buf;	/* buffer address */
	return(intdos(&r, &r));	/* do it */
}

keycon()	/* turn keycode mode on */

{
	static char cmd[] = {43, 0, 1};

	return(agios(&cmd[0], 3));
}

keycoff()	/* turn keycode mode off */

{
	static char cmd[] = {43, 0, 0};

	return(agios(&cmd[0], 3));
}

defkey()	/* change all special keys to intercept mode */

{
	static char cmd[] = {40, 0, 2, 0, 0xfe, 0};

	return(agios(&cmd[0], 6));
}

undefkey()	/* change all special keys to intercept mode */

{
	static char cmd[] = {40, 0, 0, 0, 0xfe, 0};

	return(agios(&cmd[0], 6));
}

dsplbls()	/* display the application softkey labels on the screen */

{
	static char cmd[] = {11, 0};

	return(agios(&cmd[0], 2));
}

#if	FLABEL
fnclabel(f, n)		/* label a function key */

int f,n;	/* default flag, numeric argument */

{
	register int status;	/* return status */
	register int i;		/* loop index */
	char lbl[17];	/* returned label contents */
	/* AGIOS command buffer */
	static char cmd[] = {8, 0, 1, 0, 7, 7, 7, 7, 10, 0, 10, 0};
	/*                   code  key#  ptr to      top    bottom
	                                 label string  attribute */
	union {		/* union to cast ptr into AGIOS arg string */
		char *ptr;	/* pointer to arg string */
		char cstr[4];
	} ptru;

	/* must have a numeric argument */
	if (f == FALSE) {
		mlwrite("%Need function key number");
		return(FALSE);
	}

	/* and it must be a legal key number */
	if (n < 1 || n > 8) {
		mlwrite("%Function key number out of range");
		return(FALSE);
	}

	/* get the string to send */
	status = mlreply("Label contents: ", &lbl[0], 17);
	if (status != TRUE)
		return(status);

	/* pad the label out */
	for (i=0; i < 17; i++) {
		if (lbl[i] == 0)
			break;
	}
	for (; i < 16; i++)
		lbl[i] = ' ';
	lbl[16] = 0;

	/* set up the parameters */
	cmd[2] = n;			/* function key number */
	ptru.ptr = &lbl[0];		/* set up pointer to label string */
force:	cmd[4] = ptru.cstr[0];
	cmd[5] = ptru.cstr[1];
	cmd[6] = ptru.cstr[2];
	cmd[7] = ptru.cstr[3];

	/* and send it out */
	agios(&cmd[0], 12);
	return(TRUE);
}
#endif
#else

h15hello()

{
}
#endif
SHAR_EOF
chmod +x 'hp150.c'
fi
exit 0
#	End of shell archive