+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif not lint
+
+#ifndef lint
+static char sccsid[] = "@(#)sccs.c 5.1 (Berkeley) %G%";
+#endif not lint
+
# include <stdio.h>
-# include <sys/types.h>
+# include <sys/param.h>
# include <sys/stat.h>
# include <sys/dir.h>
# include <errno.h>
# include <signal.h>
# include <sysexits.h>
-# include <whoami.h>
+# include <pwd.h>
/*
** SCCS.C -- human-oriented front end to the SCCS system.
** Copyright 1980 Regents of the University of California
*/
-static char SccsId[] = "@(#)sccs.c 1.56 %G%";
\f
/******************* Configuration Information ********************/
-/* special defines for local berkeley systems */
-# include <whoami.h>
-
-# ifdef CSVAX
-# define UIDUSER
-# define PROGPATH(name) "/usr/local/name"
-# endif CSVAX
-
-# ifdef INGVAX
-# define PROGPATH(name) "/usr/local/name"
-# endif INGVAX
-
-# ifdef CORY
-# define PROGPATH(name) "/usr/eecs/bin/name"
-# endif CORY
-
-/* end of berkeley systems defines */
-
# ifndef SCCSPATH
# define SCCSPATH "SCCS" /* pathname in which to find s-files */
# endif NOT SCCSPATH
# endif NOT MYNAME
# ifndef PROGPATH
-# define PROGPATH(name) "/usr/sccs/name" /* place to find binaries */
+# define PROGPATH(name) "/usr/local/name" /* place to find binaries */
# endif PROGPATH
/**************** End of Configuration Information ****************/
# define bitset(bit, word) ((bool) ((bit) & (word)))
-# ifdef UIDUSER
-# include <pwd.h>
-# endif UIDUSER
-
struct sccsprog
{
char *sccsname; /* name of SCCS routine */
# define SHELL 5 /* call a shell file (like PROG) */
# define DIFFS 6 /* diff between sccs & file out */
# define DODIFF 7 /* internal call to diff program */
+# define ENTER 8 /* enter new files */
/* bits for sccsflags */
# define NO_SDOT 0001 /* no s. on front of args */
"diffs", DIFFS, NO_SDOT|REALUSER, NULL,
"-diff", DODIFF, NO_SDOT|REALUSER, PROGPATH(bdiff),
"print", CMACRO, 0, "prt -e/get -p -m -s",
+ "branch", CMACRO, NO_SDOT,
+ "get:ixrc -e -b/delta: -s -n -ybranch-place-holder/get:pl -e -t -g",
+ "enter", ENTER, NO_SDOT, NULL,
+ "create", CMACRO, NO_SDOT, "enter/get:ixbeskcl -t",
NULL, -1, 0, NULL
};
char *p_user; /* user who did edit */
char *p_date; /* date of get */
char *p_time; /* time of get */
+ char *p_aux; /* extra info at end */
};
char *SccsPath = SCCSPATH; /* pathname of SCCS files */
# ifdef DEBUG
bool Debug; /* turn on tracing */
# endif
+# ifndef V6
+extern char *getenv();
+# endif V6
+
+char *gstrcat(), *strcat();
+char *gstrncat(), *strncat();
+char *gstrcpy(), *strcpy();
+#define FBUFSIZ BUFSIZ
+#define PFILELG 120
\f
main(argc, argv)
int argc;
register char *p;
extern struct sccsprog *lookup();
register int i;
+# ifndef V6
+# ifndef SCCSDIR
+ register struct passwd *pw;
+ extern struct passwd *getpwnam();
+ char buf[FBUFSIZ];
+
+ /* pull "SccsDir" out of the environment (possibly) */
+ p = getenv("PROJECTDIR");
+ if (p != NULL && p[0] != '\0')
+ {
+ if (p[0] == '/')
+ SccsDir = p;
+ else
+ {
+ pw = getpwnam(p);
+ if (pw == NULL)
+ {
+ usrerr("user %s does not exist", p);
+ exit(EX_USAGE);
+ }
+ gstrcpy(buf, pw->pw_dir, sizeof(buf));
+ gstrcat(buf, "/src", sizeof(buf));
+ if (access(buf, 0) < 0)
+ {
+ gstrcpy(buf, pw->pw_dir, sizeof(buf));
+ gstrcat(buf, "/source", sizeof(buf));
+ if (access(buf, 0) < 0)
+ {
+ usrerr("project %s has no source!", p);
+ exit(EX_USAGE);
+ }
+ }
+ SccsDir = buf;
+ }
+ }
+# endif SCCSDIR
+# endif V6
/*
** Detect and decode flags intended for this program.
# ifndef SCCSDIR
case 'p': /* path of sccs files */
SccsPath = ++p;
+ if (SccsPath[0] == '\0' && argv[1] != NULL)
+ SccsPath = *++argv;
break;
case 'd': /* directory to search from */
SccsDir = ++p;
+ if (SccsDir[0] == '\0' && argv[1] != NULL)
+ SccsDir = *++argv;
break;
# endif
{
register struct sccsprog *cmd;
register char *p;
- char buf[40];
+ char buf[FBUFSIZ];
extern struct sccsprog *lookup();
char *nav[1000];
char **np;
syserr("cannot exec %s", cmd->sccspath);
exit(EX_OSERR);
+ case ENTER: /* enter new sccs files */
+ /* skip over flag arguments */
+ for (np = &ap[1]; *np != NULL && **np == '-'; np++)
+ continue;
+ argv = np;
+
+ /* do an admin for each file */
+ p = argv[1];
+ while (*np != NULL)
+ {
+ printf("\n%s:\n", *np);
+ strcpy(buf, "-i");
+ gstrcat(buf, *np, sizeof(buf));
+ ap[0] = buf;
+ argv[0] = tail(*np);
+ argv[1] = NULL;
+ rval = command(ap, TRUE, "admin");
+ argv[1] = p;
+ if (rval == 0)
+ {
+ strcpy(buf, ",");
+ gstrcat(buf, tail(*np), sizeof(buf));
+ if (link(*np, buf) >= 0)
+ unlink(*np);
+ }
+ np++;
+ }
+ break;
+
default:
syserr("oper %d", cmd->sccsoper);
exit(EX_SOFTWARE);
char *name;
{
register char *p;
- char buf[512];
+ char buf[3*FBUFSIZ];
extern char *malloc();
extern char *rindex();
extern bool isdir();
/* first the directory part */
if (name[0] != '/')
{
- strcpy(buf, SccsDir);
- strcat(buf, "/");
+ gstrcpy(buf, SccsDir, sizeof(buf));
+ gstrcat(buf, "/", sizeof(buf));
}
else
- strcpy(buf, "");
+ gstrcpy(buf, "", sizeof(buf));
/* then the head of the pathname */
strncat(buf, name, p - name);
if (strncmp(p, "s.", 2) != 0 && !isdir(buf))
{
/* sorry, no; copy the SCCS pathname & the "s." */
- strcpy(q, SccsPath);
- strcat(buf, "/s.");
+ gstrcpy(q, SccsPath, sizeof(buf));
+ gstrcat(buf, "/s.", sizeof(buf));
/* and now the end of the name */
- strcat(buf, p);
+ gstrcat(buf, p, sizeof(buf));
}
/* if i haven't changed it, why did I do all this? */
int mode;
char **argv;
{
- struct direct dir;
- char buf[100];
- register FILE *dirfd;
+ struct direct *dir;
+ char buf[FBUFSIZ];
+ char *bufend;
+ register DIR *dirfd;
register char *basefile;
bool gotedit;
bool gotpfent;
register char **ap;
extern char *username();
char *usernm = NULL;
+ char *subdir = NULL;
+ char *cmdname;
/*
** Process the argv
*/
- for (ap = argv; *ap != NULL; ap++)
+ cmdname = *argv;
+ for (ap = argv; *++ap != NULL; )
{
if (**ap == '-')
{
break;
}
}
+ else
+ {
+ if (subdir != NULL)
+ usrerr("too many args");
+ else
+ subdir = *ap;
+ }
}
/*
** Find and open the SCCS directory.
*/
- strcpy(buf, SccsDir);
+ gstrcpy(buf, SccsDir, sizeof(buf));
if (buf[0] != '\0')
- strcat(buf, "/");
- strcat(buf, SccsPath);
+ gstrcat(buf, "/", sizeof(buf));
+ if (subdir != NULL)
+ {
+ gstrcat(buf, subdir, sizeof(buf));
+ gstrcat(buf, "/", sizeof(buf));
+ }
+ gstrcat(buf, SccsPath, sizeof(buf));
+ bufend = &buf[strlen(buf)];
- dirfd = fopen(buf, "r");
+ dirfd = opendir(buf);
if (dirfd == NULL)
{
usrerr("cannot open %s", buf);
*/
gotedit = FALSE;
- while (fread((char *)&dir, sizeof dir, 1, dirfd) != NULL)
- {
- if (dir.d_ino == 0 || strncmp(dir.d_name, "s.", 2) != 0)
+ while (dir = readdir(dirfd)) {
+ if (strncmp(dir->d_name, "s.", 2) != 0)
continue;
/* got an s. file -- see if the p. file exists */
- strcpy(buf, SccsDir);
- if (buf[0] != '\0')
- strcat(buf, "/");
- strcat(buf, SccsPath);
- strcat(buf, "/p.");
- basefile = &buf[strlen(buf)];
- strncpy(basefile, &dir.d_name[2], sizeof dir.d_name - 2);
- basefile[sizeof dir.d_name - 2] = '\0';
+ gstrcpy(bufend, "/p.", sizeof(buf));
+ basefile = bufend + 3;
+ gstrcpy(basefile, &dir->d_name[2], sizeof(buf));
/*
** open and scan the p-file.
printf("%s\n", basefile);
break;
}
- printf("%12s: being edited: %s %s %s %s %s\n",
- basefile, pf->p_osid, pf->p_nsid,
- pf->p_user, pf->p_date, pf->p_time);
+ printf("%12s: being edited: ", basefile);
+ putpfent(pf, stdout);
}
fclose(pfp);
}
/* the s. file exists and no p. file exists -- unlink the g-file */
if (mode == CLEANC && !gotpfent)
{
- strncpy(buf, &dir.d_name[2], sizeof dir.d_name - 2);
- buf[sizeof dir.d_name - 2] = '\0';
- unlink(buf);
+ char unlinkbuf[FBUFSIZ];
+ gstrcpy(unlinkbuf, &dir->d_name[2], sizeof(unlinkbuf));
+ unlink(unlinkbuf);
}
}
/* cleanup & report results */
- fclose(dirfd);
+ closedir(dirfd);
if (!gotedit && mode == INFOC)
{
printf("Nothing being edited");
char *fn;
{
register FILE *pfp;
- char *pfn;
+ char *cp, *pfn;
static char tfn[] = "/tmp/sccsXXXXX";
FILE *tfp;
register char *q;
extern char *username();
struct pfile *pent;
extern struct pfile *getpfent();
- char buf[120];
+ char buf[PFILELG];
extern char *makefile();
/* make "s." filename & find the trailing component */
else
{
/* output it again */
- fprintf(tfp, "%s %s %s %s %s\n", pent->p_osid,
- pent->p_nsid, pent->p_user, pent->p_date,
- pent->p_time);
+ 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)
{
/* actually remove the g-file */
if (delete)
{
- unlink(tail(fn));
- printf("%12s: removed\n", tail(fn));
+ /*
+ * 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
FILE *pfp;
{
static struct pfile ent;
- static char buf[120];
+ static char buf[PFILELG];
register char *p;
extern char *nextfield();
ent.p_user = p = nextfield(p);
ent.p_date = p = nextfield(p);
ent.p_time = p = nextfield(p);
- if (p == NULL || nextfield(p) != NULL)
- return (NULL);
+ ent.p_aux = p = nextfield(p);
return (&ent);
}
*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
return (pw->pw_name);
# else
extern char *getlogin();
+ extern char *getenv();
+ register char *p;
- return (getlogin());
+ p = getenv("USER");
+ if (p == NULL || p[0] == '\0')
+ p = getlogin();
+ return (p);
# endif UIDUSER
}
+\f
+/*
+** Guarded string manipulation routines; the last argument
+** is the length of the buffer into which the strcpy or strcat
+** is to be done.
+*/
+char *gstrcat(to, from, length)
+ char *to, *from;
+ int length;
+{
+ if (strlen(from) + strlen(to) >= length) {
+ gstrbotch(to, from);
+ }
+ return(strcat(to, from));
+}
+
+char *gstrncat(to, from, n, length)
+ char *to, *from;
+ int n;
+ int length;
+{
+ if (n + strlen(to) >= length) {
+ gstrbotch(to, from);
+ }
+ return(strncat(to, from, n));
+}
+
+char *gstrcpy(to, from, length)
+ char *to, *from;
+ int length;
+{
+ if (strlen(from) >= length) {
+ gstrbotch(from, (char *)0);
+ }
+ return(strcpy(to, from));
+}
+gstrbotch(str1, str2)
+ char *str1, *str2;
+{
+ usrerr("Filename(s) too long: %s %s", str1, str2);
+}