1: static char *rcsid = "$Header$"; 2: /* 3: * pmkdir - make a project 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 "system.h" 19: #include "yesno.h" 20: 21: char CWD[PATHSIZE]; /* current working directory */ 22: char *CWP; /* current working project */ 23: char *PGN = "pmkdir"; /* program name */ 24: int WANT_TO_EXIT = 0; /* advisory exit flag */ 25: 26: main(argc, argv) 27: int argc; 28: char **argv; 29: { 30: extern int PPDEBUG; /* project pathname debug flag */ 31: char *alias = NULL; /* alternative project directory name */ 32: char *getcwp(); /* get current working project */ 33: char *getwd(); /* get current working directory */ 34: int addtyp(); /* make project directory type labels */ 35: int chalias(); /* change project directory alias */ 36: int chdesc(); /* change project directory descrip */ 37: int isfg(); /* is process in foreground? */ 38: int minusdflag = YES; /* project directory description flag */ 39: int mkpdir(); /* make a project directory */ 40: int mustexist = 0; /* existing directories flag */ 41: int onintr(); /* process signals */ 42: int plusdflag = NO; /* project directory description flag */ 43: int status = 0; /* exit status */ 44: int typargtolist(); /* type labels -> pdirtyp list */ 45: int xppath(); /* expand project pathname */ 46: PATH pathbuf; /* pathname struct buffer */ 47: SLIST *pdirtyp; /* project directory type labels list */ 48: SLIST *slinit(); /* initialize singly-linked list */ 49: 50: pdirtyp = slinit(); 51: { 52: register char *s; /* option pointer */ 53: while (--argc > 0 && (**++argv == '-' || **argv == '+')) 54: { 55: if (**argv == '-') 56: { 57: for (s = argv[0]+1; *s != '\0'; s++) 58: switch (*s) 59: { 60: case 'D': 61: PPDEBUG = YES; 62: break; 63: case 'N': 64: alias = GETARG(s); 65: if (*alias == '\0') 66: status = 1; 67: goto endif; 68: case 'T': 69: if (typargtolist(GETARG(s),pdirtyp)==NO) 70: status = 1; 71: else if (*s == '\0') 72: status = 1; 73: goto endif; 74: case 'd': 75: minusdflag = NO; 76: break; 77: default: 78: warn("bad option -%c", *s); 79: status = 1; 80: goto endif; 81: } 82: } 83: else { 84: mustexist = 1; 85: for (s = argv[0]+1; *s != '\0'; s++) 86: switch (*s) 87: { 88: case 'N': 89: alias = GETARG(s); 90: if (*alias == '\0') 91: status = 1; 92: goto endif; 93: case 'T': 94: if (typargtolist(GETARG(s),pdirtyp)==NO) 95: status = 1; 96: else if (*s == '\0') 97: status = 1; 98: goto endif; 99: case 'd': 100: plusdflag = YES; 101: break; 102: default: 103: warn("bad option +%c", *s); 104: status = 1; 105: goto endif; 106: } 107: } 108: endif: continue; 109: } 110: if (status == 1 || argc < 1) 111: fatal("usage: pmkdir [{+-}d] [{+-}N alias] %s", 112: "[{+-}T type[,type...]]\n pdirname ..."); 113: } 114: 115: if ((CWP = getcwp()) == NULL) 116: fatal("no project environment"); 117: if (getwd(CWD) == NULL) 118: fatal("can't find current working directory"); 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 (mustexist) 135: switch (pathbuf.p_mode & P_IFMT) 136: { 137: case P_IFPDIR: 138: if (SLNUM(pdirtyp) > 0) 139: status |= addtyp(*argv, pdirtyp, 140: &pathbuf); 141: if (plusdflag == YES) 142: status |= chdesc(*argv, &pathbuf); 143: if (alias != NULL) 144: status |= chalias(*argv, alias, 145: &pathbuf); 146: break; 147: case P_IFNEW: 148: case P_IFREG: 149: warn("%s: no such project directory", *argv); 150: status = 1; 151: break; 152: case P_IFHOME: 153: case P_IFPROOT: 154: warn("%s is a project root directory", *argv); 155: status = 1; 156: break; 157: } 158: else 159: status |= mkpdir(*argv, alias, pdirtyp, minusdflag, &pathbuf); 160: if (WANT_TO_EXIT) 161: exit(1); 162: } 163: exit(status); 164: } 165: 166: 167: 168: /* 169: * addtyp() adds type labels to an existing project directory. 170: */ 171: addtyp(ppathname, pdirtyp, pb) 172: char *ppathname; /* project directory pathname */ 173: SLIST *pdirtyp; /* project directory type labels list */ 174: PATH *pb; /* pathname struct buffer */ 175: { 176: char *pbfndkey(); /* find key */ 177: int closepdb(); /* close database */ 178: int errpdb(); /* print database error */ 179: int pgetent(); /* load next entry into buffer */ 180: int pputent(); /* write buffer to database */ 181: PDB *openpdb(); /* open database */ 182: PDB *pldp; /* project link directory stream */ 183: void pbaddtyp(); /* add type labels to buffer */ 184: 185: if ((pldp = openpdb(PLDNAME, pb->p_project, "rw")) == NULL) 186: return(errpdb((PDB *) NULL)); 187: while (pgetent(pldp) != EOF) 188: { 189: if (pbfndkey(pb->p_alias) != NULL) 190: pbaddtyp(ppathname, pdirtyp); 191: pputent(pldp); 192: } 193: return(closepdb(pldp)); 194: } 195: 196: 197: 198: /* 199: * badtyp() prints a bad format type label message. 200: */ 201: void 202: badtyp(type) 203: char *type; /* type label */ 204: { 205: warn("\"%s\" type label is badly formatted", type); 206: } 207: 208: 209: 210: /* 211: * chalias() changes an existing project directory alias. 212: */ 213: chalias(ppathname, newalias, pb) 214: char *ppathname; /* project directory pathname */ 215: char *newalias; /* new project directory alias */ 216: PATH *pb; /* pathname struct buffer */ 217: { 218: char *pbfndkey(); /* find key */ 219: int _closepdb(); /* close database without updating */ 220: int closepdb(); /* close database */ 221: int errpdb(); /* print database error */ 222: int pbchgkey(); /* change existing key */ 223: int pgetent(); /* load next entry into buffer */ 224: int pputent(); /* write buffer to database */ 225: PDB *openpdb(); /* open database */ 226: PDB *pldp; /* project link directory stream */ 227: 228: if ((pldp = openpdb(PLDNAME, pb->p_project, "rw")) == NULL) 229: return(errpdb((PDB *) NULL)); 230: while (pgetent(pldp) != EOF) 231: { 232: if (pbfndkey(newalias) != NULL) 233: { 234: warn("%s: %s exists", ppathname, newalias); 235: _closepdb(pldp); 236: return(1); 237: } 238: pbchgkey(pb->p_alias, newalias); 239: pputent(pldp); 240: } 241: return(closepdb(pldp)); 242: } 243: 244: 245: 246: /* 247: * chdesc() changes an existing project directory description. 248: */ 249: chdesc(ppathname, pb) 250: char *ppathname; /* project directory pathname */ 251: PATH *pb; /* pathname struct buffer */ 252: { 253: char *pbfndkey(); /* find key */ 254: int closepdb(); /* close database */ 255: int errpdb(); /* print database error */ 256: int pgetent(); /* load next entry into buffer */ 257: int pputent(); /* write buffer to database */ 258: PDB *openpdb(); /* open database */ 259: PDB *pldp; /* project link directory stream */ 260: void pbadddesc(); /* add project directory description */ 261: 262: if ((pldp = openpdb(PLDNAME, pb->p_project, "rw")) == NULL) 263: return(errpdb((PDB *) NULL)); 264: while (pgetent(pldp) != EOF) 265: { 266: if (pbfndkey(pb->p_alias) != NULL) 267: pbadddesc(ppathname); 268: pputent(pldp); 269: } 270: return(closepdb(pldp)); 271: } 272: 273: 274: 275: /* 276: * mkpdir() makes a project directory. 277: */ 278: mkpdir(ppathname, alias, pdirtyp, dflag, pb) 279: char *ppathname; /* project directory pathname */ 280: char *alias; /* alternative project directory name */ 281: int dflag; /* project directory description flag */ 282: SLIST *pdirtyp; /* project directory type labels list */ 283: PATH *pb; /* pathname struct buffer */ 284: { 285: char apathname[PATHSIZE]; /* absolute regular pathname */ 286: char *mkalias(); /* construct alias from pathname */ 287: char *optpath(); /* optimize pathname */ 288: char *pathcat(); /* pathname concatenation */ 289: char *pbfndkey(); /* find database key */ 290: char *rdp; /* relative project directory path */ 291: char rpathname[PATHSIZE]; /* project root directory pathname */ 292: char *strcpy(); /* string copy */ 293: char *xorpath(); /* remove subpathname */ 294: int _closepdb(); /* close database without updating */ 295: int closepdb(); /* close database */ 296: int errpdb(); /* print database error message */ 297: int pbaddkey(); /* add key */ 298: int pbaddstring(); /* add string field */ 299: int pgetent(); /* load next entry into buffer */ 300: int pputent(); /* write buffer to database */ 301: PDB *openpdb(); /* open database */ 302: PDB *pldp; /* project link directory stream */ 303: void pbadddesc(); /* add project directory description */ 304: void pbaddtyp(); /* add type labels to buffer */ 305: void pbclear(); /* clear buffer */ 306: 307: switch (pb->p_mode & P_IFMT) 308: { 309: case P_IFNEW: 310: case P_IFREG: 311: break; 312: case P_IFPDIR: 313: case P_IFHOME: 314: case P_IFPROOT: 315: warn("%s exists", ppathname); 316: return(1); 317: } 318: 319: /* create pathname relative to project root directory */ 320: strcpy(rpathname, pb->p_project); 321: if (*pb->p_path == _RDIRC) 322: { 323: rdp = xorpath(rpathname, pb->p_path); 324: } 325: else { 326: optpath(pathcat(apathname, CWD, pb->p_path)); 327: rdp = xorpath(rpathname, apathname); 328: } 329: 330: /* open project link directory */ 331: if ((pldp = openpdb(PLDNAME, rpathname, "rw")) == NULL) 332: return(errpdb((PDB *) NULL)); 333: 334: /* 335: * check for existing aliases while preparing project link 336: * directory for new entry. 337: */ 338: if (alias == NULL) 339: if (EQUAL(pb->p_alias, CURDIR) || EQUAL(pb->p_alias, PARENTDIR)) 340: alias = mkalias(rdp); 341: else 342: alias = pb->p_alias; 343: while (pgetent(pldp) != EOF) 344: { 345: if (pbfndkey(alias) != NULL) 346: { 347: warn("%s: %s exists", ppathname, alias); 348: _closepdb(pldp); 349: return(1); 350: } 351: pputent(pldp); 352: } 353: 354: /* make the directory if non-existent */ 355: if ((pb->p_mode & P_IFMT) == P_IFREG) 356: { 357: if ((pb->p_mode & S_IFMT) != S_IFDIR) 358: { 359: warn("%s: not a directory", ppathname); 360: _closepdb(pldp); 361: return(1); 362: } 363: } 364: else if (MK_DIR(pb->p_path) != 0) 365: { 366: _closepdb(pldp); 367: return(1); 368: } 369: 370: /* update database */ 371: pbclear(); 372: pbaddkey(alias); 373: pbaddstring(PDIRPATH, rdp); 374: pbaddtyp(ppathname, pdirtyp); 375: if (dflag == YES) 376: pbadddesc(ppathname); 377: else 378: pbaddstring(PDIRDESC, ""); 379: pputent(pldp); 380: return(closepdb(pldp)); 381: } 382: 383: 384: 385: /* 386: * onintr() resets interrupt, quit, and hangup signals, and sets a flag 387: * which advises the process to exit at the first opportunity. 388: */ 389: onintr() 390: { 391: signal(SIGINT, onintr); 392: signal(SIGQUIT, onintr); 393: signal(SIGHUP, onintr); 394: 395: WANT_TO_EXIT = 1; 396: } 397: 398: 399: 400: /* 401: * pbadddesc() fetchs a project directory description from stdin and 402: * adds to database buffer. 403: */ 404: void 405: pbadddesc(ppathname) 406: char *ppathname; /* project directory pathname */ 407: { 408: char dirdesc[DIRDESCSIZE]; /* project directory description */ 409: char *gets(); /* get a line from stdin */ 410: int pbaddstring(); /* add string field */ 411: 412: printf("%s: description? (1 line): ", ppathname); 413: gets(dirdesc); 414: pbaddstring(PDIRDESC, dirdesc); 415: } 416: 417: 418: 419: /* 420: * pbaddtyp() adds type labels to database buffer. 421: */ 422: void 423: pbaddtyp(ppathname, typlist) 424: char *ppathname; /* project pathname */ 425: SLIST *typlist; /* type labels list */ 426: { 427: char *pbgetstring(); /* get specified string field */ 428: char *pdtfind(); /* find type label in buffer */ 429: char *pfxcpy(); /* copy string prefix */ 430: char *slget(); /* get next key from list */ 431: char *tp; /* pointer to type label */ 432: char type[TYPESIZE]; /* type label buffer */ 433: char typbuf[TYPBUFSIZE]; /* project directory types buffer */ 434: int pbaddstring(); /* add string field */ 435: void pdtinsert(); /* insert type label */ 436: void slrewind(); /* rewind list */ 437: 438: pbgetstring(PDIRTYPE, typbuf); 439: slrewind(typlist); 440: while ((tp = slget(typlist)) != NULL) 441: { 442: if (pdtfind(pfxcpy(type, tp), typbuf) == NULL) 443: pdtinsert(tp, typbuf); 444: else 445: warn("%s: \"%s\" type label exists", ppathname, type); 446: } 447: pbaddstring(PDIRTYPE, typbuf); 448: } 449: 450: 451: 452: /* 453: * typargtolist() prepends comma-separated type labels specified in typarg 454: * to typlist. Returns NO if type labels are badly formatted, otherwise 455: * YES. 456: */ 457: typargtolist(typarg, typlist) 458: register char *typarg; /* type labels argument */ 459: SLIST *typlist; /* type labels list */ 460: { 461: register char *t; /* type label argument pointer */ 462: char *slprepend(); /* prepend singly-linked list key */ 463: int ispdt(); /* is project dir type label legal? */ 464: int status = YES; /* return status */ 465: void badtyp(); /* print bad type label message */ 466: 467: for (t = typarg; *t != '\0'; t++) 468: continue; 469: for (; t >= typarg; t--) 470: if (t[0] == ',') 471: { 472: if (t[1] != '\0') 473: if (ispdt(t+1)) 474: slprepend(t+1, typlist); 475: else { 476: badtyp(t+1); 477: status = NO; 478: } 479: t[0] = '\0'; 480: } 481: if (ispdt(typarg)) 482: slprepend(typarg, typlist); 483: else { 484: badtyp(typarg); 485: status = NO; 486: } 487: return(status); 488: }