[comp.sources.unix] v19i029: A software configuration management system, Part16/33

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

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



#! /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 16 (of 33)."
# Contents:  src/afs/afenviron.c src/misc/citeattr.c src/vc/vlmisc.c
# Wrapped by rsalz@papaya.bbn.com on Thu Jun  1 19:27:08 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'src/afs/afenviron.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/afs/afenviron.c'\"
else
echo shar: Extracting \"'src/afs/afenviron.c'\" \(15493 characters\)
sed "s/^X//" >'src/afs/afenviron.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 *	afenviron.c -- communication with the UNIX-Filesystem
X *
X *	Author: Andreas Lampen, TU-Berlin (andy@coma.UUCP)
X *					  (andy@db0tui62.BITNET)
X *
X *	$Header: afenviron.c[1.6] Wed Feb 22 16:27:29 1989 andy@coma published $
X *
X *	EXPORT:
X *      af_uniqpath -- build unified pathname
X *	af_setarchpath -- name directory where archives shall be stored
X *      af_isarchive -- test if a given file is an archive
X *	af_garname -- build name for archive file
X *	af_garown -- get owner of archive file
X *	af_gbpname -- build name for binary pool db-file
X *	af_gtmpname -- build name for tmp file
X *	af_gbusname -- build name of busy version
X *	af_afpath -- build af-syspath from UNIX-filename
X *	af_afname -- build af-filename from UNIX-filename
X *	af_aftype -- build af-filetype from UNIX-filename
X *	af_unixname -- build UNIX-filename from af-filename/type
X *      af_gmaxbpsize -- get max. number of files in binary pool
X *      af_bpfilename -- return filename for binary pool file
X *      af_rbphashname -- get unique filename for file in binary pool
X *	af_getuid -- returns uid of user if from local host
X *	af_getgid -- returns gid of user if from local host
X *	af_getuser -- returns name and host of caller
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <string.h>
X#ifdef SUNOS_4_0
X#include <strings.h>
X#endif
X#include <sys/file.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include "typeconv.h"
X#include "afsys.h"
X#include "afs.h"
X#include "afarchive.h"
X
Xchar  *malloc();
X
X/*================================================================
X *	af_uniqpath -- build unified pathname
X *
X *================================================================*/
X
XEXPORT char *af_uniqpath (path)
X     char *path;
X{
X  static char uniqpath[4*MAXNAMLEN], tmppath[4*MAXNAMLEN];
X  char        *p, *u, *getwd();
X
X  if ((path == (char *)0) || (path[0] == '\0') || ((path[0] == '.' && path[1] == '\0')))
X    return (getwd (uniqpath));
X
X  /* build absolute pathname if only a relative one is given */
X  if (path[0] != '/')
X    {
X      if (!strcmp (path, ".."))
X	{
X	  (void) getwd (uniqpath);
X	  if ((p = rindex (uniqpath, '/')) == uniqpath)
X	    uniqpath[1] = '\0';
X	  else
X	    *p = '\0';
X	  return (uniqpath);
X	}
X      (void) getwd (tmppath);
X      (void) strcat (tmppath, "/");
X      (void) strcat (tmppath, path);
X      p = tmppath;
X    }
X  else
X    p = path;
X
X  /* eliminate things like "/usr/./bin" and "/usr/../usr/bin" */
X  u = uniqpath;
X  *u = '/';
X  while (*p)
X    {
X      if ((p[0] == '/') && (p[1] == '.'))
X	{
X	  if ((p[2] == '/') || (p[2] == '\0'))
X	    {
X	      p = &p[2];
X	      continue;
X	    }
X	  else
X	    if ((p[2] == '.') && ((p[3] == '/') || (p[3] == '\0')))
X	      {
X		if (u != uniqpath)
X		  do { *u = '\0'; u--; } while (*u != '/');
X		p = &p[3];
X		continue;
X	      }
X	}
X      u++;
X      *u = p[1];
X      p++;
X    }
X  
X  /* cut slash if present at the end */
X  u--;
X  if ((u != uniqpath) && (*u == '/'))
X    *u = '\0';
X  else
X    u[1] = '\0';
X
X  return (uniqpath);
X}
X
Xstatic char archpath[4*MAXNAMLEN] = "\0";
X
X/*================================================================
X *	af_setarchpath
X *
X *================================================================*/
X
XEXPORT af_setarchpath (pathname)
X     char *pathname;
X{
X  if (pathname == (char *)0)
X    archpath[0] = '\0';
X  else
X    (void) strcpy (archpath, af_uniqpath (pathname));
X}
X
X
X/*====================================================================
X * af_isarchive -- test if a given file is an archive
X *
X *====================================================================*/
X
XEXPORT af_isarchive (name)
X     char *name;
X{
X  char ext;
X
X  if (!name || strncmp (name, AF_AFSFILEID, AF_IDSTRLEN))
X    return (FALSE);
X
X  ext = name[strlen (name) - sizeof (char)];
X  if ((ext != AF_ARCHEXT) && (ext != AF_DATAEXT))
X    return (FALSE);
X
X  return (TRUE);
X}
X
X
X/*================================================================
X *	af_garname
X *
X *================================================================*/
X
XEXPORT char *af_garname (pathname, name, type)
X     char *pathname;
X     char *name, *type;
X{
X  char arname[MAXNAMLEN*4];
X
X  /* see if there is an explicit pathname where archives shall be stored */
X  if (archpath[0])
X    (void) strcpy (arname, archpath);
X  else
X    (void) sprintf (arname, "%s/%s\0", NOTNIL(pathname), AF_SUBDIR);
X
X  if ((type != (char *)0) && (type[0] != '\0'))
X    (void) sprintf (&arname[strlen (arname)], "/%s%s.%s%c\0",
X	     AF_AFSFILEID, NOTNIL(name), NOTNIL(type), AF_ARCHEXT);
X  else
X    (void) sprintf (&arname[strlen (arname)], "/%s%s%c\0",
X	     AF_AFSFILEID, NOTNIL(name), AF_ARCHEXT);
X
X  return (af_entersym (arname));
X} /* af_garname */ 
X
X
X/*================================================================
X *	af_garown
X *
X *================================================================*/
X
XEXPORT Af_user *af_garown (archname, writeok)
X     char    *archname;
X     bool    *writeok; /* out */
X{
X  char ardirname[MAXNAMLEN*4], *namptr;
X  struct stat ibuf;
X
X  /* build name of directory, where the archive is located */
X  (void) strcpy (ardirname, archname);
X
X  /* cut name */
X  namptr = rindex (ardirname, '/');
X  *namptr = '\0';
X
X  *writeok = FALSE;
X  if (stat (ardirname, &ibuf) == ERROR)
X    return ((Af_user *)0);
X  else
X    if (!af_sysaccess (ardirname, W_OK))
X      *writeok = TRUE;
X
X  return (af_getuser (ibuf.st_uid));
X} /* af_garown */ 
X
X
X/*================================================================
X *	af_gbpname
X *
X *================================================================*/
X
XEXPORT char *af_gbpname (pathname)
X     char *pathname;
X{
X  char bpname[MAXNAMLEN*4];
X
X  /* see if there is an explicit pathname where archives shall be stored */
X  if (archpath[0])
X    (void) strcpy (bpname, archpath);
X  else
X    (void) sprintf (bpname, "%s/%s/\0", pathname, AF_SUBDIR);
X
X  if (af_sysaccess (bpname, R_OK))
X    return ((char *)0);
X
X  (void) strcat (bpname, AF_BPOOLNAME);
X
X  return (af_entersym (bpname));
X} /* af_garname */ 
X
X
X/*================================================================
X *	af_gtmpname
X *
X *================================================================*/
X
Xstatic int count=0;
X
XEXPORT char *af_gtmpname (pathname, filename)
X     /*ARGSUSED*/
X     char *pathname; /* unused up to now */
X     char *filename;
X{
X  char tmpname[MAXNAMLEN*4];
X  
X  (void) sprintf (tmpname, "%s/%s%d%d\0", AF_TMPDIR, filename, getpid(), count++);
X  return (af_entersym (tmpname));
X} /* af_gtmpname */
X
X
X/*================================================================
X *	af_gbusname
X *
X *================================================================*/
X
XEXPORT char *af_gbusname (pathname, name, type)
X     char *pathname;
X     char *name, *type;
X{
X  char busyname[MAXNAMLEN*4];
X   
X  (void) sprintf (busyname, "%s/%s", pathname, name);
X  if ((type != (char *)0) && (type[0] != '\0'))
X      {
X	(void) strcat (busyname, ".");
X	(void) strcat (busyname, type);
X      }
X  return (af_entersym (busyname));
X} /* af_gbusname */ 
X
X
X
X/*================================================================
X *	af_afpath
X *
X *================================================================*/
X
XEXPORT char *af_afpath (unixname)
X     char *unixname;
X{
X  char *nameptr;
X  static char afpath[MAXNAMLEN];
X
X  if (unixname)
X    (void) strcpy (afpath, unixname);
X  else
X    afpath[0] = '\0';
X
X  /* cut name */
X  if ((nameptr = rindex (afpath, '/')) != (char *)0)
X    nameptr[0] = '\0';
X  else
X    {
X      afpath[0] = '\0';
X      return (afpath);
X    }
X
X  /* cut AFS subdirectory name if present */
X  if (((nameptr = rindex (afpath, '/')) != (char *)0) && 
X       !strcmp (AF_SUBDIR, nameptr+1))
X    nameptr[0] = '\0';
X  else
X    if (!strcmp (AF_SUBDIR, afpath))
X      afpath[0] = '\0';
X
X  return (afpath);
X}
X
X/*================================================================
X *	af_afname
X *
X *================================================================*/
X
XEXPORT char *af_afname (unixname)
X     char *unixname;
X{
X  char *typeptr, *nameptr;
X  static char afname[MAXNAMLEN];
X
X  if (!unixname)
X    {
X      afname[0] = '\0';
X      return (afname);
X    }
X
X  /* set nameptr to beginning of name */
X  if ((nameptr = rindex (unixname, '/')) == (char *)0)
X    nameptr = unixname;
X  else
X    nameptr++;
X
X  if (af_isarchive (nameptr))
X    {
X      (void) strcpy (afname, nameptr + strlen (AF_AFSFILEID));
X      afname[strlen (afname) - sizeof (char)] = '\0';
X    }
X  else
X    (void) strcpy (afname, nameptr);
X
X  /* special handling for "." and ".." */
X  if (!strcmp (afname, ".") || !strcmp (afname, ".."))
X    return (afname);
X
X  /* if a UNIX type-extension is given -- cut it, except the dot is */
X  /*                                      at position 0 (e.g. .cshrc) */
X  if ((typeptr = rindex (afname, '.')) != (char *)0)
X    if (typeptr != afname)
X      typeptr[0] = '\0';
X
X  return (afname);
X}
X
X/*================================================================
X *	af_aftype
X *
X *================================================================*/
X
XEXPORT char *af_aftype (unixname)
X     char *unixname;
X{
X  char *typeptr, *nameptr;
X  static char aftype[MAXTYPLEN];
X  bool isarch = FALSE;
X
X  if (!unixname)
X    {
X      aftype[0] = '\0';
X      return (aftype);
X    }
X
X  /* set nameptr to beginning of name */
X  if ((nameptr = rindex (unixname, '/')) == (char *)0)
X    nameptr = unixname;
X  else
X    nameptr++;
X
X  if (af_isarchive (nameptr))
X    {
X      nameptr += strlen (AF_AFSFILEID);
X      isarch = TRUE;
X    }
X
X  /* if there is no UNIX type-extension */
X  if ((typeptr = rindex (nameptr, '.')) == (char *)0)
X    aftype[0] = '\0';
X  else
X    {
X      /* if the found dot indicates a "hidden file" (eg. .cshrc) */
X      if (typeptr == nameptr)
X	aftype[0] = '\0';
X      else
X	{
X	  (void) strcpy (aftype, typeptr + sizeof(char));
X	  /* if the named file is an archive, cut the name-extension */
X	  if (isarch)
X	    aftype [strlen (aftype) - sizeof (char)] = '\0';
X	}
X    }
X  return (aftype);
X}
X
X
X/*================================================================
X *	af_unixname
X *
X *================================================================*/
X
XEXPORT char *af_unixname (path, name, type)
X     char *path, *name, *type;
X{
X  static char unixname[4*MAXNAMLEN];
X
X  if ((path == (char *)0) || (path[0] == '\0'))
X    (void) strcpy (unixname, NOTNIL(name));
X  else
X    (void) sprintf (unixname, "%s/%s\0", path, name);
X
X  if ((type != (char *)0) && (type[0] != '\0'))
X    {
X      (void) strcat (unixname, ".");
X      (void) strcat (unixname, type);
X    }
X  return (unixname);
X}
X
X
X/*================================================================
X *      af_gmaxbpsize -- get max. number of files in binary pool
X *
X *================================================================*/
X
XEXPORT int af_gmaxbpsize (name)
X     /*ARGSUSED*/
X     char *name; /* unused up to now */
X{
X  char *envval, *getenv();
X
X  if (envval = getenv (AF_ENVBPSIZE))
X    return (atoi (envval));
X  else
X    return AF_MAXBPSIZE;
X}
X
X
X/*================================================================
X *	af_bpfilename
X *
X *================================================================*/
X
XEXPORT char *af_bpfilename (pathname, name)
X     char *pathname, *name;
X{
X  static char bpname[MAXNAMLEN];
X
X  (void) sprintf (bpname, "%s/%s/%s\0", pathname, AF_SUBDIR, name);
X  return (bpname);
X}
X
X/*================================================================
X * af_rbphashname -- get unique filename for file in binary pool
X *
X *================================================================*/
X
XEXPORT char *af_rbphashname (name, type, gen, rev, variant, list, count)
X     char *name, *type, *variant;
X     int  gen, rev;
X     /*ARGSUSED*/
X     Af_revlist *list; /* unused up to now */
X     int count;
X{
X  char hashname[MAXNAMLEN];
X
X  (void) sprintf (hashname, "%s%s.%s[%d.%d]%s%d\0", AF_BPFILEID, 
X	   name, type, gen, rev, variant, count);
X
X  return (af_entersym (hashname));
X}
X
X
X/*========================================================================
X *	af_getuid - returns uid of user if from local host
X *                  AF_ERROR if user is unknown
X *                  AF_REMOTE if user is not local
X *
X *========================================================================*/
X
XEXPORT Uid_t af_getuid (name, host)
X     char *name, *host;
X{
X  struct passwd *pwent;
X
X  if (name == (char *)0) /* in this case, name and host are null pointers */
X    return ((Uid_t) ERROR);
X
X  if (strcmp (af_gethostname(), host))
X    return ((Uid_t) AF_REMOTE);
X
X  if ((pwent = getpwnam (name)) == (struct passwd *)0)
X    FAIL ("getuid", "cannot get user ID", AF_EINTERNAL, (Uid_t) ERROR);
X
X  return (pwent->pw_uid);
X}
X
X
X/*========================================================================
X *	af_getgid - returns gid of user if from local host
X *                  AF_ERROR if user is unknown
X *                  AF_REMOTE if user is not local
X *
X *========================================================================*/
X
XEXPORT Gid_t af_getgid (name, host)
X     char *name, *host;
X{
X  struct passwd *pwent;
X
X  if (name == (char *)0) /* in this case, name and host are null pointers */
X    return ((Gid_t) ERROR);
X
X  if (strcmp (af_gethostname(), host))
X    return ((Gid_t) AF_REMOTE);
X
X  if ((pwent = getpwnam (name)) == (struct passwd *)0)
X    FAIL ("getgid", "cannot get group ID", AF_EINTERNAL, (Gid_t) ERROR);
X
X  return (pwent->pw_gid);
X}
X
X
X/*========================================================================
X *	af_getuser - returns name and host of caller
X *
X *========================================================================*/
X
Xstatic Uid_t   calleruid;
Xstatic Af_user caller;
Xstatic bool    initcaller = FALSE;
X
XEXPORT Af_user *af_getuser (uid)
X     Uid_t uid;
X{
X  static Af_user result;
X  struct passwd *pwent;
X 
X  if (!initcaller) /* if caller struct is not yet initialized */
X    {
X      calleruid = getuid();
X      (void) strcpy (caller.af_userhost, af_gethostname ()); 
X      if ((pwent = getpwuid ((int) calleruid)) == (struct passwd *)0)
X	SFAIL ("getuser", "", AF_EINVUSER, (Af_user *)0);
X      (void) strcpy (caller.af_username, pwent->pw_name);
X      initcaller = TRUE;
X    }
X  if (uid == calleruid)
X    return (&caller);
X
X  (void) strcpy (result.af_userhost, af_gethostname ()); 
X  if ((pwent = getpwuid ((int) uid)) == (struct passwd *)0)
X    SFAIL ("getuser", "", AF_EINVUSER, (Af_user *)0);
X  (void) strcpy (result.af_username, pwent->pw_name);
X
X  return (&result);
X}
END_OF_FILE
if test 15493 -ne `wc -c <'src/afs/afenviron.c'`; then
    echo shar: \"'src/afs/afenviron.c'\" unpacked with wrong size!
fi
# end of 'src/afs/afenviron.c'
fi
if test -f 'src/misc/citeattr.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/misc/citeattr.c'\"
else
echo shar: Extracting \"'src/misc/citeattr.c'\" \(14280 characters\)
sed "s/^X//" >'src/misc/citeattr.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 */
Xstatic char *AFSid = "$Header: citeattr.c[1.6] Thu Feb 23 21:24:18 1989 axel@coma published $";
X
X/*
X * Log for /u/shape/dist-tape/src/misc/citeattr.c[1.1]
X * 	Thu Feb 23 21:24:18 1989 axel@coma save $
X *  --- empty log message ---
X *  citeattr.c[1.2] Thu Feb 23 21:24:18 1989 axel@coma save $
X *  --- empty log message ---
X *  citeattr.c[1.3] Thu Feb 23 21:24:18 1989 axel@coma save $
X *  --- empty log message ---
X *  citeattr.c[1.4] Thu Feb 23 21:24:18 1989 axel@coma published $
X *  Threw out silly #ifdef BSD43 s.
X *  I think there are also other changes concerning attribute citations.
X *  
X *  citeattr.c[1.5] Thu Feb 23 21:24:18 1989 axel@coma published $
X *  --- empty log message ---
X *  citeattr.c[1.6] Thu Feb 23 21:24:18 1989 axel@coma published $
X *  --- empty log message ---
X */
X
X#include <pwd.h>
X#include <grp.h>
X#include <stdio.h>
X#include <strings.h>
X#include "afs.h"
X#include "afsapp.h"
X#include "anames.h"
X
Xchar *st_table[] = {
X  "busy", "save", "proposed", 
X  "published", "accessed", "frozen", 
X  (char *)0 
X  };
X
XWriteXPand (buf, bufcnt, dest, curkey) 
X     char *buf; int bufcnt; FILE *dest; Af_key *curkey; {
X/*
X *  WriteXPand scans the char buffer 'buf' to the extent of bufcnt
X *  for strings of the form '$__attribute_name'. If such a string
X *  is found, the buffer contents up to the character preceding the
X *  first '$' will be sent to the destination output 'dest'.
X *  If an attribute with name 'atttribute_name' is set for the current
X *  attribute file, the citation-string will be substituted by the value
X *  of that attribute. Output of 'buf' contents resumes with the first 
X *  character after the blank delimiting the 'attribute_name'.
X *  There are two built-in pseudo-attributes, 'Header' and 'Log' which
X *  are substituted by a version header in RCS style or a log-history
X *  respectively. Lines of the log-history are preceded by a 'comment
X *  leader' symbol, defined as user-defined attribute CLEAD.
X *  Header and Log are ended by newline characters.
X */
X       short stat=0, incite=0, gotattrs=0;
X       char attrcitebuf[128];
X       Af_attrs allattrs;
X       register int i, j, k;
X       char *bufp = buf, *attrname = attrcitebuf+3,
X       *spt, *ept;
X
X       i = 0;
X
X       spt = ept = buf;
X
X       while (i < bufcnt) {
X
X	 switch (buf[i]) {
X	 /* scan attribute citation marker */
X	 case '$':
X	   if (stat) ept = &(buf[i]);
X	   stat = 1;
X	   attrcitebuf[0] = '$';
X	   break;
X	 case '_':
X	   switch (stat) {
X	   case 0:
X	     ept++;
X	     break;
X	   case 1: 
X	   case 2:
X	     attrcitebuf[stat++] = '_';
X	     break;
X	   }
X	   break;
X	 default:
X	   if (stat) 
X	     ept = &(buf[i+1]);
X	   else 
X	     ept++;
X	   stat = 0;
X	   break;
X	 }
X
X	 if (stat == 3) { /* lets see if there's an attribute citation */
X	   /* assertion: i is index of 2nd '_' */
X	   if ((i < bufcnt-1) && (buf[i+1] != ' ')) { 
X	     stat = 0; 
X	     /* ... yes, there seems to be one */
X	     i++; incite = 0;
X	     if (af_gattrs (curkey, &allattrs) < 0) {
X	       af_perror ("af_gattrs");
X	       return;
X	     }
X	     gotattrs = 1;
X	     while ((!index (" \n\t$", buf[i])) && (i < bufcnt))
X	       attrname[incite++] = buf[i++];
X	     if (i < bufcnt) {
X	       /* i points to first char after attribute name */
X	       if (buf[i] == '$') { /* consider '$' part of attr-name */
X		 attrname[incite++] = '$'; i++;
X	       }
X	       attrname[incite] = '\0';
X	       /* write out everything up to beginning of cite_mark */
X	       fwrite (spt, sizeof (*buf), ept - spt, dest);
X	       spt = ept = &(buf[i]);
X	       if (!substitute (attrname, curkey, &allattrs, dest))
X		 fputs (attrcitebuf, dest);
X	       incite = 0;
X	     }
X	     else {
X	       attrname[incite] = '\0';
X	       fwrite (spt, sizeof (*buf), ept - spt, dest);
X	       spt = ept = &(buf[i]);
X	       if (!substitute (attrname, curkey, &allattrs, dest))
X		 fputs (attrcitebuf, dest);
X	     }
X	   }
X	   else { /* blank after citemark or buffer exceeded */
X	     fputs ("$__", dest);
X	   }
X	   i--;
X	 }
X	 i++;
X       }
X       /* Ok, we've had it -- send remaining chars to dest */
X       fwrite (spt, sizeof (*buf), ept - spt, dest);
X       if (gotattrs) {
X	 i = 0;
X	 while (allattrs.af_udattrs[i]) free (allattrs.af_udattrs[i++]);
X       }
X     }
X
X
Xstatic substitute (attrname, afkey, afattrs, dest) 
X     char *attrname; Af_key *afkey; Af_attrs *afattrs; FILE *dest; {
X       /* 
X	* This procedure tries to substitute the occurrence of the 
X	* given attribute name by the corresponding value stored with the 
X	* attribute file version denoted by afkey. The substituted 
X	* value is printed on dest. If 'attrname' actually is the name
X	* of an attribute and the last character in the name is '$'
X	* it will be deleted. In case that attrname is not a known
X	* attributename, nothing happens and a value of 0, indicating
X	* that no substitution took place, will be returned. Nonzero
X	* return means successful substitution.
X	*/
X       char *ap, *p, clead[32], *note, *IsAStdAttr();
X       register char *lp, *ep, *l;
X       Af_attrs retbuf;
X       Af_set kset;
X       Af_key thiskey;
X       int cgen, crev, tgen, setsz, title_printed = FALSE;
X       register int k;
X
X       if (l = index (attrname, '$')) *l = '\0';
X       if (ap = IsAStdAttr (attrname, afattrs)) {
X	 fputs (ap, dest);
X	 return TRUE;
X       }
X       if (strcmp (attrname, HEADER)) {
X	 if (strcmp (attrname, LOG)) {
X	   ap = af_rudattr (afkey, attrname);
X	   if (ap > 0) {
X	     fputs (ap, dest);
X	     free (ap);
X	     return TRUE;
X	   }
X	   if (l) *l = '$'; /* restore '$' if 'attrname' unknown */
X	   return FALSE;
X	 }
X	 else { /* fill in the logs */
X	   /* we've got to find all preceding versions */
X	   
X	   af_initattrs (&retbuf);    
X	   strcpy (retbuf.af_syspath, p=af_rsyspath (afkey));
X	   free (p);
X	   strcpy (retbuf.af_name, p=af_rname (afkey));
X	   free (p);
X	   strcpy (retbuf.af_type, p=af_rtype (afkey));
X	   free (p);
X	   af_find (&retbuf, &kset);
X	   af_sortset (&kset, AF_ATTVERSION);
X	   cgen = af_rgen (afkey);
X	   crev = af_rrev (afkey);
X	   setsz = af_nrofkeys (&kset);
X	   
X	   /* determine comment leader sym to prepend it to loglines */
X	   p = af_rudattr (afkey, CLEAD);
X	   if (p) {
X	     strcpy (clead, p);
X	   }
X	   else clead[0] = '\0';
X	   free (p);
X	   
X	   /* write log for each version up to current on dest file */
X	   for (k = 0 ; k < setsz; k++) {
X	     af_setgkey (&kset, k, &thiskey);
X	     if (af_rstate (&thiskey) == AF_BUSY)
X	       continue; /* don't consider busy version */
X	     if ((tgen = af_rgen (&thiskey)) > cgen)
X	       break;
X	     if ((tgen == cgen) && (af_rrev(&thiskey) > crev))
X	       break;
X	     if (!title_printed) {
X	       fprintf (dest, "Log for ");
X	       putlongheader (&thiskey, dest, clead);
X	       title_printed = TRUE;
X	     }
X	     else {    /* each log preceded by version header */
X	       fprintf (dest, "%s%s", (clead && clead[0]) ? clead : "",
X			(clead && clead[0]) ? " " : "");
X	       putshortheader (&thiskey, dest, TRUE);
X
X	     }
X	     note = af_rnote (&thiskey);
X	     lp = note; 
X	     /* break log text into separate strings */
X	     /* assertion: lp == 0 if no log or log is printed */
X	     while (lp) {
X	       ep = lp;
X	       while ((*ep != '\n') && (*ep != '\0'))
X		 ep++;
X	       if (*ep == '\n') {
X		 *ep++ = '\0'; /* make it end of an ordinary string */
X		 fprintf (dest, "%s %s\n", clead, lp);
X		 /* ...and let it point to next string segment */
X	       }
X	       else {
X		 ep = NULL; /* we're ready */
X		 if (k < setsz-1) /* handle 'last-newline' problem */
X		   fprintf (dest, "%s %s\n", clead, lp);
X		 else
X		   fprintf (dest, "%s %s", clead, lp);
X	       }
X	       lp = ep;
X	     }
X	     free (note);
X	     /* aw rite --- lets go for the next log entry */
X	   }
X	   af_dropset (&kset);
X	 }
X       }
X       else { /* print standard version header -- do it RCS-style */
X	 fprintf (dest, "%cHeader: ", '$');
X	 putshortheader (afkey, dest, FALSE);
X       }
X       return TRUE;
X     }
X
Xstatic char *vnum (key) Af_key *key; {
X  int _gen, _rev;
X  static char vstr[20];
X
X  _gen = af_rgen (key);
X  _rev = af_rrev (key);
X  
X  if (af_rstate (key) == AF_BUSY)
X    strcpy (vstr, "busy");
X  else
X    sprintf (vstr, "%d.%d", _gen, _rev);
X  return vstr;
X}
X
X
Xstatic putlongheader (afkey, dest, clead) 
X     Af_key *afkey; FILE *dest; char *clead; {
X  char *spath, *name, *type, *systime(), *UidString(), *csym;
X  extern char *st_table[];
X  register int i;
X  Af_attrs allattrs;
X
X  spath = af_rsyspath (afkey);
X  name = af_rname  (afkey);
X  type = af_rtype (afkey);
X  af_gattrs (afkey, &allattrs);
X  csym = (clead && clead[0]) ? clead : "";
X  for (i = 0; allattrs.af_udattrs[i]; i++) free (allattrs.af_udattrs[i]);
X
X  fprintf (dest, "%s/%s%s%s[%s]\n%s\t%s %s %s $\n", spath, name, 
X	   type[0] ? "." : "", type, vnum(afkey), csym,
X	   systime(), UidString (&(allattrs.af_author)),
X	   st_table[af_rstate(afkey)]);
X  free (spath); free (name); free (type);
X}
X
Xstatic putshortheader (afkey, dest, nl) 
X     Af_key *afkey; FILE *dest; int nl; {
X  char *spath, *name, *type, *systime(), *UidString();
X  extern char *st_table[];
X  register int i;
X  Af_attrs allattrs;
X
X  spath = af_rsyspath (afkey);
X  name = af_rname  (afkey);
X  type = af_rtype (afkey);
X  af_gattrs (afkey, &allattrs);
X  for (i = 0; allattrs.af_udattrs[i]; i++) free (allattrs.af_udattrs[i]);
X
X  fprintf (dest, "%s%s%s[%s] %s %s %s $%s", name, 
X	   type[0] ? "." : "",type, vnum(afkey),
X	   systime(), UidString (&(allattrs.af_author)),
X	   st_table[af_rstate(afkey)], nl ? "\n" : "");
X  free (spath); free (name); free (type);
X}
X
Xstatic struct {
X  char *name;
X  short code;
X} an_tab[] = {
X  { "atime", ATIME },  /* 0 */
X  { "auuid", AUUID },
X  { "ctime", CTIME },
X  { "generation", GEN },
X  { "host", HOST },
X  { "lock",  LOCK },
X  { "ltime", LTIME },
X  { "mode", MODE },
X  { "mtime", MTIME },
X  { "name",  NAME },
X  { "ownuid", OWNUID },
X  { "revision", REV },
X  { "size", SIZE },
X  { "stime", STIME },
X  { "syspath", SYSPATH },
X  { "type", TYPE },
X  { "variant", VAR },
X  { "version", VERSION },
X  { "state", STATE }       /* 18 */
X};
X
Xstatic char *IsAStdAttr (attrname, afattrs) 
X     char *attrname; Af_attrs *afattrs; {
X  extern char *st_table[];
X  char messg[80], *UidString();
X  static char rets[32];
X  register int i;
X  int anc = 0;
X
X  for (i = 0; i < AN_TABSIZ; i++) {
X    if (!(strcmp (attrname, an_tab[i].name))) {
X      anc = an_tab[i].code;
X      break;
X    }
X  }
X  if (anc) {
X    switch (anc) {
X    case HOST:
X      return afattrs->af_host;
X      break;
X    case SYSPATH:
X      return afattrs->af_syspath;
X      break;
X    case NAME:
X      return afattrs->af_name;
X      break;
X    case TYPE:
X      return afattrs->af_type;
X      break;
X    case GEN:
X      if (afattrs->af_state == AF_BUSY) return "nogen";
X      else {
X	sprintf (rets, "%d", afattrs->af_gen);
X	return rets;
X      }
X      break;
X    case REV:
X      if (afattrs->af_state == AF_BUSY) return "nogen";
X      else {
X	sprintf (rets, "%d", afattrs->af_rev);
X	return rets;
X      }
X      break;
X    case VERSION:
X      if (afattrs->af_state == AF_BUSY) return "busy";
X      else {
X	sprintf (rets, "%d.%d", afattrs->af_gen, afattrs->af_rev);
X	return rets;
X      }
X      break;
X    case VAR:
X      return (afattrs->af_variant);
X      break;
X    case STATE:
X      return st_table[afattrs->af_state];
X      break;
X    case OWNUID:
X      return UidString (&(afattrs->af_owner));
X      break;
X    case AUUID:
X      return UidString (&(afattrs->af_author));
X      break;
X    case SIZE:
X      sprintf (rets, "%d", afattrs->af_size);
X      return rets;
X      break;
X    case MODE:
X      sprintf (rets, "%o", afattrs->af_mode);
X      return rets;
X      break;
X    case LOCK:
X      if (strcmp (afattrs->af_locker.af_username, "")) {
X	sprintf (rets, "%s@%s", afattrs->af_locker.af_username, 
X		 afattrs->af_locker.af_userhost);
X	return rets;
X      }
X      return "nobody";
X      break;
X    case MTIME:
X      strcpy (rets, asctime(localtime(&afattrs->af_mtime)));
X      rets[strlen(rets) - 1] = '\0';
X      return rets;
X      break;
X    case ATIME:
X      strcpy (rets, asctime(localtime(&afattrs->af_atime)));
X      rets[strlen(rets) - 1] = '\0';
X      return rets;
X      break;
X    case CTIME:
X      strcpy (rets, asctime(localtime(&afattrs->af_ctime)));
X      rets[strlen(rets) - 1] = '\0';
X      return rets;
X      break;
X    case STIME:
X      if (afattrs->af_state == AF_BUSY) return "no_date";
X      else {
X	strcpy (rets, asctime(localtime(&afattrs->af_stime)));
X	rets[strlen(rets) - 1] = '\0';
X	return rets;
X      }
X      break;
X      case LTIME:
X      strcpy (rets, asctime(localtime(&afattrs->af_ltime)));
X      rets[strlen(rets) - 1] = '\0';
X      return rets;
X      break;
X    default: /* shouldn't happen ! */
X      sprintf (messg, "illegal standard attribute code %d.", anc);
X      logerr (anc);
X    }
X  }
X  else return NULL; /* no standard attribute */
X}
X
Xchar *UidString (user) Af_user *user; {
X  static char rst[256];
X
X  rst[0] = '\0';
X  if (user) {
X    sprintf (rst, "%s@%s", user->af_username, user->af_userhost);
X  }
X  return rst;
X}
X
Xstatic char *systime () {
X  char *asctime();  
X  register char *ts;
X  struct timeval tm;
X  struct timezone tz;
X
X  gettimeofday (&tm, &tz);
X  ts = asctime (localtime (&tm));
X  ts[strlen(ts)-1] = '\0';
X  return ts;
X}
END_OF_FILE
if test 14280 -ne `wc -c <'src/misc/citeattr.c'`; then
    echo shar: \"'src/misc/citeattr.c'\" unpacked with wrong size!
fi
# end of 'src/misc/citeattr.c'
fi
if test -f 'src/vc/vlmisc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'src/vc/vlmisc.c'\"
else
echo shar: Extracting \"'src/vc/vlmisc.c'\" \(14112 characters\)
sed "s/^X//" >'src/vc/vlmisc.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: vlmisc.c[3.11] Thu Feb 23 18:14:52 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/vlmisc.c[3.5]
X * 	Thu Feb 23 18:14:52 1989 axel@coma published $
X *  --- empty log message ---
X *  vlmisc.c[3.7] Thu Feb 23 18:14:52 1989 uli@coma published $
X *  --- empty log message ---
X *  vlmisc.c[3.9] Thu Feb 23 18:14:52 1989 axel@coma published $
X *  --- empty log message ---
X *  vlmisc.c[3.10] Thu Feb 23 18:14:52 1989 axel@coma save $
X *  --- empty log message ---
X *  vlmisc.c[3.11] Thu Feb 23 18:14:52 1989 axel@coma published $
X *  --- empty log message ---
X */
X
X#include <stdio.h>
X#include <pwd.h>
X#include <grp.h>
X#include <strings.h>
X#include <sys/param.h>
X#include <sys/types.h>
X#include <sys/stat.h>
X
X#include <afs.h>
X#include <afsys.h>
X
X#include "vl.h"
X
X/*
X * Global, but not exported variables
X */
X#define VL_MAX_OWNERNAME 7			/* in real life 8 chars */
X#define VL_MAX_GROUPNAME 7			/* dito. */
X
Xstatic char *Progname;		                /* name of the called process*/
Xstatic char filemode[10];			/* visible file mode (ls(1)) */
Xstatic Af_user author, owner;
Xstatic char version_string[80];			/* e.g. -V1.0 */
Xstatic char error_string[80];			/* for {af_}perror */
X
Xchar **udattrs;					/* Uda sorted */
Xint  version_number;				/* Version identification
X						 * via option -V */
Xchar *version_states;				/* Version states via
X						 * option -s */
X
Xchar *GetVersionState (state)
X     int state;
X{
X  switch (state) {
X  case AF_BUSY:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[busy]" : "b");
X  case AF_SAVED:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[save]" : "s");
X  case AF_PROPOSED:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[prop]" : "p");
X  case AF_PUBLISHED:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[publ]" : "P");
X  case AF_ACCESSED:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[acce]" : "a");
X  case AF_FROZEN:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[froz]" : "f");
X  default:
X    return (IsOptionSet(VL_O_VERSIONSTATE) ? "[????]" : "?");
X  }
X}
X
Xchar *GetVersionId (generation, revision)
X     int generation, revision;
X{
X  if ( (generation != AF_BUSYVERS) || ( revision != AF_BUSYVERS)) {
X    (void)sprintf (version_string, "[%d.%d]", generation, revision);
X    return version_string;
X  }
X  else
X    return "";
X}
X
XVinfoCleanup ()
X{
X  
X}
X
Xchar *GetMode (mode)
X     u_short mode;
X{
X/* This function should return a capital 'L' in the file-class field */
X/* to indicate a *locked* version. Maybe optional. Instead of Ownername */
X/* the name of the locker is to be printed. */
X  (void)sprintf (filemode, "%c%c%c%c%c%c%c%c%c%c",
X	   (mode & S_IFDIR) ? 'd' : '-',
X	   (mode & S_IREAD) ? 'r' : '-',
X	   (mode & S_IWRITE) ? 'w' : '-',
X	   (mode & S_IEXEC) ? 'x' : '-',
X	   (mode & (S_IREAD >> 3)) ? 'r' : '-',
X	   (mode & (S_IWRITE >> 3)) ? 'w' : '-',
X	   (mode & (S_IEXEC >> 3)) ? 'x' : '-',
X	   (mode & (S_IREAD >> 6)) ? 'r' : '-',
X	   (mode & (S_IWRITE >> 6)) ? 'w' : '-',
X	   (mode & (S_IEXEC >> 6)) ? 'x' : '-'
X 	   );
X    
X  if (mode & S_ISUID)
X    filemode[1] = 's';
X  if (mode & S_ISGID)
X    filemode[6] = 's';
X  if (mode & S_ISVTX)
X    filemode[9] = 't';
X
X  return filemode;
X}
X
Xextern char *GetUserInfo (userdesc)
X     Af_user *userdesc;
X{
X  char *uinfo, *tmp;
X  
X  if ((tmp = malloc(MAXNAMLEN + MAXHOSTNAMELEN + 2)) == NULL) {
X    fprintf (stderr, "in GetUserInfo: not enough memory\n");
X    exit (1);
X  }
X
X  if ((uinfo = malloc(20)) == NULL) {
X   fprintf (stderr, "in GetUserInfo: not enough memory\n");
X    exit (1);
X }
X  
X  (void)sprintf 
X    (tmp, "%s%s%s", userdesc->af_username, userdesc->af_userhost[0] ?
X	   "@" : "", userdesc->af_userhost);
X  (void)sprintf (uinfo, "%-16s", tmp);
X  free (tmp);
X  return uinfo;
X}
X
Xchar *GetDate (date)
X     time_t date;
X{
X  char *tmp_time;
X  extern char *ctime();
X
X  tmp_time = ctime(&date);
X
X  /* Format is "Sun Sep 16 01:03:52 1973\n\0" */
X  tmp_time = tmp_time + 4;
X  tmp_time[20] = '\0';
X  return tmp_time;
X}
X
X
XIsDirectory (name)
X     char *name;
X{
X  struct stat stbuf;
X
X  if (stat(name, &stbuf)) {
X    return 0;
X  }
X
X  return (stbuf.st_mode & S_IFDIR);
X}
X
Xint FileExists (name)
X     char *name;
X{
X  struct stat buf;
X
X  return ((stat (name, &buf) == 0) ? 1 : 0);
X}
X
X
Xint PutProgramName (name)
X     char *name;
X{
X  Progname = ((Progname = rindex (name, '/')) ? ++Progname : name);
X}
X
Xchar *GetProgramName ()
X{
X  return Progname;
X}
X
Xvoid PutVersionStates (states)
X     char *states;
X{
X  version_states = states;
X}
X
X#define nxt(s) (s = (*(s+strlen(s)+1) != '\0') ? s+strlen(s)+1 : NULL)
X
XCopyUdattrs (udaval, udattrs)
X     char *udaval;
X     char **udattrs;
X{
X  /* returns # of udattrs */
X  register int i;
X
X  register char *cp;
X  char *temp;
X
X  if ( (temp = malloc ((unsigned)(strlen (udaval) +2))) == NULL) {
X    perror ("malloc");
X    exit (1);
X  }
X  (void)strcpy (temp, udaval);
X  temp[strlen(udaval)+1] = '\0';
X  
X  cp = temp;			/*  */
X  while (temp && *temp) {
X    if (*temp == ',') {
X      *temp = '\0';
X    }
X    ++temp;
X  }
X
X  i = 0;
X  while (cp && *cp) {
X    udattrs[i] = cp;
X    i++; nxt(cp);		/* nxt() is a macro !*/
X  }
X  udattrs[i] = NULL;
X
X  /*
X   * Now scan for "foo=bar<blank>bar1" and substitute <blank> by <Ctrl-A>.
X   * Don't ask why.
X   */
X
X  for (i=0; udattrs[i]; i++) {
X    cp = udattrs[i];
X    for (cp = udattrs[i]; cp && *cp; cp++)
X      if (*cp == ' ')
X	*cp = AF_UDAVALDEL;		/* This is a Ctrl-A */
X  }
X  return i;			/* return # of udattrs */
X}
X
Xint AddUdattrs (udas)
X     char *udas;
X{
X  int i, length, na;
X  char **cpp;
X
X  if ( udas && (*udas == ':')) udas++;
X  length = 0;
X  /* determine length of current udattrs */
X  if (udattrs && *udattrs) {
X    for (i = 0 ; udattrs[i]; i++)
X      length++;
X  }
X
X  length += strlen (udas) + 1;	/* plus the new udas */
X  length++;
X  if ((cpp = (char **) malloc ((unsigned)(sizeof (char **) * length))) 
X      == (char **) NULL) {
X    (void)sprintf (error_string, "%s: in AddUdattra(): malloc", Progname);
X    perror (error_string);
X    exit (1);
X  }
X
X  na = CopyUdattrs (udas, cpp);
X  
X  if (udattrs && *udattrs) {
X    for (i = 0 ; udattrs[i]; i++) /* copy old into new array */
X      cpp[na++] = udattrs[i];
X  }
X  
X  cpp[na] = (char *) NULL;
X  free ((char *)udattrs);
X  
X  udattrs = cpp;
X}
X
XAddHiddenUda (name, val)
X     char *name, *val;
X{
X  int length;
X  char *huda;
X  
X  length = strlen (name);
X  length += strlen (val);
X
X  if ((huda = malloc ((unsigned)(length+2*sizeof(char)))) == (char *) NULL) {
X    (void)sprintf (error_string, "in AddHiddenUda(): malloc");
X    perror (error_string);
X    exit (1);
X  }
X  (void)sprintf (huda, "%s=%s", name, val);
X  AddUdattrs (huda);
X}
X
Xchar **GetUdattrs ()
X{
X  return udattrs;
X}
X
Xu_long vstates = 0;
X#define VL_CHCK_BUSY 01
X#define VL_CHCK_SAVE 02
X#define VL_CHCK_PROPOSED 04
X#define VL_CHCK_PUBLISHED 010
X#define VL_CHCK_ACCESSED 020
X#define VL_CHCK_FROZEN 040
X#define VL_CHCK_ALL 077
X#define VL_MAX_STATES 6
X
Xvoid ScanVersionStates ()
X
X     /*
X      * Scans strings of the form:
X      * 	bspPaf
X      *		c+ (c is a char)
X      *		c-
X      *		~c (not)
X      *		!c (not)
X      *		c-,c+
X      *		c+c-
X      */
X{
X  register last_state;
X  
X  if (! (*version_states)) {
X    vstates  = VL_CHCK_ALL;
X    return;
X  }
X
X  while (*version_states) {
X    switch (*version_states) {
X    case 'b':
X      vstates |= VL_CHCK_BUSY;
X      last_state = AF_BUSY;
X      break;
X    case 's':
X      vstates |= VL_CHCK_SAVE;
X      last_state = AF_SAVED;
X      break;
X    case 'p':
X      vstates |= VL_CHCK_PROPOSED;
X      last_state = AF_PROPOSED;
X      break;
X    case 'P':
X      vstates |= VL_CHCK_PUBLISHED;
X      last_state = AF_PUBLISHED;
X      break;
X    case 'a':
X      vstates |= VL_CHCK_ACCESSED;
X      last_state = AF_ACCESSED;
X      break;
X    case 'f':
X      vstates |= VL_CHCK_FROZEN;
X      last_state = AF_FROZEN;
X      break;
X    case '+':			/* -sb+ */
X      switch (last_state) {
X      case AF_BUSY:
X	vstates |= VL_CHCK_BUSY;
X      case AF_SAVED:
X	vstates |= VL_CHCK_SAVE;
X      case AF_PROPOSED:
X	vstates |= VL_CHCK_PROPOSED;
X      case AF_PUBLISHED:
X	vstates |= VL_CHCK_PUBLISHED;
X      case AF_ACCESSED:
X	vstates |= VL_CHCK_ACCESSED;
X      case AF_FROZEN:
X	vstates |= VL_CHCK_FROZEN;
X	break;
X      default:
X	fprintf (stderr, "%s: fatal error in ScanVersionStates\n", Progname);
X	exit (1);
X      }
X      break;
X    case '-':			/* -sb- */
X      if ( !((*(version_states+1) == ',') ||
X	     (!*(version_states+1)))) {	/* -sb-f */
X	fprintf (stderr, "%s: subrange of states is not allowed\n",
X		 Progname);
X	exit (1);
X      }
X      else {
X	switch (last_state) {
X	case AF_FROZEN:
X	  vstates |= VL_CHCK_FROZEN;
X	case AF_ACCESSED:
X	  vstates |= VL_CHCK_ACCESSED;
X	case AF_PUBLISHED:
X	  vstates |= VL_CHCK_PUBLISHED;
X	case AF_PROPOSED:
X	  vstates |= VL_CHCK_PROPOSED;
X	case AF_SAVED:
X	  vstates |= VL_CHCK_SAVE;
X	case AF_BUSY:
X	  vstates |= VL_CHCK_BUSY;
X	  break;
X	default:
X	  fprintf (stderr, "%s: fatal error in ScanVersionStates\n", Progname);
X	  exit (1);
X	}
X      }
X      break;
X    case ',':			/* skip this char */
X      break;
X    case '~':
X    case '!':
X      if (!*(version_states + 1)) {
X	fprintf (stderr, "%s: missing version state after '%c'\n",
X		 Progname, *version_states);
X	exit (1);
X      }
X      vstates = VL_CHCK_ALL;
X      switch (*(++version_states)) {
X      case 'b':
X	vstates &= ~VL_CHCK_BUSY;
X	last_state = AF_BUSY;
X	break;
X      case 's':
X	vstates &= ~VL_CHCK_SAVE;
X	last_state = AF_SAVED;
X	break;
X      case 'p':
X	vstates &= ~VL_CHCK_PROPOSED;
X	last_state = AF_PROPOSED;
X	break;
X      case 'P':
X	vstates &= ~VL_CHCK_PUBLISHED;
X	last_state = AF_PUBLISHED;
X	break;
X      case 'a':
X	vstates &= ~VL_CHCK_ACCESSED;
X	last_state = AF_ACCESSED;
X	break;
X      case 'f':
X	vstates &= ~VL_CHCK_FROZEN;
X	last_state = AF_FROZEN;
X	break;
X      default:
X	fprintf (stderr, "%s: unknown state '%c'. Ignored.\n",
X		 Progname, *version_states);
X	break;
X      }
X      break;
X    default:
X      fprintf (stderr, "%s: unknown state '%c'. Asume 'b+'\n",
X	       Progname, *version_states);
X      vstates = VL_CHCK_ALL;
X      return;
X    }
X    version_states++;
X  }
X}
X
Xint MatchesVersionStates (attrbuf)
X     Af_attrs *attrbuf;
X{
X  register int attrstate;
X  register int state;
X
X  state = vstates;
X  attrstate = attrbuf->af_state;
X  
X  if (state == VL_CHCK_ALL) return 1;
X  
X  switch (attrstate) {
X  case AF_BUSY:
X    return (state & VL_CHCK_BUSY);
X  case AF_SAVED:
X    return (state & VL_CHCK_SAVE);
X  case AF_PROPOSED:
X    return (state & VL_CHCK_PROPOSED);
X  case AF_PUBLISHED:
X    return (state & VL_CHCK_PUBLISHED);
X  case AF_ACCESSED:
X    return (state & VL_CHCK_ACCESSED);
X  case AF_FROZEN:
X    return (state & VL_CHCK_FROZEN);
X  default:
X    return 0;
X  }  
X}
X
Xvoid PutAuthorIdentifications (author_id)
X     char *author_id;
X{
X  char *cp;
X
X  if (cp=index (author_id, '@')) {
X    *cp++ = '\0';
X    (void)strcpy (author.af_userhost, cp);
X  }
X  (void)strcpy (author.af_username, author_id);
X}
X
Xchar *GetAuthoridFromAuthor ()
X{
X    return author.af_username;
X}
X
Xchar *GetAuthorhostFromAuthor ()
X{
X    return author.af_userhost;
X}
X
X
Xvoid PutOwnerIdentifications (owner_id)
X     char *owner_id;
X{
X  char *cp;
X
X  if (cp=index (owner_id, '@')) {
X    *cp++ = '\0';
X    (void)strcpy (owner.af_userhost, cp);
X  }
X  (void)strcpy (owner.af_username, owner_id);
X}
X
Xchar *GetOwneridFromOwner ()
X{
X    return owner.af_username;
X}
X
Xchar *GetOwnerhostFromOwner ()
X{
X    return owner.af_userhost;
X}
X
X/*ARGSUSED*/
Xint
Xa_dir_and_a_file (ac, av)
X     int ac;
X     char **av;
X{
X  /*
X   * Return 1 iff av contains any directory name.
X   */
X  while (av && *av) {
X    if (IsDirectory (*av))
X      return 1;
X    av++;
X  }
X  return 0;
X}
X
Xchar **
Xrearrange_args (ac, av)
X     int ac;
X     char **av;
X{
X  /*
X   * Sorts av in the following order: first pure files, then directories.
X   * Returns sorted av.
X   */
X  char **dirs;
X  char **tdirs;
X  char **files;
X  char **tfiles;
X  char **tav;
X
X  tav = av;
X  
X  if ((dirs = (char **)
X       malloc ((unsigned)((ac + 1) * sizeof(char *)))) == (char **)NULL) {
X    perror ("malloc");
X    exit (1);
X  }
X  tdirs = dirs;
X  
X  if ((files = (char **)
X       malloc ((unsigned)((ac + 1) * sizeof(char *)))) == (char **)NULL) {
X    perror ("malloc");
X    exit (1);
X  }
X  tfiles = files;
X  
X  while (av && *av) {
X    if (IsDirectory (*av)) {
X      *dirs = *av;
X      dirs++;
X    }
X    else {
X      *files = *av;
X      files++;
X    }
X
X    av++;
X  }
X
X  files = (char **) NULL;
X  dirs = (char **) NULL;
X  
X  av = tav;
X  while (tfiles && *tfiles) {
X    *av = *tfiles;
X    av++; tfiles++;
X  }
X
X  while (tdirs && *tdirs) {
X    *av = *tdirs;
X    av++; tdirs++;
X  }
X
X  return tav;
X}
X
Xint IsHiddenUda (uda)
X     char *uda;
X{
X  /*
X   * A hidden Uda begins and ends with 2 '_'.
X   */
X  
X  return (!strncmp (uda, "__", 2));
X}
X
Xint IsHiddenFile(attrbuf)
X     Af_attrs *attrbuf;
X{
X  /* Is file a hidden file ? */
X  if ( (attrbuf->af_name[0] == '\0') || (attrbuf->af_name[0] == '.') )
X    return 1;
X  else
X    return 0;
X}
X
Xlogerr (msg) char *msg; {
X  fprintf (stderr, "%s: %s.\n", Progname, msg);
X}
END_OF_FILE
if test 14112 -ne `wc -c <'src/vc/vlmisc.c'`; then
    echo shar: \"'src/vc/vlmisc.c'\" unpacked with wrong size!
fi
# end of 'src/vc/vlmisc.c'
fi
echo shar: End of archive 16 \(of 33\).
cp /dev/null ark16isdone
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.