Received: by ATHENA-PO-2.MIT.EDU (5.45/4.7) id AA08363; Wed, 13 Jul 88 01:43:06 EDT
From: <wdc@ATHENA.MIT.EDU>
Received: by ATHENA.MIT.EDU (5.45/4.7) id AA16176; Wed, 13 Jul 88 01:42:51 EDT
Received: by LAKOTA.MIT.EDU (5.45/4.7) id AA05344; Wed, 13 Jul 88 01:42:50 EDT
Date: Wed, 13 Jul 88 01:42:50 EDT
Message-Id: <8807130542.AA05344@LAKOTA.MIT.EDU>
To: bgardner@ATHENA.MIT.EDU
Subject: [wdc@ATHENA.MIT.EDU: Submitted for your AUDIT:  pathedit.c]

From: <wdc@ATHENA.MIT.EDU>
Date: Wed, 13 Jul 88 01:08:12 EDT
To: athena-ws@ATHENA.MIT.EDU
Subject: Submitted for your AUDIT:  pathedit.c

/*
 * Pathedit
 *
 * A program for producing a variation on the current search path 
 * for binding to the 'path' shell variable in an analagous way
 *  to the workings of tset.
 */

/*
 * Wiliam D. Cattey
 * MIT Project Athena
 * Created:  7/13/88
 *
 * $Source$
 * $Author$
 * $Header$
 *
 * Copyright 1988 by the Massachusetts Institute of Technology.
 * For copying and distribution information, see the file
 * "mit-copyright.h".
 */

#include <mit-copyright.h>

/*
 * USAGE:
 *
 * Intended for use in a csh alias:
 *   alias pset 'if (-x pathedit ) set path=`pathedit \!*`'
 *
 * ARGS:
 * 
 * -f:		get an argument spec from a file.
 * -e:		put new directory at end of path.
 * -s:		put new directory at start of path.
 * -b name:	put new directory before 'name' in path.
 *		complain if 'name' not in path.
 * -a name:	put new directory after 'name' in path.
 *		complain if 'name' not in path.
 * -d name:	delete element 'name' from path
 */

/*
 * CAVEATS:
 *
 * Generates syntax for use with 'set' command in csh.  An option for
 * generating sh syntax should be added.
 *
 * Parsing for more than one argument per invocation should be added.
 *
 * Machine dependent directories are added as in the following example:
 * set path=`pathedit -b /bin/athena /mit/andrew/${HOSTTYPE}/bin`
 *
 * The -f option is not yet implemented.
 */

#include <stdio.h>

#define STRING_START 0
#define STRING_END 1

char *getenv();
char *malloc();
char *realloc();

char *match_path();

main(argc, argv)
     int argc;
     char **argv;
{
  char *path, *cshpath, *src, *dst;
  char *argp;
  char *elementp = 0;
  int len, del_len;
  int fflag = 0, eflag = 0, sflag = 0, bflag = 0, aflag = 0, badarg = 0;
  int noflag = 0, dflag = 0;
  int spaces = 0;

  path = getenv("PATH");
  src = path;
  argp = argv[1];

  if (argc > 1)
    {
      argp = argv[1];
      if (*argp == '-')
	{
	  argp++;
	  switch (*argp)
	    {
	    case 'f':
	      fflag++;
	      break;
	    case 'e':
	      eflag++;
	      spaces++;
	      break;
	    case 's':
	      sflag++;
	      spaces++;
	      break;
	    case 'b':
	      bflag++;
	      break;
	    case 'a':
	      aflag++;
	      break;
	    case 'd':
	      dflag++;
	      break;
	    default:
	      badarg++;
	      break;
	    }
	  if (!badarg && argc > 2)
	    {
	      argp = argv[2];
	    }
	  else argp = "";
	}
      else
	{
	  noflag++;
	  argp = argv[1];
	  spaces++;
	}
    }
  else
    {
      badarg++;
      argp = "";
    }

  if (bflag || dflag) elementp = match_path(src, argp, STRING_START);
  if (aflag) elementp = match_path(src, argp, STRING_END);

  if ( (aflag || bflag) && elementp)
    {
      if (argc > 3)
	{
	   argp = argv[3];
	   spaces = 0;	/* element to add and a space */
	   if (*elementp != '\0') spaces++;	/* space after new element */
	 }
      else
	{
	  badarg++;
	  argp = "";
	}
    }

  len = strlen(path) + 1; /* add space for null. */
  cshpath = malloc(len);

  if (!badarg)
    {
      if (dflag)
	{
	  if (elementp)
	    {
	      del_len = strlen(argp);
	      cshpath = realloc(cshpath, len - del_len);
	    }
	}
      else
	cshpath = realloc(cshpath, len + strlen(argp) + spaces);
    }

  dst = cshpath;

  if (sflag)	/* put arg at start of path */
    {
      while (*argp != '\0')
	{
	  *dst++ = *argp++;
	}
      *dst++ = ' ';
    }

  while (*src != '\0')
    {
      if ((bflag) && (src == elementp)) /* put arg before this element */
	{
	  while (*argp != '\0')
	    {
	      *dst++ = *argp++;
	    }
	  if (*elementp != '\0') *dst++ = ' ';	/* Should not be needed */
	}

      if (dflag && elementp && (src >= elementp) &&
	  (src <= (elementp + del_len))) ;
      else
	*dst++ = (*src == ':') ? ' ' : *src;	/* copy element character */

      if ((aflag) && (src == elementp))	/* put arg after this element */
	{
	  while (*argp != '\0')
	    {
	      *dst++ = *argp++;
	    }
	  if (*elementp != '\0') *dst++ = ' ';
	}
      
      src++;
    }
  
  if (eflag || noflag)	/* put arg at end of path */
    {
      *dst++ = ' ';
      while (*argp != '\0')
	{
	  *dst++ = *argp++;
	}
    }

  *dst++ = '\0';

  printf ("%s", cshpath);
}

/*
 * Determines if there is an exact match for key as an element of the source.
 * If so it returns: 
 *   a  pointer to the begining of the element if flag is STRING_START, 
 *   a pointer to the first chracter past the end of the element 
 *      if flag is STRING_END.
 *   0 if flag is anything else, or if there is no match.
 * Comparing against NULL is considered a failed match.
 */

char *match_path (source, key, flag)
     char *source, *key;
     int flag;
{
  char *sourcep, *keyp, *startp;
  int matched;

  sourcep = source;

  while (*sourcep != '\0')
    {
      keyp = key;
      startp = sourcep;
      matched = 0;

      for (; *keyp == *sourcep; keyp++, sourcep++) matched++;

      /* this was an exact match if the first failed characters
	 consist of '\0' in key, and either a ':' or '\0' in source.
	 Comparing against NULL is considered a failed match. */

      if ((matched >0) && (*keyp == '\0') &&
	  ((*sourcep == '\0') || (*sourcep == ':')))
	{
	  if (flag == STRING_START)
	    return startp;
	  else if (flag == STRING_END)
	    return sourcep;
	  else return 0;
	}
      else if (*sourcep == '\0') /* end of source */
	return 0;
      else
	sourcep++;	/* skip over colon. */
    }
  return 0;
}
	    

      
