rsalz@uunet.uu.net (Rich Salz) (03/20/91)
Submitted-by: Kevin Braunsdorf <ksb@cc.purdue.edu> Posting-number: Volume 24, Issue 60 Archive-name: pucc-mk/part04 #!/bin/sh # This is part 04 of pucc-1c # ============= mkcat/pt.c ============== if test ! -d 'mkcat'; then echo 'x - creating directory mkcat' mkdir 'mkcat' fi if test -f 'mkcat/pt.c' -a X"$1" != X"-c"; then echo 'x - skipping mkcat/pt.c (File already exists)' else echo 'x - extracting mkcat/pt.c (Text)' sed 's/^X//' << 'Purdue' > 'mkcat/pt.c' && /* X * an abstraction for a UNIX path name X * $Id: pt.c,v 3.1 90/11/28 09:44:01 ksb Exp $ X * X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana X * 47907. All rights reserved. X * X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb X * X * This software is not subject to any license of the American Telephone X * and Telegraph Company or the Regents of the University of California. X * X * Permission is granted to anyone to use this software for any purpose on X * any computer system, and to alter it and redistribute it freely, subject X * to the following restrictions: X * X * 1. Neither the authors nor Purdue University are responsible for any X * consequences of the use of this software. X * X * 2. The origin of this software must not be misrepresented, either by X * explicit claim or by omission. Credit to the authors and Purdue X * University must appear in documentation and sources. X * X * 3. Altered versions must be plainly marked as such, and must not be X * misrepresented as being the original software. X * X * 4. This notice may not be removed or altered. X */ X /* X * pull a path in it's parts, bent toward what I needed a little (ksb) X * X * $Compile: ${cc-cc} -DTEST ${cc_debug--g} %f -o %F X * $Cc: ${cc-cc} ${cc_debug--O} -c %f X */ #include <stdio.h> #include <ctype.h> #include <sys/types.h> #include <sys/file.h> #include <sys/param.h> X #if !defined(MAXPATHLEN) #define MAXPATHLEN 1024 #endif X #include "machine.h" #include "pt.h" X extern int strlen(); extern char *strrchr(), *strcpy(); X static char acDotZ[] = /* compresses extender */ X ".Z"; X /* X * build a path structure, a nice abstraction for a UNIX file name (ksb) X * if you pass pcFile a a null you'd better have filled acname with a X * path name... /a//b is OK now too (/a & b) X */ void PTInit(pPT, pcFile) PATH *pPT; char *pcFile; { X register char *pcScan; X if ((char *)0 != pcFile) { X (void)strcpy(pPT->acname, pcFile); X } X pcScan = pPT->acname; X while ((char *)0 != (pPT->pcdir = strrchr(pcScan, '/'))) { X pcScan = pPT->pcdir+1; X if ('\000' != pcScan[1]) X break; X *pcScan = '\000'; X pcScan = pPT->acname; X } X while (pPT->pcdir > pPT->acname && '/' == pPT->pcdir[-1]) { X --pPT->pcdir; X } X pPT->pcbase = pcScan; X if ((char *)0 == (pPT->pccomp = strrchr(pcScan, acDotZ[0])) || X 0 != strcmp(acDotZ, pPT->pccomp)) { X pPT->pccomp = (char *)0; X pPT->istate = PS_NONE; X } else { X *pPT->pccomp = '\000'; X pPT->istate = PS_COMP; X } X pPT->pcext = strrchr(pcScan, '.'); } X /* X * return the local path name of the file (no directory part) (ksb) X */ char * PTLocal(pPT) PATH *pPT; { X if ((char *)0 != pPT->pcext && 0 != (pPT->istate & PS_EXT)) { X pPT->istate &= ~PS_EXT; X *pPT->pcext = '.'; X } X if ((char *)0 != pPT->pccomp && 0 != (pPT->istate & PS_COMP)) { X pPT->istate &= ~PS_COMP; X *pPT->pccomp = acDotZ[0]; X } X return pPT->pcbase; } X /* X * return the full path name (ksb) X */ char * PTFull(pPT) PATH *pPT; { X (void) PTLocal(pPT); X if ((char *)0 != pPT->pcdir && 0 != (pPT->istate & PS_DIR)) { X pPT->istate &= ~PS_DIR; X *pPT->pcdir = '/'; X } X return pPT->acname; } X static char acDot[] = "."; static char acSlash[] = "/"; X /* X * return the directory prefix of the file name (ksb) X * handles no dir part (.), and /foo (/) X * you can check for these cases with a pointer compare (acDot, acSlash) X */ char * PTDir(pPT) PATH *pPT; { X if ((char *)0 == pPT->pcdir) { X return acDot; X } X if (pPT->pcdir == pPT->acname) { X return acSlash; X } X if (0 == (pPT->istate & PS_DIR)) { X pPT->istate |= PS_DIR; X *pPT->pcdir = '\000'; X } X return pPT->acname; } X /* X * return the base name, no extender (ksb) X */ char * PTBase(pPT) PATH *pPT; { X if ((char *)0 != pPT->pcext) { X if (0 == (pPT->istate & PS_EXT)) { X pPT->istate |= PS_EXT; X *pPT->pcext = '\000'; X } X } else if ((char *)0 != pPT->pccomp && 0 == (pPT->istate & PS_COMP)) { X pPT->istate |= PS_COMP; X *pPT->pccomp = '\000'; X } X return pPT->pcbase; } X /* X * return the exender on the path (ksb) X */ char * PTExt(pPT) PATH *pPT; { X if ((char *)0 != pPT->pccomp && 0 == (pPT->istate & PS_COMP)) { X pPT->istate |= PS_COMP; X *pPT->pccomp = '\000'; X } X return (char *)0 != pPT->pcext ? pPT->pcext + 1 : ""; } X /* X * make the file compress'd (add a .Z) return if there was one (ksb) X */ int PTComp(pPT) PATH *pPT; { X if ((char *)0 != pPT->pccomp) X return 1; X pPT->pccomp = PTLocal(pPT); X pPT->pccomp += strlen(pPT->pccomp); X (void)strcpy(pPT->pccomp, acDotZ); X return 0; } X /* X * make the file name be uncompressed (remove the .Z) (ksb) X * return 1 if the file *was* uncompressed X */ int PTUnComp(pPT) PATH *pPT; { X if ((char *)0 == pPT->pccomp) X return 1; X if (0 == (pPT->istate & PS_COMP)) X *pPT->pccomp = '\000'; X pPT->pccomp = (char *)0; X return 0; } X X #if defined(TEST) X /* Crack, simple configuration file parser (ksb) X */ char * Crack(pcText, ppcVar) char *pcText; char **ppcVar; { X register char ***pppc; X register char **ppc; X X pppc = & ppcVar; X while ((char **)0 != (ppc = *pppc++)) { X if ('\000' == *pcText) { X *ppc = (char *)0; X continue; X } X *ppc = pcText; X while (!isspace(*pcText) && '\000' != *pcText) X ++pcText; X if (isspace(*pcText)) { X *pcText++ = '\000'; X } X while (isspace(*pcText)) X ++pcText; X } X return pcText; } X extern int errno; extern char *sys_errlist[]; #define strerror(Me) (sys_errlist[Me]) X X /* X * test driver for path splitting part (ksb) X */ int main(argc, argv) int argc; char **argv; { X auto char acLine[1045], *pc; X auto char *pcOrig, *pcDir, *pcLocal, *pcBase, *pcExt, *pcComp, *pcComm; X auto PATH PTTest; X register int e = 0; X X switch (argc) { X case 1: X break; X case 2: X if (NULL == freopen(argv[1], "r", stdin)) { X fprintf(stderr, "%s: freopen: %s: %s\n", argv[0], argv[1], strerror(errno)); X exit(1); X } X break; X default: X printf("%s: usage [file]\n", argv[0]); X exit(1); X } X X while (NULL != gets(acLine)) { X pcOrig = acLine; X while (isspace(*pcOrig)) X ++pcOrig; X if ('#' == *pcOrig || '\000' == *pcOrig) X continue; X pcComm = Crack(pcOrig, &pcOrig, &pcDir, &pcLocal, &pcBase, &pcExt, &pcComp, (char **)0); X PTInit(pcOrig, & PTTest); X if (0 != strcmp(pcOrig, (pc = PTFull(& PTTest)))) { X printf("pt: Full: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcOrig, pc); X ++e; X } X if (0 != strcmp(pcDir, (pc = PTDir(& PTTest)))) { X printf("pt: Dir: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcDir, pc); X ++e; X } X if (0 != strcmp(pcLocal, (pc = PTLocal(& PTTest))) && '~' != pcLocal[0] && '\000' != pc[0]) { X printf("pt: Local: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcLocal, pc); X ++e; X } X if (0 != strcmp(pcBase, (pc = PTBase(& PTTest))) && '~' != pcBase[0] && '\000' != pc[0]) { X printf("pt: Base: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcBase, pc); X ++e; X } X if (0 != strcmp(pcExt, (pc = PTExt(& PTTest))) && '~' != pcExt[0] && '\000' != pc[0]) { X printf("pt: Ext: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcExt, pc); X ++e; X } X if (PTIsComp(&PTTest) != ('y' == *pcComp || 'Y' == *pcComp)) { X printf("pt: IsComp: broken\n", pcOrig); X ++e; X } X if (0 != strcmp(pcOrig, (pc = PTFull(& PTTest)))) { X printf("pt: Full: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcOrig, pc); X ++e; X } X if (0 != strcmp(pcBase, (pc = PTBase(& PTTest))) && '~' != pcBase[0] && '\000' != pc[0]) { X printf("pt: Base: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcBase, pc); X ++e; X } X if (0 != strcmp(pcLocal, (pc = PTLocal(& PTTest))) && '~' != pcLocal[0] && '\000' != pc[0]) { X printf("pt: Local: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcLocal, pc); X ++e; X } X if (0 != strcmp(pcDir, (pc = PTDir(& PTTest)))) { X printf("pt: Dir: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcDir, pc); X ++e; X } X if (0 != strcmp(pcOrig, (pc = PTFull(& PTTest)))) { X printf("pt: Full: `%s\' is broken, `%s\' != `%s\'\n", pcOrig, pcOrig, pc); X ++e; X } X } X X exit(e != 0); } X #endif /* test driver code */ Purdue chmod 0444 mkcat/pt.c || echo 'restore of mkcat/pt.c failed' Wc_c="`wc -c < 'mkcat/pt.c'`" test 7922 -eq "$Wc_c" || echo 'mkcat/pt.c: original size 7922, current size' "$Wc_c" fi # ============= mk/rlimsys.c ============== if test ! -d 'mk'; then echo 'x - creating directory mk' mkdir 'mk' fi if test -f 'mk/rlimsys.c' -a X"$1" != X"-c"; then echo 'x - skipping mk/rlimsys.c (File already exists)' else echo 'x - extracting mk/rlimsys.c (Text)' sed 's/^X//' << 'Purdue' > 'mk/rlimsys.c' && /* X * resource limited system Kevin S Braunsdorf (ksb) X */ #include "machine.h" X #if RESOURCE X #include <sys/types.h> #include <sys/time.h> #include <sys/resource.h> #if defined(bsd) #include <sys/wait.h> #endif #include <signal.h> #include <stdio.h> #include <ctype.h> X #include "mk.h" #include "rlimsys.h" X X /* X * resource records X */ typedef struct RRnode { X int rtype; /* resource type from resource.h */ X int fsys; /* done by kernel or us? */ X char *pchrname; /* user name */ X int rlen; /* lenght of user name */ X int fset; /* was given by user? */ X struct rlimit ourlim; /* rlim_cur, rlim_max */ } RES_REC; X #if RLIM_NLIMITS != 6 error_more_or_fewer_resources error_more_or_fewer_resources #endif X #define MY_CLOCK 0 /* X * resources we know about in alpha order X */ RES_REC sbRRLimits[] = { X { MY_CLOCK, 0, "clock", 5 }, X { RLIMIT_CORE, 1, "core", 4 }, X { RLIMIT_CPU, 1, "cpu", 3 }, X { RLIMIT_DATA, 1, "data", 4 }, X { RLIMIT_FSIZE, 1, "fsize", 5 }, X { RLIMIT_RSS, 1, "rss", 3 }, X { RLIMIT_STACK, 1, "stack", 5 } }; X /* X * we need to know how many limits we can set X */ #define MY_NLIMITS 7 X X /* X * init the resource limit stuff, make mongo syscalls (ksb) X */ void rinit() { X register int i; X register RES_REC *pRR; X X for (i = 0; i < MY_NLIMITS; ++i) { X pRR = & sbRRLimits[i]; X pRR->fset = 0; X if (pRR->fsys) { X getrlimit(pRR->rtype, & pRR->ourlim); X } else { X pRR->ourlim.rlim_cur = RLIM_INFINITY; X pRR->ourlim.rlim_max = RLIM_INFINITY; X } X } } X /* X * parse a resource limit statement of the form (ksb) X * <resource>=number_cur/number_max X * (we eat leading blanks, as all good cvt routines should) X */ char * rparse(pchState) register char *pchState; { X extern char *strchr(); X extern long atol(); X register int i; X register char *pchTemp; X register RES_REC *pRR; X register int fSetMax = 0, fSetCur = 0; X X while (isspace(*pchState)) { X ++pchState; X } X if ((char *)0 == (pchTemp = strchr(pchState, '='))) { X return pchState; X } X X for (i = 0; i < MY_NLIMITS; ++i) { X pRR = & sbRRLimits[i]; X if (0 == strncmp(pRR->pchrname, pchState, pRR->rlen)) { X break; X } X } X if (MY_NLIMITS == i) { X return pchState; X } X X do { X ++pchTemp; X } while (isspace(*pchTemp)); X if (isdigit(*pchTemp)) { X pRR->fset = 1; X pRR->ourlim.rlim_cur = atol(pchTemp); X fSetCur = 1; X do { X ++pchTemp; X } while (isdigit(*pchTemp)); X } X if ('/' == *pchTemp) X ++pchTemp; X while (isspace(*pchTemp)) X ++pchTemp; X X if (isdigit(*pchTemp)) { X pRR->fset = 1; X pRR->ourlim.rlim_max = atol(pchTemp); X fSetMax = 1; X do { X ++pchTemp; X } while (isdigit(*pchTemp)); X } X while (isspace(*pchTemp)) X ++pchTemp; X if (fSetMax != fSetCur) { /* only one set, set both same */ X if (fSetMax) { X pRR->ourlim.rlim_cur = pRR->ourlim.rlim_max; X } else { X pRR->ourlim.rlim_max = pRR->ourlim.rlim_cur; X } X } X return pchTemp; } X int r_fTrace = 0; static int iChildPid, fWarned; X /* X * trap a time out for a "real time" alarm X */ int do_alarm() { X register unsigned next; X if (kill(iChildPid, fWarned++ ? SIGALRM : SIGKILL) < 0) { X fprintf(stderr, "%s: %d: ", "rlimsys", iChildPid); X perror("kill"); X exit(1); X } X next = (unsigned)(sbRRLimits[MY_CLOCK].ourlim.rlim_max - X sbRRLimits[MY_CLOCK].ourlim.rlim_cur); X if (0 == next) { X next = 2; X } X alarm(next); } X /* X * emulate "system" with a CPU limit X */ int rlimsys(pchCmd) char *pchCmd; { #if defined(bsd) X auto union wait waitbuf; #else X auto int waitbuf; #endif X register int wret; #if SUNOS >= 40 X register void (*atrap)(), (*itrap)(), (*qtrap)(); #else /* !SUNOS40 */ X register int (*atrap)(), (*itrap)(), (*qtrap)(); #endif /* SUNOS40 */ X register int i; X register RES_REC *pRR; X auto int iRetCode; X X iChildPid = vfork(); X switch (iChildPid) { X case 0: X for (i = 0; i < MY_NLIMITS; ++i) { X pRR = & sbRRLimits[i]; X if (pRR->fset && pRR->fsys) { X setrlimit(pRR->rtype, & pRR->ourlim); X } X } X execl("/bin/sh", "sh", r_fTrace ? "-cx" : "-c", pchCmd, 0); X _exit(127); X case -1: X perror("rlimsys: fork"); X return 1; X default: X break; X } X X itrap = signal(SIGINT, SIG_IGN); X qtrap = signal(SIGQUIT, SIG_IGN); X X if (sbRRLimits[MY_CLOCK].fset) { X atrap = signal(SIGALRM, do_alarm); X alarm((unsigned)sbRRLimits[MY_CLOCK].ourlim.rlim_cur); X } X for (;;) { X if (iChildPid == (wret = wait3(& waitbuf, WUNTRACED, (struct rusage *)0))) { X if (WIFSTOPPED(waitbuf)) { X if (kill(iChildPid, SIGCONT) < 0) { X break; X } X continue; X } X if (WIFSIGNALED(waitbuf)) { X iRetCode = waitbuf.w_termsig; X } else { X iRetCode = waitbuf.w_retcode; X } X break; X } X if (wret == -1) { X fprintf(stderr, "rlimsys: lost child %d\n", iChildPid); X perror("rlimsys: wait"); X iRetCode = 1; X break; X } X } X X (void) signal(SIGINT, itrap); X (void) signal(SIGQUIT, qtrap); X if (sbRRLimits[MY_CLOCK].fset) { X alarm((unsigned)0); X (void) signal(SIGALRM, atrap); X } X return iRetCode; } X #endif /* resource usage */ Purdue chmod 0444 mk/rlimsys.c || echo 'restore of mk/rlimsys.c failed' Wc_c="`wc -c < 'mk/rlimsys.c'`" test 4889 -eq "$Wc_c" || echo 'mk/rlimsys.c: original size 4889, current size' "$Wc_c" fi # ============= mk-lib/mk.5l ============== if test ! -d 'mk-lib'; then echo 'x - creating directory mk-lib' mkdir 'mk-lib' fi if test -f 'mk-lib/mk.5l' -a X"$1" != X"-c"; then echo 'x - skipping mk-lib/mk.5l (File already exists)' else echo 'x - extracting mk-lib/mk.5l (Text)' sed 's/^X//' << 'Purdue' > 'mk-lib/mk.5l' && .\" how to code an mk marker line .TH MK 5L LOCAL .SH NAME mk \- how to write and embed \fBmk\fP commands .SH SYNOPSIS \fB$\fP \fImarker\fP[\fB(\fP\fIsubmarker\fP\fB)\fP] [\fB=\fP[\fB~\fP]\fIexit\-status\fP] [\fB,\fP\fIresource\fP\fB=\fP[\fIlimit\fP][\fB/\fP\fImaximum\fP]] \fB:\fP \fIcommand\fP [ \fB$$\fP ] .SH COMMANDS .I Mk is a utility for detecting and executing shell commands within files. Normally, when the named files contain source language statements, the commands are contained in lines that appear as comments to the language processor. This is merely a convention, however, and is not a .I mk requirement. .PP .I Mk commands are always given to \fIsh\fP(1) for execution. It is the convention of the authors to use an indirect name for the \*(lqkey\*(rq UNIX tools in each command. For example when a command requires the use of a language processor, like cc(1), one might use the shell form .sp 1 X ${cc-cc} ... .sp 1 so that different versions of the compiler (cc or gcc) or cross compilers might be used in place of the default compiler. .PP Some compilers required a special optimization level for debugging. A hook for this option is usually provided by a variable whose name ends in the string \*(lq_debug\*(rq .sp 1 X ${cc-cc} ${cc_debug-\-O} ... .sp 1 This allows the user to simply set an environment variable when debugging a product. .PP The default load name, \*(lqa.out\*(rq, should \fBnot\fP be used as an output file, if it can be avoided, (such default actions are available via the compiler itself). .I Mk rules generally use the basename of the given file as an output file (see \fImk\fP(1l) for a description of all the percent escapes). .sp 1 X ${cc-cc} ${cc_debug-\-O} \-o %F ... .sp 1 .PP If any special flags must be included to compile this program, or several options cause different versions to be built they should be specified next: .sp 1 X ${cc-cc} ${cc_debug-\-O} \-o %F ... .br X ${cc-cc} ${cc_debug-\-g} \-o %F \-DDEBUG ... .sp 1 .PP The name of the source file should be followed by any libraries that the product needs to load against. .sp 1 X ${cc-cc} ${cc_debug-\-O} \-o %F \-DNORMAL %f \-lm .sp 1 .PP Sometimes recursive calls to \fImk\fP are the best way to solve a complex problem. The escapes \fImk\fP provides for recursive calls (%b, %o, %\fIoption\fP) are used to pass down the command line switches that might be important: .sp 1 X %b %o \-mStep1 %f && %b %o \-mStep2 %f .sp 1 Sometimes one might want to force an option to a recursive call, but leave the others as given (in this case we force \-a): .sp 1 X %b \-a%C%I%N%V \-m%m %f .sp 1 .SH "MARKED LINES" .PP The default \fImarker\fP \fBmk\fP searches for is \*(lqCompile\*(rq. A marker is, in effect, a verb that is applied to a file, these are the markers \fImk\fP has conventions for (by default): .sp 1 .RS .TS l l. Clean remove any junk this file might produce Compile produce an binary from this file Display produce an output from this file Info output a description of what \fBmk\fP thinks is in the file Laser format this file to produce a hard copy Run execute this file (if possible) Mkcat format a manual page for the \fImkcat\fP(8l) program .TE .RE .sp 1 Other markers will be added as needed. .PP A submarker is a modifier on the verb. These are used to choose marked lines when more than on marked line might server. Submarkers are still primitive. .PP Currently few submarkers have a defined meaning to \fImk\fP: .RS .TS l l. debug generate a debugging version test generate a test program for this module verbose be more verbose \fIos\fP generate a version for the given operating system X SYSV, bsd, hpux, posix .TE .RE .SH "MATCHING" .PP These rules cause a match for marked lines in any file \fImk\fP searches: .RS \(bu the special marker \*(lq*\*(rq matches any \fImarker\fP .br \(bu the special submarker \*(lq*\*(rq matches any \fIsubmarker\fP .br \(bu the marker from the line must match \fImarker\fP .br \(bu if a \fIsubmarker\fP was given on the command line it must be matched .br \(bu case differentiates markers and submarkers unless \-\fBi\fP was given .br .RE .PP Thus we have a table of \fImk\fP invokations versus markers: .RS .TS l l l l l c c c. Marker \-mTest \-mTest \-ddebug \-mTest -d'*' $Fail no no no $Test yes no no $Test(bsd) yes no yes $Test(debug) yes yes yes $Test(*) yes yes yes $* yes no no $*(bsd) yes no yes $*(debug) yes yes yes $*(*) yes yes yes .TE .RE .PP When coding a template file the $\fImarker\fP(*): form is used to assure a match. .SH TEMPLATES .PP By using \fImk\fP's template's options the user might build a default rule for a given application. \fIMk\fP will expand each element of the template path as if it were a \fIcommand\fP, then try to read the generated filename. If the file exists and contains a marked line that matches the current marker \fImk\fP will use that command. .PP \fIMk\fP has a set of default templates under some directory (likely \fI/usr/local/lib/mk\fP) these are scanned if no other \-\fBe\fP or \-\fBt\fP options are given. The root of this directory is provided by the %~ escape to allow users to reference these templates. .PP The default list of templates may be examined with ``\fImk\fP \-\fBV\fP''. .PP The default \fImk\fP templates have a naming convention which also determines the order in which they are searched. .RS .TS l l. type-%y trap based on file type pre-%x trap extenders that represent nontext files comma-%U trap RCS files file-%F trap files with special names dot-%x trap text file extenders m-%M trap based on marker given .TE .RE .SH FAILURE .PP Some markers can detect that they have failed and that the user might want to take corrective or special action in this case. The convention in such cases is to call the shell form: .sp 1 X ${false-false} .sp 1 to allow the user a ``hook'' with which to trap the error. .SH EXAMPLES .TP $\&All: %b %o \-mCompile *.c Compile all the C source files in this directory using their own rules. .TP $\e&Compile: ... A trick to avoid letting mk see a marked line in an examples section of a manual page. .TP $\&Compile(debug): ${cc-cc} ${cc_debug-\-g} \-o %F \-DDEBUG %f \-lm This line will match only if \-\fBd\fPdebug or \-\fBd\fP'*' were given. .TP $\&Compile(*): ${cc-cc} ${cc_debug-\-O} \-o %F %f \-lm This line will match any default request. .TP $\&*(*): echo \'%B: %m: unknown marker\' && ${false-false} This marked line will output an error message for any marker, and fail. .SH BUGS .PP Use of \fIrcs\fP(1) keywords as markers (Author, Date, Header, Id, Locker, Log, RCSfile, Revision, Source, State) might give unexpected results. .SH AUTHORS S. McGeady, Intel, Inc., mcg@mipon2.intel.com .sp 1 Kevin Braunsdorf, Purdue University Computing Center (ksb@cc.purdue.edu) .SH "SEE ALSO" mk(1l), sh(1), printf(3) Purdue chmod 0444 mk-lib/mk.5l || echo 'restore of mk-lib/mk.5l failed' Wc_c="`wc -c < 'mk-lib/mk.5l'`" test 6777 -eq "$Wc_c" || echo 'mk-lib/mk.5l: original size 6777, current size' "$Wc_c" fi # ============= mkcat/mkcat.8l ============== if test -f 'mkcat/mkcat.8l' -a X"$1" != X"-c"; then echo 'x - skipping mkcat/mkcat.8l (File already exists)' else echo 'x - extracting mkcat/mkcat.8l (Text)' sed 's/^X//' << 'Purdue' > 'mkcat/mkcat.8l' && .\" Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana .\" 47907. All rights reserved. .\" .\" Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb .\" Jeff Smith, jsmith@cc.purdue.edu, purdue!jsmith .\" .\" This software is not subject to any license of the American Telephone .\" and Telegraph Company or the Regents of the University of California. .\" .\" Permission is granted to anyone to use this software for any purpose on .\" any computer system, and to alter it and redistribute it freely, subject .\" to the following restrictions: .\" .\" 1. Neither the authors nor Purdue University are responsible for any .\" consequences of the use of this software. .\" .\" 2. The origin of this software must not be misrepresented, either by .\" explicit claim or by omission. Credit to the authors and Purdue .\" University must appear in documentation and sources. .\" .\" 3. Altered versions must be plainly marked as such, and must not be .\" misrepresented as being the original software. .\" .\" 4. This notice may not be removed or altered. .\" .\" $Id: mkcat.8l,v 3.2 90/06/12 14:29:45 ksb Exp $ .\" .\" $Laser: ${tbl-tbl} %f | ${ltroff-ltroff} -man .\" $Compile: ${tbl-tbl} %f | ${nroff-nroff} -man | ${PAGER-${more-more}} .TH MKCAT 8L LOCAL .SH NAME mkcat \- update and format a manual page .SH SYNOPSIS \fBmkcat\fP [-\fBDIfnsv\fP] [-\fBc\fP \fIcatdirs\fP] [-\fBm\fP \fIman\fP] [-\fBr\fP \fIroot\fP] [-\fBw\fP \fIdatabase\fP] \fIpages\fP .br \fBmkcat\fP [-\fBVLRWh\fP] [-\fBc\fP \fIcatdirs\fP] [-\fBm\fP \fIman\fP] [-\fBr\fP \fIroot\fP] [-\fBw\fP \fIdatabase\fP] .SH DESCRIPTION \fIMkcat\fP formats the given \fIpages\fP and installs them in the standard manual structure. \fIMkcat\fP updates the \fIwhatis\fP(1) database and creates links to the installed page to represent alternate names for the page given in the \fBNAME\fP section of the formatted page. .PP \fIMkcat\fP depends heavily on the \fBmk\fP(1l) program to extract shell commands to format each page. The \fImk\fP program extracts any special format directive from the first 99 lines of the manual page source file which are marked with the \*(lqMkcat\*(rq marker. See the examples below. .PP Under the \fB\-D\fP option \fImkcat\fP deletes antiquated pages. .SH OPTIONS .TP .BI \-c catdirs Specify \fIcatdirs\fP as the prefix for all the cat directories. The default is \*(lqcat\*(rq which makes the standard manual system directories \*(lqcat1\*(rq, \*(lqcat2\*(rq, \*(lqcat3\*(rq, ... etc. These are used to store manual pages from the corresponding section of the manual. .TP .BI \-D Delete (rather than install) the given \fIpages\fP. The associated \fIwhatis\fP(1) entries are removed as well as any links. .TP .BI \-f The given manual pages are already formatted, simply install (delete) them. .TP .BI \-h Print a short help message. .TP .BI \-I Install the given manual page and update the whatis database. (This is the default action.) .TP .BI \-L Only rebuild missing links to the cat pages. .TP .BI \-m man When this option is specified \fImkcat\fP copies the manual page source into a parallel \fIman\fP directory. This mocks the old manual system. .TP .BI \-n Do not really run any commands. This option outputs the approximate actions of \fImkcat\fP in shell commands. .TP .BI \-r root Specify a user defined root for the manual system. The default is \*(lq\fI/usr/man\fP\*(rq. This allows users to make their own manual systems in their accounts. .TP .BI \-s Do not output descriptions of the shell commands as they are run. This is the default. .TP .BI \-v Be verbose by displaying shell commands as they are run. .TP .BI \-V Show the current configuration of the manual system. .TP .BI \-w database Specify a \fIwhatis\fP(1) database to update. The default \fIdatabase\fP is \*(lqwhatis\*(rq from the \fIroot\fP of the manual system. If this is a full path name \fIroot\fP is not prepended to it. .TP .BI \-R Install a new root manual system, specify the new root with \-\fBr\fP. If a options file exits in that directory it is used as the defaults for the new system. .TP .BI \-W Just rebuild the whatis database. .TP .BI \-Z Verify that all the cat pages are (un)compressed. .SH EXAMPLES .TP mkcat -v -r/usr/man -R Install mkcat's configuration file in /usr/man. .TP mkcat ls.1 Update the \fIls\fP(1) manual page and \fIwhatis\fP(1) entry. .TP mkcat -cnew sleep.1 sleep.3 Update both \fIsleep\fP(1) manual pages and \fIwhatis\fP(1) entries in the \*(lqnew\*(rq cat directory. .TP mkcat -D catman.8 Delete the outdated \fIcatman\fP(8) manual page. .TP mkcat -r $HOME/man myprog.1g Update the \fImyprog\fP(1g) manual page in the user\'s own manual system. X .TP \&.\e" $\&Mkcat: tbl %f | nroff -man.nopage \fBUltrix\fP manual pages require the nopage macro package. .TP \&.\e" $\&Mkcat: neqn %f | tbl | nroff -man | colcrt This line runs the \fIneqn\fP(1) processor in addition to \fItbl\fP(1) and \fInroff\fP(1). .TP \&.\e" $\&Mkcat: nroff -mlocal %f | cat -s This manual page uses a local macro package, and doesn't use \fItbl\fP. .SH FILES .TS l l. /usr/man/whatis the default \fIwhatis\fP(1) database /usr/man/cat[1-8] the default cat directories /usr/man/.mkcat-opts the manual system configuration .TE .SH BUGS .PP Under the \fB\-n\fP option \fImkcat\fP cannot always predict the links it would make. .SH AUTHOR Kevin Braunsdorf .br Purdue UNIX Group .br ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb .SH "SEE ALSO" apropos(1), colcrt(1), compress(1), man(1), mk(1l), neqn(1), nroff(1), tbl(1), whatis(1), catman(8) Purdue chmod 0444 mkcat/mkcat.8l || echo 'restore of mkcat/mkcat.8l failed' Wc_c="`wc -c < 'mkcat/mkcat.8l'`" test 5555 -eq "$Wc_c" || echo 'mkcat/mkcat.8l: original size 5555, current size' "$Wc_c" fi # ============= mkcat/sym2hard.c ============== if test -f 'mkcat/sym2hard.c' -a X"$1" != X"-c"; then echo 'x - skipping mkcat/sym2hard.c (File already exists)' else echo 'x - extracting mkcat/sym2hard.c (Text)' sed 's/^X//' << 'Purdue' > 'mkcat/sym2hard.c' && /* X * $Id: sym2hard.c,v 3.1 90/11/28 09:44:14 ksb Exp $ X * X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana X * 47907. All rights reserved. X * X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb X * X * This software is not subject to any license of the American Telephone X * and Telegraph Company or the Regents of the University of California. X * X * Permission is granted to anyone to use this software for any purpose on X * any computer system, and to alter it and redistribute it freely, subject X * to the following restrictions: X * X * 1. Neither the authors nor Purdue University are responsible for any X * consequences of the use of this software. X * X * 2. The origin of this software must not be misrepresented, either by X * explicit claim or by omission. Credit to the authors and Purdue X * University must appear in documentation and sources. X * X * 3. Altered versions must be plainly marked as such, and must not be X * misrepresented as being the original software. X * X * 4. This notice may not be removed or altered. X */ X /* X * this code replaces a symbolic link with a hard link (ksb) X * X * N.B. this is questionable code in any case.... X */ X #include "machine.h" X #include <stdio.h> #include <errno.h> #include <sys/types.h> #include <sys/param.h> #include <sys/file.h> #include <sys/stat.h> X #include "main.h" X #if !defined(MAXPATHLEN) #define MAXPATHLEN 1024 #endif X #if !defined(ELOOP) #define ELOOP ENOENT #endif /* ZZZZ ETA kludge ZZZZ */ X #if HAVE_SLINKS X extern int errno; extern char *sys_errlist[]; #define strerror(Me) sys_errlist[Me] X X extern char *getwd(); typedef struct SRnode { X struct stat *pst; X struct SRnode *psr; } STREC; X /* X * copy the parrent directory of pcFile to pcDir, which is a buffer (ksb) X * given by the user. returns the `tail part' X */ static char * getparent(pcFile, pcDir) char *pcFile, *pcDir; { X register char *pcTail; X extern char *strcpy(), *strrchr(); X X if ((char *)0 == (pcTail = strrchr(pcFile, '/'))) { X (void)strcpy(pcDir, "."); X return pcFile; X } else if (pcFile == pcTail) { X (void)strcpy(pcDir, "/"); X return pcFile+1; X } X *pcTail = '\000'; X (void)strcpy(pcDir, pcFile); X *pcTail = '/'; X return pcTail+1; } X /* X * do one level of sym2hard (ksb) X * X * pcLink is a symbolic link that should be a hard link X * (we convert all interveining symbolic links while we are at it) X * X * stat the symbolic link, is it a file? we are done. X * check for loops, maybe return ELOOP X * record pwd so we can get back X * read the link into acRead X * cd to acRead's parrent directory X * recurse on acRead's tail X * cd back X * stat acRead, on the same device, and a plain file? not -> bomb out X * remove pcLink, and re-link to acRead X */ static int sym1Hard(pcLink, pSRPrev) char *pcLink; STREC *pSRPrev; { X auto char acRead[MAXPATHLEN+1]; X auto char acNext[MAXPATHLEN+1]; X auto char acPwd[MAXPATHLEN+1]; X auto struct stat stLink, stRead; X auto STREC SR, *pSR; X register int i; X register char *pcTail; X X if (0 != lstat(pcLink, & stLink)) { X fprintf(stderr, "%s: lstat: %s: %s\n", progname, pcLink, strerror(errno)); X return -1; X } X for (pSR = pSRPrev; (STREC *)0 != pSR; pSR = pSR->psr) { X if (pSR->pst->st_dev == stLink.st_dev && X pSR->pst->st_ino == stLink.st_ino) { X errno = ELOOP; X return -1; X } X } X SR.pst = & stLink; X SR.psr = pSRPrev; X switch (stLink.st_mode & S_IFMT) { X default: X errno = EEXIST; X return -1; X case 0: X case S_IFREG: /* regular */ X return 0; X case S_IFLNK: /* symbolic link */ X break; X } X X if (-1 == (i = readlink(pcLink, acRead, MAXPATHLEN))) { X fprintf(stderr, "%s: readlink: %s: %s\n", progname, pcLink, strerror(errno)); X return -1; X } X acRead[i] = '\000'; X X if ((char *)0 == getwd(acPwd)) { X fprintf(stderr, "%s: getwd: %s\n", progname, acPwd); X return -1; X } X X pcTail = getparent(acRead, acNext); X if (-1 == chdir(acNext)) { X return -1; X } X if (-1 == sym1Hard(pcTail, & SR)) { X return -1; X } X if (-1 == chdir(acPwd)) { X return -1; X } X X if (0 != stat(acRead, & stRead)) { X fprintf(stderr, "%s: stat: %s: %s\n", progname, pcLink, strerror(errno)); X return -1; X } X if (stLink.st_dev != stRead.st_dev || S_IFREG != (stRead.st_mode & S_IFMT)) { X errno = EXDEV; X return -1; X } X X if (fVerbose) { X printf("%s: rm -f %s\n", progname, pcLink); X } X if (fExec && unlink(pcLink)) { X fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcLink, strerror(errno)); X return -1; X } X if (fVerbose) { X printf("%s: ln %s %s\n", progname, acRead, pcLink); X } X if (fExec && link(acRead, pcLink)) { X fprintf(stderr, "%s: link: %s to %s: %s\n", progname, acRead, pcLink, strerror(errno)); X return -1; X } X X return 0; } X /* X * we need a wrapper around sym1Hard to restore the top level directory (ksb) X */ int sym2Hard(pcLink) char *pcLink; { X auto char acNext[MAXPATHLEN+1]; X auto char acPwd[MAXPATHLEN+1]; X register int i; X register char *pcTail; X X if ((char *)0 == getwd(acPwd)) { X fprintf(stderr, "%s: getwd: %s\n", progname, acPwd); X return -1; X } X X pcTail = getparent(pcLink, acNext); X if (-1 == chdir(acNext)) { X return -1; X } X X i = sym1Hard(pcTail, (STREC *)0); X X (void) chdir(acPwd); X return i; } X #endif Purdue chmod 0444 mkcat/sym2hard.c || echo 'restore of mkcat/sym2hard.c failed' Wc_c="`wc -c < 'mkcat/sym2hard.c'`" test 5149 -eq "$Wc_c" || echo 'mkcat/sym2hard.c: original size 5149, current size' "$Wc_c" fi # ============= mkcat/mkcat-opts.5l ============== if test -f 'mkcat/mkcat-opts.5l' -a X"$1" != X"-c"; then echo 'x - skipping mkcat/mkcat-opts.5l (File already exists)' else echo 'x - extracting mkcat/mkcat-opts.5l (Text)' sed 's/^X//' << 'Purdue' > 'mkcat/mkcat-opts.5l' && .\" Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana .\" 47907. All rights reserved. .\" .\" Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb .\" .\" This software is not subject to any license of the American Telephone .\" and Telegraph Company or the Regents of the University of California. .\" .\" Permission is granted to anyone to use this software for any purpose on .\" any computer system, and to alter it and redistribute it freely, subject .\" to the following restrictions: .\" .\" 1. Neither the authors nor Purdue University are responsible for any .\" consequences of the use of this software. .\" .\" 2. The origin of this software must not be misrepresented, either by .\" explicit claim or by omission. Credit to the authors and Purdue .\" University must appear in documentation and sources. .\" .\" 3. Altered versions must be plainly marked as such, and must not be .\" misrepresented as being the original software. .\" .\" 4. This notice may not be removed or altered. .\" .\" $Id: mkcat-opts.5l,v 3.0 90/06/01 11:47:31 ksb Exp $ .\" .\" $Laser: ${tbl-tbl} %f | ${ltroff-ltroff} -man .\" $Compile: ${tbl-tbl} %f | ${nroff-nroff} -man | ${PAGER-${more-more}} .TH MKCAT-OPTS 5L PUCC .SH NAME mkcat-opts \- manual system configuration file .SH SYNOPSIS .B /usr/man/.mkcat-opts .SH DESCRIPTION .PP The manual system is a complex database built on top of the UNIX file system which is updated almost entirely by the \fImkcat\fP(8L) program. So that each user of \fImkcat\fP doesn't have to specify many options to update a single manual page, many defaults are kept in a single file at the root of the manual system. The paragraphs below describe the options available in this file. .PP Any line which begins with a pounds sign (`#') is taken to be a comment. .PP The formatted manual pages (called \*(lqcat\*(rq pages) may either be stored compressed or as plain ASCII files. Compressed files usually save disk space, uncompressed (ASCII) files save a little CPU time when a user runs \fIman\fP(1). To enable compression the options file may contain a line like: .sp 1 X compress: y .sp 1 to keep the files as plain ASCII: .sp 1 X compress: n .PP Manual pages which contain descriptions of more than one command (have multiple words before the `\-' in the NAME section) are made available under all their names. This service is provided by linking all the names to the formatted manual page (see \fIln\fP(1)). Either hard links or symbolic links may be used for the auxiliary names for the pages. For symbolic links: .sp 1 X links: S .sp 1 for hard links: .sp 1 X links: H .PP When \fImkcat\fP installs a file in the manual system it uses the \fIinstall\fP(1L) program. If the system administrator prefers special modes on the manual system's files, these modes may specified in the options file. For example to change the mode and group on the installed cat pages: .sp 1 X pagemode: 0660 .br X pagegroup: mandoc .sp 1 The \*(lqpage\*(rq above may be replaced by any of \*(lqwhatis\*(rq, \*(lqdir\*(rq, or \*(lqman\*(rq which \fImkcat\fP uses respectively for the whatis database, any directories, or the man page sources. The owner may be specified as: .sp 1 X whatisowner: root .br X dirowner: root .sp 1 .PP If the default \fB\-m\fP \fIman\fP directory compiled into \fImkcat\fP is not acceptable one may be specified as: .sp 1 X man: \fIman\fP .sp 1 likewise for the \fB\-w\fP \fIwhatis\fP and \fB\-c\fP \fIcat\fP options. .PP \fIMkcat\fP checks to be sure that each installed page is unique in its section. Some pages are purposely \fBnot\fP unique in a section; for example getc.3f and getc.3s. These may be explicitly exempted based on either the basename (getc) or the extenders (3f, 3s). To exempt all pages with conflict which end in 3f and 3s a line: .sp 1 X OKext: {3f,3s} .sp 1 is placed in the options file. To exempt just the getc pages: .sp 1 X OKbase: getc .sp 1 .SH EXAMPLE .RS .nf # mkcat install options (ksb) compress: y links: S # allow group write, see install(1L) pagemode: 0644/020 dirmode: 0755/020 whatismode: 0644/020 OKext: {3s,3f} OKbase: intro .fi .RE .SH FILES .TS l l. /usr/man/.mkcat-opts modes for installed files, link type, compression flag .TE .SH AUTHOR Kevin Braunsdorf, PUCC UNIX Group, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb .br Copyright \*(co 1990 Purdue Research Foundation. All rights reserved. .SH "SEE ALSO" compress(1), install(1L), ln(1), man(1), mkcat(8L), uncompress(1), zcat(1) Purdue chmod 0444 mkcat/mkcat-opts.5l || echo 'restore of mkcat/mkcat-opts.5l failed' Wc_c="`wc -c < 'mkcat/mkcat-opts.5l'`" test 4487 -eq "$Wc_c" || echo 'mkcat/mkcat-opts.5l: original size 4487, current size' "$Wc_c" fi # ============= mk/Tests/file.x,y ============== if test ! -d 'mk/Tests'; then echo 'x - creating directory mk/Tests' mkdir 'mk/Tests' fi if test -f 'mk/Tests/file.x,y' -a X"$1" != X"-c"; then echo 'x - skipping mk/Tests/file.x,y (File already exists)' else echo 'x - extracting mk/Tests/file.x,y (Text)' sed 's/^X//' << 'Purdue' > 'mk/Tests/file.x,y' && $Compile: [ %f = "file.x,y" ] && for marker in Base Ext Cut Type\n\tdo\n\t\t%b %o -a -m$marker %f && echo "$marker test OK"\n\tdone X # base names $Base(1): [ "file" = "%F" ] $Base(2): [ "file" = "%P" ] $Base(3): [ "file" = "%p" ] X # extentions $Ext(1): [ "x,y" = "%x" ] $Ext(2): [ "x,y" = "%X" ] X # Cuts on non-dot extenders that fail $Cut(1): [ -z "%u@" ] $Cut(2): [ "file.x,y" = "%q@" ] $Cut(3)=~*: exit 1 # %U@ $Cut(4)=~*: exit 1 # %Q@ X # Cuts on non-dot extenders that work $Cut(5): [ "file.x" = "%q," ] $Cut(6): [ "y" = "%u," ] $Cut(7): [ "file.x" = "%Q," ] $Cut(8): [ "y" = "%U," ] X # file type flags $Type(1): [ "f" = "%y" ]%Yf $Type(2)=~*: exit 1 # %Yd should stop xlation $Type(3)=~*: exit 1 # %Y. should stop error Purdue chmod 0644 mk/Tests/file.x,y || echo 'restore of mk/Tests/file.x,y failed' Wc_c="`wc -c < 'mk/Tests/file.x,y'`" test 725 -eq "$Wc_c" || echo 'mk/Tests/file.x,y: original size 725, current size' "$Wc_c" fi # ============= mk-lib/m-info ============== if test -f 'mk-lib/m-info' -a X"$1" != X"-c"; then echo 'x - skipping mk-lib/m-info (File already exists)' else echo 'x - extracting mk-lib/m-info (Text)' sed 's/^X//' << 'Purdue' > 'mk-lib/m-info' && # the Info target outputs a descriptive message (ksb) X $Info(*): ${file-file} %f $Info(*): ${echo-echo} type %y, extender %X $Info(*): ${echo-echo} type %y Purdue chmod 0444 mk-lib/m-info || echo 'restore of mk-lib/m-info failed' Wc_c="`wc -c < 'mk-lib/m-info'`" test 159 -eq "$Wc_c" || echo 'mk-lib/m-info: original size 159, current size' "$Wc_c" fi # ============= mkcat/main.c ============== if test -f 'mkcat/main.c' -a X"$1" != X"-c"; then echo 'x - skipping mkcat/main.c (File already exists)' else echo 'x - extracting mkcat/main.c (Text)' sed 's/^X//' << 'Purdue' > 'mkcat/main.c' && /* X * machine generated cmd line parser X */ X #include "getopt.h" #include <stdio.h> #include "machine.h" #include "mkcat.h" X char X *progname = "$Id$", X u_terse[] = " [-ADILRVWZfhnsv] [-c cat] [-m man] [-r root] [-w whatis] [pages]", X *u_help[] = { X "A scan the formatted pages for SEE ALSO errors", X "D delete the given pages from the cat directories", X "I install the given pages (default action)", X "L rebuild auxiliary links to cat pages", X "R install a new manual root", X "V show the version and configuration of this program", X "W rebuild the whatis database from the cat pages", X "Z check file compression and update", X "c cat specify the prefix for cat directories (cat1 cat2 cat3...)", X "f the given pages are already formatted, just use them", X "h print this help message", X "m man save the manual page source in parallel with the cat page", X "n do not really change the manual system", X "r root specify a user defined root for the manual system", X "s be silent", X "v be verbose by displaying shell commands as they are run", X "w whatis specify a whatis database to update", X "pages the manual pages to be updated", X (char *)0 X }; int X iExit = 0, X fCkAlso = 0, X fDelete = 0, X fGenInstck = 0, X fInstall = 0, X fMkLinks = 0, X fInitNew = 0, X fVersion = 0, X fMkWhatis = 0, X fJustComp = 0; char X copyright[] = "@(#) Copyright 1990 Purdue Research Foundation.\nAll rights reserved.\n", X *pcCat = acCat; int X fFormat = 1; char X *pcMan = (char *)0; int X fExec = 1; char X *pcRoot = acRoot; int X fVerbose = 0; char X *pcWhatis = acWhatis; X static int sbiOnly['w'-'*'+1]; static char sbForbid[] = "%s: option `%c\' forbidden by `%c\'\n"; X static void chkonly(chOpt, fDup) int chOpt, fDup; { X register int chWas; X X chWas = sbiOnly[chOpt-'*']; X if (fDup && chOpt == chWas) { X fprintf(stderr, "%s: option `%c\' cannot be given more than once\n", progname, chWas); X exit(1); X } else if (chWas < 0) { X fprintf(stderr, sbForbid, progname, chOpt, -chWas); X exit(1); X } X sbiOnly[chOpt-'*'] = chOpt; } X static void chkforbid(chOpt, pchList) int chOpt; char *pchList; { X register int chCur; X X while ('\000' != (chCur = *pchList++)) { X if (sbiOnly[chCur-'*'] > 0) { X fprintf(stderr, sbForbid, progname, chCur, chOpt); X exit(1); X } X sbiOnly[chCur-'*'] = -chOpt; X } } X /* X * parser X */ int main(argc, argv) int argc; char **argv; { X static char X sbOpt[] = "ADGILRVWZc:fhm:nr:svw:", X *u_pch = (char *)0; X static int X u_loop = 0; X register int curopt; X register char *pchEnv; X extern char *getenv(); X extern char *strncpy(); X extern int atoi(); X extern char *strrchr(); X X progname = strrchr(argv[0], '/'); X if ((char *)0 == progname) X progname = argv[0]; X else X ++progname; X if ((char *)0 != (pchEnv = getenv("MKCAT"))) X envopt(pchEnv); X while (EOF != (curopt = getopt(argc, argv, sbOpt))) { X switch (curopt) { X case BADARG: X fprintf(stderr, "%s: option %c needs a parameter\n", progname, optopt); X exit(1); X case BADCH: X fprintf(stderr, "%s: usage%s\n", progname, u_terse); X exit(1); X case 'A': X chkforbid('A', "IR"); X fCkAlso = ! 0; X continue; X case 'D': X chkonly('D', 0); X chkforbid('D', "WIZLVR"); X fDelete = ! 0; X continue; X case 'G': X fGenInstck = ! 0; X continue; X case 'I': X chkonly('I', 0); X chkforbid('I', "DLWZVR"); X fInstall = ! 0; X continue; X case 'L': X chkonly('L', 0); X chkforbid('L', "DIZVR"); X fMkLinks = ! 0; X continue; X case 'R': X chkonly('R', 0); X chkforbid('R', "WIZL"); X fInitNew = ! 0; X continue; X case 'V': X chkonly('V', 0); X chkforbid('V', "WIZLD"); X fVersion = ! 0; X continue; X case 'W': X chkonly('W', 0); X chkforbid('W', "DIZVR"); X fMkWhatis = ! 0; X continue; X case 'Z': X chkonly('Z', 0); X chkforbid('Z', "DILWVR"); X fJustComp = ! 0; X continue; X case 'c': X pcCat = optarg; X continue; X case 'f': X fFormat = ! 1; X continue; X case 'h': X fprintf(stdout, "%s: usage%s\n", progname, u_terse); X for (u_loop = 0; (char *)0 != (u_pch = u_help[u_loop]); ++u_loop) { X fprintf(stdout, "%s\n", u_pch); X } X exit(0); X case 'm': X pcMan = optarg; X continue; X case 'n': X fExec = 0; X fVerbose = 1; X continue; X case 'r': X pcRoot = optarg; X continue; X case 's': X fVerbose = 0; X continue; X case 'v': X fVerbose = 1; X continue; X case 'w': X pcWhatis = optarg; X continue; X } X break; X } X iExit = doMkCat(argc-optind, & argv[optind]); X return iExit; } Purdue chmod 0644 mkcat/main.c || echo 'restore of mkcat/main.c failed' Wc_c="`wc -c < 'mkcat/main.c'`" test 4513 -eq "$Wc_c" || echo 'mkcat/main.c: original size 4513, current size' "$Wc_c" fi # ============= mk/Makefile.mkcmd ============== if test -f 'mk/Makefile.mkcmd' -a X"$1" != X"-c"; then echo 'x - skipping mk/Makefile.mkcmd (File already exists)' else echo 'x - extracting mk/Makefile.mkcmd (Text)' sed 's/^X//' << 'Purdue' > 'mk/Makefile.mkcmd' && # Written by S. McGeady, Intel, Inc., mcg@mipon2.intel.com (sm) # Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb (ksb) # # This software is not subject to any license of the American Telephone # and Telegraph Company or the Regents of the University of California. # # Permission is granted to anyone to use this software for any purpose on # any computer system, and to alter it and redistribute it freely, subject # to the following restrictions: # # 1. The authors are not held responsible for any consequences of the # use of this software. # # 2. The origin of this software must not be misrepresented, either by # explicit claim or by omission. Credit to the authors must appear # in documentation and sources. # # 3. Altered versions must be plainly marked as such, and must not be # misrepresented as being the original software. # # 4. This notice may not be removed or altered. # # Makefile for mk # # $Id: Makefile,v 4.6 90/11/19 13:56:36 ksb Exp $ X PROG= mk BIN= ${DESTDIR}/usr/local/bin X L=../libopt #L=/usr/include/local I=/usr/include S=/usr/include/sys P= X INCLUDE= -I$L DEBUG= -O CDEFS= CFLAGS= ${DEBUG} ${CDEFS} ${INCLUDE} X HDR= mk.h optaccum.h machine.h rlimsys.h SRC= mk.c rcsname.c setenv.c optaccum.c rlimsys.c GENh= main.h GENc= main.c GEN= ${GENh} ${GENc} DEP= ${SRC} ${GENc} OBJ= main.o mk.o rcsname.o setenv.o optaccum.o rlimsys.o MAN= mk.1l SOURCE= Makefile Makefile.plain README mk.m ${MAN} ${HDR} ${SRC} X all: ${PROG} X ${PROG}:$P ${OBJ} # ${CC} -o $@ ${CFLAGS} ${OBJ} -lopt # ${CC} -o $@ ${CFLAGS} ${OBJ} -L /usr/local/lib -lopt X ${CC} -o $@ ${CFLAGS} ${OBJ} ../libopt/libopt.a X main.h: main.c X main.c: mk.m X mkcmd std_help.m mk.m X -(cmp -s prog.c main.c || (mv prog.c main.c && echo main.c updated)) X -(cmp -s prog.h main.h || (mv prog.h main.h && echo main.h updated)) X rm -rf prog.[ch] X self-test: ${PROG} X cd Tests; ../${PROG} -mCompile * X swap: ${HDR} ${SRC} ${GEN} Makefile.plain X mv Makefile Makefile.mkcmd X mv Makefile.plain Makefile X clean: FRC X rm -f Makefile.bak *.o prog.[ch] ${GEN} ${PROG} a.out core errs tags X depend: ${HDR} ${SRC} ${GEN} FRC X maketd ${CDEFS} ${INCLUDE} ${DEP} X install: all FRC X install -cs ${PROG} ${BIN}/${PROG} X lint: ${HDR} ${SRC} ${GEN} FRC X lint -h ${CDEFS} ${INCLUDE} ${DEP} X mkcat: ${MAN} X mkcat ${MAN} X print: source FRC X lpr -J'${PROG} source' ${SOURCE} X source: ${SOURCE} X spotless: clean X rcsclean ${SOURCE} X tags: ${HDR} ${SRC} ${GEN} X ctags -t ${HDR} ${SRC} ${GEN} X ${SOURCE}: X co -q $@ X FRC: X # DO NOT DELETE THIS LINE - maketd DEPENDS ON IT X main.o: machine.h main.c optaccum.h X mk.o: machine.h main.h mk.c mk.h rlimsys.h X rcsname.o: machine.h rcsname.c X setenv.o: machine.h setenv.c X optaccum.o: machine.h optaccum.c X rlimsys.o: machine.h mk.h rlimsys.c rlimsys.h X # *** Do not add anything here - It will go away. *** Purdue chmod 0644 mk/Makefile.mkcmd || echo 'restore of mk/Makefile.mkcmd failed' Wc_c="`wc -c < 'mk/Makefile.mkcmd'`" test 2823 -eq "$Wc_c" || echo 'mk/Makefile.mkcmd: original size 2823, current size' "$Wc_c" fi # ============= mk/main.c ============== if test -f 'mk/main.c' -a X"$1" != X"-c"; then echo 'x - skipping mk/main.c (File already exists)' else echo 'x - extracting mk/main.c (Text)' sed 's/^X//' << 'Purdue' > 'mk/main.c' && /* X * machine generated cmd line parser X */ X #include "getopt.h" #include <stdio.h> #include "machine.h" #include "optaccum.h" #include "mk.h" X char X *progname = "$Id$", X uline[] = " [-Aachinsv] [-D defn] [-U undef] [-d submarker] [-e templates] [-l lines] [-m marker] [-t templates] [files]", X *help[] = { X "A find the first matched command that succeeds", X "D defn give a definition of an environment variable", X "U undef remove a definition for an envoronment variable", X "a find all matched commands", X "c confirm the action before running it", X "d submarker look for the string \"$marker(submarker):\" in file", X "e templates scan templates before given files", X "h print this help message", X "i ignore case for markers and submarkers", X "l lines specify the max number of lines to search", X "m marker look for the string \"$marker:\" in file", X "n do not really do it", X "s silent operation", X "t templates look for marker in template file", X "v be verbose", X "files search for commands in these files", X (char *)0 X }, X *pathname = (char *)0; int X fFirst = 0, X debug = 0, X fAll = 0, X fConfirm = 0; char X *submark = (char *)0, X *pchExamine = (char *)0; int X fCase = 0, X lines = 99; char X *markstr = (char *)0; int X fExec = 1; char X *pchTemplates = (char *)0; int X fVerbose = 1; X /* X * a usage function X */ int usage() { X register char **ppch; X X for (ppch = help; (char *)0 != *ppch; ++ppch) X printf("%s\n", *ppch); } X /* X * parser X */ int main(argc, argv) int argc; char **argv; { X static char X sbOpt[] = "AD:U:Vacd:e:hil:m:nst:v"; X static int X retval = 0; X static char X *u_pch = (char *)0; X static int X u_loop = 0; X register int curopt, fNoArgs = 1; X register char *pchEnv; X extern char *getenv(); X extern int atoi(); X extern char *strrchr(); X X progname = strrchr(argv[0], '/'); X if ((char *)0 == progname) X progname = argv[0]; X else X ++progname; X if ((char *)0 != (pchEnv = getenv("MK"))) X envopt(pchEnv); X pathname = argv[0]; X for (;;) { X if (EOF != (curopt = getopt(argc, argv, sbOpt))) { X /* fallthrough */; X } else if (EOF != getarg(argc, argv)) { X retval += process(optarg); X fNoArgs = 0; X continue; X } else { X break; X } X switch (curopt) { X case BADARG: X fprintf(stderr, "%s: option %c needs a parameter\n", progname, optopt); X exit(1); X case BADCH: X fprintf(stderr, "%s: usage%s\n", progname, uline); X exit(1); X case 'A': X fFirst = ! 0; X continue; X case 'D': X define(optarg); X continue; X case 'U': X undefine(optarg); X continue; X case 'V': X debug = ! 0; X continue; X case 'a': X fAll = ! 0; X continue; X case 'c': X fConfirm = ! 0; X continue; X case 'd': X submark = optarg; X continue; X case 'e': X pchExamine = OptAccum(pchExamine, optarg, ":"); X continue; X case 'h': X fprintf(stdout, "%s: usage%s\n", progname, uline); X for (u_loop = 0; (char *)0 != (u_pch = help[u_loop]); ++u_loop) { X fprintf(stdout, "%s\n", u_pch); X } X exit(0); X case 'i': X fCase = ! 0; X continue; X case 'l': X lines = atoi(optarg); X continue; X case 'm': X markstr = optarg; X continue; X case 'n': X fExec = ! 1; X continue; X case 's': X fVerbose = 0; X continue; X case 't': X pchTemplates = OptAccum(pchTemplates, optarg, ":"); X continue; X case 'v': X fVerbose = 1; X continue; X } X break; X } X if (fNoArgs) { X if (debug) { X Version(); X } X } X X /* we just exit now */ X exit(retval); } Purdue chmod 0644 mk/main.c || echo 'restore of mk/main.c failed' Wc_c="`wc -c < 'mk/main.c'`" test 3495 -eq "$Wc_c" || echo 'mk/main.c: original size 3495, current size' "$Wc_c" fi # ============= mk-lib/Makefile ============== if test -f 'mk-lib/Makefile' -a X"$1" != X"-c"; then echo 'x - skipping mk-lib/Makefile (File already exists)' else echo 'x - extracting mk-lib/Makefile (Text)' sed 's/^X//' << 'Purdue' > 'mk-lib/Makefile' && # Makefile for mk default rules # Kevin S Braunsdorf, PUCC X LIB= ${DESTDIR}/usr/local/lib X MANUAL= dot-1c dot-1g dot-1l dot-1u dot-1v \ X dot-2 dot-2l \ X dot-3 dot-3c dot-3f dot-3l dot-3m dot-3n dot-3s dot-3x \ X dot-4 dot-4f dot-4l dot-4n dot-4p \ X dot-5 dot-5l \ X dot-6 dot-6l \ X dot-7 dot-7l \ X dot-8 dot-8c dot-8l dot-8v USECC= dot-s m-cc USEFORTRAN=dot-f77 m-fc USEMAKE=file-Makefile file-makefile dot-make USEMAN= dot-ms dot-me dot-mm USEM2= dot-m2 USENDBM= pre-pag USENONE=dot-i USENROFF=dot-nro USEPASCAL= m-pc USEPATCH=pre-diff USESH= dot-csh dot-tcsh dot-ksh USEUU= pre-uue USEVALID=file-Valid dot-v REAL= m-clean m-compile m-display m-info m-mkcat m-run \ X type-b type-c type-d type-p type-s \ X file-valid file-gmon.out \ X pre-a pre-C pre-dir pre-ln pre-o pre-out pre-patch \ X pre-tar pre-uu pre-Z pre-z pre-zoo \ X dot- dot-1 dot-c dot-C dot-dvi dot-e dot-el dot-f dot-h dot-l \ X dot-m4 dot-m dot-man dot-mk dot-p dot-ph dot-pl dot-ps dot-r \ X dot-sh dot-shar dot-t dot-xbm dot-y \ X comma-v IGNORE= pre-MW pre-cpio MAN= mk.5l SOURCE= Makefile README ${MAN} ${REAL} ${IGNORE} X all: source X ${LIB}/mk: X install -d -r $@ X clean: FRC X rm -f Makefile.bak a.out core errs tags X depend: FRC X : 'no depend' X deinstall: ${MAN} X rm -rf ${LIB}/mk X mkcat -D ${MAN} X dirs: ${LIB}/mk X install: all dirs FRC X install -c -m 644 ${REAL} ${LIB}/mk X -cd ${LIB}/mk; for file in ${USEVALID}; do \ X [ -f $$file ] || (ln -s file-valid $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEPATCH}; do \ X [ -f $$file ] || (ln -s pre-patch $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USENDBM}; do \ X [ -f $$file ] || (ln -s pre-dir $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEUU}; do \ X [ -f $$file ] || (ln -s pre-uu $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${MANUAL}; do \ X [ -f $$file ] || (ln -s dot-1 $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEMAN}; do \ X [ -f $$file ] || (ln -s dot-man $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USESH}; do \ X [ -f $$file ] || (ln -s dot-sh $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USECC}; do \ X [ -f $$file ] || (ln -s dot-c $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEMAKE}; do \ X [ -f $$file ] || (ln -s dot-mk $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USENONE}; do \ X [ -f $$file ] || (ln -s dot-h $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEM2}; do \ X [ -f $$file ] || (ln -s dot-m $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEPASCAL}; do \ X [ -f $$file ] || (ln -s dot-p $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USEFORTRAN}; do \ X [ -f $$file ] || (ln -s dot-f $$file && echo $$file);\ X done X -cd ${LIB}/mk; for file in ${USENROFF}; do \ X [ -f $$file ] || (ln -s dot-t $$file && echo $$file);\ X done X lint: FRC X : 'nothing to lint' X mkcat: ${MAN} X mkcat ${MAN} X print: source FRC X lpr -J'mk templates' ${SOURCE} X source: ${SOURCE} X spotless: clean X rcsclean ${SOURCE} X tags: FRC X : 'no tags' X ${SOURCE}: X co -q $@ X FRC: X Purdue chmod 0644 mk-lib/Makefile || echo 'restore of mk-lib/Makefile failed' Wc_c="`wc -c < 'mk-lib/Makefile'`" test 3088 -eq "$Wc_c" || echo 'mk-lib/Makefile: original size 3088, current size' "$Wc_c" fi true || echo 'restore of mkcat/strcasecmp.c failed' echo End of part 4, continue with part 5 exit 0 exit 0 # Just in case... -- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net. Use a domain-based address or give alternate paths, or you may lose out.