|
|
1.1 ! root 1: .nr PS 12 ! 2: .NH ! 3: Simple Tasks ! 4: .nr PS 10 ! 5: .XS ! 6: \*(SN Simple Tasks ! 7: .XE ! 8: .PP ! 9: In this document several examples related to an interactive screen-oriented ! 10: spreadsheet program are presented to demonstrate the use of SPMS for ! 11: software development and project management. It is assumed that the ! 12: reader is familiar with the ! 13: .UX ! 14: operating system and a text editor such as ! 15: .I ex. ! 16: In these examples, user input is shown in \fBbold\fR face. ! 17: .NH 2 ! 18: Getting Started ! 19: .XS ! 20: \*(SN Getting Started ! 21: .XE ! 22: .PP ! 23: Before using SPMS for the first time the following steps must be performed\** ! 24: .FS ! 25: For C shell, (\fIcsh\fR), users only. Consult the UNIX Programmer's ! 26: Manual for instructions on how to set up SPMS for the Bourne shell, ! 27: (\fIsh\fR). ! 28: .FE ! 29: .IP 1. ! 30: Include the directory `/usr/new' in the ! 31: command search path. This is done by altering the PATH environment variable ! 32: in one of the startup files, `.cshrc' or `.login', in the home directory. ! 33: .IP 2. ! 34: Add the following aliases to the `.cshrc' file located in the home directory ! 35: .br ! 36: alias chproject \'eval \`\^"chproject" \\!*\`\^\' ! 37: .br ! 38: alias pd \'eval \`\^"pd" \\!*\`\^\' ! 39: .IP 3. ! 40: Add the following command to the `.login' file located in the home directory ! 41: .br ! 42: chproject ^ ! 43: .IP 4. ! 44: Convert the home directory to a project root directory by typing ! 45: .br ! 46: \fB/usr/new/mkproject \-d ^\fR ! 47: .IP 5. ! 48: Execute the `.cshrc' and `.login' files by typing ! 49: .br ! 50: \fBsource .cshrc\fR ! 51: .br ! 52: \fBsource .login\fR ! 53: .NH 2 ! 54: Building a Project ! 55: .XS ! 56: \*(SN Building a Project ! 57: .XE ! 58: .PP ! 59: The directory structure to support a software package is created by the ! 60: .I mkproject ! 61: and ! 62: .I pmkdir ! 63: commands. These commands create directories using the standard ! 64: .UX ! 65: .I mkdir ! 66: command, and record information about each directory in a project database ! 67: called the ! 68: .I ! 69: project link directory. ! 70: .R ! 71: This information is used by various SPMS commands to control the development ! 72: and maintenance activities for a project. ! 73: .PP ! 74: The steps for building the project structure are: ! 75: .IP 1. ! 76: Initialize the project using the ! 77: .I mkproject ! 78: command. ! 79: .I Mkproject ! 80: creates a directory known as a ! 81: .I ! 82: project root directory, ! 83: .R ! 84: to serve as the focus for a project, and initializes the project database. ! 85: After ! 86: .I mkproject ! 87: creates the project root directory, the user is prompted for a line ! 88: describing the purpose of the project. ! 89: .IP 2. ! 90: Use the \fI\%chproject\fR command to change to the root directory of ! 91: the new project and make it the \fIworking project\fR (see \(sc\|2.13). ! 92: .IP 3. ! 93: Create the project directories using the ! 94: .I pmkdir ! 95: command. After ! 96: .I pmkdir ! 97: creates each directory, the user is prompted for a line describing the ! 98: purpose of the directory. ! 99: .PP ! 100: To illustrate this process, the following commands create project `vs' ! 101: with directories `doc', `src', and `work' (see fig. 2) to support a ! 102: `Visual Spreadsheet' program\** called \fIvs\fR. ! 103: .FS ! 104: \fIVs\fR is a fictitious name bearing no resemblance to any actual program. ! 105: .FE ! 106: .DS ! 107: % \fBmkproject vs\fR ! 108: vs: description? (1 line): \fBVisual Spreadsheet\fR ! 109: % \fBchproject vs\fR ! 110: % \fBpmkdir doc src work\fR ! 111: doc: description? (1 line): \fBvs user's guide\fR ! 112: src: description? (1 line): \fBvs program source code\fR ! 113: work: description? (1 line): \fBvs workbench\fR ! 114: % ! 115: .DE ! 116: .KF ! 117: .sp 11 ! 118: .SM ! 119: .ce ! 120: \fIFigure 2. \fRLayout of the project `vs' ! 121: ! 122: .NL ! 123: .KE ! 124: .NH 2 ! 125: Displaying a Project ! 126: .XS ! 127: \*(SN Displaying a Project ! 128: .XE ! 129: .PP ! 130: The ! 131: .I ppd ! 132: ``\fBp\fRrint \fBp\fRroject \fBd\fRirectory'' command may be used to list ! 133: the directories belonging to `vs': ! 134: .DS ! 135: % \fBppd\fR ! 136: doc src work ! 137: % ! 138: .DE ! 139: Alternatively, a table of contents for the project can be obtained by using ! 140: .I ppd ! 141: with the \fB\-d\fR description option to print the description of each project ! 142: directory. ! 143: .DS ! 144: % \fBppd \-d\fR ! 145: doc vs user's guide ! 146: src vs program source code ! 147: work vs workbench ! 148: % ! 149: .DE ! 150: .NH 2 ! 151: Moving Around Inside a Project ! 152: .XS ! 153: \*(SN Moving Around Inside a Project ! 154: .XE ! 155: .PP ! 156: The ! 157: .I pd ! 158: command provides a convenient way for changing to another project directory ! 159: without the user having to remember it's precise location. For example, ! 160: to move to the source code directory `src', type ! 161: .ID ! 162: % \fBpd src\fR ! 163: .DE ! 164: To change to the directory `work', type ! 165: .ID ! 166: % \fBpd work\fR ! 167: .DE ! 168: To return to the project root directory, type ! 169: .ID ! 170: % \fBpd\fR ! 171: .DE ! 172: without any arguments. ! 173: .NH 2 ! 174: Compiling a Program ! 175: .XS ! 176: \*(SN Compiling a Program ! 177: .XE ! 178: .PP ! 179: Program development and maintenance is handled by the ! 180: .I make ! 181: command\|[3]. ! 182: .I Make ! 183: mechanizes many development and maintenance activities, including ! 184: compiling and linking of programs, printing of source code, and the removal ! 185: of unneeded files. The instructions which tell ! 186: .I make ! 187: how to perform these duties are kept in a special file known as a makefile, ! 188: together with the names of the source code files which make up the ! 189: program. The makefile editor program, ! 190: .I mkmf, ! 191: creates the makefile (named `Makefile' by default) by gathering up ! 192: the names of all the source code files in the current working directory and ! 193: inserting them into a standard makefile. ! 194: .PP ! 195: The following example shows how to produce the program for the visual ! 196: spreadsheet, given the file `vs.c' containing the source code in the directory ! 197: `src'. ! 198: .DS ! 199: % \fBmkmf\fR ! 200: mkmf: creating Makefile from template /usr/new/lib/p.Makefile ! 201: % \fBmake\fR ! 202: cc \-c vs.c ! 203: Loading a.out ... done ! 204: % ! 205: .DE ! 206: In this example the executable program is called `a.out'. However, by using the ! 207: makefile editor interactively the name `vs' could have been specified instead: ! 208: .DS ! 209: % \fBmkmf \-i\fR ! 210: mkmf: creating Makefile from template /usr/new/lib/p.Makefile ! 211: program name? \fBvs\fR ! 212: destination directory? ! 213: % \fBmake\fR ! 214: cc \-c vs.c ! 215: Loading vs ... done ! 216: % ! 217: .DE ! 218: Since a carriage return was typed in response to the second question in ! 219: the example above, the destination directory for the program remains the ! 220: current directory. ! 221: .PP ! 222: Because program ! 223: .I vs ! 224: is a screen-oriented program, it would not be ! 225: surprising if it requires special functions to control cursor movement ! 226: and updating of the terminal screen. There is a standard package of C ! 227: library functions for this purpose called `curses'\|[1], and if the program ! 228: has taken advantage of these functions, this library should be included ! 229: in the makefile together with the terminal database package `termlib'. ! 230: This can be done by including the LIBS macro definition as an argument to the ! 231: .I mkmf ! 232: command\** ! 233: .FS ! 234: Arguments with embedded blanks in UNIX commands must be enclosed by double ! 235: quotes. ! 236: .FE ! 237: .ID ! 238: % \fBmkmf \-i "LIBS=\-lcurses \-ltermlib"\fR ! 239: .DE ! 240: .NH 2 ! 241: Moving Files Within a Project ! 242: .XS ! 243: \*(SN Moving Files Within a Project ! 244: .XE ! 245: .PP ! 246: A file can be moved to another project directory by using the ! 247: .I pmv ! 248: command. For instance, the following command moves the executable program ! 249: .I vs ! 250: from the current working directory to the `work' directory ! 251: .ID ! 252: % \fBpmv vs work\fR ! 253: .DE ! 254: In a similar manner, files can be copied from one project directory ! 255: to another using the ! 256: .I pcp ! 257: command. ! 258: .I Pmv ! 259: and ! 260: .I pcp ! 261: behave very similarly to the standard ! 262: .UX ! 263: .I mv ! 264: and ! 265: .I cp ! 266: commands in that they blindly overwrite any existing files of the same ! 267: name in the destination directory unless the ! 268: .B \-i ! 269: interactive option is used. ! 270: .NH 2 ! 271: More on Building a Project ! 272: .XS ! 273: \*(SN More on Building a Project ! 274: .XE ! 275: .PP ! 276: As development of a software package continues, extra project directories may ! 277: be needed to support the work. For example, project `vs' must accommodate ! 278: an additional program called ! 279: .I vstutor ! 280: which provides instruction on the use of the visual spreadsheet program; ! 281: two library packages called `hash' and `list' for hash table and linked ! 282: list operations; and three files that are ``included'' in more than one ! 283: source file \- `vs.h' which contains common program definitions, ! 284: `hash.h' which defines hash tables, and `list.h' which holds linked ! 285: list definitions. Figure 3 shows the extra directories needed for ! 286: these components and the following command sequence creates them ! 287: .DS ! 288: % \fBpd\fR ! 289: % \fBpmkdir bin include lib\fR ! 290: bin: description? (1 line): \fBvs and vstutor programs\fR ! 291: include: description? (1 line): \fBcommon included files\fR ! 292: lib: description? (1 line): \fBcompiled hash table and list libraries\fR ! 293: % \fBpd src\fR ! 294: % \fBpmkdir vs vstutor libhash liblist\fR ! 295: vs: description? (1 line): \fBvs program source code\fR ! 296: vstutor: description? (1 line): \fBvstutor program source code\fR ! 297: libhash: description? (1 line): \fBhash table library source code\fR ! 298: liblist: description? (1 line): \fBlist library source code\fR ! 299: % ! 300: .DE ! 301: The final step is to change the description of the `src' directory now ! 302: that it has been subdivided into four separate source code ! 303: directories. This can be done by using the ! 304: .I pmkdir ! 305: with the \fB+d\fR (change \fBd\fRescription) option ! 306: .DS ! 307: % \fBpmkdir +d src\fR ! 308: src: description? (1 line): \fBC source code\fR ! 309: % ! 310: .DE ! 311: .KF ! 312: .sp 17 ! 313: .SM ! 314: .ce ! 315: \fIFigure 3. \fRRevised layout of project `vs' ! 316: ! 317: .NL ! 318: .KE ! 319: Note that in Figure 3 there are two directories called `vs'. The top one ! 320: bears the name of the project, and the bottom one is named according to the ! 321: program contained within it. Similarly, the directories `libhash' and ! 322: `liblist' are named according to libraries that they contain. ! 323: .NH 2 ! 324: Creating a Program Library ! 325: .XS ! 326: \*(SN Creating a Program Library ! 327: .XE ! 328: .PP ! 329: A program library is a collection of compiled subroutines that are shared ! 330: by more than one program. In the ! 331: .UX ! 332: environment a program library is stored as an ! 333: .I archive ! 334: file. Each member of the archive is an object file containing one or ! 335: more compiled subroutines. By convention a library archive file is named ! 336: \fBlib\fIname\fR.\fBa\fR where ! 337: .I name ! 338: is the name of the program library. ! 339: .PP ! 340: The example below shows how to create a program library for the hash table ! 341: subroutines in the `libhash' directory. Note that the ! 342: .I mkmf ! 343: command must be given with the \fB\-l\fR option so that a makefile will be ! 344: created for a library rather than a program. ! 345: .DS ! 346: % \fBmkmf \-i \-l\fR ! 347: mkmf: creating Makefile from template /usr/new/lib/l.Makefile ! 348: library name? \fBlibhash.a\fR ! 349: destination directory? \fB../../lib\fR ! 350: % \fBmake\fR ! 351: cc \-c hthash.c ! 352: cc \-c htinit.c ! 353: cc \-c htinstall.c ! 354: cc \-c htlookup.c ! 355: cc \-c htrm.c ! 356: Loading libhash.a ... done ! 357: % ! 358: .DE ! 359: Since the `lib' directory is in the same ! 360: project as the `libhash' directory, the path to `lib' is ! 361: made ! 362: .I relative ! 363: to `libhash' so that the project will be portable. ! 364: .PP ! 365: The next step is to install the program library in the `lib' project directory ! 366: where the ! 367: .I vs ! 368: and ! 369: .I vstutor ! 370: programs can access it easily. ! 371: .DS ! 372: % \fBmake install\fR ! 373: Installing libhash.a in ../../lib ! 374: % ! 375: .DE ! 376: .NH 2 ! 377: More on Developing a Program ! 378: .XS ! 379: \*(SN More on Developing a Program ! 380: .XE ! 381: .NH 3 ! 382: \fIIncluded files\fR ! 383: .XS ! 384: \*(SN Included files ! 385: .XE ! 386: .PP ! 387: Definitions which are common to more than one source code file (e.g. buffer ! 388: sizes, data structure definitions) should be declared only once in a program. ! 389: This can be achieved by keeping such definitions in files separate from the ! 390: main program and ``including'' them at compilation time. In C, Fortran, and ! 391: Pascal programs, the contents of a file can be included by the statement ! 392: .ID ! 393: #include "filename" ! 394: .DE ! 395: By convention ! 396: .I filename ! 397: ends in \fB.h\fR and is commonly referred to as a ! 398: .I header ! 399: file. Hence, in the source code for programs ! 400: .I vs ! 401: and ! 402: .I vstutor, ! 403: the statements ! 404: .DS ! 405: #include "vs.h" ! 406: #include "hash.h" ! 407: #include "list.h" ! 408: .DE ! 409: include common program definitions, hash table definitions, and linked ! 410: list definitions respectively. ! 411: .PP ! 412: Since the header files in this example are used in more than ! 413: one program, they should be placed in the `include' directory where they can ! 414: be accessed easily. Although the include statements can be rewritten as ! 415: .DS ! 416: #include "../../include/vs.h" ! 417: #include "../../include/hash.h" ! 418: #include "../../include/list.h" ! 419: .DE ! 420: it is better to tell the compiler where the header files are by using the ! 421: .B \-I ! 422: compiler option\** as follows ! 423: .FS ! 424: C and Fortran compilers only. ! 425: .FE ! 426: .ID ! 427: \-I../../include ! 428: .DE ! 429: This is done most conveniently by adding the option to the compiler ! 430: flags in the makefile (see \(sc\|4.1.1). ! 431: .NH 3 ! 432: \fIProgram libraries\fR ! 433: .XS ! 434: \*(SN Program libraries ! 435: .XE ! 436: .PP ! 437: The LIBS macro definition in a makefile specifies the libraries that ! 438: are to be used by the link editor for resolving references to ! 439: subroutines that are not found in the program source code. Because ! 440: .I make ! 441: checks to see if the libraries needed by a program have changed since ! 442: the last time the program was made, their pathnames must be defined ! 443: explicitly. In the makefiles belonging to programs ! 444: .I vs ! 445: and ! 446: .I vstutor, ! 447: the LIBS macro definition looks like ! 448: .DS ! 449: LIBS = \kx../../lib/libhash.a \\\\ ! 450: \h'|\nxu'\&../../lib/liblist.a \\\\ ! 451: \h'|\nxu'\&/usr/lib/libcurses.a \\\\ ! 452: \h'|\nxu'\&/usr/lib/libtermlib.a ! 453: .DE ! 454: Note also that when this macro definition was added to the makefile by ! 455: the command ! 456: .PP ! 457: % \fBmkmf "LIBS=../../lib/libhash.a ../../lib/liblist.a \-lcurses \-ltermlib"\fR ! 458: .LP ! 459: to include the `hash' and `list' libraries, the `curses' and `termlib' ! 460: libraries were automatically expanded to full pathnames by the makefile editor. ! 461: .NH 3 ! 462: \fIInstallation\fR ! 463: .XS ! 464: \*(SN Installation ! 465: .XE ! 466: .PP ! 467: Once a program has been completed, it should be installed in a place ! 468: where it will be generally available \- that is, in a directory which ! 469: is in the command search path specified by the PATH environment ! 470: variable. In the case of the project `vs', if the `bin' directory is in ! 471: the search path, this might be a good place to install the ! 472: .I vs ! 473: and ! 474: .I vstutor ! 475: programs. If the makefiles for these programs do not already specify `bin' as ! 476: their destination directory, it can be added by the command ! 477: .ID ! 478: % \fBmkmf "DEST=../../bin"\fR ! 479: .DE ! 480: Then, each program can be installed by the ! 481: .I ! 482: make install ! 483: .R ! 484: command. For the program \fIvs\fR: ! 485: .DS ! 486: % \fBpd vs\fR ! 487: % \fBmake install\fR ! 488: Installing vs in ../../bin ! 489: % ! 490: .DE ! 491: and for the program \fIvstutor\fR: ! 492: .DS ! 493: % \fBpd vstutor\fR ! 494: % \fBmake install\fR ! 495: Installing vstutor in ../../bin ! 496: % ! 497: .DE ! 498: .NH 2 ! 499: Global Operations ! 500: .XS ! 501: \*(SN Global Operations ! 502: .XE ! 503: .PP ! 504: One of the goals of SPMS is to reduce the effort associated with software ! 505: maintenance. This can be achieved by treating a software package as an ! 506: atomic unit \- that is, a single entity on which to perform operations. ! 507: The mechanism for executing a command over an entire software package ! 508: is provided by the ! 509: .I pexec ! 510: command. This command takes another command as an argument and executes it ! 511: in each of the directories belonging to a project, as in ! 512: .ID ! 513: % \fBpexec ls\fR ! 514: .DE ! 515: which lists the names of all the files in a project. ! 516: .NH 3 ! 517: \fIDirectory selection\fR ! 518: .XS ! 519: \*(SN Directory selection ! 520: .XE ! 521: .PP ! 522: By labeling each project directory according to the type of activity that it ! 523: supports, global operations can be restricted to specific directories. These ! 524: labels, which are known as ! 525: .I ! 526: type labels, ! 527: .R ! 528: are attached to project directories by the ! 529: .I pmkdir ! 530: command, and removed by the ! 531: .I prmdir ! 532: command\**. ! 533: .FS ! 534: Except in the case of project root directories, where ! 535: .I mkproject ! 536: and ! 537: .I rmproject ! 538: must be used. ! 539: .FE ! 540: For instance, if the directories containing source code in project `vs' are ! 541: labeled `src' by ! 542: .ID ! 543: % \fBpmkdir +T\|src include libhash liblist vs vstutor\fR ! 544: .DE ! 545: then, the total number of lines of source code in a project can be counted by ! 546: giving the command ! 547: .ID ! 548: % \fBpexec \-T\|src \'cat \(**.h \(**.c\^\' | wc \-l\fR ! 549: .DE ! 550: where quotes surround the ! 551: .I cat ! 552: command to prevent file name expansion in the current directory. ! 553: .PP ! 554: If a project directory supports more than one type of activity, ! 555: labels corresponding to each of the activities can be attached to ! 556: the directory. ! 557: .NH 3 ! 558: \fIDirectory order\fR ! 559: .XS ! 560: \*(SN Directory order ! 561: .XE ! 562: .PP ! 563: In some instances the directories affected by a global command must be ! 564: processed in a particular order. For example, when installing a software ! 565: package which has both libraries and programs, the libraries should be ! 566: installed first. This ordering is achieved by appending priorities to type ! 567: labels. In the case of the project `vs', if the directories containing the ! 568: program and library source code are labeled `install' with the following ! 569: priorities ! 570: .so install.tbl ! 571: by the commands ! 572: .DS ! 573: % \fBpmkdir +T\|install.1 libhash liblist\fR ! 574: % \fBpmkdir +T\|install.2 vs vstutor\fR ! 575: .DE ! 576: then, the command ! 577: .ID ! 578: % \fBpexec \-T\|install make install\fR ! 579: .DE ! 580: installs the `vs' software package in the order shown in figure 4. ! 581: .KF ! 582: .sp 18 ! 583: .SM ! 584: .ce ! 585: \fIFigure 4. \fROrdering for `install' directories ! 586: ! 587: .NL ! 588: .KE ! 589: .KS ! 590: .PP ! 591: In a similar fashion, if the directories containing source code are ! 592: labeled `print' with the following priorities, ! 593: .so print.tbl ! 594: .KE ! 595: a source code listing for the entire project may be obtained by the command ! 596: .ID ! 597: % \fBpexec \-T\|print \'pr \(**.h \(**.c\' | lpr\fR ! 598: .DE ! 599: in the order shown in figure 5. ! 600: .KF ! 601: .sp 18 ! 602: .SM ! 603: .ce ! 604: \fIFigure 5. \fROrdering for `print' directories ! 605: ! 606: .NL ! 607: .KE ! 608: .NH 2 ! 609: Locating Files in a Project ! 610: .XS ! 611: \*(SN Locating Files in a Project ! 612: .XE ! 613: .PP ! 614: When the location of a file within a project is unknown, it can be ! 615: found by using the ! 616: .I pfind ! 617: command. For example, the command ! 618: .ID ! 619: % \fB pfind Makefile\fR ! 620: .DE ! 621: searches for all occurrences of `Makefile' in project `vs' and produces ! 622: the output ! 623: .ID ! 624: \&...^vs/Makefile ! 625: \&...^vstutor/Makefile ! 626: \&...^libhash/Makefile ! 627: \&...^liblist/Makefile ! 628: .DE ! 629: .PP ! 630: In a large project, the time required to search for a file can be reduced ! 631: by telling ! 632: .I pfind ! 633: to scan only those directories in which there is some likelihood of the ! 634: file being found. In the example above, since makefiles are only likely ! 635: to be found in source code directories (i.e. directories having type ! 636: label `src'), the command could have been given as ! 637: .ID ! 638: % \fBpfind \-T\|src Makefile\fR ! 639: .DE ! 640: .NH 2 ! 641: Searching Files for Patterns ! 642: .XS ! 643: \*(SN Searching Files for Patterns ! 644: .XE ! 645: .PP ! 646: Sometimes it is necessary to look at all the files in a software ! 647: package that contain a certain pattern\**. ! 648: .FS ! 649: The term ! 650: .I pattern ! 651: is used to denote a set of strings. ! 652: .FE ! 653: One reason might be to find all of the places from which a subroutine ! 654: is called, perhaps with the intent of altering its arguments. The ! 655: .I pgrep ! 656: command searchs through specified files in a project for lines ! 657: matching a given pattern. For example, ! 658: .ID ! 659: % \fBpgrep \-T\|src listappend \'\(**.h \(**.c\'\fR ! 660: .DE ! 661: will search all the C source code files in project `vs' for the function ! 662: `listappend'. Because of the ! 663: .B \-T ! 664: option, ! 665: .I pgrep ! 666: searchs only in those directories which have the `src' type label. ! 667: .PP ! 668: An alternative way for specifying file names is to use the ! 669: .B \-m ! 670: option. This causes ! 671: .I pgrep ! 672: to fetch the names of source code files from the HDRS and SRCS macro ! 673: definitions in a makefile. Consequently, the command in the example ! 674: above could have been expressed as ! 675: .ID ! 676: % \fBpgrep \-T\|src \-m listappend\fR ! 677: .DE ! 678: .PP ! 679: If the pattern contains characters that have a special meaning to the ! 680: shell, such as \fB\(**\fR or \fB^\fR, the pattern should be quoted. ! 681: For example, ! 682: .ID ! 683: % \fBpgrep \-T\|src \-m \'ht.\(**(\'\fR ! 684: .DE ! 685: finds all of the places where functions from the hash table library ! 686: are used. ! 687: .NH 2 ! 688: Changing the Working Project ! 689: .XS ! 690: \*(SN Changing the Working Project ! 691: .XE ! 692: .PP ! 693: Along with a working directory, each user has a ! 694: .I ! 695: working project. ! 696: .R ! 697: Immediately after logging in, the working project is the root project `^'. ! 698: To change to a new working project, the ! 699: .I chproject ! 700: command must be used, as in ! 701: .ID ! 702: % \fBchproject vs\fR ! 703: .DE ! 704: which makes `vs' the current (or working) project. To return to the ! 705: root project, execute the command ! 706: .ID ! 707: % \fBchproject ^\fR ! 708: .DE ! 709: To find out the name of the working project, type ! 710: .ID ! 711: % \fBpwp\fR ! 712: .DE ! 713: ! 714:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.