1: /* $Header$ */ 2: 3: /* 4: * Author: Peter J. Nicklin 5: */ 6: #include <stdio.h> 7: #include "hash.h" 8: #include "macro.h" 9: #include "null.h" 10: #include "path.h" 11: #include "pdb.h" 12: #include "pdset.h" 13: #include "pdlist.h" 14: #include "pdtyp.h" 15: #include "pld.h" 16: #include "slist.h" 17: #include "slslist.h" 18: #include "spms.h" 19: #include "truefalse.h" 20: #include "yesno.h" 21: 22: #define INCRPDIRS 50 /* amount to increase pdir ptr array */ 23: #define MAXPDIRS 100 /* initial size of proj dir ptr array */ 24: 25: extern char *PGN; /* program name */ 26: extern PDTYP PDIRTYP; /* project directory type labels list */ 27: 28: static int Ipdirs; /* attribute block array index */ 29: static int Maxpdirs = MAXPDIRS; /* maximum no. of project dirs */ 30: static int Ntypes; /* number of unique type labels */ 31: static PDSET **Pdarray; /* project dir attribute block array */ 32: static short *Maptyp; /* unique type label mapping array */ 33: static TYPES *Typstat; /* type label statistics */ 34: 35: /* 36: * add_pdset() adds a project directory to the set of project directories 37: * which satisfy a boolean project directory type label expression. Only 38: * those type labels which satisfy the boolean expression are included with 39: * the project directory. To determine which type labels qualify, the 40: * postfix expression is scanned from right to left. Type labels within a 41: * negated expression are ignored. For example, in the postfix equivalent 42: * of expression "src & !(cmd | lib)" (that is: src cmd lib | ! &), 43: * even if both "src" and "cmd" are found, "src" is the only type label 44: * which could qualify. 45: */ 46: void 47: add_pdset(postfix, ppathname, pathname, project) 48: register PDTYP *postfix; /* postfix expression struct */ 49: char *ppathname; /* project directory project pathname */ 50: char *pathname; /* project directory pathname */ 51: char *project; /* project directory's project */ 52: { 53: register int i; /* postfix expression index */ 54: register int opcount; /* count of expected operands */ 55: char *pdtcpy(); /* copy project directory type label */ 56: char *realloc(); /* reallocate memory block */ 57: char type[TYPESIZE]; /* project dir type label buffer */ 58: PDSET *savepdir(); /* save pdir attribute blk somewhere */ 59: void savetype(); /* save type label */ 60: 61: if (Ipdirs >= Maxpdirs) 62: { 63: Maxpdirs += INCRPDIRS; 64: if ((Pdarray = (PDSET **) realloc((char *)Pdarray, 65: (unsigned)Maxpdirs*sizeof(PDSET *))) == NULL) 66: nomorecore(); 67: } 68: Pdarray[Ipdirs] = savepdir(ppathname, pathname, project); 69: 70: opcount = 0; 71: for (i = (postfix->pfxsize)-1; i >= 0;) 72: { 73: switch ((postfix->pfx)[i].p_class) 74: { 75: case B_ID: 76: if ((postfix->pfx)[i].p_sw == TRUE) 77: { 78: pdtcpy(type, (postfix->pfx)[i].p_label); 79: savetype(type, i); 80: } 81: break; 82: case B_OR: 83: case B_AND: 84: if ((postfix->pfx)[i].p_sw == FALSE) 85: opcount += 2; 86: break; 87: case B_NOT: 88: /* always skip !subexpr */ 89: opcount += 1; 90: break; 91: } 92: /* skip false subexpression */ 93: for (--i; opcount > 0; i--) 94: switch ((postfix->pfx)[i].p_class) 95: { 96: case B_ID: 97: opcount -= 1; 98: break; 99: case B_OR: 100: case B_AND: 101: opcount += 1; 102: break; 103: case B_NOT: 104: break; 105: } 106: } 107: Ipdirs++; 108: } 109: 110: 111: 112: /* 113: * build_pdset() builds a set of project directories which satisfy a boolean 114: * project directory type label expression. 115: */ 116: build_pdset(ppathname, pathname) 117: char *ppathname; /* project root dir project pathname */ 118: char *pathname; /* regular project root dir pathname */ 119: { 120: extern int ERRSTATUS; /* pexec error status */ 121: extern SLIST *ENVLIST; /* project environment variable list */ 122: char ppathbuf[PPATHSIZE]; /* project pathname buffer */ 123: char *ppathcat(); /* project pathname concatenation */ 124: char *pv; /* PROJECT environment variable */ 125: char *slprepend(); /* prepend key */ 126: char *slsprepend(); /* prepend key+string */ 127: int closepdb(); /* close database */ 128: int errpdb(); /* print database error message */ 129: int pdtmatch(); /* match project dir type label expr */ 130: int status = 0; /* return status */ 131: PATH *pd; /* pathname struct pointer */ 132: PATH *readpld(); /* read project link directory entry */ 133: PDB *openpdb(); /* open database */ 134: PDB *pldp; /* project link directory stream */ 135: SLSBLK *pblk; /* project list block */ 136: SLSLIST *plist; /* project list */ 137: SLSLIST *slsinit(); /* initialize list */ 138: void add_pdset(); /* add to set of project dirs */ 139: void slsrm(); /* remove list item */ 140: 141: if ((pv = slprepend(pathname, ENVLIST)) == NULL) 142: pxexit(); 143: plist = slsinit(); 144: 145: /* read PLDNAME project link directory */ 146: if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL) 147: return(errpdb((PDB *) NULL)); 148: while ((pd = readpld(pldp)) != NULL) 149: { 150: if (EQUAL(pd->p_alias, PARENTPROJECT)) 151: continue; 152: 153: if (EQUAL(pd->p_alias, CURPROJECT)) 154: { 155: if (pdtmatch(&PDIRTYP, pd->p_type) == YES) 156: add_pdset(&PDIRTYP, ppathname, pd->p_path, pv); 157: } 158: else if (pd->p_mode == P_IFPROOT) 159: { 160: if (slsprepend(pd->p_alias, pd->p_path, plist) == NULL) 161: pxexit(); 162: } 163: else if (pdtmatch(&PDIRTYP, pd->p_type) == YES) 164: { 165: ppathcat(ppathbuf, ppathname, pd->p_alias); 166: add_pdset(&PDIRTYP, ppathbuf, pd->p_path, pv); 167: } 168: } 169: if (closepdb(pldp) != 0) 170: status = ERRSTATUS; 171: 172: /* build project directory type label tree for subprojects */ 173: for (pblk = plist->head; pblk != NULL; pblk = pblk->next) 174: { 175: ppathcat(ppathbuf, ppathname, pblk->key); 176: status |= build_pdset(ppathbuf, pblk->string); 177: } 178: slsrm(CNULL, plist); 179: 180: return(status); 181: } 182: 183: 184: 185: /* 186: * check_pdset() detects conflicting type label priorities by 187: * checking that project directories are sorted into ascending 188: * order according to priority. An error message is printed and 189: * 1 returned on conflict, otherwise zero. 190: */ 191: check_pdset() 192: { 193: register int iPd; /* proj dir block array index */ 194: register int ityp; /* type label block index */ 195: register int lastpr; /* previous type label priority */ 196: register int prior; /* project dir type label priority */ 197: register PDSET **ptrPd; /* Pdarray block array pointer */ 198: int nsortyp; /* no. type label categories to sort */ 199: 200: nsortyp = 0; 201: for (ityp = 0; ityp < Ntypes; ityp++) 202: if (Typstat[ityp].t_sort) 203: nsortyp++; 204: if (nsortyp < 2) 205: return(0); 206: 207: for (ityp = 0; ityp < Ntypes; ityp++) 208: if (Typstat[ityp].t_sort) 209: { 210: for (ptrPd=Pdarray, iPd=Ipdirs; iPd > 0; ptrPd++, iPd--) 211: if ((*ptrPd)->typblk[ityp].t_exist) 212: { 213: lastpr = (*ptrPd)->typblk[ityp].t_prior; 214: break; 215: } 216: for (ptrPd++, iPd--; iPd > 0; ptrPd++, iPd--) 217: { 218: if ((*ptrPd)->typblk[ityp].t_exist) 219: { 220: prior = (*ptrPd)->typblk[ityp].t_prior; 221: if (prior < lastpr) 222: goto conflict; 223: lastpr = prior; 224: } 225: } 226: } 227: return(0); 228: conflict: 229: fprintf(stderr, "%s:", PGN); 230: for (ityp = Ntypes-1; ityp >= 0; ityp--) 231: if (Typstat[ityp].t_sort) 232: fprintf(stderr, (nsortyp-- > 1) ? " %s," : 233: " %s: conflicting type label priorities\n", 234: Typstat[ityp].t_name); 235: return(1); 236: } 237: 238: 239: 240: /* 241: * debug_pdset() prints the sorted project directories together with 242: * the type labels that satisfy the boolean expression. 243: */ 244: void 245: debug_pdset() 246: { 247: int iPd; /* project dir block array index */ 248: int ityp; /* type label statistics array index */ 249: 250: for (iPd = 0; iPd < Ipdirs; iPd++) 251: { 252: fprintf(stderr, "%s:", Pdarray[iPd]->ppath); 253: for (ityp = 0; ityp < Ntypes; ityp++) 254: if (Pdarray[iPd]->typblk[ityp].t_exist) 255: fprintf(stderr," %s.%d",Typstat[ityp].t_name, 256: Pdarray[iPd]->typblk[ityp].t_prior); 257: putc('\n', stderr); 258: } 259: } 260: 261: 262: 263: /* 264: * exec_pdset() executes a set of project directories. Returns non-zero 265: * error status if error. 266: */ 267: exec_pdset() 268: { 269: extern int ERRSTATUS; /* pexec error status */ 270: extern int EXECUTE; /* execute command? */ 271: extern int PRINT_HEADING; /* print headings for project dirs */ 272: int ch_dir(); /* change current working directory */ 273: int execcmd(); /* execute command in directory */ 274: int iPd; /* project dir block array index */ 275: int status = 0; /* return status */ 276: void print_title(); /* print project directory title */ 277: 278: for (iPd = 0; iPd < Ipdirs; iPd++) 279: { 280: if (PRINT_HEADING == YES) 281: print_title(Pdarray[iPd]->ppath); 282: if (ch_dir(Pdarray[iPd]->rpath) == NO) 283: status = ERRSTATUS; 284: else if (EXECUTE == YES) 285: status |= execcmd(Pdarray[iPd]->project); 286: } 287: return(status); 288: } 289: 290: 291: 292: /* 293: * init_pdset() allocates an array of pointers (Pdarray) to project 294: * directory attribute blocks, and calculates the maximum number of type 295: * labels to be stored with each project directory based on the number of 296: * unique type labels in the boolean postfix type expression. An array 297: * (Typstat) is also created to maintain statistics on each brand of 298: * label. 299: * 300: * Hash table lookup is used in forming unique type labels and a 301: * mapping array is used to map the labels from the boolean postfix 302: * type label expression to the unique representation. 303: */ 304: #define UNIQTYPHASHSIZE 41 305: 306: void 307: init_pdset() 308: { 309: register int i; /* postfix type expression index */ 310: char *malloc(); /* memory allocator */ 311: char *pfxcpy(); /* copy string prefix */ 312: char type[TYPESIZE]; /* project dir type label buffer */ 313: HASH *htinit(); /* initialize hash table */ 314: HASH *uniqtyp; /* hash table of unique type labels */ 315: HASHBLK *htb; /* hash table block pointer */ 316: HASHBLK *htinstall(); /* install hash table entry */ 317: HASHBLK *htlookup(); /* find hash table entry */ 318: int nid; /* no. of ids in boolean expression */ 319: 320: /* project directory attribute block pointer array */ 321: if ((Pdarray = (PDSET **) malloc((unsigned)Maxpdirs*sizeof(PDSET *))) == NULL) 322: nomorecore(); 323: 324: /* create postfix expression -> unique type label mapping array */ 325: if ((Maptyp = (short *) malloc((unsigned)PDIRTYP.pfxsize*sizeof(short))) == NULL) 326: nomorecore(); 327: 328: /* create type label statistics array (estimate size first) */ 329: nid = 0; 330: for (i = (PDIRTYP.pfxsize)-1; i >= 0; i--) 331: if ((PDIRTYP.pfx)[i].p_class == B_ID) 332: nid++; 333: if ((Typstat = (TYPES *) malloc((unsigned)nid*sizeof(TYPES))) == NULL) 334: nomorecore(); 335: 336: /* unique type label determination */ 337: uniqtyp = htinit(UNIQTYPHASHSIZE); 338: for (i = (PDIRTYP.pfxsize)-1; i >= 0; i--) 339: { 340: if ((PDIRTYP.pfx)[i].p_class != B_ID) 341: continue; 342: pfxcpy(type, (PDIRTYP.pfx)[i].p_id); 343: if ((htb = htlookup(type, uniqtyp)) != NULL) 344: { 345: Maptyp[i] = htb->h_val; 346: } 347: else { 348: if ((htb = htinstall(type,"",Ntypes,uniqtyp)) == NULL) 349: nomorecore(); 350: Maptyp[i] = Ntypes; 351: Typstat[Ntypes].t_name = htb->h_key; 352: Typstat[Ntypes].t_ntl = Typstat[Ntypes].t_sort = 0; 353: Ntypes++; 354: } 355: } 356: } 357: 358: 359: 360: /* 361: * pdbcmp() compares the type label priorities and project pathnames 362: * for two project directories. Type label priorities override the 363: * lexicographical relationship of the project pathnames. Conflicting 364: * priorities are not detected. For example, a conflict occurs if the 365: * first directory has type labels print.1 and update.2, whereas the 366: * second directory has type labels print.2 and update.1. Returns 367: * an integer less than, equal to, or greater than zero, depending on 368: * the relative priorities of the type labels or lexicographical ordering 369: * of the project pathnames. 370: */ 371: pdbcmp(b1, b2) 372: PDSET **b1; /* project directory block pointer */ 373: PDSET **b2; /* project directory block pointer */ 374: { 375: register TYPBLK *t1; /* type label block pointer */ 376: register TYPBLK *t2; /* type label block pointer */ 377: register TYPES *ty; /* type statistics array pointer */ 378: register int comp; /* block comparison */ 379: register int ityp; /* type label block index */ 380: register int ntypes; /* number of unique type labels */ 381: int strcmp(); /* string comparison */ 382: 383: comp = 0; 384: ntypes = Ntypes; 385: t1 = (*b1)->typblk; 386: t2 = (*b2)->typblk; 387: ty = Typstat; 388: 389: for (ityp = 0; ityp < ntypes; ityp++) 390: { 391: if (ty->t_sort && t1->t_exist && t2->t_exist) 392: if ((comp = t1->t_prior - t2->t_prior) != 0) 393: return(comp); 394: t1++, t2++, ty++; 395: } 396: return(strcmp((*b1)->ppath, (*b2)->ppath)); 397: } 398: 399: 400: 401: /* 402: * savepdir() saves a block of project directory attributes somewhere 403: * and returns a pointer to the somewhere, or dies if out of memory. 404: */ 405: PDSET * 406: savepdir(ppathname, pathname, project) 407: char *ppathname; /* project directory project pathname */ 408: char *pathname; /* project directory regular pathname */ 409: char *project; /* project directory's project */ 410: { 411: char *calloc(); /* initialize memory to zero */ 412: char *malloc(); /* memory allocator */ 413: char *strcpy(); /* string copy */ 414: int strlen(); /* string length */ 415: PDSET *pdbptr; /* pointer to proj directory block */ 416: 417: if ((pdbptr = (PDSET *) malloc(sizeof(PDSET))) == NULL || 418: (pdbptr->ppath = malloc((unsigned)(strlen(ppathname)+1))) == NULL || 419: (pdbptr->rpath = malloc((unsigned)(strlen(pathname)+1))) == NULL || 420: (pdbptr->typblk = (TYPBLK *) calloc((unsigned)Ntypes,sizeof(TYPBLK))) == NULL) 421: nomorecore(); 422: strcpy(pdbptr->rpath, pathname); 423: strcpy(pdbptr->ppath, ppathname); 424: pdbptr->project = project; 425: return(pdbptr); 426: } 427: 428: 429: 430: /* 431: * savetype() records the priorities of the type labels attached to each 432: * directory, and also the total number of each type label. 433: */ 434: void 435: savetype(type, idx) 436: char *type; /* project dir type label */ 437: int idx; /* boolean type expression id index */ 438: { 439: register char *ptyptr; /* pointer to type label priority */ 440: register int priority; /* type label priority */ 441: register int uniqid; /* unique type label number */ 442: char *index(); /* first occurrence of character */ 443: int atoi(); /* string to decimal integer */ 444: 445: uniqid = Maptyp[idx]; 446: ptyptr = index(type, '.'); 447: priority = (ptyptr == NULL) ? 0 : atoi(++ptyptr); 448: if (Typstat[uniqid].t_ntl == 0) 449: { 450: Typstat[uniqid].t_itlp = priority; 451: } 452: else { 453: if (priority != Typstat[uniqid].t_itlp) 454: Typstat[uniqid].t_sort = 1; 455: } 456: Typstat[uniqid].t_ntl++; 457: 458: Pdarray[Ipdirs]->typblk[uniqid].t_exist++; 459: Pdarray[Ipdirs]->typblk[uniqid].t_prior = priority; 460: } 461: 462: 463: 464: /* 465: * sort_pdset() sorts the set of project directories alpahabetically 466: * and by type label priorities. 467: */ 468: void 469: sort_pdset() 470: { 471: int pdbcmp(); /* compare project dir blocks */ 472: 473: qsort((char *)Pdarray, Ipdirs, sizeof(PDSET *), pdbcmp); 474: }