Path: utzoo!attcan!uunet!mcvax!ukc!reading!onion!cf-cm!sme
From: sme@computing-maths.cardiff.ac.uk (Simon Elliott)
Newsgroups: comp.sys.ibm.pc
Subject: Re: How to add to PATH on the fly?
Summary: pathed.c - you asked for it
Message-ID: <468@cf-cm.UUCP>
Date: 11 Jul 88 11:39:24 GMT
References: <688@crcmar.crc.uucp> <604@arctic.nprdc.arpa>
Organization: Univ. Coll. Cardiff, Cardiff, WALES, UK.
Lines: 221


Here is pathed.c, containing instructions for its surrounding batch
files for various versions of DOS.  I compiled it with Turbo C v1.0.
It uses strtok, which some compilers' libraries don't have.

------------------------8x----------------------8x------------------------

/*
 * pathed.c - core of path editor
 *
 *	Written by Simon Elliott (...!mcvax!ukc!cf-cm!sme).
 *	Version 1.0 10/11/87.
 *
 * As you will see from the usage message, this claims to be PATHEDIT.
 * Actually, this program is called from within a batch file, and
 * should be called PATHED, or something. I keep PATHED.EXE _and_
 * PATHEDIT.BAT in my \BATCH directory, which is _always_ in my
 * PATH.  (PATHED.EXE is the only non-.BAT in \BATCH)
 *
 * Here is PATHEDIT.BAT for Dos < 3.30:
 *	echo off
 *	pathed %1 %2 >\$$$.bat
 *	if not errorlevel 1 \$$$
 *
 * and for Dos >= 3.30:
 *	@echo off
 *	pathed %1 %2 >$$$.bat
 *	if not errorlevel 1 call $$$.bat
 *	del $$$.bat >nul
 *
 * usage:
 *	pathedit -a d:\path	appends to current path
 *	pathedit -d d:\path	deletes d:\path from current path
 *	pathedit -i d:\path	inserts d:\path before current path
 *	pathedit -3 d:\path	adds/moves d:\path to 3rd place in path
 */

#include	

char	pathbuffer[129];	/* delete() builds path command here */
char	*pathcommand = "path ";
char	*getenv(), *strcpy(), *strchr(), *strtok();
void	usage(), pathcmd2(), delete(), moveto();

main(ac, av)
	int	ac;
	char	*av[];
{
	register char	*current;

	if (ac < 3 || *av[1] != '-' && *av[1] != '/')
		usage();

	current = getenv("PATH");
	strupr(av[2]);
	switch (av[1][1]) {
	case 'A': case 'a':	/* append */
		if (current)
			pathcmd2(current, av[2]);
		else
			pathcmd2(av[2], "");
		break;
	case 'D': case 'd':	/* delete */
		if (current)
			delete(av[2], current);
		break;
	case 'I': case 'i':	/* insert */
		if (current)
			pathcmd2(av[2], current);
		else
			pathcmd2(av[2], "");
		break;
	default:		/* numeric position or bad option */
		if (!isnumber(++av[1]))
			usage();

		/* first delete any of the target component */
		if (current) {
			strcpy(pathbuffer, current);
			delete(av[2], current);
		}
		else
			pathbuffer[0] = '\0';

		/* pathbuffer contains the path after deletions */
		moveto(atoi(av[1]), av[2], pathbuffer);
	}

	/* make batch report what the path is now */
	fputs("path\n", stdout);
	exit(0);
}


void
usage()
{
	fputs("usage: pathedit [-a] [-d] [-i] [-N] d:\\path\n", stderr);
	exit(1);
}


/*
 * pathcmd2() - output a path command with one or possibly two strings.
 */
void
pathcmd2(first, second)
	char	*first, *second;
{
	fputs(pathcommand, stdout);
	fputs(first, stdout);
	if (*second) {
		putchar(';');
		fputs(second, stdout);
	}
	putchar('\n');
}


/*
 * delete() - delete occurences of deletion from well formed PATH string
 *            pointed to by source.
 */
void
delete(deletion, source)
	char	*deletion, *source;
{
	register char	*dest;
	register int	first;
	char	*component;

	first = 1;
	dest = pathbuffer;

	/* look for ';' separator until end of string */
	component = strtok(source, ";");
	while (component != NULL) {
		if (strcmp(deletion, component)) {
			/* no match - copy component to dest */
			if (!first)
				*dest++ = ';';
			strcpy(dest, component);
			dest = strchr(dest, '\0');
			first = 0;
		}
		/* advance the component of the PATH */
		component = strtok(NULL, ";");
	}

	if (first) {
		fputs("set PATH=", stdout);
		pathbuffer[0] = '\0';
	}
	else {
		fputs(pathcommand, stdout);
		fputs(pathbuffer, stdout);
	}
	putchar('\n');
}

/*
 * moveto() - move PATH component insertion to position posn in well-formed
 *            PATH string pointed to by source.
 * we assume that insertion has been deleted already in the source string.
 */
void
moveto(posn, insertion, source)
	register int	posn;	/* desired position of insertion in source */
	char	*insertion, *source;
{
	register int	curposn;
	int	needsemi;

	fputs(pathcommand, stdout);
	curposn = 1;		/* number positions from 1 */
	needsemi = 0;		/* start off not needing a semicolon */
	while (curposn < posn && *source) {
		if (';' == *source) {
			++curposn;
			needsemi = 0;
		}
		else
			needsemi = 1;
		putchar(*source++);
	}

	/* need this kludge because we could be at 1st or last position */
	if (needsemi)
		putchar(';');
	fputs(insertion, stdout);

	if (*source) {		/* write out rest of source (if any) */
		putchar(';');
		fputs(source, stdout);
	}
	putchar('\n');
}

isnumber(str)
	char	*str;
{
	char	c;

	while (c = *str++)		/* assign */
		if (c < '0' || c > '9')
			return 0;
	return 1;
}

------------------------8x----------------------8x------------------------

If you find this half as useful as I do, then just remember - I'm
finding it twice as useful as you are, so there!

Enjoy!

-- 
Simon Elliott
Microcomputer Support
University College Cardiff Computer Centre, Cardiff, Wales
...!mcvax!ukc!cf-cm!sme