[net.sources] MS-DOS 2.0 pushd/popd sources

nathan@orstcs.UUCP (02/01/84)

x <-- (MS-DOS to you, too)
*** Of Interest Only To MS-DOS 2ers: ***
 
The following is an archive of files necessary to implement a 
"pushd"/"popd" facility on MSDOS 2.x systems.
 
It is in the format preferred by the Computer Innovations archive
manager program, as supplied with their C compiler.  For those 
without CI C86, simply split apart the file on the lines marked 
"-ARCHIVE-" where the word following is the file name.  If you
don't have CI C, you will also need to write a "segread()" and
a "sysint()" function.  "segread" copies segment registers into
struct "seg_set"; 
 
struct reg_set { int ax, bx, cx, dx, si, di, ds, es; };
struct seg_set { int code_seg, stack_seg, data_seg, extra_seg; };
 
"sysint()" is:
 
sysint(interrupt, regsin, regsout)
	int interrupt;
	struct reg_set *regsin, *regsout;
 
"sysint()" copies the registers in, traps to the specified interrupt vector,
then copies regs back into *regsout when it comes back.  This program calls 
sysint with (regsin == regsout); design accordingly.
 
The functions "fputs2()" and "fputc2" use file descriptors, not FILE *'s,
and they do NOT do newline conversion . . . (quickie functions)
 
Note that open2()'s "mode" argument semantics are inconsistent with 
standard open() usage. (numbers are 0, 1, 2 for binary; there is no ascii mode;
that's how the system call is defined)
 
Since I have an XT, the variable "stk_pth" is set to "C:\dir.stk".  If you
need it to be a different drive, you will have to change it in both pushd
and popd.
 
I don't think there's anything else non-portable....
 
The following is the procedure for compiling pushd and popd.  'cc' is my
local batch file for compiling programs.  If the second argument is 'link',
it links in all the following files, then the standard library.  You will
want to substitute your own procedure for this.  If all else fails, call
my BBS at (503) 753-7133. (300/1200 baud)
 
cc iolib2
cc sys_err2
cc pushd link iolib2 sys_err2
cc popd link iolib2 sys_err2
 
If you hack on the "_main" and "exit" routines, and eliminate most of the
library, you can eliminate 10K of unnecessary code that otherwise gets linked
in.  You will also need to compile and link in the "itoa" routine included
here, as the CI "itoa" routine calls in the floating point library (it uses
sprintf).
 
Tear off on the dotted line:
-----------------------------------------------------------
-ARCHIVE- iolib2.c 3547
/*
 *  File name:		iolib2.c
 *
 *  Belongs to:		System C library extension
 *  Description:	DOS 2.0 I/O routines for C86 (small memory model only)
 *
 *  Version:		1.0
 *  Last change:	None - original code
 *  Author:		Alan Batie
 */
 
#include "stdio.h"
#include "stdext.h"
 
#define ERROR (flags & CARRY_FLAG)
#define SYSCALL() sysint(0x21, &regs, &regs)
 
int io_err2;
 
/*  Get current directory  */
 
int getdir(drive, path_buf)
	int drive;	/*  0 = default, 1 = A, 2 = B, ...  */
	char *path_buf;
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x4700;
	regs.dx = drive;
	regs.ds = segs.stack_seg;
	regs.si = path_buf;
 
	flags = SYSCALL();
	if (ERROR)
		{
		return(regs.ax);
		}
	else
		{
		return(0);
		}
	}
 
/*  Change to new directory  */
 
int chdir(path_name)
	char *path_name;
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x3B00;
	regs.dx = path_name;
	regs.ds = segs.stack_seg;
 
	flags = SYSCALL();
	if (ERROR)
		{
		return(regs.ax);
		}
	else
		{
		return(0);
		}
	}
 
/*  Open file  */
 
int open2(path_name, mode)
	char *path_name;
	int mode;		/*  0 = read, 1 = write, 2 = read/write  */
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x3D00 | (mode & 3);	/*  Open for read/write  */
	regs.dx = path_name;
	regs.ds = segs.stack_seg;
	flags = SYSCALL();
	if (ERROR)
		{
		io_err2 = regs.ax;
		return(-1);
		}
	else
		{
		return(regs.ax);
		}
	}
 
/*  Create file  */
 
int creat2(path_name, mode)
	char *path_name;
	int mode;		/*  not used -- opened in read/write mode  */
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x3C00;	/*  Create stack file  */
	regs.cx = 0;
	regs.dx = path_name;
	regs.ds = segs.stack_seg;
 
	flags = SYSCALL();
	if (ERROR)
		{
		io_err2 = regs.ax;
		return(-1);
		}
	else
		{
		return(regs.ax);
		}
	}
 
/*  Read file  */
 
int read2(fd, buffer, count)
	int fd;
	char *buffer;
	unsigned int count;
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x3F00;
	regs.bx = fd;
	regs.cx = count;
	regs.dx = buffer;
	regs.ds = segs.stack_seg;
 
	flags = SYSCALL();
	if (ERROR)
		{
		io_err2 = regs.ax;
		return(-1);
		}
	else
		{
		return(regs.ax);
		}
	}
 
/*  Write current path name  */
 
int write2(fd, buffer, count)
	int fd;
	char *buffer;
	int count;
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x4000;
	regs.bx = fd;
	regs.cx = count;
	regs.dx = buffer;
	regs.ds = segs.stack_seg;
 
	flags = SYSCALL();
	if (ERROR)
		{
		io_err2 = regs.ax;
		return(-1);
		}
	else
		{
		return(regs.ax);
		}
	}
 
/*  Seek to just after last valid entry  */
 
long lseek2(fd, offset, base)
	int fd;
	long offset;
	int base;
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
 
	segread(&segs);
 
	regs.ax = 0x4200;
	regs.bx = fd;
	regs.cx = offset >> 16;
	regs.dx = offset & 0xFFFF;	/*  offset % 65536  */
 
	flags = SYSCALL();
	if (ERROR)
		{
		io_err2 = regs.ax;
		return(-1);
		}
	else
		{
		return(((long) regs.dx << 16) | regs.ax);
		}
	}
 
/*  Write a character to specified file  */
 
fputc2(c, fd)
	char c;
	{
	write2(fd, &c, 1);
	}
 
/*  Write a string to standard output  */
 
fputs2(str, fd)
	char *str;
	{
	write2(fd, str, strlen(str));
	}
-ARCHIVE- iolib2.h 534
/*
 *  File name:		iolib2.h
 *
 *  Belongs to:		iolib2.c (system C library extension)
 *  Description:	Definitions for iolib2.c
 *
 *  Version:		1.0
 *  Last change:	None - original code
 *  Author:		Alan Batie
 */
 
#define STDIN	0
#define STDOUT	1
#define STDERR	2
#define STDAUX	3
#define STDPR	4
 
#define READ		0
#define WRITE		1
#define READ_WRITE	2
 
#define FROM_BEG	0
#define FROM_HERE	1
#define FROM_END	2
 
#define DEFAULT_DRV	0
#define A_DRV		1
#define B_DRV		2
#define C_DRV		3
#define D_DRV		4
-ARCHIVE- itoa.c 440
/*
 * This itoa doesn't call in the floating point library:
 *   CI C86 does an sprintf!
 */
 
itoa(val, buf)
	int val;
	char *buf;
	{
	int i;
	int j;
	char tbuf[10];
 
	if (val == 0)
		{
		buf[0] = '0';
		buf[1] = '\0';
		return;
		}
 
	i = 10;
 
	while (val != 0)
		{
		tbuf[i--] = (val % 10) + '0';
		val /= 10;
		}
 
	i++;
 
	for (j = 0; i <= 10; i++, j++)
		{
		buf[j] = tbuf[i];
		}
 
	buf[j] = '\0';
	}
-ARCHIVE- makepush. 430
The following is the procedure for compiling pushd and popd.  'cc' is my
local batch file for compiling programs.  If the second argument is 'link',
it links in all the following files, then the standard library.  You will
want to substitute your own procedure for this.  If all else fails, call
my BBS at (503) 753-7133. (300/1200 baud)
 
cc iolib2
cc sys_err2
cc pushd link iolib2 sys_err2
cc popd link iolib2 sys_err2
-ARCHIVE- popd.c 1905
/*
 *  File name:		popd.c
 *
 *  Belongs to:		System commands
 *  Description:	Pops last path name from \dir.stk and cd's to it.
 *
 *  Version:		1.0
 *  Last change:	None - original code
 *  Author:		Alan Batie
 */
 
#include "stdio.h"
#include "stdext.h"
#include "iolib2.h"
 
#define PATH_SIZE	65
 
extern int io_err2;
 
char stk_path[] = "C:\\dir.stk";
 
main()
	{
	struct reg_set regs;
	struct seg_set segs;
	int flags;
	int file_num;
	int num_recs;
	int err_code;
	int count;
	long pos;
	char path_name[PATH_SIZE + 1];
 
/*  Open directory stack file  */
 
	file_num = open2(stk_path, READ_WRITE);
	if (file_num == -1)
		{
		fputs2("\r\nDirectory stack empty\r\n", STDERR);
		exit(1);
		}
 
/*  Read directory stack size  */
 
	count = read2(file_num, &num_recs, 2);
	if (count != 2)
		{
		fputs2("\r\nBad directory stack\r\n", STDERR);
		exit(255);
		}
 
/*  Make sure stack isn't empty  */
 
	if (num_recs == 0)
		{
		fputs2("\r\nEmpty directory stack\r\n", STDERR);
		exit(1);
		}
 
/*  Seek to last valid entry  */
 
	pos = lseek2(file_num, (long) PATH_SIZE * (num_recs - 1) + 2, FROM_BEG);
 
	if (pos == -1)
		{
		sys_err(io_err2);
		fputs2("\r\nUnable to seek on directory stack\r\n", STDERR);
		exit(255);
		}
 
/*  Read last valid entry  */
 
	count = read2(file_num, path_name + 1, PATH_SIZE);
	if (count != PATH_SIZE)
		{
		sys_err(io_err2);
		fputs2("\r\nRead error on directory stack\r\n", STDOUT);
		exit(255);
		}
 
/*  Fix path name so it has leading \  */
 
	path_name[0] = '\\';
 
/*  Change to new directory  */
 
	err_code = chdir(path_name);
	if (err_code != 0)
		{
		sys_err(err_code);
		exit(1);
		}
 
/*  Seek to beginning of stack file to update number of records  */
 
	lseek2(file_num, (long) 0, FROM_BEG);
 
/*  Update number of records  */
 
	num_recs--;
 
	write2(file_num, &num_recs, 2);
	}
-ARCHIVE- pushd.c 3996
/*
 *  File name:		pushd.c
 *
 *  Belongs to:		System commands
 *  Description:	Pushes current working path name onto end of \dir.stk,
 *			then cd's to path name on command line.
 *
 *  Version:		1.0
 *  Last change:	None - original code
 *  Author:		Alan Batie
 */
 
#include "stdio.h"
#include "stdext.h"
#include "iolib2.h"
 
#define PATH_SIZE	65
 
extern int io_err2;
 
char stk_path[] = "C:\\dir.stk";
 
main(argc, argv)
	int argc;
	char *argv[];
	{
	int file_num;
	int num_recs;
	int err_code;
	int count;
	long pos;
	char path_name[PATH_SIZE];
 
	if (argc == 1)
		{
		fputs2("\r\nUsage: pushd <new path>\r\n", STDERR);
		dump_stk();
		exit(0);
		}
 
/*  Get current directory  */
 
	err_code = getdir(DEFAULT_DRV, path_name);
	if (err_code != 0)
		{
		sys_err(err_code);
		fputs2("\r\nUnable obtain current directory\r\n", STDERR);
		exit(255);
		}
 
/*  Open directory stack file  */
 
	file_num = open2(stk_path, READ_WRITE);
	if (file_num == -1)
		{
		if (io_err2 == 2)
			{
			file_num = creat2(stk_path, READ_WRITE);
			if (file_num == -1)
				{
				sys_err(io_err2);
				fputs2("\r\nUnable to create directory stack file\r\n", STDERR);
				exit(255);
				}
			num_recs = 0;
 
		/*  Initialize stack file  */
 
			count = write2(file_num, &num_recs, 2);
			if (count != 2)
				{
				sys_err(io_err2);
				fputs2("\r\nUnable to initialize directory stack file\r\n", STDERR);
				exit(255);
				}
 
		/*  Reset file pointer  */
 
			pos = lseek2(file_num, (long) 0, FROM_BEG);
			}
		else
			{
			sys_err(io_err2);
			fputs2("\r\nUnable to open directory stack file\r\n", STDERR);
			exit(255);
			}
		}
 
/*  Get number of records in stack  */
 
	count = read2(file_num, &num_recs, 2);
	if (count != 2)
		{
		num_recs = 0;
 
	/*  Initialize stack file  */
 
		lseek2(file_num, (long) 0, FROM_BEG);
 
		count = write2(file_num, &num_recs, 2);
		if (count != 2)
			{
			sys_err(io_err2);
			fputs2("\r\nUnable to initialize directory stack file\r\n", STDERR);
			exit(255);
			}
		}
 
/*  Seek to just after last valid entry  */
 
	pos = lseek2(file_num, (long) PATH_SIZE * num_recs + 2, FROM_BEG);
 
	if (pos == -1)
		{
		sys_err(io_err2);
		fputs2("\r\nSeek error on directory stack file\r\n", STDERR);
		exit(255);
		}
 
/*  Change to new directory  */
 
	err_code = chdir(argv[1]);
	if (err_code != 0)
		{
		sys_err(err_code);
		exit(1);
		}
 
/*  Write old path name  */
 
	count = write2(file_num, path_name, PATH_SIZE);
	if (count != PATH_SIZE)
		{
		sys_err(io_err2);
		fputs2("\r\nWrite error on directory stack file\r\n", STDERR);
		exit(255);
		}
 
/*  Seek to beginning of stack file to update number of records  */
 
	lseek2(file_num, (long) 0, FROM_BEG);
 
/*  Update number of records  */
 
	num_recs++;
 
	count = write2(file_num, &num_recs, 2);
	if (count != 2)
		{
		sys_err(io_err2);
		fputs2("\r\nWrite error on directory stack file\r\n", STDERR);
		exit(255);
		}
	}
 
dump_stk()
	{
	int i;
	int count;
	int num_recs;
	int file_num;
	char path[PATH_SIZE];
 
	fputs2("\r\nDirectory stack currently contains:\r\n\r\n", STDOUT);
 
/*  Open directory stack file  */
 
	file_num = open2(stk_path, READ_WRITE);
	if (file_num == -1)
		{
		if (io_err2 == 2)
			{
			fputs2("\r\nEmpty directory stack\r\n", STDOUT);
			exit(1);
			}
		else
			{
			sys_err(io_err2);
			fputs2("\r\nUnable to open directory stack file\r\n", STDERR);
			exit(255);
			}	
		}
 
/*  Get number of records in stack  */
 
	count = read2(file_num, &num_recs, 2);
	if (count != 2)
		{
		fputs2("\r\nBad directory stack\r\n", STDERR);
		exit(255);
		}
 
/*  Dump them out  */
 
	for (i = 0; i < num_recs; i++)
		{
		count = read2(file_num, path, PATH_SIZE);
 
		fputs2(path, STDOUT);
		fputs2("\r\n", STDOUT);
 
		if (count != PATH_SIZE)
			{
			fputs2("\r\nPremature end-of-file encountered\r\n", STDERR);
			exit(255);
			}
		}
	}
-ARCHIVE- stdext.h 1237
/*  stdext.h - Standard extensions to i/o header file for c86  */
 
#define EOFmark(c) (c == (-1) || c == '\32')
#define min(a,b) ((a) < (b) ? (a) : (b))
#define max(a,b) ((a) > (b) ? (a) : (b))
 
#define INKEY() (bdos(6, 0xFF) & 0xFF)
#define OUTCHAR(c) bdos(6, c)
#define CHAR_RDY() (bdos(0x0B) & 0xFF)
#define GET_NO_ECHO() (bdos(8) & 0xFF)
 
#define BEL '\7'
#define TAB '\11'
#define BS '\10'
#define LF '\12'
#define CR '\15'
#define SPACE ' '
 
#define AND &&
#define OR  ||
#define NOT !
 
/*  Flag register definitions  */
 
#define CARRY_FLAG	0x0001
#define PARITY_FLAG	0x0004
#define AUX_CARRY_FLAG	0x0010
#define ZERO_FLAG	0x0040
#define SIGN_FLAG	0x0080
#define TRAP_FLAG	0x0100
#define INTERRUPT_FLAG	0x0200
#define DIRECTION_FLAG	0x0400
#define OVERFLOW_FLAG	0x0800
 
/*  File attribute definitions  */
 
#define F_NORMAL	0x00
#define F_READ_ONLY	0x01
#define F_HIDDEN	0x02
#define F_SYSTEM	0x04
#define F_VOLUME	0x08
#define F_DIRECTORY	0x10
#define F_ARCHIVE	0x20
 
#define FALSE 0
#define TRUE 0xFF
 
typedef char BOOLEAN;
 
struct reg_set { int ax, bx, cx, dx, si, di, ds, es; };
struct seg_set { int code_seg, stack_seg, data_seg, extra_seg; };
 
#define FOREVER while (TRUE)
-ARCHIVE- sys_err2.c 1924
/*
 *  File name:		sys_err.c
 *
 *  Belongs to:		System library
 *  Description:	Displays error message based on error code returned
 *			from system call.
 *
 *  Version:		1.0
 *  Last change:	None - original code
 *  Author:		Alan Batie
 */
 
#include "stdio.h"
#include "stdext.h"
#include "iolib2.h"
 
sys_err(err_code)
	int err_code;
	{
	char buf[10];
 
	switch (err_code)
		{
		case 1:
			fputs2("\nInvalid function number\n", STDERR);
			break;
 
		case 2:
			fputs2("\nFile not found\n", STDERR);
			break;
 
		case 3:
			fputs2("\nPath not found\n", STDERR);
			break;
 
		case 4:
			fputs2("\nToo many open files\n", STDERR);
			break;
 
		case 5:
			fputs2("\nAccess denied\n", STDERR);
			break;
 
		case 6:
			fputs2("\nInvalid handle\n", STDERR);
			break;
 
		case 7:
			fputs2("\nMemory control blocks destroyed\n", STDERR);
			break;
 
		case 8:
			fputs2("\nInsufficient memory\n", STDERR);
			break;
 
		case 9:
			fputs2("\nInvalid memory block address\n", STDERR);
			break;
 
		case 10:
			fputs2("\nInvalid environment\n", STDERR);
			break;
 
		case 11:
			fputs2("\nInvalid format\n", STDERR);
			break;
 
		case 12:
			fputs2("\nInvalid access code\n", STDERR);
			break;
 
		case 13:
			fputs2("\nInvalid data\n", STDERR);
			break;
 
		case 14:
			fputs2("\nUnknown error code ", STDERR);
			itoa(err_code, buf);
			fputs2(buf, STDERR);
			fputs2("\n", STDERR);
			break;
 
		case 15:
			fputs2("\nInvalid drive was specified\n", STDERR);
			break;
 
		case 16:
			fputs2("\nAttempted to remove current directory\n", STDERR);
			break;
 
		case 17:
			fputs2("\nNot same device\n", STDERR);
			break;
 
		case 18:
			fputs2("\nNo more files\n", STDERR);
			break;
 
		default:
			fputs2("\nUnknown error code ", STDERR);
			itoa(err_code, buf);
			fputs2(buf, STDERR);
			fputs2("\n", STDERR);
			break;
		}
	}