xref: /original-bsd/usr.bin/sccs/sccs.c (revision 2444cd3e)
1adf8f7d4Seric # include <stdio.h>
2adf8f7d4Seric # include <sys/types.h>
3adf8f7d4Seric # include <sys/stat.h>
4b2538d76Seric # include <sys/dir.h>
5adf8f7d4Seric # include <sysexits.h>
6b5d4f080Seric # include <whoami.h>
7adf8f7d4Seric 
8*2444cd3eSeric static char SccsId[] = "@(#)sccs.c	1.19 07/28/80";
9c4432be4Seric 
10c4432be4Seric # define bitset(bit, word)	((bit) & (word))
11c4432be4Seric 
12c4432be4Seric typedef char	bool;
137de81dc7Seric # define TRUE	1
147de81dc7Seric # define FALSE	0
15d02a4f42Seric 
16adf8f7d4Seric struct sccsprog
17adf8f7d4Seric {
18adf8f7d4Seric 	char	*sccsname;	/* name of SCCS routine */
197de81dc7Seric 	short	sccsoper;	/* opcode, see below */
207de81dc7Seric 	short	sccsflags;	/* flags, see below */
21adf8f7d4Seric 	char	*sccspath;	/* pathname of binary implementing */
22adf8f7d4Seric };
23adf8f7d4Seric 
247de81dc7Seric /* values for sccsoper */
257de81dc7Seric # define PROG		0	/* call a program */
261777fbcbSeric # define CMACRO		1	/* command substitution macro */
27172147faSeric # define FIX		2	/* fix a delta */
28b2538d76Seric # define CLEAN		3	/* clean out recreatable files */
29e39a5722Seric # define UNEDIT		4	/* unedit a file */
307de81dc7Seric 
31c4432be4Seric /* bits for sccsflags */
327de81dc7Seric # define NO_SDOT	0001	/* no s. on front of args */
337de81dc7Seric # define REALUSER	0002	/* protected (e.g., admin) */
34adf8f7d4Seric 
35b5d4f080Seric # ifdef CSVAX
36b5d4f080Seric # define PROGPATH(name)	"/usr/local/name"
37b5d4f080Seric # endif CSVAX
38b5d4f080Seric 
39b5d4f080Seric # ifndef PROGPATH
40b5d4f080Seric # define PROGPATH(name)	"/usr/sccs/name"
41b5d4f080Seric # endif PROGPATH
42b5d4f080Seric 
43adf8f7d4Seric struct sccsprog SccsProg[] =
44adf8f7d4Seric {
45b5d4f080Seric 	"admin",	PROG,	REALUSER,		PROGPATH(admin),
46b5d4f080Seric 	"chghist",	PROG,	0,			PROGPATH(rmdel),
47b5d4f080Seric 	"comb",		PROG,	0,			PROGPATH(comb),
48b5d4f080Seric 	"delta",	PROG,	0,			PROGPATH(delta),
49b5d4f080Seric 	"get",		PROG,	0,			PROGPATH(get),
50b5d4f080Seric 	"help",		PROG,	NO_SDOT,		PROGPATH(help),
51b5d4f080Seric 	"prt",		PROG,	0,			PROGPATH(prt),
52b5d4f080Seric 	"rmdel",	PROG,	REALUSER,		PROGPATH(rmdel),
53b5d4f080Seric 	"what",		PROG,	NO_SDOT,		PROGPATH(what),
54f0cc3246Seric 	"edit",		CMACRO,	0,			"get -e",
55f0cc3246Seric 	"delget",	CMACRO,	0,			"delta/get",
56d7e8b658Seric 	"deledit",	CMACRO,	0,			"delta/get -e",
571777fbcbSeric 	"del",		CMACRO,	0,			"delta/get",
58172147faSeric 	"delt",		CMACRO,	0,			"delta/get",
59172147faSeric 	"fix",		FIX,	0,			NULL,
603a208c77Seric 	"clean",	CLEAN,	REALUSER,		(char *) TRUE,
613a208c77Seric 	"info",		CLEAN,	REALUSER,		(char *) FALSE,
62e39a5722Seric 	"unedit",	UNEDIT,	0,			NULL,
637de81dc7Seric 	NULL,		-1,	0,			NULL
64adf8f7d4Seric };
65adf8f7d4Seric 
66e39a5722Seric struct pfile
67e39a5722Seric {
68e39a5722Seric 	char	*p_osid;	/* old SID */
69e39a5722Seric 	char	*p_nsid;	/* new SID */
70e39a5722Seric 	char	*p_user;	/* user who did edit */
71e39a5722Seric 	char	*p_date;	/* date of get */
72e39a5722Seric 	char	*p_time;	/* time of get */
73e39a5722Seric };
74e39a5722Seric 
75c4432be4Seric char	*SccsPath = "SCCS";	/* pathname of SCCS files */
76c4432be4Seric bool	RealUser;		/* if set, running as real user */
77f0cc3246Seric # ifdef DEBUG
78f0cc3246Seric bool	Debug;			/* turn on tracing */
79f0cc3246Seric # endif
80adf8f7d4Seric 
81adf8f7d4Seric main(argc, argv)
82adf8f7d4Seric 	int argc;
83adf8f7d4Seric 	char **argv;
84adf8f7d4Seric {
85adf8f7d4Seric 	register char *p;
86b1ed8a43Seric 	extern struct sccsprog *lookup();
87adf8f7d4Seric 
88adf8f7d4Seric 	/*
89adf8f7d4Seric 	**  Detect and decode flags intended for this program.
90adf8f7d4Seric 	*/
91adf8f7d4Seric 
927de81dc7Seric 	if (argc < 2)
93adf8f7d4Seric 	{
947de81dc7Seric 		fprintf(stderr, "Usage: sccs [flags] command [flags]\n");
957de81dc7Seric 		exit(EX_USAGE);
967de81dc7Seric 	}
977de81dc7Seric 	argv[argc] = NULL;
987de81dc7Seric 
99b1ed8a43Seric 	if (lookup(argv[0]) == NULL)
100b1ed8a43Seric 	{
1017de81dc7Seric 		while ((p = *++argv) != NULL)
1027de81dc7Seric 		{
103adf8f7d4Seric 			if (*p != '-')
104adf8f7d4Seric 				break;
105adf8f7d4Seric 			switch (*++p)
106adf8f7d4Seric 			{
107adf8f7d4Seric 			  case 'r':		/* run as real user */
108adf8f7d4Seric 				setuid(getuid());
109c4432be4Seric 				RealUser++;
110adf8f7d4Seric 				break;
111adf8f7d4Seric 
112adf8f7d4Seric 			  case 'p':		/* path of sccs files */
113adf8f7d4Seric 				SccsPath = ++p;
114adf8f7d4Seric 				break;
115adf8f7d4Seric 
116f0cc3246Seric # ifdef DEBUG
117f0cc3246Seric 			  case 'T':		/* trace */
118f0cc3246Seric 				Debug++;
119f0cc3246Seric 				break;
120f0cc3246Seric # endif
121f0cc3246Seric 
122adf8f7d4Seric 			  default:
123adf8f7d4Seric 				fprintf(stderr, "Sccs: unknown option -%s\n", p);
124adf8f7d4Seric 				break;
125adf8f7d4Seric 			}
126adf8f7d4Seric 		}
1275cabffd9Seric 		if (SccsPath[0] == '\0')
1285cabffd9Seric 			SccsPath = ".";
129b1ed8a43Seric 	}
130adf8f7d4Seric 
1311777fbcbSeric 	command(argv, FALSE);
1327de81dc7Seric 	exit(EX_OK);
1337de81dc7Seric }
1347de81dc7Seric 
1351777fbcbSeric command(argv, forkflag)
1367de81dc7Seric 	char **argv;
1371777fbcbSeric 	bool forkflag;
1387de81dc7Seric {
1397de81dc7Seric 	register struct sccsprog *cmd;
1407de81dc7Seric 	register char *p;
1411777fbcbSeric 	register char *q;
1421777fbcbSeric 	char buf[40];
143b1ed8a43Seric 	extern struct sccsprog *lookup();
144f0cc3246Seric 	char *nav[7];
145f0cc3246Seric 	char **avp;
146f0cc3246Seric 
147f0cc3246Seric # ifdef DEBUG
148f0cc3246Seric 	if (Debug)
149f0cc3246Seric 	{
150f0cc3246Seric 		printf("command:\n");
151f0cc3246Seric 		for (avp = argv; *avp != NULL; avp++)
152f0cc3246Seric 			printf("    \"%s\"\n", *avp);
153f0cc3246Seric 	}
154f0cc3246Seric # endif
155c4432be4Seric 
156c4432be4Seric 	/*
157adf8f7d4Seric 	**  Look up command.
1587de81dc7Seric 	**	At this point, argv points to the command name.
159adf8f7d4Seric 	*/
160adf8f7d4Seric 
161e39a5722Seric 	cmd = lookup(argv[0]);
162b1ed8a43Seric 	if (cmd == NULL)
163adf8f7d4Seric 	{
164e39a5722Seric 		fprintf(stderr, "Sccs: Unknown command \"%s\"\n", argv[0]);
165adf8f7d4Seric 		exit(EX_USAGE);
166adf8f7d4Seric 	}
167adf8f7d4Seric 
168adf8f7d4Seric 	/*
1697de81dc7Seric 	**  Interpret operation associated with this command.
170c4432be4Seric 	*/
171c4432be4Seric 
1727de81dc7Seric 	switch (cmd->sccsoper)
1737de81dc7Seric 	{
1747de81dc7Seric 	  case PROG:		/* call an sccs prog */
1751777fbcbSeric 		callprog(cmd->sccspath, cmd->sccsflags, argv, forkflag);
1761777fbcbSeric 		break;
1771777fbcbSeric 
1781777fbcbSeric 	  case CMACRO:		/* command macro */
1791777fbcbSeric 		for (p = cmd->sccspath; *p != '\0'; p++)
1801777fbcbSeric 		{
181f0cc3246Seric 			avp = nav;
182f0cc3246Seric 			*avp++ = buf;
1831777fbcbSeric 			for (q = buf; *p != '/' && *p != '\0'; p++, q++)
184f0cc3246Seric 			{
185f0cc3246Seric 				if (*p == ' ')
186f0cc3246Seric 				{
1871777fbcbSeric 					*q = '\0';
188f0cc3246Seric 					*avp++ = &q[1];
189f0cc3246Seric 				}
190f0cc3246Seric 				else
191f0cc3246Seric 					*q = *p;
192f0cc3246Seric 			}
193f0cc3246Seric 			*q = '\0';
194f0cc3246Seric 			*avp = NULL;
195f0cc3246Seric 			xcommand(&argv[1], *p != '\0', nav[0], nav[1], nav[2],
196f0cc3246Seric 				 nav[3], nav[4], nav[5], nav[6]);
1971777fbcbSeric 		}
1981777fbcbSeric 		fprintf(stderr, "Sccs internal error: CMACRO\n");
1997de81dc7Seric 		exit(EX_SOFTWARE);
2007de81dc7Seric 
201172147faSeric 	  case FIX:		/* fix a delta */
202b2538d76Seric 		if (strcmpn(argv[1], "-r", 2) != 0)
203172147faSeric 		{
204172147faSeric 			fprintf(stderr, "Sccs: -r flag needed for fix command\n");
205172147faSeric 			break;
206172147faSeric 		}
207172147faSeric 		xcommand(&argv[1], TRUE, "get", "-k", NULL);
208172147faSeric 		xcommand(&argv[1], TRUE, "rmdel", NULL);
209172147faSeric 		xcommand(&argv[2], FALSE, "get", "-e", "-g", NULL);
210172147faSeric 		fprintf(stderr, "Sccs internal error: FIX\n");
211172147faSeric 		exit(EX_SOFTWARE);
212172147faSeric 
213b2538d76Seric 	  case CLEAN:
2143a208c77Seric 		clean((bool) cmd->sccspath);
215b2538d76Seric 		break;
216b2538d76Seric 
217e39a5722Seric 	  case UNEDIT:
218e39a5722Seric 		for (avp = &argv[1]; *avp != NULL; avp++)
219e39a5722Seric 			unedit(*avp);
220e39a5722Seric 		break;
221e39a5722Seric 
2227de81dc7Seric 	  default:
2237de81dc7Seric 		fprintf(stderr, "Sccs internal error: oper %d\n", cmd->sccsoper);
2247de81dc7Seric 		exit(EX_SOFTWARE);
2257de81dc7Seric 	}
2267de81dc7Seric }
227b1ed8a43Seric /*
228b1ed8a43Seric **  LOOKUP -- look up an SCCS command name.
229b1ed8a43Seric **
230b1ed8a43Seric **	Parameters:
231b1ed8a43Seric **		name -- the name of the command to look up.
232b1ed8a43Seric **
233b1ed8a43Seric **	Returns:
234b1ed8a43Seric **		ptr to command descriptor for this command.
235b1ed8a43Seric **		NULL if no such entry.
236b1ed8a43Seric **
237b1ed8a43Seric **	Side Effects:
238b1ed8a43Seric **		none.
239b1ed8a43Seric */
240b1ed8a43Seric 
241b1ed8a43Seric struct sccsprog *
242b1ed8a43Seric lookup(name)
243b1ed8a43Seric 	char *name;
244b1ed8a43Seric {
245b1ed8a43Seric 	register struct sccsprog *cmd;
246b1ed8a43Seric 
247b1ed8a43Seric 	for (cmd = SccsProg; cmd->sccsname != NULL; cmd++)
248b1ed8a43Seric 	{
249b1ed8a43Seric 		if (strcmp(cmd->sccsname, name) == 0)
250b1ed8a43Seric 			return (cmd);
251b1ed8a43Seric 	}
252b1ed8a43Seric 	return (NULL);
253b1ed8a43Seric }
2547de81dc7Seric 
255172147faSeric 
256172147faSeric xcommand(argv, forkflag, arg0)
257172147faSeric 	char **argv;
258172147faSeric 	bool forkflag;
259172147faSeric 	char *arg0;
260172147faSeric {
261172147faSeric 	register char **av;
262172147faSeric 	char *newargv[1000];
263172147faSeric 	register char **np;
264172147faSeric 
265172147faSeric 	np = newargv;
266172147faSeric 	for (av = &arg0; *av != NULL; av++)
267172147faSeric 		*np++ = *av;
268172147faSeric 	for (av = argv; *av != NULL; av++)
269172147faSeric 		*np++ = *av;
270172147faSeric 	*np = NULL;
271172147faSeric 	command(newargv, forkflag);
272172147faSeric }
273172147faSeric 
2747de81dc7Seric callprog(progpath, flags, argv, forkflag)
2757de81dc7Seric 	char *progpath;
2767de81dc7Seric 	short flags;
2777de81dc7Seric 	char **argv;
2787de81dc7Seric 	bool forkflag;
2797de81dc7Seric {
2807de81dc7Seric 	register char *p;
2817de81dc7Seric 	register char **av;
2827de81dc7Seric 	extern char *makefile();
2837de81dc7Seric 	register int i;
2841777fbcbSeric 	auto int st;
2857de81dc7Seric 
2867de81dc7Seric 	if (*argv == NULL)
2877de81dc7Seric 		return (-1);
288c4432be4Seric 
289c4432be4Seric 	/*
290172147faSeric 	**  Fork if appropriate.
291adf8f7d4Seric 	*/
292adf8f7d4Seric 
2937de81dc7Seric 	if (forkflag)
2947de81dc7Seric 	{
295f0cc3246Seric # ifdef DEBUG
296f0cc3246Seric 		if (Debug)
297f0cc3246Seric 			printf("Forking\n");
298f0cc3246Seric # endif
2997de81dc7Seric 		i = fork();
3007de81dc7Seric 		if (i < 0)
3017de81dc7Seric 		{
3027de81dc7Seric 			fprintf(stderr, "Sccs: cannot fork");
3037de81dc7Seric 			exit(EX_OSERR);
3047de81dc7Seric 		}
3057de81dc7Seric 		else if (i > 0)
3061777fbcbSeric 		{
3071777fbcbSeric 			wait(&st);
3081777fbcbSeric 			return (st);
3091777fbcbSeric 		}
3107de81dc7Seric 	}
3117de81dc7Seric 
3127de81dc7Seric 	/*
313172147faSeric 	**  Build new argument vector.
314172147faSeric 	*/
315172147faSeric 
316172147faSeric 	/* copy program filename arguments and flags */
317172147faSeric 	av = argv;
318172147faSeric 	while ((p = *++av) != NULL)
319172147faSeric 	{
320172147faSeric 		if (!bitset(NO_SDOT, flags) && *p != '-')
321172147faSeric 			*av = makefile(p);
322172147faSeric 	}
323172147faSeric 
324172147faSeric 	/*
3257de81dc7Seric 	**  Set protection as appropriate.
3267de81dc7Seric 	*/
3277de81dc7Seric 
3287de81dc7Seric 	if (bitset(REALUSER, flags))
3297de81dc7Seric 		setuid(getuid());
3307de81dc7Seric 
3317de81dc7Seric 	/*
332172147faSeric 	**  Call real SCCS program.
3337de81dc7Seric 	*/
3347de81dc7Seric 
335172147faSeric 	execv(progpath, argv);
336adf8f7d4Seric 	fprintf(stderr, "Sccs: cannot execute ");
3377de81dc7Seric 	perror(progpath);
338adf8f7d4Seric 	exit(EX_UNAVAILABLE);
339adf8f7d4Seric }
340adf8f7d4Seric 
341adf8f7d4Seric 
342adf8f7d4Seric char *
343adf8f7d4Seric makefile(name)
344adf8f7d4Seric 	char *name;
345adf8f7d4Seric {
346adf8f7d4Seric 	register char *p;
347adf8f7d4Seric 	register char c;
348adf8f7d4Seric 	char buf[512];
349adf8f7d4Seric 	struct stat stbuf;
350adf8f7d4Seric 	extern char *malloc();
351adf8f7d4Seric 
352adf8f7d4Seric 	/*
353adf8f7d4Seric 	**  See if this filename should be used as-is.
354adf8f7d4Seric 	**	There are three conditions where this can occur.
355adf8f7d4Seric 	**	1. The name already begins with "s.".
356adf8f7d4Seric 	**	2. The name has a "/" in it somewhere.
357adf8f7d4Seric 	**	3. The name references a directory.
358adf8f7d4Seric 	*/
359adf8f7d4Seric 
360b2538d76Seric 	if (strcmpn(name, "s.", 2) == 0)
361adf8f7d4Seric 		return (name);
362adf8f7d4Seric 	for (p = name; (c = *p) != '\0'; p++)
363adf8f7d4Seric 	{
364adf8f7d4Seric 		if (c == '/')
365adf8f7d4Seric 			return (name);
366adf8f7d4Seric 	}
367adf8f7d4Seric 	if (stat(name, &stbuf) >= 0 && (stbuf.st_mode & S_IFMT) == S_IFDIR)
368adf8f7d4Seric 		return (name);
369adf8f7d4Seric 
370adf8f7d4Seric 	/*
371adf8f7d4Seric 	**  Prepend the path of the sccs file.
372adf8f7d4Seric 	*/
373adf8f7d4Seric 
374adf8f7d4Seric 	strcpy(buf, SccsPath);
375c4432be4Seric 	strcat(buf, "/s.");
376adf8f7d4Seric 	strcat(buf, name);
377adf8f7d4Seric 	p = malloc(strlen(buf) + 1);
378adf8f7d4Seric 	if (p == NULL)
379adf8f7d4Seric 	{
380adf8f7d4Seric 		perror("Sccs: no mem");
381adf8f7d4Seric 		exit(EX_OSERR);
382adf8f7d4Seric 	}
383adf8f7d4Seric 	strcpy(p, buf);
384adf8f7d4Seric 	return (p);
385adf8f7d4Seric }
386b2538d76Seric /*
387b2538d76Seric **  CLEAN -- clean out recreatable files
388b2538d76Seric **
389b2538d76Seric **	Any file for which an "s." file exists but no "p." file
390b2538d76Seric **	exists in the current directory is purged.
391b2538d76Seric **
392b2538d76Seric **	Parameters:
3933a208c77Seric **		really -- if TRUE, remove everything.
3943a208c77Seric **			else, just report status.
395b2538d76Seric **
396b2538d76Seric **	Returns:
397b2538d76Seric **		none.
398b2538d76Seric **
399b2538d76Seric **	Side Effects:
400b2538d76Seric **		removes files in the current directory.
401b2538d76Seric */
402b2538d76Seric 
4033a208c77Seric clean(really)
4043a208c77Seric 	bool really;
405b2538d76Seric {
406b2538d76Seric 	struct direct dir;
407b2538d76Seric 	struct stat stbuf;
408b2538d76Seric 	char buf[100];
409bf9c1e66Seric 	char pline[120];
4103a208c77Seric 	register FILE *dirfd;
4113a208c77Seric 	register char *basefile;
4122caac8fdSeric 	bool gotedit;
413bf9c1e66Seric 	FILE *pfp;
414b2538d76Seric 
415b2538d76Seric 	dirfd = fopen(SccsPath, "r");
416b2538d76Seric 	if (dirfd == NULL)
417b2538d76Seric 	{
418b2538d76Seric 		fprintf(stderr, "Sccs: cannot open %s\n", SccsPath);
419b2538d76Seric 		return;
420b2538d76Seric 	}
421b2538d76Seric 
422b2538d76Seric 	/*
423b2538d76Seric 	**  Scan the SCCS directory looking for s. files.
424b2538d76Seric 	*/
425b2538d76Seric 
4262caac8fdSeric 	gotedit = FALSE;
427b2538d76Seric 	while (fread(&dir, sizeof dir, 1, dirfd) != NULL)
428b2538d76Seric 	{
429b2538d76Seric 		if (dir.d_ino == 0 || strcmpn(dir.d_name, "s.", 2) != 0)
430b2538d76Seric 			continue;
431b2538d76Seric 
432b2538d76Seric 		/* got an s. file -- see if the p. file exists */
433b2538d76Seric 		strcpy(buf, SccsPath);
434b2538d76Seric 		strcat(buf, "/p.");
4353a208c77Seric 		basefile = &buf[strlen(buf)];
4363a208c77Seric 		strcpyn(basefile, &dir.d_name[2], sizeof dir.d_name - 2);
437bf9c1e66Seric 		basefile[sizeof dir.d_name - 2] = '\0';
438bf9c1e66Seric 		pfp = fopen(buf, "r");
439bf9c1e66Seric 		if (pfp != NULL)
4403a208c77Seric 		{
441bf9c1e66Seric 			while (fgets(pline, sizeof pline, pfp) != NULL)
442*2444cd3eSeric 				printf("%12s: being edited: %s", basefile, pline);
443bf9c1e66Seric 			fclose(pfp);
4442caac8fdSeric 			gotedit = TRUE;
445b2538d76Seric 			continue;
4463a208c77Seric 		}
447b2538d76Seric 
448b2538d76Seric 		/* the s. file exists and no p. file exists -- unlink the g-file */
4493a208c77Seric 		if (really)
4503a208c77Seric 		{
451b2538d76Seric 			strcpyn(buf, &dir.d_name[2], sizeof dir.d_name - 2);
4523a208c77Seric 			buf[sizeof dir.d_name - 2] = '\0';
453b2538d76Seric 			unlink(buf);
454b2538d76Seric 		}
4553a208c77Seric 	}
456b2538d76Seric 
457b2538d76Seric 	fclose(dirfd);
4582caac8fdSeric 	if (!gotedit && !really)
459*2444cd3eSeric 		printf("Nothing being edited\n");
460b2538d76Seric }
461e39a5722Seric /*
462e39a5722Seric **  UNEDIT -- unedit a file
463e39a5722Seric **
464e39a5722Seric **	Checks to see that the current user is actually editting
465e39a5722Seric **	the file and arranges that s/he is not editting it.
466e39a5722Seric **
467e39a5722Seric **	Parameters:
468*2444cd3eSeric **		fn -- the name of the file to be unedited.
469e39a5722Seric **
470e39a5722Seric **	Returns:
471e39a5722Seric **		none.
472e39a5722Seric **
473e39a5722Seric **	Side Effects:
474e39a5722Seric **		fn is removed
475e39a5722Seric **		entries are removed from pfile.
476e39a5722Seric */
477e39a5722Seric 
478e39a5722Seric unedit(fn)
479e39a5722Seric 	char *fn;
480e39a5722Seric {
481e39a5722Seric 	register FILE *pfp;
482e39a5722Seric 	char *pfn;
483e39a5722Seric 	static char tfn[] = "/tmp/sccsXXXXX";
484e39a5722Seric 	FILE *tfp;
485e39a5722Seric 	register char *p;
486e39a5722Seric 	register char *q;
487e39a5722Seric 	bool delete = FALSE;
488e39a5722Seric 	bool others = FALSE;
489e39a5722Seric 	char *myname;
490e39a5722Seric 	extern char *getlogin();
491e39a5722Seric 	struct pfile *pent;
492e39a5722Seric 	extern struct pfile *getpfile();
493e39a5722Seric 	char buf[120];
494e39a5722Seric 
495e39a5722Seric 	/* make "s." filename & find the trailing component */
496e39a5722Seric 	pfn = makefile(fn);
497e39a5722Seric 	q = &pfn[strlen(pfn) - 1];
498e39a5722Seric 	while (q > pfn && *q != '/')
499e39a5722Seric 		q--;
500e39a5722Seric 	if (q <= pfn && (q[0] != 's' || q[1] != '.'))
501e39a5722Seric 	{
502e39a5722Seric 		fprintf(stderr, "Sccs: bad file name \"%s\"\n", fn);
503e39a5722Seric 		return;
504e39a5722Seric 	}
505e39a5722Seric 
506e39a5722Seric 	/* turn "s." into "p." */
507e39a5722Seric 	*++q = 'p';
508e39a5722Seric 
509e39a5722Seric 	pfp = fopen(pfn, "r");
510e39a5722Seric 	if (pfp == NULL)
511e39a5722Seric 	{
512*2444cd3eSeric 		printf("%12s: not being edited\n", fn);
513e39a5722Seric 		return;
514e39a5722Seric 	}
515e39a5722Seric 
516e39a5722Seric 	/*
517e39a5722Seric 	**  Copy p-file to temp file, doing deletions as needed.
518e39a5722Seric 	*/
519e39a5722Seric 
520e39a5722Seric 	mktemp(tfn);
521e39a5722Seric 	tfp = fopen(tfn, "w");
522e39a5722Seric 	if (tfp == NULL)
523e39a5722Seric 	{
524e39a5722Seric 		fprintf(stderr, "Sccs: cannot create \"%s\"\n", tfn);
525e39a5722Seric 		exit(EX_OSERR);
526e39a5722Seric 	}
527e39a5722Seric 
528e39a5722Seric 	myname = getlogin();
529e39a5722Seric 	while ((pent = getpfile(pfp)) != NULL)
530e39a5722Seric 	{
531e39a5722Seric 		if (strcmp(pent->p_user, myname) == 0)
532e39a5722Seric 		{
533e39a5722Seric 			/* a match */
534e39a5722Seric 			delete++;
535e39a5722Seric 		}
536e39a5722Seric 		else
537e39a5722Seric 		{
538e39a5722Seric 			fprintf(tfp, "%s %s %s %s %s\n", pent->p_osid,
539e39a5722Seric 			    pent->p_nsid, pent->p_user, pent->p_date,
540e39a5722Seric 			    pent->p_time);
541e39a5722Seric 			others++;
542e39a5722Seric 		}
543e39a5722Seric 	}
544e39a5722Seric 
545e39a5722Seric 	/* do final cleanup */
546e39a5722Seric 	if (others)
547e39a5722Seric 	{
548e39a5722Seric 		if (freopen(tfn, "r", tfp) == NULL)
549e39a5722Seric 		{
550e39a5722Seric 			fprintf(stderr, "Sccs: cannot reopen \"%s\"\n", tfn);
551e39a5722Seric 			exit(EX_OSERR);
552e39a5722Seric 		}
553e39a5722Seric 		if (freopen(pfn, "w", pfp) == NULL)
554e39a5722Seric 		{
555e39a5722Seric 			fprintf(stderr, "Sccs: cannot create \"%s\"\n", pfn);
556e39a5722Seric 			return;
557e39a5722Seric 		}
558e39a5722Seric 		while (fgets(buf, sizeof buf, tfp) != NULL)
559e39a5722Seric 			fputs(buf, pfp);
560e39a5722Seric 	}
561e39a5722Seric 	else
562e39a5722Seric 	{
563e39a5722Seric 		unlink(pfn);
564e39a5722Seric 	}
565e39a5722Seric 	fclose(tfp);
566e39a5722Seric 	fclose(pfp);
567e39a5722Seric 	unlink(tfn);
568e39a5722Seric 
569e39a5722Seric 	if (delete)
570e39a5722Seric 	{
571e39a5722Seric 		unlink(fn);
572e39a5722Seric 		printf("%12s: removed\n", fn);
573e39a5722Seric 	}
574e39a5722Seric 	else
575e39a5722Seric 	{
576*2444cd3eSeric 		printf("%12s: not being edited by you\n", fn);
577e39a5722Seric 	}
578e39a5722Seric }
579e39a5722Seric /*
580e39a5722Seric **  GETPFILE -- get an entry from the p-file
581e39a5722Seric **
582e39a5722Seric **	Parameters:
583e39a5722Seric **		pfp -- p-file file pointer
584e39a5722Seric **
585e39a5722Seric **	Returns:
586e39a5722Seric **		pointer to p-file struct for next entry
587e39a5722Seric **		NULL on EOF or error
588e39a5722Seric **
589e39a5722Seric **	Side Effects:
590e39a5722Seric **		Each call wipes out results of previous call.
591e39a5722Seric */
592e39a5722Seric 
593e39a5722Seric struct pfile *
594e39a5722Seric getpfile(pfp)
595e39a5722Seric 	FILE *pfp;
596e39a5722Seric {
597e39a5722Seric 	static struct pfile ent;
598e39a5722Seric 	static char buf[120];
599e39a5722Seric 	register char *p;
600e39a5722Seric 	extern char *nextfield();
601e39a5722Seric 
602e39a5722Seric 	if (fgets(buf, sizeof buf, pfp) == NULL)
603e39a5722Seric 		return (NULL);
604e39a5722Seric 
605e39a5722Seric 	ent.p_osid = p = buf;
606e39a5722Seric 	ent.p_nsid = p = nextfield(p);
607e39a5722Seric 	ent.p_user = p = nextfield(p);
608e39a5722Seric 	ent.p_date = p = nextfield(p);
609e39a5722Seric 	ent.p_time = p = nextfield(p);
610e39a5722Seric 	if (p == NULL || nextfield(p) != NULL)
611e39a5722Seric 		return (NULL);
612e39a5722Seric 
613e39a5722Seric 	return (&ent);
614e39a5722Seric }
615e39a5722Seric 
616e39a5722Seric 
617e39a5722Seric char *
618e39a5722Seric nextfield(p)
619e39a5722Seric 	register char *p;
620e39a5722Seric {
621e39a5722Seric 	if (p == NULL || *p == '\0')
622e39a5722Seric 		return (NULL);
623e39a5722Seric 	while (*p != ' ' && *p != '\n' && *p != '\0')
624e39a5722Seric 		p++;
625e39a5722Seric 	if (*p == '\n' || *p == '\0')
626e39a5722Seric 	{
627e39a5722Seric 		*p = '\0';
628e39a5722Seric 		return (NULL);
629e39a5722Seric 	}
630e39a5722Seric 	*p++ = '\0';
631e39a5722Seric 	return (p);
632e39a5722Seric }
633