1 #
2 /*
3 	Program to convert release 3 (or release 2 or even 1) SCCS files
4 	to release 4 SCCS files.
5 	Usage:
6 		scv arg ...
7 	arg is any argument acceptable as an SCCS file
8 	name argument to the get command. E.g.:
9 		scv mysccsdir
10 	will convert every release 3 (or 2 or 1 but NOT 4) SCCS file in the
11 	directory "mysccsdir".
12 */
13 # include	"../hdr/defines.h"
14 # include	"dir.h"
15 
16 SCCSID(@(#)scv.c	4.7);
17 
18 
19 /*
20 	Release 3 SCCS File Structures  (2.1  78/06/05 17:31:17)
21 	See osccsfile(V).
22 */
23 
24 struct Header {
25 	short  Hmagicno;
26 	char Htype[10];
27 	char Hpers[14];
28 	char Hdesc[100];
29 	short  Hfloor;
30 	short  Hceil;
31 	short  Hsw[5];
32 	short  Hrdef;
33 	char Hulist[32];
34 	char Hexpand[50];
35 	short  Hash;
36 };
37 #define MAGICNO (7)
38 #define HASHADDR (226)
39 
40 
41 struct Reltab {
42 	short  Rrel;
43 	short  Rlevs;
44 };
45 
46 
47 struct Deltab {
48 	short  Drel;
49 	short  Dlev;
50 	char Dtype;	/*'D': delta,'P','U': non-prop,'I': incl,'E': excl */
51 	char Dfill;	/* Used to be option letter */
52 /* compiler once forced unfortunate alignment here.
53 /* also, fp-11c high/low long goof strikes again.
54 /*	long  Ddatetime;
55 */
56 	short Ddthi,Ddtlo;
57 	char Dpgmr[SZLNAM];
58 	char Dhist[200];
59 };
60 
61 
62 struct Control {
63 	short  Crel;
64 	short  Clev;
65 	char Cctl;	/* -11: ins, -12: del, -13: end */
66 };
67 #define SIZEOFCONTROL (5)
68 #define OINS (-11)
69 #define ODEL (-12)
70 #define OEND (-13)
71 
72 
73 struct Line {
74 	char Lline [256];
75 };
76 
77 
78 /*
79 	Structure for use with buffered I/O routines opnl, opnr,
80 	getl and getr.
81 */
82 struct Ibufr {
83 	short  Ifildes;
84 	char *Irecptr;
85 	char *Iend;
86 	char Ibuff1[256];
87 	char Ibuff2[512];
88 	char Ibuff3[2];
89 	short  Ilen;
90 	short  Ihflag;
91 	short  Ihcnt;
92 	short  Ihtot;
93 };
94 
95 
96 /*
97 	Structure for use with buffered I/O routines crtr, crtl, putl,
98 	putr, flshr and buflsh.
99 */
100 struct Obufr {
101 	short  Ofildes;
102 	char *Orecptr;
103 	char *Oend;
104 	char Obuff1[512];
105 	short  Ohflag;
106 	short  Ohcnt;
107 };
108 
109 
110 /*
111  * structure to access an
112  * shorteger in bytes
113  */
114 struct
115 {
116 	char	lobyte;
117 	char	hibyte;
118 };
119 
120 
121 /*
122  * structure to access an shorteger
123  */
124 struct
125 {
126 	short	shorteg;
127 };
128 
129 
130 /*
131  * structure to access a long as shortegers
132  */
133 struct {
134 	short	hiword;
135 	short	loword;
136 };
137 
138 
139 /*
140 	Structure for referencing pieces of localtime().
141 */
142 struct Time {
143 	short	Tseconds;
144 	short	Tminutes;
145 	short	Thours;
146 	short	Tday_month;
147 	short	Tmonth;
148 	short	Tyear;
149 	short	Tday_week;
150 	short	Tday_year;
151 	short	Tflag;
152 };
153 /*
154 	SCCS Internal Structures (used by get and delta).     (2.1)
155 */
156 
157 struct Apply {
158 	short    Adt;		/* pseudo date-time */
159 	short    Acode;		/* APPLY, NOAPPLY or EMPTY */
160 };
161 #define APPLY	  (1)
162 #define NOAPPLY  (-1)
163 #define EMPTY	  (0)
164 
165 
166 struct Queue {
167 	struct Queue *Qnext;
168 	short    Qrel;		/* release */
169 	short    Qlev;		/* level */
170 	short    Qdt;		/* pseudo date-time */
171 	short    Qkeep;		/* keep switch setting */
172 };
173 #define YES	 (1)
174 #define NO	(-1)
175 
176 #define SIZEOFPfile (50)
177 
178 
179 struct Packet {
180 	char	Pfile[SIZEOFPfile];	/* file name containing module */
181 /*
182 			Note: the order of the next two words
183 				can not___ be changed!
184 			This is because the release and level together
185 			are treated as a long.
186 */
187 	short	Prel;		/* specified release (-1 = not spec.) */
188 	short	Plev;		/* specified level (-1 = not spec.)*/
189 	char	Pverbose;	/* verbose flags (see #define's below) */
190 	char	Pupd;		/* update flag (!0 = update mode) */
191 	long    Pcutoff;	/* specified cutoff date-time */
192 	struct	Header	Phdr;	/* header from module */
193 	short	Plnno;		/* line number of current line */
194 	short	Precno;		/* record number of current rec */
195 	char	Pwrttn;		/* written flag (!0 = written) */
196 	char	Pkeep;		/* keep switch for readmod() */
197 	struct	Apply **Papply;	/* ptr to apply array */
198 	struct	Queue *Pq;	/* ptr to control queue */
199 	struct	Ibufr Pibuf;	/* input buffer */
200 	long	Pcdt;		/* date/time of newest applied delta */
201 	char	*Plfile;	/* 0 = no l-file; else ptr to l arg */
202 	char	Punack;		/* !0 if unacknowledged non-prop deltas */
203 	char	Pnoprop;	/* !0 if new delta is to be non-prop */
204 	short	Pirel;		/* rel which inserted current rec */
205 	short	Pilev;		/* lev which inserted current rec */
206 };
207 /*
208 	Masks for Pverbose
209 */
210 
211 # define RLACCESS	(1)
212 # define NLINES		(2)
213 # define DOLIST		(4)
214 # define UNACK		(8)
215 # define NEWRL		(16)
216 # define WARNING	(32)
217 
218 /*
219 	size of login name
220 */
221 
222 
223 USXALLOC();
224 
225 main(argc,argv)
226 char **argv;
227 {
228 	register short i;
229 	register char *p;
230 	extern conv();
231 	extern short Fcnt;
232 
233 	setsig();
234 	Fflags = FTLMSG | FTLCLN | FTLJMP;
235 	for (i = 1; i < argc; i++)
236 		if (p = argv[i])
237 			odo_file(p,conv);
238 	exit(Fcnt ? 1 : 0);
239 }
240 
241 
242 struct packet npkt;
243 
244 conv(ofile)
245 char *ofile;
246 {
247 	struct Packet opkt;
248 	struct deltab *dt;
249 	char **hists;
250 	short **rlp;
251 	char statstr[32];
252 	short ndels;
253 	char *line;
254 	short n;
255 	char *p;
256 
257 	if (setjmp(Fjmp))
258 		return;
259 	printf("%s:\n",ofile);
260 	ckpfile(auxf(ofile,'p'));
261 	bzero(&opkt,sizeof(opkt));
262 	opnr(&opkt.Pibuf,ofile);
263 	dohead(&opkt);
264 	rlp = 0;
265 	ndels = doreltab(&opkt,&rlp);
266 	hists = alloc((ndels + 1) * sizeof(*hists));
267 	dt = alloc((ndels + 1) * sizeof(*dt));
268 	dodelt(&opkt,dt,hists,ndels);
269 	fixup(dt,ndels,rlp);
270 	sinit(&npkt,ofile,0);
271 	npkt.p_upd = 1;
272 	line = npkt.p_line;
273 	sprintf(line,"%c%c00000\n",CTLCHAR,HEAD);
274 	putline(&npkt,line);
275 	statstr[0] = 0;
276 	for (n = ndels; n; n--) {
277 		if (!statstr[0])
278 			newstats(&npkt,statstr,"?");
279 		else
280 			putline(&npkt,statstr);
281 		putline(&npkt,del_ba(&dt[n],line));
282 		sprintf(line,"%c%c %s\n",CTLCHAR,COMMENTS,hists[n]);
283 		putline(&npkt,line);
284 		sprintf(line,CTLSTR,CTLCHAR,EDELTAB);
285 		putline(&npkt,line);
286 	}
287 	sprintf(line,CTLSTR,CTLCHAR,BUSERNAM);
288 	putline(&npkt,line);
289 	dousers(opkt.Phdr.Hulist,&npkt);
290 	sprintf(line,CTLSTR,CTLCHAR,EUSERNAM);
291 	putline(&npkt,line);
292 	if (*(p = opkt.Phdr.Htype)) {
293 		sprintf(line,"%c%c %c %s\n",CTLCHAR,FLAG,TYPEFLAG,p);
294 		putline(&npkt,line);
295 	}
296 	if (n = opkt.Phdr.Hfloor) {
297 		sprintf(line,"%c%c %c %d\n",CTLCHAR,FLAG,FLORFLAG,n);
298 		putline(&npkt,line);
299 	}
300 	if (n = opkt.Phdr.Hceil) {
301 		sprintf(line,"%c%c %c %d\n",CTLCHAR,FLAG,CEILFLAG,n);
302 		putline(&npkt,line);
303 	}
304 	if (n = opkt.Phdr.Hrdef) {
305 		sprintf(line,"%c%c %c %d\n",CTLCHAR,FLAG,DEFTFLAG,n);
306 		putline(&npkt,line);
307 	}
308 	sprintf(line,CTLSTR,CTLCHAR,BUSERTXT);
309 	putline(&npkt,line);
310 	if (*(p = opkt.Phdr.Hpers)) {
311 		sprintf(line,"%s\n",p);
312 		putline(&npkt,line);
313 	}
314 	if (*(p = opkt.Phdr.Hdesc)) {
315 		sprintf(line,"%s\n",p);
316 		putline(&npkt,line);
317 	}
318 	sprintf(line,CTLSTR,CTLCHAR,EUSERTXT);
319 	putline(&npkt,line);
320 	dobod(&opkt,&npkt,rlp,line);
321 	convflush(&npkt);
322 	close(opkt.Pibuf.Ifildes);
323 	for (n = ndels; n; n--)
324 		free(hists[n]);
325 	free(hists);
326 	free(dt);
327 /* [compiler bug, ignore this for now ]
328 	if (rlp) {
329 		for (n = (short) (*rlp); n; n--)
330 			if (rlp[n])
331 				free(rlp[n]);
332 		free(rlp);
333 	}
334 */
335 	rename(auxf(npkt.p_file,'x'),npkt.p_file);
336 	xrm(&npkt);
337 }
338 
339 
340 getline()
341 {
342 }
343 
344 
345 clean_up()
346 {
347 	xrm(&npkt);
348 }
349 
350 
351 
352 fixup(dt,ndels,rlp)
353 struct deltab *dt;
354 short ndels;
355 short **rlp;
356 {
357 	short m, n;
358 	short maxr;
359 	short seqcnt;
360 	short pred;
361 	register struct deltab *p1, *p2;
362 	register short *brp;
363 
364 	for (m = ndels; m; m--) {
365 		p1 = &dt[m];
366 		if (p1->d_sid.s_lev > 1) {
367 			for (n = m - 1; n; n--) {
368 				if (p1->d_sid.s_rel == dt[n].d_sid.s_rel)
369 					break;
370 			}
371 			pred = n;
372 		}
373 		else {
374 			maxr = pred = 0;
375 			for (n = m - 1; n; n--) {
376 				p2 = &dt[n];
377 				if (p1->d_sid.s_rel > p2->d_sid.s_rel &&
378 					p2->d_type == 'D' &&
379 					p2->d_sid.s_rel > maxr) {
380 						maxr = p2->d_sid.s_rel;
381 						pred = n;
382 				}
383 			}
384 		}
385 		p1->d_pred = pred;
386 		rlp[p1->d_sid.s_rel][p1->d_sid.s_lev] = m;
387 	}
388 	brp = alloca(n = (ndels + 1) * sizeof(*brp));
389 	bzero(brp,n);
390 	for (m = 1; m <= ndels; m++) {
391 		p1 = &dt[m];
392 		if (p1->d_type != 'D') {
393 			seqcnt = 0;
394 			p2 = &dt[p1->d_pred];
395 			p1->d_type = 'D';
396 			p1->d_sid.s_rel = p2->d_sid.s_rel;
397 			p1->d_sid.s_lev = p2->d_sid.s_lev;
398 			p1->d_sid.s_br = ++brp[p1->d_pred];
399 			p1->d_sid.s_seq = ++seqcnt;
400 			pred = m;
401 			for (n = m + 1; n <= ndels; n++) {
402 				if (dt[n].d_pred == pred) {
403 					p2 = &dt[n];
404 					p2->d_type = 'D';
405 					p2->d_sid.s_rel = p1->d_sid.s_rel;
406 					p2->d_sid.s_lev = p1->d_sid.s_lev;
407 					p2->d_sid.s_br = p1->d_sid.s_br;
408 					p2->d_sid.s_seq = ++seqcnt;
409 					pred = n;
410 				}
411 			}
412 		}
413 	}
414 }
415 
416 
417 
418 struct	names {
419 	struct	names	*n_next;
420 	char	n_name[SZLNAM];
421 	short	n_uid;
422 };
423 
424 struct names *names;
425 
426 dousers(up,pkt)
427 register char *up;
428 struct packet *pkt;
429 {
430 	short i, j;
431 	register char mask, c;
432 	char *p;
433 	char str[16];
434 
435 	for (i = 0; i < 32; i++)
436 		if (c = *up++) {
437 			j = 0;
438 			for (mask = 1; mask; mask <<= 1) {
439 				if ((c & mask) && (p = getlnam(i * SZLNAM + j))) {
440 					sprintf(str,"%s\n",p);
441 					putline(pkt,str);
442 				}
443 				j++;
444 			}
445 		}
446 }
447 
448 
449 getlnam(uid)
450 short uid;
451 {
452 	char str[128];
453 	register struct names *cur, *prev;
454 	register char *p;
455 
456 	for (cur = &names; cur = (prev = cur)->n_next; )
457 		if (cur->n_uid == uid)
458 			return(cur->n_name);
459 	if (getpw(uid,str))
460 		return(0);
461 	prev->n_next = cur = alloc(sizeof(*cur));
462 	cur->n_next = 0;
463 	cur->n_uid = uid;
464 	for (p = str; *p++ != ':'; )
465 		;
466 	*--p = 0;
467 	str[SZLNAM] = 0;
468 	copy(str,cur->n_name);
469 	return(cur->n_name);
470 }
471 
472 
473 
474 /*
475 	Routine to process the module header. All that's necessary is
476 	to slide it shorto the packet.
477 */
478 
479 dohead(pkt)
480 register struct Packet *pkt;
481 {
482 	register struct Header *hdr;
483 
484 	if(rdrec(pkt) == 1) fatal("premature eof (58)");
485 	hdr = pkt->Pibuf.Irecptr;
486 	if(hdr->Hmagicno != MAGICNO) fatal("not an SCCS file (53)");
487 	bcopy(hdr,&pkt->Phdr,sizeof(*hdr));
488 }
489 
490 
491 doreltab(pkt,rlp)
492 register struct Packet *pkt;
493 register short ***rlp;
494 {
495 	short n;
496 	short sz;
497 	register struct Reltab *rt;
498 
499 	n = 0;
500 	while (rdrec(pkt) != 1 && (rt = pkt->Pibuf.Irecptr)->Rrel) {
501 		if (n == 0) {
502 			*rlp = alloc(sz = (rt->Rrel + 1) * sizeof(**rlp));
503 			bzero(*rlp,sz);
504 			**rlp = rt->Rrel;
505 		}
506 		(*rlp)[rt->Rrel] = alloc((rt->Rlevs + 1) * sizeof(***rlp));
507 		(*rlp)[rt->Rrel][0] = rt->Rlevs;
508 		n += rt->Rlevs;
509 	}
510 	return(n);
511 }
512 
513 
514 dodelt(pkt,dt,hists,ndels)
515 struct Packet *pkt;
516 register struct deltab *dt;
517 char **hists;
518 short ndels;
519 {
520 	short n;
521 	register struct deltab *ndt;
522 	register struct Deltab *odt;
523 
524 	for (; rdrec(pkt) != 1 && (odt = pkt->Pibuf.Irecptr)->Drel; --ndels) {
525 		if (!(odt->Dtype == 'D' || odt->Dtype == 'P' || odt->Dtype == 'U')) {
526 			++ndels;
527 			continue;
528 		}
529 		if (!ndels)
530 			return(fatal("internal error in dodeltab"));
531 		ndt = &dt[ndels];
532 		ndt->d_type = odt->Dtype;
533 		bcopy(odt->Dpgmr,ndt->d_pgmr,sizeof(ndt->d_pgmr));
534 		ndt->d_datetime = (odt->Ddthi<<16)+(unsigned)odt->Ddtlo;
535 		ndt->d_sid.s_rel = odt->Drel;
536 		ndt->d_sid.s_lev = odt->Dlev;
537 		ndt->d_sid.s_br = 0;
538 		ndt->d_sid.s_seq = 0;
539 		ndt->d_serial = ndels;
540 		ndt->d_pred = 0;
541 		n = size(odt->Dhist);
542 		n++;
543 		n &= ~1;
544 		if (odt->Dtype == 'P' || odt->Dtype == 'U') {
545 			hists[ndels] = alloc(n + 16);
546 			sprintf(hists[ndels],"[was %d.%d] ",odt->Drel,odt->Dlev);
547 		}
548 		else {
549 			hists[ndels] = alloc(n);
550 			hists[ndels][0] = 0;
551 		}
552 		bcopy(odt->Dhist,index(hists[ndels], '\0'),n);
553 	}
554 	if (ndels) {
555 		fatal("in dodelt");
556 	}
557 }
558 
559 
560 dobod(opkt,npkt,rlp,line)
561 struct Packet *opkt;
562 struct packet *npkt;
563 short **rlp;
564 char *line;
565 {
566 	register struct Control *octl;
567 	register char *p, c;
568 
569 	while (rdrec(opkt) != 1 && (octl = opkt->Pibuf.Irecptr)->Crel) {
570 		if (octlrec(octl,opkt->Pibuf.Ilen)) {
571 			sprintf(line,"%c%c %u\n",CTLCHAR,"EDI"[octl->Cctl-OEND],rlp[octl->Crel][octl->Clev]);
572 			putline(npkt,line);
573 		}
574 		else {
575 			c = (p = octl)[opkt->Pibuf.Ilen];
576 			p[opkt->Pibuf.Ilen] = 0;
577 			sprintf(line,"%s\n",p);
578 			putline(npkt,line);
579 			p[opkt->Pibuf.Ilen] = c;
580 		}
581 	}
582 }
583 
584 
585 octlrec(ctl,len)
586 register struct Control *ctl;
587 short len;
588 {
589 	register short ch;
590 
591 	if (len==SIZEOFCONTROL &&
592 		((ch=ctl->Cctl)==OINS || ch==ODEL || ch==OEND))
593 			return(1);
594 	return(0);
595 }
596 
597 
598 rdrec(pkt)
599 register struct Packet *pkt;
600 {
601 	register n;
602 
603 	if ((n = getr(&pkt->Pibuf)) != 1)
604 		pkt->Precno++;
605 	return(n);
606 }
607 
608 
609 xwrite(a,b,c)
610 {
611 	return(write(a,b,c));
612 }
613 
614 
615 
616 
617 # define CALL(p,func,cnt)	Ffile=p; (*func)(p); cnt++;
618 short	nfiles;
619 char	had_dir;
620 char	had_standinp;
621 
622 
623 odo_file(p,func)
624 register char *p;
625 short (*func)();
626 {
627 	extern char *Ffile;
628 	char str[FILESIZE];
629 	char ibuf[FILESIZE];
630 	FILE *iop;
631 	struct dir dir[2];
632 	register char *s;
633 	short fd;
634 
635 	if (p[0] == '-') {
636 		had_standinp = 1;
637 		while (gets(ibuf) != NULL) {
638 			if (osccsfile(ibuf)) {
639 				CALL(ibuf,func,nfiles);
640 			}
641 		}
642 	}
643 	else if (exists(p) && (Statbuf.st_mode & S_IFMT) == S_IFDIR) {
644 		had_dir = 1;
645 		Ffile = p;
646 		if((iop = fopen(p,"r")) == NULL)
647 			return;
648 		dir[1].d_ino = 0;
649 		fread(dir,sizeof(dir[0]),1,iop);   /* skip "."  */
650 		fread(dir,sizeof(dir[0]),1,iop);   /* skip ".."  */
651 		while(fread(dir,sizeof(dir[0]),1,iop) == 1) {
652 			if(dir[0].d_ino == 0) continue;
653 			sprintf(str,"%s/%s",p,dir[0].d_name);
654 			if(osccsfile(str)) {
655 				CALL(str,func,nfiles);
656 			}
657 		}
658 		fclose(iop);
659 	}
660 	else {
661 		CALL(p,func,nfiles);
662 	}
663 }
664 
665 
666 osccsfile(file)
667 register char *file;
668 {
669 	register short ff, result;
670 	short magic[2];
671 
672 	result = (ff=open(file,0)) > 0
673 	  && read(ff,magic,4) == 4
674 	  && magic[1] == MAGICNO;
675 	close(ff);
676 	return(result);
677 }
678 
679 
680 
681 /*
682 	Routine to write out either the current line in the packet
683 	(if newline is zero) or the line specified by newline.
684 	A line is actually written (and the x-file is only
685 	opened) if pkt->p_upd is non-zero.  When the current line from
686 	the packet is written, pkt->p_wrttn is set non-zero, and
687 	further attempts to write it are ignored.  When a line is
688 	read shorto the packet, pkt->p_wrttn must be turned off.
689 */
690 
691 short	Xcreate;
692 FILE	*Xiop;
693 
694 
695 putline(pkt,newline)
696 register struct packet *pkt;
697 char *newline;
698 {
699 	static char obf[BUFSIZ];
700 	char *xf;
701 	register char *p;
702 
703 	if(pkt->p_upd == 0) return;
704 
705 	if(!Xcreate) {
706 		stat(pkt->p_file,&Statbuf);
707 		xf = auxf(pkt->p_file,'x');
708 		Xiop = xfcreat(xf,Statbuf.st_mode);
709 		setbuf(Xiop,obf);
710 		chown(xf,(Statbuf.st_gid<<8)|Statbuf.st_uid);
711 	}
712 	if (newline)
713 		p = newline;
714 	else {
715 		if(!pkt->p_wrttn++)
716 			p = pkt->p_line;
717 		else
718 			p = 0;
719 	}
720 	if (p) {
721 		fputs(p,Xiop);
722 		if (Xcreate)
723 			while (*p)
724 				pkt->p_nhash += *p++;
725 	}
726 	Xcreate = 1;
727 }
728 
729 
730 convflush(pkt)
731 register struct packet *pkt;
732 {
733 	register char *p;
734 	char hash[6];
735 
736 	if (pkt->p_upd == 0)
737 		return;
738 	putline(pkt,0);
739 	rewind(Xiop);
740 	sprintf(hash,"%5u",pkt->p_nhash&0xFFFF);
741 	zeropad(hash);
742 	fprintf(Xiop,"%c%c%s\n",CTLCHAR,HEAD,hash);
743 	fclose(Xiop);
744 }
745 
746 
747 xrm(pkt)
748 struct packet *pkt;
749 {
750 	if (Xiop)
751 		fclose(Xiop);
752 	if(Xcreate)
753 		unlink(auxf(pkt,'x'));
754 	Xiop = Xcreate = 0;
755 }
756 
757 
758 char bpf[] "bad p-file (216)";
759 
760 rdpfile(f,rp,un)
761 char f[], un[];
762 short *rp;
763 {
764 	register short fd, i;
765 	register char *p;
766 	char s[65], *name;
767 
768 	fd = xopen(f,0);
769 	if ((i=read(fd,s,64))<=0)
770 		fatal(bpf);
771 	close(fd);
772 	p = s;
773 	p[i] = 0;
774 	for (; *p != ' '; p++)
775 		if (*p == 0)
776 			fatal(bpf);
777 	*p = 0;
778 	if ((*rp=patoi(s)) == -1)
779 		fatal(bpf);
780 	++p;
781 	while (*p++ == ' ') ;
782 	name = --p;
783 	for (; *p != '\n'; p++)
784 		if (*p == 0)
785 			fatal(bpf);
786 	*p = 0;
787 	if ((p-name)>SZLNAM)
788 		fatal(bpf);
789 	copy(name,un);
790 }
791 
792 
793 ckpfile(file)
794 register char *file;
795 {
796 	short r;
797 	char un[SZLNAM];
798 
799 	if(exists(file)) {
800 		rdpfile(file,&r,un);
801 		sprintf(Error,"being edited at release %d by `%s' (scv1)",r,un));
802 		fatal(Error);
803 	}
804 }
805 
806 
807 /*
808 	Bottom level read routines for release 3 SCCS files.
809 
810 	Usage:
811 		struct Ibufr ib;
812 		...
813 		opnr(&ib,"filename");
814 		...
815 		if(getr(&ib) == 1) [end-of-file];
816 		[ib.Irecptr is addr of record (always on word boundary)]
817 		[ib.Ilen is length]
818 
819 	Address HASHADDR of the file must contain a 1-word stored hash count.
820 	If this count is non-zero, then on end-of-file a computed hash count
821 	is compared with it and a fatal error is issued if they aren't equal.
822 */
823 
824 opnr(buf,file)
825 register struct Ibufr *buf;
826 char file[];
827 {
828 	buf->Ifildes = xopen(file,0);
829 	buf->Irecptr = buf->Ibuff2 + 2;
830 	buf->Iend = buf->Irecptr + 510;
831 	buf->Ilen = 510;
832 	buf->Ibuff3[1] = -128;
833 	buf->Ihcnt = buf->Ihtot = buf->Ihflag = 0;
834 }
835 
836 
837 getr(buf)
838 register struct Ibufr *buf;
839 {
840 	register char *p, *q;
841 	short *w;
842 	short i, n;
843 
844 	buf->Irecptr += buf->Ilen + !(buf->Ilen & 1);
845 
846 	i = 0;
847 	while(1) {
848 		buf->Ilen = 0;
849 		buf->Ilen = *buf->Irecptr + 128;
850 
851 		if(buf->Irecptr <= buf->Iend - (buf->Ilen+!(buf->Ilen&1)))
852 			return(++buf->Irecptr);
853 
854 		if(i++ == 1) return(1);
855 
856 		q = buf->Irecptr;
857 		p = buf->Irecptr -= 512;
858 
859 		while(q <= buf->Iend) *p++ = *q++;
860 
861 		if((n = read(buf->Ifildes,buf->Ibuff2,512)) <= 0)
862 			return(1);
863 
864 		buf->Iend = buf->Ibuff2 + n - 1;
865 		*(buf->Iend + 1) = -128;
866 
867 		w = buf->Ibuff2;
868 		if(buf->Ihflag == 0) {
869 			buf->Ihflag = 1;
870 			buf->Ihtot = w[HASHADDR>>1];
871 			w[HASHADDR>>1] = 0;
872 		}
873 		if(n < 512) buf->Ibuff2[n] = 0;
874 
875 		buf->Ihcnt += sumr(w,&w[(n&1?n-1:n-2)>>1]);
876 
877 		if(n<512 && buf->Ihtot && buf->Ihcnt != buf->Ihtot)
878 			fatal("corrupted file (201)");
879 	}
880 }
881 
882 
883 sumr(from,to)
884 register short *from, *to;
885 {
886 	register short sum;
887 
888 	for (sum=0; from<=to; )
889 		sum += *from++;
890 	return(sum);
891 }
892