+ if (mode == CLEANC && !gotpfent)
+ {
+ char unlinkbuf[FBUFSIZ];
+ gstrcpy(unlinkbuf, &dir->d_name[2], sizeof(unlinkbuf));
+ unlink(unlinkbuf);
+ }
+ }
+
+ /* cleanup & report results */
+ closedir(dirfd);
+ if (!gotedit && mode == INFOC)
+ {
+ printf("Nothing being edited");
+ if (nobranch)
+ printf(" (on trunk)");
+ if (usernm == NULL)
+ printf("\n");
+ else
+ printf(" by %s\n", usernm);
+ }
+ if (mode == CHECKC)
+ exit(gotedit);
+ return (EX_OK);
+}
+\f
+/*
+** ISBRANCH -- is the SID a branch?
+**
+** Parameters:
+** sid -- the sid to check.
+**
+** Returns:
+** TRUE if the sid represents a branch.
+** FALSE otherwise.
+**
+** Side Effects:
+** none.
+*/
+
+isbranch(sid)
+ char *sid;
+{
+ register char *p;
+ int dots;
+
+ dots = 0;
+ for (p = sid; *p != '\0'; p++)
+ {
+ if (*p == '.')
+ dots++;
+ if (dots > 1)
+ return (TRUE);
+ }
+ return (FALSE);
+}
+\f
+/*
+** UNEDIT -- unedit a file
+**
+** Checks to see that the current user is actually editting
+** the file and arranges that s/he is not editting it.
+**
+** Parameters:
+** fn -- the name of the file to be unedited.
+**
+** Returns:
+** TRUE -- if the file was successfully unedited.
+** FALSE -- if the file was not unedited for some
+** reason.
+**
+** Side Effects:
+** fn is removed
+** entries are removed from pfile.
+*/
+
+bool
+unedit(fn)
+ char *fn;
+{
+ register FILE *pfp;
+ char *cp, *pfn;
+ static char tfn[] = "/tmp/sccsXXXXX";
+ FILE *tfp;
+ register char *q;
+ bool delete = FALSE;
+ bool others = FALSE;
+ char *myname;
+ extern char *username();
+ struct pfile *pent;
+ extern struct pfile *getpfent();
+ char buf[PFILELG];
+ extern char *makefile();
+
+ /* make "s." filename & find the trailing component */
+ pfn = makefile(fn);
+ if (pfn == NULL)
+ return (FALSE);
+ q = rindex(pfn, '/');
+ if (q == NULL)
+ q = &pfn[-1];
+ if (q[1] != 's' || q[2] != '.')
+ {
+ usrerr("bad file name \"%s\"", fn);
+ return (FALSE);
+ }
+
+ /* turn "s." into "p." & try to open it */
+ *++q = 'p';
+
+ pfp = fopen(pfn, "r");
+ if (pfp == NULL)
+ {
+ printf("%12s: not being edited\n", fn);
+ return (FALSE);
+ }
+
+ /* create temp file for editing p-file */
+ mktemp(tfn);
+ tfp = fopen(tfn, "w");
+ if (tfp == NULL)
+ {
+ usrerr("cannot create \"%s\"", tfn);
+ exit(EX_OSERR);
+ }
+
+ /* figure out who I am */
+ myname = username();
+
+ /*
+ ** Copy p-file to temp file, doing deletions as needed.
+ */
+
+ while ((pent = getpfent(pfp)) != NULL)
+ {
+ if (strcmp(pent->p_user, myname) == 0)
+ {
+ /* a match */
+ delete++;
+ }
+ else
+ {
+ /* output it again */
+ putpfent(pent, tfp);
+ others++;
+ }
+ }
+
+ /*
+ * Before changing anything, make sure we can remove
+ * the file in question (assuming it exists).
+ */
+ if (delete) {
+ extern int errno;
+
+ cp = tail(fn);
+ errno = 0;
+ if (access(cp, 0) < 0 && errno != ENOENT)
+ goto bad;
+ if (errno == 0)
+ /*
+ * This is wrong, but the rest of the program
+ * has built in assumptions about "." as well,
+ * so why make unedit a special case?
+ */
+ if (access(".", 2) < 0) {
+ bad:
+ printf("%12s: can't remove\n", cp);
+ fclose(tfp);
+ fclose(pfp);
+ unlink(tfn);
+ return (FALSE);
+ }
+ }
+ /* do final cleanup */
+ if (others)
+ {
+ /* copy it back (perhaps it should be linked?) */
+ if (freopen(tfn, "r", tfp) == NULL)
+ {
+ syserr("cannot reopen \"%s\"", tfn);
+ exit(EX_OSERR);
+ }
+ if (freopen(pfn, "w", pfp) == NULL)
+ {
+ usrerr("cannot create \"%s\"", pfn);
+ return (FALSE);
+ }
+ while (fgets(buf, sizeof buf, tfp) != NULL)
+ fputs(buf, pfp);
+ }
+ else
+ {
+ /* it's empty -- remove it */
+ unlink(pfn);
+ }
+ fclose(tfp);
+ fclose(pfp);
+ unlink(tfn);
+
+ /* actually remove the g-file */
+ if (delete)
+ {
+ /*
+ * Since we've checked above, we can
+ * use the return from unlink to
+ * determine if the file existed or not.
+ */
+ if (unlink(cp) >= 0)
+ printf("%12s: removed\n", cp);
+ return (TRUE);
+ }
+ else
+ {
+ printf("%12s: not being edited by you\n", fn);
+ return (FALSE);
+ }
+}
+\f
+/*
+** DODIFF -- diff an s-file against a g-file
+**
+** Parameters:
+** getv -- argv for the 'get' command.
+** gfile -- name of the g-file to diff against.
+**
+** Returns:
+** Result of get.
+**
+** Side Effects:
+** none.
+*/
+
+dodiff(getv, gfile)
+ char **getv;
+ char *gfile;
+{
+ int pipev[2];
+ int rval;
+ register int i;
+ register int pid;
+ auto int st;
+ extern int errno;
+ int (*osig)();
+ register char *p;
+ register char **ap;
+ bool makescript = FALSE;
+
+ for (ap = getv; *ap != NULL; ap++)
+ {
+ p = *ap;
+ if (p[0] == '-')
+ {
+ switch (p[1])
+ {
+ case 'E':
+ p[1] = 'e';
+ makescript = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (makescript)
+ {
+ printf("sccs edit %s\n", gfile);
+ printf("ed - %s << 'xxEOFxx'\n", gfile);
+ }
+ else
+ printf("\n------- %s -------\n", gfile);
+ fflush(stdout);
+
+ /* create context for diff to run in */
+ if (pipe(pipev) < 0)
+ {
+ syserr("dodiff: pipe failed");
+ exit(EX_OSERR);
+ }
+ if ((pid = fork()) < 0)
+ {
+ syserr("dodiff: fork failed");
+ exit(EX_OSERR);
+ }
+ else if (pid > 0)
+ {
+ /* in parent; run get */
+ OutFile = pipev[1];
+ close(pipev[0]);
+ rval = command(&getv[1], TRUE, "get:rcixt -s -k -p");
+ osig = signal(SIGINT, SIG_IGN);
+ while (((i = wait(&st)) >= 0 && i != pid) || errno == EINTR)
+ errno = 0;
+ signal(SIGINT, osig);
+ /* ignore result of diff */
+ }
+ else
+ {
+ /* in child, run diff */
+ if (close(pipev[1]) < 0 || close(0) < 0 ||
+ dup(pipev[0]) != 0 || close(pipev[0]) < 0)
+ {
+ syserr("dodiff: magic failed");
+ exit(EX_OSERR);
+ }
+ command(&getv[1], FALSE, "-diff:elsfhbC");
+ }
+
+ if (makescript)
+ {
+ printf("w\n");
+ printf("q\n");
+ printf("'xxEOFxx'\n");
+ printf("sccs delta %s\n", gfile);
+ }
+
+ return (rval);
+}
+\f
+/*
+** TAIL -- return tail of filename.
+**
+** Parameters:
+** fn -- the filename.
+**
+** Returns:
+** a pointer to the tail of the filename; e.g., given
+** "cmd/ls.c", "ls.c" is returned.
+**
+** Side Effects:
+** none.
+*/
+
+char *
+tail(fn)
+ register char *fn;
+{
+ register char *p;
+
+ for (p = fn; *p != 0; p++)
+ if (*p == '/' && p[1] != '\0' && p[1] != '/')
+ fn = &p[1];
+ return (fn);
+}
+\f
+/*
+** GETPFENT -- get an entry from the p-file
+**
+** Parameters:
+** pfp -- p-file file pointer
+**
+** Returns:
+** pointer to p-file struct for next entry
+** NULL on EOF or error
+**
+** Side Effects:
+** Each call wipes out results of previous call.
+*/
+
+struct pfile *
+getpfent(pfp)
+ FILE *pfp;
+{
+ static struct pfile ent;
+ static char buf[PFILELG];
+ register char *p;
+ extern char *nextfield();
+
+ if (fgets(buf, sizeof buf, pfp) == NULL)
+ return (NULL);
+
+ ent.p_osid = p = buf;
+ ent.p_nsid = p = nextfield(p);
+ ent.p_user = p = nextfield(p);
+ ent.p_date = p = nextfield(p);
+ ent.p_time = p = nextfield(p);
+ ent.p_aux = p = nextfield(p);
+
+ return (&ent);
+}
+
+
+char *
+nextfield(p)
+ register char *p;
+{
+ if (p == NULL || *p == '\0')
+ return (NULL);
+ while (*p != ' ' && *p != '\n' && *p != '\0')
+ p++;
+ if (*p == '\n' || *p == '\0')
+ {
+ *p = '\0';
+ return (NULL);
+ }
+ *p++ = '\0';
+ return (p);
+}
+\f/*
+** PUTPFENT -- output a p-file entry to a file
+**
+** Parameters:
+** pf -- the p-file entry
+** f -- the file to put it on.
+**
+** Returns:
+** none.
+**
+** Side Effects:
+** pf is written onto file f.
+*/
+
+putpfent(pf, f)
+ register struct pfile *pf;
+ register FILE *f;
+{
+ fprintf(f, "%s %s %s %s %s", pf->p_osid, pf->p_nsid,
+ pf->p_user, pf->p_date, pf->p_time);
+ if (pf->p_aux != NULL)
+ fprintf(f, " %s", pf->p_aux);
+ else
+ fprintf(f, "\n");
+}
+\f
+/*
+** USRERR -- issue user-level error
+**
+** Parameters:
+** f -- format string.
+** p1-p3 -- parameters to a printf.
+**
+** Returns:
+** -1
+**
+** Side Effects:
+** none.
+*/
+
+/*VARARGS1*/
+usrerr(f, p1, p2, p3)
+ char *f;
+{
+ fprintf(stderr, "\n%s: ", MyName);
+ fprintf(stderr, f, p1, p2, p3);
+ fprintf(stderr, "\n");
+
+ return (-1);
+}
+\f
+/*
+** SYSERR -- print system-generated error.
+**
+** Parameters:
+** f -- format string to a printf.
+** p1, p2, p3 -- parameters to f.
+**
+** Returns:
+** never.
+**
+** Side Effects:
+** none.
+*/
+
+/*VARARGS1*/
+syserr(f, p1, p2, p3)
+ char *f;
+{
+ extern int errno;
+
+ fprintf(stderr, "\n%s SYSERR: ", MyName);
+ fprintf(stderr, f, p1, p2, p3);
+ fprintf(stderr, "\n");
+ if (errno == 0)
+ exit(EX_SOFTWARE);
+ else
+ {
+ perror(NULL);
+ exit(EX_OSERR);
+ }
+}
+\f/*
+** USERNAME -- return name of the current user
+**
+** Parameters:
+** none
+**
+** Returns:
+** name of current user
+**
+** Side Effects:
+** none
+*/
+
+char *
+username()
+{
+# ifdef UIDUSER
+ extern struct passwd *getpwuid();
+ register struct passwd *pw;
+
+ pw = getpwuid(getuid());
+ if (pw == NULL)
+ {
+ syserr("who are you? (uid=%d)", getuid());
+ exit(EX_OSERR);