From decwrl!elroy.jpl.nasa.gov!usc!cs.utexas.edu!uunet!allbery Sat Mar 10 15:34:32 PST 1990
Article 1389 of comp.sources.misc:
Path: decwrl!elroy.jpl.nasa.gov!usc!cs.utexas.edu!uunet!allbery
From: dmt@pegasus.ATT.COM (Dave Tutelman)
Newsgroups: comp.sources.misc
Subject: v11i014: Stevie 3.69a - 6/6
Message-ID: <80854@uunet.UU.NET>
Date: 10 Mar 90 19:44:43 GMT
Sender: allbery@uunet.UU.NET
Organization: AT&T Bell Labs - Lincroft, NJ
Lines: 2866
Approved: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)

Posting-number: Volume 11, Issue 14
Submitted-by: dmt@pegasus.ATT.COM (Dave Tutelman)
Archive-name: stevie3.69a/part06

: This is a shar archive.  Extract with sh, not csh.
: The rest of this file will extract:
: dos.c minix.c os2.c unix.c setenv.c ctags.c
echo extracting - dos.c
sed 's/^X//' > dos.c << '!EOR!'
X/* $Header:
X *
X * MSDOS support for Stevie.
X * Many of the functions in this file have two versions:
X *   -	The original version, using ANSI escape sequences
X *	(by Tim Thompson and/or Tony Andrews).
X *	It requires a non-IBM ANSI driver, such as the shareware NANSI.SYS.
X *   -	The BIOS-function version (by Larry A. Shurr).  The BIOS version
X *	doesn't require an enhanced console driver such as NANSI.SYS.
X *	Invoke it by #defining BIOS in ENV.H.
X * Dave Tutelman has incorporated many features of Larry Shurr's BIOS
X * version (such as colors and 43-line mode) into the ANSI version.
X */
X
X#include "stevie.h"
X#include <stdio.h>
X#include <dos.h>
X#include <signal.h>
X
Xchar	*getenv();
X
Xstatic	char	getswitch();
Xstatic	void	setswitch();
X
X#ifdef BIOS
Xvoid bios_t_ed();
Xvoid bios_t_el();
X#endif
X
Xenum hostval_e {hIBMPC, hTIPRO};
Xtypedef enum hostval_e hostval;
Xstatic	hostval	host_type   = 0;	/* Gets host computer type */
X
Xstatic	char	bgn_color   = 0x7;	/* For saving orig color */
Xstatic	char	quitting_now= 0;	/* Set for windexit() */
Xstatic	int	crt_int     = 0;	/* Gets CRT BIOS interrupt */
Xstatic	char	bgn_page    = 0;	/* For saving current page (IBM PC) */
Xstatic	char	bgn_mode    = 0;	/* For saving video mode (IBM PC) */
X
X#ifdef BIOS
Xstatic	int	sav_curattr = 0;	/* For saving cursor attributes */
Xstatic	int	sav_curpos  = 0;	/* For saving cursor position */
X#endif
X
X/*
X * inchar() - get a character from the keyboard
X */
Xint
Xinchar()
X{
X	int	c;
X
X	got_int = FALSE;
X
X	for (;;beep()) {	/* loop until we get a valid character */
X
X		flushbuf();	/* flush any pending output */
X
X		switch (c = getch()) {
X		case 0x1e:
X			return K_CCIRCM;
X		case 0:				/* special key */
X			if (State != NORMAL) {
X				c = getch();	/* throw away next char */
X				continue;	/* and loop for another char */
X			}
X			switch (c = getch()) {
X			case 0x50:
X				return K_DARROW;
X			case 0x48:
X				return K_UARROW;
X			case 0x4b:
X				return K_LARROW;
X			case 0x4d:
X				return K_RARROW;
X			case 0x47:		/* Home key */
X				stuffin("1G");
X				return -1;
X			case 0x4f:		/* End key */
X				stuffin("G");
X				return -1;
X			case 0x51:		/* PgDn key */
X				stuffin(mkstr(CTRL('F')));
X				return -1;
X			case 0x49:		/* PgUp key */
X				stuffin(mkstr(CTRL('B')));
X				return -1;
X			case 0x52:		/* insert key */
X				return K_INSERT;
X			case 0x53:		/* delete key */
X				stuffin("x");
X				return -1;
X			/*
X			 * Hard-code some useful function key macros.
X			 */
X			case 0x3b: /* F1 */
X				stuffin(":help\n");
X				return -1;
X			case 0x3c: /* F2 */
X				stuffin(":n\n");
X				return -1;
X			case 0x55: /* SF2 */
X				stuffin(":n!\n");
X				return -1;
X			case 0x3d: /* F3 */
X				stuffin(":N\n");
X				return -1;
X			case 0x56: /* SF3 */
X				stuffin(":N!\n");
X				return -1;
X			case 0x3e: /* F4 */
X				stuffin(":e #\n");
X				return -1;
X			case 0x57: /* SF4 */
X				stuffin(":e! #\n");
X				return -1;
X			case 0x3f: /* F5 */
X				stuffin(":rew\n");
X				return -1;
X			case 0x58: /* SF5 */
X				stuffin(":rew!\n");
X				return -1;
X			case 0x40: /* F6 */
X				stuffin("]]");
X				return -1;
X			case 0x59: /* SF6 */
X				stuffin("[[");
X				return -1;
X			case 0x42: /* F8 - Set up global substitute */
X				stuffin(":1,$s/");
X				return -1;
X			case 0x43: /* F9 - declare C variable */
X				stuffin("yyp!!cdecl\n");
X				return -1;
X			case 0x5C: /* SF9 - explain C declaration */
X				stuffin("yyp^iexplain \033!!cdecl\n");
X				return -1;
X			case 0x44: /* F10 - save & quit */
X				stuffin(":x\n");
X				return -1;
X			case 0x5D: /* F10 - quit without saving */
X				stuffin(":q!\n");
X				return -1;
X			default:
X				break;
X			}
X			break;
X
X		default:
X			return c;
X		}
X	}
X}
X
X
Xstatic	int	bpos = 0;
X#ifdef BIOS
X
X#define	BSIZE	256
Xstatic	char	outbuf[BSIZE];
X
X/* Flushbuf() is used a little differently here in the BIOS-only interface
X * than in the case of other systems.  In general, the other systems buffer
X * large amounts of text and screen management data (escape sequences).
X * Here, only text is buffered, screen management is performed using BIOS
X * calls.  Hence, the buffer is much smaller since no more than one line of
X * text is buffered.  Also, screen management calls must assure that the
X * buffered text is output before performing the requested function.
X *
X * O.K.  Now I had better explain the tricky code sequences for IBM PC and
X * TI Pro.  In both cases, the tricks involve: 1) getting the text written
X * to the display as quickly as possible in the desired color and 2) assur-
X * ing that the cursor is positioned immediately following the latest text
X * output.
X *
X * On the IBM PC, we output the first character using the "write character
X * with attribute" function followed by code which outputs the buffer, a
X * character at a time, using the "write tty" function.  The first write
X * sets the display attributes, which are then reused by the "write tty"
X * function.  The "write tty" is then used to quickly write the data while
X * advancing the cursor.  The "write character with attribute" function
X * does not advance the cursor and so cannot be used to write the entire
X * buffer without additional code to advance the cursor in a separate oper-
X * ation.  Even though the first character in each buffer gets written
X * twice, the result is still substantially faster than it would be using a
X * "write character with attribute" - "[re]position cursor" sequence.
X *
X * On the TI Pro, we output the entire buffer using the "write character
X * string with attribute" function which is fast and convenient.  Unfortun-
X * ately, it does not advance the cursor.  Therefore, we include code which
X * determines the current location of the cursor, writes the buffer, then
X * positions the cursor at the end of the new data.
X *
X * I admit it, this is tricky, but it makes display updates much faster
X * than the would be using a more straightforward approach.
X */
X
X
Xvoid
Xflushbuf()				/* Flush buffered output to display */
X{
X	union	REGS	inregs, curregs, outregs;
X
X	if (bpos != 0) {
X		char	*bptr = outbuf;
X
X		switch (host_type) {
X		case hIBMPC:
X			inregs.h.ah = 0x09;
X			inregs.h.al = *bptr;
X			inregs.h.bh = bgn_page;
X			inregs.h.bl = P(P_CO);
X			inregs.x.cx = 1;
X			int86(crt_int, &inregs, &outregs);
X			inregs.h.ah = 0x0E;
X			while (bpos-- > 0) {
X				inregs.h.al = *bptr++;
X				int86(crt_int, &inregs, &outregs);
X			}
X			break;
X		case hTIPRO:
X			curregs.h.ah = 0x03;
X			int86(crt_int, &curregs, &curregs);
X			inregs.h.ah = 0x10;
X			inregs.h.al = P(P_CO);
X			inregs.x.bx = FP_OFF(outbuf);
X			inregs.x.cx = bpos;
X			inregs.x.dx = FP_SEG(outbuf);
X			int86(crt_int, &inregs, &outregs);
X			curregs.h.ah = 0x02;
X			curregs.h.dh += bpos;
X			int86(crt_int, &curregs, &outregs);
X			break;
X		}
X	}
X	bpos = 0;
X}
X
Xvoid
Xwrite_tty(c)				/* Used to execute control chars */
Xchar	c;
X{
X	int	curcol;
X
X	union	REGS	inregs, curregs, outregs;
X
X	flushbuf(); \
X
X	switch (c) {
X	case '\t':
X		inregs.h.ah = 0x09;
X		inregs.h.al = ' ';
X		inregs.h.bh = bgn_page;
X		inregs.h.bl = P(P_CO);
X		inregs.x.cx = 1;
X		int86(crt_int, &inregs, &outregs);
X		inregs.h.ah = 0x0E;
X		int86(crt_int, &inregs, &outregs);
X		curregs.h.ah = 0x03;
X		curregs.h.bh = bgn_page;
X		int86(crt_int, &curregs, &outregs);
X		curcol = host_type == hIBMPC ? outregs.h.dl : outregs.h.dh;
X		while (curcol++ % P(P_TS)) int86(crt_int, &inregs, &outregs);
X		break;
X	case '\n':
X		if (host_type == hTIPRO) bios_t_el();
X		/* No break, fall through to default action. */
X	default:
X		inregs.h.ah = 0x0E;
X		inregs.h.bh = bgn_page;
X		inregs.h.al = c;
X		int86(crt_int, &inregs, &outregs);
X		break;
X	}
X}
X
X#else		/* Not BIOS */
X
X#define	BSIZE	2048
Xstatic	char	outbuf[BSIZE];
X
Xvoid
Xflushbuf()
X{
X	if (bpos != 0)
X		write(1, outbuf, bpos);
X	bpos = 0;
X}
X
X#endif
X
X
X/*
X * Macro to output a character. Used within this file for speed.
X *
X * This macro had to be upgraded for the BIOS-only version because we
X * cannot count on flushbuf() to execute control characters such as
X * end-of-line or tab.  Therefore, when we encounter one, we flush
X * the buffer and call a routine which executes the character.
X */
X
X#ifdef BIOS
X
X#define	outone(cc) {                 \
X  register char ch = cc;             \
X  if (ch >= ' ') {                   \
X    outbuf[bpos++] = ch;             \
X    if (bpos >= BSIZE) flushbuf();   \
X  } else write_tty(ch);              \
X}
X
X#else
X
X#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
X
X#endif
X
X/*
X * Function version for use outside this file.
X */
X
Xvoid
Xoutchar(c)
Xchar	c;
X{
X	outone(c);
X}
X
X/*
X * outstr(s) - write a string to the console
X */
X
Xvoid
Xoutstr(s)
Xchar	*s;
X{
X	while (*s) {
X		outone(*s++);
X	}
X}
X
Xvoid
Xbeep()
X{
X	if ( P(P_VB) )
X		vbeep();
X	else
X		outchar('\007');
X}
X
Xvbeep()		/* "Visual Bell" - reverse color flash */
X{
X	unsigned char oldcolor, revcolor, temp;
X
X	oldcolor = P(P_CO);
X
X	/* put reverse color in revcolor */
X	revcolor = (P(P_CO) & 0x07) << 4;	/* foregnd -> bkgnd */
X	temp     = (P(P_CO) & 0x70) >> 4;	/* bkgnd -> foregnd */
X	revcolor  |= temp;
X
X	/* Flash revcolor, then back */
X	setcolor (revcolor);
X	flushbuf();
X#ifdef TURBOC
X	delay (100);
X#endif
X	setcolor (oldcolor);
X	windgoto (Cursrow, Curscol);
X	flushbuf();
X}
X
X
X#ifndef TURBOC
Xsleep(n)
Xint	n;
X{
X	/*
X	 * Should do something reasonable here.
X	 */
X}
X#endif
X
Xvoid
Xpause()
X{
X	long	l;
X
X	flushbuf();
X
X#ifdef TURBOC
X	delay (600);	/* "stop" for a fraction of a second */
X#else
X	/*
X	 * Should do something better here...
X	 */
X	for (l=0; l < 5000 ;l++)
X		;
X#endif
X}
X
Xvoid
Xsig()
X{
X	signal(SIGINT, sig);
X
X	got_int = TRUE;
X}
X
Xstatic	char	schar;		/* save original switch character */
X
X/*	While Larry Shurr's addition of color and mode support was
X *	dependent on #define BIOS, there's no reason it needs to be.
X *	The BIOS is always there, even if NANSI.SYS isn't.  We'll
X *	use the BIOS where appropriate, and extend support to
X *	all cases of #define DOS.  This is especially true of the
X *	setup in windinit() and the termination in windexit().
X */
X
Xvoid
Xwindinit()
X{
X	union	REGS	regs;
X	struct	SREGS	sregs;
X
X	/* The "SYSROM..." string is a signature in the TI Pro's ROM which
X	 * which we can look for to determine whether or not we're running
X	 * on a TI Pro.  If we don't find it at F400:800D,
X	 * we assume we're running on an IBM PC or clone.
X	 * Unfortunately, the signature is actually
X	 * the system ROM's copyright notice though you will note that the
X	 * year is omitted.  Still, placing it in this program might
X	 * inadvertantly make it appear to be an official copyright notice
X	 * for THIS program.  Hence, I have surrounded the signature
X	 * string with disclaimers.
X	 */
X
X        static	char far *disclaimer1 =
X	  "The following is *NOT* a copyright notice for this program: ";
X
X	static	char far *ti_sig =
X          "SYSROM (c) Copyright Texas Instruments Inc.";
X
X	static	char far *disclaimer2[] = {
X	  "\nInstead, it is a signature string we look for ",
X	  "to distinguish the TI Pro computer.\n",
X	  "Actually, this program is in the public domain."
X	};
X
X	static char far	*ti_sig_addr = (char far *)0xF400800D;
X	static int ti_sig_len = sizeof(ti_sig) - 1;
X
X	/* Identify the host type.  Look for signature in TI Pro ROM.  If */
X	/* found, set host type to TI Pro, else assume host is an IBM PC. */
X
X	host_type = strncmp(ti_sig, ti_sig_addr, ti_sig_len) ? hIBMPC : hTIPRO;
X
X	/* Next, perform host-dependent initialization. */
X
X	switch (host_type) {
X	case hIBMPC:
X		/* Get the video mode info */
X		crt_int = 0x10;
X		regs.h.ah = 0x0F;
X		int86(crt_int, &regs, &regs);
X		bgn_page = regs.h.bh;
X		bgn_mode = regs.h.al;
X		Columns = regs.h.ah;
X		/*  Find the starting color, and save to restore later */
X		regs.h.ah = 8;		/* Read char/attr BIOS fn */
X		regs.h.bh = bgn_page;
X		int86(crt_int, &regs, &regs);
X		bgn_color = (int) regs.h.ah;
X		P(P_CO) = bgn_color;
X		break;
X	case hTIPRO:
X		Columns = 80;
X		crt_int = 0x49;
X		P(P_CO) = 0x0F;
X		break;
X
X	default:
X		Columns = 80;
X		break;
X	}
X
X	P(P_LI) = Rows = 25;
X
X	schar = getswitch();
X	setswitch('/');
X
X	signal(SIGINT, sig);
X#ifndef BIOS
X	setraw (1);
X#endif
X}
X
Xvoid
Xwindexit(r)
Xint r;
X{
X
X	union	REGS	regs;
X
X	quitting_now = 1;
X
X	/* Restore original color */
X	setcolor (bgn_color);
X
X	if (host_type == hIBMPC) {
X		/* If we've changed any of the setup, reset the mode.
X		 * Otherwise, leave stuff on the screen.
X		 */
X		regs.h.ah = 0x0F;	/* "Get-mode" BIOS fn */
X		int86(0x10, &regs, &regs);
X		if (bgn_mode != regs.h.al)
X			set_mode (bgn_mode);
X	}
X
X	flushbuf();
X	setswitch(schar);
X#ifndef BIOS
X	setraw(0);
X#endif
X	exit(r);
X}
X
X
X#ifndef BIOS
X/*	Setraw sets the console driver into raw mode, which makes it run
X *	somewhat faster.  Details of the function:
X *	If r=1, remember current mode, and set into raw mode.
X *	   r=0, return to the original mode.
X */
X
Xsetraw (r)
X  int	r;
X{
X	static int origr=0;	/* save the original r */
X	union REGS rr;
X
X	/* Do IOCTL call to get current control info */
X	rr.x.ax = 0x4400;	/* Read IOCTL info - DOS fn */
X	rr.x.bx = 1;		/* Handle for stdout */
X	intdos (&rr, &rr);
X
X	/* Save relevant info, and modify for "set" call */
X	if (r) {
X		origr = rr.h.dl & 0x20;		/* save current "raw" bit */
X		rr.h.dl = rr.h.dl | 0x20;	/* set "raw" bit */
X	}
X	else
X		rr.h.dl = (rr.h.dl & (~0x20)) | (origr & 0x20);
X
X	/* Do IOCTL call to set control info */
X	rr.x.ax = 0x4401;	/* Set IOCTL function call */
X	rr.x.bx = 1;		/* Handle for stdout */
X	rr.h.dh = 0;		/* DL already set up */
X	intdos (&rr, &rr);
X}
X#endif
X
X
Xvoid
Xwindgoto(r, c)				/* Move cursor to r'ow & c'olumn */
Xregister int	r, c;
X{
X#ifdef BIOS
X	union	REGS	inregs, outregs;
X
X	if (bpos > 0) flushbuf();
X
X	inregs.h.ah = 0x02;
X
X	switch (host_type) {
X	case hIBMPC :
X		inregs.h.bh = bgn_page;
X		inregs.h.dh = r;
X		inregs.h.dl = c;
X		break;
X	case hTIPRO:
X		inregs.h.dh = c;
X		inregs.h.dl = r;
X		break;
X	}
X
X	int86(crt_int, &inregs, &outregs);
X
X#else		/* Not BIOS */
X
X	r += 1;
X	c += 1;
X
X	/*
X	 * Check for overflow once, to save time.
X	 */
X	if (bpos + 8 >= BSIZE)
X		flushbuf();
X
X	outbuf[bpos++] = '\033';
X	outbuf[bpos++] = '[';
X	if (r >= 10)
X		outbuf[bpos++] = r/10 + '0';
X	outbuf[bpos++] = r%10 + '0';
X	outbuf[bpos++] = ';';
X	if (c >= 10)
X		outbuf[bpos++] = c/10 + '0';
X	outbuf[bpos++] = c%10 + '0';
X	outbuf[bpos++] = 'H';
X
X#endif
X}
X
XFILE *
Xfopenb(fname, mode)
Xchar	*fname;
Xchar	*mode;
X{
X	FILE	*fopen();
X	char	modestr[16];
X
X	sprintf(modestr, "%sb", mode);
X	return fopen(fname, modestr);
X}
X
Xstatic	char
Xgetswitch()
X{
X	union	REGS	inregs, outregs;
X
X	inregs.h.ah = 0x37;
X	inregs.h.al = 0;
X
X	intdos(&inregs, &outregs);
X
X	return outregs.h.dl;
X}
X
Xstatic	void
Xsetswitch(c)
Xchar	c;
X{
X	union	REGS	inregs, outregs;
X
X	inregs.h.ah = 0x37;
X	inregs.h.al = 1;
X	inregs.h.dl = c;
X
X	intdos(&inregs, &outregs);
X}
X
X#define	PSIZE	128
X
X/*
X * fixname(s) - fix up a dos name
X *
X * Takes a name like:
X *
X *	\x\y\z\base.ext
X *
X * and trims 'base' to 8 characters, and 'ext' to 3.
X */
Xchar *
Xfixname(s)
Xchar	*s;
X{
X	char	*strchr(), *strrchr();
X	static	char	f[PSIZE];
X	char	base[32];
X	char	ext[32];
X	char	*p;
X	int	i;
X
X	strcpy(f, s);
X
X	for (i=0; i < PSIZE ;i++)
X		if (f[i] == '/')
X			f[i] = '\\';
X
X	/*
X	 * Split the name into directory, base, extension.
X	 */
X	if ((p = strrchr(f, '\\')) != NULL) {
X		strcpy(base, p+1);
X		p[1] = '\0';
X	} else {
X		strcpy(base, f);
X		f[0] = '\0';
X	}
X
X	if ((p = strchr(base, '.')) != NULL) {
X		strcpy(ext, p+1);
X		*p = '\0';
X	} else
X		ext[0] = '\0';
X
X	/*
X	 * Trim the base name if necessary.
X	 */
X	if (strlen(base) > 8)
X		base[8] = '\0';
X
X	if (strlen(ext) > 3)
X		ext[3] = '\0';
X
X	/*
X	 * Paste it all back together
X	 */
X	strcat(f, base);
X	strcat(f, ".");
X	strcat(f, ext);
X
X	return f;
X}
X
Xvoid
Xdoshell(cmd)
Xchar	*cmd;
X{
X	if (cmd == NULL)
X		if ((cmd = getenv ("COMSPEC")) == NULL)
X			cmd = "command.com";
X
X	system(cmd);
X	wait_return();
X}
X
X
X/*
X *	setcolor (color)
X *	Set the screen attributes (basically, color) to value co.
X *	The color attributes for a DOS machine are the BIOS colors
X *	for text.  Where BIOS is not defined, we map the Escape
X *	sequences to the NANSI.SYS equivalents of the BIOS colors.
X */
X
Xsetcolor (color)
X  int	color;
X{
X#ifdef BIOS
X	P(P_CO) = host_type == hIBMPC ? color : ((color & 0x17) | 0x08);
X#else
X	unsigned char work;
X
X	/* Send the ANSI define-attribute sequence */
X	outone('\033');
X	outone('[');
X	outone('0');		/* Normal color */
X	outone(';');
X	/* BIOS-to-NANSI color conversion may look a little bizarre.
X	 * They have different bit orderings to represent the
X	 * color (BIOS=RGB, NANSI=BGR).
X	 *
X	 * First put the foreground color.
X	 */
X	work = 0;
X	if (color & 1)		work += 4;	/* Blue */
X	if (color & 2)		work += 2;	/* Green */
X	if (color & 4)		work += 1;	/* Red */
X	outone('3');		/* NANSI foreground starts at 30 */
X	outone(work + '0');
X	outone(';');
X	/*  Now the background color */
X	work = 0;
X	if (color & 0x10)	work += 4;	/* Blue */
X	if (color & 0x20)	work += 2;	/* Green */
X	if (color & 0x40)	work += 1;	/* Red */
X	outone('4');		/* NANSI background starts at 40 */
X	outone(work + '0');
X	/*  Do the intensity and blinking, if any  */
X	if (color & 8) {	/* intensity */
X		outone(';');
X		outone('1');
X	}
X	if (color & 0x80) {	/* blink */
X		outone(';');
X		outone('5');
X	}
X	/*  The 'm' suffix means "set graphic rendition"  */
X	outone('m');
X	P(P_CO) = color;
X
X#endif		/* Not BIOS */
X
X	if (!quitting_now) {
X		screenclear();
X		updatescreen();
X	}
X}
X
X
X/*	setrows (r)
X *	Sets the screen to "r" rows, or lines, where "r" is a feasible
X *	value for the IBM PC with some common display.  In this function:
X *   -	We set the mode to 25-line or 43-line mode, assuming the display
X *	supports the requested mode.
X *   -	We set the logical number of lines that Stevie uses to "r",
X *	so that the screen USED may not be the same as the physical screen.
X *
X *	The function returns the number of rows set.
X */
Xsetrows (r)
X  int r;
X{
X	int	rphys, rlog;	/* physical and logical "r" */
X
X	rphys = (r <= 25) ? 25 : 43 ;
X	rlog  = (r <= 50) ? r : 50;
X
X	/* Set the mode to correspond to the number of lines */
X	set_mode (rphys);
X
X	return (rlog);
X}
X
X
Xset_mode (m)
X  int m;
X{
X	set_25 ();
X	if (m == 43)
X		set_43 ();
X}
X
X#ifdef BIOS
X
Xint
Xset_25(lines)			/* Set display to 25 line mode */
Xint	lines;
X{
X	union	REGS	inregs, outregs;
X
X	switch (host_type) {
X	case hIBMPC:
X		inregs.h.ah = 0x00;
X		inregs.h.al = bgn_mode;
X		int86(crt_int, &inregs, &outregs);
X		break;
X	case hTIPRO:
X		windgoto(0, 0);
X		inregs.h.ah = 0x09;
X		inregs.h.al = ' ';
X		inregs.h.bl = P(P_CO);
X		inregs.x.cx = 80 * 25;
X		int86(crt_int, &inregs, &outregs);
X		if (lines > 25) lines = 25;
X		break;
X	}
X
X	return(lines);
X}
X
Xint
Xset_43(lines)			/* Set display to 43/50 line mode */
Xint	lines;
X{
X	union	REGS	inregs, outregs;
X
X	switch (host_type) {
X	case hIBMPC:
X		inregs.x.ax = 0x1112;
X		inregs.h.bl = 0;
X		int86(crt_int, &inregs, &outregs);
X		inregs.x.ax = 0x1200;
X		inregs.h.bl = 0x20;
X		int86(crt_int, &inregs, &outregs);
X		inregs.h.ah = 0x01;
X		inregs.x.cx = 0x0707;
X		int86(crt_int, &inregs, &outregs);
X		break;
X	case hTIPRO:
X		if (lines > 25) lines = 25;
X		break;
X	}
X
X	return(lines);
X}
X
X#else		/* Not BIOS */
X
Xset_25 ()
X{
X	send_setmode (bgn_mode);
X}
X
Xset_43 ()
X{
X	send_setmode (43);
X}
X
Xsend_setmode (m)
X{
X	outone('\033');
X	outone('[');
X
X	/* Convert 2-digit decimal to ASCII */
X	if (m >= 10)
X		outone( m/10 + '0' );
X	outone( m%10 + '0' );
X	outone ('h');
X}
X
X#endif		/* Not BIOS */
X
X#ifdef BIOS
X/*
X *	The rest of the file is BIOS-specific
X */
X
Xvoid
Xbios_t_ci()				/* Make cursor invisible */
X{
X	union	REGS	inregs, outregs;
X
X	if (sav_curattr == 0) {
X		inregs.h.ah = 0x03;
X		inregs.h.bh = bgn_page;
X		int86(crt_int, &inregs, &outregs);
X		sav_curattr = outregs.x.cx;
X		inregs.h.ah = 0x01;
X		inregs.x.cx = 0x2000;
X		int86(crt_int, &inregs, &outregs);
X	}
X}
X
Xvoid
Xbios_t_cv()				/* Make cursor visible */
X{
X	union	REGS	inregs, outregs;
X
X	if (sav_curattr != 0) {
X		inregs.h.ah = 0x01;
X		inregs.h.bh = bgn_page;
X		inregs.x.cx = sav_curattr;
X		int86(crt_int, &inregs, &outregs);
X		sav_curattr = 0;
X	}
X}
X
X/*
X * O.K., I have tried to keep bios.c as "pure" as possible. I.e., I have used
X * BIOS calls for everything instead of going for all-out speed by using
X * direct-video access for updating the display - after all, I named it this
X * module bios.c.  There is one area, however, where using the BIOS is just
X * too much of a compromise... the TI Pro's "scroll display" functions are so
X * slow and ugly that I hate them.  True, they are very flexible, but their
X * poor on-screen appearance and low performance are a liability - you prob-
X * ably think I'm exaggerating, but you're wrong - it is truly bad.  There-
X * fore, I am bypassing them and scrolling the screen myself; something I
X * nearly always do.  From a purist like me, that really says something.
X */
X
Xvoid
Xbios_t_dl(r,l)				/* Delete lines */
Xint r, l;
X{
X	char	far	*end;		/* End ptr for TI Pro screen */
X	char	far	*dst;		/* Dest ptr for scrolling TI Pro scrn */
X	char	far	*src;		/* Src  ptr for scrolling TI Pro scrn */
X
X	union	REGS	inregs, outregs;
X
X	switch (host_type) {
X	case hIBMPC:
X		inregs.h.ah = 0x06;
X		inregs.h.al = l;
X		inregs.h.bh = P(P_CO);
X		inregs.h.ch = r;
X		inregs.h.cl = 0;
X		inregs.h.dh = Rows - 1;
X		inregs.h.dl = Columns - 1;
X		int86(crt_int, &inregs, &outregs);
X		break;
X	case hTIPRO:
X		inregs.h.ah = 0x17;
X		int86(crt_int, &inregs, &outregs);
X		dst = MK_FP(0xDE00, outregs.x.dx + (r * Columns));
X		src = dst + (l * Columns);
X		end = MK_FP(0xDE00, outregs.x.dx + ((Rows - 1) * Columns));
X		while (src < end) *dst++ = *src++;
X		while (dst < end) *dst++ = ' ';
X		break;
X	}
X}
X
Xvoid
Xbios_t_ed()				/* Home cursor, erase display */
X{
X	union	REGS	inregs, outregs;
X
X	windgoto(0, 0);
X
X	inregs.h.ah = 0x09;
X	inregs.h.al = ' ';
X	inregs.h.bh = bgn_page;
X	inregs.h.bl = P(P_CO);
X	inregs.x.cx = Columns * Rows;
X	int86(crt_int, &inregs, &outregs);
X}
X
Xvoid
Xbios_t_el()				/* Erase to end-of-line */
X{
X	short	ccol;
X
X	union	REGS	inregs, outregs;
X
X	inregs.h.ah = 0x03;
X	inregs.h.bh = bgn_page;
X	int86(crt_int, &inregs, &outregs);
X
X	inregs.h.ah = 0x09;
X	inregs.h.al = ' ';
X	inregs.h.bl = P(P_CO);
X
X	ccol = host_type == hIBMPC ? outregs.h.dl : outregs.h.dh;
X
X	inregs.x.cx = Columns - ccol;
X	int86(crt_int, &inregs, &outregs);
X}
X
X/* As in the delete-line function, we scroll the TI display ourselves
X * rather than the use the slow-and-ugly software scroll in the BIOS.  See
X * the remarks for bios_t_dl() additional information.
X */
X
Xvoid
Xbios_t_il(r,l)				/* Insert lines */
Xint r, l;
X{
X	char	far	*end;		/* End ptr for TI Pro screen */
X	char	far	*dst;		/* For scrolling TI Pro screen */
X	char	far	*src;		/* For scrolling TI Pro screen */
X
X	union	REGS	inregs, outregs;
X
X	switch (host_type) {
X	case hIBMPC:
X		inregs.h.ah = 0x07;
X		inregs.h.al = l;
X		inregs.h.bh = P(P_CO);
X		inregs.h.ch = r;
X		inregs.h.cl = 0;
X		inregs.h.dh = Rows - 1;
X		inregs.h.dl = Columns - 1;
X		int86(crt_int, &inregs, &outregs);
X		break;
X	case hTIPRO:
X		inregs.h.ah = 0x17;
X		int86(crt_int, &inregs, &outregs);
X		dst = MK_FP(0xDE00, outregs.x.dx + (Columns * (Rows - 1)) - 1);
X		src = dst - (Columns * l);
X		end = MK_FP(0xDE00, outregs.x.dx + (Columns * r));
X		while (src >= end) *dst-- = *src--;
X		src = MK_FP(0xDE00, outregs.x.dx + (r * Columns));
X		end = src + (l * Columns);
X		while (src < end) *src++ = ' ';
X		break;
X	}
X}
X
Xvoid
Xbios_t_rc()				/* Restore saved cursor position */
X{
X	union	REGS	inregs, outregs;
X
X	inregs.h.ah = 0x02;
X	inregs.h.bh = bgn_page;
X	inregs.x.dx = sav_curpos;
X	int86(crt_int, &inregs, &outregs);
X}
X
Xvoid
Xbios_t_sc()				/* Save cursor position */
X{
X	union	REGS	inregs, outregs;
X
X	inregs.h.ah = 0x03;
X	inregs.h.bh = bgn_page;
X	int86(crt_int, &inregs, &outregs);
X	sav_curpos = outregs.x.dx;
X}
X
X#endif
X
!EOR!
echo extracting - minix.c
sed 's/^X//' > minix.c << '!EOR!'
X/* $Header: /nw/tony/src/stevie/src/RCS/minix.c,v 1.5 89/07/11 21:24:18 tony Exp $
X *
X * System-dependent routines for Minix-ST
X */
X
X#include "stevie.h"
X#include <sgtty.h>
X#include <signal.h>
X
X/*
X * inchar() - get a character from the keyboard
X */
Xint
Xinchar()
X{
X	char	c;
X
X	flushbuf();		/* flush any pending output */
X
X	while (read(0, &c, 1) != 1)
X		;
X
X	got_int = FALSE;
X	return c;
X}
X
X#define	BSIZE	2048
Xstatic	char	outbuf[BSIZE];
Xstatic	int	bpos = 0;
X
Xvoid
Xflushbuf()
X{
X	if (bpos != 0)
X		write(1, outbuf, bpos);
X	bpos = 0;
X}
X
X/*
X * Macro to output a character. Used within this file for speed.
X */
X#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
X
X/*
X * Function version for use outside this file.
X */
Xvoid
Xoutchar(c)
Xregister char	c;
X{
X	outbuf[bpos++] = c;
X	if (bpos >= BSIZE)
X		flushbuf();
X}
X
Xvoid
Xoutstr(s)
Xregister char	*s;
X{
X	while (*s) {
X		outone(*s++);
X	}
X}
X
Xvoid
Xbeep()
X{
X	if ( P(P_VB) )
X		vbeep();
X	else
X		outone('\007');
X}
X
X/*
X * remove(file) - remove a file
X */
Xvoid
Xremove(file)
Xchar *file;
X{
X	unlink(file);
X}
X
X/*
X * rename(of, nf) - rename existing file 'of' to 'nf'
X */
Xvoid
Xrename(of, nf)
Xchar	*of, *nf;
X{
X	unlink(nf);
X	link(of, nf);
X	unlink(of);
X}
X
Xvoid
Xpause()
X{
X	sleep (1);
X}
X
Xstatic	struct	sgttyb	ostate;
X
X/*
X * Go into cbreak mode
X */
Xvoid
Xset_tty()
X{
X	struct	sgttyb	nstate;
X
X	 ioctl(0, TIOCGETP, &ostate);
X	 nstate = ostate;
X	 nstate.sg_flags &= ~(XTABS|ECHO);
X	 nstate.sg_flags |= CBREAK;
X	 ioctl(0, TIOCSETP, &nstate);
X}
X
X/*
X * Restore original terminal modes
X */
Xvoid
Xreset_tty()
X{
X	ioctl(0, TIOCSETP, &ostate);
X}
X
Xvoid
Xsig()
X{
X	signal(SIGINT, sig);
X	signal(SIGQUIT, sig);
X
X	got_int = TRUE;
X}
X
Xvoid
Xwindinit()
X{
X#ifdef	TERMCAP
X	if (t_init() != 1) {
X		fprintf(stderr, "unknown terminal type\n");
X		exit(1);
X	}
X#else
X	Columns = 80;
X	P(P_LI) = Rows = 25;
X#endif
X	/*
X	 * The code here makes sure that there isn't a window during which
X	 * we could get interrupted and exit with the tty in a weird state.
X	 */
X	signal(SIGINT, sig);
X	signal(SIGQUIT, sig);
X
X	set_tty();
X
X	if (got_int)
X		windexit(0);
X}
X
Xvoid
Xwindexit(r)
Xint r;
X{
X	reset_tty();
X	exit(r);
X}
X
Xvoid
Xwindgoto(r, c)
Xregister int	r, c;
X{
X#ifdef	TERMCAP
X	char	*tgoto();
X#else
X	r += 1;
X	c += 1;
X#endif
X
X	/*
X	 * Check for overflow once, to save time.
X	 */
X	if (bpos + 8 >= BSIZE)
X		flushbuf();
X
X#ifdef	TERMCAP
X	outstr(tgoto(T_CM, c, r));
X#else
X	outbuf[bpos++] = '\033';
X	outbuf[bpos++] = '[';
X	if (r >= 10)
X		outbuf[bpos++] = r/10 + '0';
X	outbuf[bpos++] = r%10 + '0';
X	outbuf[bpos++] = ';';
X	if (c >= 10)
X		outbuf[bpos++] = c/10 + '0';
X	outbuf[bpos++] = c%10 + '0';
X	outbuf[bpos++] = 'H';
X#endif
X}
X
XFILE *
Xfopenb(fname, mode)
Xchar	*fname;
Xchar	*mode;
X{
X	return fopen(fname, mode);
X}
X
Xchar *
Xstrchr(s, c)
Xchar	*s;
Xchar	c;
X{
X	char *index();
X
X	return index(s, c);
X}
X
Xchar *
Xfixname(s)
Xchar	*s;
X{
X	return s;
X}
X
X/*
X * doshell() - run a command or an interactive shell
X */
Xvoid
Xdoshell(cmd)
Xchar	*cmd;
X{
X	char	*cp, *getenv();
X	char	cline[128];
X
X	outstr("\r\n");
X	flushbuf();
X
X	if (cmd == NULL) {
X		if ((cmd = getenv("SHELL")) == NULL)
X			cmd = "/bin/sh";
X		sprintf(cline, "%s -i", cmd);
X		cmd = cline;
X	}
X
X	reset_tty();
X	system(cmd);
X	set_tty();
X
X	wait_return();
X}
X
X/*
X *	FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT!
X *
X *	The next couple of functions do system-specific stuff.
X *	They currently do nothing; I'm not familiar enough with
X *	system-specific programming on this system.
X *	If you fill it in for your system, please post the results
X *	and share with the rest of us.
X */
X
X
Xsetcolor (c)
X/*
X * Set the color to c, using the local system convention for numbering
X * colors or video attributes.
X *
X * If you implement this, remember to note the original color in
X * windinit(), before you do any setcolor() commands, and
X * do a setcolor() back to the original as part of windexit().
X */
X  int c:
X{
X}
X
X
Xsetrows (r)
X/*
X * Set the number of lines to r, if possible.  Otherwise
X * "do the right thing".  Return the number of lines actually set.
X *
X * If you implement this, remember to note the original number of rows
X * in windinit(), before you do any setrows() commands, and
X * do a setrows() back to the original as part of windexit().
X */
X  int r;
X{
X	/* Since we do nothing, just return the current number of lines */
X	return ( P(P_LI) );
X}
X
X
Xvbeep ()
X/*
X * Do a "visual bell".  This generally consists of flashing the screen
X * once in inverse video.
X */
X{
X	int	color, revco;
X
X	color = P( P_CO );		/* get current color */
X	revco = reverse_color (color);	/* system-specific */
X	setcolor (revco);
X	flushbuf ();
X	pause ();
X	setcolor (color);
X	windgoto (Cursrow, Curscol);
X	flushbuf ();
X}
X
Xreverse_color (co)
X/*
X * Returns the inverse video attribute or color of co.
X * The existing code below is VERY simple-minded.
X * Replace it with proper code for your system.
X */
X int co;
X{
X	if (co)		return (0);
X	else		return (1);
X}
X
X
X/********** End of do-it-yourself kit **********************/
X
!EOR!
echo extracting - os2.c
sed 's/^X//' > os2.c << '!EOR!'
X/* $Header: /nw/tony/src/stevie/src/RCS/os2.c,v 1.7 89/08/07 05:49:19 tony Exp $
X *
X * OS/2 System-dependent routines.
X */
X
X#define	INCL_BASE
X#include <os2.h>
X#include <signal.h>
X#include "stevie.h"
X
X/*
X * inchar() - get a character from the keyboard
X */
Xint
Xinchar()
X{
X	register int	c;
X
X	got_int = FALSE;
X
X	for (;;beep()) {	/* loop until we get a valid character */
X
X		flushbuf();	/* flush any pending output */
X
X		switch (c = getch()) {
X		case 0x1e:
X			return K_CCIRCM;
X		case 0:				/* special key */
X			if (State != NORMAL) {
X				c = getch();	/* throw away next char */
X				continue;	/* and loop for another char */
X			}
X			switch (c = getch()) {
X			case 0x50:
X				return K_DARROW;
X			case 0x48:
X				return K_UARROW;
X			case 0x4b:
X				return K_LARROW;
X			case 0x4d:
X				return K_RARROW;
X			case 0x52:
X				return K_INSERT;
X			case 0x47:		/* Home key */
X				stuffin("1G");
X				return -1;
X			case 0x4f:		/* End key */
X				stuffin("G");
X				return -1;
X			case 0x51:		/* PgDn key */
X				stuffin(mkstr(CTRL('F')));
X				return -1;
X			case 0x49:		/* PgUp key */
X				stuffin(mkstr(CTRL('B')));
X				return -1;
X			case 0x52:		/* insert key */
X				return K_INSERT;
X			case 0x53:		/* delete key */
X				stuffin("x");
X				return -1;
X			/*
X			 * Hard-code some useful function key macros.
X			 */
X			case 0x3b: /* F1 */
X				stuffin(":help\n");
X				return -1;
X			case 0x3c: /* F2 */
X				stuffin(":n\n");
X				return -1;
X			case 0x55: /* SF2 */
X				stuffin(":n!\n");
X				return -1;
X			case 0x3d: /* F3 */
X				stuffin(":N\n");
X				return -1;
X			case 0x56: /* SF3 */
X				stuffin(":N!\n");
X				return -1;
X			case 0x3e: /* F4 */
X				stuffin(":e #\n");
X				return -1;
X			case 0x57: /* SF4 */
X				stuffin(":e! #\n");
X				return -1;
X			case 0x3f: /* F5 */
X				stuffin(":rew\n");
X				return -1;
X			case 0x58: /* SF5 */
X				stuffin(":rew!\n");
X				return -1;
X			case 0x40: /* F6 */
X				stuffin("]]");
X				return -1;
X			case 0x59: /* SF6 */
X				stuffin("[[");
X				return -1;
X			case 0x42: /* F8 - Set up global substitute */
X				stuffin(":1,$s/");
X				return -1;
X			case 0x43: /* F9 - declare C variable */
X				stuffin("yyp!!cdecl\n");
X				return -1;
X			case 0x5C: /* SF9 - explain C declaration */
X				stuffin("yyp^iexplain \033!!cdecl\n");
X				return -1;
X			case 0x44: /* F10 - save & quit */
X				stuffin(":x\n");
X				return -1;
X			case 0x5D: /* F10 - quit without saving */
X				stuffin(":q!\n");
X				return -1;
X			default:
X				break;
X			}
X			break;
X
X		default:
X			return c;
X		}
X	}
X}
X
X#define	BSIZE	2048
Xstatic	char	outbuf[BSIZE];
Xstatic	int	bpos = 0;
X
Xvoid
Xflushbuf()
X{
X	if (bpos != 0)
X		write(1, outbuf, bpos);
X	bpos = 0;
X}
X
X/*
X * Macro to output a character. Used within this file for speed.
X */
X#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
X
X/*
X * Function version for use outside this file.
X */
Xvoid
Xoutchar(c)
Xregister char	c;
X{
X	outbuf[bpos++] = c;
X	if (bpos >= BSIZE)
X		flushbuf();
X}
X
Xstatic	char	cell[2] = { 0, 7 };
X
X/*
X * outstr(s) - write a string to the console
X *
X * We implement insert/delete line escape sequences here. This is kind
X * of a kludge, but at least it's localized to a single point.
X */
Xvoid
Xoutstr(s)
Xregister char	*s;
X{
X	if (strcmp(s, T_DL) == 0) {		/* delete line */
X		int	r, c;
X
X		flushbuf();
X		VioGetCurPos(&r, &c, 0);
X		VioScrollUp(r, 0, 100, 100, 1, cell, 0);
X		return;
X	}
X	if (strcmp(s, T_IL) == 0) {		/* insert line */
X		int	r, c;
X
X		flushbuf();
X		VioGetCurPos(&r, &c, 0);
X		VioScrollDn(r, 0, 100, 100, 1, cell, 0);
X		return;
X	}
X
X	while (*s) {
X		outone(*s++);
X	}
X}
X
Xvoid
Xbeep()
X{
X	in ( P(P_VB) )
X		vbeep();
X	else
X		outone('\007');
X}
X
Xsleep(n)
Xint	n;
X{
X	DosSleep(1000L * n);
X}
X
Xvoid
Xpause()
X{
X	flushbuf();
X	DosSleep(300L);
X}
X
Xvoid
Xsig()
X{
X	signal(SIGINT, sig);
X
X	got_int = TRUE;
X}
X
Xvoid
Xwindinit()
X{
X	Columns = 80;
X	P(P_LI) = Rows = 25;
X
X	signal(SIGINT, sig);
X}
X
Xvoid
Xwindexit(r)
Xint r;
X{
X	flushbuf();
X	exit(r);
X}
X
Xvoid
Xwindgoto(r, c)
Xregister int	r, c;
X{
X	r += 1;
X	c += 1;
X
X	/*
X	 * Check for overflow once, to save time.
X	 */
X	if (bpos + 8 >= BSIZE)
X		flushbuf();
X
X	outbuf[bpos++] = '\033';
X	outbuf[bpos++] = '[';
X	if (r >= 10)
X		outbuf[bpos++] = r/10 + '0';
X	outbuf[bpos++] = r%10 + '0';
X	outbuf[bpos++] = ';';
X	if (c >= 10)
X		outbuf[bpos++] = c/10 + '0';
X	outbuf[bpos++] = c%10 + '0';
X	outbuf[bpos++] = 'H';
X}
X
XFILE *
Xfopenb(fname, mode)
Xchar	*fname;
Xchar	*mode;
X{
X	FILE	*fopen();
X	char	modestr[16];
X
X	sprintf(modestr, "%sb", mode);
X	return fopen(fname, modestr);
X}
X
X#define	PSIZE	128
X
X/*
X * fixname(s) - fix up a dos name
X *
X * Takes a name like:
X *
X *	\x\y\z\base.ext
X *
X * and trims 'base' to 8 characters, and 'ext' to 3.
X */
Xchar *
Xfixname(s)
Xchar	*s;
X{
X	char	*strchr(), *strrchr();
X	static	char	f[PSIZE];
X	char	base[32];
X	char	ext[32];
X	char	*p;
X	int	i;
X
X	strcpy(f, s);
X
X	for (i=0; i < PSIZE ;i++)
X		if (f[i] == '/')
X			f[i] = '\\';
X
X	/*
X	 * Split the name into directory, base, extension.
X	 */
X	if ((p = strrchr(f, '\\')) != NULL) {
X		strcpy(base, p+1);
X		p[1] = '\0';
X	} else {
X		strcpy(base, f);
X		f[0] = '\0';
X	}
X
X	if ((p = strchr(base, '.')) != NULL) {
X		strcpy(ext, p+1);
X		*p = '\0';
X	} else
X		ext[0] = '\0';
X
X	/*
X	 * Trim the base name if necessary.
X	 */
X	if (strlen(base) > 8)
X		base[8] = '\0';
X	
X	if (strlen(ext) > 3)
X		ext[3] = '\0';
X
X	/*
X	 * Paste it all back together
X	 */
X	strcat(f, base);
X	strcat(f, ".");
X	strcat(f, ext);
X
X	return f;
X}
X
Xvoid
Xdoshell(cmd)
Xchar	*cmd;
X{
X	if (cmd == NULL)
X		cmd = "cmd.exe";
X
X	system(cmd);
X	wait_return();
X}
X
X/*
X *	FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT!
X *
X *	The next couple of functions do system-specific stuff.
X *	They currently do nothing; I'm not familiar enough with
X *	system-specific programming on this system.
X *	If you fill it in for your system, please post the results
X *	and share with the rest of us.
X */
X
X
Xsetcolor (c)
X/*
X * Set the color to c, using the local system convention for numbering
X * colors or video attributes.
X *
X * If you implement this, remember to note the original color in
X * windinit(), before you do any setcolor() commands, and
X * do a setcolor() back to the original as part of windexit().
X */
X  int c:
X{
X}
X
X
Xsetrows (r)
X/*
X * Set the number of lines to r, if possible.  Otherwise
X * "do the right thing".  Return the number of lines actually set.
X *
X * If you implement this, remember to note the original number of rows
X * in windinit(), before you do any setrows() commands, and
X * do a setrows() back to the original as part of windexit().
X */
X  int r;
X{
X	/* Since we do nothing, just return the current number of lines */
X	return ( P(P_LI) );
X}
X
X
Xvbeep ()
X/*
X * Do a "visual bell".  This generally consists of flashing the screen
X * once in inverse video.
X */
X{
X	int	color, revco;
X
X	color = P( P_CO );		/* get current color */
X	revco = reverse_color (color);	/* system-specific */
X	setcolor (revco);
X	flushbuf ();
X	pause ();
X	setcolor (color);
X	windgoto (Cursrow, Curscol);
X	flushbuf ();
X}
X
Xreverse_color (co)
X/*
X * Returns the inverse video attribute or color of co.
X * The existing code below is VERY simple-minded.
X * Replace it with proper code for your system.
X */
X int co;
X{
X	if (co)		return (0);
X	else		return (1);
X}
X
X
X/********** End of do-it-yourself kit **********************/
X
!EOR!
echo extracting - unix.c
sed 's/^X//' > unix.c << '!EOR!'
X/* $Header: /nw/tony/src/stevie/src/RCS/unix.c,v 1.8 89/08/06 09:51:13 tony Exp $
X *
X * System-dependent routines for UNIX System V or Berkeley.
X */
X
X#include "stevie.h"
X#ifdef BSD
X#include <sgtty.h>
X#else
X#include <termio.h>
X#endif
X#include <signal.h>
X
X/*
X * inchar() - get a character from the keyboard
X */
Xint
Xinchar()
X{
X	char	c;
X
X	flushbuf();		/* flush any pending output */
X
X	do {
X		while (read(0, &c, 1) != 1)
X			;
X	} while (c == NUL);
X
X	got_int = FALSE;
X	return c;
X}
X
X#define	BSIZE	2048
Xstatic	char	outbuf[BSIZE];
Xstatic	int	bpos = 0;
X
Xvoid
Xflushbuf()
X{
X	if (bpos != 0)
X		write(1, outbuf, bpos);
X	bpos = 0;
X}
X
X/*
X * Macro to output a character. Used within this file for speed.
X */
X#define	outone(c)	outbuf[bpos++] = c; if (bpos >= BSIZE) flushbuf()
X
X/*
X * Function version for use outside this file.
X */
Xvoid
Xoutchar(c)
Xchar	c;
X{
X	outone(c);
X}
X
Xvoid
Xoutstr(s)
Xregister char	*s;
X{
X	while (*s) {
X		outone(*s++);
X	}
X}
X
Xvoid
Xbeep()
X{
X	if ( P(P_VB) )
X		vbeep ();
X	else
X		outone('\007');
X}
X
X/*
X * remove(file) - remove a file
X */
Xvoid
Xremove(file)
Xchar *file;
X{
X	unlink(file);
X}
X
X/*
X * rename(of, nf) - rename existing file 'of' to 'nf'
X */
Xvoid
Xrename(of, nf)
Xchar	*of, *nf;
X{
X	unlink(nf);
X	link(of, nf);
X	unlink(of);
X}
X
Xvoid
Xpause()
X{
X	sleep (1);
X}
X
X#ifdef BSD
Xstatic	struct	sgttyb	ostate;
X#else
Xstatic	struct	termio	ostate;
X#endif
X
X/*
X * Go into cbreak mode
X */
Xvoid
Xset_tty()
X{
X#ifdef BSD
X	struct	sgttyb	nstate;
X
X	ioctl(0, TIOCGETP, &ostate);
X	nstate = ostate;
X	nstate.sg_flags &= ~(XTABS|CRMOD|ECHO);
X	nstate.sg_flags |= CBREAK;
X	ioctl(0, TIOCSETN, &nstate);
X#else
X	struct	termio	nstate;
X
X	ioctl(0, TCGETA, &ostate);
X	nstate = ostate;
X	nstate.c_lflag &= ~(ICANON|ECHO|ECHOE|ECHOK|ECHONL);
X	nstate.c_cc[VMIN] = 1;
X	nstate.c_cc[VTIME] = 0;
X	ioctl(0, TCSETAW, &nstate);
X#endif
X}
X
X/*
X * Restore original terminal modes
X */
Xvoid
Xreset_tty()
X{
X#ifdef BSD
X	ioctl(0, TIOCSETP, &ostate);
X#else
X	ioctl(0, TCSETAW, &ostate);
X#endif
X}
X
Xvoid
Xsig()
X{
X	signal(SIGINT, sig);
X	signal(SIGQUIT, sig);
X
X	got_int = TRUE;
X}
X
Xvoid
Xwindinit()
X{
X#ifdef	TERMCAP
X	if (t_init() != 1) {
X		fprintf(stderr, "unknown terminal type\n");
X		exit(1);
X	}
X#else
X	Columns = 80;
X	P(P_LI) = Rows = 24;
X#endif
X
X	/*
X	 * The code here makes sure that there isn't a window during which
X	 * we could get interrupted and exit with the tty in a weird state.
X	 */
X	signal(SIGINT, sig);
X	signal(SIGQUIT, sig);
X
X	set_tty();
X
X	if (got_int)
X		windexit(0);
X}
X
Xvoid
Xwindexit(r)
Xint r;
X{
X	reset_tty();
X	exit(r);
X}
X
Xvoid
Xwindgoto(r, c)
Xregister int	r, c;
X{
X#ifdef	TERMCAP
X	char	*tgoto();
X#else
X	r += 1;
X	c += 1;
X#endif
X
X	/*
X	 * Check for overflow once, to save time.
X	 */
X	if (bpos + 8 >= BSIZE)
X		flushbuf();
X
X#ifdef	TERMCAP
X	outstr(tgoto(T_CM, c, r));
X#else
X	outbuf[bpos++] = '\033';
X	outbuf[bpos++] = '[';
X	if (r >= 10)
X		outbuf[bpos++] = r/10 + '0';
X	outbuf[bpos++] = r%10 + '0';
X	outbuf[bpos++] = ';';
X	if (c >= 10)
X		outbuf[bpos++] = c/10 + '0';
X	outbuf[bpos++] = c%10 + '0';
X	outbuf[bpos++] = 'H';
X#endif
X}
X
XFILE *
Xfopenb(fname, mode)
Xchar	*fname;
Xchar	*mode;
X{
X	return fopen(fname, mode);
X}
X
Xchar *
Xfixname(s)
Xchar	*s;
X{
X	return s;
X}
X
X/*
X * doshell() - run a command or an interactive shell
X */
Xvoid
Xdoshell(cmd)
Xchar	*cmd;
X{
X	char	*getenv();
X	char	cline[128];
X
X	outstr("\r\n");
X	flushbuf();
X
X	if (cmd == NULL) {
X		if ((cmd = getenv("SHELL")) == NULL)
X			cmd = "/bin/sh";
X		sprintf(cline, "%s -i", cmd);
X		cmd = cline;
X	}
X
X	reset_tty();
X	system(cmd);
X	set_tty();
X
X	wait_return();
X}
X
X
X/*
X *	FILL IT IN, FOR YOUR SYSTEM, AND SHARE IT!
X *
X *	The next couple of functions do system-specific stuff.
X *	They currently do nothing; I'm not familiar enough with
X *	system-specific programming on this system.
X *	If you fill it in for your system, please post the results
X *	and share with the rest of us.
X */
X
X
Xsetcolor (c)
X/*
X * Set the color to c, using the local system convention for numbering
X * colors or video attributes.
X *
X * If you implement this, remember to note the original color in
X * windinit(), before you do any setcolor() commands, and
X * do a setcolor() back to the original as part of windexit().
X */
X  int c;
X{
X	/* Dummy routine, just return 0 */
X	return (0);
X}
X
X
Xsetrows (r)
X/*
X * Set the number of lines to r, if possible.  Otherwise
X * "do the right thing".  Return the number of lines actually set.
X *
X * If you implement this, remember to note the original number of rows
X * in windinit(), before you do any setrows() commands, and
X * do a setrows() back to the original as part of windexit().
X */
X  int r;
X{
X	/* Since we do nothing, just return the current number of lines */
X	return ( P(P_LI) );
X}
X
X
Xvbeep ()
X/*
X * Do a "visual bell".  This generally consists of flashing the screen
X * once in inverse video.
X */
X{
X	int	color, revco;
X
X	color = P( P_CO );		/* get current color */
X	revco = reverse_color (color);	/* system-specific */
X	setcolor (revco);
X	flushbuf ();
X	pause ();
X	setcolor (color);
X	windgoto (Cursrow, Curscol);
X	flushbuf ();
X}
X
Xreverse_color (co)
X/*
X * Returns the inverse video attribute or color of co.
X * The existing code below is VERY simple-minded.
X * Replace it with proper code for your system.
X */
X int co;
X{
X	if (co)		return (0);
X	else		return (1);
X}
X
X
X/********** End of do-it-yourself kit **********************/
!EOR!
echo extracting - setenv.c
sed 's/^X//' > setenv.c << '!EOR!'
X/*****************************************************************************
X * A program for adding or changing environment variable values for MSDOS.
X * The "set" command provided by command.com is very limited.  It fails to
X * provide the ability to use quotation marks and escape characters and
X * octal/hex constants in the value definition.  Setenv provides these
X * abilities.
X *
X * Usage notes:
X *
X *	setenv <symbol> = <value>
X *
X *	<symbol> ::= legal MSDOS environment symbol.  Lower case converted
X *		     to uppercase.
X *
X *	<value>  ::= environment symbol value in one of three forms:
X *
X *		     * No quotation marks.  The value is the literal string
X *		       of characters starting IMMEDIATELY after the equal
X *		       sign and extending to the end-of-line.
X *
X *		     * Single quotation marks (').  The value is the literal
X *		       string enclosed in quotation marks.
X *
X *		     * Double quotation marks (").  The value is the string
X *		       enclosed in double quotation marks.  Backslash escape
X *		       constructions are processed -- this includes the usual
X *		       C language constructions such as \n for newline and
X *		       \r for carriage return plus octal and hexadecimal
X *		       constants (\ddd & \0xdd, respectively).
X *****************************************************************************/
X
X/*****************************************************************************
X * Based on a program by Alan J Myrvold (ajmyrvold@violet.waterloo.edu)
X *
X * WARNING WARNING WARNING - virtually no error checking is done !!
X *                           use at own risk !!
X *
X * This program by Larry A. Shurr (las@cbema.ATT.COM)
X *
X * I added checking for env seg overrun, so now it's a little more robust.
X *****************************************************************************/
X
X/*****************************************************************************
X *
X * Notes by Alan J Myrgold:
X *
X * Technical information : A program's PSP contains a pointer at
X * offset 44 (decimal) to a COPY of the parent's environment.
X * The environment is a set of strings of the form NAME=value,
X * each terminated by a NULL byte.
X * An additional NULL byte marks the end of the environment.
X * The environment area is ALWAYS paragraph aligned
X * i.e. on a 16 byte boundary.
X *
X * Searching backwards from the PSP, I consistently find
X * two copies of the envronment area.
X *
X * The program : finds the two areas
X *               reads one into memory
X *               udpates the specified environment variable
X *               writes updated environment to parent environment
X *****************************************************************************/
X
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <time.h>
X#include <process.h>
X#include <conio.h>
X#include <dos.h>
X
X#define FALSE 0
X#define TRUE  1
X
Xstruct mcb {				/* MSDOS Memory Control Block */
X  unsigned char tag4D;			/* Tag field must = 0x4D */
X  unsigned int  next;			/* Segment base for next block */
X  unsigned int  size;			/* Memory block size in paragraphs */
X};
X
X
Xunsigned env_size = 0;			/* Maintain size of environment */
X/***************************************************************************/
Xint env_size_bytes(unsigned env_seg)
X/* Determine the length of the environment area in bytes */
X{
X    int n;
X
X    n = 0;
X    while (peekb(env_seg,n) != 0) {
X          while (peekb(env_seg,n) != 0) n++;
X          n++;
X    }
X    return(n);
X}
X/***************************************************************************/
Xint env_size_strings(unsigned env_seg)
X/* Determine how many strings are in the environment area */
X{
X    int k,n;
X
X    k = n = 0;
X    while (peekb(env_seg,n) != 0) {
X          k++;
X          while (peekb(env_seg,n) != 0) n++;
X          n++;
X    }
X    return(k);
X}
X/***************************************************************************/
Xint peek_cmp(unsigned seg1,unsigned seg2,int nbytes)
X/* A trivial compare routine for segement aligned data items */
X{
X   int i;
X
X   for (i = 0; (i < nbytes) && (peekb(seg1,i) == peekb(seg2,i)); i++);
X   return(i == nbytes);
X}
X/***************************************************************************/
Xvoid find_env(unsigned seg_ray[2])
X{
X    unsigned psp_seg,copy_of_seg,env_seg;
X    int k,n;
X
X/* Find first copy of environment */
X    psp_seg = _psp;
X    copy_of_seg = peek(psp_seg,44);
X
X/* Set return value to non-garabage */
X    seg_ray[0] = seg_ray[1] = copy_of_seg;
X
X/* Search back to find 2 copies of environment */
X    env_size = n = env_size_bytes(copy_of_seg);
X    env_seg = copy_of_seg - 1;
X    for (k = 0; (env_seg != 0) && (k < 2); k++) {
X          while ((env_seg != 0) &&
X                 (peek_cmp(copy_of_seg,env_seg,n) == 0)) {
X                     env_seg--;
X          }
X          if (env_seg != 0) {
X              seg_ray[k] = env_seg;
X              env_seg--;
X          }
X    }
X
X/* If not found, display error message and abort */
X    if (k != 2) {
X       fprintf(stderr,"Two copies of the environment were not found\n");
X       exit(-1);
X    }
X}
X/***************************************************************************/
Xvoid read_env(unsigned env_seg,int *k,char ***s,char ***t)
X/* Read environment into a malloc'd array of malloc'd strings */
X{
X  int i,j,n;
X
X  env_size = env_size_bytes(env_seg);
X
X  *k = env_size_strings(env_seg);
X  *s = (char **) malloc((*k)*sizeof(char *));
X  *t = (char **) malloc((*k)*sizeof(char *));
X
X  n = 0;
X  for (i = 0; i < *k; i++) {
X    for (j = 0; peekb(env_seg,n+j) != '='; j++);
X    (*s)[i] = (char *) malloc(j+1);
X    for (j = 0; peekb(env_seg,n+j) != '='; j++)
X      ((*s)[i])[j] = peekb(env_seg,n+j);
X    ((*s)[i])[j] = 0;
X    n += j + 1;
X    for (j = 0; peekb(env_seg,n+j) != 0; j++);
X    (*t)[i] = (char *) malloc(j+1);
X    for (j = 0; peekb(env_seg,n+j) != 0; j++)
X      ((*t)[i])[j] = peekb(env_seg,n+j);
X    ((*t)[i])[j] = 0;
X    n += j + 1;
X  }
X}
X/***************************************************************************/
Xvoid write_env(unsigned env_seg, int k, char **s, char **t)
X/* Write the environment back out to memory */
X{
X  int i,j,n;
X
X  struct mcb far *tmcb = (struct mcb far *)((long)(env_seg-1) << 16);
X
X  if (tmcb->tag4D == 0x4D) {
X    unsigned env_seg_siz = tmcb->size << 4;
X    if (env_size < env_seg_siz) {
X      for (n = i = 0; i < k; i++) {
X        char *si = s[i];
X        char *ti = t[i];
X	for (j = 0; si[j] != 0; j++) pokeb(env_seg,n++,si[j]);
X	pokeb(env_seg,n++,'=');
X	for (j = 0; ti[j] != 0; j++) pokeb(env_seg,n++,ti[j]);
X	pokeb(env_seg,n++,0);
X      }
X      pokeb(env_seg,n,0);
X    } else {
X      fprintf(stderr,"Insufficient space in environment\n");
X      exit(-1);
X    }
X  } else {
X    fprintf(stderr,"Environment memory control block trashed\n");
X    exit(-1);
X  }
X}
X/***************************************************************************/
Xchar *get_env_var(int k,char **s,char **t,char *var)
X/* Return the value of the environment variable or NULL if not found */
X{
X    char *val;
X    int i;
X
X    val = NULL;
X    for (i = 0; i < k; i++) if (stricmp(s[i],var) == 0) val = t[i];
X
X    return(val);
X}
X
X/***************************************************************************/
Xvoid set_env_var(int *k,char ***s,char ***t,char *var,char *val)
X/* Set a new or existing environment variable to a new value */
X{
X  int i,done;
X
X  done = 0;
X  for (i = 0; i < *k; i++) {
X    if (stricmp((*s)[i],var) == 0) {
X      /* Existing variable */
X      done = 1;
X      env_size -= strlen((*t)[i]);
X      free((*t)[i]);
X      (*t)[i] = (char *) malloc(1+strlen(val));
X      strcpy((*t)[i],val);
X      env_size += strlen((*t)[i]);
X    }
X  }
X
X  if (!done) {
X    /* New environment variable */
X    (*k)++;
X    *s = realloc(*s,(*k)*sizeof(char *));
X    *t = realloc(*t,(*k)*sizeof(char *));
X    (*s)[*k-1] = (char *) malloc(1+strlen(var));
X    strcpy((*s)[*k-1],var);
X    strupr((*s)[*k-1]);
X    (*t)[*k-1] = (char *) malloc(1+strlen(val));
X    strcpy((*t)[*k-1],val);
X    /* Length of name  + length of '=' + length of value + length of '\0' */
X    env_size += (strlen((*s)[*k-1]) + 1 + strlen((*t)[*k-1]) + 1);
X  }
X}
X/***************************************************************************/
Xvoid show_env(int k,char **s,char **t)
X/* Display the array of environment strings */
X{
X   int i;
X   for (i = 0; i < k; i++) printf("%s=%s\n",s[i],t[i]);
X}
X/***************************************************************************/
Xvoid get_cmdline(char *cmd)
X/* Read raw command line text into string buffer */
X{
X    char far *pcmd;
X
X    int idx,odx;
X
X    pcmd = (char far *)((long)_psp << 16) + 128L;
X
X    for (idx = *pcmd++, odx = 0; idx > 0; idx--, odx++) {
X      cmd[odx] = *pcmd++;
X    }
X
X    cmd[odx] = '\0';
X}
X/***************************************************************************/
Xchar_in(char ch, char *set)
X/* Determine if a character is in a set of characters */
X{
X  do {
X    if (ch == *set) return(TRUE);
X  } while ((int)*(++set));
X  return(FALSE);
X}
X/***************************************************************************/
Xchar get_num(char *cmd, int *pidx)
X/* Interpret octal or hexadecimal constant in string */
X{
X  int   accum  = 0;
X  char  ch;
X  int   f_scan = TRUE;
X  int   idx    = *pidx;
X  int   limit;
X  char *nch    = cmd+idx;
X  char *och    = nch+1;
X  int   radix;
X
X#define HEXDIG "0123456789ABCDEFabcdef"
X
X  if (*nch == '0' && char_in(*och,"xX") && char_in(*(och+1),HEXDIG)) {
X    radix = 16;
X    limit = 2;
X    och += 1;
X  } else {
X    radix = 8;
X    limit = 3;
X    och = nch;
X  }
X
X  while (limit-- > 0 && f_scan) {
X
X    f_scan = FALSE;
X
X    while ((int)(*nch)) *nch++ = *och++;
X
X    nch = cmd+idx;
X    och = nch+1;
X
X    switch (ch = *nch) {
X      case '0' :
X      case '1' :
X      case '2' :
X      case '3' :
X      case '4' :
X      case '5' :
X      case '6' :
X      case '7' :
X      case '8' :
X      case '9' :
X	if (ch == 9 && radix == 8) break;
X	accum = accum * radix + (int)(ch - '0');
X        f_scan = TRUE;
X	break;
X      case 'A' :
X      case 'B' :
X      case 'C' :
X      case 'D' :
X      case 'E' :
X      case 'F' :
X	if (radix == 8) break;
X	accum = accum * radix + (int)(ch - 'A') + 10;
X        f_scan = TRUE;
X	break;
X      case 'a' :
X      case 'b' :
X      case 'c' :
X      case 'd' :
X      case 'e' :
X      case 'f' :
X	if (radix == 8) break;
X	accum = accum * radix + (int)(ch - 'a') + 10;
X        f_scan = TRUE;
X	break;
X      default  : break;
X    }
X  }
X
X  *pidx = idx;
X  return(accum);
X}
X/***************************************************************************/
Xget_escape(char *cmd, int *pidx, char quote)
X/* Interpret escape'd (i.e., '\' (backslash) character */
X{
X  int   idx = *pidx;
X
X  if (quote == '"') {
X    char *nch = cmd+idx;
X    char *och = nch+1;
X    char *xch = nch;
X    while ((int)(*nch)) *nch++ = *och++;
X    switch (*xch) {
X      case 'a' : *xch = '\a'; break;
X      case 'b' : *xch = '\b'; break;
X      case 'c' : *xch = '\c'; break;
X      case 'd' : *xch = '\d'; break;
X      case 'e' : *xch = '\e'; break;
X      case 'f' : *xch = '\f'; break;
X      case 'g' : *xch = '\g'; break;
X      case 'h' : *xch = '\h'; break;
X      case 'i' : *xch = '\i'; break;
X      case 'j' : *xch = '\j'; break;
X      case 'k' : *xch = '\k'; break;
X      case 'l' : *xch = '\l'; break;
X      case 'm' : *xch = '\m'; break;
X      case 'n' : *xch = '\n'; break;
X      case 'o' : *xch = '\o'; break;
X      case 'p' : *xch = '\p'; break;
X      case 'q' : *xch = '\q'; break;
X      case 'r' : *xch = '\r'; break;
X      case 's' : *xch = '\s'; break;
X      case 't' : *xch = '\t'; break;
X      case 'u' : *xch = '\u'; break;
X      case 'v' : *xch = '\v'; break;
X      case 'w' : *xch = '\w'; break;
X      case 'x' : *xch = '\x'; break;
X      case 'y' : *xch = '\y'; break;
X      case 'z' : *xch = '\z'; break;
X      case '0' :
X      case '1' :
X      case '2' :
X        *xch = get_num(cmd, &idx);
X        break;
X    }
X  }
X
X  *pidx = idx + 1;
X}
X/***************************************************************************/
Xget_qvalue(char *cmd, int idx, char quote, char **value)
X/* Extract a quoted value part from command line */
X{
X  char ch;
X  int  f_esc;
X
X  *value = cmd + (++idx);
X
X  do {
X    while ((int)(ch = cmd[idx]) && ch != '\\' && ch != quote) idx++;
X    if (!(int)ch) return(-1);
X    if (ch == '\\') {
X      f_esc = TRUE;
X      get_escape(cmd, &idx, quote);
X    } else f_esc = FALSE;
X  } while (f_esc);
X
X  cmd[idx] = '\0';
X
X  for (idx += 1; (int)(ch = cmd[idx]) && ch == ' '; idx++);
X
X  if ((int)ch) return(-1);
X
X  return(0);
X}
X/***************************************************************************/
Xget_parm(char **name, char **value)
X/* Extract environment symbol name and value from command line */
X{
X    char ch;
X    int  idx;
X    int  sdx;
X
X    static char cmd[128];
X
X    get_cmdline(cmd);
X
X    for (idx = 0; (int)(ch = cmd[idx]) && ch  == ' '; idx++);
X
X    if (!(int)ch) return(1);
X
X    *name = cmd + idx;
X
X    for (; (int)(ch = cmd[idx]) && ch != '=' && ch != ' '; idx++);
X
X    if (!(int)ch) return(-1);
X
X    if (ch == ' ') {
X      cmd[idx] = '\0';
X      for (idx += 1; (int)(ch = cmd[idx]) && ch != '='; idx++);
X    } else cmd[idx] = '\0';
X
X    if (!(int)ch) return(-1);
X
X    for (sdx = (idx += 1); (int)(ch = cmd[idx]) && ch == ' '; idx++);
X
X    /*if (!(int)ch) return(-1);*/
X
X    switch (ch) {
X      case '"'  : return(get_qvalue(cmd, idx, '"', value));
X      case '\'' : return(get_qvalue(cmd, idx, '\'', value));
X      default   : *value = cmd + sdx; break;
X    }
X
X    return(0);
X}
X/***************************************************************************/
Xmain(int argc,char **argv)
X{
X    unsigned env_seg[2];
X    char **s,**t;
X    int k;
X    long now;
X    struct tm *local;
X
X    static char *name = NULL, *value = NULL;
X
X    switch (get_parm(&name,&value)) {
X
X    case -1:
X
X	fprintf(stderr,"Invalid symbol definition syntax\n");
X	exit(-1);
X
X    case 0:
X
X        /* Find and read environment */
X
X        find_env(env_seg);
X        read_env(env_seg[1],&k,&s,&t);
X
X	/* Set the variable <name> to <value> */
X
X	set_env_var(&k,&s,&t,name,value);
X
X	/* Update caller's environment */
X
X	write_env(env_seg[0],k,s,t);
X
X	break;
X
X    case 1:
X
X	fprintf(stderr,"Usage: setenv <symbol name> = <value>\n");
X	break;
X    }
X
X    return(0);
X}
X/***************************************************************************/
X
!EOR!
echo extracting - ctags.c
sed 's/^X//' > ctags.c << '!EOR!'
X/*
X * ctags - first cut at a UNIX ctags re-implementation
X */
X
X/*
X * Caveats:
X *
X * Only simple function declarations are recognized, as in:
X *
X * type
X * fname(...)
X *
X * where "fname" is the name of the function and must come at the beginning
X * of a line. This is the form I always use, so the limitation doesn't
X * bother me.
X *
X * Macros (with or without parameters) of the following form are also detected:
X *
X * "#" [white space] "define" [white space] NAME
X *
X * No sorting or detection of duplicate functions is done.
X *
X * If there are no arguments, a list of filenames to be searched is read
X * from the standard input. Otherwise, all arguments are assumed to be
X * file names.
X *
X * Tony Andrews
X * August 1987
X */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X
Xint	ac;
Xchar	**av;
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	char	*fname, *nextfile();
X	FILE	*tp, *fopen();
X
X	ac = argc;
X	av = argv;
X
X	if ((tp = fopen("tags", "w")) == NULL) {
X		fprintf(stderr, "Can't create tags file\n");
X		exit(1);
X	}
X
X	while ((fname = nextfile()) != NULL)
X		dofile(fname, tp);
X
X	fclose(tp);
X	exit(0);
X}
X
Xchar *
Xnextfile()	/* returns ptr to next file to be searched, null at end */
X{
X	static	char	buf[128];
X	static	int	ap = 1;
X	char	*gets();
X
X	if (ac <= 1) {		/* read from stdin */
X		if (feof(stdin))
X			return (char *) NULL;
X		return (gets(buf));
X	} else {
X		if (ap < ac)
X			return av[ap++];
X		else
X			return (char *) NULL;
X	}
X}
X
X#define	LSIZE	512	/* max. size of a line */
X
X#define	BEGID(c)	(isalpha(c) || (c) == '_')
X#define	MIDID(c)	(isalpha(c) || isdigit(c) || (c) == '_')
X
Xdofile(fn, tp)
Xchar	*fn;
XFILE	*tp;
X{
X	FILE	*fp, *fopen();
X	char	*cp, *strchr();
X	char	lbuf[LSIZE];
X	char	func[LSIZE];
X	int	i, j;
X
X	if ((fp = fopen(fn, "r")) == NULL) {
X		fprintf(stderr, "Can't open file '%s' - skipping\n", fn);
X		return;
X	}
X
X	while (fgets(lbuf, LSIZE, fp) != NULL) {
X
X		lbuf[strlen(lbuf)-1] = '\0';	/* bag the newline */
X
X		if (BEGID(lbuf[0])) {		/* could be a function */
X			for (i=0; MIDID(lbuf[i]) ;i++)	/* grab the name */
X				func[i] = lbuf[i];
X
X			func[i] = '\0';		/* null terminate the name */
X
X			/*
X			 * We've skipped to the end of what may be a function
X			 * name. Check to see if the next non-whitespace
X			 * char is a paren,
X			 * and make sure the closing paren is here too.
X			 */
X			while (lbuf[i]==' ' || lbuf[i]=='\t') i++;
X			if (lbuf[i]=='(' && (((cp = strchr(lbuf,')'))!=NULL))) {
X				*++cp = '\0';
X				fprintf(tp, "%s\t%s\t/^%s$/\n", func,fn,lbuf);
X			}
X
X		} else if (lbuf[0] == '#') {	/* could be a define */
X			for (i=1; isspace(lbuf[i]) ;i++)
X				;
X			if (strncmp(&lbuf[i], "define", 6) != 0)
X				continue;
X
X			i += 6;			/* skip "define" */
X
X			for (; isspace(lbuf[i]) ;i++)
X				;
X
X			if (!BEGID(lbuf[i]))
X				continue;
X
X			for (j=0; MIDID(lbuf[i]) ;i++, j++)
X				func[j] = lbuf[i];
X
X			func[j] = '\0';		/* null terminate the name */
X			lbuf[i] = '\0';
X			fprintf(tp, "%s\t%s\t/^%s/\n", func, fn, lbuf);
X		}
X	}
X	fclose(fp);
X}
!EOR!


