1: static char *rcsid = "$Header$"; 2: /* 3: * ppd - list project directories 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 "slslist.h" 16: #include "spms.h" 17: #include "yesno.h" 18: 19: #define MAXLINE 80 /* maximum output line size */ 20: #define TABSIZE 8 /* default tab width */ 21: #define MINIMUM_GAP 2 /* minimum space between items */ 22: 23: /* 24: * Information request definitions 25: */ 26: #define ABSOLUTE_PATH_INFO 1 /* list absolute pathnames */ 27: #define ALIAS_INFO 2 /* list aliases + absolute pathnames */ 28: #define DESCRIPTION_INFO 3 /* list directory descriptions */ 29: #define REGULAR_INFO 4 /* list project directory aliases */ 30: #define TYPE_LABEL_INFO 5 /* list type labels */ 31: 32: char *PGN = "ppd"; /* program name */ 33: int INFORMATION = REGULAR_INFO; /* type of information to be printed */ 34: int LIST_ALL_ENTRIES = NO; /* print "..." && "...." ? */ 35: int LIST_PLD_CONTENTS = YES; /* list project link dir contents */ 36: int MARK_PROJECT_ROOT = 0; /* append project root dirs with `^' */ 37: int ONE_ENTRY_PER_LINE = 0; /* print 1 project directory/line */ 38: int PRINT_HEADING = YES; /* print headings for projects */ 39: int RECURSIVE = 0; /* recursively print projects */ 40: PDTYP PDIRTYP; /* project directory type labels list */ 41: 42: main(argc, argv) 43: int argc; 44: char **argv; 45: { 46: extern int PPDEBUG; /* project pathname debug flag */ 47: char *cwp; /* current working project */ 48: char *getcwp(); /* get current working project */ 49: char *slsappend(); /* append key+string */ 50: int pdtolist(); /* add project directories to pdlist */ 51: int pdtparse(); /* parse boolean type label expr */ 52: int qsort(); /* quicker sort */ 53: int readpath(); /* read project or regular pathname */ 54: int status = 0; /* exit status */ 55: int strpcmp(); /* compare pointed-to strings */ 56: PATH pathbuf; /* pathname struct buffer */ 57: SLSBLK *pblk; /* project list block */ 58: SLSLIST *pdlist; /* project directory list */ 59: SLSLIST *plist; /* project list */ 60: SLSLIST *slsinit(); /* initialize key+string list */ 61: void printlist(); /* print project directory list */ 62: void slsrm(); /* remove key+string list */ 63: 64: { 65: register char *s; /* option pointer */ 66: while (--argc > 0 && **++argv == '-') 67: { 68: for (s = argv[0]+1; *s != '\0'; s++) 69: switch (*s) 70: { 71: case '1': 72: ONE_ENTRY_PER_LINE++; 73: break; 74: case 'D': 75: PPDEBUG = YES; 76: break; 77: case 'T': 78: if (pdtparse(GETARG(s), &PDIRTYP) == NO) 79: status = 1; 80: goto endfor; 81: case 'a': 82: LIST_ALL_ENTRIES = YES; 83: break; 84: case 'd': 85: INFORMATION = DESCRIPTION_INFO; 86: ONE_ENTRY_PER_LINE++; 87: break; 88: case 'l': 89: INFORMATION = ABSOLUTE_PATH_INFO; 90: ONE_ENTRY_PER_LINE++; 91: break; 92: case 'm': 93: MARK_PROJECT_ROOT++; 94: break; 95: case 'n': 96: INFORMATION = ALIAS_INFO; 97: ONE_ENTRY_PER_LINE++; 98: break; 99: case 'p': 100: LIST_PLD_CONTENTS = NO; 101: break; 102: case 'q': 103: PRINT_HEADING = NO; 104: break; 105: case 'r': 106: RECURSIVE++; 107: break; 108: case 't': 109: INFORMATION = TYPE_LABEL_INFO; 110: ONE_ENTRY_PER_LINE++; 111: break; 112: default: 113: warn("bad option -%c", *s); 114: status = 1; 115: goto endfor; 116: } 117: endfor: continue; 118: } 119: } 120: if (status == 1) 121: fatal("usage: ppd [-1adlmnpqrt] [-T typexpr] [pdirname ...]"); 122: 123: if (argc < 1) 124: { 125: if ((cwp = getcwp()) == NULL) 126: fatal("no project environment"); 127: status |= listproject("", cwp); 128: exit(status); 129: } 130: 131: pdlist = slsinit(); 132: plist = slsinit(); 133: qsort((char *) argv, argc, sizeof(char *), strpcmp); 134: for (; argc > 0; argc--, argv++) 135: if (readpath(*argv, &pathbuf) == -1) 136: { 137: patherr(*argv); 138: status = 1; 139: } 140: else switch (pathbuf.p_mode & P_IFMT) 141: { 142: case P_IFNEW: 143: case P_IFREG: 144: warn("%s: no such project or project directory", *argv); 145: status = 1; 146: break; 147: case P_IFHOME: 148: case P_IFPROOT: 149: if (LIST_PLD_CONTENTS == YES) 150: { 151: if (slsappend(*argv, pathbuf.p_path, 152: plist) == NULL) 153: exit(1); 154: } 155: else { 156: status |= pdtolist(*argv, &pathbuf, pdlist); 157: } 158: break; 159: case P_IFPDIR: 160: status |= pdtolist(*argv, &pathbuf, pdlist); 161: break; 162: } 163: 164: /* don't bother to print heading if single project request */ 165: if (RECURSIVE == 0 && SLSNUM(pdlist) == 0 && SLSNUM(plist) == 1) 166: PRINT_HEADING = NO; 167: 168: /* print discrete project directories */ 169: printlist("", pdlist); 170: slsrm(CNULL, pdlist); 171: 172: /* print projects */ 173: for (pblk = plist->head; pblk != NULL; pblk = pblk->next) 174: status |= listproject(pblk->key, pblk->string); 175: exit(status); 176: } 177: 178: 179: 180: /* 181: * getpdesc() gets a project description. Returns constant 1 if error, 182: * otherwise 0. 183: */ 184: getpdesc(desc, pathname) 185: char *desc; /* description receiving buffer */ 186: char *pathname; /* project link directory pathname */ 187: { 188: char *pbgetstring(); /* get specified string field */ 189: int closepdb(); /* close database */ 190: int errpdb(); /* print database error message */ 191: int pfndent(); /* find and load database entry */ 192: PDB *pldp; /* project link directory stream */ 193: PDB *openpdb(); /* open database */ 194: 195: *desc = '\0'; 196: if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL) 197: return(errpdb((PDB *) NULL)); 198: if (pfndent(CURPROJECT, pldp) == YES) 199: pbgetstring(PDIRDESC, desc); 200: return(closepdb(pldp)); 201: } 202: 203: 204: 205: /* 206: * getptype() gets project root directory types. Returns constant 1 if error, 207: * otherwise 0. 208: */ 209: getptype(type, pathname) 210: char *type; /* type receiving buffer */ 211: char *pathname; /* project link directory pathname */ 212: { 213: char *pbgetstring(); /* get specified string field */ 214: int closepdb(); /* close database */ 215: int errpdb(); /* print database error message */ 216: int pfndent(); /* find and load database entry */ 217: PDB *pldp; /* project link directory stream */ 218: PDB *openpdb(); /* open database */ 219: 220: *type = '\0'; 221: if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL) 222: return(errpdb((PDB *) NULL)); 223: if (pfndent(CURPROJECT, pldp) == YES) 224: pbgetstring(PDIRTYPE, type); 225: return(closepdb(pldp)); 226: } 227: 228: 229: 230: /* 231: * ksprint() prints a list of key+string pairs (one pair per line). 232: */ 233: void 234: ksprint(colwidth, pdlist) 235: int colwidth; /* maximum column width */ 236: SLSLIST *pdlist; /* project directory list */ 237: { 238: register char *kp; /* key pointer */ 239: register char *tp; /* type label pointer */ 240: register int cw; /* column width */ 241: SLSBLK *curblk; /* current list block */ 242: 243: for (curblk = pdlist->head; curblk != NULL; curblk = curblk->next) 244: { 245: for (cw=colwidth, kp=curblk->key; *kp != '\0' && cw-- > 0; kp++) 246: putchar(*kp); 247: if (cw > 0 && *curblk->string != '\0') 248: for(; cw > 0; cw -= TABSIZE) 249: putchar('\t'); 250: if (INFORMATION == TYPE_LABEL_INFO) 251: { 252: for (tp = curblk->string; *tp != '\0'; tp++) 253: if (*tp == _PDTSC) 254: { 255: putchar(','); 256: putchar(' '); 257: } 258: else { 259: putchar(*tp); 260: } 261: putchar('\n'); 262: } 263: else { 264: puts(curblk->string); 265: } 266: } 267: } 268: 269: 270: 271: /* 272: * listproject() lists a project link directory. 273: */ 274: listproject(ppathname, pathname) 275: char *ppathname; /* project pathname */ 276: char *pathname; /* regular pathname */ 277: { 278: register char *alias; /* alias buffer pointer */ 279: register char *path; /* path buffer pointer */ 280: char aliasbuf[ALIASSIZE+1]; /* alias marking buffer */ 281: char descbuf[DIRDESCSIZE]; /* project root directory description */ 282: char *kp; /* key pointer */ 283: char pathbuf[PATHSIZE+1]; /* regular pathname marking buffer */ 284: char ppathbuf[PPATHSIZE]; /* project path concatenation buffer */ 285: char *ppathcat(); /* project pathname concatenation */ 286: char *slsappend(); /* append key+string */ 287: char *strcat(); /* string concatenation */ 288: char *strcpy(); /* string copy */ 289: char typebuf[TYPBUFSIZE]; /* project root directory types */ 290: int closepdb(); /* close database */ 291: int errpdb(); /* print database error message */ 292: int getpdesc(); /* get project description */ 293: int getptype(); /* get project root directory types */ 294: int pdtmatch(); /* match project dir type label expr */ 295: int slssort(); /* sort key+string list */ 296: int status = 0; /* return status */ 297: int strcmp(); /* string comparison */ 298: PATH *pd; /* pathname struct pointer */ 299: PATH *readpld(); /* read project link directory entry */ 300: PDB *openpdb(); /* open database */ 301: PDB *pldp; /* project link directory stream */ 302: SLSBLK *pblk; /* project list block */ 303: SLSLIST *pdlist; /* project directory list */ 304: SLSLIST *plist; /* project list */ 305: SLSLIST *slsinit(); /* initialize key+string list */ 306: void printlist(); /* print project directory list */ 307: void slsrm(); /* remove key+string list */ 308: 309: pdlist = slsinit(); 310: plist = slsinit(); 311: 312: /* read PLDNAME project link directory */ 313: if ((pldp = openpdb(PLDNAME, pathname, "r")) == NULL) 314: return(errpdb((PDB *) NULL)); 315: while ((pd = readpld(pldp)) != NULL) 316: { 317: alias = pd->p_alias; 318: path = pd->p_path; 319: if (EQUAL(alias, PARENTPROJECT)) 320: { 321: if (LIST_ALL_ENTRIES == NO) 322: continue; 323: } 324: else if (EQUAL(alias, CURPROJECT)) 325: { 326: if (PDIRTYP.pfxsize == 0 && LIST_ALL_ENTRIES == NO) 327: continue; 328: } 329: else if (RECURSIVE && pd->p_mode == P_IFPROOT) 330: if (slsappend(alias, path, plist) == NULL) 331: exit(1); 332: 333: if (PDIRTYP.pfxsize != 0 && pdtmatch(&PDIRTYP,pd->p_type) == NO) 334: continue; 335: 336: if (MARK_PROJECT_ROOT) 337: if (pd->p_mode == P_IFPROOT) 338: if (INFORMATION == ABSOLUTE_PATH_INFO) 339: { 340: path = strcpy(pathbuf, path); 341: strcat(path, ROOTPROJECT); 342: } 343: else { 344: alias = strcpy(aliasbuf, alias); 345: strcat(alias, ROOTPROJECT); 346: } 347: 348: switch (INFORMATION) 349: { 350: case REGULAR_INFO: 351: kp = slsappend(alias, "", pdlist); 352: break; 353: case ABSOLUTE_PATH_INFO: 354: kp = slsappend(path, "", pdlist); 355: break; 356: case ALIAS_INFO: 357: kp = slsappend(alias, path, pdlist); 358: break; 359: case TYPE_LABEL_INFO: 360: if (pd->p_mode == P_IFPDIR) 361: { 362: kp=slsappend(alias, pd->p_type, pdlist); 363: } 364: else { 365: status |= getptype(typebuf, path); 366: kp=slsappend(alias, typebuf, pdlist); 367: } 368: break; 369: case DESCRIPTION_INFO: 370: if (pd->p_mode == P_IFPDIR) 371: { 372: kp=slsappend(alias, pd->p_desc, pdlist); 373: } 374: else { 375: status |= getpdesc(descbuf, path); 376: kp=slsappend(alias, descbuf, pdlist); 377: } 378: break; 379: } 380: if (kp == NULL) 381: exit(1); 382: } 383: status |= closepdb(pldp); 384: 385: /* sort and print project directories */ 386: if (slssort(strcmp, pdlist) == NO) 387: exit(1); 388: printlist(ppathname, pdlist); 389: slsrm(CNULL, pdlist); 390: 391: /* if RECURSIVE, list subprojects */ 392: if (RECURSIVE) 393: { 394: if (slssort(strcmp, plist) == NO) 395: exit(1); 396: for (pblk = plist->head; pblk != NULL; pblk = pblk->next) 397: { 398: ppathcat(ppathbuf, ppathname, pblk->key); 399: status |= listproject(ppathbuf, pblk->string); 400: } 401: } 402: slsrm(CNULL, plist); 403: 404: return(status); 405: } 406: 407: 408: 409: /* 410: * pdtolist() adds project (root) directories to pdlist. Returns 411: * constant 1 if error, otherwise 0. 412: */ 413: pdtolist(ppathname, pb, pdlist) 414: char *ppathname; /* project pathname */ 415: PATH *pb; /* pathname struct buffer */ 416: SLSLIST *pdlist; /* project directory list */ 417: { 418: char *kp; /* key pointer */ 419: char *slsappend(); /* append key+string */ 420: char *strcat(); /* string concatenation */ 421: int status = 0; /* return status */ 422: unsigned long pathtyp; /* type of pathname */ 423: 424: pathtyp = pb->p_mode & P_IFMT; 425: 426: if (MARK_PROJECT_ROOT) 427: if (pathtyp == P_IFHOME || pathtyp == P_IFPROOT) 428: if (INFORMATION == ABSOLUTE_PATH_INFO) 429: strcat(pb->p_path, ROOTPROJECT); 430: else 431: strcat(ppathname, ROOTPROJECT); 432: switch (INFORMATION) 433: { 434: case REGULAR_INFO: 435: kp = slsappend(ppathname, "", pdlist); 436: break; 437: case ABSOLUTE_PATH_INFO: 438: kp = slsappend(pb->p_path, "", pdlist); 439: break; 440: case ALIAS_INFO: 441: kp = slsappend(ppathname, pb->p_path, pdlist); 442: break; 443: case TYPE_LABEL_INFO: 444: kp = slsappend(ppathname, pb->p_type, pdlist); 445: break; 446: case DESCRIPTION_INFO: 447: kp = slsappend(ppathname, pb->p_desc, pdlist); 448: break; 449: } 450: if (kp == NULL) 451: exit(1); 452: return(status); 453: } 454: 455: 456: 457: /* 458: * printlist() prints out a list of project directories. 459: */ 460: void 461: printlist(ppathname, pdlist) 462: char *ppathname; /* project pathname */ 463: SLSLIST *pdlist; /* project directory list */ 464: { 465: static int have_printed; /* has printing already been done? */ 466: int colwidth; /* maximum column width */ 467: int ncol; /* number of columns */ 468: void ksprint(); /* print list of key+string pairs */ 469: void slsprint(); /* print key+string list (key only) */ 470: 471: colwidth = pdlist->maxkey + MINIMUM_GAP; 472: if (colwidth % TABSIZE) colwidth = TABSIZE * (colwidth/TABSIZE + 1); 473: 474: if (*ppathname != '\0' && PRINT_HEADING == YES) 475: printf((have_printed) ? "\n%s:\n" : "%s:\n", ppathname); 476: 477: if (INFORMATION == REGULAR_INFO || INFORMATION == ABSOLUTE_PATH_INFO) 478: if (ONE_ENTRY_PER_LINE) 479: slsprint(1, colwidth, YES, stdout, pdlist); 480: else { 481: ncol = MAXLINE / colwidth; 482: slsprint(ncol, colwidth, YES, stdout, pdlist); 483: } 484: else 485: ksprint(colwidth, pdlist); 486: 487: if (SLSNUM(pdlist) > 0) 488: have_printed = 1; 489: } 490: 491: 492: 493: /* 494: * strpcmp() compares strings stored in a pointer array. Returns whatever 495: * strcmp() returns. 496: */ 497: strpcmp(p1, p2) 498: char **p1, **p2; /* string pointers */ 499: { 500: int strcmp(); /* string comparison */ 501: 502: return(strcmp(*p1, *p2)); 503: }