BSD 4_2 development
authorCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 14 May 1983 00:54:01 +0000 (16:54 -0800)
committerCSRG <csrg@ucbvax.Berkeley.EDU>
Sat, 14 May 1983 00:54:01 +0000 (16:54 -0800)
Work on file usr/src/new/new/spms/src/bin/pd/pd.c
Work on file usr/src/new/new/spms/src/bin/pdiff/ptree.c
Work on file usr/src/new/new/spms/src/bin/pdiff/pdiff.c
Work on file usr/src/new/new/spms/src/bin/pdiff/ptree.h
Work on file usr/src/new/new/spms/src/bin/pexec/exec.c
Work on file usr/src/new/new/spms/src/bin/pexec/pdlist.c
Work on file usr/src/new/new/spms/src/bin/pexec/misc.c
Work on file usr/src/new/new/spms/src/bin/pexec/pdlist.h
Work on file usr/src/new/new/spms/src/bin/pexec/Pexec.c
Work on file usr/src/new/new/spms/src/bin/pexec/pdset.h
Work on file usr/src/new/new/spms/src/bin/pexec/pdset.c
Work on file usr/src/new/new/spms/src/bin/pfind/binary.c
Work on file usr/src/new/new/spms/src/bin/pgrep/pgrep.c
Work on file usr/src/new/new/spms/src/bin/phelp/phelp.h
Work on file usr/src/new/new/spms/src/bin/phelp/requestq.c
Work on file usr/src/new/new/spms/src/bin/pman/pman.c

Synthesized-from: CSRG/cd1/4.2

16 files changed:
usr/src/new/new/spms/src/bin/pd/pd.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pdiff/pdiff.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pdiff/ptree.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pdiff/ptree.h [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/Pexec.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/exec.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/misc.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/pdlist.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/pdlist.h [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/pdset.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pexec/pdset.h [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pfind/binary.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pgrep/pgrep.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/phelp/phelp.h [new file with mode: 0644]
usr/src/new/new/spms/src/bin/phelp/requestq.c [new file with mode: 0644]
usr/src/new/new/spms/src/bin/pman/pman.c [new file with mode: 0644]

diff --git a/usr/src/new/new/spms/src/bin/pd/pd.c b/usr/src/new/new/spms/src/bin/pd/pd.c
new file mode 100644 (file)
index 0000000..9d9635f
--- /dev/null
@@ -0,0 +1,120 @@
+static char *rcsid = "$Header$";
+/*
+ * pd - change working project directory
+ *
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "macro.h"
+#include "null.h"
+#include "path.h"
+#include "pdb.h"
+#include "pld.h"
+#include "spms.h"
+#include "yesno.h"
+
+char *PGN = "pd";                      /* program name */
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int PPDEBUG;             /* project pathname debug flag */
+       char *alias;                    /* project directory alias */
+       char *cmd;                      /* change directory command pointer */
+       char *cwp;                      /* current project regular pathname */
+       char dirdesc[DIRDESCSIZE];      /* project directory description */
+       char *getcwp();                 /* get current project pathname */
+       char *pbgetstring();            /* get specified string field */
+       char *ppathname;                /* project pathname */
+       int dflag = NO;                 /* print description flag */
+       int errpdb();                   /* print database error message */
+       int pfndent();                  /* find and load database entry */
+       int status = 0;                 /* exit status */
+       int xppath();                   /* expand project pathname */
+       PATH pathbuf;                   /* pathname struct buffer */
+       PDB *openpdb();                 /* open database */
+       PDB *pldp;                      /* project link directory stream */
+       void nodir();                   /* "can't find dir" fatal error call */
+
+       cmd = "cd";
+       {
+       register char *s;               /* option pointer */
+       while (--argc > 0 && **++argv == '-')
+               {
+               for (s = argv[0]+1; *s != '\0'; s++)
+                       switch (*s)
+                               {
+                               case 'D':
+                                       PPDEBUG = YES;
+                                       break;
+                               case 'd':
+                                       dflag = YES;
+                                       break;
+                               case 'p':
+                                       cmd = "pushd";
+                                       break;
+                               default:
+                                       warn("bad option -%c", *s);
+                                       status = 1;
+                                       goto endfor;
+                               }
+               endfor: continue;
+               }
+       }
+       if (status == 1 || argc > 1)
+               fatal("usage: pd [-d] pdirname");
+
+       /* print the target directory */
+       ppathname = (argc < 1) ? CURPROJECT : *argv;
+       if (xppath(ppathname, &pathbuf) == -1)
+               nodir(ppathname);
+       else switch (pathbuf.p_mode & P_IFMT)
+               {
+               case P_IFNEW:
+                       nodir(ppathname);
+                       break;
+               case P_IFREG:
+                       break;
+               case P_IFPDIR:
+               case P_IFHOME:
+               case P_IFPROOT:
+                       /* change project if different (for cd only) */
+                       if (*cmd == 'c' && (cwp = getcwp()) != NULL)
+                               if (!EQUAL(cwp, pathbuf.p_project))
+                                       printf("setenv PROJECT %s;",
+                                              pathbuf.p_project);
+                       break;
+               }
+       printf("%s %s", cmd, pathbuf.p_path);
+
+       /* print project directory description */
+       if (dflag == YES && (pathbuf.p_mode&P_IFMT) != P_IFREG)
+               {
+               if ((pathbuf.p_mode&P_IFMT) == P_IFPDIR)
+                       alias = pathbuf.p_alias;
+               else
+                       alias = CURPROJECT;
+               if ((pldp = openpdb(PLDNAME, pathbuf.p_project, "r")) == NULL)
+                       exit(errpdb((PDB *) NULL));
+               if (pfndent(alias, pldp) == NO)
+                       fatal("can't find %s alias in %s", alias, pldp->path);
+               if (*pbgetstring(PDIRDESC, dirdesc) != '\0')
+                       fprintf(stderr, "%s\n", dirdesc);
+               }
+       exit(0);
+}
+
+
+
+/*
+ * nodir() complains that it can't find the directory and calls exit(1).
+ */
+void
+nodir(ppathname)
+       char *ppathname;                /* project pathname */
+{
+       *PGN = '\0';
+       patherr(ppathname);
+       exit(1);
+}
diff --git a/usr/src/new/new/spms/src/bin/pdiff/pdiff.c b/usr/src/new/new/spms/src/bin/pdiff/pdiff.c
new file mode 100644 (file)
index 0000000..30402a6
--- /dev/null
@@ -0,0 +1,376 @@
+static char *rcsid = "$Header$";
+/*
+ * pdiff - differential project comparator
+ *
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "getarg.h"
+#include "macro.h"
+#include "null.h"
+#include "path.h"
+#include "pdb.h"
+#include "pdtyp.h"
+#include "pld.h"
+#include "ptree.h"
+#include "spms.h"
+#include "yesno.h"
+
+char **NARGV;                          /* new argument list */
+char *PGN = "pdiff";                   /* program name */
+int EXECUTE = YES;                     /* execute command? */
+int NARGI = 0;                         /* new argument list index */
+int RECURSIVE = 0;                     /* recursively compare projects */
+PDTYP PDIRTYP;                         /* project directory type labels list */
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int PPDEBUG;             /* project pathname debug flag */
+       char p1[PPATHSIZE];             /* project pathname buffer */
+       char p2[PPATHSIZE];             /* project pathname buffer */
+       char *strcpy();                 /* string copy */
+       int balance();                  /* balance PDIR structs */
+       int diffdir();                  /* compare directories or files */
+       int diffproject();              /* compare projects */
+       int pdtparse();                 /* parse boolean type label expr */
+       int read_path();                /* read project or regular pathname */
+       int status = 0;                 /* exit status */
+       PATH pb1;                       /* pathname struct buffer 1 */
+       PATH pb2;                       /* pathname struct buffer 2 */
+       unsigned long pathtyp1;         /* type of pathname 1 */
+       unsigned long pathtyp2;         /* type of pathname 2 */
+
+       NARGV = argv;
+       NARGV[NARGI++] = "diff";
+
+       {
+       register char *s;               /* option pointer */
+       while (--argc > 0 && **++argv == '-')
+               {
+               for (s = argv[0]+1; *s != '\0'; s++)
+                       switch (*s)
+                               {
+                               case 'D':
+                                       PPDEBUG = YES;
+                                       break;
+                               case 'T':
+                                       if (pdtparse(GETARG(s), &PDIRTYP) == NO)
+                                               status = 1;
+                                       goto endfor;
+                               case 'r':
+                                       RECURSIVE++;
+                                       break;
+                               case 'x':
+                                       EXECUTE = NO;
+                                       break;
+                               default:
+                                       NARGV[NARGI++] = *argv;
+                                       break;
+                               }
+               endfor: continue;
+               }
+       }
+       if (status == 1 || argc < 2)
+               {
+               warn("usage: pdiff [-rx] [-T typexpr] [diff options] p1 p2");
+               exit(2);
+               }
+       
+       strcpy(p1, argv[0]);
+       strcpy(p2, argv[1]);
+       NARGV[NARGI+2] = NULL;
+
+       if (read_path(p1, &pb1) == NO || read_path(p2, &pb2) == NO)
+               exit(2);
+       
+       pathtyp1 = (pb1.p_mode & P_IFMT);
+       pathtyp2 = (pb2.p_mode & P_IFMT);
+
+       if (pathtyp1 == P_IFPROOT || pathtyp1 == P_IFHOME)
+               {
+               if (pathtyp2 == P_IFPROOT || pathtyp2 == P_IFHOME)
+                       status = diffproject(p1, pb1.p_path, p2, pb2.p_path);
+               else if (balance(p1, &pb1, &pb2) == NO)
+                       exit(2);
+               else
+                       status = diffdir(p1, pb1.p_path, p2, pb2.p_path);
+               }
+       else if (pathtyp2 == P_IFPROOT || pathtyp2 == P_IFHOME)
+               {
+               if (balance(p2, &pb2, &pb1) == NO)
+                       exit(2);
+               else
+                       status = diffdir(p1, pb1.p_path, p2, pb2.p_path);
+               }
+       else    {
+               status = diffdir(p1, pb1.p_path, p2, pb2.p_path);
+               }
+
+       if (status > 1)
+               status = 2;
+       exit(status);
+}
+
+
+
+/*
+ * balance() balances a PATH struct given a project and a directory or file.
+ * If a regular directory or file, then it is assumed to be relative to the
+ * current working project directory. Returns NO if balancing fails, otherwise
+ * YES. The project pathname p1 is updated to reflect the balancing.
+ */
+balance(p1, pb1, pb2)
+       char *p1;                       /* we know this is a project root dir */
+       PATH *pb1;                      /* project root directory buffer */
+       PATH *pb2;                      /* (project) directory or file buffer */
+{
+       char *pathcat();                /* regular pathname concatenation */
+       char *ppathcat();               /* project pathname concatenation */
+       int getcpd();                   /* get current working project dir */
+       int read_path();                /* read project or regular pathname */
+       PATH cpathbuf;                  /* current pathname struct buffer */
+
+       if ((pb2->p_mode&P_IFMT) == P_IFPDIR)
+               {
+               ppathcat(p1, p1, pb2->p_alias);
+               return(read_path(p1, pb1));
+               }
+       else if (*pb2->p_path == _RDIRC || getcpd(&cpathbuf) != 1)
+               {
+               warn("don't know which project directory to use in %s", p1);
+               return(NO);
+               }
+       else    {
+               ppathcat(p1, p1, cpathbuf.p_alias);
+               pathcat(p1, p1, pb2->p_path);
+               return(read_path(p1, pb1));
+               }
+}
+
+
+
+/*
+ * diffdir() compares two directories or files. Returns whatever diff()
+ * returns.
+ */
+diffdir(pp1, d1, pp2, d2)
+       char *pp1;                      /* project pathname */
+       char *d1;                       /* directory or file pathname */
+       char *pp2;                      /* project pathname */
+       char *d2;                       /* directory or file pathname */
+{
+       static int have_printed;        /* has printing already been done? */
+       int diff();                     /* fork diff program */
+       int iargi;                      /* argument index */
+
+       if (have_printed)
+               putchar('\n');
+       have_printed = 1;
+       printf("==> ");
+       for (iargi = 0; iargi < NARGI; iargi++)
+               printf("%s ", NARGV[iargi]);
+       printf("%s %s <==\n", pp1, pp2);
+       fflush(stdout);
+
+       if (EXECUTE == NO)
+               return(0);
+
+       NARGV[NARGI] = d1;
+       NARGV[NARGI+1] = d2;
+       return(diff(NARGV));
+}
+
+
+
+/*
+ * diffproject() compares two projects, recursively if necessary. Returns
+ * 0 if no differences, 1 if some, 2 if trouble.
+ */
+diffproject(pp1, p1, pp2, p2)
+       char *pp1;                      /* project pathname */
+       char *p1;                       /* project root directory pathname */
+       char *pp2;                      /* project pathname */
+       char *p2;                       /* project root directory pathname */
+{
+       int closepdb();                 /* close database */
+       int diffpdtree();               /* diff project directory tree */
+       int diffptree();                /* diff tree of projects */
+       int errpdb();                   /* print database error message */
+       int pdtmatch();                 /* match project dir type label expr */
+       int status = 0;                 /* return status */
+       PATH *pd;                       /* pathname struct pointer */
+       PATH *readpld();                /* read project link directory entry */
+       PDB *openpdb();                 /* open database */
+       PDB *pldp;                      /* project link directory stream */
+       PTREE *proot;                   /* root of project tree */
+       PTREE *pdroot;                  /* root of project directory tree */
+       PTREE *ptree();                 /* search and insert in proj dir tree */
+       void ptreerm();                 /* remove project directory tree */
+
+       proot = NULL;
+       pdroot = NULL;
+
+       /* read PLDNAME project link directory belonging to p1 */
+       if ((pldp = openpdb(PLDNAME, p1, "r")) == NULL)
+               {
+               errpdb((PDB *) NULL);
+               return(2);
+               }
+       while ((pd = readpld(pldp)) != NULL)
+               {
+               if (EQUAL(pd->p_alias, PARENTPROJECT))
+                       continue;
+               else if (EQUAL(pd->p_alias, CURPROJECT))
+                       {
+                       if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES)
+                               pdroot = ptree(pdroot, "", pd->p_path, CNULL);
+                       }
+               else if (pd->p_mode == P_IFPROOT)
+                       {
+                       if (RECURSIVE)
+                               proot = ptree(proot, pd->p_alias, pd->p_path, CNULL);
+                       }
+               else if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES)
+                       pdroot = ptree(pdroot, pd->p_alias, pd->p_path, CNULL);
+               }
+       closepdb(pldp);
+
+       /* read PLDNAME project link directory belonging to p2 */
+       if ((pldp = openpdb(PLDNAME, p2, "r")) == NULL)
+               {
+               errpdb((PDB *) NULL);
+               return(2);
+               }
+       while ((pd = readpld(pldp)) != NULL)
+               {
+               if (EQUAL(pd->p_alias, PARENTPROJECT))
+                       continue;
+               else if (EQUAL(pd->p_alias, CURPROJECT))
+                       {
+                       if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES)
+                               pdroot = ptree(pdroot, "", CNULL, pd->p_path);
+                       }
+               else if (pd->p_mode == P_IFPROOT)
+                       {
+                       if (RECURSIVE)
+                               proot = ptree(proot, pd->p_alias, CNULL, pd->p_path);
+                       }
+               else if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES)
+                       pdroot = ptree(pdroot, pd->p_alias, CNULL, pd->p_path);
+               }
+       closepdb(pldp);
+
+       /* diff project directory tree */
+       status |= diffpdtree(pdroot, pp1, pp2);
+       ptreerm(pdroot);
+
+       /* diff subprojects */
+       status |= diffptree(proot, pp1, pp2);
+       ptreerm(proot);
+
+       return(status);
+}
+
+
+
+/*
+ * diffpdtree() compares project directories in a project directory tree.
+ */
+diffpdtree(p, pp1, pp2)
+       PTREE *p;                       /* current node in project dir tree */
+       char *pp1;                      /* project pathname */
+       char *pp2;                      /* project pathname */
+{
+       char ppathbuf1[PPATHSIZE];      /* project pathname buffer */
+       char ppathbuf2[PPATHSIZE];      /* project pathname buffer */
+       char *ppathcat();               /* project pathname concantenation */
+       int diffdir();                  /* compare directories or files */
+       int status = 0;                 /* return status */
+       void printonly();               /* print "only in project ..." mesg */
+
+       if (p == NULL)
+               return(0);
+       status |= diffpdtree(p->left, pp1, pp2);
+       if (p->pd1 == NULL)
+               printonly(pp2, p->alias);
+       else if (p->pd2 == NULL)
+               printonly(pp1, p->alias);
+       else    {
+               ppathcat(ppathbuf1, pp1, p->alias);
+               ppathcat(ppathbuf2, pp2, p->alias);
+               status |= diffdir(ppathbuf1, p->pd1, ppathbuf2, p->pd2);
+               }
+       status |= diffpdtree(p->right, pp1, pp2);
+       return(status);
+}
+
+
+
+/*
+ * diffptree() compares projects in a project tree.
+ */
+diffptree(p, pp1, pp2)
+       PTREE *p;                       /* current node in project tree */
+       char *pp1;                      /* project pathname */
+       char *pp2;                      /* project pathname */
+{
+       char ppathbuf1[PPATHSIZE];      /* project pathname buffer */
+       char ppathbuf2[PPATHSIZE];      /* project pathname buffer */
+       char *ppathcat();               /* project pathname concantenation */
+       int diffproject();              /* compare projects */
+       int status = 0;                 /* return status */
+       void printonly();               /* print "only in project ..." mesg */
+
+       if (p == NULL)
+               return(0);
+       status |= diffptree(p->left, pp1, pp2);
+       if (p->pd1 == NULL)
+               printonly(pp2, p->alias);
+       else if (p->pd2 == NULL)
+               printonly(pp1, p->alias);
+       else    {
+               ppathcat(ppathbuf1, pp1, p->alias);
+               ppathcat(ppathbuf2, pp2, p->alias);
+               status |= diffproject(ppathbuf1, p->pd1, ppathbuf2, p->pd2);
+               }
+       status |= diffptree(p->right, pp1, pp2);
+       return(status);
+}
+
+
+
+/*
+ * printonly() prints "only in project ..." message.
+ */
+void
+printonly(project, pdirname)
+       char *project;                  /* project pathname */
+       char *pdirname;                 /* unique project directory */
+{
+       printf("Only in project %s: %s\n", project,
+             (*pdirname == '\0') ? CURPROJECT : pdirname);
+       fflush(stdout);
+}
+
+
+
+/*
+ * read_path() loads a PATH struct given a regular or project pathname.
+ * Returns integer NO if an invalid pathname or non-existent target,
+ * otherwise YES.
+ */
+read_path(pathname, pb)
+       char *pathname;                 /* regular or project pathname */
+       PATH *pb;                       /* pathname struct buffer */
+{
+       int readpath();                 /* read project or regular pathname */
+
+       if (readpath(pathname, pb) == -1 || (pb->p_mode & P_IFMT) == P_IFNEW)
+               {
+               patherr(pathname);
+               return(NO);
+               }
+       return(YES);
+}
diff --git a/usr/src/new/new/spms/src/bin/pdiff/ptree.c b/usr/src/new/new/spms/src/bin/pdiff/ptree.c
new file mode 100644 (file)
index 0000000..1f201f2
--- /dev/null
@@ -0,0 +1,89 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include "null.h"
+#include "ptree.h"
+/*
+ * ptree() searchs for a project directory name in a binary tree. If the
+ * search is unsuccessful, a new node is added to the tree.
+ */
+PTREE *
+ptree(p, alias, pd1, pd2)
+       PTREE *p;                       /* current node pointer */
+       char *alias;                    /* project directory alias */
+       char *pd1;                      /* project directory pathname */
+       char *pd2;                      /* project directory pathname */
+{
+       char *strsav();                 /* save a string somewhere */
+       int comp;                       /* compare key values */
+       int strcmp();                   /* string comparison */
+       PTREE *palloc();                /* allocate a tree node */
+
+       if (p == NULL)
+               {                       /* a new alias has arrived */
+               if ((p = palloc()) == NULL || (p->alias = strsav(alias)) == NULL)
+                       goto nomemory;
+               if (pd1 != NULL)
+                       {
+                       if ((p->pd1 = strsav(pd1)) == NULL)
+                               goto nomemory;
+                       p->pd2 = NULL;
+                       }
+               else    {
+                       if ((p->pd2 = strsav(pd2)) == NULL)
+                               goto nomemory;
+                       p->pd1 = NULL;
+                       }
+               p->left  = p->right = NULL;
+               }
+       else if ((comp = strcmp(alias, p->alias)) < 0)
+               p->left = ptree(p->left, alias, pd1, pd2);
+       else if (comp > 0)
+               p->right = ptree(p->right, alias, pd1, pd2);
+       else if (comp == 0)
+               if ((p->pd2 = strsav(pd2)) == NULL)
+                       {
+nomemory:              warn("out of memory");
+                       exit(2);
+                       }
+       return(p);
+       }
+
+
+
+/*
+ * ptreerm() removes a project directory tree.
+ */
+void
+ptreerm(p)
+       PTREE *p;                       /* current node pointer */
+{
+       if (p != NULL)
+               {
+               if (p->left != NULL)
+                       ptreerm(p->left);
+               if (p->right != NULL)
+                       ptreerm(p->right);
+               free(p->alias);
+               if (p->pd1 != NULL)
+                       free(p->pd1);
+               if (p->pd2 != NULL)
+                       free(p->pd2);
+               free((char *) p);
+               }
+}
+
+
+
+/*
+ * palloc allocates memory for a project tree node.
+ */
+static PTREE *
+palloc()
+{
+       char *malloc();                 /* memory allocator */
+
+       return((PTREE *) malloc(sizeof(PTREE)));
+       }
diff --git a/usr/src/new/new/spms/src/bin/pdiff/ptree.h b/usr/src/new/new/spms/src/bin/pdiff/ptree.h
new file mode 100644 (file)
index 0000000..c4e7036
--- /dev/null
@@ -0,0 +1,16 @@
+/* $Header$ */
+
+/*
+ * project comparison tree definitions
+ *
+ * Author: Peter J. Nicklin
+ */
+
+typedef struct _pnode
+       {
+       char   *alias;                  /* project directory alias */
+       char   *pd1;                    /* project directory pathname */
+       char   *pd2;                    /* project directory pathname */
+       struct _pnode *left;            /* left child */
+       struct _pnode *right;           /* right child */
+       } PTREE;
diff --git a/usr/src/new/new/spms/src/bin/pexec/Pexec.c b/usr/src/new/new/spms/src/bin/pexec/Pexec.c
new file mode 100644 (file)
index 0000000..689d6d4
--- /dev/null
@@ -0,0 +1,170 @@
+static char *rcsid = "$Header$";
+/*
+ * pexec - execute command over project hierarchy
+ *
+ * Author: Peter J. Nicklin
+ */
+#include "bin.h"
+#include "macro.h"
+#include "getarg.h"
+#include "null.h"
+#include "path.h"
+#include "pdtyp.h"
+#include "slist.h"
+#include "spms.h"
+#include "yesno.h"
+
+char *COMMAND;                         /* command string to be executed */
+char *PGN = "pexec";                   /* program name */
+char *SHELLNAME;                       /* name of command shell */
+char *SHELLPATH;                       /* pathname of command shell */
+int CSHELL = 0;                                /* use csh or sh? */
+int CSHRC = NO;                                /* execute .cshrc if csh shell */
+int DEBUG = NO;                                /* print pexec debugging info */
+int ERRSTATUS = 1;                     /* pexec error status */
+int EXECUTE = YES;                     /* execute command? */
+int IGNORE_BAD_EXIT = NO;              /* exit if command doesn't return 0 */
+int NOQUERY;                           /* query user about quitting? */
+int PRINT_HEADING = YES;               /* print headings for project dirs */
+int PVINDEX;                           /* environ index for PROJECT variable */
+PDTYP PDIRTYP;                         /* project directory type labels list */
+SLIST *ENVLIST;                                /* project environment variable list */
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int PPDEBUG;             /* project pathname debug flag */
+       char *argvtos();                /* convert cmd args to string */
+       char *getcwp();                 /* get current working project */
+       char *getshell();               /* get command shell pathname */
+       char *pathtail();               /* remove pathname head */
+       char *ppathname = CURPROJECT;   /* project pathname */
+       int atoi();                     /* string to integer conversion */
+       int build_pdset();              /* create set of project dirs */
+       int ch_dir();                   /* change current working directory */
+       int check_pdset();              /* check ordering of set of proj dirs */
+       int exec_pdset();               /* execute cmds in set of proj dirs */
+       int execcmd();                  /* execute command in directory */
+       int getpvindex();               /* get PROJECT env. variable index */
+       int pdtparse();                 /* parse boolean type label expr */
+       int status = 0;                 /* exit status */
+       int xppath();                   /* expand project pathname */
+       PATH pathbuf;                   /* pathname struct buffer */
+       SLIST *slinit();                /* initialize list */
+       void debug_pdset();             /* print dirs + types after sorting */
+       void init_pdset();              /* initialize set of project dirs */
+       void print_title();             /* print project directory title */
+       void sort_pdset();              /* sort set of project dirs */
+
+       {
+       register char *s;               /* option pointer */
+       while (--argc > 0 && **++argv == '-')
+               {
+               for (s = argv[0]+1; *s != '\0'; s++)
+                       switch (*s)
+                               {
+                               case '?':
+                                       NOQUERY++;
+                                       break;
+                               case 'D':
+                                       DEBUG = YES;
+                                       PPDEBUG = YES;
+                                       break;
+                               case 'P':
+                                       ppathname = GETARG(s);
+                                       if (*ppathname == '\0')
+                                               {
+                                               warn("missing project name");
+                                               status = 1;
+                                               }
+                                       goto endfor;
+                               case 'T':
+                                       if (pdtparse(GETARG(s), &PDIRTYP) == NO)
+                                               status = 1;
+                                       goto endfor;
+                               case 'X':
+                                       ERRSTATUS = atoi(GETARG(s));
+                                       goto endfor;
+                               case 'c':
+                                       CSHRC = YES;
+                                       break;
+                               case 'i':
+                                       IGNORE_BAD_EXIT = YES;
+                                       break;
+                               case 'q':
+                                       PRINT_HEADING = NO;
+                                       break;
+                               case 'x':
+                                       EXECUTE = NO;
+                                       break;
+                               default:
+                                       warn("bad option -%c", *s);
+                                       status = 1;
+                                       goto endfor;
+                               }
+               endfor: continue;
+               }
+       }
+       if (status == 1 || argc < 1)
+               {
+               warn("usage: pexec [-?ciqx] [-P pdirname] [-T typexpr] command");
+               pxexit();
+               }
+       /*
+        * The PROJECT environment variable must exist because
+        * it has to be modified before each command execution.
+        */
+       if ((PVINDEX = getpvindex()) < 0)
+               {
+               warn("no project environment");
+               pxexit();
+               }
+
+       if ((COMMAND = argvtos(argc, argv)) == NULL)
+               pxexit();
+       SHELLPATH = getshell();
+       SHELLNAME = pathtail(SHELLPATH);
+       if (EQUAL(SHELLNAME, pathtail(CSH)))
+               CSHELL++;
+
+       /* convert project pathname to regular pathname */
+       if (xppath(ppathname, &pathbuf) == -1)
+               {
+               patherr(ppathname);
+               pxexit();
+               }
+       else switch (pathbuf.p_mode & P_IFMT)
+               {
+               case P_IFNEW:
+               case P_IFREG:
+                       warn("%s: no such project or project directory", ppathname);
+                       pxexit();
+               case P_IFPDIR:
+                       IGNORE_BAD_EXIT = NO;
+                       if (PRINT_HEADING == YES)
+                               print_title(ppathname);
+                       ch_dir(pathbuf.p_path);
+                       if (EXECUTE == YES)
+                               status |= execcmd(pathbuf.p_project);
+                       break;
+               case P_IFHOME:
+               case P_IFPROOT:
+                       if (PDIRTYP.pfxsize == 0)
+                               status |= execproject(ppathname, pathbuf.p_path);
+                       else    {
+                               ENVLIST = slinit();
+                               init_pdset();
+                               if (build_pdset(ppathname, pathbuf.p_path) != 0)
+                                       pxexit();
+                               sort_pdset();
+                               if (DEBUG == YES)
+                                       debug_pdset();
+                               if (check_pdset() != 0)
+                                       pxexit();
+                               status |= exec_pdset();
+                               }
+                       break;
+               }
+       exit(status);
+}
diff --git a/usr/src/new/new/spms/src/bin/pexec/exec.c b/usr/src/new/new/spms/src/bin/pexec/exec.c
new file mode 100644 (file)
index 0000000..e02e512
--- /dev/null
@@ -0,0 +1,123 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "macro.h"
+#include "null.h"
+#include "path.h"
+#include "pdb.h"
+#include "pdlist.h"
+#include "pld.h"
+#include "slslist.h"
+#include "spms.h"
+#include "yesno.h"
+
+/*
+ * execlist() executes a project directory list. Returns non-zero error
+ * status if error.
+ */
+execlist(pdlist)
+       PDLIST *pdlist;                 /* project directory list */
+{
+       extern int ERRSTATUS;           /* pexec error status */
+       extern int EXECUTE;             /* execute command? */
+       extern int PRINT_HEADING;       /* print headings for project dirs */
+       int ch_dir();                   /* change current working directory */
+       int execcmd();                  /* execute command in directory */
+       int status = 0;                 /* return status */
+       PDBLK *pdblk;                   /* project directory list block */
+       void print_title();             /* print project directory title */
+
+       for (pdblk = pdlist->head; pdblk != NULL; pdblk = pdblk->next)
+               {
+               if (PRINT_HEADING == YES)
+                       print_title(pdblk->ppath);
+               if (ch_dir(pdblk->rpath) == NO)
+                       status = ERRSTATUS;
+               else if (EXECUTE == YES)
+                       status |= execcmd(pdblk->project);
+               }
+       return(status);
+}
+
+
+
+/*
+ * execproject() builds a project directory list and executes commands
+ * within directories on that list.
+ */
+execproject(ppathname, pathname)
+       char *ppathname;                /* project root dir project pathname */
+       char *pathname;                 /* regular project root dir pathname */
+{
+       extern int ERRSTATUS;           /* pexec error status */
+       char ppathbuf[PPATHSIZE];       /* project pathname buffer */
+       char *pdprepend();              /* prepend project directory */
+       char *ppathcat();               /* project pathname concatenation */
+       char *slsprepend();             /* prepend key+string */
+       int closepdb();                 /* close database */
+       int errpdb();                   /* print database error message */
+       int execlist();                 /* execute project directory list */
+       int slssort();                  /* sort list */
+       int status = 0;                 /* return status */
+       int strcmp();                   /* string comparison */
+       PATH *pd;                       /* pathname struct pointer */
+       PATH *readpld();                /* read project link directory entry */
+       PDB *openpdb();                 /* open database */
+       PDB *pldp;                      /* project link directory stream */
+       PDLIST *pdinit();               /* initialize project directory list */
+       PDLIST *pdlist;                 /* project directory list */
+       SLSBLK *pblk;                   /* project list block */
+       SLSLIST *plist;                 /* project list */
+       SLSLIST *slsinit();             /* initialize list */
+       void pdrm();                    /* remove project directory list */
+       void pdsort();                  /* sort project directory list */
+       void slsrm();                   /* remove list item */
+
+       pdlist = pdinit();
+       plist = slsinit();
+
+       /* read PLDNAME project link directory */
+       if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL)
+               return(errpdb((PDB *) NULL));
+       while ((pd = readpld(pldp)) != NULL)
+               {
+               if (EQUAL(pd->p_alias, PARENTPROJECT))
+                       continue;
+
+               if (EQUAL(pd->p_alias, CURPROJECT))
+                       {
+                       pdprepend(ppathname, pd->p_path, pathname, pdlist);
+                       }
+               else if (pd->p_mode == P_IFPROOT)
+                       {
+                       if (slsprepend(pd->p_alias, pd->p_path, plist) == NULL)
+                               pxexit();
+                       }
+               else    {
+                       ppathcat(ppathbuf, ppathname, pd->p_alias);
+                       pdprepend(ppathbuf, pd->p_path, pathname, pdlist);
+                       }
+               }
+       if (closepdb(pldp) != 0)
+               status = ERRSTATUS;
+
+       /* sort and execute project directories */
+       pdsort(strcmp, pdlist);
+       status |= execlist(pdlist);
+       pdrm(pdlist);
+
+       /* execute subprojects */
+       if (slssort(strcmp, plist) == NO)
+               pxexit();
+       for (pblk = plist->head; pblk != NULL; pblk = pblk->next)
+               {
+               ppathcat(ppathbuf, ppathname, pblk->key);
+               status |= execproject(ppathbuf, pblk->string);
+               }
+       slsrm(CNULL, plist);
+
+       return(status);
+}
diff --git a/usr/src/new/new/spms/src/bin/pexec/misc.c b/usr/src/new/new/spms/src/bin/pexec/misc.c
new file mode 100644 (file)
index 0000000..7271d33
--- /dev/null
@@ -0,0 +1,84 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "macro.h"
+#include "yesno.h"
+
+/*
+ * ch_dir changes current working directory. Returns integer YES if
+ * successful, otherwise NO.
+ */
+ch_dir(pathname)
+       char *pathname;                 /* pathname of destination directory */
+{
+       extern int IGNORE_BAD_EXIT;     /* exit if command doesn't return 0 */
+
+       if (!CHDIR(pathname))
+               {
+               pperror(pathname);
+               if (IGNORE_BAD_EXIT == NO)
+                       pxexit();
+               return(NO);
+               }
+       return(YES);
+}
+
+
+
+/*
+ * getpvindex() returns the location of the PROJECT environment
+ * variable in the global cell environ.
+ */
+getpvindex()
+{
+       extern char **environ;          /* global environment cell */
+       register int i;                 /* location of PROJECT env. variable */
+       int strncmp();                  /* compare n characters */
+
+       for (i = 0; environ[i] != NULL; i++)
+               if (strncmp(environ[i], "PROJECT=", 8) == 0)
+                       return(i);
+       return(-1);
+}
+
+
+
+/*
+ * nomorecore() prints a warning error message and then exits.
+ */
+nomorecore()
+{
+       warn("out of memory");
+       pxexit();
+}
+
+
+
+/*
+ * print_title prints a project directory title.
+ */
+void
+print_title(ppathname)
+       char *ppathname;                /* project directory pathname */
+{
+       static int done_command;        /* has a command been done? */
+
+       printf((done_command) ? "\n==> %s <==\n" : "==> %s <==\n", ppathname);
+       fflush(stdout);
+       done_command = 1;
+}
+
+
+
+/*
+ * pxexit() calls exit(ERRSTATUS).
+ */
+pxexit()
+{
+       extern int ERRSTATUS;           /* pexec error status */
+
+       exit(ERRSTATUS);
+}
diff --git a/usr/src/new/new/spms/src/bin/pexec/pdlist.c b/usr/src/new/new/spms/src/bin/pexec/pdlist.c
new file mode 100644 (file)
index 0000000..c5f77a5
--- /dev/null
@@ -0,0 +1,135 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include "null.h"
+#include "pdlist.h"
+#include "yesno.h"
+
+/*
+ * pdinit() returns a pointer to the head block of a new project directory
+ * list, or dies if out of memory.
+ */
+PDLIST *
+pdinit()
+{
+       char *malloc();                 /* memory allocator */
+       PDLIST *pdlist;                 /* pointer to list head block */
+
+       if ((pdlist = (PDLIST *) malloc(sizeof(PDLIST))) == NULL)
+               nomorecore();
+       pdlist->nd = 0;
+       pdlist->head = NULL;
+       return(pdlist);
+}
+
+
+
+/*
+ * pdprepend() saves null-terminated project directory pathnames
+ * somewhere and inserts a pointer to the directory at the head of list
+ * pdlist. Returns a pointer to the pathname, or dies if out of
+ * memory.
+ */
+char *
+pdprepend(ppathname, pathname, project, pdlist)
+       char *ppathname;                /* project directory project pathname */
+       char *pathname;                 /* project directory regular pathname */
+       char *project;                  /* project directory's project */
+       PDLIST *pdlist;                 /* pointer to list head block */
+{
+       char *malloc();                 /* memory allocator */
+       char *strcpy();                 /* string copy */
+       int strlen();                   /* string length */
+       PDBLK *pdbptr;                  /* pointer to list block */
+
+       if (pdlist == NULL)
+               return(NULL);
+       if ((pdbptr = (PDBLK *) malloc(sizeof(PDBLK))) == NULL ||
+           (pdbptr->ppath = malloc((unsigned)(strlen(ppathname)+1))) == NULL ||
+           (pdbptr->rpath = malloc((unsigned)(strlen(pathname)+1))) == NULL)
+               nomorecore();
+       strcpy(pdbptr->rpath, pathname);
+       strcpy(pdbptr->ppath, ppathname);
+       pdbptr->project = project;
+       pdbptr->next = pdlist->head;
+       pdlist->head = pdbptr;
+       pdlist->nd++;
+       return(pdbptr->ppath);
+}
+
+
+
+/*
+ * pdrm() removes a project directory list.
+ */
+void
+pdrm(pdlist)
+       PDLIST *pdlist;                 /* pointer to list head block */
+{
+       PDBLK *nxtblk;                  /* next list block */
+
+       while (pdlist->head != NULL)
+               {
+               nxtblk = pdlist->head->next;
+               free(pdlist->head->ppath);
+               free(pdlist->head->rpath);
+               free((char *) pdlist->head);
+               pdlist->head = nxtblk;
+               }
+       free((char *) pdlist);
+}
+
+
+
+/*
+ * pdsort() sorts list pdlist according to comparison function compar().
+ * compar() is to be called with two arguments and must return an integer
+ * greater than, equal to, or less than 0, depending on the lexicographic
+ * relationship between the two arguments.
+ */
+
+static int (*sscmp)();                 /* string compare function */
+
+void
+pdsort(compar, pdlist)
+       int (*compar)();                /* compare two strings */
+       PDLIST *pdlist;                 /* pointer to list head block */
+{
+       char *malloc();                 /* memory allocator */
+       int bpi;                        /* block pointer array index */
+       int comparb();                  /* compare 2 list blocks */
+       PDBLK **bp;                     /* pointer to block pointer array */
+       PDBLK *curblk;                  /* current list block */
+
+       if (pdlist->nd <= 0)
+               return;
+       else if ((bp = (PDBLK **) malloc((unsigned)pdlist->nd*sizeof(PDBLK *)))==NULL)
+               nomorecore();
+       for (bpi=0, curblk=pdlist->head; curblk != NULL; bpi++, curblk=curblk->next)
+               bp[bpi] = curblk;
+
+       sscmp = compar;
+       qsort((char *) bp, pdlist->nd, sizeof(PDBLK *), comparb);
+
+       for (bpi=0, curblk=pdlist->head=bp[bpi++]; bpi < pdlist->nd; bpi++)
+               curblk = curblk->next = bp[bpi];
+       curblk->next = NULL;
+       
+       free((char *) bp);
+}
+
+
+
+/*
+ * comparb() compares project directory pathnames in 2 list blocks.
+ * Returns whatever sscmp() returns. sscmp() is a string compare function.
+ */
+static int
+comparb(b1, b2)
+       PDBLK **b1;                     /* block pointer */
+       PDBLK **b2;                     /* block pointer */
+{
+       return(sscmp((*b1)->ppath, (*b2)->ppath));
+}
diff --git a/usr/src/new/new/spms/src/bin/pexec/pdlist.h b/usr/src/new/new/spms/src/bin/pexec/pdlist.h
new file mode 100644 (file)
index 0000000..03027e0
--- /dev/null
@@ -0,0 +1,37 @@
+/* $Header$ */
+
+/*
+ * Project directory list definitions
+ *
+ * Author: Peter J. Nicklin
+ */
+
+/*
+ * Singly-linked project directory list macros
+ */
+#define pdnum(pdlist)  (pdlist)->nd
+/*
+ * Singly-linked project directory list block
+ */
+typedef struct _pdblk
+       {
+       char *ppath;                    /* project directory project pathname */
+       char *rpath;                    /* project directory regular pathname */
+       char *project;                  /* project directory's project */
+       struct _pdblk *next;            /* ptr to next list block */
+       } PDBLK;
+/*
+ * Singly-linked project directory list head block
+ */
+typedef struct _pdlisthb
+       {
+       int nd;                         /* number of directories in list */
+       PDBLK *head;                    /* pointer to first list block */
+       } PDLIST;
+/*
+ * Functions defined for singly-linked project directory list operations
+ */
+extern PDLIST *pdinit();               /* initialize project directory list */
+extern char *pdprepend();              /* prepend project directory */
+extern void pdrm();                    /* remove project directory list */
+extern void pdsort();                  /* sort project directory list */
diff --git a/usr/src/new/new/spms/src/bin/pexec/pdset.c b/usr/src/new/new/spms/src/bin/pexec/pdset.c
new file mode 100644 (file)
index 0000000..bdda7c3
--- /dev/null
@@ -0,0 +1,474 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "hash.h"
+#include "macro.h"
+#include "null.h"
+#include "path.h"
+#include "pdb.h"
+#include "pdset.h"
+#include "pdlist.h"
+#include "pdtyp.h"
+#include "pld.h"
+#include "slist.h"
+#include "slslist.h"
+#include "spms.h"
+#include "truefalse.h"
+#include "yesno.h"
+
+#define INCRPDIRS       50             /* amount to increase pdir ptr array */
+#define MAXPDIRS       100             /* initial size of proj dir ptr array */
+
+extern char *PGN;                      /* program name */
+extern PDTYP PDIRTYP;                  /* project directory type labels list */
+
+static int Ipdirs;                     /* attribute block array index */
+static int Maxpdirs = MAXPDIRS;                /* maximum no. of project dirs */
+static int Ntypes;                     /* number of unique type labels */
+static PDSET **Pdarray;                        /* project dir attribute block array */
+static short *Maptyp;                  /* unique type label mapping array */
+static TYPES *Typstat;                 /* type label statistics */
+
+/*
+ * add_pdset() adds a project directory to the set of project directories
+ * which satisfy a boolean project directory type label expression. Only
+ * those type labels which satisfy the boolean expression are included with
+ * the project directory. To determine which type labels qualify, the
+ * postfix expression is scanned from right to left. Type labels within a
+ * negated expression are ignored. For example, in the postfix equivalent
+ * of expression "src & !(cmd | lib)" (that is: src cmd lib | ! &),
+ * even if both "src" and "cmd" are found, "src" is the only type label
+ * which could qualify.
+ */
+void
+add_pdset(postfix, ppathname, pathname, project)
+       register PDTYP *postfix;        /* postfix expression struct */
+       char *ppathname;                /* project directory project pathname */
+       char *pathname;                 /* project directory pathname */
+       char *project;                  /* project directory's project */
+{
+       register int i;                 /* postfix expression index */
+       register int opcount;           /* count of expected operands */
+       char *pdtcpy();                 /* copy project directory type label */
+       char *realloc();                /* reallocate memory block */
+       char type[TYPESIZE];            /* project dir type label buffer */
+       PDSET *savepdir();              /* save pdir attribute blk somewhere */
+       void savetype();                /* save type label */
+
+       if (Ipdirs >= Maxpdirs)
+               {
+               Maxpdirs += INCRPDIRS;
+               if ((Pdarray = (PDSET **) realloc((char *)Pdarray,
+                              (unsigned)Maxpdirs*sizeof(PDSET *))) == NULL)
+                       nomorecore();
+               }
+       Pdarray[Ipdirs] = savepdir(ppathname, pathname, project);
+
+       opcount = 0;
+       for (i = (postfix->pfxsize)-1; i >= 0;)
+               {
+               switch ((postfix->pfx)[i].p_class)
+                       {
+                       case B_ID:
+                               if ((postfix->pfx)[i].p_sw == TRUE)
+                                       {
+                                       pdtcpy(type, (postfix->pfx)[i].p_label);
+                                       savetype(type, i);
+                                       }
+                               break;
+                       case B_OR:
+                       case B_AND:
+                               if ((postfix->pfx)[i].p_sw == FALSE)
+                                       opcount += 2;
+                               break;
+                       case B_NOT:
+                               /* always skip !subexpr */
+                               opcount += 1;
+                               break;
+                       }
+               /* skip false subexpression */
+               for (--i; opcount > 0; i--)
+                       switch ((postfix->pfx)[i].p_class)
+                               {
+                               case B_ID:
+                                       opcount -= 1;
+                                       break;
+                               case B_OR:
+                               case B_AND:
+                                       opcount += 1;
+                                       break;
+                               case B_NOT:
+                                       break;
+                               }
+               }
+       Ipdirs++;
+}
+
+
+
+/*
+ * build_pdset() builds a set of project directories which satisfy a boolean
+ * project directory type label expression.
+ */
+build_pdset(ppathname, pathname)
+       char *ppathname;                /* project root dir project pathname */
+       char *pathname;                 /* regular project root dir pathname */
+{
+       extern int ERRSTATUS;           /* pexec error status */
+       extern SLIST *ENVLIST;          /* project environment variable list */
+       char ppathbuf[PPATHSIZE];       /* project pathname buffer */
+       char *ppathcat();               /* project pathname concatenation */
+       char *pv;                       /* PROJECT environment variable */
+       char *slprepend();              /* prepend key */
+       char *slsprepend();             /* prepend key+string */
+       int closepdb();                 /* close database */
+       int errpdb();                   /* print database error message */
+       int pdtmatch();                 /* match project dir type label expr */
+       int status = 0;                 /* return status */
+       PATH *pd;                       /* pathname struct pointer */
+       PATH *readpld();                /* read project link directory entry */
+       PDB *openpdb();                 /* open database */
+       PDB *pldp;                      /* project link directory stream */
+       SLSBLK *pblk;                   /* project list block */
+       SLSLIST *plist;                 /* project list */
+       SLSLIST *slsinit();             /* initialize list */
+       void add_pdset();               /* add to set of project dirs */
+       void slsrm();                   /* remove list item */
+
+       if ((pv = slprepend(pathname, ENVLIST)) == NULL)
+               pxexit();
+       plist = slsinit();
+
+       /* read PLDNAME project link directory */
+       if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL)
+               return(errpdb((PDB *) NULL));
+       while ((pd = readpld(pldp)) != NULL)
+               {
+               if (EQUAL(pd->p_alias, PARENTPROJECT))
+                       continue;
+
+               if (EQUAL(pd->p_alias, CURPROJECT))
+                       {
+                       if (pdtmatch(&PDIRTYP, pd->p_type) == YES)
+                               add_pdset(&PDIRTYP, ppathname, pd->p_path, pv);
+                       }
+               else if (pd->p_mode == P_IFPROOT)
+                       {
+                       if (slsprepend(pd->p_alias, pd->p_path, plist) == NULL)
+                               pxexit();
+                       }
+               else if (pdtmatch(&PDIRTYP, pd->p_type) == YES)
+                       {
+                       ppathcat(ppathbuf, ppathname, pd->p_alias);
+                       add_pdset(&PDIRTYP, ppathbuf, pd->p_path, pv);
+                       }
+               }
+       if (closepdb(pldp) != 0)
+               status = ERRSTATUS;
+
+       /* build project directory type label tree for subprojects */
+       for (pblk = plist->head; pblk != NULL; pblk = pblk->next)
+               {
+               ppathcat(ppathbuf, ppathname, pblk->key);
+               status |= build_pdset(ppathbuf, pblk->string);
+               }
+       slsrm(CNULL, plist);
+
+       return(status);
+}
+
+
+
+/*
+ * check_pdset() detects conflicting type label priorities by
+ * checking that project directories are sorted into ascending
+ * order according to priority. An error message is printed and
+ * 1 returned on conflict, otherwise zero.
+ */
+check_pdset()
+{
+       register int iPd;               /* proj dir block array index */
+       register int ityp;              /* type label block index */
+       register int lastpr;            /* previous type label priority */
+       register int prior;             /* project dir type label priority */
+       register PDSET **ptrPd;         /* Pdarray block array pointer */
+       int nsortyp;                    /* no. type label categories to sort */
+
+       nsortyp = 0;
+       for (ityp = 0; ityp < Ntypes; ityp++)
+               if (Typstat[ityp].t_sort)
+                       nsortyp++;
+       if (nsortyp < 2)
+               return(0);
+
+       for (ityp = 0; ityp < Ntypes; ityp++)
+               if (Typstat[ityp].t_sort)
+                       {
+                       for (ptrPd=Pdarray, iPd=Ipdirs; iPd > 0; ptrPd++, iPd--)
+                               if ((*ptrPd)->typblk[ityp].t_exist)
+                                       {
+                                       lastpr = (*ptrPd)->typblk[ityp].t_prior;
+                                       break;
+                                       }
+                       for (ptrPd++, iPd--; iPd > 0; ptrPd++, iPd--)
+                               {
+                               if ((*ptrPd)->typblk[ityp].t_exist)
+                                       {
+                                       prior = (*ptrPd)->typblk[ityp].t_prior;
+                                       if (prior < lastpr)
+                                               goto conflict;
+                                       lastpr = prior;
+                                       }
+                               }
+                       }
+       return(0);
+conflict:
+       fprintf(stderr, "%s:", PGN);
+       for (ityp = Ntypes-1; ityp >= 0; ityp--)
+               if (Typstat[ityp].t_sort)
+                       fprintf(stderr, (nsortyp-- > 1) ? " %s," :
+                               " %s: conflicting type label priorities\n",
+                               Typstat[ityp].t_name);
+       return(1);
+}
+
+
+
+/*
+ * debug_pdset() prints the sorted project directories together with
+ * the type labels that satisfy the boolean expression.
+ */
+void
+debug_pdset()
+{      
+       int iPd;                        /* project dir block array index */
+       int ityp;                       /* type label statistics array index */
+
+       for (iPd = 0; iPd < Ipdirs; iPd++)
+               {
+               fprintf(stderr, "%s:", Pdarray[iPd]->ppath);
+               for (ityp = 0; ityp < Ntypes; ityp++)
+                       if (Pdarray[iPd]->typblk[ityp].t_exist)
+                               fprintf(stderr," %s.%d",Typstat[ityp].t_name,
+                                       Pdarray[iPd]->typblk[ityp].t_prior);
+               putc('\n', stderr);
+               }
+}
+
+
+
+/*
+ * exec_pdset() executes a set of project directories. Returns non-zero
+ * error status if error.
+ */
+exec_pdset()
+{
+       extern int ERRSTATUS;           /* pexec error status */
+       extern int EXECUTE;             /* execute command? */
+       extern int PRINT_HEADING;       /* print headings for project dirs */
+       int ch_dir();                   /* change current working directory */
+       int execcmd();                  /* execute command in directory */
+       int iPd;                        /* project dir block array index */
+       int status = 0;                 /* return status */
+       void print_title();             /* print project directory title */
+
+       for (iPd = 0; iPd < Ipdirs; iPd++)
+               {
+               if (PRINT_HEADING == YES)
+                       print_title(Pdarray[iPd]->ppath);
+               if (ch_dir(Pdarray[iPd]->rpath) == NO)
+                       status = ERRSTATUS;
+               else if (EXECUTE == YES)
+                       status |= execcmd(Pdarray[iPd]->project);
+               }
+       return(status);
+}
+
+
+
+/*
+ * init_pdset() allocates an array of pointers (Pdarray) to project
+ * directory attribute blocks, and calculates the maximum number of type
+ * labels to be stored with each project directory based on the number of
+ * unique type labels in the boolean postfix type expression. An array
+ * (Typstat) is also created to maintain statistics on each brand of
+ * label.
+ *
+ * Hash table lookup is used in forming unique type labels and a
+ * mapping array is used to map the labels from the boolean postfix
+ * type label expression to the unique representation.
+ */
+#define UNIQTYPHASHSIZE                41
+
+void
+init_pdset()
+{
+       register int i;                 /* postfix type expression index */
+       char *malloc();                 /* memory allocator */
+       char *pfxcpy();                 /* copy string prefix */
+       char type[TYPESIZE];            /* project dir type label buffer */
+       HASH *htinit();                 /* initialize hash table */
+       HASH *uniqtyp;                  /* hash table of unique type labels */
+       HASHBLK *htb;                   /* hash table block pointer */
+       HASHBLK *htinstall();           /* install hash table entry */
+       HASHBLK *htlookup();            /* find hash table entry */
+       int nid;                        /* no. of ids in boolean expression */
+
+       /* project directory attribute block pointer array */
+       if ((Pdarray = (PDSET **) malloc((unsigned)Maxpdirs*sizeof(PDSET *))) == NULL)
+               nomorecore();
+
+       /* create postfix expression -> unique type label mapping array */
+       if ((Maptyp = (short *) malloc((unsigned)PDIRTYP.pfxsize*sizeof(short))) == NULL)
+               nomorecore();
+
+       /* create type label statistics array (estimate size first) */
+       nid = 0;
+       for (i = (PDIRTYP.pfxsize)-1; i >= 0; i--)
+               if ((PDIRTYP.pfx)[i].p_class == B_ID)
+                       nid++;
+       if ((Typstat = (TYPES *) malloc((unsigned)nid*sizeof(TYPES))) == NULL)
+               nomorecore();
+
+       /* unique type label determination */
+       uniqtyp = htinit(UNIQTYPHASHSIZE);
+       for (i = (PDIRTYP.pfxsize)-1; i >= 0; i--)
+               {
+               if ((PDIRTYP.pfx)[i].p_class != B_ID)
+                       continue;
+               pfxcpy(type, (PDIRTYP.pfx)[i].p_id);
+               if ((htb = htlookup(type, uniqtyp)) != NULL)
+                       {
+                       Maptyp[i] = htb->h_val;
+                       }
+               else    {
+                       if ((htb = htinstall(type,"",Ntypes,uniqtyp)) == NULL)
+                               nomorecore();
+                       Maptyp[i] = Ntypes;
+                       Typstat[Ntypes].t_name = htb->h_key;
+                       Typstat[Ntypes].t_ntl = Typstat[Ntypes].t_sort = 0;
+                       Ntypes++;
+                       }
+               }
+}
+
+
+
+/*
+ * pdbcmp() compares the type label priorities and project pathnames
+ * for two project directories. Type label priorities override the
+ * lexicographical relationship of the project pathnames. Conflicting
+ * priorities are not detected. For example, a conflict occurs if the
+ * first directory has type labels print.1 and update.2, whereas the
+ * second directory has type labels print.2 and update.1. Returns
+ * an integer less than, equal to, or greater than zero, depending on
+ * the relative priorities of the type labels or lexicographical ordering
+ * of the project pathnames.
+ */
+pdbcmp(b1, b2)
+       PDSET **b1;                     /* project directory block pointer */
+       PDSET **b2;                     /* project directory block pointer */
+{
+       register TYPBLK *t1;            /* type label block pointer */
+       register TYPBLK *t2;            /* type label block pointer */
+       register TYPES *ty;             /* type statistics array pointer */
+       register int comp;              /* block comparison */
+       register int ityp;              /* type label block index */
+       register int ntypes;            /* number of unique type labels */
+       int strcmp();                   /* string comparison */
+
+       comp = 0;
+       ntypes = Ntypes;
+       t1 = (*b1)->typblk;
+       t2 = (*b2)->typblk;
+       ty = Typstat;
+
+       for (ityp = 0; ityp < ntypes; ityp++)
+               {
+               if (ty->t_sort && t1->t_exist && t2->t_exist)
+                       if ((comp = t1->t_prior - t2->t_prior) != 0)
+                               return(comp);
+               t1++, t2++, ty++;
+               }
+       return(strcmp((*b1)->ppath, (*b2)->ppath));
+}
+
+
+
+/*
+ * savepdir() saves a block of project directory attributes somewhere
+ * and returns a pointer to the somewhere, or dies if out of memory.
+ */
+PDSET *
+savepdir(ppathname, pathname, project)
+       char *ppathname;                /* project directory project pathname */
+       char *pathname;                 /* project directory regular pathname */
+       char *project;                  /* project directory's project */
+{
+       char *calloc();                 /* initialize memory to zero */
+       char *malloc();                 /* memory allocator */
+       char *strcpy();                 /* string copy */
+       int strlen();                   /* string length */
+       PDSET *pdbptr;                  /* pointer to proj directory block */
+
+       if ((pdbptr = (PDSET *) malloc(sizeof(PDSET))) == NULL ||
+           (pdbptr->ppath = malloc((unsigned)(strlen(ppathname)+1))) == NULL ||
+           (pdbptr->rpath = malloc((unsigned)(strlen(pathname)+1))) == NULL ||
+           (pdbptr->typblk = (TYPBLK *) calloc((unsigned)Ntypes,sizeof(TYPBLK))) == NULL)
+               nomorecore();
+       strcpy(pdbptr->rpath, pathname);
+       strcpy(pdbptr->ppath, ppathname);
+       pdbptr->project = project;
+       return(pdbptr);
+}
+
+
+
+/*
+ * savetype() records the priorities of the type labels attached to each
+ * directory, and also the total number of each type label.
+ */
+void
+savetype(type, idx)
+       char *type;                     /* project dir type label */
+       int idx;                        /* boolean type expression id index */
+{
+       register char *ptyptr;          /* pointer to type label priority */
+       register int priority;          /* type label priority */
+       register int uniqid;            /* unique type label number */
+       char *index();                  /* first occurrence of character */
+       int atoi();                     /* string to decimal integer */
+
+       uniqid = Maptyp[idx];
+       ptyptr = index(type, '.');
+       priority = (ptyptr == NULL) ? 0 : atoi(++ptyptr);
+       if (Typstat[uniqid].t_ntl == 0)
+               {
+               Typstat[uniqid].t_itlp = priority;
+               }
+       else    {
+               if (priority != Typstat[uniqid].t_itlp)
+                       Typstat[uniqid].t_sort = 1;
+               }
+       Typstat[uniqid].t_ntl++;
+
+       Pdarray[Ipdirs]->typblk[uniqid].t_exist++;
+       Pdarray[Ipdirs]->typblk[uniqid].t_prior = priority;
+}
+
+
+
+/*
+ * sort_pdset() sorts the set of project directories alpahabetically
+ * and by type label priorities.
+ */
+void
+sort_pdset()
+{
+       int pdbcmp();                   /* compare project dir blocks */
+
+       qsort((char *)Pdarray, Ipdirs, sizeof(PDSET *), pdbcmp);
+}
diff --git a/usr/src/new/new/spms/src/bin/pexec/pdset.h b/usr/src/new/new/spms/src/bin/pexec/pdset.h
new file mode 100644 (file)
index 0000000..e6e18ef
--- /dev/null
@@ -0,0 +1,36 @@
+/* $Header$ */
+
+/*
+ * Project directory set definitions
+ *
+ * Author: Peter J. Nicklin
+ */
+
+/*
+ * Project directory type label block
+ */
+typedef struct _typblk
+       {
+       short t_exist;                  /* type label exist for this dir? */
+       short t_prior;                  /* type label priority */
+       } TYPBLK;
+/*
+ * Project directory attribute block
+ */
+typedef struct _pdset
+       {
+       char *ppath;                    /* project directory project pathname */
+       char *rpath;                    /* project directory regular pathname */
+       char *project;                  /* project directory's project */
+       TYPBLK *typblk;                 /* project directory's type labels */
+       } PDSET;
+/*
+ * Project directory type label statistics (for each set of type labels)
+ */
+typedef struct _types
+       {
+       char *t_name;                   /* type label name */
+       short t_ntl;                    /* number of type labels */
+       short t_itlp;                   /* initial type label priority */
+       short t_sort;                   /* sort on this type label? */
+       } TYPES;
diff --git a/usr/src/new/new/spms/src/bin/pfind/binary.c b/usr/src/new/new/spms/src/bin/pfind/binary.c
new file mode 100644 (file)
index 0000000..9fd1efe
--- /dev/null
@@ -0,0 +1,71 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include "yesno.h"
+
+static char **STRINGS;                 /* pointer array containing strings */
+static int NSTRINGS;                   /* number of strings in STRINGS */
+
+/*
+ * bininit() initializes and sorts the STRINGS pointer array.
+ */
+void
+bininit(argc, argv)
+       int argc;
+       char **argv;
+{
+       int qsort();                    /* quicker sort */
+       int strpcmp();                  /* pointed-to string comparison */
+
+       NSTRINGS = argc;
+       STRINGS = argv;
+       qsort((char *) STRINGS, NSTRINGS, sizeof(char *), strpcmp);
+}
+
+
+
+/*
+ * binsearch() returns integer YES if string is found in sorted pointer
+ * array STRINGS, otherwise NO. Uses binary search.
+ */
+binsearch(string)
+       char *string;                   /* string to be matched */
+{
+       int comp;                       /* compare string values */
+       int high;                       /* upper limit of array */
+       int low;                        /* lower limit of array */
+       int mid;                        /* middle of search range */
+       int strcmp();                   /* string comparison */
+
+       low = 0;
+       high = NSTRINGS - 1;
+       while (low <= high)
+               {
+               mid = (low+high) / 2;
+               if ((comp = strcmp(string, STRINGS[mid])) < 0)
+                       high = mid - 1;
+               else if (comp > 0)
+                       low = mid + 1;
+               else
+                       return(YES);
+               }
+       return(NO);
+}
+
+
+
+/*
+ * strpcmp() compares strings in a pointer array. Returns whatever strcmp()
+ * returns.
+ */
+static int
+strpcmp(s1, s2)
+       char **s1;
+       char **s2;
+{
+       int strcmp();                   /* string comparison */
+
+       return(strcmp(*s1, *s2));
+}
diff --git a/usr/src/new/new/spms/src/bin/pgrep/pgrep.c b/usr/src/new/new/spms/src/bin/pgrep/pgrep.c
new file mode 100644 (file)
index 0000000..efbf5f6
--- /dev/null
@@ -0,0 +1,147 @@
+static char *rcsid = "$Header$";
+/*
+ * pgrep - search files in a project for a pattern
+ *
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "getarg.h"
+#include "null.h"
+#include "path.h"
+#include "spms.h"
+
+#define CMDBUFSIZE     1024
+#define MAXPXARGV      12
+
+char *PGN = "pgrep";                   /* program name */
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       register char *gp;              /* pointer to grep command buffer */
+       register char **px;             /* pointer to pexec command args */
+       char cwd[PATHSIZE];             /* current working directory pathname */
+       char *getwd();                  /* get current working directory */
+       char gpcmdbuf[CMDBUFSIZE];      /* SPMSLIB/grep command buffer */
+       char *patfile = NULL;           /* pattern file name */
+       char *pathcat();                /* pathname concatenation */
+       char pexeccmd[PATHSIZE];        /* location of pexec command */
+       char *pxargv[MAXPXARGV];        /* pexec command and args */
+       char *strpcpy();                /* copy string and update pointer */
+       int command;                    /* execute command on files? */
+       int readmf;                     /* read makefile for source files? */
+       int status = 0;                 /* exit status */
+       int strlen();                   /* string length */
+
+       pathcat(pexeccmd, SPMSBIN, "pexec");
+       pathcat(gpcmdbuf, SPMSLIB, "pgrep");
+       gp = gpcmdbuf + strlen(gpcmdbuf);
+       px = pxargv;
+       *px++ = "pexec";
+       *px++ = "-iX2";                 /* ignore non-zero return codes */
+                                       /* set pexec error code to 2 */
+       command = 0;
+       readmf = 0;
+       {
+       register char *s;               /* option pointer */
+       while (--argc > 0 && **++argv == '-')
+               {
+               for (s = argv[0]+1; *s != '\0'; s++)
+                       switch (*s)
+                               {
+                               case 'C':
+                                       command++;
+                                       gp = strpcpy(gp, " -C\"");
+                                       gp = strpcpy(gp, GETARG(s));
+                                       gp = strpcpy(gp, "\"");
+                                       goto endfor;
+                               case 'D':
+                                       *px++ = "-D";
+                                       break;
+                               case 'F':
+                                       gp = strpcpy(gp, " -F");
+                                       patfile = GETARG(s);
+                                       if (*patfile != _RDIRC)
+                                               {
+                                               if (getwd(cwd) == NULL)
+                                                       {
+                                                       warn(cwd);
+                                                       status = 1;
+                                                       }
+                                               gp = strpcpy(gp, cwd);
+                                               gp = strpcpy(gp, PATHSEP);
+                                               }
+                                       gp = strpcpy(gp, patfile);
+                                       goto endfor;
+                               case 'P':
+                                       *px++ = "-P";
+                                       *px++ = GETARG(s);
+                                       goto endfor;
+                               case 'T':
+                                       *px++ = "-T";
+                                       *px++ = GETARG(s);
+                                       goto endfor;
+                               case 'e':
+                                       gp = strpcpy(gp, " -e");
+                                       break;
+                               case 'f':
+                                       gp = strpcpy(gp, " -f");
+                                       gp = strpcpy(gp, GETARG(s));
+                                       gp = strpcpy(gp, " -m");
+                                       readmf++;
+                                       goto endfor;
+                               case 'i':
+                                       gp = strpcpy(gp, " -i");
+                                       break;
+                               case 'l':
+                                       gp = strpcpy(gp, " -l");
+                                       break;
+                               case 'm':
+                                       gp = strpcpy(gp, " -m");
+                                       readmf++;
+                                       break;
+                               case 'n':
+                                       gp = strpcpy(gp, " -n");
+                                       break;
+                               case 'w':
+                                       gp = strpcpy(gp, " -w");
+                                       break;
+                               default:
+                                       warn("bad option -%c", *s);
+                                       status = 1;
+                                       goto endfor;
+                               }
+               endfor: continue;
+               }
+       }
+       if (status == 1 ||
+          (argc < 1 && patfile == NULL) ||
+          (argc < 2 && !readmf && patfile == NULL))
+               {
+               warn("usage: pgrep [-eilmnw] [-f makefile] [-C command] [-F patfile]\n       [-P pdirname] [-T typexpr] [pattern [file ...]]");
+               exit(2);
+               }
+
+       if (!command)                   /* turn off quit query if no command */
+               *px++ = "-?";
+       if (patfile == NULL)
+               {
+               gp = strpcpy(gp, " \"");
+               gp = strpcpy(gp, *argv);
+               gp = strpcpy(gp, "\"");
+               argv++, argc--;
+               }
+       while (argc-- > 0)
+               {
+               gp = strpcpy(gp, " ");
+               gp = strpcpy(gp, *argv++);
+               }
+
+       *px++ = gpcmdbuf;
+       *px = NULL;
+
+       execv(pexeccmd, pxargv);
+       warn("can't exec %s", pexeccmd);
+       exit(2);
+}
diff --git a/usr/src/new/new/spms/src/bin/phelp/phelp.h b/usr/src/new/new/spms/src/bin/phelp/phelp.h
new file mode 100644 (file)
index 0000000..2429b0f
--- /dev/null
@@ -0,0 +1,18 @@
+/* $Header$ */
+
+/*
+ * phelp definitions
+ *
+ * Author: Peter J. Nicklin
+ */
+
+#define PHELP          EQUAL(*argv, "phelp")
+#define PHELP_CMD_FILE "phelp.cmd"     /* help commands */
+#define PHELP_HELP_FILE        "phelp.help"    /* brief help introduction */
+
+#define MAXHELPLEVEL   50              /* max depth of help hierarchy */
+#define REQUESTSIZE    128             /* size of help request buffer */
+
+#define MAXLINE                80              /* maximum width of index */
+#define MINIMUM_GAP    2               /* minimum gap between index columns */
+#define TABSIZE                8               /* number of columns per tab */
diff --git a/usr/src/new/new/spms/src/bin/phelp/requestq.c b/usr/src/new/new/spms/src/bin/phelp/requestq.c
new file mode 100644 (file)
index 0000000..d5a8074
--- /dev/null
@@ -0,0 +1,338 @@
+/* $Header$ */
+
+/*
+ * Author: Peter J. Nicklin
+ */
+#include <ctype.h>
+#include <stdio.h>
+#include "macro.h"
+#include "null.h"
+#include "path.h"
+#include "phelp.h"
+#include "slist.h"
+#include "spms.h"
+#include "system.h"
+#include "yesno.h"
+
+char *helpstack[MAXHELPLEVEL];         /* stack of topics and subtopics */
+extern int HELPLEVEL;                  /* current level in help hierarchy */
+static SLIST *requestqueue = NULL;     /* queue of topics to process */
+
+/*
+ * gettopic() parses a help request from standard input into tokens and
+ * adds the tokens to a previously purged request queue.
+ */
+void
+gettopic()
+{
+       char *gets();                   /* get a line from standard input */
+       char *getword();                /* get next word on line from stdin */
+       char request[REQUESTSIZE];      /* input line buffer */
+       char *rp;                       /* request buffer pointer */
+       char *topic;                    /* topic word pointer */
+       void initrq();                  /* initialize request queue */
+       void puttopic();                /* add topic to request queue */
+       void purgrq();                  /* purge request queue */
+       
+       if (requestqueue == NULL)
+               initrq();
+       else
+               purgrq();
+       if ((rp = gets(request)) != NULL)
+               {
+               do      {
+                       rp = getword(&topic, rp);
+                       if (*topic != '\0')
+                               puttopic(topic);
+                       } while (*rp != '\0');
+               }
+}
+
+
+
+/*
+ * getword() gets the next word on a line from standard input and returns
+ * a pointer to the next word.
+ */
+char *
+getword(word, bp)
+       char **word;                    /* receiving pointer for word */
+       register char *bp;              /* buffer pointer */
+{
+
+       for (; *bp != '\0' && isspace(*bp); bp++)
+               continue;
+       *word = bp;
+       for (; *bp != '\0' && !isspace(*bp); bp++)
+               continue;
+       if (*bp != '\0')
+               *bp++ = '\0';
+       return(bp);
+}
+
+
+
+/*
+ * printnotopics() prints a "no topics" error message.
+ */
+void
+printnotopics(ppathname)
+       char *ppathname;                /* project pathname */
+{
+       if (HELPLEVEL < 1)
+               {
+               if (EQUAL(ppathname, CURPROJECT))
+                       {
+                       warn("There is no help available for this project");
+                       }
+               else    {
+                       warn("There is no help available for project %s",
+                            ppathname);
+                       }
+               }
+       else    {
+               warn("%s doesn't have any subtopics", helpstack[HELPLEVEL-1]);
+               }
+}
+
+
+
+/*
+ * processtopic() interprets the request queue and controls the help
+ * stack.
+ */
+processtopic()
+{
+       extern char PHELP_CMD[];        /* help command file pathname */
+       extern char PHELP_HELP[];       /* help introduction file pathname */
+       char *getcwp();                 /* get current working project */
+       char *mkndir();                 /* make a directory name */
+       char *ppathname;                /* project pathname */
+       char *slget();                  /* get a list item */
+       char *topic;                    /* next topic from request queue */
+       char *strsav();                 /* save a string somewhere */
+       int chproject();                /* change project */
+       int mkindex();                  /* make topic index */
+       int nrq;                        /* no. items in request queue */
+       int printtopic();               /* print topic file and index */
+       int status = 0;                 /* return status */
+       void printindex();              /* print topic index */
+       void printnotopics();           /* print "no topics" error message */
+       void slrewind();                /* rewind list */
+
+       if ((nrq = SLNUM(requestqueue)) < 1)
+               {
+               /* go up one level */
+               if (HELPLEVEL > 0)
+                       {
+                       chdir(PARENTDIR);
+                       free(helpstack[--HELPLEVEL]);
+                       }
+               else    {
+                       fprintf(stderr, "You are at the top level of help topics. ");
+                       printtopic(PHELP_CMD, CURDIR);
+                       }
+
+               }
+       else    {
+               slrewind(requestqueue);
+
+               topic = slget(requestqueue);
+               if (EQUAL(topic, "help"))
+                       {
+                       /* print help introduction */
+                       printtopic(PHELP_HELP, CURDIR);
+                       return(status);
+                       }
+               else if (EQUAL(topic, "?"))
+                       {
+                       /* print command summary */
+                       printtopic(PHELP_CMD, CURDIR);
+                       return(status);
+                       }
+               else if (EQUAL(topic, "q"))
+                       {
+                       /* quit phelp */
+                       exit(status);
+                       }
+               else if (EQUAL(topic, "~"))
+                       {
+                       /* return to top level help directory */
+                       for (; HELPLEVEL > 0; HELPLEVEL--)
+                               {
+                               chdir(PARENTDIR);
+                               free(helpstack[HELPLEVEL-1]);
+                               }
+                       if (mkindex(CURDIR) == YES)
+                               printindex(stdout);
+                       return(status);
+                       }
+               else if (EQUAL(topic, "P"))
+                       {
+                       /* change project */
+                       if (nrq < 2)
+                               {
+                               warn("Missing project name");
+                               status = 1;
+                               }
+                       else if (nrq > 2)
+                               {
+                               warn("Too many arguments");
+                               status = 1;
+                               }
+                       else    {
+                               ppathname = slget(requestqueue);
+                               if (chghelp(ppathname) == NO)
+                                       {
+                                       status = 1;
+                                       }
+                               else if (mkindex(CURDIR) == NO)
+                                       {
+                                       printnotopics(ppathname);
+                                       status = 1;
+                                       }
+                               else    {
+                                       printindex(stdout);
+                                       }
+                               }
+                       return(status);
+                       }
+               else    {
+                       /* travel to the requested level */
+                       while (nrq-- > 1)
+                               {
+                               if (CHDIR(mkndir(topic)))
+                                       helpstack[HELPLEVEL++] = strsav(topic);
+                               else if (FILEXIST(topic))
+                                       {
+                                       warn("%s doesn't have any subtopics", topic);
+                                       status = 1;
+                                       }
+                               else if (mkindex(CURDIR) == NO)
+                                       {
+                                       printnotopics(CURPROJECT);
+                                       status = 1;
+                                       }
+                               else    {
+                                       warn("Can't find %s", topic);
+                                       printindex(stderr);
+                                       status = 1;
+                                       }
+                               if (status != 0)
+                                       break;
+                               topic = slget(requestqueue);
+                               }
+                       }
+
+               if (status != 0)
+                       return(status);
+
+               /* process help topic request */
+               if (EQUAL(topic, "index"))
+                       {
+                       /* print topic index */
+                       if (mkindex(CURDIR) == YES)
+                               printindex(stdout);
+                       else    {
+                               printnotopics(CURPROJECT);
+                               if (HELPLEVEL > 0)
+                                       {
+                                       chdir(PARENTDIR);
+                                       free(helpstack[--HELPLEVEL]);
+                                       }
+                               status = 1;
+                               }
+                       }
+               else    {
+                       helpstack[HELPLEVEL++] = strsav(topic);
+                       switch (printtopic(topic, mkndir(topic)))
+                               {
+                               case 0:         /* help file and subtopics */
+                               case 1:         /* subtopics only */
+                                       chdir(mkndir(topic));
+                                       break;
+                               case 2:         /* help file, no subtopics */
+                                       free(helpstack[--HELPLEVEL]);
+                                       break;
+                               case 3:         /* no help available at all */
+                                       free(helpstack[--HELPLEVEL]);
+                                               /* is there any help at */
+                                               /* current level? */
+                                       if (mkindex(CURDIR) == NO)
+                                               {
+                                               printnotopics(CURPROJECT);
+                                               status = 1;
+                                               }
+                                       else    {
+                                               warn("Sorry, %s is not available",
+                                                    topic);
+                                               printindex(stderr);
+                                               status = 1;
+                                               }
+                                       break;
+                               }
+                       }
+               }
+       return(status);
+}
+
+
+
+/*
+ * prompt() prints the stack of topics and subtopics to the current
+ * level and prompts for the next command.
+ */
+void
+prompt()
+{
+       int tsindex;                    /* topic stack index */
+
+       if (HELPLEVEL > 3)
+               printf("-->");
+       for (tsindex = MAX(0, HELPLEVEL-3); tsindex < HELPLEVEL; tsindex++)
+               printf("%s-->", helpstack[tsindex]);
+       printf("??? ");
+}
+
+
+
+/*
+ * puttopic() adds a help topic to the end of the request queue.
+ */
+void
+puttopic(topic)
+       char *topic;                    /* topic string */
+{
+       char *slappend();               /* append item to list */
+
+       if (requestqueue == NULL)
+               initrq();
+       slappend(topic, requestqueue);
+}
+
+
+
+/*
+ * initrq() initializes the request queue.
+ */
+void
+initrq()
+{
+       SLIST *slinit();                /* initialize list */
+
+       requestqueue = slinit();
+}
+
+
+
+/*
+ * purgrq() empties the request queue.
+ */
+void
+purgrq()
+{
+       int slpop();                    /* pop items off list */
+
+       while (slpop(CNULL, 0, requestqueue) == YES)
+               continue;
+}
diff --git a/usr/src/new/new/spms/src/bin/pman/pman.c b/usr/src/new/new/spms/src/bin/pman/pman.c
new file mode 100644 (file)
index 0000000..c74dc12
--- /dev/null
@@ -0,0 +1,78 @@
+static char *rcsid = "$Header$";
+/*
+ * pman - print project manual
+ *
+ * Author: Peter J. Nicklin
+ */
+#include <stdio.h>
+#include "getarg.h"
+#include "path.h"
+#include "spms.h"
+#include "yesno.h"
+
+#define CMDBUFSIZE     1024
+
+char *PGN = "pman";                    /* program name */
+
+main(argc, argv)
+       int argc;
+       char **argv;
+{
+       extern int PPDEBUG;             /* project pathname debug flag */
+       char *argvtos();                /* convert cmd arguments to string */
+       char cmdbuf[CMDBUFSIZE];        /* man command buffer */
+       char *getcwp();                 /* get current working project */
+       char *ppathname = CURPROJECT;   /* project pathname */
+       char *sprintf();                /* print output to string */
+       int status = 0;                 /* exit status */
+       int xppath();                   /* expand project pathname */
+       PATH pathbuf;                   /* pathname struct buffer */
+
+       {
+       register char *s;               /* option pointer */
+       while (--argc > 0 && **++argv == '-')
+               {
+               for (s = argv[0]+1; *s != '\0'; s++)
+                       switch (*s)
+                               {
+                               case 'D':
+                                       PPDEBUG = YES;
+                                       break;
+                               case 'P':
+                                       ppathname = GETARG(s);
+                                       if (*ppathname == '\0')
+                                               {
+                                               warn("missing project name");
+                                               status = 1;
+                                               }
+                                       goto endfor;
+                               default:
+                                       warn("bad option -%c", *s);
+                                       status = 1;
+                                       goto endfor;
+                               }
+               endfor: continue;
+               }
+       }
+       if (status == 1 || argc < 1)
+               fatal("usage: pman [-P projectname] [section] topic ...");
+
+       /* convert project pathname to regular pathname */
+       if (xppath(ppathname, &pathbuf) == -1)
+               {
+               patherr(ppathname);
+               exit(1);
+               }
+       else switch (pathbuf.p_mode & P_IFMT)
+               {
+               case P_IFHOME:
+               case P_IFPROOT:
+                       break;
+               default:
+                       fatal("%s: no such project", ppathname);
+                       break;
+               }
+       sprintf(cmdbuf, "man -P %s/man %s",pathbuf.p_path,argvtos(argc, argv));
+       system(cmdbuf);
+       exit(status);
+}