/* $Header$ */ /* * Author: Peter J. Nicklin */ #include #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); }