[comp.os.minix] SVC - Revision control for Minix

housel@ea.ecn.purdue.edu (Peter S. Housel) (02/04/88)

	The following is my own "poor-man's version control" system,
which is usable with Minix or almost any other Unix workalike. This should
help keep track of all of those wonderful patches we've been getting in this
newsgroup.
	It is, of course, in the public domain. Do anything you want with it.

-Peter S. Housel-	housel@ei.ecn.purdue.edu	...!pur-ee!housel
----------------------cut-here------------------------------------------
#!/bin/sh
# this is a shell archive. extract with /bin/sh.
echo 'x - README'
sed 's/^X//' <<'**-README-EOF-**' >README
X
X	SVC is the Shell Version Control system, and is inspired by Walter
XTichy's Revision Control System, or RCS. The intention of SVC is to implement
Xthe subset of RCS that is commonly used for everyday maintainance. (That is,
Xthe part I know how to use.)
X
X	To run SVC on Minix, you need to do three things. First, apply the
Xpatches I posted to comp.os.minix to repair the getc() and fseek()
Xlibrary routines; otherwise you will get spurious lines inserted into
Xthe front of your files when you check them in/out. Similarly, you also need
Xto apply my patches to scanf(). Thirdly, you need a version of ctime().
XVersions have been posted by myself and a few other people, or you could
Xuse a dummy version (e.g. return "\n";).
X
X	To use SVC on a non-Minix system, you will need to find a copy
Xof "fix", or of Larry Wall's "patch" program. To use patch, you need to
Xcompile ci.c with "-DPATCH".
X
XMAN PAGES
X
XCommand:	ci - check in an SVC revision
XSyntax:		ci [-l] [-u] file
XFlags:		-l	After checking in, check back out again and lock
X		-u	After checking in, do not delete the file
XExamples:	ci -u Makefile		check Makefile back in
X		ci -l newfile		create SVC file for newfile, relock
X
X   Ci checks the specified file into its SVC archive. If an SVC archive file
Xdid not exist, one is created with the name "file,S". (If a directory named
X"SVC" is present in the same directory as "file", the archive will be placed
Xthere instead.) 
X   A log message will be prompted for, and read from standard input; this
Xmay be several lines, terminated with "." on a line by itself or EOT. After
Xthe file has been checked in, the default action is to remove the source
Xfile. If "-u" is specified, the file will not be unlinked, but all write
Xpermissions will be removed. If "-l" is specified, a lock is placed on
Xthe SVC archive, and the file will remain writable by the owner. SVC archive
Xfiles are always read-only.
X   Version numbers start at "1" and are incremented by one for each revision
Xchecked in.
X
X
XCommand:	co - check out an SVC revision
XSyntax:		co [-l] [-r rev] file
XFlags:		-l	Place a lock on the SVC archive after checkout
X		-r rev	Check out revision "rev" instead most recent revision
XExamples:	co -l Makefile		check out and lock Makefile
X		co -r 4 foo		check out version 4 of foo
X
X   Co checks the specified file out of its SVC archive. If the archive
X".../file,S" does not exist, it is searched for in ".../SVC/file,S".
X   The specified revision will be checked out and placed in "file"; by
Xdefault it will be non-writable. If "-l" is specified, a lock will be
Xplaced on the archive and the file will be writable.
X
X
XCommand:	svclog - print log of SVC revisions
XSyntax:		svclog file
XFlags:		none
XExamples:	svclog foo		print out revision history for foo
X		svclog Makefile,S	print out revision history for Makefile
X
X   Svclog prints out the revision history of the specified file. This
Xinformation includes the revision numbers, dates, and log entries for each
Xof the revisions, and indicates whether or not a lock on this file exists.
XFor simplicity, the output format is rather raw.
X
X
XINSTALLATION
X
X	Installation of SVC should be rather straightforward. The "ci" and
X"co" binaries should be compiled using the supplied makefile, and the "ci",
X"co", and "svclog" files should be put in your favorite default path
Xdirectory (such as /usr/bin). It may also be helpful to increase the memory
Xallocation for /usr/bin/diff and /usr/bin/fix (using chmem) to as high as
Xpossible.
X
XBACKGROUND
X
X	SVC stands for Shell Version Control, and is so named for two
Xreasons. The first is that it was originally implemented using Bourne
Xshell scripts. (These are included as "ci.sh" and "co.sh"; they serve no
Xuseful purpose in the current version but are presented for your amusement
Xand/or enlightenment). This implementation gave pretty good performance on
Xan 8-MIPS machine running BSD4.3+, but on my AT compatible it was just too
Xslow. Also, the scripts make heavy use of "sed," which doesn't _quite_ work
Xon Minix yet. For this reason "ci" and "co" were rewritten in C.
X
X	The other reason for the name is that the SVC archives are in the
Xform of shell scripts, in the manner of shar-files. The original reason for
Xthis was so that the archives could literally extract themselves - by
Xexecuting them with "sh". This format is reasonably easy to figure out by
Xreading it, and not too difficult for the program to understand. In a pinch,
Xyou can do without "co".
X
X	However, there is a problem with this approach. Shell input using
X"<<" (a here document in Minix sh source file terminology) is processed
Xby the shell, including the expansion of environment variables and such.
XThis means that files which contain shell-variable syntax (i.e. makefiles
Xand other shell scripts) may be garbled on extraction. This was another
Xreason why the programs were translated into C.
X
X	ci.c and co.c were designed to be somewhat bullet-proof, and have
Xworked pretty well in the time I have been using them.
X
XSUGGESTED USE
X
X	The major use for SVC on my system is keeping track of system
Xsources. There are "SVC" subdirectories all throughout /usr/src, and
Xwhenever a fix is posted to the net I can check out a file, apply the
Xpatches, and check it back in. The advantage of this is that if I want
Xto refer to an earlier version of the file, or want to apply patches to a
Xfile I have changed since the last official version, an older revision can
Xbe checked out.
X
X	I suggest experimenting with the system to get a feel for how it
Xworks if you are not already familiar with RCS. Do not use it on any
Xfiles for which you do not have a backup copy until you are confident
Xthat you are doing things correctly.
X
X-Peter S. Housel-
Xhousel@ei.ecn.purdue.edu	...!pur-ee!housel
X
**-README-EOF-**
echo 'x - Makefile'
sed 's/^X//' <<'**-Makefile-EOF-**' >Makefile
X#
X# makefile for SVC
X#
X
XCFLAGS = -F -T/usr/tmp
X
Xall:	ci co
X
Xci:	ci.c
X	cc $(CFLAGS) -o ci ci.c
X	chmem =8000 ci
X
Xco:	co.c
X	cc $(CFLAGS) -o co co.c
X	chmem =8000 co
X
Xsvclog:	svclog.sh
X	cp svclog.sh svclog
X	chmod 755 svclog
**-Makefile-EOF-**
echo 'x - ci.c'
sed 's/^X//' <<'**-ci.c-EOF-**' >ci.c
X/* file: ci.c
X** author: Peter S. Housel 12/17/87
X*/
X
X#include <stdio.h>
X#include <strings.h>
X#include <stat.h>
X#include <pwd.h>
X#include <signal.h>
X
X#define SUFFIX		",S"		/* svc indicator */
X#define SVCDIR		"SVC"		/* svc postfix indicator */
X
X#define LINELEN		256		/* maximum line length */
X
X#ifndef PATCH
X#define FIX		"fix $1 Fix.$1 > New.$1; mv New.$1 $1\n"
X#else
X#define FIX		"patch -n -s $1 < Fix.$1; rm -f $1.orig\n"
X#endif !PATCH
X
X#ifdef MAXPATHLEN
X#define PATHLEN MAXPATHLEN
X#else
X#define PATHLEN 80			/* buffer length for filenames */
X#endif
X
Xint unlocked = 0;			/* leave unlocked after checkin */
Xint relock = 0;				/* lock next revision after checkin */
Xchar file[PATHLEN];			/* file to be checked in */
Xchar svc[PATHLEN];			/* filename for svc file */
Xchar newsvc[PATHLEN];			/* new copy of SVC file */
Xchar line[LINELEN];			/* temporary line buffer */
Xchar *p;				/* scratch character pointer */
X
XFILE *svcfp;				/* svc file */
XFILE *origfp, *newfp;			/* "orig" and "new" temp files */
XFILE *srcfp;				/* source file */
Xint rev;				/* new revision number */
Xint status;				/* wait() buffer */
Xstruct stat stb1, stb2;			/* stat buffers for size compare */
Xchar original[] = "/tmp/cioXXXXXX";	/* previous revision */
Xchar diffout[] =  "/tmp/cidXXXXXX";	/* diffs */
X
Xextern FILE *fopen();
Xextern char *mktemp(), *fgets(), *rindex(), *index();
Xextern char *ctime();
Xextern struct passwd *getpwuid();
Xextern long ftell();
X
Xchar *whoami();
Xint onintr();
X
Xmain(argc, argv)
Xint argc; char **argv;
X{
X#ifdef perprintf
X char errbuf[BUFSIZ];
X setbuf(stderr, errbuf);
X perprintf(stderr);
X#endif
X
X while(++argv, --argc)
X      {
X       if('-' == (*argv)[0])
X         {
X	  if('u' == (*argv)[1])
X	     ++unlocked;
X	  else if('l' == (*argv)[1])
X	     ++relock;
X	  else
X	    {fprintf(stderr, "ci: illegal option -%c\n", (*argv)[1]);
X	     exit(1);
X	    }
X	 }
X       else
X	  break;
X      }
X
X if(1 != argc)
X   {
X    fprintf(stderr, "ci: bad number of files arguments\n");
X    exit(1);
X   }
X
X fname(*argv, file);
X svcname(file, svc);
X
X fprintf(stderr, "%s -> %s\n", file, svc);
X
X signal(SIGHUP, onintr);
X signal(SIGINT, onintr);
X signal(SIGTERM, onintr);
X 
X#ifndef BSD
X if(NULL == (p = rindex(file, '/')))
X    p = file;
X else
X    ++p;
X
X if(strlen(p) > 13)
X   {
X    fprintf(stderr, "ci: filename %s is too long\n");
X    exit(1);
X   }
X#endif !BSD
X
X strcpy(newsvc, svc);
X *(rindex(newsvc, ',')) = ';';		/* temporary file will be "file;S" */
X
X if(NULL == (newfp = fopen(newsvc, "w")))
X   {
X    perror("ci: can't create SVC temporary");
X    exit(1);
X   }
X
X (void) mktemp(original);
X (void) mktemp(diffout);
X
X if(NULL != (svcfp = fopen(svc, "r")))  /* does svc-file exist? */
X   {
X    fgets(line, LINELEN, svcfp);
X    if(1 != sscanf(line, "# %d", &rev))
X      {
X       fprintf(stderr, "ci: %s: illegal SVC file header\n", svc);
X       exit(1);
X      }
X    ++rev;
X
X    if(!lockcheck(svcfp, rev))
X      {
X       fprintf(stderr, "Revision %d not locked\n", rev);
X       clean();
X       exit(1);
X      }    
X
X    if(NULL == (origfp = fopen(original, "w")))
X      {
X       fprintf(stderr, "ci: can't create %s", original);
X       perror("");
X      }
X    fgets(line, LINELEN, svcfp);   /* skip "cat <<***MAIN-eof***" line */
X
X    while(NULL != fgets(line, LINELEN, svcfp)
X	  && strcmp(line, "***MAIN-eof***\n"))
X         {
X	  fputs(line, origfp);
X	  if(ferror(origfp))
X	    {
X	     perror("ci: origfile");
X	     exit(1);
X	    }
X	 }
X    fclose(origfp);
X    
X    rundiff();
X
X    if(0 != stat(original, &stb1) || 0 != stat(diffout, &stb2))
X      {
X       perror("ci: can't stat original or diffout");
X       clean();
X       exit(1);
X      }
X   }
X else
X   { /* no - create one */
X    rev = 1;
X   }
X
X fprintf(newfp, "# %d\n", rev);
X fprintf(newfp, "cat <<***MAIN-eof*** >$1\n");
X if(NULL == (srcfp = fopen(file, "r")))
X   {
X    perror("ci: can't read source file");
X    clean();
X    exit(1);
X   }
X while(NULL != fgets(line, LINELEN, srcfp))
X       fputs(line, newfp);
X fclo);srcfp);
X fputs("***MAIN-eof***\n", newfp);
X 
X if(rev > 1)
X   {
X    fprintf(newfp, "if test $2 -ge %d ; then rm -f Fix.$1 ; exit 0 ; fi ; cat <<***%d-eof*** >Fix.$1\n", rev, rev);
X    p = (stb1.st_size <= stb2.st_size) ? original : diffout;
X    if(NULL == (origfp = fopen(p, "r")))
X      {
X       perror("can't open diff output file");
X       clean();
X       exit(1);
X      }
X    while(NULL != fgets(line, LINELEN, origfp))
X          fputs(line, newfp);
X    fclose(origfp);
X    fprintf(newfp, "***%d-eof***\n", rev);
X    fputs((original == p) ? "mv Fix.$1 $1\n" : FIX, newfp);
X    logmsg(newfp);
X    while(NULL != fgets(line, LINELEN, svcfp) && strncmp(line, "#***SVCLOCK***", 14)) 
X	  fputs(line, newfp);
X   }
X else
X   {
X    logmsg(newfp);
X    fputs("rm -f Fix.$1\n", newfp);
X   }
X 
X if(relock)
X   {fprintf(stderr, "(relocking into revision %d)\n", rev+1);
X    fprintf(newfp, "#***SVCLOCK*** %s %d\n", whoami(), rev+1);
X   }
X
X signal(SIGHUP, SIG_IGN);	/* disable during critical section */
X signal(SIGINT, SIG_IGN);
X
X if(ferror(newfp) || fclose(newfp) || ((rev > 1) && unlink(svc))
X				   || link(newsvc, svc))
X   {
X    fprintf(stderr, "SVC file write/link error - Checkin aborted\n");
X    clean();
X    exit(1);
X   }
X else
X    fprintf(stderr, "Checkin complete.\n");
X
X if(stat(svc, &stb1) < 0 || chmod(svc, stb1.st_mode & 0555) < 0)
X    perror("ci: can't chmod SVC file");
X
X if(unlocked)
X   {if(stat(file, &stb1) < 0 || chmod(file, stb1.st_mode & 0555) < 0)
X       perror("ci: can't chmod source file");
X   }
X else if(relock)
X   {if(stat(file, &stb1) < 0 || chmod(file, stb1.st_mode | 0200) < 0)
X       perror("ci: can't chmod source file");
X   }
X else
X    unlink(file);
X
X clean();
X exit(0);
X}
X
Xrundiff()
X{		/* do "diff file original > diffout" */
X int fd;				/* redirected output file */
X
X switch(fork())
X       {
X	case -1:perror("ci: fork");	/* error */
X		clean();
X		exit(1);
X
X	case 0:				/* child */
X		if((fd = creat(diffout, 0600)) < 0 || -1 == dup2(fd, 1))
X		  {
X		   perror("ci: diffout");
X		   clean();
X		   exit(1);
X		  }
X		close(fd);
X		execl("/usr/bin/diff", "diff",  file, original, 0);
X		perror("ci: exec diff failed");
X		exit(1);
X
X	default:break;			/* parent */
X       }
X wait(&status);
X if(0 != status && 1<<8 != status)
X   {
X    fprintf(stderr, "ci: bad return status (0x%x) from diff\n", status);
X    clean();
X    exit(1);
X   }
X}
X
Xlogmsg(fp)
XFILE *fp;
X{
X long now;
X
X time(&now);
X fprintf(stderr, "Enter log message for revision %d (end with ^D or '.'):\n", rev);
X fprintf(fp, "#***SVC*** revision %d %s %s", rev, file, ctime(&now));
X while(NULL != gets(line) && strcmp(line, "."))
X       fprintf(fp, "#***SVC*** %s\n", line);
X}
X
Xfname(src, dst)
Xchar *src, *dst;
X{
X char *p;
X strcpy(dst, src);
X p = &dst[strlen(src) - strlen(SUFFIX)];
X if(!strcmp(p, SUFFIX))
X    *p = '\0';
X}
X
Xsvcname(src, dst)
Xchar *src, *dst;
X{
X extern char *rindex();
X char *p;
X 
X strcpy(dst, src);
X strcat(dst, SUFFIX);
X
X if(0 != access(dst, 4))
X   {
X    char dirname[PATHLEN];
X    if(NULL != (p = rindex(src, '/')))
X       strncpy(dirname, src, p - src + 1);
X    else
X       dirname[0] = '\0';
X    strcat(dirname, SVCDIR);
X
X    if(0 == access(dirname, 1))
X      {
X       strcpy(dst, dirname);
X       if(NULL == p)
X	 {strcat(dst, "/");
X          strcat(dst, src);
X         }
X       else
X          strcat(dst, p);
X       strcat(dst, SUFFIX);
X      }
X   } 
X}
X
Xlockcheck(fp, rev)
XFILE *fp;
Xint rev;
X{
X char lock[40], check[40];
X long pos;
X int ret;
X
X sprintf(lock, "#***SVCLOCK*** %s %d\n", whoami(), rev);
X  
X pos = ftell(fp);
X fseek(fp, -((long)strlen(lock)), 2);
X fgets(check, 40, fp);
X ret = (0 == strcmp(lock, check));
X fseek(fp, pos, 0);
X
X return ret;
X}
X
Xonintr()
X{
X fprintf(stderr, "Interrupt - Aborting checkin, cleaning up\n");
X clean();
X exit(1);
X}
X
Xclean()
X{
X if(strlen(original))		/* if only RCS made this check! */
X    unlink(original);
X if(strlen(diffout))
X    unlink(diffout);
X if(strlen(newsvc))
X    unlink(newsvc);
X}
X
Xchar *whoami()
X{
X struct passwd *pw;
X
X if(NULL != (pw = getpwuid(getuid())))
X    return pw->pw_name;
X else
X    return "nobody";
X}
**-ci.c-EOF-**
echo 'x - co.c'
sed 's/^X//' <<'**-co.c-EOF-**' >co.c
X/* file: co.c
X** author: Peter S. Housel 12/24/87
X*/
X
X#include <stdio.h>
X#include <strings.h>
X#include <stat.h>
X#include <pwd.h>
X
X#define SUFFIX		",S"		/* svc indicator */
X#define SVCDIR		"SVC"		/* svc postfix indicator */
X
X#define LINELEN		256		/* maximum line length */
X
X#ifdef MAXPATHLEN
X#define PATHLEN MAXPATHLEN
X#else
X#define PATHLEN 80			/* buffer length for filenames */
X#endif
X
Xchar file[PATHLEN];			/* file to be checked in */
Xchar svc[PATHLEN];			/* filename for svc file */
Xchar newsvc[PATHLEN];			/* new copy of SVC file */
Xchar line[LINELEN];			/* temporary line buffer */
Xchar *p;				/* scratch character pointer */
X
XFILE *svcfp;				/* svc file */
Xint rev;				/* old revision number */
Xint lastrev, lockrev;			/* latest file revision, lock into */
Xint status;				/* wait() buffer */
Xint lock;				/* lock the SVC file */
Xstruct stat stb;			/* stat() buffer */
Xchar *base;				/* basename of file */
X
Xchar difftemp[PATHLEN];			/* extract() fix/patch input */
X
Xextern FILE *fopen();
Xextern char *mktemp(), *fgets(), *rindex(), *index();
Xextern struct passwd *getpwuid();
X
Xchar *whoami(), *basename();
X
Xmain(argc, argv)
Xint argc; char **argv;
X{
X#ifdef perprintf
X char errbuf[BUFSIZ];
X setbuf(stderr, errbuf);
X perprintf(stderr);
X#endif
X
X while(++argv, --argc)
X      {
X       if('-' == (*argv)[0])
X         {
X	  if('r' == (*argv)[1])
X	    {--argc;
X	     rev = atoi(*++argv);
X	     if(rev < 1)
X	       {fprintf(stderr, "Illegal revision number\n");
X		exit(1);
X	       }
X	    }
X	  else if('l' == (*argv)[1])
X	     ++lock;
X	  else
X	    {fprintf(stderr, "co: illegal option -%c\n", (*argv)[1]);
X	     exit(1);
X	    }
X	 }
X       else
X	  break;
X      }
X
X if(1 != argc)
X   {
X    fprintf(stderr, "co: bad number of files arguments\n");
X    exit(1);
X   }
X
X fname(*argv, file);
X svcname(file, svc);
X 
X fprintf(stderr, "%s -> %s\n", svc, base = basename(file));
X
X if(NULL == (svcfp = fopen(svc, "r")))
X   {
X    perror("co: can't read SVC file");
X    exit(1);
X   }
X
X if(1 != fscanf(svcfp, "# %d", &lastrev) || lastrev < 1)
X   {
X    fprintf(stderr, "co: illegal SVC file format\n");
X    exit(1);
X   }
X
X fclose(svcfp);
X
X if(stat(base, &stb) >= 0 && (stb.st_mode & 0222))
X   {
X    fprintf(stderr, "Writable %s exists - overwrite (n/y)? ", base);
X    if(!getyn())
X      {
X       fprintf(stderr, "Checkout aborted\n");
X       exit(1);
X      }
X   }
X
X if(strlen(base))
X    unlink(base);
X
X if(0 == rev)
X    rev = lastrev;
X
X fprintf(stderr, "Checking out revision %d", rev);
X
X extract(svc, base, rev);
X
X if(lock)
X   {
X    lockrev = lastrev + 1;
X    fprintf(stderr, "; Locking into revision %d\n", lockrev);
X    if(stat(svc, &stb) < 0 || chmod(svc, stb.st_mode | 0200) < 0)
X       perror("co: can't chmod SVC file");
X    
X    if(stat(base, &stb) < 0 || chmod(base, stb.st_mode | 0200) < 0)
X       perror("co: can't chmod source file");
X
X    if(NULL == (svcfp = fopen(svc, "a"))
X       || (fprintf(svcfp, "#***SVCLOCK*** %s %d\n", whoami(), lockrev), ferror(svcfp)))
X      {
X       fprintf(stderr, "co: can't lock %s\n", svc);
X       exit(1);
X      }
X    if(stat(svc, &stb) < 0 || chmod(svc, stb.st_mode & 0555))
X       perror("co: can't chmod SVC file");
X   }
X else
X   {
X    putchar('\n');
X    if(stat(base, &stb) < 0 || chmod(base, stb.st_mode & 0555))
X       perror("co: can't chmod source file");
X   }
X
X exit(0);
X}
X
X
Xfname(src, dst)
Xchar *src, *dst;
X{
X char *p;
X strcpy(dst, src);
X p = &dst[strlen(src) - strlen(SUFFIX)];
X if(!strcmp(p, SUFFIX))
X    *p = '\0';
X}
X
Xsvcname(src, dst)
Xchar *src, *dst;
X{
X extern char *rindex();
X char *p;
X 
X strcpy(dst, src);
X strcat(dst, SUFFIX);
X
X if(0 != access(dst, 4))
X   {
X    char dirname[PATHLEN];
X    if(NULL != (p = rindex(src, '/')))
X       strncpy(dirname, src, p - src + 1);
X    else
X       dirname[0] = '\0';
X    strcat(dirname, SVCDIR);
X
X    if(0 == access(dirname, 1))
X      {
X       strcpy(dst, dirname);
X       if(NULL == p)
X	 {strcat(dst, "/");
X          strcat(dst, src);
X         }
X       else
X          strcat(dst, p);
X       strcat(dst, SUFFIX);
X      }
X   } 
X}
X
Xextract(script, out, rev)
Xchar *script, *out; int rev;
X{
X FILE *outfp;
X int testrev;
X char buf[80];
X
X sprintf(difftemp, "Fix.%s", out);
X
X svcfp = fopen(script, "r");
X fgets(line, LINELEN, svcfp);		/* skip '# rev' line */
X fgets(line, LINELEN, svcfp);		/* skip 'cat <***MAIN-eof***' line */
X
X if(NULL == (outfp = fopen(out, "w")))
X   {
X    perror("co: can't create output file");
X    return;
X   }
X
X while(NULL != fgets(line, LINELEN, svcfp) && strcmp(line, "***MAIN-eof***\n"))
X       fputs(line, outfp);
X
X fclose(outfp);
X
X while(NULL != fgets(line, LINELEN, svcfp))
X      {
X       if(!strncmp(line, "if ", 3))
X         {
X	  sscanf(line, "if test $2 -ge %d", &testrev);
X	  if(rev >= testrev)
X	    {
X	     unlink(difftemp);
X	     return;
X	    }
X          if(NULL ==  (outfp = fopen(difftemp, "w")))
X	    {
X	     perror("co: can't create output file");
X	     return;
X	    }
X	  sprintf(buf, "***%d-eof***\n", testrev);
X	  while(NULL != fgets(line, LINELEN, svcfp) && strcmp(line, buf))
X 		fputs(line, outfp);
X	  fclose(outfp);
X	 }
X       else if(!strncmp(line, "mv ", 3))
X	 {
X	  sprintf(buf, "mv Fix.%s %s", out, out);
X	  system(buf);
X	 }
X       else if(!strncmp(line, "fix ", 4))
X	 {
X	  sprintf(buf, "fix %s Fix.%s > New.%s; mv New.%s %s", out, out, out, out, out);
X	  system(buf);
X	 }
X       else if(!strncmp(line, "patch ", 6))
X	 {
X	  sprintf(buf, "patch -n -s %s < Fix.%s; rm -f %s.orig", out, out, out);
X	  system(buf);
X	 }
X       else
X	 {	/* ignore */
X	 }
X      }
X
X unlink(difftemp);
X return;	
X}
X
Xchar *basename(name)
Xchar *name;
X{
X char *p;
X
X if(NULL == (p = rindex(name, '/')))
X    return name;
X else
X    return p + 1;
X}
X
Xchar *whoami()
X{
X struct passwd *pw;
X
X if(NULL != (pw = getpwuid(getuid())))
X    return pw->pw_name;
X else
X    return "nobody";
X}
X
Xint getyn()
X{
X char ans[10];
X
X return (NULL != fgets(ans, 10, stdin)) && ('y' == ans[0] || 'Y' == ans[0]);
X}
**-co.c-EOF-**
echo 'x - svclog.sh'
sed 's/^X//' <<'**-svclog.sh-EOF-**' >svclog.sh
X#!/bin/sh
X#
Xsvc=`basename $1 ,S`,S
Xif test \( ! -r $svc \) -a -d "SVC" ; then svc=SVC/$svc ; fi
Xgrep '^#\*\*\*SVC' $svc
X
**-svclog.sh-EOF-**
echo 'x - ci.sh'
sed 's/^X//' <<'**-ci.sh-EOF-**' >ci.sh
X#!/bin/sh
X# SVC - the Shell Version Control system
X# author: Peter S. Housel 10/24/87
X#
Xremove="rm -f"
Xlock="false"
X#
Xwhile :; do
X   case $1 in
X-u ) remove="chmod a-w"
X     shift;;
X-l ) remove="chmod u+w"
X     lock=":"
X     shift;;
X*  ) break
X   esac
Xdone
X#
Xfile=`basename $1 ,S`
Xsvc=$file,S
Xif test \( ! -r $svc \) -a -d "SVC" ; then svc=SVC/$svc ; fi
Xecho '***MAIN-eof***' >/tmp/cir$$
Xif test -r $svc; then
X  rev=`sed -n '1s/#.* //p' $svc`; rev=`expr $rev + 1`
X  if test "#***SVCLOCK*** $USER $rev" != "`tail -1 $svc`" ; then
X    echo "Revision $rev not locked by $USER"
X    exit 1
X  fi
X  sed -e '3,/^\*\*\*MAIN-eof\*\*\*/!d' \
X      -e '/^\*\*\*MAIN-eof\*\*\*/d' $svc >/tmp/cio$$
X  sed -e '/^\*\*\*MAIN-eof\*\*\*/,$!d' \
X      -e '/^#\*\*\*SVCLOCK\*\*\*/d' \
X      -e '/^\*\*\*MAIN-eof\*\*\*/d' $svc >/tmp/cid$$
X  echo 'if test $2 -ge $rev ; then rm -f /tmp/$$ ; exit 0 ; fi ; cat <<***$rev-eof*** >/tmp/$$' >>/tmp/cir$$
X  diff $file /tmp/cio$$ >>/tmp/cir$$
X  echo "***$rev-eof***" >>/tmp/cir$$
X  echo 'fix $1 /tmp/$$ > New.$1; mv New.$1 $1' >>/tmp/cir$$
Xelse
X  rev=1
X  echo 'rm -f /tmp/$$' > /tmp/cid$$
Xfi
Xecho "Enter log message for revision $rev (end with ^D or '.'):"
Xecho "#***SVC*** revision $rev $file "`date` $USER >>/tmp/cir$$
Xwhile read logline; do
X  if test x"$logline" = x. ; then break; fi
X  echo "#***SVC*** $logline" >>/tmp/cir$$
Xdone
Xecho "# " $rev >$svc+
Xecho 'cat <<***MAIN-eof*** >$1' >> $svc+
Xif cat $file /tmp/cir$$ /tmp/cid$$ >> $svc+ ; then
X  rm -f /tmp/ci?$$
X  echo "Checkin complete."
X  mv $svc+ $svc
X  if $lock; then
X    rev=`expr $rev + 1`
X    echo "#***SVCLOCK*** $USER $rev" >>$svc
X    echo "(Locking into revision $rev.)"
X  fi
X  chmod a-w $svc
X  $remove $file
Xelse
X  echo "Checkout ABORTED!!!"
X  exit 1
Xfi
**-ci.sh-EOF-**
echo 'x - co.sh'
sed 's/^X//' <<'**-co.sh-EOF-**' >co.sh
X#!/bin/sh
X# SVC - the Shell Version Control system
X# author: Peter S. Housel 10/24/87
X#
Xlock="false"
X#
Xwhile :; do
X   case $1 in
X-l ) lock=":"
X     shift;;
X-r ) rev=$2;
X     shift;
X     shift;;
X*  ) break
X   esac
Xdone
X#
Xfile=`basename $1 ,S`
Xsvc=$file,S
Xif test \( ! -r $svc \) -a -d "SVC" ; then svc=SVC/$svc ; fi
Xif test ! -r $svc ; then
X  echo "can't find $file,S or RCS/$file,S"
X  exit 1
Xfi
Xlastrev=`sed -n '1s/#.* //p' $svc`
Xif test -w $file; then
X  echo -n "Writable $file exists; Continue (n/y)? " ; read yn
X  if test x$yn != xy ; then echo "Checkout aborted" ; exit 1 ; fi
Xelif test -f $file; then
X  chmod u+w $file
Xfi
Xecho -n "Checking out revision " ${rev=$lastrev}
Xsh $svc $file $rev
Xif $lock; then
X  lockrev=`expr $lastrev + 1`
X  echo "; Locking into revision $lockrev"
X  chmod u+w $file
X  chmod u+w $svc; echo "#***SVCLOCK*** $USER $lockrev" >>$svc; chmod u-w $svc
Xelse
X  echo
X  chmod a-w $file
Xfi
Xexit 0
X
**-co.sh-EOF-**

worsley@ditmela.oz (Andrew Worsley) (02/05/88)

in article <1660@ea.ecn.purdue.edu>, housel@ea.ecn.purdue.edu (Peter S. Housel) says:
> 
> 
> 	The following is my own "poor-man's version control" system,
> which is usable with Minix or almost any other Unix workalike. This should
> help keep track of all of those wonderful patches we've been getting in this
> newsgroup.
> 	It is, of course, in the public domain. Do anything you want with it.

  Why not post the orginal RCS or atleast port it to MINIX. It is public domain
and I think available from the source achives. It is distributed in the
/usr/src/new part of BSD Unix, which I believe contains the User contributed
stuff. The only non public part is diff, but there are PD versions of that
around.

  If someone could volunteer to maintain an RCS tree of all the major versions
of MINIX it would help the job of coordinating the work done on it. Otherwise
I fear that a lot of effort will be lost as it will not be combinale with
other changes. I am not volunteering, at least not until I start using MINIX.


				Andrew Worsley

ncoverby@ndsuvax.UUCP (Glen Overby) (02/07/88)

In article <285@ditmela.oz> worsley@ditmela.oz (Andrew Worsley) writes:
>in article <1660@ea.ecn.purdue.edu>, housel@ea.ecn.purdue.edu (Peter S. Housel) says:
>
>  If someone could volunteer to maintain an RCS tree of all the major versions
>of MINIX it would help the job of coordinating the work done on it. Otherwise
>I fear that a lot of effort will be lost as it will not be combinale with
>other changes. I am not volunteering, at least not until I start using MINIX.

I have tried doing exactly this for local use, with some success.  The
major problem is the time involved.  And, as you mention, combinability
of changes (figuring out what changes will co-exist).  It would help
greatly if everybody had a system like RCS set up with identical
revision trees.  Then new patches could be merged into the tree in their
proper place, and co-existing changes would be documented by where in
the tree the changes fell. 

Also, how would changes from this be distributed? Re-posting to Usenet
is rather wasteful, and there is no Minix moderated sources group.  And
who is to determine what goes "in" and what stays "out"? This means
somebody will have to determine things like quality of the work (bug
free), documentation, etc.  We could go the route of the two
comp.sources.{unix,misc}, where the really good stuff (documented,
passes lint, etc) goes one way, and everything else goes the other way. 
To date, it's been everybody on their own determining what changes work
by trying them out; the only real unifying force has been Andy
Tannebaum's "accepting" people's changes.  Andy has already said he
doesn't have the time required to be a moderator of sorts. 

I think the way to really make something like RCS-style maintenance
benefit us as a whole is to have a standard "tree" (revision) format
established, and place $Header lines in every file.  Then convice people
to USE it. 

I'm willing to post the non-minix-source part of my RCS files with the
header info (stuff like descriptions and "$Header"s if I can figure out
a decent way to do this (lateley, I've been moving the $Header lines to
the END of the files because they mess me up when applying new patches,
but they're a lot nicer at the beginning)).  To give credit where credit
is due, much of this "grunt work" was done by Freeman Pascal at NDSU,
not me (I just badgered him into doing it). 

I'd also like to mention that without the 'idx' utility from
comp.sources.unix I'd surely go crazy working with Minix's internals!

wheels@mks.UUCP (Gerry Wheeler) (02/10/88)

In article <285@ditmela.oz>, worsley@ditmela.oz (Andrew Worsley) writes:
>   Why not post the orginal RCS or atleast port it to MINIX. It is public
> domain, and I think available from the source achives.

I think this is incorrect.  Although RCS is distributed with some
versions of Berkeley Unix, it is not public domain.  There was some
discussion about this in comp.sys.ibm.pc (I think) recently. 

MKS has just recently ported a *licensed* copy of Mr.  Tichy's source
code to MS-DOS, and we don't want people thinking they can make copies
of it for their friends.
-- 
     Gerry Wheeler                           Phone: (519)884-2251
Mortice Kern Systems Inc.               UUCP: uunet!watmath!mks!wheels
   35 King St. North                             BIX: join mks
Waterloo, Ontario  N2J 2W9                  CompuServe: 73260,1043

aja@i.cc.purdue.edu (Miek Rowan) (02/12/88)

	You are right, RCS was developed here, and it is free 
only to people with a Unix licence.  But I do hear that GNU-RCS
will be out really soon... has anyone else heard anything about
it?  

miek

callen@ada-uts (02/12/88)

>In article <285@ditmela.oz>, worsley@ditmela.oz (Andrew Worsley) writes:
>>   Why not post the orginal RCS or atleast port it to MINIX. It is
>>public domain, and I think available from the source achives.

>I think this is incorrect.  Although RCS is distributed with some
>versions of Berkeley Unix, it is not public domain.  There was some
>discussion about this in comp.sys.ibm.pc (I think) recently.

>MKS has just recently ported a *licensed* copy of Mr.  Tichy's source
>code to MS-DOS, and we don't want people thinking they can make copies
>of it for their friends.
>--
>     Gerry Wheeler                           Phone: (519)884-2251
>Mortice Kern Systems Inc.               UUCP: uunet!watmath!mks!wheels
>   35 King St. North                             BIX: join mks
>Waterloo, Ontario  N2J 2W9                  CompuServe: 73260,1043
>----------

Hmmm... I suggest that anyone porting RCS contact Walter Tichy (his
address is tichy@pudue) and get the straight poop. I just asked him about
doing a port for the Macintosh, and he said fine. My understanding the
way this works is:

 - RCS ports are encouraged. Contact Tichy before you start, though, so
   he knows what you are up to; he tries to coordinate ports to avoid
   duplication of effort. He also wants the source code for the port
   once it's done so that he may furnish it to others.

 - Anyone can have RCS for FREE; just ask Tichy first.

 - You may NOT sell a port of RCS. You MAY sell a product that INCLUDES
   RCS (like, say, a complete compilation/editing/debugging system), but
   you must furnish the RCS portion for free and supply source upon
   request.

In other words, he wants RCS to see the widest possible distribution but
does NOT want to lose control of his work, or see anyone else profit from
his work. So MKS CANNOT insist that their port not be copied.

wnp@killer.UUCP (Wolf Paul) (02/19/88)

In article <70900002@ada-uts> callen@ada-uts writes:
>
>>MKS has just recently ported a *licensed* copy of Mr.  Tichy's source
>>code to MS-DOS, and we don't want people thinking they can make copies
>>of it for their friends.
>Hmmm... I suggest that anyone porting RCS contact Walter Tichy (his
>address is tichy@pudue) and get the straight poop. I just asked him about
>doing a port for the Macintosh, and he said fine. My understanding the
>way this works is:
> ...
>In other words, he wants RCS to see the widest possible distribution but
>does NOT want to lose control of his work, or see anyone else profit from
>his work. So MKS CANNOT insist that their port not be copied.

I would be careful making statements like that. IF MKS has a license contract
in writing, with Walter Tichy's signature on it, which allows them to restrict
rights to their port of RCS, then anything Walter Tichy tells you or anyone elseis irrelevant, and MKS could go after anyone copying their port.

So, unless you have seen a copy of MKS's agreement with Mr Tichy, and KNOW
FOR CERTAIN that it does not give MKS exclusive rights to their port, you should
not make suggestions which might get those who follow them into serious
legal trouble.

Wolf Paul
wnp@killer
wnp@dcs

KLH@sri-nic.arpa (Ken Harrenstien) (02/19/88)

FYI.
                ---------------

Return-Path: <@RELAY.CS.NET,@ira.uka.de,@i41s1.ira.uka.de:tichy@ira.uka.de>
Received: from RELAY.CS.NET by SRI-NIC.ARPA with TCP; Thu 18 Feb 88 05:49:58-PST
Received: from germany.csnet by RELAY.CS.NET id ai08492; 18 Feb 88 8:09 EST
Received: from i41s1 by iraun1.ira.uka.de. id aa06846; 18 Feb 88 9:22 MET
Date:     Thu, 18 Feb 88 9:21:58 MET
From:     Walter Tichy <tichy%ira.uka.de@RELAY.CS.NET>
To:       Ken Harrenstien <KLH%sri-nic.arpa%ira.uka.de@RELAY.CS.NET>
cc:       tichy%ira.uka.de@RELAY.CS.NET, 
          wheels%mks.uucp%ira.uka.de@RELAY.CS.NET
Subject:  Re:  [callen@ada-uts: Re: SVC - Revision control for Minix]

An important correction to your message:

MKS can very well insist that their port not be copied.
MKS has	 a licensed version of RCS that is not in the public
domain (an enhancement of the one on the Berkeley tape).
They have furthermore added their own software, namely diff
and diff3. The originals, as you may know, are AT&T's,
and have so far hampered porting RCS. MKS has written its own
to overcome this.

MKS has a license to sell its port of RCS to the IBM PC.
The licencse grants them full rights to their port,
and all the copyright protection etc. available.

You cannot copy the MKS RCS without permission from MKS.

-Walter Tichy

-------

mitch@Stride.COM (Thomas Mitchell) (02/20/88)

In article <70900002@ada-uts> callen@ada-uts writes:
>
>>In article <285@ditmela.oz>, worsley@ditmela.oz (Andrew Worsley) writes:
>>>   Why not post the original RCS or atleast port it to MINIX. It is
>>>public domain, and I think available from the source achives.
>
>address is tichy@pudue) and get the straight poop.

Good Idea.  

When we at MicroSage looked at RCS it contained (used) AT&T
pattern matching code.  The result was that a source license was
required.  Our last contact with Walter Tichy was 21 Feb. 1986.
so -- in the intervening time RCS may have been recoded without
the AT&T code.

Remember that one of the goals of Unix was economy of
programming. 

P.S.  I think RCS is vastly better than sccs.