home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume24 / pucc-mk / part01 next >
Encoding:
Internet Message Format  |  1991-03-19  |  40.6 KB

  1. Subject:  v24i057:  Purdue shell turbo charger and manual installer, Part01/06
  2. Newsgroups: comp.sources.unix
  3. Approved: rsalz@uunet.UU.NET
  4. X-Checksum-Snefru: b222d50d 502472c7 47c21e05 62f92e18
  5.  
  6. Submitted-by: Kevin Braunsdorf <ksb@nostromo.cc.purdue.edu>
  7. Posting-number: Volume 24, Issue 57
  8. Archive-name: pucc-mk/part01
  9.  
  10. This six part archive contains the mk tool (a turbo charger for the
  11. shell) and the manual page installer.  This might not be for everyone;
  12. if you don't write or install manual pages you can skip it.  It needs
  13. the libs to build and the install package to run.
  14.  
  15. Sometimes you want to hide a bit of shell code in a file, then later extract
  16. and run that code on that file to produce an output.  A good example of this
  17. is the manual system: it would be terrible to have to name a Makefile for
  18. each manual page in /usr/man/man*, or keep said file(s) in sync with the
  19. pages.
  20.  
  21. What we do instead is hide the formatting command in the comments of the
  22. manual page, then extract it when we need to format the page.  Thus the
  23. command moves with the page and cannot get lost.  If a page has no command
  24. hidden in it we will fall back to a set formula, much as make(1) does.
  25.  
  26. The manual page installer complete replaces catman and makewhatis,
  27. among others.
  28.  
  29. kayessbee
  30. --
  31. "This may be a new sense of the word `robust' for you."
  32. Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb
  33.  
  34. #!/bin/sh
  35. # This is pucc-1c, a shell archive (produced by shar 3.49)
  36. # To extract the files from this archive, save it to a file, remove
  37. # everything above the "!/bin/sh" line above, and type "sh file_name".
  38. #
  39. # made 11/29/1990 15:58 UTC by ksb@cc.purdue.edu (Kevin Braunsdorf)
  40. # Source directory /ksb/c.s.u-2
  41. #
  42. # existing files will NOT be overwritten unless -c is specified
  43. #
  44. # This shar contains:
  45. # length  mode       name
  46. # ------ ---------- ------------------------------------------
  47. #   1737 -rw-r--r-- INSTALL.03
  48. #  32072 -r--r--r-- mkcat/mkcat.c
  49. #  21421 -r--r--r-- mk/mk.c
  50. #   2737 -rw-r--r-- mk/Makefile
  51. #   1182 -rw-r--r-- mk/Tests/ExitCodes
  52. #    376 -rw-r--r-- mk/Tests/compat
  53. #    190 -r--r--r-- mk/rlimsys.h
  54. #  27828 -r--r--r-- mkcat/scan.c
  55. #  15821 -r--r--r-- mkcat/genwhatis.c
  56. #  12839 -r--r--r-- mkcat/format.c
  57. #   1292 -r--r--r-- mk/setenv.c
  58. #    191 -r--r--r-- mk-lib/m-clean
  59. #  11371 -r--r--r-- mkcat/readman.c
  60. #  10944 -r--r--r-- mk/mk.1l
  61. #   7922 -r--r--r-- mkcat/pt.c
  62. #   4889 -r--r--r-- mk/rlimsys.c
  63. #   6777 -r--r--r-- mk-lib/mk.5l
  64. #   5555 -r--r--r-- mkcat/mkcat.8l
  65. #   5149 -r--r--r-- mkcat/sym2hard.c
  66. #   4487 -r--r--r-- mkcat/mkcat-opts.5l
  67. #    725 -rw-r--r-- mk/Tests/file.x,y
  68. #    159 -r--r--r-- mk-lib/m-info
  69. #   4513 -rw-r--r-- mkcat/main.c
  70. #   2823 -rw-r--r-- mk/Makefile.mkcmd
  71. #   3495 -rw-r--r-- mk/main.c
  72. #   3088 -rw-r--r-- mk-lib/Makefile
  73. #   3766 -r--r--r-- mkcat/strcasecmp.c
  74. #   3675 -rw-r--r-- mkcat/Makefile
  75. #   3718 -rw-r--r-- mkcat/Makefile.mkcmd
  76. #   2007 -r--r--r-- mk/mk.m
  77. #   1954 -r--r--r-- mkcat/mkcat.h
  78. #   2050 -r--r--r-- mkcat/pt.h
  79. #   1815 -r--r--r-- mkcat/genwhatis.h
  80. #   2423 -r--r--r-- mkcat/mkcat.m
  81. #   1630 -rw-r--r-- mk/Tests/options
  82. #   1101 -r--r--r-- mk/README
  83. #   1123 -r--r--r-- mk-lib/file-valid
  84. #   1168 -r--r--r-- mk-lib/pre-uu
  85. #   1371 -r--r--r-- mk-lib/dot-m
  86. #   1259 -r--r--r-- mk-lib/README
  87. #   1493 -r--r--r-- mkcat/readman.h
  88. #   1164 -r--r--r-- mkcat/scan.h
  89. #   1525 -rw-r--r-- mkcat/machine.h
  90. #   1204 -r--r--r-- mkcat/format.h
  91. #    806 -rw-r--r-- mk/mk.h
  92. #    825 -r--r--r-- mk/rcsname.c
  93. #    977 -r--r--r-- mk/optaccum.c
  94. #   1011 -r--r--r-- mk-lib/pre-dir
  95. #    897 -r--r--r-- mk-lib/pre-Z
  96. #   1049 -r--r--r-- mk-lib/pre-z
  97. #    859 -r--r--r-- mk-lib/pre-zoo
  98. #    830 -r--r--r-- mk-lib/dot-y
  99. #   1019 -r--r--r-- mk-lib/pre-MW
  100. #    911 -r--r--r-- mkcat/README
  101. #    430 -r--r--r-- mk/optaccum.h
  102. #    657 -r--r--r-- mk/INSTALL
  103. #    610 -rw-r--r-- mk/machine.h
  104. #    712 -r--r--r-- mk-lib/pre-out
  105. #    533 -r--r--r-- mk-lib/dot-c
  106. #    672 -r--r--r-- mk-lib/dot-e
  107. #    530 -r--r--r-- mk-lib/dot-l
  108. #    693 -r--r--r-- mk-lib/dot-man
  109. #    601 -r--r--r-- mk-lib/dot-ps
  110. #    705 -r--r--r-- mk-lib/dot-r
  111. #    501 -r--r--r-- mk-lib/dot-shar
  112. #    545 -r--r--r-- mk-lib/dot-t
  113. #    605 -r--r--r-- mk-lib/comma-v
  114. #    647 -r--r--r-- mkcat/INSTALL
  115. #    471 -r--r--r-- mk-lib/pre-a
  116. #    473 -r--r--r-- mk-lib/pre-C
  117. #    485 -r--r--r-- mk-lib/pre-patch
  118. #    481 -r--r--r-- mk-lib/dot-1
  119. #    384 -r--r--r-- mk-lib/dot-dvi
  120. #    441 -r--r--r-- mk-lib/dot-f
  121. #    417 -r--r--r-- mk-lib/dot-m4
  122. #    467 -r--r--r-- mk-lib/dot-mk
  123. #    435 -r--r--r-- mk-lib/dot-p
  124. #    426 -r--r--r-- mk-lib/pre-cpio
  125. #    320 -rw-r--r-- mk/Tests/typenot
  126. #    264 -rw-r--r-- mk/Tests/markers
  127. #    275 -rw-r--r-- mk/Tests/params
  128. #    314 -r--r--r-- mk-lib/m-mkcat
  129. #    300 -r--r--r-- mk-lib/m-run
  130. #    298 -r--r--r-- mk-lib/type-b
  131. #    314 -r--r--r-- mk-lib/type-c
  132. #    274 -r--r--r-- mk-lib/type-d
  133. #    281 -r--r--r-- mk-lib/type-p
  134. #    263 -r--r--r-- mk-lib/type-s
  135. #    320 -r--r--r-- mk-lib/file-gmon.out
  136. #    339 -r--r--r-- mk-lib/pre-o
  137. #    296 -r--r--r-- mk-lib/pre-tar
  138. #    263 -r--r--r-- mk-lib/dot-
  139. #    257 -r--r--r-- mk-lib/dot-h
  140. #    299 -r--r--r-- mk-lib/dot-sh
  141. #    286 -rw-r--r-- mkcat/main.h
  142. #    238 -rw-r--r-- mk/main.h
  143. #    222 -r--r--r-- mk-lib/dot-xbm
  144. #    205 -r--r--r-- mk-lib/m-compile
  145. #    225 -r--r--r-- mk-lib/m-display
  146. #    203 -r--r--r-- mk-lib/pre-ln
  147. #    233 -r--r--r-- mk-lib/dot-C
  148. #    239 -r--r--r-- mk-lib/dot-pl
  149. #    199 -r--r--r-- mk-lib/dot-el
  150. #    131 -rw-r--r-- mk/Tests/lines
  151. #    111 -r--r--r-- mk-lib/dot-ph
  152. #
  153. # ============= INSTALL.03 ==============
  154. if test -f 'INSTALL.03' -a X"$1" != X"-c"; then
  155.     echo 'x - skipping INSTALL.03 (File already exists)'
  156. else
  157. echo 'x - extracting INSTALL.03 (Text)'
  158. sed 's/^X//' << 'Purdue' > 'INSTALL.03' &&
  159. Contains:
  160. X    mk(1l)        - detect and execute shell commands in files
  161. X    mk(5l)        - how to write and embed mk commands
  162. X    mkcat(8l)    - update and format a manual page
  163. X
  164. X
  165. Notes on depends:
  166. X    - libopt.a and libsrtunq.a need not be installed, but it
  167. X      would make life easier if you want other PUCC tools.
  168. X
  169. X    - mk-lib needs a lib directory (like /usr/local/lib/mk)
  170. X
  171. X    - mk needs to know mk-lib's lib directory, and needs libopt
  172. X
  173. X    - mkcat needs mk(1L) and install(1L) to function at all,
  174. X      and needs libopt and libsrtunq
  175. X
  176. X
  177. To install these tools:
  178. X
  179. 0\ read the manual pages, see if you want any of them
  180. X
  181. 1\ decide where to install all this stuff, change the destinations in
  182. X   the Makefiles {BIN,LIB,ETC,HEADER}
  183. X    vi */Makefile
  184. X    
  185. 2\ edit mk-lib/Makefile and mk/mk.h to change `/usr/local/lib/mk' to
  186. X   whatever lib directory you want mk to use
  187. X    vi mk-lib/Makefile mk/mk.h
  188. X
  189. 3\ edit */machine.h and set up and macros that look important to you
  190. X    vi */machine.h
  191. X
  192. 4\ remove strcasecmp.o from the OBJ list in mkcat/Makefile if you have
  193. X    one in libc (or just ignore it)
  194. X    nm /lib/libc.a | grep strcasecmp
  195. X
  196. 5\ build mk, test it if you like
  197. X    (cd mk && make all)
  198. X    (cd mk && make self-test)
  199. X
  200. 6\ build mkcat {it has some hard coded stuff you might edit later in mkcat.c}
  201. X    (cd mkcat && make)
  202. X
  203. 7\ install the tools, note that install must be first the others us it
  204. X    su
  205. X    (cd mk && make install)                #
  206. X    (cd mk-lib && make install)            #
  207. X    (cd mkcat && make install)            #
  208. X    exit                        # the root shell
  209. X
  210. 8\ install the manual pages
  211. X    su
  212. X    mkcat -v mk/mk.1l mk-lib/mk.5l mkcat/mkcat.8l mkcat/mkcat-opts.5l
  213. X    exit
  214. X
  215. 9\ clean up the dirs
  216. X    (cd mk && make clean)
  217. X    (cd mk-lib && make clean)
  218. X    (cd mkcat && make clean)
  219. X
  220. kayessbee
  221. --
  222. Kevin Braunsdorf, ksb@cc.purdue.edu, pur-ee!ksb, purdue!ksb
  223. Purdue
  224. chmod 0644 INSTALL.03 ||
  225. echo 'restore of INSTALL.03 failed'
  226. Wc_c="`wc -c < 'INSTALL.03'`"
  227. test 1737 -eq "$Wc_c" ||
  228.     echo 'INSTALL.03: original size 1737, current size' "$Wc_c"
  229. fi
  230. # ============= mkcat/mkcat.c ==============
  231. if test ! -d 'mkcat'; then
  232.     echo 'x - creating directory mkcat'
  233.     mkdir 'mkcat'
  234. fi
  235. if test -f 'mkcat/mkcat.c' -a X"$1" != X"-c"; then
  236.     echo 'x - skipping mkcat/mkcat.c (File already exists)'
  237. else
  238. echo 'x - extracting mkcat/mkcat.c (Text)'
  239. sed 's/^X//' << 'Purdue' > 'mkcat/mkcat.c' &&
  240. /*
  241. X * Copyright 1990 Purdue Research Foundation, West Lafayette, Indiana
  242. X * 47907.  All rights reserved.
  243. X *
  244. X * Written by Kevin S Braunsdorf, ksb@cc.purdue.edu, purdue!ksb
  245. X *
  246. X * This software is not subject to any license of the American Telephone
  247. X * and Telegraph Company or the Regents of the University of California.
  248. X *
  249. X * Permission is granted to anyone to use this software for any purpose on
  250. X * any computer system, and to alter it and redistribute it freely, subject
  251. X * to the following restrictions:
  252. X *
  253. X * 1. Neither the authors nor Purdue University are responsible for any
  254. X *    consequences of the use of this software.
  255. X *
  256. X * 2. The origin of this software must not be misrepresented, either by
  257. X *    explicit claim or by omission.  Credit to the authors and Purdue
  258. X *    University must appear in documentation and sources.
  259. X *
  260. X * 3. Altered versions must be plainly marked as such, and must not be
  261. X *    misrepresented as being the original software.
  262. X *
  263. X * 4. This notice may not be removed or altered.
  264. X */
  265. X
  266. /*
  267. X * this module sets some global variables that tell mkcat how this    (ksb)
  268. X * system is aranged
  269. X *
  270. X * who are we today, parse options with mkcmd parsers and stuff
  271. X */
  272. #include "machine.h"
  273. X
  274. #include <stdio.h>
  275. #include <ctype.h>
  276. #include <math.h>
  277. #include <errno.h>
  278. #include <sys/types.h>
  279. #include <sys/file.h>
  280. #include <sys/param.h>
  281. #if defined(SYSV)
  282. #include <ndir.h>
  283. #else
  284. #include <sys/dir.h>
  285. #endif
  286. #include <sys/stat.h>
  287. X
  288. #include <grp.h>
  289. #include <pwd.h>
  290. extern struct group *getgrgid(), *getgrnam();
  291. extern struct passwd *getpwuid(), *getpwnam();
  292. X
  293. #if !defined(MAXPATHLEN)
  294. #define MAXPATHLEN    1024
  295. #endif
  296. X
  297. #include "main.h"
  298. #include "pt.h"
  299. #include "genwhatis.h"
  300. #include "mkcat.h"
  301. #include "srtunq.h"
  302. X
  303. extern int errno;
  304. extern char *sys_errlist[];
  305. #define strerror(Me) sys_errlist[Me]
  306. extern char *strrchr(), *strchr(), *strcat(), *strcpy(), *strncpy();
  307. extern char *strsave();
  308. extern char *malloc(), *calloc(), *mktemp();
  309. extern int strcmp(), strncmp();
  310. X
  311. #define HAVE_A(Mp)    ((char *)0 != (Mp) && '\000' != *(Mp))
  312. X
  313. int fSawCfg;                /* we found/read a config file    */
  314. char acOpts[] = ".mkcat-opts";        /* file to read/write options    */
  315. int fUseHards = 1;            /* -H or -S            */
  316. int fCompress = 1;            /* or 0                */
  317. char *apcModes[] = {
  318. X    /* owner      group       mode                    */
  319. X    (char *)0, (char *)0, (char *)0,    /* dir            */
  320. X    (char *)0, (char *)0, (char *)0,    /* page            */
  321. X    (char *)0, (char *)0, (char *)0,    /* whatis        */
  322. X    (char *)0, (char *)0, (char *)0        /* man src        */
  323. };
  324. char *pcMkToken = (char *)0;
  325. X
  326. typedef struct LInode {            /* linked list, extender combos    */
  327. X    struct LInode *pLInext;
  328. X    SRTTABLE STall;
  329. } LIST;
  330. LIST *pLIExt;
  331. SRTTABLE STBase;
  332. X
  333. static char
  334. X    acZKey[] = "compress:",        /* use compress/zcat        */
  335. X    acLKey[] = "links:",        /* hard or soft flag        */
  336. X    acTKey[] = "token:",        /* `mk -m$token file' to format    */
  337. X    acBKey[] = "OKbase:",        /* intro page bases        */
  338. X    acSKey[] = "OKext:",        /* getc.3s !conflict gets.3f    */
  339. X    acPKey[] = "page",        /* optional            */
  340. X    acDKey[] = "dir",
  341. X    acWKey[] = "whatis",
  342. X    acNKey[] = "man",
  343. X    acMKey[] = "mode:",        /* install opts            */
  344. X    acOKey[] = "owner:",
  345. X    acGKey[] = "group:";
  346. X
  347. X
  348. /* is this base in the list of legal dup bases?                (ksb)
  349. X */
  350. int
  351. IsOKBase(pc)
  352. char *pc;
  353. {
  354. X    return (char *)0 != srtmem(& STBase, pc, strcmp);
  355. }
  356. X
  357. /* do the given extenders conflict?                    (ksb)
  358. X * find a list that contains both, then no conflict
  359. X */
  360. int
  361. ExtConflict(pcE1, pcE2)
  362. char *pcE1, *pcE2;
  363. {
  364. X    register LIST *pLI;
  365. X
  366. X    for (pLI = pLIExt; (LIST *)0 != pLI; pLI = pLI->pLInext) {
  367. X        if ((char *)0 == srtmem(& pLI->STall, pcE1, strcmp))
  368. X            continue;
  369. X        if ((char *)0 != srtmem(& pLI->STall, pcE2, strcmp))
  370. X            return 0;
  371. X    }
  372. X    return 1;
  373. }
  374. X
  375. /*
  376. X * learn these things by reading $ROOT/.mkcat-opt            (ksb)
  377. X *    # comments
  378. X *    compress: y|n
  379. X *    links: H|S
  380. X *    {dir,page,}{mode,group,owner}: string
  381. X *    OKbase: intro
  382. X *    OKext: {3f,3s}
  383. X */
  384. static void
  385. PrepInfo()
  386. {
  387. X    register FILE *fpCnf;
  388. X    register char *pcScan, *pcNl;
  389. X    register int j;
  390. X    auto char acConfig[MAXPATHLEN+1];
  391. X    auto char acLine[BUFSIZ];
  392. X
  393. X    srtinit(&STBase);
  394. X    pLIExt = (LIST *)0;
  395. X
  396. X    fSawCfg = 0;
  397. X    (void)sprintf(acConfig, "%s/%s", pcRoot, acOpts);
  398. X    if (NULL == (fpCnf = fopen(acConfig, "r"))) {
  399. X        return;        /* use defaults        */
  400. X    }
  401. X    fSawCfg = 1;
  402. X    while ((char *)0 != (pcScan = fgets(acLine, BUFSIZ, fpCnf))) {
  403. X        while (isspace(*pcScan)) {
  404. X            if ('\n' == *pcScan)
  405. X                break;
  406. X            ++pcScan;
  407. X        }
  408. X        if ('\n' == *pcScan || '#' == *pcScan) {
  409. X            continue;
  410. X        }
  411. X        if (0 == strncasecmp(acZKey, pcScan, sizeof(acZKey)-1)) {
  412. X            pcScan += sizeof(acZKey)-1;
  413. X            while (isspace(*pcScan)) {
  414. X                if ('\n' == *pcScan)
  415. X                    break;
  416. X                ++pcScan;
  417. X            }
  418. X            switch (*pcScan) {
  419. X            case 'y':
  420. X            case 'Y':
  421. X                fCompress = 1;
  422. X                break;
  423. X            case 'n':
  424. X            case 'N':
  425. X                fCompress = 0;
  426. X                break;
  427. X            default:
  428. X            case '\n':
  429. X                break;
  430. X            }
  431. X            continue;
  432. X        }
  433. X        if (0 == strncasecmp(acLKey, pcScan, sizeof(acLKey)-1)) {
  434. X            pcScan += sizeof(acLKey)-1;
  435. X            while (isspace(*pcScan)) {
  436. X                if ('\n' == *pcScan)
  437. X                    break;
  438. X                ++pcScan;
  439. X            }
  440. X            switch (*pcScan) {
  441. X            case 'H':
  442. X            case 'h':
  443. X                fUseHards = 1;
  444. X                break;
  445. X            case 's':
  446. X            case 'S':
  447. X                fUseHards = 0;
  448. X                break;
  449. X            default:
  450. X            case '\n':
  451. X                break;
  452. X            }
  453. X            continue;
  454. X        }
  455. X
  456. X        if (0 == strncasecmp(acBKey, pcScan, sizeof(acBKey)-1)) {
  457. X            register char *pcLast;
  458. X
  459. X            pcScan += sizeof(acBKey)-1;
  460. X            while (isspace(*pcScan)) {
  461. X                if ('\n' == *pcScan)
  462. X                    break;
  463. X                ++pcScan;
  464. X            }
  465. X            switch (*pcScan) {
  466. X            default:
  467. X                if ((char *)0 == (pcLast = strchr(pcScan, '\n'))) {
  468. X                    fprintf(stderr, "%s: %s line too long\n", progname, acBKey);
  469. X                    break;
  470. X                }
  471. X                *pcLast = '\000';
  472. X                (void)srtin(&STBase, pcScan, strcmp);
  473. X                break;
  474. X            case '\n':
  475. X                fprintf(stderr, "%s: %s missing basename\n", progname, acBKey);
  476. X                break;
  477. X            }
  478. X            continue;
  479. X        }
  480. X
  481. X        if (0 == strncasecmp(acSKey, pcScan, sizeof(acSKey)-1)) {
  482. X            register char *pcLast, cSave;
  483. X            register LIST *pLITemp;
  484. X
  485. X            pLITemp = (LIST *)malloc(sizeof(LIST));
  486. X            if ((LIST *)0 == pLITemp) {
  487. X                write(2, "out of memory\n", 13);
  488. X                exit(2);
  489. X            }
  490. X            pLITemp->pLInext = pLIExt;
  491. X            pLIExt = pLITemp;
  492. X            (void)srtinit(& pLITemp->STall);
  493. X            pcScan += sizeof(acSKey)-1;
  494. X            do {    /* {a,v,c} */
  495. X                while (isspace(*pcScan)) {
  496. X                    if ('\n' == *pcScan)
  497. X                        break;
  498. X                    ++pcScan;
  499. X                }
  500. X                switch (*pcScan) {
  501. X                case ',':
  502. X                case '{':
  503. X                    ++pcScan;
  504. X                    /* fallthrough */
  505. X                default:
  506. X                    pcLast = pcScan;
  507. X                    while (',' != *pcScan && '}' != *pcScan && '\000' != *pcScan && '\n' != *pcScan)
  508. X                        ++pcScan;
  509. X                    cSave = *pcScan;
  510. X                    *pcScan = '\000';
  511. X                    (void)srtin(& pLITemp->STall, pcLast, strcmp);
  512. X                    *pcScan = cSave;
  513. X                    break;
  514. X                case '}':
  515. X                    ++pcScan;
  516. X                case '\n':
  517. X                    break;
  518. X                }
  519. X            } while ('\n' != *pcScan && '\000' != *pcScan);
  520. X            continue;
  521. X        }
  522. X
  523. X        if ((char *)0 == (pcNl = strchr(pcScan, '\n'))) {
  524. X            fprintf(stderr, "%s: %s: line too long?\n", progname, acConfig);
  525. X            exit(1);
  526. X        }
  527. X        *pcNl = '\000';
  528. X
  529. X        if (0 == strncasecmp(acTKey, pcScan, sizeof(acTKey)-1)) {
  530. X            pcScan += sizeof(acTKey)-1;
  531. X            pcMkToken = strsave(pcScan);
  532. X            continue;
  533. X        }
  534. X        if (0 == strncasecmp(acDKey, pcScan, sizeof(acDKey)-1)) {
  535. X            j = DIRMODE-MINMODE;
  536. X            pcScan += sizeof(acDKey)-1;
  537. X        } else if (0 == strncasecmp(acPKey, pcScan, sizeof(acPKey)-1)) {
  538. X            j = PAGEMODE-MINMODE;
  539. X            pcScan += sizeof(acPKey)-1;
  540. X        } else if (0 == strncasecmp(acWKey, pcScan, sizeof(acWKey)-1)) {
  541. X            j = WHATISMODE-MINMODE;
  542. X            pcScan += sizeof(acWKey)-1;
  543. X        } else if (0 == strncasecmp(acNKey, pcScan, sizeof(acNKey)-1)) {
  544. X            j = MANMODE-MINMODE;
  545. X            pcScan += sizeof(acNKey)-1;
  546. X        } else {
  547. X            j = PAGEMODE-MINMODE;
  548. X        }
  549. X        while (isspace(*pcScan)) {
  550. X            ++pcScan;
  551. X        }
  552. X        if (':' == *pcScan) {
  553. X            do {
  554. X                ++pcScan;
  555. X            } while (isspace(*pcScan));
  556. X            switch (j) {
  557. X            case DIRMODE-MINMODE:
  558. X                pcCat = strsave(pcScan);
  559. X                break;
  560. X            case WHATISMODE-MINMODE:
  561. X                pcWhatis = strsave(pcScan);
  562. X                break;
  563. X            case MANMODE-MINMODE:
  564. X                pcMan = strsave(pcScan);
  565. X                break;
  566. X            case PAGEMODE-MINMODE:
  567. X            default:
  568. X                fprintf(stderr, "%s: unknown config file option\n", progname);
  569. X                exit(3);
  570. X            }
  571. X            continue;
  572. X        }
  573. X
  574. X        if (0 == strncasecmp(acOKey, pcScan, sizeof(acOKey)-1)) {
  575. X            pcScan += sizeof(acOKey)-1;
  576. X            while (isspace(*pcScan)) {
  577. X                ++pcScan;
  578. X            }
  579. X            if ('\000' == pcScan)
  580. X                continue;
  581. X            apcModes[j+DIROWNER] = strsave(pcScan);
  582. X            continue;
  583. X        }
  584. X        if (0 == strncasecmp(acGKey, pcScan, sizeof(acGKey)-1)) {
  585. X            pcScan += sizeof(acGKey)-1;
  586. X            while (isspace(*pcScan)) {
  587. X                ++pcScan;
  588. X            }
  589. X            if ('\000' == pcScan)
  590. X                continue;
  591. X            apcModes[j+DIRGROUP] = strsave(pcScan);
  592. X            continue;
  593. X        }
  594. X        if (0 == strncasecmp(acMKey, pcScan, sizeof(acMKey)-1)) {
  595. X            pcScan += sizeof(acMKey)-1;
  596. X            while (isspace(*pcScan)) {
  597. X                ++pcScan;
  598. X            }
  599. X            if ('\000' == pcScan)
  600. X                continue;
  601. X            apcModes[j+DIRMODE] = strsave(pcScan);
  602. X            continue;
  603. X        }
  604. X        printf("%s: %s: unknown: %s", progname, pcScan);
  605. X    }
  606. X    (void)fclose(fpCnf);
  607. }
  608. X
  609. X
  610. /*
  611. X * select the cat directories to scan                    (ksb)
  612. X */
  613. static int
  614. rootSelect(pEnt)
  615. struct direct *pEnt;
  616. {
  617. X    extern int strlen();
  618. X    auto struct stat stDir;
  619. X    register int len;
  620. X
  621. X    len = strlen(pcCat);
  622. X    if (0 != strncmp(pcCat, pEnt->d_name, len) || !isdigit(pEnt->d_name[len])) {
  623. X        return 0;
  624. X    }
  625. X    if (-1 == LSTAT(pEnt->d_name, & stDir)) {
  626. X        fprintf(stderr, "%s: stat: %s: %s\n", progname, pEnt->d_name, strerror(errno));
  627. X        return 0;
  628. X    }
  629. X    if ((stDir.st_mode & S_IFMT) != S_IFDIR) {
  630. X        fprintf(stderr, "%s: `%s\' should be a directory?\n", progname, pEnt->d_name);
  631. X        return 0;
  632. X    }
  633. X    return 1;
  634. }
  635. X
  636. /*
  637. X * do show config                            (ksb)
  638. X */
  639. void
  640. doShowCfg()
  641. {
  642. X    register int i;
  643. X    register LIST *pLI;
  644. X    register char chSep, *pc;
  645. X    auto int fSeeInstall;
  646. X
  647. X    for (fSeeInstall = 0, i = 0; i < MAXMODE+1; ++i) {
  648. X        if ((char *)0 == apcModes[i]) {
  649. X            apcModes[i] = "<see install>";
  650. X            fSeeInstall = 1;
  651. X        }
  652. X    }
  653. X    printf("%s: version: $Id: mkcat.c,v 3.21 90/11/28 09:54:46 ksb Exp $\n", progname);
  654. X    printf("%s: root = `%s\', cat = `%s\', whatis = `%s\'", progname, pcRoot, pcCat, pcWhatis);
  655. X    if (HAVE_A(pcMan)) {
  656. X        printf(", man = `%s\'", pcMan);
  657. X    }
  658. X    printf("\n%s: pages are%s compressed, links are %s", progname, fCompress ? "":" not", fUseHards ? "hard" : "symbolic");
  659. X    if (fSawCfg) {
  660. X        printf(", config in %s\n", acOpts);
  661. X    } else {
  662. X        printf(", no config file\n");
  663. X    }
  664. X    srtgti(& STBase);
  665. X    while ((char *)0 != (pc = srtgets(& STBase)))
  666. X        printf("%s: %s %s\n", progname, acBKey, pc);
  667. X    for (pLI = pLIExt; 0 != pLI; pLI = pLI->pLInext) {
  668. X        printf("%s: %s ", progname, acSKey);
  669. X        chSep = '{';
  670. X        srtgti(& pLI->STall);
  671. X        while ((char *)0 != (pc = srtgets(& pLI->STall))) {
  672. X            printf("%c%s", chSep, pc);
  673. X            chSep = ',';
  674. X        }
  675. X        printf("}\n");
  676. X    }
  677. X    printf("%s: dirs: owner=%-16s group=%-16s mode=%-12s\n", progname, apcModes[DIROWNER], apcModes[DIRGROUP], apcModes[DIRMODE]);
  678. X    printf("%s: page: owner=%-16s group=%-16s mode=%-12s\n", progname, apcModes[PAGEOWNER], apcModes[PAGEGROUP], apcModes[PAGEMODE]);
  679. X    printf("%s: what: owner=%-16s group=%-16s mode=%-12s\n", progname, apcModes[WHATISOWNER], apcModes[WHATISGROUP], apcModes[WHATISMODE]);
  680. X    printf("%s:  man: owner=%-16s group=%-16s mode=%-12s\n", progname, apcModes[MANOWNER], apcModes[MANGROUP], apcModes[MANMODE]);
  681. X    if (fSeeInstall) {
  682. X        printf("%s: use install -V to see install\'s defaults\n", progname);
  683. X    }
  684. X    if (fVerbose) {
  685. X        printf("%s", copyright);
  686. X    }
  687. }
  688. X
  689. X
  690. /*
  691. X * build an instck(1L) list for this manual system from mkcat-opts    (ksb)
  692. X */
  693. void
  694. doGen()
  695. {
  696. X    register int i;
  697. X    auto char acPat[MAXPATHLEN+2];
  698. X    static char acFmt[] = "%-31s %-17s %-11s %-11s -\n";
  699. X    static char acQuote[] = "\"";
  700. X
  701. X    for (i = 0; i < MAXMODE+1; ++i) {
  702. X        if ((char *)0 == apcModes[i]) {
  703. X            apcModes[i] = "*";
  704. X        }
  705. X    }
  706. X    printf("# instck list machine generated by mkcat\n");
  707. X    /* handle all the dirs we can build
  708. X     */
  709. X    printf(acFmt, pcRoot, apcModes[DIRMODE], apcModes[DIROWNER], apcModes[DIRGROUP]);
  710. X    sprintf(acPat, "%s/%s", pcRoot, "OLD");
  711. X    printf(acFmt, acPat, acQuote, acQuote, acQuote);
  712. X    if ('/' == pcCat[0] || ('.' == pcCat[0] && '/' == pcCat[1]))
  713. X        sprintf(acPat, "%s*", pcCat);
  714. X    else
  715. X        sprintf(acPat, "%s/%s*", pcRoot, pcCat);
  716. X    printf(acFmt, acPat, acQuote, acQuote, acQuote);
  717. X    (void)strcat(acPat, "/OLD");
  718. X    printf(acFmt, acPat, acQuote, acQuote, acQuote);
  719. X    if (HAVE_A(pcMan)) {
  720. X        if ('/' == pcMan[0] || ('.' == pcMan[0] && '/' == pcMan[1]))
  721. X            sprintf(acPat, "%s*", pcMan);
  722. X        else
  723. X            sprintf(acPat, "%s/%s*", pcRoot, pcMan);
  724. X        printf(acFmt, acPat, acQuote, acQuote, acQuote);
  725. X        (void)strcat(acPat, "/OLD");
  726. X        printf(acFmt, acPat, acQuote, acQuote, acQuote);
  727. X    }
  728. X    /* now do all the files
  729. X     */
  730. X    if ('/' == pcWhatis[0] || ('.' == pcWhatis[0] && '/' == pcWhatis[1]))
  731. X        sprintf(acPat, "%s*", pcWhatis);
  732. X    else
  733. X        sprintf(acPat, "%s/%s", pcRoot, pcWhatis);
  734. X    printf(acFmt, acPat, apcModes[WHATISMODE], apcModes[WHATISOWNER], apcModes[WHATISGROUP]);
  735. X    if ('/' == pcCat[0] || ('.' == pcCat[0] && '/' == pcCat[1]))
  736. X        sprintf(acPat, "%s*/*", pcCat);
  737. X    else
  738. X        sprintf(acPat, "%s/%s*/*", pcRoot, pcCat);
  739. X    printf(acFmt, acPat, apcModes[PAGEMODE], apcModes[PAGEOWNER], apcModes[PAGEGROUP]);
  740. X    if (HAVE_A(pcMan)) {
  741. X        if ('/' == pcMan[0] || ('.' == pcMan[0] && '/' == pcMan[1]))
  742. X            sprintf(acPat, "%s*/*", pcMan);
  743. X        else
  744. X            sprintf(acPat, "%s/%s*/*", pcRoot, pcMan);
  745. X        printf(acFmt, acPat, apcModes[MANMODE], apcModes[MANOWNER], apcModes[MANGROUP]);
  746. X    }
  747. }
  748. X
  749. extern int alphasort();
  750. X
  751. /*
  752. X * sync the whatis db with the cat pages                (ksb)
  753. X */
  754. static int
  755. doOthers(argc, argv)
  756. int argc;
  757. char **argv;
  758. {
  759. X    static char acDir[] = ".";
  760. X    register struct direct *pEnt;
  761. X    register int i, ndir;
  762. X    auto int iErrors, *piCounts;
  763. X    auto struct direct **ppDECats;
  764. X    auto WHATIS **ppWU;
  765. X
  766. X    if (fVerbose) {
  767. X        fprintf(fpOut, "%s: cd %s\n", progname, pcRoot);
  768. X    }
  769. X    if (-1 == chdir(pcRoot)) {
  770. X        fprintf(stderr, "%s: chdir: %s: %s\n", progname, pcRoot, strerror(errno));
  771. X        return 0;
  772. X    }
  773. X
  774. X    if (-1 == (ndir = scandir(acDir, & ppDECats, rootSelect, alphasort))) {
  775. X        fprintf(stderr, "%s: scandir: %s: %s\n", progname, acDir, strerror(errno));
  776. X        return 0;
  777. X    }
  778. X
  779. X    if (0 == ndir) {
  780. X        fprintf(fpOut, "%s: no cat directories?\n", progname);
  781. X        return 0;
  782. X    }
  783. X
  784. X    if (0 == (ppWU = (WHATIS **)malloc((unsigned)sizeof(WHATIS *)*ndir))) {
  785. X        fprintf(stderr, acNoMem, progname);
  786. X        return 0;
  787. X    }
  788. X    if (0 == (piCounts = (int *)malloc((unsigned)sizeof(int)*ndir))) {
  789. X        fprintf(stderr, acNoMem, progname);
  790. X        return 0;
  791. X    }
  792. X
  793. X    iErrors = 0;
  794. X    for (i = 0; i < ndir; ++i) {
  795. X        pEnt = ppDECats[i];
  796. X        if (-1 == chdir(pEnt->d_name)) {
  797. X            fprintf(stderr, "%s: chdir: %s: %s\n", progname, pEnt->d_name, strerror(errno));
  798. X            continue;
  799. X        }
  800. X        if (! AllDir(atoi(pEnt->d_name+strlen(pcCat)), ppWU+i, piCounts+i)) {
  801. X            ++iErrors;
  802. X        }
  803. X        if (fCkAlso) {
  804. X            AlsoScan(ppWU[i], piCounts[i]);
  805. X        }
  806. X        /* if the .. pointer is missing come in from above
  807. X         * you know, I hope this never happens!
  808. X         */
  809. X        if (-1 == chdir("..") && -1 == chdir(pcRoot)) {
  810. X            fprintf(stderr, "%s: chdir: %s: %s\n", progname, pcRoot, strerror(errno));
  811. X            exit(1);
  812. X        }
  813. X    }
  814. X    if (fMkWhatis) {
  815. X        (void)NewWhatis(ndir, ppWU, piCounts);
  816. X    }
  817. X    return iErrors;
  818. }
  819. X
  820. /*
  821. X * make a directory via install(1L)                    (ksb)
  822. X */
  823. void
  824. MakeDir(pcDir, wOwner, wGroup, wMode)
  825. char *pcDir;
  826. int wOwner, wGroup, wMode;
  827. {
  828. X    auto char acCmd[2*MAXPATHLEN+1];
  829. X
  830. X    (void)sprintf(acCmd, "INSTALL=\"%s\" install -d", fVerbose ? "-v" : "");
  831. X    if ((char *)0 != apcModes[wOwner]) {
  832. X        (void)strcat(acCmd, " -o");
  833. X        (void)strcat(acCmd, apcModes[wOwner]);
  834. X    }
  835. X    if ((char *)0 != apcModes[wGroup]) {
  836. X        (void)strcat(acCmd, " -g");
  837. X        (void)strcat(acCmd, apcModes[wGroup]);
  838. X    }
  839. X    if ((char *)0 != apcModes[wMode]) {
  840. X        (void)strcat(acCmd, " -m");
  841. X        (void)strcat(acCmd, apcModes[wMode]);
  842. X    }
  843. X    (void)strcat(acCmd, " ");
  844. X    (void)strcat(acCmd, pcDir);
  845. X    if (fVerbose) {
  846. X        fprintf(fpOut, "%s: %s\n", progname, acCmd);
  847. X    }
  848. X    (void)fflush(fpOut);
  849. X    if (fExec && 0 != system(acCmd)) {
  850. X        fprintf(stderr, "%s: install -d %s failed\n", progname, pcDir);
  851. X    }
  852. }
  853. X
  854. /*
  855. X * use pcDest = NIL and pcFlags = "-R" for deinstall file        (ksb)
  856. X */
  857. void
  858. InstFile(pcSrc, pcDest, wOwner, wGroup, wMode, pcFlags)
  859. char *pcSrc, *pcDest, *pcFlags;
  860. int wOwner, wGroup, wMode;
  861. {
  862. X    auto char acCmd[MAXPATHLEN*2+104];
  863. X
  864. X    sprintf(acCmd, "INSTALL=\"%s\" install", fVerbose ? "-v" : "");
  865. X    if ((char *)0 != pcFlags) {
  866. X        (void)strcat(acCmd, " ");
  867. X        (void)strcat(acCmd, pcFlags);
  868. X    }
  869. X    if ((char *)0 != apcModes[wOwner]) {
  870. X        (void)strcat(acCmd, " -o");
  871. X        (void)strcat(acCmd, apcModes[wOwner]);
  872. X    }
  873. X    if ((char *)0 != apcModes[wGroup]) {
  874. X        (void)strcat(acCmd, " -g");
  875. X        (void)strcat(acCmd, apcModes[wGroup]);
  876. X    }
  877. X    if ((char *)0 != apcModes[wMode]) {
  878. X        (void)strcat(acCmd, " -m");
  879. X        (void)strcat(acCmd, apcModes[wMode]);
  880. X    }
  881. X    (void)strcat(acCmd, " ");
  882. X    (void)strcat(acCmd, pcSrc);
  883. X    if ((char *)0 != pcDest) {
  884. X        (void)strcat(acCmd, " ");
  885. X        (void)strcat(acCmd, pcDest);
  886. X    }
  887. X    if (fVerbose) {
  888. X        fprintf(fpOut, "%s: %s\n", progname, acCmd);
  889. X    }
  890. X    (void)fflush(fpOut);
  891. X    if (fExec && 0 != system(acCmd)) {
  892. X        fprintf(stderr, "%s: install %s failed\n", progname, pcSrc);
  893. X    }
  894. }
  895. X
  896. /*
  897. X * get the words of wisdom from the user                (ksb)
  898. X * strip leading white space, etc
  899. X */
  900. char *
  901. GetWord(pcBuf, iLen, pcDef)
  902. char *pcBuf, *pcDef;
  903. int iLen;
  904. {
  905. X    register char *pcWhite, *pcCopy;
  906. X    register int l;
  907. X
  908. X    (void)fflush(stdout);
  909. X    pcBuf[0] = '\n';
  910. X    if ((char *)0 == fgets(pcBuf, iLen, stdin))
  911. X        return (char *)0;
  912. X    pcWhite = pcBuf;
  913. X    while (isspace(*pcWhite) && '\n' != *pcWhite)
  914. X        ++pcWhite;
  915. X
  916. X    pcCopy = pcBuf;
  917. X    l = iLen;
  918. X    while (l-- > 0 && '\n' != (*pcCopy = *pcWhite))
  919. X        ++pcCopy, ++pcWhite;
  920. X
  921. X    if (pcCopy == pcBuf)
  922. X        (void)strncpy(pcBuf, pcDef, iLen);
  923. X    else
  924. X        *pcCopy = '\000';
  925. X    return pcBuf;
  926. }
  927. X
  928. /*
  929. X * edit the modes we have, let the user pick'm                (ksb)
  930. X * this could be done better, but what the heck.
  931. X */
  932. void
  933. EditModes(wOwner, wGroup, wMode, pcWhat)
  934. int wOwner, wGroup, wMode;
  935. char *pcWhat;
  936. {
  937. #define MAXOGM    128        /* max owner, group, or mode length    */
  938. X    static char acNotSet[] = "-";
  939. X    auto char acMode[MAXOGM+1];
  940. X    register char *pcDef;
  941. X
  942. X    for (;;) {
  943. X        pcDef = apcModes[wOwner];
  944. X        if ((char *)0 == pcDef)
  945. X            pcDef = acNotSet;
  946. X        printf("Owner for %s? [%s] ", pcWhat, pcDef);
  947. X        if ((char *)0 == GetWord(acMode, MAXOGM, pcDef)) {
  948. X            exit(0);
  949. X        }
  950. X        switch (acMode[0]) {
  951. X        case '-':
  952. X            apcModes[wOwner] = (char *)0;
  953. X            break;
  954. X        default:
  955. X            if ((struct passwd *)0 == getpwnam(acMode)) {
  956. X                fprintf(stderr, "%s: %s: unknown login name\n", progname, acMode);
  957. X                continue;
  958. X            }
  959. X            apcModes[wOwner] = strsave(acMode);
  960. X            break;
  961. X        }
  962. X        break;
  963. X    }
  964. X    for (;;) {
  965. X        pcDef = apcModes[wGroup];
  966. X        if ((char *)0 == pcDef)
  967. X            pcDef = acNotSet;
  968. X        printf("Group for %s? [%s] ", pcWhat, pcDef);
  969. X        if ((char *)0 == GetWord(acMode, MAXOGM, pcDef)) {
  970. X            exit(0);
  971. X        }
  972. X        switch (acMode[0]) {
  973. X        case '-':
  974. X            apcModes[wGroup] = (char *)0;
  975. X            break;
  976. X        default:
  977. X            if ((struct group *)0 == getgrnam(acMode)) {
  978. X                fprintf(stderr, "%s: %s: unknown group name\n", progname, acMode);
  979. X                continue;
  980. X            }
  981. X            apcModes[wGroup] = strsave(acMode);
  982. X            break;
  983. X        }
  984. X        break;
  985. X    }
  986. X    for (;;) {
  987. X        pcDef = apcModes[wMode];
  988. X        if ((char *)0 == pcDef)
  989. X            pcDef = acNotSet;
  990. X        printf("Mode for %s? [%s] ", pcWhat, pcDef);
  991. X        if ((char *)0 == GetWord(acMode, MAXOGM, pcDef)) {
  992. X            exit(0);
  993. X        }
  994. X        switch (acMode[0]) {
  995. X        case '-':
  996. X            apcModes[wMode] = (char *)0;
  997. X            break;
  998. X        default:
  999. X            /* ZZZ we should check to see if this is a mode,
  1000. X             * but that could be hard, as install takes about
  1001. X             * 400 mode forms... (hehheh) [ksb]
  1002. X             */
  1003. X            apcModes[wMode] = strsave(acMode);
  1004. X            break;
  1005. X        }
  1006. X        break;
  1007. X    }
  1008. }
  1009. X
  1010. static char acEditBlurb[] =
  1011. X    "Use a dash (-) to select install\'s default\n";
  1012. X
  1013. /*
  1014. X * ask the user how to setup the mkcat-opts file            (ksb)
  1015. X */
  1016. int
  1017. doInit()
  1018. {
  1019. #define MAXANS    80
  1020. X    register LIST *pLI;
  1021. X    auto char chSep, *pc;
  1022. X    auto struct stat stDir;
  1023. X    auto char acAns[MAXANS+1];
  1024. X    auto char acConfig[MAXPATHLEN+1];
  1025. X    static char acDefMan[MAXPATHLEN+1];    /* returned in a global */
  1026. X    auto char acTCnf[MAXPATHLEN+1];        /* temp configuration    */
  1027. X    auto FILE *fpOpts;
  1028. X    auto char *pcUser;
  1029. X    auto int fOldCompress, fOldUseHards, fNew, fDidDir;
  1030. X    extern char *getenv(), **environ;
  1031. X
  1032. X    fDidDir = 0;
  1033. X    fNew = 1;
  1034. X    printf("\nBuilding `%s' in manual root `%s'\n", acOpts, pcRoot);
  1035. X
  1036. X    /* build the man dir if it isn't there and we can
  1037. X     */
  1038. X    if (-1 == stat(pcRoot, & stDir)) {
  1039. X        if (ENOENT != errno) {
  1040. X            fprintf(stderr, "%s: stat: %s: %s\n", progname, pcRoot, strerror(errno));
  1041. X            exit(1);
  1042. X        }
  1043. X        for (;;) {
  1044. X            printf("\nBuild `%s\' [yn] ", pcRoot);
  1045. X            if ((char *)0 == GetWord(acAns, MAXANS, "yes"))
  1046. X                exit(0);
  1047. X            switch (acAns[0]) {
  1048. X            case 'q':
  1049. X            case 'Q':
  1050. X            case 'N':
  1051. X            case 'n':
  1052. X                exit(0);
  1053. X            case 'y':
  1054. X            case 'Y':
  1055. X                printf("%s\n", acEditBlurb);
  1056. X                EditModes(DIROWNER, DIRGROUP, DIRMODE, "all directories");
  1057. X                fDidDir = 1;
  1058. X                break;
  1059. X            default:
  1060. X                continue;
  1061. X            }
  1062. X            break;
  1063. X        }
  1064. X        MakeDir(pcRoot, DIROWNER, DIRGROUP, DIRMODE);
  1065. X    }
  1066. X
  1067. X    /* read the existing options file if it is there and that is OK
  1068. X     */
  1069. X    sprintf(acConfig, "%s/%s", pcRoot, acOpts);
  1070. X    /* at least set up minimal stuff */
  1071. X    srtinit(& STBase);
  1072. X    pLIExt = (LIST *)0;
  1073. X    if (-1 != access(acConfig, 0)) {
  1074. X        for (;;) {
  1075. X            printf("\nRead existing `%s\' [yn] ", acConfig);
  1076. X            if ((char *)0 == GetWord(acAns, MAXANS, "yes"))
  1077. X                exit(0);
  1078. X            switch (acAns[0]) {
  1079. X            case 'q':
  1080. X            case 'Q':
  1081. X                exit(0);
  1082. X            case 'N':
  1083. X            case 'n':
  1084. X                break;
  1085. X            case 'y':
  1086. X            case 'Y':
  1087. X                PrepInfo();
  1088. X                fNew = 0;
  1089. X                break;
  1090. X            default:
  1091. X                continue;
  1092. X            }
  1093. X            break;
  1094. X        }
  1095. X    } else {
  1096. X        srtin(&STBase, "intro", strcmp);
  1097. X        apcModes[PAGEMODE] = "0644";
  1098. X        apcModes[WHATISMODE] = "0644";
  1099. X        apcModes[MANMODE] = "0444";
  1100. X    }
  1101. X
  1102. X    fOldCompress = fCompress;
  1103. X    fOldUseHards = fUseHards;
  1104. X    /* ask about the compress/links options
  1105. X     */
  1106. X    for (;;) {
  1107. X        printf("\nShould fomatted pages be kept compressed? [%s] ", fCompress ? "yn" : "ny");
  1108. X        if ((char *)0 == GetWord(acAns, MAXANS, fCompress ? "yes" : "no"))
  1109. X            exit(0);
  1110. X        switch (acAns[0]) {
  1111. X        case 'q':
  1112. X        case 'Q':
  1113. X            exit(0);
  1114. X        case 'N':
  1115. X        case 'n':
  1116. X            fCompress = 0;
  1117. X            break;
  1118. X        case 'y':
  1119. X        case 'Y':
  1120. X            fCompress = 1;
  1121. X            break;
  1122. X        default:
  1123. X            continue;
  1124. X        }
  1125. X        break;
  1126. X    }
  1127. X    for (;;) {
  1128. X        printf("\nShould extra links be symbolic or hard? [%s] ", fUseHards ? "HS" : "SH");
  1129. X        if ((char *)0 == GetWord(acAns, MAXANS, fUseHards ? "Hard" : "Symbolic"))
  1130. X            exit(0);
  1131. X        switch (acAns[0]) {
  1132. X        case 'q':
  1133. X        case 'Q':
  1134. X            exit(0);
  1135. X        case 'H':
  1136. X        case 'h':
  1137. X            fUseHards = 1;
  1138. X            break;
  1139. X        case 'S':
  1140. X        case 's':
  1141. X            fUseHards = 0;
  1142. X            break;
  1143. X        default:
  1144. X            continue;
  1145. X        }
  1146. X        break;
  1147. X    }
  1148. X
  1149. X    /* should we auto-save manual source?
  1150. X     */
  1151. X    for (;;) {
  1152. X        printf("\nKeep all manual source files? [%s] ", HAVE_A(pcMan)? "yn" : "ny");
  1153. X        if ((char *)0 == GetWord(acAns, MAXANS, HAVE_A(pcMan) ? "yes" : "no"))
  1154. X            exit(0);
  1155. X        switch (acAns[0]) {
  1156. X        case 'q':
  1157. X        case 'Q':
  1158. X            exit(0);
  1159. X        case 'N':
  1160. X        case 'n':
  1161. X            pcMan = (char *)0;
  1162. X            break;
  1163. X        case 'y':
  1164. X        case 'Y':
  1165. X            if ((char *)0 == pcMan)
  1166. X                pcMan = "man";
  1167. X            printf("Prefix for saved manual directories? [%s] ", pcMan);
  1168. X            if ((char *)0 == GetWord(acDefMan, MAXPATHLEN, pcMan))
  1169. X                exit(0);
  1170. X            pcMan = acDefMan;
  1171. X            break;
  1172. X        default:
  1173. X            continue;
  1174. X        }
  1175. X        break;
  1176. X    }
  1177. X
  1178. X    /* ask about OK base names
  1179. X     */
  1180. X    printf("\nNames of pages that appear multiple times in a single section are common\nbasenames, like `intro\' (intro.3c, intro.3x,...)\n");
  1181. X    for (;;) {
  1182. X        auto char acBase[MAXPATHLEN+1];
  1183. X
  1184. X        srtgti(& STBase);
  1185. X        if ((char *)0 != (pc = srtgets(& STBase))) {
  1186. X            printf("These are the current common basenames:\n");
  1187. X            do
  1188. X                printf("\t%s\n", pc);
  1189. X            while ((char *)0 != (pc = srtgets(& STBase)));
  1190. X        } else {
  1191. X            printf("There are no current common basenames for manual pages\n");
  1192. X        }
  1193. X        printf("\nAdd, Clear all, Delete, Exit? [EADC] ");
  1194. X        if ((char *)0 == GetWord(acAns, MAXANS, HAVE_A(pcMan) ? "yes" : "no"))
  1195. X            exit(0);
  1196. X        switch (acAns[0]) {
  1197. X        case 'q':
  1198. X        case 'Q':
  1199. X            exit(0);
  1200. X        case 'e':
  1201. X        case 'E':
  1202. X            break;
  1203. X        case 'c':
  1204. X        case 'C':
  1205. X            srtdtree(& STBase);
  1206. X            continue;
  1207. X        case 'D':
  1208. X        case 'A':
  1209. X            acAns[0] = tolower(acAns[0]);
  1210. X            /* fall through */
  1211. X        case 'd':
  1212. X        case 'a':
  1213. X            printf("Base to %s? [intro] ", 'a' == acAns[0] ? "add" : "delete");
  1214. X            if ((char *)0 == GetWord(acBase, MAXPATHLEN, "intro"))
  1215. X                exit(0);
  1216. X            if ('a' == acAns[0]) {
  1217. X                if (NULL == srtin(&STBase, acBase, strcmp)) {
  1218. X                    printf("Out of memory?\n");
  1219. X                    exit(2);
  1220. X                }
  1221. X                continue;
  1222. X            }
  1223. X            if (!srtdel(&STBase, acBase, strcmp)) {
  1224. X                printf("Base `%s\' not found\n", acBase);
  1225. X            }
  1226. X            continue;
  1227. X        }
  1228. X        break;
  1229. X    }
  1230. X
  1231. X    /* ask about modes */
  1232. X    printf("\n%s\n", acEditBlurb);
  1233. X    if (!fDidDir) {
  1234. X        EditModes(DIROWNER, DIRGROUP, DIRMODE, "all directories");
  1235. X    }
  1236. X    if ((char *)0 != apcModes[DIROWNER] && (char *)0 == apcModes[PAGEOWNER])
  1237. X        apcModes[PAGEOWNER] = apcModes[DIROWNER];
  1238. X    if ((char *)0 != apcModes[DIRGROUP] && (char *)0 == apcModes[PAGEGROUP])
  1239. X        apcModes[PAGEGROUP] = apcModes[DIRGROUP];
  1240. X    EditModes(PAGEOWNER, PAGEGROUP, PAGEMODE, "cat pages");
  1241. X
  1242. X    if ((char *)0 != apcModes[PAGEOWNER] && (char *)0 == apcModes[WHATISOWNER])
  1243. X        apcModes[WHATISOWNER] = apcModes[PAGEOWNER];
  1244. X    if ((char *)0 != apcModes[PAGEGROUP] && (char *)0 == apcModes[WHATISGROUP])
  1245. X        apcModes[WHATISGROUP] = apcModes[PAGEGROUP];
  1246. X    EditModes(WHATISOWNER, WHATISGROUP, WHATISMODE, "the whatis database");
  1247. X
  1248. X    if (HAVE_A(pcMan)) {
  1249. X        EditModes(MANOWNER, MANGROUP, MANMODE, "saved manual sources");
  1250. X    }
  1251. X
  1252. X    /* ask about OK extensions ZZZ */
  1253. X
  1254. X    /* write what we have */
  1255. X    for (;;) {
  1256. X        printf("\nInstall this configuration in %s? [yn] ", acConfig);
  1257. X        if ((char *)0 == GetWord(acAns, MAXANS, "yes"))
  1258. X            exit(0);
  1259. X        switch (acAns[0]) {
  1260. X        case 'q':
  1261. X        case 'Q':
  1262. X        case 'N':
  1263. X        case 'n':
  1264. X            exit(0);
  1265. X        case 'y':
  1266. X        case 'Y':
  1267. X            break;
  1268. X        default:
  1269. X            continue;
  1270. X        }
  1271. X        break;
  1272. X    }
  1273. X    (void)strcpy(acTCnf, "/tmp/catcnfXXXXXX");
  1274. X    if ((char *)0 == mktemp(acTCnf)) {
  1275. X        fprintf(stderr, "%s: mktemp: %s\n", progname, acTCnf);
  1276. X        exit(3);
  1277. X    }
  1278. X    if (NULL == (fpOpts = fopen(acTCnf, "w"))) {
  1279. X        fprintf(stderr, "%s: fopen: %s: %s\n", progname, acConfig, strerror(errno));
  1280. X        exit(2);
  1281. X    }
  1282. X    pcUser = getenv("USER");
  1283. X    if ((char *)0 == pcUser || '\000' == pcUser[0]) {
  1284. X        pcUser = getenv("LOGNAME");
  1285. X    }
  1286. X    if ((char *)0 == pcUser || '\000' == pcUser[0]) {
  1287. X        pcUser = "an unknown user";
  1288. X    }
  1289. X
  1290. X    fprintf(fpOpts, "# mkcat options updated by %s\n", pcUser);
  1291. X    fprintf(fpOpts, "compress: %c\nlinks: %c\n",
  1292. X        fCompress ? 'y' : 'n',
  1293. X        fUseHards ? 'H' : 'S');
  1294. X    if (HAVE_A(pcMan)) {
  1295. X        fprintf(fpOpts, "man: %s\n", pcMan);
  1296. X    }
  1297. X    fprintf(fpOpts, "# Add {page,dir,man,whatis}{mode,owner,group}: value\n");
  1298. X    {    static char *apcHead[4], *apcTail[3];
  1299. X        register int t;
  1300. X
  1301. X        /* This code keeps #define renumberings from hurting us
  1302. X         * (have care here, the ice can be thin).
  1303. X         */
  1304. X        apcHead[PAGEOWNER/3] = acPKey;
  1305. X        apcHead[DIROWNER/3] = acDKey;
  1306. X        apcHead[WHATISOWNER/3] = acWKey;
  1307. X        apcHead[MANOWNER/3] = acNKey;
  1308. X        /* see which order stats are kept
  1309. X         */
  1310. X        t = DIROWNER < DIRMODE && DIROWNER < DIRGROUP ?
  1311. X            DIROWNER :
  1312. X            DIRMODE < DIRGROUP ?
  1313. X            DIRMODE : DIRGROUP;
  1314. X        apcTail[DIROWNER-t] = acOKey;
  1315. X        apcTail[DIRGROUP-t] = acGKey;
  1316. X        apcTail[DIRMODE-t] = acMKey;
  1317. X        for (t = 0; t < MAXMODE+1; ++t) {
  1318. X            if ((char *)0 == apcModes[t])
  1319. X                continue;
  1320. X            fprintf(fpOpts, "%s%s %s\n", apcHead[t/3], apcTail[t % 3], apcModes[t]);
  1321. X        }
  1322. X    }
  1323. X    fprintf(fpOpts, "# these base names may exist under all externders\n");
  1324. X    fprintf(fpOpts, "# like intro.3m, intro.3x, intro.3s, etc.\n");
  1325. X    srtgti(& STBase);
  1326. X    while ((char *)0 != (pc = srtgets(& STBase)))
  1327. X        fprintf(fpOpts, "%s %s\n", acBKey, pc);
  1328. X    fprintf(fpOpts, "# these extenders might have common basenames\n");
  1329. X    fprintf(fpOpts, "# e.g.: {3f,3s} for getc\n");
  1330. X    for (pLI = pLIExt; 0 != pLI; pLI = pLI->pLInext) {
  1331. X        fprintf(fpOpts, "%s ", acSKey);
  1332. X        chSep = '{';
  1333. X        srtgti(& pLI->STall);
  1334. X        while ((char *)0 != (pc = srtgets(& pLI->STall))) {
  1335. X            fprintf(fpOpts, "%c%s", chSep, pc);
  1336. X            chSep = ',';
  1337. X        }
  1338. X        fprintf(fpOpts, "}\n");
  1339. X    }
  1340. X    (void)fclose(fpOpts);
  1341. X
  1342. X    if (!CmpFile(acTCnf, acConfig)) {
  1343. X        InstFile(acTCnf, acConfig, WHATISOWNER, WHATISGROUP, WHATISMODE, (char *)0);
  1344. X    }
  1345. X
  1346. X    /* ask to build cat[1-9] */
  1347. X    if ((char *)0 != pcCat) {
  1348. X        auto char acNCat[MAXPATHLEN+2];
  1349. X        register int i;
  1350. X
  1351. X        for (i = 1; i < 10; ++i) {
  1352. X            if ('/' == pcCat[0] || ('.' == pcCat[0] && '/' == pcCat[1]))
  1353. X                (void)sprintf(acNCat, "%s%1d", pcCat, i);
  1354. X            else
  1355. X                (void)sprintf(acNCat, "%s/%s%1d", pcRoot, pcCat, i);
  1356. X            MakeDir(acNCat, DIROWNER, DIRGROUP, DIRMODE);
  1357. X        }
  1358. X    }
  1359. X    /* ask to build man[1-9] */
  1360. X    if (HAVE_A(pcMan)) {
  1361. X        auto char acNMan[MAXPATHLEN+2];
  1362. X        register int i;
  1363. X
  1364. X        for (i = 1; i < 10; ++i) {
  1365. X            if ('/' == pcMan[0] || ('.' == pcMan[0] && '/' == pcMan[1]))
  1366. X                (void)sprintf(acNMan, "%s%1d", pcMan, i);
  1367. X            else
  1368. X                (void)sprintf(acNMan, "%s/%s%1d", pcRoot, pcMan, i);
  1369. X            MakeDir(acNMan, DIROWNER, DIRGROUP, DIRMODE);
  1370. X        }
  1371. X    }
  1372. X    if (fNew || fCompress != fOldCompress) {
  1373. X        for (;;) {
  1374. X            printf("\nCompression flag changed! Use `%s -Z\' to restore order? [yn] ", progname);
  1375. X            if ((char *)0 == GetWord(acAns, MAXANS, "yes"))
  1376. X                exit(0);
  1377. X            switch (acAns[0]) {
  1378. X            case 'q':
  1379. X            case 'Q':
  1380. X                exit(0);
  1381. X            case 'N':
  1382. X            case 'n':
  1383. X                break;
  1384. X            case 'y':
  1385. X            case 'Y':
  1386. X                switch (fork()) {
  1387. X                case -1:
  1388. X                    fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
  1389. X                    break;
  1390. X                case 0:
  1391. X                    /* execlp(progname, "(mkcat)", fVerbose ? "-vL" : "-L", (char *)0); */
  1392. X                    fJustComp = 1;
  1393. X                    fUseHards = fOldUseHards;
  1394. X                    doOthers(0, &progname);
  1395. X                    exit(0);
  1396. X                default:
  1397. X                    break;
  1398. X                }
  1399. X                while (-1 != wait((int *)0))
  1400. X                    ;
  1401. X                break;
  1402. X            default:
  1403. X                continue;
  1404. X            }
  1405. X            break;
  1406. X        }
  1407. X    }
  1408. X    if (fNew || fUseHards != fOldUseHards) {
  1409. X        for (;;) {
  1410. X            printf("\nLink type changed! Use `%s -L\' to relink pages? [yn] ", progname);
  1411. X            if ((char *)0 == GetWord(acAns, MAXANS, "yes"))
  1412. X                exit(0);
  1413. X            switch (acAns[0]) {
  1414. X            case 'q':
  1415. X            case 'Q':
  1416. X                exit(0);
  1417. X            case 'N':
  1418. X            case 'n':
  1419. X                break;
  1420. X            case 'y':
  1421. X            case 'Y':
  1422. X                switch (fork()) {
  1423. X                case -1:
  1424. X                    fprintf(stderr, "%s: fork: %s\n", progname, strerror(errno));
  1425. X                    break;
  1426. X                case 0:
  1427. X                    /* execlp(progname, "(mkcat)", fVerbose ? "-vH" : "-H", (char *)0); */
  1428. X                    fMkLinks = 1;
  1429. X                    doOthers(0, &progname);
  1430. X                    exit(0);
  1431. X                default:
  1432. X                    break;
  1433. X                }
  1434. X                while (-1 != wait((int *)0))
  1435. X                    ;
  1436. X                break;
  1437. X            default:
  1438. X                continue;
  1439. X            }
  1440. X            break;
  1441. X        }
  1442. X    }
  1443. }
  1444. X
  1445. /*
  1446. X * mkcat -- install a manual page in the std place            (ksb)
  1447. X */
  1448. int
  1449. doMkCat(argc, argv)
  1450. int argc;
  1451. char **argv;
  1452. {
  1453. X    auto int iErrors, i;
  1454. X    auto WHATIS *pWUAdd, *pWUDel;
  1455. X    auto PATH *pPTNames;
  1456. X    auto char acDir[MAXPATHLEN+2];
  1457. X    auto struct stat stSrc, stDest;
  1458. X
  1459. X    (void)umask(0022);
  1460. X    if (fInitNew) {
  1461. X        doInit();
  1462. X        exit(0);
  1463. X    }
  1464. X
  1465. X    PrepInfo();
  1466. X
  1467. X    if (fVersion) {
  1468. X        doShowCfg();
  1469. X        exit(0);
  1470. X    }
  1471. X    if (fGenInstck) {
  1472. X        doGen();
  1473. X        exit(0);
  1474. X    }
  1475. X
  1476. X    fInstall |= !(fMkWhatis||fCkAlso||fMkLinks||fJustComp) && !fDelete;
  1477. X    if (!fInstall && !fDelete) {
  1478. X        exit(doOthers(argc, argv));
  1479. X    }
  1480. X    if (0 == argc) {
  1481. X        fprintf(stderr, "%s: missing pages (see -h)\n", progname);
  1482. X        exit(0);
  1483. X    }
  1484. X
  1485. X    iErrors = 0;
  1486. X    if ((PATH *)0 == (pPTNames = (PATH *)calloc((unsigned)argc+2, sizeof(PATH)))) {
  1487. X        fprintf(stderr, acNoMem, progname);
  1488. X        exit(1);
  1489. X    }
  1490. X    if ((WHATIS *)0 == (pWUAdd = (WHATIS *)calloc((unsigned)argc+2, sizeof(WHATIS)))) {
  1491. X        fprintf(stderr, acNoMem, progname);
  1492. X        exit(1);
  1493. X    }
  1494. X
  1495. X    if ((WHATIS *)0 == (pWUDel = (WHATIS *)calloc((unsigned)argc+2, sizeof(WHATIS)))) {
  1496. X        fprintf(stderr, acNoMem, progname);
  1497. X        exit(1);
  1498. X    }
  1499. X
  1500. X    /* format or read the pages and read the links out of them
  1501. X     */
  1502. X    for (i = 0; i < argc; ++i) {
  1503. X        PTInit(&pPTNames[i], argv[i]);
  1504. X        if (-1 == stat(argv[i], & stSrc)) {
  1505. X            fprintf(stderr, "%s: stat: %s: %s\n", progname, argv[i], strerror(errno));
  1506. X            continue;
  1507. X        }
  1508. X        iErrors += ModFmt(&pPTNames[i], &pWUAdd[i], &pWUDel[i]);
  1509. X
  1510. X        if (!HAVE_A(pcMan) || !fFormat) {
  1511. X            continue;
  1512. X        }
  1513. X
  1514. X        if ('/' == pcMan[0] || ('.' == pcMan[0] && '/' == pcMan[1])) {
  1515. X            sprintf(acDir, "%s%d", pcMan, pWUAdd[i].isection);
  1516. X        } else {
  1517. X            sprintf(acDir, "%s/%s%d", pcRoot, pcMan, pWUAdd[i].isection);
  1518. X        }
  1519. X        if (-1 == stat(acDir, &stDest)) {
  1520. X            MakeDir(acDir, DIROWNER, DIRGROUP, DIRMODE);
  1521. X        }
  1522. X
  1523. X        (void)strcat(acDir, "/");
  1524. X        (void)strcat(acDir, pWUAdd[i].pcbase);
  1525. X        (void)strcat(acDir, ".");
  1526. X        (void)strcat(acDir, pWUAdd[i].pcext);
  1527. X        if (-1 != stat(acDir, &stDest) && stDest.st_ino == stSrc.st_ino && stDest.st_dev == stSrc.st_dev) {
  1528. X            fprintf(stdout, "%s: given file is installed in %s\n", progname, acDir);
  1529. X            continue;
  1530. X        }
  1531. X        if (fDelete) {
  1532. X            InstFile(acDir, (char *)0, MANOWNER, MANGROUP, MANMODE, "-R");
  1533. X        } else {
  1534. X            InstFile(argv[i], acDir, MANOWNER, MANGROUP, MANMODE, "-c");
  1535. X        }
  1536. X    }
  1537. X
  1538. X    /* update the whatis database with all the pages
  1539. X     * (this wastes the complex data struct we just built)
  1540. X     */
  1541. X    if (argc - iErrors > 0) {
  1542. X        iErrors += ModWhatis(argc, pWUAdd, argc, pWUDel);
  1543. X    }
  1544. X
  1545. X    return iErrors;
  1546. }
  1547. Purdue
  1548. chmod 0444 mkcat/mkcat.c ||
  1549. echo 'restore of mkcat/mkcat.c failed'
  1550. Wc_c="`wc -c < 'mkcat/mkcat.c'`"
  1551. test 32072 -eq "$Wc_c" ||
  1552.     echo 'mkcat/mkcat.c: original size 32072, current size' "$Wc_c"
  1553. fi
  1554. true || echo 'restore of mk/mk.c failed'
  1555. echo End of part 1, continue with part 2
  1556. exit 0
  1557.  
  1558. exit 0 # Just in case...
  1559.