1: static char *rcsid = "$Header"; 2: /* 3: * mkproject - make a project root directory 4: * 5: * Author: Peter J. Nicklin 6: */ 7: #include <signal.h> 8: #include <stdio.h> 9: #include <sys/types.h> 10: #include <sys/stat.h> 11: #include "getarg.h" 12: #include "macro.h" 13: #include "null.h" 14: #include "path.h" 15: #include "pdb.h" 16: #include "pld.h" 17: #include "slist.h" 18: #include "spms.h" 19: #include "system.h" 20: #include "yesno.h" 21: 22: char CWD[PATHSIZE]; /* current working directory */ 23: char *CWP; /* current working project */ 24: char *PGN = "mkproject"; /* program name */ 25: int WANT_TO_EXIT = 0; /* advisory exit flag */ 26: 27: main(argc, argv) 28: int argc; 29: char **argv; 30: { 31: extern int PPDEBUG; /* project pathname debug flag */ 32: char *alias = NULL; /* alternative project directory name */ 33: char *getcwp(); /* get current working project */ 34: char *getwd(); /* get current working directory */ 35: int addtyp(); /* make project directory type labels */ 36: int chalias(); /* change project directory alias */ 37: int chdesc(); /* change project directory descrip */ 38: int isfg(); /* is process in foreground? */ 39: int minusdflag = YES; /* project directory description flag */ 40: int mkproject(); /* make a project root directory */ 41: int mustexist = 0; /* existing directories flag */ 42: int plusdflag = NO; /* project directory description flag */ 43: int typargtolist(); /* type labels -> pdirtyp list */ 44: int xppath(); /* expand project pathname */ 45: PATH pathbuf; /* pathname struct buffer */ 46: SLIST *pdirtyp; /* project directory type labels list */ 47: SLIST *slinit(); /* initialize singly-linked list */ 48: int onintr(); /* process signals */ 49: int status = 0; /* exit status */ 50: 51: pdirtyp = slinit(); 52: { 53: register char *s; /* option pointer */ 54: while (--argc > 0 && (**++argv == '-' || **argv == '+')) 55: { 56: if (**argv == '-') 57: { 58: for (s = argv[0]+1; *s != '\0'; s++) 59: switch (*s) 60: { 61: case 'D': 62: PPDEBUG = YES; 63: break; 64: case 'N': 65: alias = GETARG(s); 66: if (*alias == '\0') 67: status = 1; 68: goto endif; 69: case 'T': 70: if (typargtolist(GETARG(s),pdirtyp)==NO) 71: status = 1; 72: else if (*s == '\0') 73: status = 1; 74: goto endif; 75: case 'd': 76: minusdflag = NO; 77: break; 78: default: 79: warn("bad option -%c", *s); 80: status = 1; 81: goto endif; 82: } 83: } 84: else { 85: mustexist = 1; 86: for (s = argv[0]+1; *s != '\0'; s++) 87: switch (*s) 88: { 89: case 'N': 90: alias = GETARG(s); 91: if (*alias == '\0') 92: status = 1; 93: goto endif; 94: case 'T': 95: if (typargtolist(GETARG(s),pdirtyp)==NO) 96: status = 1; 97: else if (*s == '\0') 98: status = 1; 99: goto endif; 100: case 'd': 101: plusdflag = YES; 102: break; 103: default: 104: warn("bad option +%c", *s); 105: status = 1; 106: goto endif; 107: } 108: } 109: endif: continue; 110: } 111: if (status == 1 || argc < 1) 112: fatal("usage: mkproject [{+-}d] [{+-}N alias] %s", 113: "[{+-}T type[,type...]]\n projectname ..."); 114: } 115: 116: if (getwd(CWD) == NULL) 117: fatal("can't find current working directory"); 118: CWP = getcwp(); 119: if (isfg() == YES) 120: { 121: signal(SIGINT, onintr); 122: signal(SIGQUIT, onintr); 123: signal(SIGHUP, onintr); 124: } 125: 126: for (; argc > 0; argv++, argc--) 127: { 128: if (xppath(*argv, &pathbuf) == -1) 129: { 130: patherr(*argv); 131: status = 1; 132: continue; 133: } 134: if (CWP == NULL && (pathbuf.p_mode&P_IFMT) != P_IFHOME) 135: fatal("no project environment"); 136: if (mustexist) 137: switch (pathbuf.p_mode & P_IFMT) 138: { 139: case P_IFHOME: 140: case P_IFPROOT: 141: if (SLNUM(pdirtyp) > 0) 142: status |= addtyp(*argv, pdirtyp, 143: &pathbuf); 144: if (plusdflag == YES) 145: status |= chdesc(*argv, &pathbuf); 146: if (alias != NULL) 147: status |= chalias(*argv, alias, 148: &pathbuf); 149: break; 150: case P_IFPDIR: 151: warn("%s is a project directory", *argv); 152: status = 1; 153: break; 154: case P_IFNEW: 155: case P_IFREG: 156: warn("%s: no such project", *argv); 157: status = 1; 158: break; 159: } 160: else { 161: status |= mkproject(*argv, alias, pdirtyp, minusdflag, &pathbuf); 162: } 163: if (WANT_TO_EXIT) 164: exit(1); 165: } 166: exit(status); 167: } 168: 169: 170: 171: /* 172: * addtyp() adds type labels to an existing project directory. 173: */ 174: addtyp(ppathname, pdirtyp, pb) 175: char *ppathname; /* project directory pathname */ 176: SLIST *pdirtyp; /* project directory type labels list */ 177: PATH *pb; /* pathname struct buffer */ 178: { 179: char *pbfndkey(); /* find key */ 180: int closepdb(); /* close database */ 181: int errpdb(); /* print database error */ 182: int pgetent(); /* load next entry into buffer */ 183: int pputent(); /* write buffer to database */ 184: PDB *openpdb(); /* open database */ 185: PDB *pldp; /* project link directory stream */ 186: void pbaddtyp(); /* add type labels to buffer */ 187: 188: if ((pldp = openpdb(PLDNAME, pb->p_project, "rw")) == NULL) 189: return(errpdb((PDB *) NULL)); 190: while (pgetent(pldp) != EOF) 191: { 192: if (pbfndkey(CURPROJECT) != NULL) 193: pbaddtyp(ppathname, pdirtyp); 194: pputent(pldp); 195: } 196: return(closepdb(pldp)); 197: } 198: 199: 200: 201: /* 202: * badtyp() prints a bad format type label message. 203: */ 204: void 205: badtyp(type) 206: char *type; /* type label */ 207: { 208: warn("\"%s\" type label is badly formatted", type); 209: } 210: 211: 212: 213: /* 214: * chalias() changes an existing project directory alias. 215: */ 216: chalias(ppathname, newalias, pb) 217: char *ppathname; /* project directory pathname */ 218: char *newalias; /* new project directory alias */ 219: PATH *pb; /* pathname struct buffer */ 220: { 221: char *pbfndkey(); /* find key */ 222: char *ppathcat(); /* project pathname concatenation */ 223: char pppathname[PPATHSIZE]; /* parent project pathname */ 224: int _closepdb(); /* close database without updating */ 225: int closepdb(); /* close database */ 226: int errpdb(); /* print database error */ 227: int pbchgkey(); /* change existing key */ 228: int pgetent(); /* load next entry into buffer */ 229: int pputent(); /* write buffer to database */ 230: int xppath(); /* expand project pathname */ 231: PATH ppathbuf; /* parent pathname struct buffer */ 232: PDB *openpdb(); /* open database */ 233: PDB *pldp; /* project link directory stream */ 234: 235: ppathcat(pppathname, ppathname, PARENTPROJECT); 236: xppath(pppathname, &ppathbuf); 237: if ((pldp = openpdb(PLDNAME, ppathbuf.p_path, "rw")) == NULL) 238: return(errpdb((PDB *) NULL)); 239: while (pgetent(pldp) != EOF) 240: { 241: if (pbfndkey(newalias) != NULL) 242: { 243: warn("%s: %s exists", ppathname, newalias); 244: _closepdb(pldp); 245: return(1); 246: } 247: pbchgkey(pb->p_alias, newalias); 248: pputent(pldp); 249: } 250: return(closepdb(pldp)); 251: } 252: 253: 254: 255: /* 256: * chdesc() changes an existing project directory description. 257: */ 258: chdesc(ppathname, pb) 259: char *ppathname; /* project directory pathname */ 260: PATH *pb; /* pathname struct buffer */ 261: { 262: char *pbfndkey(); /* find key */ 263: int closepdb(); /* close database */ 264: int errpdb(); /* print database error */ 265: int pgetent(); /* load next entry into buffer */ 266: int pputent(); /* write buffer to database */ 267: PDB *openpdb(); /* open database */ 268: PDB *pldp; /* project link directory stream */ 269: void pbadddesc(); /* add project directory description */ 270: 271: if ((pldp = openpdb(PLDNAME, pb->p_project, "rw")) == NULL) 272: return(errpdb((PDB *) NULL)); 273: while (pgetent(pldp) != EOF) 274: { 275: if (pbfndkey(CURPROJECT) != NULL) 276: pbadddesc(ppathname); 277: pputent(pldp); 278: } 279: return(closepdb(pldp)); 280: } 281: 282: 283: 284: /* 285: * mkpld() creates a project link directory. If PLDNAME already exists, 286: * the database is altered accordingly. 287: */ 288: mkpld(pathname, ppathname, ptp, pdirtyp, dflag) 289: char *pathname; /* project root directory pathname */ 290: char *ppathname; /* project directory pathname */ 291: char *ptp; /* path to parent project */ 292: SLIST *pdirtyp; /* project directory type labels list */ 293: int dflag; /* project directory description flag */ 294: { 295: char *pathcat(); /* pathname concatenation */ 296: char *pbfndkey(); /* find key */ 297: char pldpath[PATHSIZE]; /* project link directory pathname */ 298: int closepdb(); /* close database */ 299: int errpdb(); /* print database error message */ 300: int pbaddflag(); /* add flag field */ 301: int pbaddkey(); /* add key */ 302: int pbaddstring(); /* add string field */ 303: int pgetent(); /* load database entry into buffer */ 304: int pputent(); /* write buffer to database */ 305: PDB *openpdb(); /* open database */ 306: PDB *pldp; /* project link directory stream */ 307: void pbclear(); /* clear buffer */ 308: void resetpdb(); /* reset current database pointer */ 309: void pbadddesc(); /* add project directory description */ 310: void pbaddtyp(); /* add type labels to buffer */ 311: 312: if (FILEXIST(pathcat(pldpath, pathname, PLDNAME))) 313: { 314: if ((pldp = openpdb(PLDNAME, pathname, "rw")) == NULL) 315: return(errpdb((PDB *) NULL)); 316: while (pgetent(pldp) != EOF) 317: { 318: if (pbfndkey(CURPROJECT) != NULL) 319: { 320: pbaddtyp(ppathname, pdirtyp); 321: if (dflag == YES) 322: pbadddesc(ppathname); 323: } 324: else if (pbfndkey(PARENTPROJECT) != NULL) 325: pbaddstring(PDIRPATH, ptp); 326: pputent(pldp); 327: } 328: } 329: else { 330: if ((pldp = openpdb(PLDNAME, pathname, "w")) == NULL) 331: return(errpdb((PDB *) NULL)); 332: 333: /* create current project entry */ 334: resetpdb(pldp); 335: pbclear(); 336: pbaddkey(CURPROJECT); 337: pbaddflag(PROOTDIR); 338: pbaddstring(PDIRPATH, CURDIR); 339: pbaddtyp(ppathname, pdirtyp); 340: if (dflag == YES) 341: pbadddesc(ppathname); 342: else 343: pbaddstring(PDIRDESC, ""); 344: pputent(pldp); 345: 346: /* create parent project entry */ 347: pbclear(); 348: pbaddkey(PARENTPROJECT); 349: pbaddflag(PROOTDIR); 350: pbaddstring(PDIRPATH, ptp); 351: pputent(pldp); 352: } 353: return(closepdb(pldp)); 354: } 355: 356: 357: 358: /* 359: * mkproject() makes a project root directory. 360: */ 361: mkproject(ppathname, alias, pdirtyp, dflag, pb) 362: char *ppathname; /* project root directory pathname */ 363: char *alias; /* alternative project directory name */ 364: int dflag; /* project directory description flag */ 365: SLIST *pdirtyp; /* project directory type labels list */ 366: PATH *pb; /* pathname struct buffer */ 367: { 368: char apathname[PATHSIZE]; /* absolute regular pathname */ 369: char *mkalias(); /* construct alias from pathname */ 370: char *mkptp(); /* make path to parent project */ 371: char *optpath(); /* optimize pathname */ 372: char *pathcat(); /* pathname concatenation */ 373: char *pbfndkey(); /* find database key */ 374: char *rdp; /* relative project directory path */ 375: char rpathname[PATHSIZE]; /* project root directory pathname */ 376: char *strcpy(); /* string copy */ 377: char *xorpath(); /* remove subpathname */ 378: int _closepdb(); /* close database without updating */ 379: int closepdb(); /* close database */ 380: int errpdb(); /* print database error message */ 381: int mkpld(); /* make project link directory */ 382: int mkrootproject(); /* make root project root directory */ 383: int pbaddflag(); /* add flag field */ 384: int pbaddkey(); /* add key */ 385: int pbaddstring(); /* add string field */ 386: int pgetent(); /* load next entry into buffer */ 387: int pputent(); /* write buffer to database */ 388: PDB *openpdb(); /* open database */ 389: PDB *pldp; /* project link directory stream */ 390: void pbadddesc(); /* add project directory description */ 391: void pbclear(); /* clear buffer */ 392: 393: switch (pb->p_mode & P_IFMT) 394: { 395: case P_IFNEW: 396: case P_IFREG: 397: break; 398: case P_IFHOME: 399: return(mkrootproject(ppathname, pdirtyp, dflag, pb)); 400: case P_IFPDIR: 401: case P_IFPROOT: 402: warn("%s exists", ppathname); 403: return(1); 404: } 405: 406: /* create pathname relative to project root directory */ 407: strcpy(rpathname, pb->p_project); 408: if (*pb->p_path == _RDIRC) 409: { 410: rdp = xorpath(rpathname, pb->p_path); 411: } 412: else { 413: optpath(pathcat(apathname, CWD, pb->p_path)); 414: rdp = xorpath(rpathname, apathname); 415: } 416: 417: /* open project link directory */ 418: if ((pldp = openpdb(PLDNAME, rpathname, "rw")) == NULL) 419: return(errpdb((PDB *) NULL)); 420: 421: /* 422: * check for existing aliases while preparing project link 423: * directory for new entry 424: */ 425: if (alias == NULL) 426: if (EQUAL(pb->p_alias, CURDIR) || EQUAL(pb->p_alias, PARENTDIR)) 427: alias = mkalias(rdp); 428: else 429: alias = pb->p_alias; 430: while (pgetent(pldp) != EOF) 431: { 432: if (pbfndkey(alias) != NULL) 433: { 434: warn("%s: %s exists", ppathname, alias); 435: _closepdb(pldp); 436: return(1); 437: } 438: pputent(pldp); 439: } 440: 441: /* make the directory if non-existent */ 442: if ((pb->p_mode & P_IFMT) == P_IFREG) 443: { 444: if ((pb->p_mode & S_IFMT) != S_IFDIR) 445: { 446: warn("%s: not a directory", ppathname); 447: _closepdb(pldp); 448: return(1); 449: } 450: } 451: else if (MK_DIR(pb->p_path) != 0) 452: { 453: _closepdb(pldp); 454: return(1); 455: } 456: 457: /* update database */ 458: pbclear(); 459: pbaddkey(alias); 460: pbaddflag(PROOTDIR); 461: pbaddstring(PDIRPATH, rdp); 462: pputent(pldp); 463: if (mkpld(pb->p_path, ppathname, mkptp(rpathname, rdp), pdirtyp, dflag) != 0) 464: { 465: _closepdb(pldp); 466: return(1); 467: } 468: return(closepdb(pldp)); 469: } 470: 471: 472: 473: /* 474: * mkptp() returns a pathname to the parent project root directory. 475: * It attempts to create a relative pathname if possible, otherwise 476: * the parent root directory pathname is used. 477: */ 478: char * 479: mkptp(rpathname, rdp) 480: char *rpathname; /* parent project root directory */ 481: register char *rdp; /* pathname to project being created */ 482: { 483: register char *rp; /* parent project root directory ptr */ 484: char *strpcpy(); /* string copy and update pointer */ 485: 486: if (*rdp == _RDIRC) 487: return(rpathname); 488: for(rp = rpathname; *rdp != '\0'; rdp++) 489: if (*rdp == _PSC) 490: rp = strpcpy(strpcpy(rp, PARENTDIR), PATHSEP); 491: rp = strpcpy(rp, PARENTDIR); 492: return(rpathname); 493: } 494: 495: 496: 497: /* 498: * mkrootproject creates a project link directory in the user's home 499: * directory. Returns zero if successful, otherwise 1. 500: */ 501: mkrootproject(ppathname, pdirtyp, dflag, pb) 502: char *ppathname; /* project pathname */ 503: SLIST *pdirtyp; /* project directory type labels list */ 504: int dflag; /* project directory description flag */ 505: PATH *pb; /* pathname struct buffer */ 506: { 507: char *pathcat(); /* pathname concatenation */ 508: char pldpath[PATHSIZE]; /* project link directory pathname */ 509: int mkpld(); /* make a project link directory */ 510: 511: if (FILEXIST(pathcat(pldpath, pb->p_path, PLDNAME))) 512: { 513: warn("%s exists", ppathname); 514: return(1); 515: } 516: return(mkpld(pb->p_path, ROOTPROJECT, CURDIR, pdirtyp, dflag)); 517: } 518: 519: 520: 521: /* 522: * onintr() resets interrupt, quit, and hangup signals, and sets a flag 523: * which advises the process to exit at the first opportunity. 524: */ 525: onintr() 526: { 527: signal(SIGINT, onintr); 528: signal(SIGQUIT, onintr); 529: signal(SIGHUP, onintr); 530: 531: WANT_TO_EXIT = 1; 532: } 533: 534: 535: 536: /* 537: * pbadddesc() fetchs a project directory description from stdin and 538: * adds to database buffer. 539: */ 540: void 541: pbadddesc(ppathname) 542: char *ppathname; /* project directory pathname */ 543: { 544: char dirdesc[DIRDESCSIZE]; /* project directory description */ 545: char *gets(); /* get a line from stdin */ 546: int pbaddstring(); /* add string field */ 547: 548: printf("%s: description? (1 line): ", ppathname); 549: gets(dirdesc); 550: pbaddstring(PDIRDESC, dirdesc); 551: } 552: 553: 554: 555: 556: /* 557: * pbaddtyp() adds type labels to database buffer. 558: */ 559: void 560: pbaddtyp(ppathname, typlist) 561: char *ppathname; /* project pathname */ 562: SLIST *typlist; /* type labels list */ 563: { 564: char *pbgetstring(); /* get specified string field */ 565: char *pdtfind(); /* find type label in buffer */ 566: char *pfxcpy(); /* copy string prefix */ 567: char *slget(); /* get next key from list */ 568: char *tp; /* pointer to type label */ 569: char type[TYPESIZE]; /* type label buffer */ 570: char typbuf[TYPBUFSIZE]; /* project directory types buffer */ 571: int pbaddstring(); /* add string field */ 572: void pdtinsert(); /* insert type label */ 573: void slrewind(); /* rewind list */ 574: 575: pbgetstring(PDIRTYPE, typbuf); 576: slrewind(typlist); 577: while ((tp = slget(typlist)) != NULL) 578: { 579: if (pdtfind(pfxcpy(type, tp), typbuf) == NULL) 580: pdtinsert(tp, typbuf); 581: else 582: warn("%s: \"%s\" type label exists", ppathname, type); 583: } 584: pbaddstring(PDIRTYPE, typbuf); 585: } 586: 587: 588: 589: /* 590: * typargtolist() prepends comma-separated type labels specified in typarg 591: * to typlist. Returns NO if type labels are badly formatted, otherwise 592: * YES. 593: */ 594: typargtolist(typarg, typlist) 595: register char *typarg; /* type labels argument */ 596: SLIST *typlist; /* type labels list */ 597: { 598: register char *t; /* type label argument pointer */ 599: char *slprepend(); /* prepend singly-linked list key */ 600: int ispdt(); /* is project dir type label legal? */ 601: int status = YES; /* return status */ 602: void badtyp(); /* print bad type label message */ 603: 604: for (t = typarg; *t != '\0'; t++) 605: continue; 606: for (; t >= typarg; t--) 607: if (t[0] == ',') 608: { 609: if (t[1] != '\0') 610: if (ispdt(t+1)) 611: slprepend(t+1, typlist); 612: else { 613: badtyp(t+1); 614: status = NO; 615: } 616: t[0] = '\0'; 617: } 618: if (ispdt(typarg)) 619: slprepend(typarg, typlist); 620: else { 621: badtyp(typarg); 622: status = NO; 623: } 624: return(status); 625: }