[comp.sources.unix] v19i032: A software configuration management system, Part19/33

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

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



#! /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 19 (of 33)."
# Contents:  src/afs/afdelta.c src/shape/rule.c src/vc/doretrv.c
# Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:11 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/afs/afdelta.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/afs/afdelta.c'\"
else
echo shar: Extracting \"'src/afs/afdelta.c'\" \(17045 characters\)
sed "s/^X//" >'src/afs/afdelta.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/*
X *	Shape/AFS
X *
X *	afdelta.c -- Delta processing
X *
X *	Author: Andreas Lampen, TU-Berlin (andy@coma.UUCP
X *					   andy@db0tui62.BITNET)
X *
X *	$Header: afdelta.c[1.4] Wed Feb 22 16:27:26 1989 andy@coma published $
X *
X *	EXPORT:
X *	af_nodelta -- save entire file
X *	af_dodelta -- save delta
X *	af_undodelta -- rebuild file
X *      af_rmdelta -- remove delta from delta chain
X */
X
X#include <stdio.h>
X
X#include "typeconv.h"
X#include "afsys.h"
X#include "afs.h"
X
X/*====================================================================
X *    af_nodelta
X *
X * Store the busy version (busykey) without building a delta.
X * "nodelta" is necessary for saving the initial version (1.0)
X * or for storing versions without delta technique.
X *
X *====================================================================*/
X
XEXPORT af_nodelta (busykey, savekey)
X
X     Af_key *busykey;
X     Af_key *savekey;
X{
X  char	*malloc();
X  FILE	*busyfile;
X  
X  VATTR(savekey).af_fsize = af_retfsize (busykey->af_ldes->af_busyfilename);
X  VATTR(savekey).af_dsize = 0;
X  VATTR(savekey).af_repr = AF_CHUNK;
X  VATTR(savekey).af_data = 
X    af_malloc (savekey->af_ldes, (unsigned) VATTR(savekey).af_fsize);
X
X  if ((busyfile = fopen (busykey->af_ldes->af_busyfilename, "r")) == (FILE *)0)
X    FAIL ("nodelta", "fopen", AF_ESYSERR, ERROR);
X
X  if (fread (VATTR(savekey).af_data, sizeof (char), (Size_t) VATTR(savekey).af_fsize, busyfile) != VATTR(savekey).af_fsize)
X    FAIL ("nodelta", "fread", AF_ESYSERR, ERROR);
X
X  (void) fclose (busyfile);
X  savekey->af_ldes->af_datasize += VATTR(savekey).af_fsize;
X  return (AF_OK);
X} /* af_nodelta */
X
X
X
X/*====================================================================
X *    af_dodelta
X *
X * Build a delta between a busy version (busykey) and its preceeding
X * version (predkey) and store it as a new version (savekey).
X * If no busykey is given ((Af_key *)0), build a null delta and store
X * it as new version.
X * The latter case is needed, if a version shall be stored with different
X * attributes but unchanged contents. 
X *
X *====================================================================*/
X
XEXPORT af_dodelta (busykey, predkey, savekey)
X
X     Af_key *busykey;
X     Af_key *predkey;
X     Af_key *savekey;
X{
X  char	*delname, *malloc();
X  FILE	*busyfile, *delfile;
X  
X  if (busykey != (Af_key *)0 )
X    {
X      /* read in busyfile for delta processing */
X      VATTR(savekey).af_fsize = af_retfsize(busykey->af_ldes->af_busyfilename);
X      
X      VATTR(savekey).af_data =
X	af_malloc (savekey->af_ldes, (unsigned) VATTR(savekey).af_fsize);
X      if ((busyfile = fopen (busykey->af_ldes->af_busyfilename,"r"))
X	                                                        == (FILE *)0)
X	FAIL ("dodelta", "fopen", AF_ESYSERR, ERROR);
X
X      if (fread (VATTR(savekey).af_data, sizeof (char), (Size_t) VATTR(savekey).af_fsize, busyfile) != VATTR(savekey).af_fsize)
X	FAIL ("dodelta", "fread", AF_ESYSERR, ERROR);
X
X      (void) fclose (busyfile);
X      savekey->af_ldes->af_datasize += VATTR(savekey).af_fsize;
X      VATTR(savekey).af_dsize = 0;
X      VATTR(savekey).af_repr = AF_CHUNK;
X    }
X  else
X    /* produce null delta (new generation) */
X    {
X      VATTR(savekey).af_data = VATTR(predkey).af_data;
X      VATTR(savekey).af_fsize = VATTR(predkey).af_fsize;
X      VATTR(savekey).af_dsize = 0;
X      VATTR(savekey).af_repr = AF_CHUNK;
X      savekey->af_ldes->af_datasize += VATTR(savekey).af_fsize;
X    }
X
X  /* if version opens a new branch, no delta processing is necessary */
X  if ((predkey->af_ldes == (Af_revlist *)0) || 
X      (VATTR(predkey).af_repr == AF_DELTA))
X    { 
X      VATTR(savekey).af_predgen = AF_NOVNUM;
X      VATTR(savekey).af_predrev = AF_NOVNUM;
X      return (AF_OK);
X    }
X
X  /* else do delta processing */
X
X  /* create filename for delta */
X  delname = af_gtmpname (CATTR(savekey).af_syspath, VATTR(savekey).af_name);
X  af_regtmpfile (delname);
X
X  if (lcs (VATTR(savekey).af_data, VATTR(predkey).af_data,
X      VATTR(savekey).af_fsize, VATTR(predkey).af_fsize, delname) == ERROR)
X    FAIL ("dodelta", "", AF_EDELTA, ERROR);
X
X  /* update predversion */
X  /* read deltafile */
X  VATTR(predkey).af_dsize = af_retfsize (delname);
X  if ((VATTR(predkey).af_dsize > VATTR(predkey).af_fsize) || 
X                                      (busykey == (Af_key *)0 ))
X    VATTR(predkey).af_data = af_malloc (predkey->af_ldes, (unsigned) VATTR(predkey).af_dsize);
X
X  if ((delfile = fopen (delname, "r")) == (FILE *)0)
X    FAIL ("dodelta", "fopen", AF_ESYSERR, ERROR);
X
X  if ((fread (VATTR(predkey).af_data, sizeof (char), (Size_t) VATTR(predkey).af_dsize, delfile)) != VATTR(predkey).af_dsize)
X    FAIL ("dodelta", "fread", AF_ESYSERR, ERROR);
X  (void) fclose (delfile);
X
X  /* remove tmp-file */
X  (void) af_unlink (delname);
X  af_unregtmpfile (delname);
X  
X  /* update list descriptor (file is replaced by delta) */
X  savekey->af_ldes->af_datasize -= VATTR(predkey).af_fsize;
X  savekey->af_ldes->af_datasize += VATTR(predkey).af_dsize;
X  VATTR(predkey).af_repr = AF_DELTA;
X  VATTR(predkey).af_succgen = VATTR(savekey).af_gen;
X  VATTR(predkey).af_succrev = VATTR(savekey).af_rev;
X  
X  return (AF_OK);
X} /* af_dodelta */
X
X
X
X/*====================================================================
X *    af_undodelta
X *
X * The version pointed to by deltakey is supposed to be a (at least)
X * saved version represented by a chunk (AF_CHUNK) or a delta (AF_DELTA).
X * Passing a busy version causes an error (AF_NOVERS).
X * Filename has to be the name of an accessible UNIX-file,
X * where the rebuilt version will be stored.
X * The version pointed to by deltakey remains unchanged. 
X *
X *====================================================================*/
X
XEXPORT af_undodelta (deltakey, filename)
X     Af_key *deltakey;
X     char   *filename;
X{
X  Af_key *deltachain, *keyptr;
X  char   *tmpname, *data, *malloc(), *realloc();
X  int    i;
X  off_t  fsize;
X  FILE   *tmpfile;
X
X  /* this error should never occur */
X  if (VATTR(deltakey).af_repr == AF_FILE)
X    FAIL ("undodelta", "wrong kind of representation", AF_EINTERNAL, ERROR);
X
X  if ((deltachain = (Af_key *) malloc ((unsigned) (AF_SEGLEN * sizeof (Af_key)))) == (Af_key *)0)
X    FAIL ("undodelta", "malloc", AF_ESYSERR, ERROR);
X
X  /* collect deltachain */
X  i = 0;
X  deltachain[0] = *deltakey;
X  keyptr = deltakey;
X  while (VATTR(keyptr).af_repr == AF_DELTA)
X    {
X      i++;
X      if ((i & AF_SEGLEN) == AF_SEGLEN) /* if segment is full */
X	if ((deltachain = (Af_key *) realloc ((char *) deltachain, (unsigned) ((i + AF_SEGLEN) * sizeof (Af_key)))) == (Af_key *)0)
X	  FAIL ("undodelta", "realloc", AF_ESYSERR, ERROR);
X
X      if (af_buildkey (deltakey->af_ldes, VATTR(keyptr).af_succgen,
X		       VATTR(keyptr).af_succrev, &(deltachain[i])) == ERROR)
X	FAIL ("undodelta", "delta chain broken", AF_EINTERNAL, ERROR);
X      keyptr = &(deltachain[i]);
X    }
X
X  fsize = VATTR(keyptr).af_fsize;
X  if ((data = malloc ((unsigned) VATTR(keyptr).af_fsize)) == (char *)0)
X    FAIL ("undodelta", "malloc", AF_ESYSERR, ERROR);
X  bcopy (VATTR(keyptr).af_data, data, (Size_t) fsize);
X  /* first step is done */
X  i--;
X
X  /* process delta chain */
X  tmpname = af_gtmpname (CATTR(deltakey).af_syspath, VATTR(deltakey).af_name);
X  af_regtmpfile (tmpname);
X
X  if (i < 0) /* no delta chain */
X    {
X      if ((tmpfile = fopen (tmpname, "w")) == (FILE *)0)
X	FAIL ("undodelta", "fopen", AF_ESYSERR, ERROR);
X      (void) fwrite (data, (Size_t) fsize, sizeof (char), tmpfile);
X      (void) fclose (tmpfile);
X    }
X      
X  /* else */
X  for (i; i >= 0; i--)
X    {
X      keyptr = &(deltachain[i]);
X      if (bsfd (data, VATTR(keyptr).af_data, fsize, VATTR(keyptr).af_dsize,
X		tmpname) == ERROR)
X	FAIL ("undodelta", "", AF_EDELTA, ERROR);
X      if (i == 0) 
X	continue;  /* increase performance */
X      fsize = af_retfsize (tmpname);
X      if ((data = realloc (data, (unsigned) (fsize * sizeof (char)))) == (char *)0)
X	FAIL ("undodelta", "realloc", AF_ESYSERR, ERROR);
X      if ((tmpfile = fopen (tmpname, "r")) == (FILE *)0)
X	FAIL ("undodelta", "fopen", AF_ESYSERR, ERROR);
X      (void) fread (data, (Size_t) fsize, sizeof (char), tmpfile);
X      (void) fclose (tmpfile);
X    }
X  free ((char *) deltachain);
X  free (data);
X
X  (void) af_unlink (filename);
X  if (af_syslink (tmpname, filename) == ERROR)
X    FAIL ("undodelta", "link", AF_ESYSERR, ERROR);
X  (void) af_unlink (tmpname);
X  af_unregtmpfile (tmpname);
X
X  return (AF_OK);
X}
X
X/*====================================================================
X *    af_rmdelta
X *
X *====================================================================*/
X
XEXPORT af_rmdelta (deltakey)
X     Af_key *deltakey;
X{
X  register i;
X  int      succsize, predsize;
X  char     *succdata, *preddata, *malloc(), *realloc(), *tmpname;
X  FILE     *tmpfile;
X  Af_key   *deltachain, *keyptr, *predptr;
X                    /* deltachain shall hold all keys from the physical
X		     * predecessor to the end of the physical line of 
X		     * descent (chunk). That is:
X		     * deltachain[0] = predecessor
X		     * deltachain[1] = deltakey
X		     * deltachain[2] = successor ...
X		     * ... deltachain[n] = chunk
X		     */
X
X  if ((deltachain = (Af_key *) malloc ((unsigned) (AF_SEGLEN * sizeof (Af_key)))) == (Af_key *)0)
X    FAIL ("rmdelta", "malloc", AF_ESYSERR, ERROR);
X
X  /* update predecessor attributes of successor version */
X  if ((VATTR(deltakey).af_succgen != AF_NOVNUM) && 
X      (VATTR(deltakey).af_succrev != AF_NOVNUM))
X    {
X      (void) af_buildkey (deltakey->af_ldes, VATTR(deltakey).af_succgen, VATTR(deltakey).af_succrev, &(deltachain[2]));
X      VATTR((&(deltachain[2]))).af_predgen = VATTR(deltakey).af_predgen;
X      VATTR((&(deltachain[2]))).af_predrev = VATTR(deltakey).af_predrev;
X    }
X
X  /* if deltakey points to the predecessor of the busy version,  */
X  /* update busy version (should be optimized) */
X  /* works only, if busy version is at position 0 */
X  if ((deltakey->af_ldes->af_list[0].af_predgen == VATTR(deltakey).af_gen) &&
X      (deltakey->af_ldes->af_list[0].af_predrev == VATTR(deltakey).af_rev))
X    {
X      deltakey->af_ldes->af_list[0].af_predgen = AF_NOVNUM;
X      deltakey->af_ldes->af_list[0].af_predrev = AF_NOVNUM;
X    }
X  
X  /* if deltakey points to first element in delta chain */
X  /*    no delta processing is necessary */
X  if ((VATTR(deltakey).af_predgen == AF_NOVNUM) && 
X      (VATTR(deltakey).af_predrev == AF_NOVNUM))
X    {
X      return (AF_OK);
X    }
X
X  /* else collect delta chain */
X  (void) af_buildkey (deltakey->af_ldes, VATTR(deltakey).af_predgen,
X	       VATTR(deltakey).af_predrev, &(deltachain[0]));
X  predptr = &(deltachain[0]);
X  deltachain[1] = *deltakey;
X  /* if deltakey points to chunk do nothing else */
X  if ((VATTR(deltakey).af_succgen == AF_NOVNUM) && 
X      (VATTR(deltakey).af_succrev == AF_NOVNUM))
X    {
X      i = 1;
X    }
X  else
X    {
X      i = 2;
X      keyptr = &(deltachain[2]);
X      while (VATTR(keyptr).af_repr == AF_DELTA)
X	{
X	  i++;
X	  if ((i & AF_SEGLEN) == AF_SEGLEN) /* if segment is full */
X	    if ((deltachain = (Af_key *) realloc ((char *) deltachain, (unsigned) ((i+AF_SEGLEN) * sizeof(Af_key)))) == (Af_key *)0)
X	      FAIL ("rmdelta", "realloc", AF_ESYSERR, ERROR);
X	  
X	  (void) af_buildkey (deltakey->af_ldes, VATTR(keyptr).af_succgen,
X		       VATTR(keyptr).af_succrev, &(deltachain[i]));
X	  keyptr = &(deltachain[i]);
X	}
X    }
X
X  tmpname = af_gtmpname (CATTR(deltakey).af_syspath, VATTR(deltakey).af_name);
X  af_regtmpfile (tmpname);
X
X  /* if deltakey points to chunk, only the predecessor version has to */
X  /*    be rebuilt */
X  if (i == 1)
X    {
X      /* generate chunk for predecessor */
X      if (bsfd (VATTR(deltakey).af_data, VATTR(predptr).af_data,
X		VATTR(deltakey).af_fsize, VATTR(predptr).af_dsize, tmpname)
X	  == ERROR)
X	FAIL ("rmdelta", "", AF_EDELTA, ERROR);
X
X      VATTR(predptr).af_repr = AF_CHUNK;
X      /* update sizes in revision list descriptor and in attribute buffer */
X      deltakey->af_ldes->af_datasize -= VATTR(predptr).af_dsize;
X      VATTR(predptr).af_dsize = 0;
X      VATTR(predptr).af_fsize = af_retfsize (tmpname);
X      deltakey->af_ldes->af_datasize += VATTR(predptr).af_fsize;
X
X      /* if VATTR(predptr).af_data points to memory allocated by an own
X       * af_malloc (and not in af_readdata), this memory segment remains
X       * "unfreed" (This is a BUG !).
X       */
X      if ((VATTR(predptr).af_data = af_malloc (predptr->af_ldes, (unsigned) (VATTR(predptr).af_fsize * sizeof(char)))) == (char *)0)
X	FAIL ("rmdelta", "malloc", AF_ESYSERR, ERROR);
X
X      tmpfile = fopen (tmpname, "r");
X      (void) fread (VATTR(predptr).af_data, (Size_t) VATTR(predptr).af_fsize, sizeof (char), tmpfile);
X      (void) fclose (tmpfile);
X      (void) af_unlink (tmpname);
X      af_unregtmpfile (tmpname);
X      VATTR(predptr).af_succgen = AF_NOVNUM;
X      VATTR(predptr).af_succrev = AF_NOVNUM;
X      return (AF_OK);
X    }
X      
X  /* else process delta chain and build pred and succ version */
X  succsize = VATTR(keyptr).af_fsize;
X  if ((succdata = malloc ((unsigned) (VATTR(keyptr).af_fsize * sizeof (char)))) == (char *)0)
X    FAIL ("rmdelta", "malloc", AF_ESYSERR, ERROR);
X  bcopy (VATTR(keyptr).af_data, succdata, succsize);
X  /* first step is done */
X  i--;
X
X  /* first regenerate sucessor version and leave it in the buffer "succdata" */
X  for (i; i >= 2; i--)
X    {
X      keyptr = &(deltachain[i]);
X      if (bsfd (succdata, VATTR(keyptr).af_data, (long) succsize,
X		VATTR(keyptr).af_dsize, tmpname) == ERROR)
X	FAIL ("rmdelta", "", AF_EDELTA, ERROR);
X
X      succsize = af_retfsize (tmpname);
X      if ((succdata = realloc (succdata, (unsigned) (succsize * sizeof(char)))) == (char *)0)
X	FAIL ("rmdelta", "realloc", AF_ESYSERR, ERROR);
X      tmpfile = fopen (tmpname, "r");
X      (void) fread (succdata, (Size_t)succsize, sizeof (char), tmpfile);
X      (void) fclose (tmpfile);
X    }
X  /* regenerate predecessor version in buffer "preddata" */
X  if (bsfd (succdata, VATTR(deltakey).af_data, (long) succsize,
X	    VATTR(deltakey).af_dsize, tmpname) == ERROR)
X    FAIL ("rmdelta", "", AF_EDELTA, ERROR);
X
X  predsize = af_retfsize (tmpname);
X  if ((preddata = malloc ((unsigned) (predsize * sizeof (char)))) == (char *)0)
X    FAIL ("rmdelta", "malloc", AF_ESYSERR, ERROR);
X  tmpfile = fopen (tmpname, "r");
X  (void) fread (preddata, predsize, sizeof (char), tmpfile);
X  (void) fclose (tmpfile);
X  if (bsfd (preddata, VATTR((&(deltachain[0]))).af_data, (long) predsize, VATTR((&(deltachain[0]))).af_dsize, tmpname) == ERROR)
X    FAIL ("rmdelta", "", AF_EDELTA, ERROR);
X  
X  predsize = af_retfsize (tmpname);
X  if ((preddata = realloc (preddata, (unsigned) (predsize * sizeof (char)))) == (char *)0)
X    FAIL ("rmdelta", "realloc", AF_ESYSERR, ERROR);
X  tmpfile = fopen (tmpname, "r");
X  (void) fread (preddata, predsize, sizeof (char), tmpfile);
X  (void) fclose (tmpfile);
X  
X  /* build new delta for predecessor version */
X  if (lcs (succdata, preddata, (long) succsize, (long) predsize, tmpname) == ERROR)
X    FAIL ("rmdelta", "", AF_EDELTA, ERROR);
X
X  /* update sizes in revision list descriptor and in attribute buffer */
X  deltakey->af_ldes->af_datasize -= VATTR(predptr).af_dsize;
X  VATTR(predptr).af_dsize = af_retfsize (tmpname);
X  deltakey->af_ldes->af_datasize += VATTR(predptr).af_dsize;
X
X  /* if VATTR(predptr).af_data points to memory allocated by an own
X   * af_malloc (and not in af_readdata), this memory segment remains
X   * "unfreed" (This is a BUG !).
X   */
X  if ((VATTR(predptr).af_data = af_malloc (predptr->af_ldes, (unsigned) (VATTR(predptr).af_dsize*sizeof(char)))) == (char *)0)
X    FAIL ("rmdelta", "malloc", AF_ESYSERR, ERROR);
X  tmpfile = fopen (tmpname, "r");
X  (void) fread (VATTR(predptr).af_data, (Size_t) VATTR(predptr).af_dsize, sizeof (char), tmpfile);
X  (void) fclose (tmpfile);
X  (void) af_unlink (tmpname);
X  af_unregtmpfile (tmpname);
X  free (succdata);
X  free (preddata);
X  VATTR(predptr).af_succgen = VATTR((&(deltachain[2]))).af_gen;
X  VATTR(predptr).af_succrev = VATTR((&(deltachain[2]))).af_rev;
X  free ((char *) deltachain);
X  return (AF_OK);
X}
X
END_OF_FILE
if test 17045 -ne `wc -c <'src/afs/afdelta.c'`; then
    echo shar: \"'src/afs/afdelta.c'\" unpacked with wrong size!
fi
# end of 'src/afs/afdelta.c'
fi
if test -f 'src/shape/rule.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/shape/rule.c'\"
else
echo shar: Extracting \"'src/shape/rule.c'\" \(17098 characters\)
sed "s/^X//" >'src/shape/rule.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#ifndef lint
Xstatic char *RCSid = "$Header: rule.c,v 3.0 89/01/24 11:36:35 wolfgang Stable $";
X#endif
X#ifndef lint
Xstatic char *ConfFlg = CFFLGS;	/* should be defined from within Makefile */
X#endif
X/*
X * $Log:	rule.c,v $
X * Revision 3.0  89/01/24  11:36:35  wolfgang
X * New System Generation
X * 
X * Revision 2.16  89/01/19  12:38:05  wolfgang
X * check for .IGNORE added
X * 
X * Revision 2.15  89/01/03  13:13:00  wolfgang
X * changes done for lint
X * 
X * Revision 2.14  88/12/21  15:11:59  wolfgang
X * changes done for lint
X * 
X * Revision 2.13  88/12/19  13:24:06  wolfgang
X * things for special targets .BPOOL & .NOBPOOL added.
X * 
X * Revision 2.12  88/12/12  13:16:40  wolfgang
X * bug fixed (something for sun).
X * 
X * Revision 2.11  88/11/22  17:17:14  wolfgang
X * changes done for sun & bugs fixed.
X * 
X * Revision 2.10  88/11/21  15:48:55  wolfgang
X * return code of all malloc's checked
X * 
X * Revision 2.9  88/11/08  11:05:13  wolfgang
X * This version is part of a release
X * 
X * Revision 2.8  88/09/16  12:59:29  wolfgang
X * overload_stdrules() added.
X * 
X * Revision 2.7  88/09/14  10:52:06  wolfgang
X * undone last changes
X * 
X * Revision 2.6  88/09/13  14:41:03  wolfgang
X * Because of bad performance: get_src_name deleted.
X * 
X * Revision 2.5  88/09/09  11:57:33  wolfgang
X * Performance improved. get_src_name has been called to often.
X * 
X * Revision 2.4  88/08/31  12:03:20  wolfgang
X * Standard dependent added to depency list.
X * 
X * Revision 2.3  88/08/23  15:37:13  wolfgang
X * ruledump() has been changed. In dependncy lines the first dependent
X * is supressed if it is a name of a selection rule and we are generating
X * a confid.
X * 
X * Revision 2.2  88/08/23  10:25:36  wolfgang
X * Changed ruledump; now it can be used both to generate confid's
X * and for the -d option.
X * 
X * Revision 2.1  88/08/19  10:17:50  wolfgang
X * This version is part of a release
X * 
X */
X
X/* allow a:b   ?????? geht noch nicht ....
X         a:c
X	 a:d  etc. if only one action is defined !!!!! */
X
X/* :: still not yet implememnted */
X/* intermixing of implicit "." rules and normal targets is *not* allowed */
X
X#include "shape.h"
X#include "rule.h"
X
Xextern int hashval();
Xextern int errexit();
Xextern char *expandmacro();
Xextern char *get_src_name();
Xextern struct rules *stdruletab[];
Xextern int implicit_suffs[];
Xextern Bool is_old_rule();
Xstruct rules *ruletab[RULETABSIZE];
Xchar *firsttarget;
XBool oldrule;
X
Xint depnr;
Xint targnr;
Xint cmdnr;
Xint heritnr;
Xchar *targfield[MAXTARGS];
Xchar *depfield[MAXDEPS];
Xchar *cmdfield[MAXCMDS];
Xchar *heritfield[MAXHERIT];
X
X
Xruledef(string)
X     char *string;
X{
Xint i = 0;
Xint k = 0;
Xchar klazu;
Xchar *t;
X
Xtargnr = 0;
Xdepnr = 0;
Xcmdnr = 0;
Xheritnr = 0;
X
Xif ((t = malloc( (unsigned) strlen(string) + 1)) == NIL)
X  errexit(10,"malloc");
X
Xstring = expandmacro(string);
X
Xwhile(string[i] != ':')
X  {
X    while((string[i] != ' ') && (string[i] != '\t') && (string[i] != ':'))
X      {
X	t[k] = string[i];
X	i++;
X	k++;
X      }
X    t[k] = '\0';
X    targnr++;
X    if (targnr > MAXTARGS)
X      errexit(27, "targets");
X    if ((targfield[targnr] = malloc((unsigned) strlen(t) + 1)) == NIL)
X      errexit(10,"malloc");
X    (void) strcpy(targfield[targnr], t);
X#ifdef DEBUG_RULE
Xprintf("target no. %d = #%s#\n", targnr, targfield[targnr]);
X#endif DEBUG_RULE
X    k = 0;
X    while((string[i] == ' ') || (string[i] == '\t'))
X      i++;
X  }
Xif (string[i+1] == ':')
X  {
X    doublecolon = TRUE;
X    i = i + 2;
X  }
Xelse
X  i++;
X
Xwhile((string[i] != '\0') && (string[i] != ';') && (string[i] != ':'))
X  {
X    while((string[i] == ' ') || (string[i] == '\t') ||
X	  (string[i] == '\\'))
X      {
X	if ((string[i] == '\\') && (string[i+1] == '\n'))
X	  i = i+2;
X	else
X	  i++;
X      }
X    while((string[i] != ' ') && (string[i] != '\t') &&
X	  (string[i] != ';') && (string[i] != '\0') &&
X	  (string[i] != ':') && (string[i] != '\\'))
X      {
X	t[k] = string[i];
X	i++;
X	k++;
X      }
X    t[k] = '\0';
X    if (k != 0)
X      {
X	depnr++;
X	if (depnr > MAXDEPS)
X	  errexit(27, "dependents");
X	if ((depfield[depnr] = malloc((unsigned) strlen(t) + 1)) == NIL)
X	  errexit(10,"malloc");
X	(void) strcpy(depfield[depnr],t);
X#ifdef DEBUG_RULE
Xprintf("dependent no. %d=#%s#\n", depnr , depfield[depnr]);
X#endif DEBUG_RULE
X      }
X    k = 0;
X  }
X
X
Xwhile((string[i] == ' ') || (string[i] == '\t'))
X  i++;
X
X/* heritage */
X
Xk = 0;
Xif (string[i] == ':')
X  {
X    i++;
X    while( (string[i] != '\0') )
X      {
X	while((string[i] == ' ') || (string[i] == '\t'))
X	  i++;
X	if (string[i] != '+')
X	  errexit(26, &string[i]);
X	if (string[i+1] == '(')
X	  klazu = ')';
X	else
X	  {
X	    if (string[i+1] == '{')
X	      klazu = '}';
X	    else
X	      klazu = ' ';
X	  }
X
X	while (string[i] != klazu)
X	  {
X	    t[k] = string[i];
X	    i++;
X	    k++;
X	    if (string[i] == '\0')
X	      errexit(26,&string[i]);
X	  }
X	t[k] = string[i];
X	k++;
X	i++;
X	t[k] = '\0';
X	heritnr++;
X	if (heritnr > MAXHERIT)
X	  errexit(27, "iherits");
X	if ((heritfield[heritnr] = malloc((unsigned) strlen(t) + 1)) == NIL)
X	  errexit(10,"malloc");
X	(void) strcpy(heritfield[heritnr],t);
X	k = 0;
X      }
X  }
X
X/* commands on ruledef line */
Xif( string[i] == ';')
X  {
X    i++;
X    while( (string[i] != '\0'))
X      {
X	t[k] = string[i];
X	i++;
X	k++;
X      }
X    t[k] = '\0';
X    cmdnr++;
X    if (cmdnr > MAXCMDS)
X      errexit(27, "commands");
X    if ((cmdfield[cmdnr] = malloc((unsigned) strlen(t) + 1)) == NIL)
X      errexit(10,"malloc");
X    if (t[strlen(t)-1] == '\n')
X      t[strlen(t)-1] = '\0';
X    (void) strcpy(cmdfield[cmdnr], t);
X#ifdef DEBUG_RULE
Xprintf("command[%d] = #%s#\n", cmdnr, cmdfield[cmdnr]);
X#endif DEBUG_RULE
X  }
X}
X
Xrulecont(string)
X     char *string;
X{
X/* only commands have been found */
Xcmdnr++;
Xif(cmdnr > MAXCMDS)
X  errexit(27, "commands");
Xif ((cmdfield[cmdnr] = malloc ((unsigned) strlen(string) + 1)) == NIL)
X  errexit(10,"malloc");
Xif (string[strlen(string)-1] == '\n')
X  string[strlen(string)-1] = '\0';
X(void) strcpy(cmdfield[cmdnr], string);
X#ifdef DEBUG_RULE
Xprintf("command[%d] = #%s#\n", cmdnr, cmdfield[cmdnr]);
X#endif DEBUG_RULE
X}
X
Xruleend()
X{
X  struct rules *current;
X  struct cmds *curcmd;
X  int i = 0;
X  int j = 0;
X  int jjj = 0;
X  int kkk = 0;
X  int xx = 0;
X  int ss = 0;
X  int minus = 0;
X  Bool src_found = FALSE;
X  int hasht = 0;
X  char *p;
X  char *srcname;
X  Bool std_rule = FALSE;
X  Bool found = FALSE;
X  int targs = 0;
X  
X  if(targnr == 0)
X    return;
X
X  if(!strcmp(targfield[1],".BPOOL"))
X    bpoolflg = TRUE;
X
X  if(!strcmp(targfield[1],".NOBPOOL"))
X    nobpoolflg = TRUE;
X
X  if(!strcmp(targfield[1],".IGNORE"))
X    ignoreflg = TRUE;
X  
X  if ((is_old_rule(targfield[1])) && (strcmp(targfield[1],".SUFFIXES") != 0))
X    {
X      oldrule = TRUE;
X      targs = targnr;
X      for(i = 1; i <= targs; i++)
X	{
X	  if (is_old_rule(targfield[i]))
X	    {
X	      if (targfield[i] != NIL)
X		convertrule(i);
X	    }
X	      ruleend();
X	}
X      oldrule = FALSE;
X      return;
X    }
X
X  for(i = 1; i <= targnr; i++)
X    {
X      p = index(targfield[i],'%');
X      if ((p != NIL) && ((*(p+1) == '\0') || (*(p+1) == '.')))
X	{
X	  std_rule = TRUE;
X	  break;
X	}
X    }
X
X  for(i = 1; i <= targnr; i++)
X    {
X      found = FALSE;
X      if(!std_rule)
X	{
X	  hasht = hashval(targfield[i]);
X#ifdef DEBUG_RULE
Xprintf("targfield[i] = %s; i = %d\n", targfield[i], i);
X#endif DEBUG_RULE
X	  if ( ruletab[hasht] == (struct rules *) NIL)
X	    {
X	      if((current = ruletab[hasht] = (struct rules *) malloc( sizeof(struct rules))) == (struct rules *)NIL)
X		errexit(10,"malloc");
X	    }
X	  else
X	  {
X	    current = ruletab[hasht];
X	    if ((!strcmp(ruletab[hasht]->name, targfield[i])) &&
X		(strcmp(ruletab[hasht]->name, ".SUFFIXES")) &&
X		(current->doublecolon == FALSE) &&
X		(doublecolon == FALSE) &&
X		(ruletab[hasht]->cmdlist != (struct cmds *) NIL) &&
X		(cmdfield[0] != NIL))
X	      errexit(1, targfield[i]);
X
X	    if((!strcmp(current->name,targfield[i])) &&
X	       ((cmdfield[0] == NIL) ||
X		(current->cmdlist == (struct cmds *) NIL)))
X	      {
X		found = TRUE;
X	      }
X
X	    while((current->nextrule != (struct rules *) NIL) && (!found))
X	      {
X		if((strcmp(current->name,targfield[i]) == 0) &&
X		   ((cmdfield[0] == NIL) ||
X		    (current->cmdlist == (struct cmds *) NIL)))
X		  {
X		    found = TRUE;
X		    break;
X		  }
X		else
X		  current = current->nextrule;
X		if ((strcmp(current->name, targfield[i]) == 0) &&
X		    (strcmp(ruletab[hasht]->name, ".SUFFIXES") != 0) &&
X		    (ruletab[hasht]->cmdlist != (struct cmds *) NIL) &&
X		    (current->doublecolon == FALSE) &&
X		    (doublecolon == FALSE) &&
X		    (cmdfield[0] != NIL))
X		  errexit(1, targfield[i]);
X		if ((strcmp(current->name, ".SUFFIXES")) == 0)
X		  {
X		    if (depnr == 0) /* delete suffix list */
X		      {
X			current->deplist[0] = NIL;
X		      }
X		    else
X		      {
X			while (current->deplist[jjj] != NIL)
X			  jjj++;
X		        for (kkk = 1; kkk <= depnr; kkk++)
X			  {
X			    if ((current->deplist[jjj + kkk - 1] =
X				 malloc((unsigned) (strlen(depfield[kkk]) + 1))) == NIL)
X			      errexit(10,"malloc");
X			    (void) strcpy(current->deplist[jjj + kkk - 1], depfield[kkk]);
X			  }
X		      }
X		  }
X	      }
X	    if (!found)
X	      {
X		if((current = current->nextrule = (struct rules *) malloc( sizeof(struct rules))) == (struct rules *)NIL)
X		  errexit(10,"malloc");
X	      }
X	  }
X	}
X      else
X	{
X	  if((current = stdruletab[lastrule] = (struct rules *) malloc( sizeof(struct rules))) == (struct rules *) NIL)
X	    errexit(10,"malloc");
X	  overload_stdrule();
X	  implicit_suffs[lastrule] = lastrule;
X	  lastrule++;
X	  implicit_suffs[lastrule] = -1;
X	  stdruletab[lastrule] = (struct rules *) NIL;
X	}
X      if (!found)
X	{
X	  if((current->name = malloc( (unsigned) strlen( targfield[i] ) + 1)) == NIL)
X	    errexit(10,"malloc");
X	  (void) strcpy(current->name, targfield[i]);
X	}
X      current->done = FALSE;
X      if (doublecolon)
X	current->doublecolon = TRUE;
X      else
X	current->doublecolon = FALSE;
X      if((i == 1) && (firsttarget == NIL) && (current->name[0] != '%') &&
X	 (current->name[0] != '.'))
X	 firsttarget = current->name;
X      if(!found)
X	{
X	  current->deplist[0] = NIL;
X	  current->cmdlist = (struct cmds *) NIL;
X	  current->nextrule = (struct rules *) NIL;
X	}
X      if ((depnr > 0) && (!found))
X	{
X	  if ((current->firstdep = malloc((unsigned) (strlen(depfield[1]) + sizeof(char)))) == NIL)
X	    errexit(10,"malloc");
X	  (void) strcpy(current->firstdep, depfield[1]);
X	}
X      
X      if (found)
X	{
X	  for(xx = 0; current->deplist[xx] != NIL; xx++)
X	    ;
X	}	  
X      minus = 0;
X      for(j = xx+1; j <= xx+depnr; j++)
X	{
X	  for(ss = 0; current->deplist[ss] != NIL; ss++)
X	    {
X	      if (!strcmp(current->deplist[ss],depfield[j-xx]))
X		{
X		  src_found = TRUE;
X		  minus = 1;
X		  break;
X		}
X	    }
X	  if(!src_found)
X	    {
X	      if ((current->deplist[j-1-minus] =
X		   malloc((unsigned) (strlen(depfield[j-xx]) + sizeof(char)))) == NIL)
X		errexit(10,"malloc");
X	      (void) strcpy(current->deplist[j-1-minus], depfield[j-xx]);
X	    }
X	}
X      current->deplist[j-1] = NIL;
X      src_found = FALSE;
X	
X      /* get standard dependent */
X
X      if(current->name[0] != '%')
X	{
X	  if((srcname = get_src_name(current->name)) != NIL)
X	    {
X	      for(ss = 0; ss <= j-2; ss++)
X		{
X		  if(!strcmp(srcname,current->deplist[ss]))
X		    {
X		      src_found = TRUE;
X		      break;
X		    }
X		}
X	      if (!src_found)
X		{
X		  if((current->deplist[j-1] =
X		      malloc((unsigned) (strlen(srcname) + 1))) == NIL)
X		    errexit(10,"malloc");
X		  (void) strcpy(current->deplist[j-1],srcname);
X		  current->deplist[j] = NIL;
X		}
X	      src_found = FALSE;
X	    }
X	}
X
X      if (heritnr > 0)
X	{
X	  for (j = 1; j <= heritnr; j++)
X	    {
X	      if((current->heritage[j-1] =
X		  malloc((unsigned) (strlen(heritfield[j]) + sizeof(char)))) == NIL)
X		errexit(10,"malloc");
X	      (void) strcpy(current->heritage[j-1], heritfield[j]);
X	    }
X	  current->heritage[j-1] = NIL;
X	}
X      else
X	current->heritage[0] = NIL;
X
X      if(std_rule)
X	{
X	  for (j = 1; j <= targnr; j++)
X	    {
X	      if((current->targetlist[j-1] =
X		  malloc((unsigned) (strlen(targfield[j]) + 1))) == NIL)
X		errexit(10,"malloc");
X	      (void) strcpy(current->targetlist[j-1],targfield[j]);
X	    }
X	  current->targetlist[j-1] = NIL;
X	}
X      if (cmdnr > 0)
X	{
X	  if ((curcmd = current->cmdlist = (struct cmds *) malloc( sizeof( struct cmds))) == (struct cmds *) NIL)
X	    errexit(10,"malloc");
X	  for (j = 1; j <= cmdnr; j++)
X	    {
X	      if((curcmd->command = malloc( (unsigned) strlen (cmdfield[j]) + 1)) == NIL)
X		errexit(10,"malloc");
X	      (void) strcpy(curcmd->command, cmdfield[j]);
X	      if (j != cmdnr)
X		{
X		  if((curcmd = curcmd->nextcmd = (struct cmds *) malloc( sizeof( struct cmds))) == (struct cmds *) NIL)
X		    errexit(10,"malloc");
X		}
X	      else
X		curcmd->nextcmd = (struct cmds *) NIL;
X	    }
X	}
X    }
X
Xdoublecolon = FALSE;
X
Xif (!oldrule)
X  {
X    targnr = 0;
X    targfield[1] = NIL;
X    depnr =  0;
X    depfield[1] = NIL;
X    cmdnr = 0;
X    cmdfield[1] = NIL;
X    heritnr = 0;
X    heritfield[1] = NIL;
X  }
X} /* end ruleend */
X
Xconvertrule(i)
X     int i;
X{
X  char *p;
X  p = rindex(targfield[i],'.');
X  *p = '\0';
X  p++;
X  if ((depfield[1] = malloc((unsigned) (strlen(targfield[i]) + 3))) == NIL)
X    errexit(10,"malloc");
X  (void) strcpy(depfield[1],"%");
X  (void) strcat(depfield[1],targfield[i]);
X  if((targfield[1] = malloc((unsigned) (strlen(p) + 3))) == NIL)
X    errexit(10,"malloc");
X  (void) strcpy(targfield[1],"%.");
X  (void) strcat(targfield[1],p);
X  targnr = 1;
X  depnr = 1;
X}
X
Xruledump(fd)
X     FILE *fd;
X{
Xstruct rules *cur;
Xstruct cmds *ccmd;
Xint i;
Xint k = 0;
Xfor(i = 0; i< RULETABSIZE; i++)
X  {
X    if (ruletab[i] != (struct rules *) NIL)
X      {
X	k = 0;
X	cur = ruletab[i];
X	while( cur != (struct rules *) NIL)
X	  {
X	    if(fd == stdout)
X	      fprintf(fd,"%s\n", cur->name);
X	    else
X	      fprintf(fd,"%s", cur->name);
X
X	    if (fd == stdout)
X	      fprintf(fd," depends on:");
X	    else
X	      fprintf(fd,":");
X
X	    while (cur->deplist[k] != NIL)
X	      {
X		if (fd != stdout)
X		  {
X		    if(!is_selrule_name(cur->deplist[k]))
X		      fprintf(fd," %s",cur->deplist[k]);
X		    k++;
X		  }
X		else
X		  {
X		    fprintf(fd," %s",cur->deplist[k]);
X		    k++;
X		  }
X	      }
X	    fprintf(fd,"\n");
X
X	    ccmd = cur->cmdlist;
X
X	    if(fd == stdout)
X	      fprintf(fd," commands:\n");
X	      
X	    while (ccmd != (struct cmds *) NIL)
X	      {
X		fprintf(fd,"%s\n", ccmd->command);
X		ccmd = ccmd->nextcmd;
X	      }
X	    fprintf(fd,"\n");
X	    cur = cur->nextrule;
X	  }
X      }
X  }
X
X
Xfor(i = 0; i < lastrule; i++)
X  {
X    k = 0;
X    cur = stdruletab[i];
X
X    if(fd == stdout)
X      fprintf(fd,"%s\n", cur->name);
X    else
X      fprintf(fd,"%s", cur->name);
X
X    if (fd == stdout)
X      fprintf(fd," depends on:");
X    else
X      fprintf(fd," :");
X
X    while (cur->deplist[k] != NIL)
X      {
X	fprintf(fd," %s",cur->deplist[k]);
X	k++;
X      }
X
X    if (fd == stdout)
X      fprintf(fd,"\n");
X
X    k = 0;
X    
X    if (fd == stdout)
X      fprintf(fd," inherits:");
X    else
X      fprintf(fd," :");
X
X    while (cur->heritage[k] != NIL)
X      {
X	fprintf(fd," %s", cur->heritage[k]);
X	k++;
X      }
X    fprintf(fd,"\n");
X
X    ccmd = cur->cmdlist;
X    
X    if (fd == stdout)
X      fprintf(fd," commands:\n");
X
X    while (ccmd != (struct cmds *) NIL)
X      {
X	fprintf(fd,"%s\n", ccmd->command);
X	ccmd = ccmd->nextcmd;
X	if (ccmd->command == NIL)
X	  break;
X      }
X    fprintf(fd,"\n");
X  }
X
X(void) fflush(fd);
X
X} /* end ruledump */
X
X
Xadjust_stdrules(suffs)
X     /*ARGSUSED*/
X     char *suffs;
X{
X
X;
X}
X      
XBool is_old_rule(string)
X     char *string;
X{
X  char *p1,*p2;
X  if (index(string,'/') != NIL)
X    return(FALSE);
X  if (((p1 = index(string,'.')) != NIL) &&
X      ((p2 = index(string+2,'.')) != NIL) &&
X      (p1 < p2))
X    return(TRUE);
X  else
X    return(FALSE);
X}
X      
X   
Xoverload_stdrule()
X{
X  int i;
X  
X  for(i = 0; i < lastrule; i++)
X    {
X      if((strcmp(stdruletab[implicit_suffs[i]]->name,targfield[1]) == 0) &&
X	 (strcmp(stdruletab[implicit_suffs[i]]->deplist[0], depfield[1]) == 0))
X	{
X	  implicit_suffs[i] = lastrule;
X	  return;
X	}
X    }
X}
X	
X	
X	
Xinit_ruletab()
X{
X  bzero((char *) ruletab, 257 * sizeof(struct rules *));
X}
X
END_OF_FILE
if test 17098 -ne `wc -c <'src/shape/rule.c'`; then
    echo shar: \"'src/shape/rule.c'\" unpacked with wrong size!
fi
# end of 'src/shape/rule.c'
fi
if test -f 'src/vc/doretrv.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/vc/doretrv.c'\"
else
echo shar: Extracting \"'src/vc/doretrv.c'\" \(17013 characters\)
sed "s/^X//" >'src/vc/doretrv.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#ifndef lint
Xstatic char *AFSid = "$Header: doretrv.c[3.12] Thu Feb 23 18:13:27 1989 axel@coma published $";
X#ifdef CFFLGS
Xstatic char *ConfFlg = CFFLGS;
X	/* should be defined from within Makefile */
X#endif
X#endif
X/*
X * Log for /u/shape/dist-tape/src/vc/doretrv.c[3.6]
X * 	Thu Feb 23 18:13:27 1989 axel@coma published $
X *  --- empty log message ---
X *  doretrv.c[3.8] Thu Feb 23 18:13:27 1989 axel@coma published $
X *  --- empty log message ---
X *  doretrv.c[3.9] Thu Feb 23 18:13:27 1989 axel@coma save $
X *  --- empty log message ---
X *  doretrv.c[3.10] Thu Feb 23 18:13:27 1989 axel@coma save $
X *  --- empty log message ---
X *  doretrv.c[3.11] Thu Feb 23 18:13:27 1989 axel@coma published $
X *  --- empty log message ---
X *  doretrv.c[3.12] Thu Feb 23 18:13:27 1989 axel@coma published $
X *  --- empty log message ---
X */
X
X#include <sys/file.h>
X#include <pwd.h>
X#include <stdio.h>
X#include <strings.h>
X#include "afs.h"
X#include "retrv.h"
X#include "project.h"
X#include "locks.h"
X
Xextern struct Transaction ThisTransaction;
Xextern unsigned int options;
X
X#ifndef ERROR
X#define ERROR -1
X#endif
X
XRetrieveAFile (fname, vdesc, proj, destpath)
X     char *fname, *destpath;
X     struct Vdesc *vdesc;
X     Project *proj; {
X /*
X  *  NOTE: use of variant attribute in af_getkey is not yet functional.
X  *        The parameter, however, is necessary to occupy the slot.
X  *        Implementation of variant selection may make it necessary
X  *        to add another parameter to this procedure.
X  */
X       char spath[MAXNAMLEN], origpath[MAXNAMLEN], name[MAXNAMLEN], *afname,
X       *aftype, *afvariant = NULL, messg[80], vsymname[80], *lbuf, *busyloc,
X       tname[MAXNAMLEN], *getattr(), *vnum(), *mktemp(), *malloc(),
X       destname[256], lockdir[256], lockfn[256], *intent, *getintent(),
X       *lockerid();
X       FILE *vfil, *bfile, *tfil;
X       Af_attrs reqattrs, fattrs;
X       Af_set hits;
X       Af_key busy, tkey, tmpkey, *busykey, *thiskey = &tkey;
X       Af_user *locker;
X       int nudattr = 0, nhits, nbytes;
X       unsigned int pstat = 0;
X       register int i;
X
X       if (!fname) return;
X       af_initattrs (&reqattrs);
X       busykey = &busy;
X       getsyspath (fname, proj, spath, origpath, name);
X       afname = af_afname (name);
X       aftype = af_aftype (name);
X       /* start fill out the warrant -- first 3 items may differ */
X       (void)strcpy (reqattrs.af_name, afname);
X       (void)strcpy (reqattrs.af_type, aftype);
X       (void)strcpy (reqattrs.af_syspath, spath);
X
X       /* ... the following settings will remain constant */
X       if (options & VSPECSET) {
X	 if (vdesc->v_vno) {
X	   reqattrs.af_gen = gen(vdesc->v_vno);
X	   reqattrs.af_rev = rev(vdesc->v_vno);
X	 }
X	 else {
X	   (void)sprintf (vsymname, "%s=%s", SYMNAME, vdesc->v_spec);
X	   reqattrs.af_udattrs[nudattr] = vsymname;
X	   nudattr++;
X	 }
X       }
X       if (options & ATTRDEF) {
X	 reqattrs.af_udattrs[nudattr] = 
X	   getattr (vdesc->v_attrf, proj, aftype, REWIND);
X	 if (reqattrs.af_udattrs[nudattr]) nudattr++;
X	 while (reqattrs.af_udattrs[nudattr] = getattr (vdesc->v_attrf, 
X							  proj, aftype, NEXT))
X	   nudattr++;
X       }
X       if ((options & GENSET) && (!(options & VSPECSET))) {
X	 reqattrs.af_gen = vdesc->v_genno;
X       }
X       if (options & AUNSET) {
X	 (void)strcpy (reqattrs.af_author.af_username, vdesc->v_aunam);
X	 (void)strcpy (reqattrs.af_author.af_userhost, vdesc->v_auhost);
X       }
X       if (options & STATSET) {
X	 reqattrs.af_state = vdesc->v_state;
X       }
X       /* descriptive attributes are filled in now. 
X	* lets try to find something 
X	*/
X       if (fail(af_find(&reqattrs, &hits))) {
X	 af_perror (fname);
X	 abort_this(TRUE);
X       }
X       Register ((char *)&hits, AFSET);
X       
X       /* Now lets see what kind of deed needs to be done */
X       nhits = af_nrofkeys (&hits);
X       if (nhits == 0) {
X	 (void)sprintf (messg, "No appropriate version of %s.", fname);
X	 logmsg (messg);
X	 (void)sprintf (messg, NORESTORE, fname);
X	 logmsg (messg);
X	 abort_this(FALSE);
X       }
X       if (nhits == 1) {
X	 if (af_setgkey (&hits, 0, &tkey) == ERROR) {
X	   af_perror ("af_setgkey");
X	   abort_this (TRUE);
X	 }
X       }
X       else if (nhits > 1) {
X	 if (fail(af_sortset(&hits, AF_ATTSTIME))) {
X	   af_perror ("af_sortset");
X	   abort_this (TRUE);
X	 }
X	 if (!(options & DATESET)) {
X	   if (af_setgkey (&hits, nhits-1, &tkey) == ERROR) {
X	     af_perror ("af_setgkey");
X	     abort_this (TRUE);
X	   }
X	 }
X	 else { /* some cutoff-date was specified */
X	   /* Don't consider busy version here */
X	   af_setgkey (&hits, 0, &tmpkey);
X	   if (af_rstate (&tmpkey) == AF_BUSY) {
X	     af_setrmkey (&hits, &tmpkey);
X	     nhits--;
X	   }
X	   for (i = nhits; i > 0; i--) {
X	     if (af_setgkey (&hits, i-1, &tkey) == ERROR) {
X	       af_perror ("af_setgkey");
X	       abort_this (TRUE);
X	     }
X	     if (fail(af_gattrs(thiskey, &fattrs))) {
X	       af_perror ("af_gattrs");
X	       abort_this (FALSE);
X	     }
X	     if (fattrs.af_stime >= vdesc->v_time) {
X	       af_setrmkey (&hits, thiskey);
X	       udafree (&fattrs);
X	     }
X	     else {
X	       udafree (&fattrs);
X	       break;
X	     }
X	   } /* end loop */
X	   if ((nhits = af_nrofkeys (&hits)) == 0) {
X	     (void)sprintf (messg, "No appropriate version of %s.", fname);
X	     logmsg (messg);
X	     abort_this (FALSE);
X	   }
X	 } /* end of else (some cut-off date) */
X	 if ((options & XACT) && (nhits > 1)) {
X	   (void)sprintf (messg, "No exact hit for %s. (got %d)", fname, nhits);
X	   logmsg (messg);
X	   (void)sprintf (messg, NORESTORE, fname);
X	   logmsg (messg);
X	   abort_this (FALSE);
X	 }
X       }
X       else {
X	 (void)sprintf (messg, "%d is an unreasonble number of hits.", nhits);
X	 logerr (messg);
X	 abort_this (TRUE);
X       }
X
X       if (fail(af_gattrs(thiskey, &fattrs))) {
X	 af_perror ("af_gattrs");
X	 abort_this (FALSE);
X       }
X       Register ((char *)&fattrs, AFATTRS);
X       /* at this point we do have a single af_key and 'thiskey' points 
X	* at it. now decide what 
X	* to do with it. fattrs contains its attributes.
X	*/
X       switch (options & (TYPEOUT | COPY | LOCKIT)) {
X       case TYPEOUT:
X	 if (!(vfil = af_open (thiskey, "r"))) {
X	   af_perror ("af_open");
X	   abort_this (TRUE);
X	 }
X	 mkvstring (messg, thiskey);
X	 logdiag (messg);
X	 lbuf = malloc ((unsigned)fattrs.af_size);
X	 nbytes=fread (lbuf, sizeof (*lbuf), (Size_t)fattrs.af_size, vfil);
X	 WriteXPand (lbuf, nbytes, stdout, thiskey);
X	 free (lbuf);
X	 af_close (vfil);
X	 UnRegister ((char *)&hits, AFSET);
X	 af_dropset (&hits);
X	 UnRegister ((char *)&fattrs, AFATTRS);
X	 udafree (&fattrs);
X	 return;
X	 break;
X       case COPY:
X	 /* This option creates a plain UNIX file from the specified
X	  * AFS file. The created copy is - in general - an object without
X	  * history. If, however, the copy happens to go into the 
X	  * history-directory (the one containing the archive) it will
X	  * 'automatically' be considered the busy-version.
X	  * If - in this case - a copy replaces a formerly locked busy-version,
X	  * the lock will be released.
X	  */
X	 busyloc = destpath ? destpath : ".";
X	 (void)sprintf (destname, "%s%s%s", destpath ? busyloc : "", 
X		  destpath ? "/" : "", name);
X	 if ((tfil = fopen (destname, "r")) == NULL) {
X	   /* take this as test for presence */
X	   if (access (busyloc, W_OK) == 0) { /* may we create ? */
X	     pstat |= DOIT; /* No scruples if no busyvers current */
X	   }
X	   else {
X	     (void)sprintf (messg, "write permission for directory %s denied.",
X		      busyloc);
X	     logerr (messg);
X	     pstat |= DENIED;
X	   }
X	 }
X	 else { /* file exists */
X	   (void)fclose (tfil);
X	   if (access (destname, W_OK) < 0) {
X	     if (access (busyloc, W_OK) == 0) {
X	       (void)sprintf (messg, "%s write-protected, re-create it ?",
X			destname);
X	       if (options & QUIETPLEASE) {
X		 pstat |= (options & FORCE) ? (RECREATE | DOIT) : DENIED;
X	       }
X	       else {
X		 if (ask_confirm (messg, "no")) {
X		   pstat |= DENIED;
X		 }
X		 else {
X		   pstat |= (RECREATE | DOIT);
X		 }
X	       }
X	     }
X	     else { 
X	       (void)sprintf (messg, "no write permission for %s", destname);
X	       logmsg (messg);
X	       pstat |= DENIED;
X	     }
X	   }
X	   else { /* write access on destfile */
X	     if (strcmp (busyloc, ".")) {
X	       (void)sprintf (messg, "%s exists and is writable. Overwrite it ?",
X		      destname);
X	       if (options & QUIETPLEASE) {
X		 pstat |= (options & FORCE) ? DOIT : 0;
X	       }
X	       else {
X		 if (!ask_confirm (messg, "no")) {
X		   pstat |= DOIT;
X		 }
X	       }
X	     }
X	     else { /* current dir! - test for lock */
X	       if (fail (af_getkey (spath, afname, aftype, AF_BUSYVERS,
X				    AF_BUSYVERS, afvariant, &busy)))
X		 { /* No busy-key -- no lock, this is impossible here */
X		   pstat |= DOIT;
X		 }
X	       else {
X		 if (lockeruid (vc_testlock_g(&busy)) == getuid ()) {
X		   (void)sprintf (messg, "Give up lock on %s and overwrite it ?",
X			    destname);
X		   if (options & QUIETPLEASE) {
X		     pstat |= (options & FORCE) ? DOIT : 0;
X		   }
X		   else {
X		     if (!ask_confirm (messg, "no")) {
X		       pstat |= DOIT;
X		       (void)vc_unlock_g(&busy);
X		     }
X		     else {
X		       pstat |= DENIED;
X		     }
X		   }
X		 }
X		 else {
X		   pstat |= DOIT;
X		 }
X	       }
X	     }
X	   }
X	 }
X	 if (pstat & DOIT) {
X	   if ((vfil=af_open(thiskey, "r")) == NULL) {
X	     af_perror ("af_open");
X	     abort_this (TRUE);
X	   } 
X	   (void)sprintf (tname, "%s%s%s", destpath ? destpath : "",
X		    destpath ? "/" : "", mktemp("retrvXXXXXX"));
X	   if ((bfile = fopen (tname, "w")) == NULL) {
X	     (void)sprintf (messg, "cannot create tmp-file (%s) for writing.",
X		      tname);
X	     logerr (messg);
X	     abort_this (TRUE);
X	   }
X	   Register (tname, TYPEF);
X	   (void)sprintf (messg, "%s%s%s[%s] -> %s", spath[0] ? spath : "",
X		    spath[0] ? "/" : "", name, vnum (thiskey), destname);
X	   logdiag (messg);
X	   lbuf = malloc ((unsigned)fattrs.af_size);
X	   nbytes=fread (lbuf, sizeof (*lbuf), (Size_t)fattrs.af_size, vfil);
X	   WriteXPand (lbuf, nbytes, bfile, thiskey);
X	   free (lbuf);
X	   (void)fclose (bfile); (void)fclose (vfil);
X	   (void)unlink (destname);
X	   if (link (tname, destname) < 0) {
X	     perror (destname);
X	     abort_this (TRUE);
X	   }
X	   (void)chmod (destname, 0444); 
X	   UnRegister (tname, TYPEF);
X	   (void)unlink (tname);
X	 }
X	 else {
X	   (void)sprintf (messg, "%s not retrieved", fname);
X	   logmsg (messg);
X	 }
X	 UnRegister ((char *)&hits, AFSET);
X	 af_dropset (&hits);
X	 UnRegister ((char *)&fattrs, AFATTRS);
X	 udafree (&fattrs);
X	 return;
X	 break;
X       case LOCKIT:
X	 /*
X	  *  Before a version is retrieved, set-busy, and locked, the
X	  *  following preconditions must be fulfilled:
X	  *  - the retrieve must go to the directory containing the 
X	  *    archive directory. -> current directory
X	  *  - the retrieved version must not be locked by anybody but
X	  *    the calling user.
X	  *  - the current directory must grant write access to the 
X	  *    calling user.
X	  *  - if some busy-version would be overwritten by the retrieve,
X	  *    the user is asked if she wants that
X	  */
X	 if ((destpath) && (destpath[0])) {
X	   (void)sprintf (messg, "can't checkout (with lock) to %s.", destpath);
X	   logmsg (messg);
X	   abort_this (FALSE);
X	 }
X	 (void)sprintf (lockfn, "%s%s%s", spath[0] ? spath : "", 
X		  spath[0] ? "/" : "", name);
X	 (void)sprintf (lockdir, "%s", spath[0] ? spath : ".");
X	 /*
X	  *  The following checks are based on the permission information
X	  *  stored in the archive files. It is unclear how
X	  *  to properly handle vanilla filesystem related inquiries.
X	  */
X	 if (fail (af_getkey (spath, afname, aftype, AF_LASTVERS,
X			      AF_LASTVERS, afvariant, &busy))) {
X	   /* well, this case seems to be impossible. If we get here, */
X	   /* at least _*some*_ version should be present */
X
X	   af_perror ("RetrieveAFile -- no version in sight.");
X	   abort_this (TRUE);
X	 }
X	 else { /* there is a version */
X	   if (((lockeruid (locker = af_testlock (&busy, AF_GLOBALLOCK))) 
X		== getuid ()) || !(locked (locker))) {
X#ifdef AFACCOK
X	     if (af_access (spath[0] ? spath : ".", afname, 
X			    aftype, W_OK) == 0) {
X#else
X	     if (access (fname, W_OK) == 0) {
X#endif
X	       (void)sprintf (messg, "Writable %s exists, overwrite it ?", lockfn);
X	       if (options & QUIETPLEASE) {
X		 pstat |= (options & FORCE) ? DOIT : DENIED;
X	       }
X	       else {
X		 pstat |= (ask_confirm (messg, "no")) ? DENIED : DOIT;
X	       }
X	     }
X	     else if (access (lockdir, W_OK) == 0) {
X	       if (access (lockfn, F_OK) == 0) {
X		 (void)sprintf (messg, 
X			  "Write access on %s denied. Overwrite it anyway ?",
X			  lockfn);
X		 if (options & QUIETPLEASE) {
X		   pstat |= (options & FORCE) ? DOIT : DENIED;
X		 }
X		 else {
X		   pstat |= (ask_confirm (messg, "no")) ? DENIED : DOIT;
X		 }
X	       }
X	       else pstat |= DOIT;
X	     }
X	     else { /* no write access on current dir */
X	       (void)sprintf (messg, "Can't create in %s.", lockdir);
X	       abort_this (TRUE);
X	     }
X	     if (!locked(locker)) {
X	       if (!vc_lock_g(&busy, getuid())) {
X		 af_perror ("af_lock");
X		 abort_this (TRUE);
X	       }
X	     }
X	   }
X	   else { /* busy version locked by someone else */
X	     pstat |= DENIED;
X	     (void)sprintf (messg, "%s already locked by %s.", lockfn, 
X		      lockerid(locker));
X	     logmsg (messg);
X	   }
X	 } 
X	 /* now all the checks are done. set retrieved version busy and 
X	  * create it in lockdir.
X	  */
X	 if ((pstat & DOIT) && (!(pstat & DENIED))) {
X	   if (! ((options & QUIETPLEASE) || (options & FORCE)))
X	     intent = getintent ("Describe intended changes ?", (char *)NULL);
X	   else intent = (char *)NULL;
X	   /* setbusy sets just the attributes. data must be moved manually */
X	   if ((vfil=af_open(thiskey, "r")) == NULL) {
X	     af_perror ("af_open");
X	     abort_this (TRUE);
X	   } 
X	   (void)sprintf (tname, "%s/%s", lockdir, mktemp("retrvXXXXXX"));
X	   if ((bfile = fopen (tname, "w")) == NULL) {
X	     (void)sprintf (messg, "cannot create tmp-file (%s) for writing.",
X		    tname);
X	     logerr (messg);
X	     af_close (vfil);
X	     abort_this (TRUE);
X	   }
X	   Register (tname, TYPEF);
X	   (void)sprintf (messg, "%s%s%s[%s] -> %s%s%s", spath[0] ? spath : "", 
X		    spath[0] ? "/" : "", name,
X		    vnum (thiskey), spath[0] ? spath : "", 
X		    spath[0] ? "/" : "",
X		    name);
X	   logdiag (messg);
X
X	   /* there's no attribute citation for locked busy versions .... */
X	   lbuf = malloc ((unsigned)fattrs.af_size);
X	   nbytes=fread (lbuf, sizeof (*lbuf), (Size_t)fattrs.af_size, vfil);
X	   if (fwrite (lbuf, sizeof (*lbuf), nbytes, bfile) != nbytes) {
X	     logerr ("fatal: couldn't write busy file.");
X	     abort_this (TRUE);
X	   }
X	   free (lbuf);
X	   (void)fclose (bfile);
X	   (void)chmod (tname, 0644);
X	   af_close (vfil);
X	   /* if no busyversion was present, busykey contains garbage */
X	   /* this might be responsible for trouble here */
X	   (void)unlink (fname);
X	   (void)link (tname, fname);
X	   ThisTransaction.tr_done = TRUE;
X	   UnRegister (tname, TYPEF);
X	   (void)unlink (tname);
X	   if (af_crkey (spath, afname, aftype, busykey) < 0) {
X	     af_perror ("af_crkey");
X	     abort_this (TRUE);
X	   }
X	   if (fail(af_setbusy(busykey, thiskey))) {
X	     af_perror ("af_setbusy");
X	     abort_this (TRUE); /* check out what happens in abort_this */
X	   }
X	   (void)vc_lock_g(busykey, getuid());
X	   if (intent) {
X	     char *intattr;
X	     intattr = malloc ((unsigned)(strlen (intent)+strlen (INTENT)+ 1));
X	     (void)sprintf (intattr, "%s%s", INTENT, intent);
X	     if (fail(af_sudattr (busykey, AF_REPLACE, intattr)))
X	       af_sudattr (busykey, AF_ADD, intattr);
X	     free (intattr);
X	   }
X	 }
X	 else { /* denied or not doit */
X	   (void)sprintf (messg, NORESTORE, ThisTransaction.tr_fname);
X	   logmsg (messg);
X	 }
X	 UnRegister ((char *)&fattrs, AFATTRS);
X	 udafree (&fattrs);
X	 UnRegister ((char *)&hits, AFSET);
X	 af_dropset (&hits);
X	 break;
X       default:
X	 logerr ("fatal: illegal action switch in doretrv.c");
X	 break;
X       }
X     }
END_OF_FILE
if test 17013 -ne `wc -c <'src/vc/doretrv.c'`; then
    echo shar: \"'src/vc/doretrv.c'\" unpacked with wrong size!
fi
# end of 'src/vc/doretrv.c'
fi
echo shar: End of archive 19 \(of 33\).
cp /dev/null ark19isdone
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.