1: static char *rcsid = "$Header$"; 2: /* 3: * pdiff - differential project comparator 4: * 5: * Author: Peter J. Nicklin 6: */ 7: #include <stdio.h> 8: #include "getarg.h" 9: #include "macro.h" 10: #include "null.h" 11: #include "path.h" 12: #include "pdb.h" 13: #include "pdtyp.h" 14: #include "pld.h" 15: #include "ptree.h" 16: #include "spms.h" 17: #include "yesno.h" 18: 19: char **NARGV; /* new argument list */ 20: char *PGN = "pdiff"; /* program name */ 21: int EXECUTE = YES; /* execute command? */ 22: int NARGI = 0; /* new argument list index */ 23: int RECURSIVE = 0; /* recursively compare projects */ 24: PDTYP PDIRTYP; /* project directory type labels list */ 25: 26: main(argc, argv) 27: int argc; 28: char **argv; 29: { 30: extern int PPDEBUG; /* project pathname debug flag */ 31: char p1[PPATHSIZE]; /* project pathname buffer */ 32: char p2[PPATHSIZE]; /* project pathname buffer */ 33: char *strcpy(); /* string copy */ 34: int balance(); /* balance PDIR structs */ 35: int diffdir(); /* compare directories or files */ 36: int diffproject(); /* compare projects */ 37: int pdtparse(); /* parse boolean type label expr */ 38: int read_path(); /* read project or regular pathname */ 39: int status = 0; /* exit status */ 40: PATH pb1; /* pathname struct buffer 1 */ 41: PATH pb2; /* pathname struct buffer 2 */ 42: unsigned long pathtyp1; /* type of pathname 1 */ 43: unsigned long pathtyp2; /* type of pathname 2 */ 44: 45: NARGV = argv; 46: NARGV[NARGI++] = "diff"; 47: 48: { 49: register char *s; /* option pointer */ 50: while (--argc > 0 && **++argv == '-') 51: { 52: for (s = argv[0]+1; *s != '\0'; s++) 53: switch (*s) 54: { 55: case 'D': 56: PPDEBUG = YES; 57: break; 58: case 'T': 59: if (pdtparse(GETARG(s), &PDIRTYP) == NO) 60: status = 1; 61: goto endfor; 62: case 'r': 63: RECURSIVE++; 64: break; 65: case 'x': 66: EXECUTE = NO; 67: break; 68: default: 69: NARGV[NARGI++] = *argv; 70: break; 71: } 72: endfor: continue; 73: } 74: } 75: if (status == 1 || argc < 2) 76: { 77: warn("usage: pdiff [-rx] [-T typexpr] [diff options] p1 p2"); 78: exit(2); 79: } 80: 81: strcpy(p1, argv[0]); 82: strcpy(p2, argv[1]); 83: NARGV[NARGI+2] = NULL; 84: 85: if (read_path(p1, &pb1) == NO || read_path(p2, &pb2) == NO) 86: exit(2); 87: 88: pathtyp1 = (pb1.p_mode & P_IFMT); 89: pathtyp2 = (pb2.p_mode & P_IFMT); 90: 91: if (pathtyp1 == P_IFPROOT || pathtyp1 == P_IFHOME) 92: { 93: if (pathtyp2 == P_IFPROOT || pathtyp2 == P_IFHOME) 94: status = diffproject(p1, pb1.p_path, p2, pb2.p_path); 95: else if (balance(p1, &pb1, &pb2) == NO) 96: exit(2); 97: else 98: status = diffdir(p1, pb1.p_path, p2, pb2.p_path); 99: } 100: else if (pathtyp2 == P_IFPROOT || pathtyp2 == P_IFHOME) 101: { 102: if (balance(p2, &pb2, &pb1) == NO) 103: exit(2); 104: else 105: status = diffdir(p1, pb1.p_path, p2, pb2.p_path); 106: } 107: else { 108: status = diffdir(p1, pb1.p_path, p2, pb2.p_path); 109: } 110: 111: if (status > 1) 112: status = 2; 113: exit(status); 114: } 115: 116: 117: 118: /* 119: * balance() balances a PATH struct given a project and a directory or file. 120: * If a regular directory or file, then it is assumed to be relative to the 121: * current working project directory. Returns NO if balancing fails, otherwise 122: * YES. The project pathname p1 is updated to reflect the balancing. 123: */ 124: balance(p1, pb1, pb2) 125: char *p1; /* we know this is a project root dir */ 126: PATH *pb1; /* project root directory buffer */ 127: PATH *pb2; /* (project) directory or file buffer */ 128: { 129: char *pathcat(); /* regular pathname concatenation */ 130: char *ppathcat(); /* project pathname concatenation */ 131: int getcpd(); /* get current working project dir */ 132: int read_path(); /* read project or regular pathname */ 133: PATH cpathbuf; /* current pathname struct buffer */ 134: 135: if ((pb2->p_mode&P_IFMT) == P_IFPDIR) 136: { 137: ppathcat(p1, p1, pb2->p_alias); 138: return(read_path(p1, pb1)); 139: } 140: else if (*pb2->p_path == _RDIRC || getcpd(&cpathbuf) != 1) 141: { 142: warn("don't know which project directory to use in %s", p1); 143: return(NO); 144: } 145: else { 146: ppathcat(p1, p1, cpathbuf.p_alias); 147: pathcat(p1, p1, pb2->p_path); 148: return(read_path(p1, pb1)); 149: } 150: } 151: 152: 153: 154: /* 155: * diffdir() compares two directories or files. Returns whatever diff() 156: * returns. 157: */ 158: diffdir(pp1, d1, pp2, d2) 159: char *pp1; /* project pathname */ 160: char *d1; /* directory or file pathname */ 161: char *pp2; /* project pathname */ 162: char *d2; /* directory or file pathname */ 163: { 164: static int have_printed; /* has printing already been done? */ 165: int diff(); /* fork diff program */ 166: int iargi; /* argument index */ 167: 168: if (have_printed) 169: putchar('\n'); 170: have_printed = 1; 171: printf("==> "); 172: for (iargi = 0; iargi < NARGI; iargi++) 173: printf("%s ", NARGV[iargi]); 174: printf("%s %s <==\n", pp1, pp2); 175: fflush(stdout); 176: 177: if (EXECUTE == NO) 178: return(0); 179: 180: NARGV[NARGI] = d1; 181: NARGV[NARGI+1] = d2; 182: return(diff(NARGV)); 183: } 184: 185: 186: 187: /* 188: * diffproject() compares two projects, recursively if necessary. Returns 189: * 0 if no differences, 1 if some, 2 if trouble. 190: */ 191: diffproject(pp1, p1, pp2, p2) 192: char *pp1; /* project pathname */ 193: char *p1; /* project root directory pathname */ 194: char *pp2; /* project pathname */ 195: char *p2; /* project root directory pathname */ 196: { 197: int closepdb(); /* close database */ 198: int diffpdtree(); /* diff project directory tree */ 199: int diffptree(); /* diff tree of projects */ 200: int errpdb(); /* print database error message */ 201: int pdtmatch(); /* match project dir type label expr */ 202: int status = 0; /* return status */ 203: PATH *pd; /* pathname struct pointer */ 204: PATH *readpld(); /* read project link directory entry */ 205: PDB *openpdb(); /* open database */ 206: PDB *pldp; /* project link directory stream */ 207: PTREE *proot; /* root of project tree */ 208: PTREE *pdroot; /* root of project directory tree */ 209: PTREE *ptree(); /* search and insert in proj dir tree */ 210: void ptreerm(); /* remove project directory tree */ 211: 212: proot = NULL; 213: pdroot = NULL; 214: 215: /* read PLDNAME project link directory belonging to p1 */ 216: if ((pldp = openpdb(PLDNAME, p1, "r")) == NULL) 217: { 218: errpdb((PDB *) NULL); 219: return(2); 220: } 221: while ((pd = readpld(pldp)) != NULL) 222: { 223: if (EQUAL(pd->p_alias, PARENTPROJECT)) 224: continue; 225: else if (EQUAL(pd->p_alias, CURPROJECT)) 226: { 227: if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES) 228: pdroot = ptree(pdroot, "", pd->p_path, CNULL); 229: } 230: else if (pd->p_mode == P_IFPROOT) 231: { 232: if (RECURSIVE) 233: proot = ptree(proot, pd->p_alias, pd->p_path, CNULL); 234: } 235: else if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES) 236: pdroot = ptree(pdroot, pd->p_alias, pd->p_path, CNULL); 237: } 238: closepdb(pldp); 239: 240: /* read PLDNAME project link directory belonging to p2 */ 241: if ((pldp = openpdb(PLDNAME, p2, "r")) == NULL) 242: { 243: errpdb((PDB *) NULL); 244: return(2); 245: } 246: while ((pd = readpld(pldp)) != NULL) 247: { 248: if (EQUAL(pd->p_alias, PARENTPROJECT)) 249: continue; 250: else if (EQUAL(pd->p_alias, CURPROJECT)) 251: { 252: if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES) 253: pdroot = ptree(pdroot, "", CNULL, pd->p_path); 254: } 255: else if (pd->p_mode == P_IFPROOT) 256: { 257: if (RECURSIVE) 258: proot = ptree(proot, pd->p_alias, CNULL, pd->p_path); 259: } 260: else if (PDIRTYP.pfxsize==0 || pdtmatch(&PDIRTYP,pd->p_type)==YES) 261: pdroot = ptree(pdroot, pd->p_alias, CNULL, pd->p_path); 262: } 263: closepdb(pldp); 264: 265: /* diff project directory tree */ 266: status |= diffpdtree(pdroot, pp1, pp2); 267: ptreerm(pdroot); 268: 269: /* diff subprojects */ 270: status |= diffptree(proot, pp1, pp2); 271: ptreerm(proot); 272: 273: return(status); 274: } 275: 276: 277: 278: /* 279: * diffpdtree() compares project directories in a project directory tree. 280: */ 281: diffpdtree(p, pp1, pp2) 282: PTREE *p; /* current node in project dir tree */ 283: char *pp1; /* project pathname */ 284: char *pp2; /* project pathname */ 285: { 286: char ppathbuf1[PPATHSIZE]; /* project pathname buffer */ 287: char ppathbuf2[PPATHSIZE]; /* project pathname buffer */ 288: char *ppathcat(); /* project pathname concantenation */ 289: int diffdir(); /* compare directories or files */ 290: int status = 0; /* return status */ 291: void printonly(); /* print "only in project ..." mesg */ 292: 293: if (p == NULL) 294: return(0); 295: status |= diffpdtree(p->left, pp1, pp2); 296: if (p->pd1 == NULL) 297: printonly(pp2, p->alias); 298: else if (p->pd2 == NULL) 299: printonly(pp1, p->alias); 300: else { 301: ppathcat(ppathbuf1, pp1, p->alias); 302: ppathcat(ppathbuf2, pp2, p->alias); 303: status |= diffdir(ppathbuf1, p->pd1, ppathbuf2, p->pd2); 304: } 305: status |= diffpdtree(p->right, pp1, pp2); 306: return(status); 307: } 308: 309: 310: 311: /* 312: * diffptree() compares projects in a project tree. 313: */ 314: diffptree(p, pp1, pp2) 315: PTREE *p; /* current node in project tree */ 316: char *pp1; /* project pathname */ 317: char *pp2; /* project pathname */ 318: { 319: char ppathbuf1[PPATHSIZE]; /* project pathname buffer */ 320: char ppathbuf2[PPATHSIZE]; /* project pathname buffer */ 321: char *ppathcat(); /* project pathname concantenation */ 322: int diffproject(); /* compare projects */ 323: int status = 0; /* return status */ 324: void printonly(); /* print "only in project ..." mesg */ 325: 326: if (p == NULL) 327: return(0); 328: status |= diffptree(p->left, pp1, pp2); 329: if (p->pd1 == NULL) 330: printonly(pp2, p->alias); 331: else if (p->pd2 == NULL) 332: printonly(pp1, p->alias); 333: else { 334: ppathcat(ppathbuf1, pp1, p->alias); 335: ppathcat(ppathbuf2, pp2, p->alias); 336: status |= diffproject(ppathbuf1, p->pd1, ppathbuf2, p->pd2); 337: } 338: status |= diffptree(p->right, pp1, pp2); 339: return(status); 340: } 341: 342: 343: 344: /* 345: * printonly() prints "only in project ..." message. 346: */ 347: void 348: printonly(project, pdirname) 349: char *project; /* project pathname */ 350: char *pdirname; /* unique project directory */ 351: { 352: printf("Only in project %s: %s\n", project, 353: (*pdirname == '\0') ? CURPROJECT : pdirname); 354: fflush(stdout); 355: } 356: 357: 358: 359: /* 360: * read_path() loads a PATH struct given a regular or project pathname. 361: * Returns integer NO if an invalid pathname or non-existent target, 362: * otherwise YES. 363: */ 364: read_path(pathname, pb) 365: char *pathname; /* regular or project pathname */ 366: PATH *pb; /* pathname struct buffer */ 367: { 368: int readpath(); /* read project or regular pathname */ 369: 370: if (readpath(pathname, pb) == -1 || (pb->p_mode & P_IFMT) == P_IFNEW) 371: { 372: patherr(pathname); 373: return(NO); 374: } 375: return(YES); 376: }