[comp.sources.unix] v19i033: A software configuration management system, Part20/33

rsalz@uunet.uu.net (Rich Salz) (06/05/89)

Submitted-by: Axel Mahler <unido!coma!axel>
Posting-number: Volume 19, Issue 33
Archive-name: shape/part20



#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 20 (of 33)."
# Contents:  src/afs/afhash.c src/vfind/vfind.c tutorial/make2shape.ms
# Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:12 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/afs/afhash.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/afs/afhash.c'\"
else
echo shar: Extracting \"'src/afs/afhash.c'\" \(17913 characters\)
sed "s/^X//" >'src/afs/afhash.c' <<'END_OF_FILE'
X/*
X * Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
X *  and U. Pralle
X * 
X * This software is published on an as-is basis. There is ABSOLUTELY NO
X * WARRANTY for any part of this software to work correctly or as described
X * in the manuals. We do not accept any liability for any kind of damage
X * caused by use of this software, such as loss of data, time, money, or 
X * effort.
X * 
X * Permission is granted to use, copy, modify, or distribute any part of
X * this software as long as this is done without asking for charge, and
X * provided that this copyright notice is retained as part of the source
X * files. You may charge a distribution fee for the physical act of
X * transferring a copy, and you may at your option offer warranty
X * protection in exchange for a fee.
X * 
X * Direct questions to: Tech. Univ. Berlin
X * 		     Wilfried Koch
X * 		     Sekr. FR 5-6 
X * 		     Franklinstr. 28/29
X * 		     D-1000 Berlin 10, West Germany
X * 
X * 		     Tel: +49-30-314-22972
X * 		     E-mail: shape@coma.uucp or shape@db0tui62.bitnet
X */
X/*LINTLIBRARY*/
X/*
X *	Shape/AFS
X *
X *	afhash.c -- manage hashtable for user defined attributes
X *
X *	Author: Axel Mahler, TU-Berlin
X *
X *      adapted by: Andreas Lampen, TU-Berlin (andy@coma.UUCP)
X *					      (andy@db0tui62.BITNET)
X *
X *	$Header: afhash.c[1.4] Wed Feb 22 16:27:37 1989 andy@coma published $
X *
X *	EXPORT:
X *	af_hashinit -- initialize hash table
X *      af_hashfree -- detach hash table (free allocated memory)
X *      af_hashsym -- put entry into hashtable
X *      af_fhash -- get hash value
X *      af_replsym -- replace symbol in hashtable
X *      af_delsym -- delete symbol from hashtable
X *      af_symlookup -- look for symbol in hashtable
X *      af_vallookup -- look for single value
X *      af_lhashsyms -- create a list of all symbols in hashtable
X *      af_hashcopy -- copy hashtable
X *	af_match -- test match of user defined attributes
X *      af_dumphtb -- dump hash table
X */
X 
X#include <stdio.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <string.h>
X#ifdef SUNOS_4_0
X#include <strings.h>
X#endif
X
X#include "typeconv.h"
X#include "afsys.h"
X#include "afs.h"
X
X#ifdef CCOLL
Xint af_collcnt = 0;
Xint af_symcount = 0;
X#endif
X
X#ifdef MEMDEBUG
Xextern FILE *memprot;
X#endif
X#ifdef HASHDEBUG
Xextern FILE *hashprot;
X#endif
X
XAf_hashent af_hashentry; /* hashtable entry that was found during last */
X                         /* retrieve operation */
X
X/*=====================================================================
X * af_hashinit -- initialize hash table
X *
X *=====================================================================*/ 
X
XEXPORT af_hashinit (htab, hsize, af_fhash) 
X     Af_hash *htab; 
X     int hsize, (*af_fhash)();
X{
X  char *malloc();
X
X  /* initialize Hash - structure */
X  htab->hsize = hsize;
X  if ((htab->hashtb = (Af_hashent *)malloc ((unsigned) (htab->hsize*sizeof (Af_hashent)))) == NULL)
X    FAIL ("hashinit", "malloc", AF_ESYSERR, ERROR);
X  htab->fhash = af_fhash;
X
X  /* set hashlist all zeros */
X  bzero ((char *)htab->hashtb, htab->hsize*sizeof (Af_hashent));
X  return (AF_OK);
X}
X
X
X/*=====================================================================
X * af_hashfree -- detach hash table (free allocated memory)
X *
X * may be slow; perhaps a memory management with af_malloc would be 
X * better.
X *=====================================================================*/ 
X
XEXPORT af_hashfree (htab)
X     Af_hash *htab;
X{
X  register int  i;
X  Af_hashent    *entry;
X
X  for (i=0; i<htab->hsize; i++)
X    {
X      if (htab->hashtb[i].next)
X	{
X	  entry = htab->hashtb[i].next;
X	  do
X	    {
X#ifdef MEMDEBUG
X	      fprintf (memprot, "%x(sym-fr)\n", entry->symbol);
X#endif
X	      free (entry->symbol);
X#ifdef MEMDEBUG
X	      fprintf (memprot, "%x(e-fr)\n", entry);
X#endif
X	      free ((char *)entry); 
X	    }
X	  while (entry = entry->next);
X	}
X      if (htab->hashtb[i].symbol)
X	{
X#ifdef MEMDEBUG
X	  fprintf (memprot, "%x(sym-fr)\n", entry->symbol);
X#endif
X	  free (htab->hashtb[i].symbol);
X	}
X    }
X  free ((char *)htab->hashtb);
X  htab->hashtb = (Af_hashent *)0;
X}
X
X
X/*=====================================================================
X * af_hashsym -- put entry into hashtable
X *
X *=====================================================================*/ 
X
XEXPORT char *af_hashsym (htab, symbol, list)
X     Af_hash    *htab; 
X     char       *symbol;
X     Af_revlist *list;
X{
X  /*
X   * put entry into hashtable. Only called, if symbol hasn't been found in 
X   * hashtable. Function returns pointer to the symbol-string.
X   */
X  int symindex;
X  Af_hashent *new, *curptr;
X  char *retptr, *malloc();
X
X#ifdef HASHDEBUG
X  fprintf (hashprot, "HASHSYM: %s\n", symbol);
X#endif
X  symindex = htab->fhash (htab->hsize, symbol);
X  if (!htab->hashtb[symindex].symbol)  /* found entry is not used yet */
X    {
X      if ((htab->hashtb[symindex].symbol = malloc ((unsigned) (strlen (symbol) + sizeof (char)))) == (char *)0)
X	FAIL ("hashsym", "malloc", AF_ESYSERR, (char *)0);
X#ifdef MEMDEBUG
X      fprintf (memprot, "%x(sym-al) %d bytes ", htab->hashtb[symindex].symbol,
X	       strlen (symbol) + sizeof (char));
X#endif
X      (void) strcpy (htab->hashtb[symindex].symbol, symbol);
X      htab->hashtb[symindex].revlist = list;
X      htab->hashtb[symindex].next = NULL;
X      retptr = htab->hashtb[symindex].symbol;
X      curptr = &(htab->hashtb[symindex]);
X    }
X  else /* oh boy - a collision! */
X    {
X#ifdef CCOLL
X      af_collcnt++;
X      fprintf (stderr, "%d'th hash-collision (symbol).\n", af_collcnt);
X#endif
X      if ((new = (Af_hashent*)malloc ((unsigned) sizeof (Af_hashent))) == (Af_hashent*)0)
X	FAIL ("hashsym", "malloc", AF_ESYSERR, (char *)0);
X#ifdef MEMDEBUG
X      fprintf (memprot, "%x(e-al) %d bytes ", new, sizeof (Af_hashent));
X#endif
X      if ((new->symbol = malloc ((unsigned) (strlen (symbol) + sizeof (char)))) == (char *)0)
X	FAIL ("hashsym", "malloc", AF_ESYSERR, (char *)0);
X#ifdef MEMDEBUG
X      fprintf (memprot, "%x(sym-al) %d bytes ", new->symbol,
X	       strlen (symbol) + sizeof (char));
X#endif
X      (void) strcpy (new->symbol, symbol);
X      new->revlist = list;
X      new->next = NULL;
X      curptr = &htab->hashtb[symindex];
X      while (curptr->next)
X	curptr = curptr->next;
X      curptr->next = new;
X      curptr = curptr->next; /* points to new entry */
X      retptr =  new->symbol;
X    } /* endif */
X
X  /* filter out double values if list == *0 */
X  /* not yet implemented (filter out double values) */
X
X  return (retptr);
X} /* end af_hashsym */
X
X
XEXPORT int af_fhash (htabsiz, hstr) /* from Aho/Ullman */
X     int  htabsiz; 
X     char *hstr;
X{
X  register char *p;
X  register unsigned long hval, g;
X
X  hval = 0;
X  for (p = hstr; (*p!=AF_UDANAMDEL) && (*p!=AF_UDAVALDEL) && (*p!='\0'); p++)
X    {
X      hval = (hval << 4) ^ (*p);
X      if (g = hval & 0xf0000000)
X	{
X	  hval = hval ^ (g >> 24);
X	  hval = hval ^ g;
X	}
X    }
X  return (hval % htabsiz);
X}
X
X/*=====================================================================
X * af_replsym -- replace symbol in hashtable
X *
X *=====================================================================*/ 
X
XEXPORT char *af_replsym (htab, symbol, list)
X     Af_hash    *htab; 
X     char       *symbol;
X     Af_revlist *list;
X{
X  int symindex;
X  Af_hashent *entry;
X  char *realloc();
X
X#ifdef HASHDEBUG
X  fprintf (hashprot, "REPLSYM: %s\n", symbol);
X#endif
X  symindex = htab->fhash (htab->hsize, symbol);
X  if (htab->hashtb[symindex].symbol)  /* found something */
X    {
X      if (!af_symcmp (&htab->hashtb[symindex], symbol, list))  /* found it ? */
X	{ 
X	  if ((htab->hashtb[symindex].symbol =
X	       realloc (htab->hashtb[symindex].symbol, (unsigned) (strlen (symbol) + sizeof (char)))) == (char *)0)
X	    FAIL ("replsym", "realloc", AF_ESYSERR, (char *)0);
X	  (void) strcpy (htab->hashtb[symindex].symbol, symbol);
X	  htab->hashtb[symindex].revlist = list;
X	  return (htab->hashtb[symindex].symbol);
X	}
X      else /* maybe it is somewhere down the gully */ 
X	{ 
X	  entry = &htab->hashtb[symindex];
X	  while (entry->next)
X	    {
X	      entry = entry->next;
X	      if (!af_symcmp (entry, symbol, list))
X		{
X		  if ((entry->symbol = 
X		       realloc (entry->symbol, (unsigned) (strlen (symbol) + sizeof (char)))) == (char *)0)
X		    FAIL ("replsym", "realloc", AF_ESYSERR, (char *)0);
X		  (void) strcpy (entry->symbol, symbol);
X		  entry->revlist = list;
X		  return (entry->symbol);
X		}
X	    }
X	}
X    }
X  /* when we reach this point, the symbol hasn't been known */
X
X  /* this should never occur */
X  FAIL ("replsym", "symbol not found", AF_EINTERNAL, (char *)0);
X} /* end af_replsym */
X
X/*=====================================================================
X * af_delsym -- delete symbol from hashtable
X *
X *=====================================================================*/ 
X
XEXPORT af_delsym (htab, symbol, list)
X     Af_hash    *htab; 
X     char       *symbol;
X     Af_revlist *list;
X{
X  int  symindex;
X  Af_hashent *del, *succ;
X  char *malloc();
X
X#ifdef HASHDEBUG
X  fprintf (hashprot, "DELSYM: %s\n", symbol);
X#endif
X  symindex = htab->fhash (htab->hsize, symbol);
X  if (!htab->hashtb[symindex].symbol) /* no entry found (should never occur) */
X    FAIL ("delsym", "symbol not found", AF_EINTERNAL, ERROR); 
X
X  del = &htab->hashtb[symindex];
X  if (!af_symcmp (del, symbol, list))  /* found it ? */
X    {
X#ifdef MEMDEBUG
X      fprintf (memprot, "%x(sym-fr)\n", del->symbol);
X#endif
X      free (del->symbol);
X
X      if (del->next) /* if there are more entries */
X	{
X#ifdef HASHDEBUG
X  fprintf (hashprot, "NEXT: %s\n", del->next->symbol);
X#endif
X	  del->symbol = del->next->symbol;
X          del->revlist = del->next->revlist;
X	  succ = del->next->next;
X#ifdef MEMDEBUG
X  fprintf (memprot, "%x(e-fr)\n", del->next);
X#endif
X	  free ((char *)del->next);
X	  del->next = succ;
X	}
X      else
X	{
X	  del->symbol = (char *)0;
X          del->revlist = (Af_revlist *)0;
X	  del->next = (Af_hashent *)0;
X	}
X      return (AF_OK);
X    }
X  else /* search for entry in gully */
X    {
X      while (del->next)
X	{
X	  if (!af_symcmp (del->next, symbol, list))
X	    {	  
X#ifdef MEMDEBUG
X	      fprintf (memprot, "%x(sym-fr)\n", del->next->symbol);
X#endif
X	      free (del->next->symbol);
X	      succ = del->next->next;
X#ifdef MEMDEBUG
X  fprintf (memprot, "%x(e-fr)\n", del->next);
X#endif
X	      free ((char *)del->next);
X	      del->next = succ;
X	      return (AF_OK);
X	    }
X	  del = del->next;
X	}
X      FAIL ("delsym", "symbol not found (in gully)", AF_EINTERNAL, ERROR);
X    }
X}
X
X/*=====================================================================
X * af_symlookup -- look for symbol in hashtable
X *
X *=====================================================================*/ 
X
XEXPORT char *af_symlookup (htab, symbol, listin, listout)
X     Af_hash    *htab; 
X     char       *symbol; 
X     Af_revlist *listin, **listout;
X{
X  /* 
X   * Function searches htab for an entry with the given name symbol.
X   * If such an entry exists, a pointer to the symbol string is returned
X   * and the external variable af_cursymval is set to the corresponding
X   * symbolvalue
X   */
X  int where;
X  Af_hashent *targ;
X  bool delivernext = FALSE;
X
X  where = htab->fhash (htab->hsize, symbol);
X  if (htab->hashtb[where].symbol)  /* well, we found at least something */
X    {
X      /* if we search a specific revlist in the gully */
X      if (listin)
X	{
X	  if (!af_symcmp (&htab->hashtb[where], symbol, listin))
X	    delivernext = TRUE;
X
X	  targ = &htab->hashtb[where];
X	  while (targ = targ->next)
X	    {
X	      if (!af_symcmp (targ, symbol, (Af_revlist *)0))
X		{
X		  if (delivernext)
X		    {
X		      af_hashentry = *targ;
X		      *listout = targ->revlist;
X		      return (targ->symbol);
X		    }
X		  else
X		    if (targ->revlist == listin)
X		      delivernext = TRUE;
X		}
X	    }
X	}
X      else /* normal case */
X	{
X	  if (!af_symcmp (&htab->hashtb[where], symbol, (Af_revlist *)0))
X	    { 
X	      af_hashentry = htab->hashtb[where];
X	      if (listout != (Af_revlist **)0)
X		*listout = htab->hashtb[where].revlist;
X	      return htab->hashtb[where].symbol;
X	    }
X	  else /* maybe it is somewhere down the gully */ 
X	    { 
X	      targ = &htab->hashtb[where];
X	      while (targ->next)
X		{
X		  targ = targ->next;
X		  if (!af_symcmp (targ, symbol, (Af_revlist *)0))
X		    {
X		      af_hashentry = *targ;
X		      if (listout != (Af_revlist **)0)
X			*listout = targ->revlist;
X		      return (targ->symbol);
X		    }
X		}
X	    }
X	}
X    }
X  /* when we come to this point, the symbol hasn't been known */
X  if (listout != (Af_revlist **)0)
X    *listout = (Af_revlist *)0;
X  return ((char *)0);
X}
X
X/*=====================================================================
X * af_vallookup -- look for single value
X *
X *=====================================================================*/ 
X
XEXPORT char *af_vallookup (entry, value)
X     Af_hashent *entry;
X     char *value; 
X{
X  char *valptr;
X
X  if (valptr = index (entry->symbol, AF_UDANAMDEL))
X    valptr += sizeof (char);
X
X  /* search until value is found */
X  while (af_valcmp (valptr, value))
X    {
X      if ((valptr = index (valptr, AF_UDAVALDEL)) == (char *)0) 
X	return (char *)0;
X      valptr += sizeof (char);
X    }
X
X  return (valptr);
X}
X
X/*=====================================================================
X * af_lhashsyms -- create a list of all symbols in hashtable.
X *                 A (char *)0 terminated pointerlist, listing all
X *                 symbols in the hashtable is created.
X *
X *=====================================================================*/ 
X
XEXPORT af_lhashsyms (htab, symbollist)
X     Af_hash *htab;
X     char    **symbollist;
X{
X  register int i, j=0, size=0;
X  register Af_hashent *h;
X  
X  if (htab->hashtb != (Af_hashent *)0)
X    {
X      for (i = 0; i < htab->hsize; i++)
X	if (htab->hashtb[i].symbol != (char *)0)
X	  {
X	    h = &htab->hashtb[i];
X	    while (h) 
X	      {
X		symbollist[j] = h->symbol;
X		size = size + (strlen (h->symbol)+1);
X		j++;
X		h = h->next;
X	      }
X	  }
X    }
X  symbollist[j] = (char *)0;
X  return (size);
X}
X
X
X/*=====================================================================
X * af_hashcopy -- copy hash table
X *
X *=====================================================================*/ 
X
XEXPORT af_hashcopy (oldhtab, newhtab) 
X     Af_hash *oldhtab, *newhtab;
X{
X  register i;
X  char *af_hashsysm(), *list[AF_MAXUDAS];
X
X
X  /* initialize new hashtable */
X  newhtab->hsize = oldhtab->hsize;
X  newhtab->fhash = oldhtab->fhash;
X
X  /* copy hashtable */
X  (void) af_lhashsyms (oldhtab, list);
X  i=0;
X  while (list[i] != (char *)0)
X    {
X      (void) af_hashsym (newhtab, list[i], (Af_revlist *)0);
X      i++;
X    }
X
X  return (AF_OK);
X}
X
X
X/*===============================================================
X * af_symcmp -- compare contents of hashtable entry
X *              either of the form name=[value ...]
X *              or                 name; listptr;
X *           Return values like strcmp.
X *
X *==============================================================*/
X
XLOCAL af_symcmp (entry, str, listptr)
X     Af_hashent *entry;
X     char       *str;
X     Af_revlist *listptr;
X{
X  char *str1;
X
X  /* if a listpointer is given */
X  if (listptr)
X    {
X      if (entry->revlist == listptr)
X	return (strcmp (entry->symbol, str));
X      else
X	return (1);
X    }
X  else
X    {
X      str1 = entry->symbol;
X      while (*str1 == *str)
X	{
X	  if ((*str1 == AF_UDANAMDEL) || (*str1 == '\0'))
X	    return (0);
X	  str1++;
X	  str++;
X	}
X      if (((*str1 == AF_UDANAMDEL) && (*str =='\0')) ||
X	  ((*str1 =='\0') && (*str == AF_UDANAMDEL)))
X	return (0);
X      else
X	
Xreturn (*str1 - *str);
X    }
X}
X
X/*===============================================================
X * af_valcmp -- compare single values in a string of the form
X *                          name=[value1 value2 ...]
X *           Return values like strcmp.
X *
X *==============================================================*/
X
XLOCAL af_valcmp (str1, str2)
X     char *str1, *str2;
X{
X  while (*str1 == *str2)
X    {
X      if ((*str1 == AF_UDAVALDEL) || (*str1 == '\0'))
X	return (0);
X      str1++;
X      str2++;
X    }
X  if (((*str1 == AF_UDAVALDEL) && (*str2 =='\0')) ||
X      ((*str1 =='\0') && (*str2 == AF_UDAVALDEL)))
X    return (0);
X  else
X    return (*str1 - *str2);
X}
X
X/*====================================================================
X *    af_match
X *    returnes FALSE if entry matches, else TRUE
X *
X *====================================================================*/
X
XEXPORT af_match (entry, hashtab)
X     char    *entry;
X     Af_hash *hashtab;
X{
X  char *valptr, *af_symlookup(), *af_vallookup();
X
X  /* if user defined attribute does not exist */
X  if ((af_symlookup (hashtab, entry, (Af_revlist *)0, (Af_revlist **)0))
X                                                              == (char*)0)
X      return (ERROR);
X
X  /* else compare values */
X  if (valptr = index (entry, AF_UDANAMDEL))
X    {
X      do
X	{
X	  valptr = valptr + sizeof (char);
X	  if ((af_vallookup (&af_hashentry, valptr) == (char *)0)
X	      && (*valptr != '\0'))
X	    return (ERROR);
X	}
X      while (valptr = index (valptr, AF_UDAVALDEL));
X    }
X  return (AF_OK);
X}
X
X/**** DEBUG **** DEBUG **** DEBUG **** DEBUG **** DEBUG **** DEBUG ****/
X
X/*=====================================================================
X * af_dumphtb -- dump hashtable
X *
X *=====================================================================*/ 
X
XEXPORT af_dumphtb (htab) /* for debug purposes */
X     Af_hash *htab;
X{
X  register int i;
X  register Af_hashent *h;
X
X#ifdef CCOLL
X  fprintf (stderr, "Hash-collision statistics:\n");
X  fprintf (stderr, "Table-size: %d\tNo. of symbols: %d\tCollisions: %d\n",
X	   htab->hsize, af_symcount, af_collcnt);
X#endif
X
X  for (i = 0; i < htab->hsize; i++)
X    {
X      if (htab->hashtb[i].symbol[0])
X	{
X	  h = &htab->hashtb[i];
X	  while (h) 
X	    {
X	      fprintf (stderr, "\nsymbol: (%d) %s -- list: %x", 
X		       i, h->symbol, h->revlist);
X	      h = h->next;
X	    }
X	}
X      else fprintf (stderr, ".");
X    }
X}
X
X
END_OF_FILE
if test 17913 -ne `wc -c <'src/afs/afhash.c'`; then
    echo shar: \"'src/afs/afhash.c'\" unpacked with wrong size!
fi
# end of 'src/afs/afhash.c'
fi
if test -f 'src/vfind/vfind.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/vfind/vfind.c'\"
else
echo shar: Extracting \"'src/vfind/vfind.c'\" \(17438 characters\)
sed "s/^X//" >'src/vfind/vfind.c' <<'END_OF_FILE'
X/*
X * Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
X *  and U. Pralle
X * 
X * This software is published on an as-is basis. There is ABSOLUTELY NO
X * WARRANTY for any part of this software to work correctly or as described
X * in the manuals. We do not accept any liability for any kind of damage
X * caused by use of this software, such as loss of data, time, money, or 
X * effort.
X * 
X * Permission is granted to use, copy, modify, or distribute any part of
X * this software as long as this is done without asking for charge, and
X * provided that this copyright notice is retained as part of the source
X * files. You may charge a distribution fee for the physical act of
X * transferring a copy, and you may at your option offer warranty
X * protection in exchange for a fee.
X * 
X * Direct questions to: Tech. Univ. Berlin
X * 		     Wilfried Koch
X * 		     Sekr. FR 5-6 
X * 		     Franklinstr. 28/29
X * 		     D-1000 Berlin 10, West Germany
X * 
X * 		     Tel: +49-30-314-22972
X * 		     E-mail: shape@coma.uucp or shape@db0tui62.bitnet
X */
X/*  LAST EDIT: Mon Feb 20 14:15:16 1989 by Uli Pralle (coma!uli)  */
X/*
X * vfind.c
X */
X#ifndef lint
Xstatic char *AFSid = "$Header: vfind.c[1.6] Tue Feb 21 20:22:53 1989 uli@coma published $";
Xstatic char *Objfile = "vfind.c[1.6] published";
X#ifdef CFFLGS
X  static char *Cflags = CFFLGS;
X#endif
X#endif
X/*
X * Log for /u/shape/dist-tape/src/vfind/vfind.c[1.6]
X * 	Tue Feb 21 20:22:53 1989 uli@coma published $
X *  
X *    	* Vfind is the same as find(1) except that it has more afs
X *    	related primaries such as -eq, -le, -lt, -ge, -gt, -uda,
X *  	-symbolic, -locked, -locker, etc.
X *  
X *  	* vfind has problems with udas.
X *  
X *  	* vfind is part of the shape toolkit release for comp.sources.unix.
X *  
X *  
X */
X
X#include <sys/types.h>
X#include <sys/stat.h>
X#include <sys/dir.h>
X#include <sys/wait.h>
X#include <stdio.h>
X#include <strings.h>
X#include <afs.h>
X#include <afsapp.h>
X#include <ParseArgs.h>
X
X#include "atk.h"
X
Xtypedef struct expr *Expr;	/* short hand */
Xstruct expr {
X  int (*eval)();		/* evaluator */
X  Expr left;			/* left op */
X  Expr right;			/* right op */
X};
X
Xextern char *getwd();
Xextern char *malloc();
Xextern char *re_comp();
X
Xstatic char *progname;			/* av[0] w/o leading path */ 
Xstatic char startdir[MAXPATHLEN+1]; /* dir at beginning of process */
Xstatic char garbage[80];	/* for error messages */
Xstatic int nac;			/* ac after option parsing */
Xstatic char **nav;		/* av after option parsing */
Xstatic int npaths;		/* pathname list */
Xstatic struct expr *exprl;	/* expression list */
Xstatic int idx;			/*  */
Xstatic long now;		/* time in secs */
Xstatic Af_attrs attrs;		/* attr buf */
Xstatic Af_set set, bset;	/* attr set */
Xstatic int Bflag, Pflag, Fflag;
X
X/* Options */
Xstatic int vf_prune_opt () {
X  Pflag++;
X  return 0;
X}
X
Xstatic int vf_version_opt () {
X  char *vfversion();
X  
X  (void) printf ("This is %s version %s.\n", progname, vfversion());
X  (void) printf ("AFS version %s.\n", af_version());
X  return 1;			/* force termination */
X}
X
Xstatic int vf_b_opt () {
X  Bflag++;
X  return 0;
X}
X
Xstatic int vf_f_opt () {
X  Fflag++;
X  return 0;
X}
X
Xstatic int vf_help_opt () {
X  extern OptDesc optdesc[];
X  pa_ShortUsage(progname, optdesc, "path-list expression");
X
X  return 1;
X}
X
XOptDesc optdesc[] = {
X  { "version", OPT_IS_SWITCH, vf_version_opt },
X  { "bpool", OPT_IS_SWITCH, vf_b_opt},
X  { "h", OPT_IS_SWITCH, vf_help_opt},
X  { "prune", OPT_IS_SWITCH, vf_prune_opt},
X  { "force", OPT_IS_SWITCH, vf_f_opt},
X  { (char *) NULL, NULL, NULL },
X};
X
Xvoid byebye(i) {
X  (void) chdir("/tmp");		/* in case of -pg. */
X  exit(i);
X}
X
Xvoid Usage() {
X  (void) fprintf (stderr,"%s: usage: %s path-list expression.\n",
X		  progname , progname);
X  byebye(1);
X}
X
X/* primaries */
Xstatic int print () {
X  puts(at_getbndvers(&attrs));
X  return 1;
X}
X
Xchar *mkedpat(pat) char *pat; {
X  char pattern[1024];
X  char *cp;
X  int i;
X
X  if (pat && *(cp = pat) == '\0')
X    return (char *) NULL;
X
X  *pattern = '^';
X  for (i = 1; *cp; cp++) {
X    if (i >= 1024) {
X      (void) fprintf (stderr, "%s: pattern to long.\n", progname);
X      byebye(1);
X    }
X    
X    switch (*cp) {
X    case '?':
X      pattern[i++] = '.';
X      break;
X    case '*':
X      pattern[i++] = '.'; pattern[i++] = '*';
X      break;
X    default:
X      pattern[i++] = *cp;
X      break;
X    }
X  }
X  pattern[i++] = '$'; pattern[i] = '\0';
X  
X  if ((cp = malloc ((unsigned) (strlen(pattern) + 1))) == (char *) NULL) {
X    (void) fprintf (stderr, "%s: out of memory.\n", progname);
X    byebye(1);
X  }
X  return strcpy(cp, pattern);
X}
X
Xstatic int name (exp) Expr exp; {
X  char *cp;
X  
X  if (cp = re_comp ((char *) exp->left)) {
X    (void) fprintf (stderr, "%s: %s\n", progname, cp);
X    byebye(1);
X  }
X
X  return re_exec(at_getfilename(&attrs));
X
X}
X
Xstatic int state (exp) Expr exp; {
X  return attrs.af_state == (int) exp->left;
X}
X
Xstatic int uda (exp) Expr exp; {
X  return (at_matchuda(&attrs, (char *) exp->left));
X}
X
Xstatic int symname (exp) Expr exp; {
X  char symnameuda[AF_UDANAMLEN+1];
X
X  return at_matchuda(&attrs, sprintf(symnameuda, "%s=%s", SYMNAME,
X				     (char *) exp->left));
X}
X
Xstatic int perm (exp) Expr exp; {
X  return (attrs.af_mode & (int) exp->right & 07777) == (int) exp->left;
X}
X
Xstatic int user (exp) Expr exp; {
X  return (!strcmp((char *)exp->left, attrs.af_owner.af_username)
X	  && (exp->right ? !strcmp((char *)exp->right,
X				  attrs.af_owner.af_userhost) : 1));
X}
X
Xstatic int locked () {
X  return (attrs.af_locker.af_username[0] != '\0');
X}
X
Xstatic int locker (exp) Expr exp; {
X  return (!strcmp((char *)exp->left, attrs.af_locker.af_username)
X	  && (exp->right ? !strcmp((char *)exp->right,
X				  attrs.af_locker.af_userhost) : 1));
X}
X
Xstatic int type (exp) Expr exp; {
X  return (attrs.af_mode&S_IFMT) == (int) exp->left;
X}
X
Xstatic int vl () {
X  printf ("%s %s %s %8d %s %s\n",
X	  at_getmode(&attrs),
X	  at_getversstate(&attrs, 0),
X	  at_getuser(&(attrs.af_owner)),
X	  attrs.af_size,
X	  at_getdate(&attrs),
X	  at_getbndvers(&attrs));
X  return 1;
X}
X
Xstatic int eq (exp) Expr exp; {
X  return (attrs.af_gen == (int) exp->left) &&
X    (attrs.af_rev == (int) exp->right);
X}
X
Xstatic int lt (exp) Expr exp; {
X  return (attrs.af_gen < (int) exp->left ||
X	  (attrs.af_gen == (int) exp->left &&
X	   attrs.af_rev < (int) exp->right));
X}
X
Xstatic int le (exp) Expr exp; {
X  return lt(exp) || eq(exp);
X}
X
Xstatic int gt (exp) Expr exp; {
X  return (attrs.af_gen > (int) exp->left ||
X	  (attrs.af_gen == (int) exp->left &&
X	   attrs.af_rev > (int) exp->right));
X}
X
Xstatic int ge (exp) Expr exp; {
X  return gt(exp) || eq(exp);
X}
X
X
X#define SECSPERDAY 86400L
Xstatic int comptime(secs, days, sign)
X     time_t secs;
X     int days;
X     char sign;
X{
X  int d;
X  
X  d = (int) ((now - secs) / SECSPERDAY);
X  switch (sign) {
X  case '+': return (d>days);
X  case '-': return (d < (days * -1));
X  default: return (d==days);
X  }
X}
X
Xstatic int mtime (exp) Expr exp; {
X  return comptime(attrs.af_mtime, (int) exp->left, *(char*)(exp->right));
X}
X
Xstatic int atime (exp) Expr exp; {
X  return comptime(attrs.af_atime, (int) exp->left, *(char*)(exp->right));
X}
X
Xstatic int chngtime (exp) Expr exp; {
X  return comptime(attrs.af_ctime, (int) exp->left, *(char*)(exp->right));
X}
X
Xstatic int stime (exp) Expr exp; {
X  return comptime(attrs.af_stime, (int) exp->left, *(char*)(exp->right));
X}
X
Xstatic int ltime (exp) Expr exp; {
X  return comptime(attrs.af_ltime, (int) exp->left, *(char*)(exp->right));
X}
X
Xstatic int execute (exp) Expr exp; {
X  char *pav[40], *arg;
X  int i, j;
X  int pid, wpid;
X  union wait retcode;
X
X  i = (int) exp->left;
X  for (j = 0; strcmp((arg = nav[i++]), ";"); j++)
X    if (!strcmp(arg, "{}"))
X      pav[j] = at_getbndvers(&attrs);
X    else
X      pav[j] = arg;
X
X  pav[j] = (char *) NULL;
X  if (j == 0) return 1;
X  
X  (void) fflush(stdout);
X  switch (pid = fork()) {
X  case -1:
X    perror (sprintf(garbage, "%s: fork failed\n", progname));
X    byebye(1);
X    break;
X  case 0:
X    (void) chdir(startdir);
X    /*VARARGS*/
X    (void) execvp(pav[0], pav);
X    (void) perror("vfind: exec failed");
X    (void) kill (getpid(), SIGHUP);
X    _exit(127);
X    break;
X  default:
X    while ((wpid = wait(&retcode)) != -1 && wpid != pid);
X    if (retcode.w_status&0177) {
X      (void) fprintf (stderr, "%s: execution terminated\n", progname);
X      byebye(1);
X    }
X    return (!retcode.w_status);
X    break;
X  }
X  /*NOTREACHED*/
X}
X
Xstatic int not (exp) Expr exp; {
X  return ! ((*exp->left->eval) (exp->left));
X}
X
Xstatic int and (exp) Expr exp; {
X  return ((*exp->left->eval) (exp->left) &&
X	  (*exp->right->eval) (exp->right)) ? 1 : 0;
X}
X
Xstatic int or (exp) Expr exp; {
X  return ((*exp->left->eval) (exp->left) ||
X	  (*exp->right->eval) (exp->right)) ? 1 : 0;
X}
X
X/* constructors */
Xstatic Expr build(func, l, r)
X     int (*func)();
X     Expr l, r;
X{
X  Expr this;
X  if ((this = (Expr) malloc ((unsigned) sizeof (struct expr))) ==
X      (Expr) NULL) {
X    (void) fprintf (stderr, "%s: out of memory.\n", progname);
X    byebye (1);
X  }
X
X  this->eval = func; this->left = l; this->right = r;
X  return this;
X}
X
Xstatic void skip() {
X  if (nav[idx])
X    idx++;
X  else {
X    (void) fprintf (stderr, "%s: parsing error\n", progname);
X    byebye(1);
X  }
X}
X
Xstatic Expr primary () {
X  char *prim, *val, *cp;
X  char c;
X  int i = 0;
X  int mode = 0;
X  int mask = 0;
X
X  val = cp = (char *) NULL;
X  
X  if (!(prim = nav[idx])) {
X    (void) fprintf (stderr, "%s: parsing error\n", progname);
X    byebye(1);
X  }
X  
X  if (*prim != '-') {
X    (void) fprintf(stderr, "%s: %s is not a primary\n", progname, prim);
X    byebye(1);
X  }
X  prim++;
X  if (!strcmp (prim, "print"))
X    return build(print, (Expr) NULL, (Expr) NULL);
X  if (!strcmp(prim, "ls") || !strcmp(prim, "vl"))
X    return build(vl, (Expr) NULL, (Expr) NULL);
X  if (!strcmp(prim, "locked"))
X    return build(locked, (Expr) NULL, (Expr) NULL);
X  
X  skip();
X  if (!(val = nav[idx])) {
X    (void) fprintf (stderr, "%s: parsing error\n", progname);
X    byebye(1);
X  }
X  
X  if (!strcmp (prim, "name"))
X    return build(name, (Expr) mkedpat(val), (Expr) NULL);
X  if (!strcmp(prim, "type")) {
X    c = *val;
X    i = (c=='b' ? S_IFBLK : c=='c' ? S_IFCHR :
X	 c=='d' ? S_IFDIR : c=='f' ? S_IFREG :
X	 c=='l' ? S_IFLNK : c=='s' ? S_IFSOCK : NULL);
X      return build(type, (Expr) i, (Expr) NULL);
X  }
X  if (!strcmp(prim, "perm")) {
X    while(c = *val++)
X      if (c=='-') mask++;
X      else {
X	c -= '0'; mode <<= 3; mode += c;
X      }
X    return build(perm, (Expr) mode, (Expr) (mask ? mode : 07777));
X  }
X  if (!strcmp(prim, "atime"))
X    return build(atime, (Expr) atoi(val), (Expr) val);
X  if (!strcmp(prim, "ctime"))
X    return build(chngtime, (Expr) atoi(val), (Expr) val);
X  if (!strcmp(prim, "mtime"))
X    return build(mtime, (Expr) atoi(val), (Expr) val);
X  if (!strcmp(prim, "stime"))
X    return build(stime, (Expr) atoi(val), (Expr) val);
X  if (!strcmp(prim, "ltime"))
X    return build(ltime, (Expr) atoi(val), (Expr) val);
X  if (!strcmp(prim, "user")) {
X    if (cp = rindex(val, '@')) *cp++ = '\0';
X    return build(user, (Expr) val, (Expr) cp);
X  }
X  if (!strcmp(prim, "eq")) {
X    if (cp = rindex(val, '.')) *cp++ = '\0';
X    return build(eq, (Expr) atoi(val), (Expr) atoi(cp));
X  }
X  if (!strcmp(prim, "le")) {
X    if (cp = rindex(val, '.')) *cp++ = '\0';
X    return build(le, (Expr) atoi(val), (Expr) atoi(cp));
X  }
X  if (!strcmp(prim, "lt")) {
X    if (cp = rindex(val, '.')) *cp++ = '\0';
X    return build(lt, (Expr) atoi(val), (Expr) atoi(cp));
X  }
X  if (!strcmp(prim, "ge")) {
X    if (cp = rindex(val, '.')) *cp++ = '\0';
X    return build(ge, (Expr) atoi(val), (Expr) atoi(cp));
X  }
X  if (!strcmp(prim, "gt")) {
X    if (cp = rindex(val, '.')) *cp++ = '\0';
X    return build(gt, (Expr) atoi(val), (Expr) atoi(cp));
X  }
X  if (!strcmp(prim, "locker")) {
X    if (cp = rindex(val, '@')) *cp++ = '\0';
X    return build(locker, (Expr) val, (Expr) cp);
X  }
X  if (!strcmp(prim, "exec") || !strcmp(prim, "ok")) {
X    i = idx;
X    while(nav[++idx] && strcmp(nav[idx], ";"));
X    return build(execute, (Expr) i, (Expr) prim);
X  }
X  if (!strcmp(prim, "state"))
X    return build(state, (Expr) at_string2state(val), (Expr) NULL);
X  if (!strcmp(prim,"uda"))
X    return build(uda, (Expr) val, (Expr) NULL);
X  if (!strcmp(prim,"symbolic"))    
X    return build(symname, (Expr) val, (Expr) NULL);
X  (void) fprintf (stderr,"%s: unknown primary %s.\n", progname, prim);
X  byebye(1);
X  /*NOTREACHED*/
X}
X
Xstatic Expr alternation();	/* forward declaration */
X
Xstatic Expr grouping () {
X  Expr expr;
X  
X  if (!strcmp(nav[idx], "(")){
X    skip();
X    expr = alternation();
X    if (nav[idx] && !strcmp(nav[idx], ")")) {
X      skip();
X      return expr;
X    }
X    (void) fprintf (stderr, "%s: missing closing ')'.\n", progname);
X    byebye(1);
X  }
X  else {
X    expr = primary();
X    skip();		/* primary() does not skip the */
X				/* processed token, so we do it here. */
X    return expr;
X  }
X  /*NOTREACHED*/
X}
X
Xstatic Expr negation() {
X  if (nav[idx] && !strcmp(nav[idx], "!")) {
X    skip();
X    return build(not, grouping(), (Expr) NULL);
X  }
X  else
X    return grouping();
X}
X
Xstatic Expr concatenation() {
X  Expr left;
X  char *this;
X  
X  left = negation ();
X  this = nav[idx];
X  if (this && (!strcmp(this, "-a") || !strcmp(this, "!") ||
X	       !strcmp(this,"(") || (*this == '-' && strcmp(this, "-o")))){
X    if (!strcmp(this,"-a")) skip();
X    return build(and, left, concatenation());
X  }
X  else
X    return left;
X}
X
Xstatic Expr alternation() {
X  Expr left;
X  
X  left = concatenation();
X  if (nav[idx] && !strcmp(nav[idx], "-o")) {
X    skip();
X    return build(or, left, concatenation());
X  }
X  else
X    return left;
X}
X
Xstatic Expr expression() {
X  return alternation();
X}
X
Xstatic int dselect (d)
X     struct direct *d;
X{
X  char *name = d->d_name;
X  
X  if ((name[0] == '.' && name[1] == '\0') ||
X       (name[0] == '.' && name[1] == '.' && name[2] == '\0'))
X    return 0;
X  return 1;
X}
X
Xstatic int adselect (d)
X     struct direct *d;
X{
X  char *name = d->d_name;
X  
X  if (d->d_name[d->d_namlen -1] == AF_ARCHEXT)
X    return 1;
X  return 0;
X}
X
Xstatic int indp (dp, dpentr, name, len)
X     struct direct **dp;
X     char *name;
X     int len, dpentr;
X{
X  int i;
X  for (i = 0; i < dpentr; i++)
X    if (dp[i]->d_namlen == len && !strcmp(dp[i]->d_name, name))
X      return 1;
X  return 0;
X}
X
Xstatic void traverse (name, afs_is_dir)
X     char *name;
X     int afs_is_dir;		/* 1 if symbolic link */
X{
X  struct stat buf, abuf;
X  struct direct **dp, **adp;
X  int nhits, ahits, i;
X  static int ncalls;
X  char *cp;
X
X  (void) af_initattrs(&attrs); (void) af_initset(&set);
X  (void) strcpy(attrs.af_syspath, af_afpath(name));
X  (void) strcpy(attrs.af_name, af_afname(name));
X  (void) strcpy(attrs.af_type, af_aftype(name));
X
X  if (!afs_is_dir)		/* afs dir is symbolic link */
X    attrs.af_state = AF_BUSY;
X
X  if (af_find(&attrs, &set) == -1) {
X    (void) af_perror(sprintf(garbage, "%s: af_find(%s)", progname, name));
X    return;
X  }
X  if (Bflag) {
X    (void) af_initset(&bset);
X    if (af_bpfind(&attrs, &bset) == -1) {
X      (void) af_perror(sprintf(garbage, "%s: bp_find(%s)", progname, name));
X      (void) af_dropset(&set);
X      return;
X    }
X    (void) af_union(&set, &bset, &set); (void) af_dropset(&bset);
X  }
X	
X  nhits = af_nrofkeys(&set);
X  (void) af_sortset(&set, AF_ATTHUMAN);
X  for (i = 0; i < nhits; i++) {
X    if (af_gattrs(&(set.af_klist[i]),&attrs) == -1) {
X      (void) af_perror(sprintf(garbage,"%s: af_gattrs():",progname));
X      continue;
X    }
X    (*exprl->eval)(exprl);
X  }
X  (void) af_dropset(&set);
X  
X  if ((lstat(name, &buf) == -1) ||
X      ((buf.st_mode&S_IFMT) != S_IFDIR) ||
X      (Pflag && ncalls) || 
X      !strcmp(name, AF_SUBDIR))
X    return;
X
X  if (chdir(name) == -1)
X    return;
X  
X  if ((nhits = scandir(".", &dp, dselect, NULL)) == -1) {
X    fprintf (stderr, "%s: can't open dir %s.\n", progname, name);
X    return;
X  }
X  afs_is_dir = (lstat(AF_SUBDIR, &abuf) != -1 &&
X		(((abuf.st_mode&S_IFMT) == S_IFDIR) || Fflag));
X  if (afs_is_dir &&
X      ((ahits = scandir(AF_SUBDIR, &adp, adselect, NULL)) != -1)) {
X    for (i = 0; i < ahits; i++) {
X      cp = adp[i]->d_name + 2;
X      cp[adp[i]->d_namlen -3] = '\0';
X      if ((cp && *cp) && !indp(dp, nhits, cp, adp[i]->d_namlen - 3)) {
X	ncalls++; traverse(cp, afs_is_dir); ncalls--;
X      }
X      (void) free((char *)adp[i]);
X    }
X    (void) free((char *)adp);
X  }
X  for (i = 0; i < nhits; i++){
X    ncalls++; traverse(dp[i]->d_name, afs_is_dir); ncalls--;
X    (void) free((char *)dp[i]);
X  }
X  (void) free((char *)dp);
X
X  (void) chdir("..");
X  return;
X}
X
Xmain (ac, av)
X     int ac;
X     char *av[];
X{
X  char *cp;
X  struct stat buf;
X  int afs_is_dir;
X  
X  progname = (cp = rindex(av[0], '/')) ? ++cp : av[0];
X  if (ParseArgs(ac, av, &nac, &nav, optdesc)) byebye(1);
X  (void) getwd(startdir); (void) time(&now);
X  
X  if (nac < 2) Usage();
X  for (idx = 0; idx < nac; idx++) /* find path list */
X    if (*nav[idx] == '-' ||  *nav[idx] == '!' || *nav[idx] == '(') break;
X  if (!(npaths = idx)){
X    (void) fprintf (stderr, "%s: no path list.\n", progname); Usage();
X  }
X  if (idx == nac) {
X    (void) fprintf (stderr, "%s: no expression.\n", progname); Usage();
X  }
X
X  if ((exprl = expression()) == (Expr) NULL) byebye(1);
X  
X  for (idx = 0 ; idx < npaths; idx++) {	/* for all directories */
X    (void) chdir(startdir);	/* back to normal */
X    afs_is_dir = (lstat(sprintf(garbage, "%s/%s", cp = nav[idx], AF_SUBDIR),
X			&buf) != -1 &&
X		  (((buf.st_mode&S_IFMT) == S_IFDIR) || Fflag));
X    traverse(cp, afs_is_dir);
X  }
X
X  byebye(0);
X}
END_OF_FILE
if test 17438 -ne `wc -c <'src/vfind/vfind.c'`; then
    echo shar: \"'src/vfind/vfind.c'\" unpacked with wrong size!
fi
# end of 'src/vfind/vfind.c'
fi
if test -f 'tutorial/make2shape.ms' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'tutorial/make2shape.ms'\"
else
echo shar: Extracting \"'tutorial/make2shape.ms'\" \(17381 characters\)
sed "s/^X//" >'tutorial/make2shape.ms' <<'END_OF_FILE'
X.\"
X.\" Copyright (C) 1989, 1990 W. Koch, A. Lampen, A. Mahler, W. Obst,
X.\"  and U. Pralle
X.\" 
X.\" This software is published on an as-is basis. There is ABSOLUTELY NO
X.\" WARRANTY for any part of this software to work correctly or as described
X.\" in the manuals. We do not accept any liability for any kind of damage
X.\" caused by use of this software, such as loss of data, time, money, or 
X.\" effort.
X.\" 
X.\" Permission is granted to use, copy, modify, or distribute any part of
X.\" this software as long as this is done without asking for charge, and
X.\" provided that this copyright notice is retained as part of the source
X.\" files. You may charge a distribution fee for the physical act of
X.\" transferring a copy, and you may at your option offer warranty
X.\" protection in exchange for a fee.
X.\" 
X.\" Direct questions to: Tech. Univ. Berlin
X.\" 		     Wilfried Koch
X.\" 		     Sekr. FR 5-6 
X.\" 		     Franklinstr. 28/29
X.\" 		     D-1000 Berlin 10, West Germany
X.\" 
X.\" 		     Tel: +49-30-314-22972
X.\" 		     E-mail: shape@coma.uucp or shape@db0tui62.bitnet
X.\" 
X.NH 1
XA quick guide through shape for make users
X.PP
XThis chapter is intended to give users of \fImake\fR a quick guide
Xhow to change their development environment when switching
Xfrom the usage of \fImake\fR to \fIshape\fR.
X.PP
XThe first step is quite simple. As the shape program is upward
Xcompatible to make, you can just type \fCshape\fR instead of \fCmake\fR
Xand shape will fulfill your (make\-)wishes.
XOoops, we nearly forgot to mention, that you have to create a
Xsubdirectory named \fCAFS\fR first.
XYou will later see why.
X.PP
XBy using shape instead of make on your old Makefile you can
Xalready take advantage of one important improvement of shape
Xwith respect to make.
XShape is sensible for changes in the compile environment.
XIf you change for example your compiler flags or preprocessor
Xdefinitions in the Makefile, shape will recompile all 
Xfiles that are affected by this change (make does not).
XFor example, if \fCfoo.o\fR was generated by \fCcc -c -DBSD43\fR
Xand you change your Makefile in order to produce a version
Xsuitable for System V so that \fCfoo.c\fR should be
Xproduced by \fCcc -c -DSYSV\fR, shape recognizes this change,
Xin contrary to make.
X.PP
XYou might ask yourself now "how can shape do this ?".
XBefore we can give you an answer to this question, you got to learn
Xto know a few things about the architecture of the shape toolkit.
XThe whole shape toolkit is implemented on top af an object base (AFS),
Xthat is able to store software objects (regular UNIX files for instance)
Xas a bunch
Xof content data together with an arbitrary number of attributes.
XThese things are called \fIattributed software objects\fR (ASO).
XAttributes are strings of the general form \fCname=value\fR.
XAFS supports a set of standard attributes (examples are:
Xname, type, version number, owner, author) an unlimited number
Xof \fIuser defined attributes\fR.
XEach application may introduce its own user defined attributes.
XAdditionally, AFS has a built-in version control system that
Xsupports the storage and identification of different versions
Xof software objects.
XFor further details on the object base see afintro (3).
X.PP
XShape uses the mechanism of application defined attributes for recording
Xthe compile
Xenvironment (the name of the transformation tool and all options and
Xarguments) of each derived file (you may know be more familiar with
Xthe term \fI.o file\fR).
XSo, shape bases its decision whether to recompile a system component
Xfrom its source not only on comparing the date of last modification
X(like make does) but also on the comparison of the compile environments.
X.PP
XDue to that mechanism, you have to bear one inconvenience on your journey
Xfrom make to shape. Your first \fCshape\fR call causes all your files
Xto be recompiled. This is necessary to initialize the object base.
X.PP
XBut you get indemnified for that with the next step.
XSuppose, you want to produce different versions of your system
Xby setting different compiler options.
XTypically, you have a local test system that is compiled and linked
Xwith the \fC-g\fR option (for symbolic debugging) and you publish
X(install) product versions of your system compiled with \fC-O\fR
X(optimizing) and the symbol table stripped off.
X.PP
XSo you might think, shape recompiles the whole stuff with \fC-O\fR
Xfor publication and afterwards recompiles it again with \fC-g\fR
Xfor continuing the work.
X.br
XNot true !
X.br
XAll derived files generated during a system building operation driven
Xby shape are stored in a cache named \fIderived object pool\fR
X(or \fIbinary pool\fR).
XThe derived object pool is able to store multiple versions of
Xequally named derived files and to distinguish between them by the
Xuser defined attributes they have.
XSo when you want to continue your work after an installation,
Xyou old \fC.o\fR files are still there and
Xshape restores them from the derived object pool instead
Xof regenerating them from their source files.
X.PP
XTo prevent your disk from being flooded with derived files, each binary
Xpool has a limited size (a maximum number of files stored in it).
XBinary pools are administered in a cache fashion.
XThe oldest (access date) derived files get removed if no additional
Xfiles can be inserted due to the size limit.
XYou can define the size of your private binary pool by setting
Xthe environment variable \fCAFSBPSIZ\fR to an appropriate value.
XA reasonable value is (\fI number of your source files * 2 \fR).
XThe default value is 64.
X.PP
XRemember, all your work with shape up to now did not require
Xany modification of your Makefile.
XIf you don't like shape up to now \- no problem, \fCrm -rf AFS\fR
Xremoves all shape specific stuff and you can go on with make.
XBut if you like it, it is the right time to rename your Makefile to
X\fCShapefile\fR and begin to implant shape specific things.
X.NH 2
XVersion Control
X.PP
XBeside the make functionality (system building), a main feature
Xof the shape toolkit is the integration of a version control
Xsystem in your system building environment.
XShape does not only operate on regular UNIX files, but on
Xmultiple versions of files.
XFor this reason, we constructed a version control system which is
Xintegral part of the shape toolkit.
X.PP
XThis version control system has a lot of similarities to existing
Xversion control systems like RCS and SCCS, but also some
Ximprovements with respect to these systems.
XYou can read more about the version control in the manual pages.
XWe just want to mention one important feature of the version control system
Xhere, that is important to know while reading this chapter.
X.PP
XShape's version control system has a built in version status model.
XThe essential thing for you to know about this is, that there are
X"busy" and "saved" versions. Saved versions have
Xa version number that consists of a generation number and
Xa revision number (eg. 4.3). Saved versions cannot be modified;
Xonce saved, they are "read only". Busy versions are the place
Xwhere development takes place. They are alterable and have no
Xversion number yet. Each regular UNIX file is a busy version
Xin this sense. Saved versions come into being by making a copy
Xof a busy version, tagging a version number to it and entering it
X(as delta) in the appropriate archive file in the AFS subdirectory.
XThe status model is more complex, but for further reading of this
Xchapter it is enough when you know the states "busy", "saved"
Xand "published".
XPublished versions play a role when you working in a multi
Xprogrammer team. You can use the publishing mechanism of the
Xshape toolkit then to make specific versions of the system
Xcomponent you work on accessible for your co workers.
X.PP
XIf you have worked with another version control system before
Xit is advisable to transform your old version histories to
Xshape histories.
XIf you have used RCS before, you can have this be done
Xautomatically by running the program \fIrcs2afs\fR.
X.NH 2
XVersion Selection Rules
X.PP
XOk, long enough now, let's dive into shape's selection mechanism.
XMake's task is it, to produce names \- so called \fItargets\fR.
XIt does this by traversing a system model consisting of
X\fItarget \- dependent\fR lines to determine which components
Xgo into a system and producing targets from their dependents.
XTargets and dependents may correspond to equally named files in the
Xfilesystem to which transformation tools are applied.
XWhen doing make's job, due to the introduction of multiple versions
Xof files, shape has the additional task to select one
Xspecific version of each file involved.
XIf does this by evaluating \fIversion selection rules\fR 
Xgiven by the
Xprogrammer in a special part of the Shapefile, called the \fIrule-section\fR.
XA version selection is driven by evaluating a selection rule
Xwith the name given as parameter.
XRemember that each version (software object) has a number of
Xattributes attached to it. These attributes are the ground,
Xselection rules operate on.
XSo let's look at the following rule section:
X.nf
X.sp
X\fC#% RULE-SECTION
Xdefaultrule:
X	*, attr (state, busy).
X#% END-RULE-SECTION\fR
X.fi
X.sp
X.PP
XA rule section always begins with a comment symbol (\fC#\fR) followed
Xby a percent sign and the string \fCRULE-SECTION\fR.
XIt ends accordingly (see example).
XEach rule begins with the rule name followed by a colon (in the above case
X\fCdefaultrule:\fR).
XThe rest ot the selection rule is a named sequence of \fIalternatives\fR,
Xseparated by semicolons, which form a logical OR expression. Each alternative
Xconsists of a sequence of \fIpredicates\fR, separated by commas, which form
Xa logical AND expression. A selection rule succeeds if one of its
Xalternatives succeeds (i.e. leads to the unique identification of some
Xdocument instance).
XIn alternatives, the first predicate (e.g. \fC*\fR or \fC*.c\fR) is usually a
Xpattern against which the name of a document that has to be retrieved
Xis matched.  The patterns used by shape have the same structure as those
Xused by \fCed\fR.
X.PP
XThe rule above consists of only one alternative, so do not worry if you
Xdo not find the semicolon in it.
XBeside that, you never need to write a rule like this, because it is
Xthe default rule \- this rule is active if no other selection rule
Xis given.
XIt makes exactly what make does: for each name (\fC*\fR) it selects the
Xbusy version, which is an equally named regular UNIX file.
XThis rule makes sense if you have no saved versions.
X.PP
XTo go on with shape it is necessary that you begin to work with
Xthe version control system.
XYou should save a releasable state of
Xyour work by applying the command \fCsave\fR to all the files
Xbelonging to your system.
XThis can probably be done by inserting an entry in your Shapefile
Xthat looks like
X.sp
X.nf
X\fCsave:
X	save $(COMPONENTS)\fR
X.fi
X.sp
Xand calling \fCshape save\fR.
X.PP
XIf you have done this, a rule like
X.nf
X.sp
X\fC#% RULE-SECTION
Xreleaserule:
X	*, attr (state, saved), attrmax (version).
X#% END-RULE-SECTION\fR
X.fi
X.sp
Xmakes sense for building releases.
XThis rule selects for each component (\fC*\fR) of your system the
Xlatest (\fCattrmax (version)\fR) saved (\fCattr (state, saved)\fR)
Xversion.
XIf for example there is \fIno\fR saved version of your component
X\fCfoo.c\fR shape complains about that with the message:
X\fCshape - selection rule for foo.c failed\fR
X.PP
XYou can activate a selection rule by inserting its name in the 
Xtarget - dependents line of your system at the place of the first dependent.
XFor example
X.nf
X.sp
X\fCall: releaserule program1 program2\fR
Xor
X\fCprogram: releaserule $(COMPONENTS)\fR
X.sp
X.fi
Xcan be meaningful rule activations.
XOnce set active, a selection rule is inherited to all subtargets.
XBut be careful, the active selection rule can also be redefined
Xwith each single target \-
Xa mechanism that takes a little while to get used to.
XSo if you are wondering about shape selecting other versions than 
Xyou expect, check your Shapefile for constructions like:
X.nf
X.sp
X\fCall: releaserule program1 program2\fR
X
X\fCprogram1: defaultrule $(COMPONENTS1)\fR
X
X\fCprogram2: $(COMPONENTS2)\fR
X.fi
X.sp
XIn this case \fCshape all\fR builds
X\fCprogram1\fR with \fCdefaultrule\fR (explicitly set) and program2
Xwith \fCreleaserule\fR (inherited).
X.PP
XWe cannot deal with all issues of the selection rule mechanism here;
Xyou find more details on this in the chapter (.\" to be inserted),
Xbut just to illustrate the power of expression sleeping in the
Xselection rule mechanism,
Xan example for a very complex selection rule.
XIt does not make very much sense but it shall give you an idea
Xof what you can express with the selection rule mechanism.
X.nf
X.sp
X\fC#% RULE-SECTION
X\&...
Xcomplexrule:
X	# to be inserted
X#% END-RULE-SECTION\fR
X.fi
X.sp
X.NH 2
XVariants
X.PP
XAfter having played around with selection rules
Xyou may turn your attention to another very powerful mechanism of shape.
XRemember the example from the beginning of this chapter that dealt with
Xdifferent \fIvariants\fR (<- thats the buzzword) of your system for
Xdifferent machines.
XLet's introduce another section in the Shapefile.
XThe first and the last line of this section look very much like
Xthese of the rule section with the word \fCVARIANT\fR instead of \fCRULE\fR.
X.nf
X.sp
X\fC#% VARIANT-SECTION
Xvclass system ::= (bsd, sysV, sunos)
X
Xbsd:
X	vpath = bsd
X	vflags = -DBSD
XsysV:
X	vpath = sysV
X	vflags = -DSYSV
Xsunos:
X	vpath = sunos
X	vflags = -DSUNOS
X#% END-VARIANT-SECTION\fR
X.fi
X.sp
X.PP
XThis helps you to deal on one hand with variants that are generated from
X\fIone\fR source file by setting different precompiler switched and
Xon the other hand with variants that are stored in equally named 
Xfiles in different directories.
XWith a variant activated, shape passes variant dependent options
X(vflags: eg. \fC-DBSD\fR) to each transformation tool (eg. \fCcc\fR)
Xit triggers and it extends its search path for files by the
Xdirectories named in vpath (eg. the subdirectory \fCbsd\fR).
X.PP
XThe activation mechanism for variants is quite similar to the rule
Xactivation.
XJust after the rule name you can optionally insert the variant name
Xpreceded by a plus sign (\fC+\fR).
XThe following example of a target \- dependent line is suitable for
Xcalling shape with \fCshape SYSTEM=sunos all\fR. This builds the
Xbsd variant of your system.
X.nf
X.sp
X\fCall: releaserule +$(SYSTEM) program1 program2\fR
X.fi
X.sp
XIt is advisable to have a line like
X.nf
X.sp
X\fCSYSTEM=bsd\fR
X.fi
X.sp
Xsomewhere in your Shapefile in order to define a default for your
XSYSTEM macro. You can then omit the definition for SYSTEM on the command
Xline when you want to build the default variant.
XOne little hint in respect to activation of variants. When shape
Xcomes up with an error message like
X\fCshape - don't know how to shape +blabla\fR, this points to a
Xspelling mismatch between variant naming and variant activation.
X.PP
XIn a variant definition, not only vpath and vflags can be defined.
XYou can also redefine any macro.
XAnother typical application is
X.nf
X.sp
X\fC#% VARIANT-SECTION
Xvclass quality ::= (test, test_profiling, final)
X
Xtest:
X	CFLAGS = -g
X	LDFLAGS = -g
Xtest_profiling:
X	CFLAGS = -pg -g
X	LDFLAGS = -pg -g
Xfinal:
X	CFLAGS = -O
X	LDFLAGS = -s
X#% END-VARIANT-SECTION\fR
X.fi
X.sp
Xthat helps to manage the other case of system variants that occured in an
Xexample earlier in tis paper.
XWith the targets
X.nf
X.sp
X\fCall: +$(SYSTEM) +test_profiling program1 program2
X
Xinstall: +$(SYSTEM) +final program1 program2\fR
X.fi
X.sp
Xyou can build test systems by calling \fCshape all\fR and release systems
Xby calling \fCshape install\fR.
X.PP
XA few words about vclasses (to be inserted).
XThe name of the vclass is not explicitely used up to now, but there should
Xbe a equally named Macro (in capital letters) that holds the actual
Xvariant setting.
XFor this macro (as said earlier), a default should be defined.
X.NH 2
XBuilding up a target raster.
X.PP
XRule and variant activations should only be inserted in top level targets.
XSee the sample Shapefiles for examples.
X.NH 2
XMacros
X.PP
XMacro naming conventions -> shape manual.
X.NH 2
XTransformation Rules
X.PP
XLike in make, you can write implicit transformation rules.
XShape understands make syntax, but we recommend to use
Xthe extended syntax described in the following paragraph
X.PP
XTransformation rules consist of a \fItransformation specification\fR,
Xand a \fItransformation script\fR. Transformation specifications
Xdescribe prerequisites and resulting objects of a transformation. The
Xtransformation script is a template for a shell script that
Xwill be passed to a shell process upon activation of a transformation.
XThe syntax for these rules is an extension of Make's default rule
Xspecification formalism. \*(sh's rule by which the transformation
Xof a C source object into a '\fC\&.\&o\fR' (speak: dot-o) derived object
Xis defined looks like:
X.sp
X.nf
X\fC\s-1%.o: %.c : +(CC) +(CFLAGS)
X	$(CC) -c $(CFLAGS) %.c\s+1\fR
X.fi
X.LP
X.PP
XA request to produce a derived object \- let's say \fCxyzzy.o\fR \- would,
Xby evaluating the transformation rule, result in the compilation
Xof \fCxyzzy.c\fR with the compiler defined by 
Xthe macro \fCCC\fR, with compile switches defined by \fCCFLAGS\fR.
XThe percent sign is consistently substituted by the name \(lqxyzzy\(rq
Xthroughout the transformation rule. The notation \fI$(NAME)\fR substitutes
Xthe value of the macro \fINAME\fR, while \fI+(NAME)\fR substitutes the
Xentire macro definition (i.e. \fINAME=value\fR).
X
END_OF_FILE
if test 17381 -ne `wc -c <'tutorial/make2shape.ms'`; then
    echo shar: \"'tutorial/make2shape.ms'\" unpacked with wrong size!
fi
# end of 'tutorial/make2shape.ms'
fi
echo shar: End of archive 20 \(of 33\).
cp /dev/null ark20isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 33 archives.
    rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0
-- 
Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.