PWB1/sys/source/sccs4/cmd/scv.c
#
/*
Program to convert release 3 (or release 2 or even 1) SCCS files
to release 4 SCCS files.
Usage:
scv arg ...
arg is any argument acceptable as an SCCS file
name argument to the get command. E.g.:
scv mysccsdir
will convert every release 3 (or 2 or 1 but NOT 4) SCCS file in the
directory "mysccsdir".
*/
# include "../hdr/defines.h"
# include <dir.h>
/*
Release 3 SCCS File Structures (1.8 77/06/13 13:44:39)
See osccsfile(V).
*/
struct Header {
int Hmagicno;
char Htype[10];
char Hpers[14];
char Hdesc[100];
int Hfloor;
int Hceil;
int Hsw[5];
int Hrdef;
char Hulist[32];
char Hexpand[50];
int Hash;
};
#define MAGICNO (7)
#define HASHADDR (226)
struct Reltab {
int Rrel;
int Rlevs;
};
struct Deltab {
int Drel;
int Dlev;
char Dtype; /*'D': delta,'P','U': non-prop,'I': incl,'E': excl */
char Dfill; /* Used to be option letter */
long Ddatetime;
char Dpgmr[8];
char Dhist[200];
};
struct Control {
int Crel;
int Clev;
char Cctl; /* -11: ins, -12: del, -13: end */
};
#define SIZEOFCONTROL (5)
#define OINS (-11)
#define ODEL (-12)
#define OEND (-13)
struct Line {
char Lline [256];
};
/*
Structure for use with buffered I/O routines opnl, opnr,
getl and getr.
*/
struct Ibufr {
int Ifildes;
char *Irecptr;
char *Iend;
char Ibuff1[256];
char Ibuff2[512];
char Ibuff3[2];
int Ilen;
int Ihflag;
int Ihcnt;
int Ihtot;
};
/*
Structure for use with buffered I/O routines crtr, crtl, putl,
putr, flshr and buflsh.
*/
struct Obufr {
int Ofildes;
char *Orecptr;
char *Oend;
char Obuff1[512];
int Ohflag;
int Ohcnt;
};
/*
* structure to access an
* integer in bytes
*/
struct
{
char lobyte;
char hibyte;
};
/*
* structure to access an integer
*/
struct
{
int integ;
};
/*
* structure to access a long as integers
*/
struct {
int hiword;
int loword;
};
/*
Structure for referencing pieces of localtime().
*/
struct Time {
int Tseconds;
int Tminutes;
int Thours;
int Tday_month;
int Tmonth;
int Tyear;
int Tday_week;
int Tday_year;
int Tflag;
};
/*
SCCS Internal Structures (used by get and delta). (1.8)
*/
struct Apply {
int Adt; /* pseudo date-time */
int Acode; /* APPLY, NOAPPLY or EMPTY */
};
#define APPLY (1)
#define NOAPPLY (-1)
#define EMPTY (0)
struct Queue {
struct Queue *Qnext;
int Qrel; /* release */
int Qlev; /* level */
int Qdt; /* pseudo date-time */
int Qkeep; /* keep switch setting */
};
#define YES (1)
#define NO (-1)
#define NULL (0)
#define SIZEOFPfile (50)
struct Packet {
char Pfile[SIZEOFPfile]; /* file name containing module */
/*
Note: the order of the next two words
can not___ be changed!
This is because the release and level together
are treated as a long.
*/
int Prel; /* specified release (-1 = not spec.) */
int Plev; /* specified level (-1 = not spec.)*/
char Pverbose; /* verbose flags (see #define's below) */
char Pupd; /* update flag (!0 = update mode) */
long Pcutoff; /* specified cutoff date-time */
struct Header Phdr; /* header from module */
int Plnno; /* line number of current line */
int Precno; /* record number of current rec */
char Pwrttn; /* written flag (!0 = written) */
char Pkeep; /* keep switch for readmod() */
struct Apply **Papply; /* ptr to apply array */
struct Queue *Pq; /* ptr to control queue */
struct Ibufr Pibuf; /* input buffer */
long Pcdt; /* date/time of newest applied delta */
char *Plfile; /* 0 = no l-file; else ptr to l arg */
char Punack; /* !0 if unacknowledged non-prop deltas */
char Pnoprop; /* !0 if new delta is to be non-prop */
int Pirel; /* rel which inserted current rec */
int Pilev; /* lev which inserted current rec */
};
/*
Masks for Pverbose
*/
# define RLACCESS (1)
# define NLINES (2)
# define DOLIST (4)
# define UNACK (8)
# define NEWRL (16)
# define WARNING (32)
/*
size of login name
*/
# define SZLNAM (7)
USXALLOC();
main(argc,argv)
char **argv;
{
register int i;
register char *p;
extern conv();
extern int Fcnt;
setsig();
Fflags = FTLMSG | FTLCLN | FTLJMP;
for (i = 1; i < argc; i++)
if (p = argv[i])
odo_file(p,conv);
exit(Fcnt ? 1 : 0);
}
struct packet npkt;
conv(ofile)
char *ofile;
{
struct Packet opkt;
struct deltab *dt;
char **hists;
int **rlp;
char statstr[32];
int ndels;
char *line;
register int n;
char *p;
if (setjmp(Fjmp))
return;
printf("%s:\n",ofile);
ckpfile(auxf(ofile,'p'));
zero(&opkt,sizeof(opkt));
opnr(&opkt.Pibuf,ofile);
dohead(&opkt);
rlp = 0;
ndels = doreltab(&opkt,&rlp);
hists = alloc((ndels + 1) * sizeof(*hists));
dt = alloc((ndels + 1) * sizeof(*dt));
dodelt(&opkt,dt,hists,ndels);
fixup(dt,ndels,rlp);
sinit(&npkt,ofile,0);
npkt.p_upd = 1;
line = npkt.p_line;
putline(&npkt,sprintf(line,"%c%c00000\n",CTLCHAR,HEAD),0);
statstr[0] = 0;
for (n = ndels; n; n--) {
if (!statstr[0])
newstats(&npkt,statstr,"?");
else
putline(&npkt,statstr);
putline(&npkt,del_ba(&dt[n],line));
putline(&npkt,sprintf(line,"%c%c %s\n",CTLCHAR,COMMENTS,
hists[n]));
putline(&npkt,sprintf(line,CTLSTR,CTLCHAR,EDELTAB));
}
putline(&npkt,sprintf(line,CTLSTR,CTLCHAR,BUSERNAM));
dousers(opkt.Phdr.Hulist,&npkt);
putline(&npkt,sprintf(line,CTLSTR,CTLCHAR,EUSERNAM));
if (*(p = opkt.Phdr.Htype))
putline(&npkt,sprintf(line,"%c%c %c %s\n",CTLCHAR,FLAG,
TYPEFLAG,p));
if (n = opkt.Phdr.Hfloor)
putline(&npkt,sprintf(line,"%c%c %c %d\n",CTLCHAR,FLAG,
FLORFLAG,n));
if (n = opkt.Phdr.Hceil)
putline(&npkt,sprintf(line,"%c%c %c %d\n",CTLCHAR,FLAG,
CEILFLAG,n));
if (n = opkt.Phdr.Hrdef)
putline(&npkt,sprintf(line,"%c%c %c %d\n",CTLCHAR,FLAG,
DEFTFLAG,n));
putline(&npkt,sprintf(line,CTLSTR,CTLCHAR,BUSERTXT));
if (*(p = opkt.Phdr.Hpers))
putline(&npkt,sprintf(line,"%s\n",p));
if (*(p = opkt.Phdr.Hdesc))
putline(&npkt,sprintf(line,"%s\n",p));
putline(&npkt,sprintf(line,CTLSTR,CTLCHAR,EUSERTXT));
dobod(&opkt,&npkt,rlp,line);
convflush(&npkt);
close(opkt.Pibuf.Ifildes);
for (n = ndels; n; n--)
free(hists[n]);
free(hists);
free(dt);
if (rlp) {
for (n = *rlp; n; n--)
if (rlp[n])
free(rlp[n]);
free(rlp);
}
rename(auxf(npkt.p_file,'x'),npkt.p_file);
xrm(&npkt);
}
getline()
{
}
clean_up()
{
xrm(&npkt);
}
fixup(dt,ndels,rlp)
struct deltab *dt;
int ndels;
int **rlp;
{
int m, n;
int maxr;
int seqcnt;
int pred;
register struct deltab *p1, *p2;
register int *brp;
for (m = ndels; m; m--) {
p1 = &dt[m];
if (p1->d_sid.s_lev > 1) {
for (n = m - 1; n; n--) {
if (p1->d_sid.s_rel == dt[n].d_sid.s_rel)
break;
}
pred = n;
}
else {
maxr = pred = 0;
for (n = m - 1; n; n--) {
p2 = &dt[n];
if (p1->d_sid.s_rel > p2->d_sid.s_rel &&
p2->d_type == 'D' &&
p2->d_sid.s_rel > maxr) {
maxr = p2->d_sid.s_rel;
pred = n;
}
}
}
p1->d_pred = pred;
rlp[p1->d_sid.s_rel][p1->d_sid.s_lev] = m;
}
brp = alloca(n = (ndels + 1) * sizeof(*brp));
zero(brp,n);
for (m = 1; m <= ndels; m++) {
p1 = &dt[m];
if (p1->d_type != 'D') {
seqcnt = 0;
p2 = &dt[p1->d_pred];
p1->d_type = 'D';
p1->d_sid.s_rel = p2->d_sid.s_rel;
p1->d_sid.s_lev = p2->d_sid.s_lev;
p1->d_sid.s_br = ++brp[p1->d_pred];
p1->d_sid.s_seq = ++seqcnt;
pred = m;
for (n = m + 1; n <= ndels; n++) {
if (dt[n].d_pred == pred) {
p2 = &dt[n];
p2->d_type = 'D';
p2->d_sid.s_rel = p1->d_sid.s_rel;
p2->d_sid.s_lev = p1->d_sid.s_lev;
p2->d_sid.s_br = p1->d_sid.s_br;
p2->d_sid.s_seq = ++seqcnt;
pred = n;
}
}
}
}
}
struct names {
struct names *n_next;
char n_name[SZLNAM];
int n_uid;
};
struct names *names;
dousers(up,pkt)
register char *up;
struct packet *pkt;
{
int i, j;
register char mask, c;
char *p;
char str[16];
for (i = 0; i < 32; i++)
if (c = *up++) {
j = 0;
for (mask = 1; mask; mask =<< 1) {
if ((c & mask) && (p = getlnam(i * 8 + j)))
putline(pkt,sprintf(str,"%s\n",p));
j++;
}
}
}
getlnam(uid)
int uid;
{
char str[128];
register struct names *cur, *prev;
register char *p;
for (cur = &names; cur = (prev = cur)->n_next; )
if (cur->n_uid == uid)
return(cur->n_name);
if (getpw(uid,str))
return(0);
prev->n_next = cur = alloc(sizeof(*cur));
cur->n_next = 0;
cur->n_uid = uid;
for (p = str; *p++ != ':'; )
;
*--p = 0;
str[SZLNAM] = 0;
copy(str,cur->n_name);
return(cur->n_name);
}
/*
Routine to process the module header. All that's necessary is
to slide it into the packet.
*/
dohead(pkt)
register struct Packet *pkt;
{
register struct Header *hdr;
if(rdrec(pkt) == 1) fatal("premature eof (58)");
hdr = pkt->Pibuf.Irecptr;
if(hdr->Hmagicno != MAGICNO) fatal("not an SCCS file (53)");
move(hdr,&pkt->Phdr,sizeof(*hdr));
}
doreltab(pkt,rlp)
register struct Packet *pkt;
register int ***rlp;
{
int n;
int sz;
register struct Reltab *rt;
n = 0;
while (rdrec(pkt) != 1 && (rt = pkt->Pibuf.Irecptr)->Rrel) {
if (n == 0) {
*rlp = alloc(sz = (rt->Rrel + 1) * sizeof(**rlp));
zero(*rlp,sz);
**rlp = rt->Rrel;
}
(*rlp)[rt->Rrel] = alloc((rt->Rlevs + 1) * sizeof(***rlp));
(*rlp)[rt->Rrel][0] = rt->Rlevs;
n =+ rt->Rlevs;
}
return(n);
}
dodelt(pkt,dt,hists,ndels)
struct Packet *pkt;
register struct deltab *dt;
char **hists;
int ndels;
{
int n;
register struct deltab *ndt;
register struct Deltab *odt;
for (; rdrec(pkt) != 1 && (odt = pkt->Pibuf.Irecptr)->Drel; --ndels) {
if (!(odt->Dtype == 'D' || odt->Dtype == 'P' || odt->Dtype == 'U')) {
++ndels;
continue;
}
if (!ndels)
return(fatal("internal error in dodeltab"));
ndt = &dt[ndels];
ndt->d_type = odt->Dtype;
move(odt->Dpgmr,ndt->d_pgmr,sizeof(ndt->d_pgmr));
ndt->d_datetime = odt->Ddatetime;
ndt->d_sid.s_rel = odt->Drel;
ndt->d_sid.s_lev = odt->Dlev;
ndt->d_sid.s_br = 0;
ndt->d_sid.s_seq = 0;
ndt->d_serial = ndels;
ndt->d_pred = 0;
n = size(odt->Dhist);
n++;
n =& ~1;
if (odt->Dtype == 'P' || odt->Dtype == 'U') {
hists[ndels] = alloc(n + 16);
sprintf(hists[ndels],"[was %d.%d] ",odt->Drel,odt->Dlev);
}
else {
hists[ndels] = alloc(n);
hists[ndels][0] = 0;
}
move(odt->Dhist,strend(hists[ndels]),n);
}
if (ndels) {
fatal("in dodelt");
}
}
dobod(opkt,npkt,rlp,line)
struct Packet *opkt;
struct packet *npkt;
int **rlp;
char *line;
{
register struct Control *octl;
register char *p, c;
while (rdrec(opkt) != 1 && (octl = opkt->Pibuf.Irecptr)->Crel) {
if (octlrec(octl,opkt->Pibuf.Ilen))
putline(npkt,sprintf(line,"%c%c %u\n",CTLCHAR,
"EDI"[octl->Cctl-OEND],
rlp[octl->Crel][octl->Clev]));
else {
c = (p = octl)[opkt->Pibuf.Ilen];
p[opkt->Pibuf.Ilen] = 0;
putline(npkt,sprintf(line,"%s\n",p));
p[opkt->Pibuf.Ilen] = c;
}
}
}
octlrec(ctl,len)
register struct Control *ctl;
int len;
{
register int ch;
if (len==SIZEOFCONTROL &&
((ch=ctl->Cctl)==OINS || ch==ODEL || ch==OEND))
return(1);
return(0);
}
rdrec(pkt)
register struct Packet *pkt;
{
register n;
if ((n = getr(&pkt->Pibuf)) != 1)
pkt->Precno++;
return(n);
}
xwrite(a,b,c)
{
return(write(a,b,c));
}
SCCSID(@(#)scv 1.8);
# define CALL(p,func,cnt) Ffile=p; (*func)(p); cnt++;
int nfiles;
char had_dir;
char had_standinp;
odo_file(p,func)
register char *p;
int (*func)();
{
extern char *Ffile;
char str[FILESIZE];
char ibuf[FILESIZE];
FILE *iop;
struct dir dir[2];
register char *s;
int fd;
if (p[0] == '-') {
had_standinp = 1;
while (gets(ibuf) != NULL) {
if (osccsfile(ibuf)) {
CALL(ibuf,func,nfiles);
}
}
}
else if (exists(p) && (Statbuf.i_mode & IFMT) == IFDIR) {
had_dir = 1;
Ffile = p;
if((iop = fopen(p,"r")) == NULL)
return;
dir[1].d_ino = 0;
fread(dir,sizeof(dir[0]),1,iop); /* skip "." */
fread(dir,sizeof(dir[0]),1,iop); /* skip ".." */
while(fread(dir,sizeof(dir[0]),1,iop) == 1) {
if(dir[0].d_ino == 0) continue;
sprintf(str,"%s/%s",p,dir[0].d_name);
if(osccsfile(str)) {
CALL(str,func,nfiles);
}
}
fclose(iop);
}
else {
CALL(p,func,nfiles);
}
}
osccsfile(file)
register char *file;
{
register int ff, result;
int magic[2];
result = (ff=open(file,0)) > 0
&& read(ff,magic,4) == 4
&& magic[1] == MAGICNO;
close(ff);
return(result);
}
/*
Routine to write out either the current line in the packet
(if newline is zero) or the line specified by newline.
A line is actually written (and the x-file is only
opened) if pkt->p_upd is non-zero. When the current line from
the packet is written, pkt->p_wrttn is set non-zero, and
further attempts to write it are ignored. When a line is
read into the packet, pkt->p_wrttn must be turned off.
*/
int Xcreate;
FILE *Xiop;
putline(pkt,newline)
register struct packet *pkt;
char *newline;
{
static char obf[BUFSIZ];
char *xf;
register char *p;
if(pkt->p_upd == 0) return;
if(!Xcreate) {
stat(pkt->p_file,&Statbuf);
xf = auxf(pkt->p_file,'x');
Xiop = xfcreat(xf,Statbuf.i_mode);
setbuf(Xiop,obf);
chown(xf,(Statbuf.i_gid<<8)|Statbuf.i_uid);
}
if (newline)
p = newline;
else {
if(!pkt->p_wrttn++)
p = pkt->p_line;
else
p = 0;
}
if (p) {
fputs(p,Xiop);
if (Xcreate)
while (*p)
pkt->p_nhash =+ *p++;
}
Xcreate = 1;
}
convflush(pkt)
register struct packet *pkt;
{
register char *p;
char hash[6];
if (pkt->p_upd == 0)
return;
putline(pkt,0);
rewind(Xiop);
sprintf(hash,"%5u",pkt->p_nhash);
zeropad(hash);
fprintf(Xiop,"%c%c%s\n",CTLCHAR,HEAD,hash);
fclose(Xiop);
}
xrm(pkt)
struct packet *pkt;
{
if (Xiop)
fclose(Xiop);
if(Xcreate)
unlink(auxf(pkt,'x'));
Xiop = Xcreate = 0;
}
char bpf[] "bad p-file (216)";
rdpfile(f,rp,un)
char f[], un[];
int *rp;
{
register int fd, i;
register char *p;
char s[65], *name;
fd = xopen(f,0);
if ((i=read(fd,s,64))<=0)
fatal(bpf);
close(fd);
p = s;
p[i] = 0;
for (; *p != ' '; p++)
if (*p == 0)
fatal(bpf);
*p = 0;
if ((*rp=patoi(s)) == -1)
fatal(bpf);
++p;
while (*p++ == ' ') ;
name = --p;
for (; *p != '\n'; p++)
if (*p == 0)
fatal(bpf);
*p = 0;
if ((p-name)>SZLNAM)
fatal(bpf);
copy(name,un);
}
ckpfile(file)
register char *file;
{
int r;
char un[SZLNAM];
if(exists(file)) {
rdpfile(file,&r,un);
fatal(sprintf(Error,"being edited at release %d by `%s' (scv1)",
r,un));
}
}
/*
Bottom level read routines for release 3 SCCS files.
Usage:
struct Ibufr ib;
...
opnr(&ib,"filename");
...
if(getr(&ib) == 1) [end-of-file];
[ib.Irecptr is addr of record (always on word boundary)]
[ib.Ilen is length]
Address HASHADDR of the file must contain a 1-word stored hash count.
If this count is non-zero, then on end-of-file a computed hash count
is compared with it and a fatal error is issued if they aren't equal.
*/
opnr(buf,file)
register struct Ibufr *buf;
char file[];
{
buf->Ifildes = xopen(file,0);
buf->Irecptr = buf->Ibuff2 + 2;
buf->Iend = buf->Irecptr + 510;
buf->Ilen = 510;
buf->Ibuff3[1] = -128;
buf->Ihcnt = buf->Ihtot = buf->Ihflag = 0;
}
getr(buf)
register struct Ibufr *buf;
{
register char *p, *q;
int *w;
int i, n;
buf->Irecptr =+ buf->Ilen + !(buf->Ilen & 1);
i = 0;
while(1) {
buf->Ilen = 0;
buf->Ilen = *buf->Irecptr + 128;
if(buf->Irecptr <= buf->Iend - (buf->Ilen+!(buf->Ilen&1)))
return(++buf->Irecptr);
if(i++ == 1) return(1);
q = buf->Irecptr;
p = buf->Irecptr =- 512;
while(q <= buf->Iend) *p++ = *q++;
if((n = read(buf->Ifildes,buf->Ibuff2,512)) <= 0)
return(1);
buf->Iend = buf->Ibuff2 + n - 1;
*(buf->Iend + 1) = -128;
w = buf->Ibuff2;
if(buf->Ihflag == 0) {
buf->Ihflag = 1;
buf->Ihtot = w[HASHADDR>>1];
w[HASHADDR>>1] = 0;
}
if(n < 512) buf->Ibuff2[n] = 0;
buf->Ihcnt =+ sumr(w,&w[(n&1?n-1:n-2)>>1]);
if(n<512 && buf->Ihtot && buf->Ihcnt != buf->Ihtot)
fatal("corrupted file (201)");
}
}
sumr(from,to)
register int *from, *to;
{
register int sum;
for (sum=0; from<=to; )
sum =+ *from++;
return(sum);
}