home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume11 / tcsh / part04 < prev    next >
Text File  |  1987-08-10  |  43KB  |  1,652 lines

  1. Path: uunet!rs
  2. From: rs@uunet.UU.NET (Rich Salz)
  3. Newsgroups: comp.sources.unix
  4. Subject: v10i004:  New version of T-shell, Part04/06
  5. Message-ID: <862@uunet.UU.NET>
  6. Date: 11 Aug 87 23:52:37 GMT
  7. Organization: UUNET Communications Services, Arlington, VA
  8. Lines: 1641
  9. Approved: rs@uunet.UU.NET
  10.  
  11. Submitted-by: Paul Placeway <pyramid!osu-eddie!paul>
  12. Posting-number: Volume 10, Issue 4
  13. Archive-name: tcsh/Part04
  14.  
  15. # This is a shell archive.  Remove anything before this line
  16. # then unpack it by saving it in a file and typing "sh file"
  17. # (Files unpacked will be owned by you and have default permissions).
  18. # This archive contains the following files:
  19. #    ./pwprintf.c
  20. #    ./nmalloc.c
  21. #    ./tw.h
  22. #    ./tw.help.c
  23. #    ./tw.init.c
  24. #    ./tw.parse.c
  25. #
  26. if `test ! -s ./pwprintf.c`
  27. then
  28. echo "writing ./pwprintf.c"
  29. sed 's/^x//' > ./pwprintf.c << '\Rogue\Monster\'
  30. x/* A public-domain, minimal printf routine that prints through the putchar()
  31. x   routine.  Feel free to use for anything...  -- 7/17/87 Paul Placeway */
  32. x
  33. x#include <ctype.h>
  34. x#include <varargs.h>
  35. x
  36. x/* use varargs since it's the RIGHT WAY, and assuming things about parameters
  37. x   on the stack will be wrong on a register passing machine (Pyramid) */
  38. x
  39. x#define INF    32766        /* should be bigger than any field to print */
  40. x
  41. xstatic char buf[128];
  42. x
  43. x/*VARARGS*/
  44. xprintf (va_alist)
  45. xva_dcl
  46. x{
  47. x    va_list ap;
  48. x    register char *f, *bp;
  49. x    register long l;
  50. x    register unsigned long u;
  51. x    register int i;
  52. x    register int fmt;
  53. x    register char pad = ' ';
  54. x    int flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
  55. x    int sign = 0;
  56. x
  57. x    va_start(ap);
  58. x    
  59. x    f = va_arg(ap, char *);
  60. x    for (; *f; f++) {
  61. x    if (*f != '%') {    /* then just out the char */
  62. x        putchar (*f);
  63. x    } else {
  64. x        f++;        /* skip the % */
  65. x
  66. x        if (*f == '-') {    /* minus: flush left */
  67. x        flush_left = 1;
  68. x        f++;
  69. x        }
  70. x
  71. x        if (*f == '0') {    /* padding with 0 rather than blank */
  72. x        pad = '0';
  73. x        f++;
  74. x        }
  75. x        if (*f == '*') {    /* field width */
  76. x        f_width = va_arg(ap, int);
  77. x        f++;
  78. x        } else if (isdigit(*f)) {
  79. x        f_width = atoi (f);
  80. x        while (isdigit(*f)) f++; /* skip the digits */
  81. x        }
  82. x       
  83. x        if (*f == '.') {    /* precision */
  84. x        f++;
  85. x        if (*f == '*') {
  86. x            prec = va_arg(ap, int);
  87. x            f++;
  88. x        } else if (isdigit(*f)) {
  89. x            prec = atoi (f);
  90. x            while (isdigit(*f)) f++; /* skip the digits */
  91. x        }
  92. x        }
  93. x
  94. x        if (*f == '#') {    /* alternate form */
  95. x        hash = 1;
  96. x        f++;
  97. x        }
  98. x
  99. x        if (*f == 'l') {    /* long format */
  100. x        do_long = 1;
  101. x        f++;
  102. x        }
  103. x
  104. x        fmt = *f;
  105. x        if (isupper(fmt)) {
  106. x        do_long = 1;
  107. x        fmt = tolower(fmt);
  108. x        }
  109. x        bp = buf;
  110. x        switch (fmt) {    /* do the format */
  111. x          case 'd':
  112. x        if (do_long)
  113. x            l = va_arg(ap, long);
  114. x        else
  115. x            l = (long) ( va_arg(ap, int) );
  116. x        if (l < 0) {
  117. x            sign = 1;            
  118. x            l = -l;
  119. x        }
  120. x        do {
  121. x            *bp++ = l % 10 + '0';
  122. x        } while ((l /= 10) > 0);
  123. x        if (sign)
  124. x            *bp++ = '-';
  125. x        f_width = f_width - (bp - buf);
  126. x        if (!flush_left)
  127. x            while (f_width-- > 0)
  128. x            putchar (pad);
  129. x        for (bp--; bp >= buf; bp--)
  130. x            putchar (*bp);
  131. x        if (flush_left)
  132. x            while (f_width-- > 0)
  133. x            putchar (' ');
  134. x        break;
  135. x
  136. x          case 'o':
  137. x          case 'x':
  138. x          case 'u':
  139. x        if (do_long)
  140. x            u = va_arg(ap, unsigned long);
  141. x        else
  142. x            u = (unsigned long) ( va_arg(ap, unsigned) );
  143. x        if (fmt == 'u') { /* unsigned decimal */
  144. x            do {
  145. x            *bp++ = u % 10 + '0';
  146. x            } while ((u /= 10) > 0);
  147. x        } else if (fmt == 'o') { /* octal */
  148. x            do {
  149. x            *bp++ = u % 8 + '0';
  150. x            } while ((u /= 8) > 0);
  151. x            if (hash)
  152. x            *bp++ = '0';
  153. x        } else if (fmt == 'x') { /* hex */
  154. x            do {
  155. x            i = u % 16;
  156. x            if (i < 10)
  157. x                *bp++ = i + '0';
  158. x            else
  159. x                *bp++ = i - 10 + 'a';
  160. x            } while ((u /= 16) > 0);
  161. x            if (hash) {
  162. x            *bp++ = 'x';
  163. x            *bp++ = '0';
  164. x            }
  165. x        }
  166. x        i = f_width - (bp - buf);
  167. x        if (!flush_left)
  168. x            while (i-- > 0)
  169. x            putchar (pad);
  170. x        for (bp--; bp >= buf; bp--)
  171. x            putchar (*bp);
  172. x        if (flush_left)
  173. x            while (i-- > 0)
  174. x            putchar (' ');
  175. x        break;
  176. x        
  177. x
  178. x          case 'c':
  179. x        i = va_arg(ap, int);
  180. x        putchar (i);
  181. x        break;
  182. x
  183. x          case 's':
  184. x        bp = va_arg(ap, char *);
  185. x        f_width = f_width - strlen(bp);
  186. x        if (!flush_left)
  187. x            while (f_width-- > 0)
  188. x            putchar (pad);
  189. x            for (i = 0; *bp && i < prec; i++) {
  190. x            putchar (*bp);
  191. x            bp++;
  192. x        }
  193. x        if (flush_left)
  194. x            while (f_width-- > 0)
  195. x            putchar (' ');
  196. x
  197. x        break;
  198. x
  199. x          case '%':
  200. x        putchar ('%');
  201. x        break;
  202. x        }
  203. x        flush_left = 0, f_width = 0, prec = INF, hash = 0, do_long = 0;
  204. x        sign = 0;
  205. x        pad = ' ';
  206. x    }
  207. x    }
  208. x    va_end(ap);
  209. x    return 0;
  210. x}
  211. \Rogue\Monster\
  212. else
  213.   echo "will not over write ./pwprintf.c"
  214. fi
  215. if [ `wc -c ./pwprintf.c | awk '{printf $1}'` -ne 3648 ]
  216. then
  217. echo `wc -c ./pwprintf.c | awk '{print "Got " $1 ", Expected " 3648}'`
  218. fi
  219. if `test ! -s ./nmalloc.c`
  220. then
  221. echo "writing ./nmalloc.c"
  222. sed 's/^x//' > ./nmalloc.c << '\Rogue\Monster\'
  223. xstatic char RCSid[] = "$Header: nmalloc.c,v 1.1 85/02/11 21:19:46 paul Exp $";
  224. x#define MSTATS
  225. x
  226. x/*
  227. x * malloc.c (Caltech) 2/21/82
  228. x * Chris Kingsley, kingsley@cit-20.
  229. x *
  230. x * This is a very fast storage allocator.  It allocates blocks of a small 
  231. x * number of different sizes, and keeps free lists of each size.  Blocks that
  232. x * don't exactly fit are passed up to the next larger size.  In this 
  233. x * implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
  234. x * This is designed for use in a program that uses vast quantities of memory,
  235. x * but bombs when it runs out. 
  236. x */
  237. x
  238. x#include <sys/types.h>
  239. x
  240. x#define    NULL 0
  241. x
  242. x/*
  243. x * The overhead on a block is at least 4 bytes.  When free, this space
  244. x * contains a pointer to the next free block, and the bottom two bits must
  245. x * be zero.  When in use, the first byte is set to MAGIC, and the second
  246. x * byte is the size index.  The remaining bytes are for alignment.
  247. x * If range checking is enabled and the size of the block fits
  248. x * in two bytes, then the top two bytes hold the size of the requested block
  249. x * plus the range checking words, and the header word MINUS ONE.
  250. x */
  251. xunion    overhead {
  252. x    union    overhead *ov_next;    /* when free */
  253. x    struct {
  254. x        u_char    ovu_magic;    /* magic number */
  255. x        u_char    ovu_index;    /* bucket # */
  256. x#ifdef RCHECK
  257. x        u_short    ovu_size;    /* actual block size */
  258. x        u_int    ovu_rmagic;    /* range magic number */
  259. x#endif
  260. x    } ovu;
  261. x#define    ov_magic    ovu.ovu_magic
  262. x#define    ov_index    ovu.ovu_index
  263. x#define    ov_size        ovu.ovu_size
  264. x#define    ov_rmagic    ovu.ovu_rmagic
  265. x};
  266. x
  267. x#define    MAGIC        0xff        /* magic # on accounting info */
  268. x#define RMAGIC        0x55555555    /* magic # on range info */
  269. x#ifdef RCHECK
  270. x#define    RSLOP        sizeof (u_int)
  271. x#else
  272. x#define    RSLOP        0
  273. x#endif
  274. x
  275. x/*
  276. x * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  277. x * smallest allocatable block is 8 bytes.  The overhead information
  278. x * precedes the data area returned to the user.
  279. x */
  280. x#define    NBUCKETS 30
  281. xstatic    union overhead *nextf[NBUCKETS];
  282. xextern    char *sbrk();
  283. xstatic char *memtop = NULL;    /* PWP: top of current memory */
  284. x
  285. x#ifdef MSTATS
  286. x/*
  287. x * nmalloc[i] is the difference between the number of mallocs and frees
  288. x * for a given block size.
  289. x */
  290. xstatic    u_int nmalloc[NBUCKETS];
  291. x#endif
  292. x
  293. x#include "sh.local.h"
  294. x#ifdef debug
  295. x#define    ASSERT(p)   if (!(p)) botch("p"); else
  296. xstatic
  297. xbotch(s)
  298. x    char *s;
  299. x{
  300. x
  301. x    printf("assertion botched: %s\n", s);
  302. x    abort();
  303. x}
  304. x#else
  305. x#define    ASSERT(p)
  306. x#endif
  307. x
  308. xchar *
  309. xmalloc(nbytes)
  310. x    register unsigned nbytes;
  311. x{
  312. x      register union overhead *p;
  313. x      register int bucket = 0;
  314. x      register unsigned shiftr;
  315. x
  316. x    /*
  317. x     * Convert amount of memory requested into
  318. x     * closest block size stored in hash buckets
  319. x     * which satisfies request.  Account for
  320. x     * space used per block for accounting.
  321. x     */
  322. x      nbytes += sizeof (union overhead) + RSLOP;
  323. x      nbytes = (nbytes + 3) &~ 3; 
  324. x      shiftr = (nbytes - 1) >> 2;
  325. x    /* apart from this loop, this is O(1) */
  326. x      while (shiftr >>= 1)
  327. x          bucket++;
  328. x    /*
  329. x     * If nothing in hash bucket right now,
  330. x     * request more memory from the system.
  331. x     */
  332. x      if (nextf[bucket] == NULL)    
  333. x          morecore(bucket);
  334. x      if ((p = (union overhead *)nextf[bucket]) == NULL)
  335. x          return (NULL);
  336. x    /* remove from linked list */
  337. x      nextf[bucket] = nextf[bucket]->ov_next;
  338. x    p->ov_magic = MAGIC;
  339. x    p->ov_index= bucket;
  340. x#ifdef MSTATS
  341. x      nmalloc[bucket]++;
  342. x#endif
  343. x#ifdef RCHECK
  344. x    /*
  345. x     * Record allocated size of block and
  346. x     * bound space with magic numbers.
  347. x     */
  348. x      if (nbytes <= 0x10000)
  349. x        p->ov_size = nbytes - 1;
  350. x    p->ov_rmagic = RMAGIC;
  351. x      *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
  352. x#endif
  353. x      return ((char *)(p + 1));
  354. x}
  355. x
  356. x/*
  357. x * Allocate more memory to the indicated bucket.
  358. x */
  359. xstatic
  360. xmorecore(bucket)
  361. x    register bucket;
  362. x{
  363. x      register union overhead *op;
  364. x      register int rnu;       /* 2^rnu bytes will be requested */
  365. x      register int nblks;     /* become nblks blocks of the desired size */
  366. x    register int siz;
  367. x
  368. x      if (nextf[bucket])
  369. x          return;
  370. x    /*
  371. x     * Insure memory is allocated
  372. x     * on a page boundary.  Should
  373. x     * make getpageize call?
  374. x     */
  375. x      op = (union overhead *)sbrk(0);
  376. x    memtop = (char *) op;    /* PWP */
  377. x      if ((int)op & 0x3ff) {
  378. x          memtop = sbrk(1024 - ((int)op & 0x3ff)); /* PWP */
  379. x        memtop += 1024 - ((int)op & 0x3ff);
  380. x    }
  381. x    /* take 2k unless the block is bigger than that */
  382. x      rnu = (bucket <= 8) ? 11 : bucket + 3;
  383. x      nblks = 1 << (rnu - (bucket + 3));  /* how many blocks to get */
  384. x      if (rnu < bucket)
  385. x        rnu = bucket;
  386. x    memtop = sbrk(1 << rnu); /* PWP */
  387. x    op = (union overhead *) memtop;
  388. x    memtop += 1 << rnu;
  389. x    /* no more room! */
  390. x      if ((int)op == -1)
  391. x          return;
  392. x    /*
  393. x     * Round up to minimum allocation size boundary
  394. x     * and deduct from block count to reflect.
  395. x     */
  396. x      if ((int)op & 7) {
  397. x          op = (union overhead *)(((int)op + 8) &~ 7);
  398. x          nblks--;
  399. x      }
  400. x    /*
  401. x     * Add new memory allocated to that on
  402. x     * free list for this hash bucket.
  403. x     */
  404. x      nextf[bucket] = op;
  405. x      siz = 1 << (bucket + 3);
  406. x      while (--nblks > 0) {
  407. x        op->ov_next = (union overhead *)((caddr_t)op + siz);
  408. x        op = (union overhead *)((caddr_t)op + siz);
  409. x      }
  410. x}
  411. x
  412. xfree(cp)
  413. x    char *cp;
  414. x{   
  415. x      register int size;
  416. x    register union overhead *op;
  417. x
  418. x      if (cp == NULL)
  419. x          return;
  420. x    if (cp > memtop) {
  421. x        /* printf ("free(%lx) above top of memory: %lx\n", cp, memtop); */
  422. x        return;
  423. x    }
  424. x
  425. x    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  426. x#ifdef debug
  427. x/*      ASSERT(op->ov_magic == MAGIC);        /* make sure it was in use */
  428. x#else
  429. x    if (op->ov_magic != MAGIC)
  430. x        return;                /* sanity */
  431. x#endif
  432. x#ifdef RCHECK
  433. x      ASSERT(op->ov_rmagic == RMAGIC);
  434. x    if (op->ov_index <= 13)
  435. x        ASSERT(*(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC);
  436. x#endif
  437. x      ASSERT(op->ov_index < NBUCKETS);
  438. x      size = op->ov_index;
  439. x    op->ov_next = nextf[size];
  440. x      nextf[size] = op;
  441. x#ifdef MSTATS
  442. x      nmalloc[size]--;
  443. x#endif
  444. x}
  445. x
  446. x/*
  447. x * When a program attempts "storage compaction" as mentioned in the
  448. x * old malloc man page, it realloc's an already freed block.  Usually
  449. x * this is the last block it freed; occasionally it might be farther
  450. x * back.  We have to search all the free lists for the block in order
  451. x * to determine its bucket: 1st we make one pass thru the lists
  452. x * checking only the first block in each; if that fails we search
  453. x * ``realloc_srchlen'' blocks in each list for a match (the variable
  454. x * is extern so the caller can modify it).  If that fails we just copy
  455. x * however many bytes was given to realloc() and hope it's not huge.
  456. x */
  457. xint realloc_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
  458. x
  459. xchar *
  460. xrealloc(cp, nbytes)
  461. x    char *cp; 
  462. x    unsigned nbytes;
  463. x{   
  464. x      register u_int onb;
  465. x    union overhead *op;
  466. x      char *res;
  467. x    register int i;
  468. x    int was_alloced = 0;
  469. x
  470. x      if (cp == NULL)
  471. x          return (malloc(nbytes));
  472. x    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  473. x    if (op->ov_magic == MAGIC) {
  474. x        was_alloced++;
  475. x        i = op->ov_index;
  476. x    } else {
  477. x        /*
  478. x         * Already free, doing "compaction".
  479. x         *
  480. x         * Search for the old block of memory on the
  481. x         * free list.  First, check the most common
  482. x         * case (last element free'd), then (this failing)
  483. x         * the last ``realloc_srchlen'' items free'd.
  484. x         * If all lookups fail, then assume the size of
  485. x         * the memory block being realloc'd is the
  486. x         * smallest possible.
  487. x         */
  488. x        if ((i = findbucket(op, 1)) < 0 &&
  489. x            (i = findbucket(op, realloc_srchlen)) < 0)
  490. x            i = 0;
  491. x    }
  492. x    onb = (1 << (i + 3)) - sizeof (*op) - RSLOP;
  493. x    /* avoid the copy if same size block */
  494. x    if (was_alloced &&
  495. x        nbytes <= onb && nbytes > (onb >> 1) - sizeof(*op) - RSLOP)
  496. x        return(cp);
  497. x      if ((res = malloc(nbytes)) == NULL)
  498. x          return (NULL);
  499. x      if (cp != res)            /* common optimization */
  500. x        bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
  501. x      if (was_alloced)
  502. x        free(cp);
  503. x      return (res);
  504. x}
  505. x
  506. x/*
  507. x * Search ``srchlen'' elements of each free list for a block whose
  508. x * header starts at ``freep''.  If srchlen is -1 search the whole list.
  509. x * Return bucket number, or -1 if not found.
  510. x */
  511. xstatic
  512. xfindbucket(freep, srchlen)
  513. x    union overhead *freep;
  514. x    int srchlen;
  515. x{
  516. x    register union overhead *p;
  517. x    register int i, j;
  518. x
  519. x    for (i = 0; i < NBUCKETS; i++) {
  520. x        j = 0;
  521. x        for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
  522. x            if (p == freep)
  523. x                return (i);
  524. x            j++;
  525. x        }
  526. x    }
  527. x    return (-1);
  528. x}
  529. x
  530. x#ifdef MSTATS
  531. x/*
  532. x * mstats - print out statistics about malloc
  533. x * 
  534. x * Prints two lines of numbers, one showing the length of the free list
  535. x * for each size category, the second showing the number of mallocs -
  536. x * frees for each size category.
  537. x */
  538. xshowall(v)
  539. x    char **v;
  540. x{
  541. x      register int i, j;
  542. x      register union overhead *p;
  543. x      int totfree = 0,
  544. x      totused = 0;
  545. x
  546. x      printf("tcsh memory allocation statistics\nfree:\t");
  547. x      for (i = 0; i < NBUCKETS; i++) {
  548. x          for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
  549. x              ;
  550. x          printf(" %4d", j);
  551. x          totfree += j * (1 << (i + 3));
  552. x      }
  553. x      printf("\nused:\t");
  554. x      for (i = 0; i < NBUCKETS; i++) {
  555. x          printf(" %4d", nmalloc[i]);
  556. x          totused += nmalloc[i] * (1 << (i + 3));
  557. x      }
  558. x      printf("\n\tTotal in use: %d, total free: %d\n",
  559. x        totused, totfree);
  560. x}
  561. x#endif
  562. \Rogue\Monster\
  563. else
  564.   echo "will not over write ./nmalloc.c"
  565. fi
  566. if [ `wc -c ./nmalloc.c | awk '{printf $1}'` -ne 8882 ]
  567. then
  568. echo `wc -c ./nmalloc.c | awk '{print "Got " $1 ", Expected " 8882}'`
  569. fi
  570. if `test ! -s ./tw.h`
  571. then
  572. echo "writing ./tw.h"
  573. sed 's/^x//' > ./tw.h << '\Rogue\Monster\'
  574. x#ifdef MAKE_TWENEX
  575. x
  576. x#define FREE_ITEMS(items,num)\
  577. x{\
  578. x    sighold (SIGINT);\
  579. x    free_items (items,num);\
  580. x    items = NULL;\
  581. x    sigrelse (SIGINT);\
  582. x}
  583. x
  584. x#define FREE_DIR(fd)\
  585. x{\
  586. x    sighold (SIGINT);\
  587. x    closedir (fd);\
  588. x    fd = NULL;\
  589. x    sigrelse (SIGINT);\
  590. x}
  591. x
  592. x#define TRUE        1
  593. x#define FALSE        0
  594. x#define ON        1
  595. x#define OFF        0
  596. x#define FILSIZ        512        /* Max reasonable file name length */
  597. x#define ESC        '\033'
  598. x#define equal(a, b)    (strcmp(a, b) == 0)
  599. x
  600. x#define is_set(var)    adrof(var)
  601. x
  602. x#define BUILTINS    "/usr/local/lib/builtins/" /* fake builtin bin */
  603. x#define SEARCHLIST "HPATH"    /* Env. param for helpfile searchlist */
  604. x#define DEFAULTLIST ":/u0/osu/man/cat1:/u0/osu/man/cat8:/u0/osu/man/cat6:/usr/man/cat1:/usr/man/cat8:/usr/man/cat6:/u0/local/man/cat1:/u0/local/man/cat8:/u0/local/man/cat6"    /* if no HPATH */
  605. x
  606. xextern char  PromptBuf[];
  607. x
  608. xextern char *getenv ();
  609. x
  610. xtypedef enum {LIST, RECOGNIZE, PRINT_HELP, SPELL} COMMAND;
  611. x
  612. x
  613. xchar *getentry();
  614. xchar GetAChar();
  615. xchar *tilde();
  616. xchar filetype();
  617. x
  618. x#define NUMCMDS_START 512    /* was 800 */
  619. x#define NUMCMDS_INCR 256
  620. x#define ITEMS_START 512
  621. x#define ITEMS_INCR 256
  622. x
  623. x#ifndef DONT_EXTERN
  624. x
  625. xextern char **command_list;  /* the pre-digested list of commands
  626. x                     for speed and general usefullness */
  627. xextern int numcommands;
  628. xextern int have_sorted;
  629. x
  630. xextern int  dirctr;        /* -1 0 1 2 ... */
  631. xextern char dirflag[5];        /*  ' nn\0' - dir #s -  . 1 2 ... */
  632. x
  633. x
  634. x#endif
  635. x#endif
  636. \Rogue\Monster\
  637. else
  638.   echo "will not over write ./tw.h"
  639. fi
  640. if [ `wc -c ./tw.h | awk '{printf $1}'` -ne 1398 ]
  641. then
  642. echo `wc -c ./tw.h | awk '{print "Got " $1 ", Expected " 1398}'`
  643. fi
  644. if `test ! -s ./tw.help.c`
  645. then
  646. echo "writing ./tw.help.c"
  647. sed 's/^x//' > ./tw.help.c << '\Rogue\Monster\'
  648. xstatic char RCSid[] = "$Header: tw.help.c,v 1.1 85/02/11 21:22:00 paul Exp $";
  649. x#define MAKE_TWENEX        /* flag to include definitions */
  650. x#include "tw.h"
  651. x#include "sh.h"
  652. x
  653. x
  654. x/* actually look up and print documentation on a file.  Look down the path
  655. x   for an approiate file, then print it.  Note that the printing is NOT 
  656. x   PAGED.  This is because the function is NOT ment to look at manual pages,
  657. x   it only does so if there is no .help file to look in. */
  658. x
  659. xstatic int f = -1;
  660. x
  661. xdo_help (command)
  662. xchar *command;
  663. x{
  664. x    char name[FILSIZ + 1];
  665. x    char *cmd_p;
  666. x    int cleanf(), orig_intr;
  667. x    char curdir[128];        /* Current directory being looked at */
  668. x    char *getenv();
  669. x    register char *hpath;    /* The environment parameter */
  670. x    char *skipslist();
  671. x    char full[128], buf[512];    /* full path name and buffer for read */
  672. x    int len;            /* length of read buffer */
  673. x
  674. x                /* copy the string to a safe place */
  675. x    copyn (name, command, sizeof (name));
  676. x
  677. x            /* trim off the garbage that may be at the end */
  678. x    for (cmd_p = name; *cmd_p != '\0'; cmd_p++) {
  679. x    if (*cmd_p == ' ' || *cmd_p == '\t') *cmd_p = '\0';
  680. x    }
  681. x
  682. x                /* if nothing left, return */
  683. x    if (*name == '\0') return;
  684. x
  685. x        /* got is, now "cat" the file based on the path $HPATH */
  686. x
  687. x    hpath = getenv(SEARCHLIST);
  688. x    if(hpath == (char *)0)
  689. x        hpath = DEFAULTLIST;
  690. x
  691. x    while (1)
  692. x    {
  693. x    if(!*hpath)
  694. x    {
  695. x        printf("No help file for %s\n", name);
  696. x        break;
  697. x    }
  698. x    nextslist(hpath, curdir);
  699. x    hpath = skipslist(hpath);
  700. x
  701. x/* now make the full path name - try first /bar/foo.help, then /bar/foo.1,
  702. x   /bar/foo.8, then finally /bar/foo.6 .  This is so that you don't spit
  703. x   a binary at the tty when $HPATH == $PATH.  I know, I know, gotos are
  704. x   BOGUS */
  705. x
  706. x    copyn (full, curdir, sizeof (full));
  707. x    catn (full, "/", sizeof (full));
  708. x    catn (full, name, sizeof (full));
  709. x    catn (full, ".help", sizeof (full));
  710. x    f = open (full, 0);    /* try to open for reading */
  711. x    if (f != -1) goto cat_it;    /* no file there */
  712. x
  713. x    copyn (full, curdir, sizeof (full));
  714. x    catn (full, "/", sizeof (full));
  715. x    catn (full, name, sizeof (full));
  716. x    catn (full, ".1", sizeof (full));
  717. x    f = open (full, 0);    /* try to open for reading */
  718. x    if (f != -1) goto cat_it;    /* no file there */
  719. x
  720. x    copyn (full, curdir, sizeof (full));
  721. x    catn (full, "/", sizeof (full));
  722. x    catn (full, name, sizeof (full));
  723. x    catn (full, ".8", sizeof (full));
  724. x    f = open (full, 0);    /* try to open for reading */
  725. x    if (f != -1) goto cat_it;    /* no file there */
  726. x
  727. x    copyn (full, curdir, sizeof (full));
  728. x    catn (full, "/", sizeof (full));
  729. x    catn (full, name, sizeof (full));
  730. x    catn (full, ".6", sizeof (full));
  731. x    f = open (full, 0);    /* try to open for reading */
  732. x    if (f == -1) continue;    /* no file there */
  733. x
  734. xcat_it:
  735. x    orig_intr = (int) signal(SIGINT, cleanf);
  736. x    while ((f != -1) && (len = read (f, buf, 512)) != 0) {
  737. x                            /* the file is here */
  738. x        write (SHOUT, buf, len);            /* so cat it to the */
  739. x    }                        /* terminal */
  740. x    if (f != -1)
  741. x        close(f);
  742. x    f = (-1);
  743. x    signal(SIGINT, orig_intr);
  744. x    break;
  745. x    }
  746. x}
  747. x
  748. xstatic
  749. xcleanf()
  750. x{
  751. x    if (f != -1)
  752. x    close(f);
  753. x    f = (-1);
  754. x}
  755. x
  756. x/* these next two are stolen from CMU's man(1) command for looking down 
  757. x * paths.  they are prety straight forward. */
  758. x
  759. x/*
  760. x * nextslist takes a search list and copies the next path in it
  761. x * to np.  A null search list entry is expanded to ".".
  762. x * If there are no entries in the search list, then np will point
  763. x * to a null string.
  764. x */
  765. x
  766. xnextslist(sl, np)
  767. x  register char *sl;
  768. x  register char *np;
  769. x{
  770. x    if(!*sl)
  771. x    *np = '\000';
  772. x    else if(*sl == ':')
  773. x    {
  774. x    *np++ = '.';
  775. x    *np = '\000';
  776. x    }
  777. x    else
  778. x    {
  779. x    while(*sl && *sl != ':')
  780. x        *np++ = *sl++;
  781. x    *np = '\000';
  782. x    }
  783. x}
  784. x
  785. x/*
  786. x * skipslist returns the pointer to the next entry in the search list.
  787. x */
  788. x
  789. xchar *
  790. xskipslist(sl)
  791. x  register char *sl;
  792. x{
  793. x    while(*sl && *sl++ != ':');
  794. x    return(sl);
  795. x}
  796. x
  797. \Rogue\Monster\
  798. else
  799.   echo "will not over write ./tw.help.c"
  800. fi
  801. if [ `wc -c ./tw.help.c | awk '{printf $1}'` -ne 3785 ]
  802. then
  803. echo `wc -c ./tw.help.c | awk '{print "Got " $1 ", Expected " 3785}'`
  804. fi
  805. if `test ! -s ./tw.init.c`
  806. then
  807. echo "writing ./tw.init.c"
  808. sed 's/^x//' > ./tw.init.c << '\Rogue\Monster\'
  809. x#define MAKE_TWENEX        /* flag to include definitions */
  810. x#include "tw.h"
  811. x#include "sh.h"
  812. x
  813. x/*
  814. x * Build the command name list (and print the results).  This is a HACK until
  815. x * I can get the rehash command to include its results in the command list.
  816. x */
  817. x
  818. xchar    *extract_dir_from_path();
  819. xint    fcompare();
  820. xchar    *malloc();
  821. xchar    *calloc();
  822. xstatic int maxcommands = 0;
  823. x
  824. xstatic int tw_been_inited = 0;
  825. x            /* to avoid double reading of commands file */
  826. x
  827. xtw_clear_comm_list() {
  828. x    register int i;
  829. x
  830. x    have_sorted = 0;
  831. x    if (numcommands != 0) {
  832. x/*        for (i = 0; command_list[i]; i++) { */
  833. x        for (i = 0; i < numcommands; i++) {
  834. x        if (command_list[i] == 0) {
  835. x        printf ("tried to free a null, i = %d\n", i);
  836. x        } else {
  837. x        free (command_list[i]);
  838. x        }
  839. x        command_list[i] = NULL;
  840. x    }
  841. x    numcommands = 0;
  842. x    }
  843. x}
  844. x
  845. xtw_sort_comms () {        /* could be re-written */
  846. x    register int i,forward;
  847. x    
  848. x    /* sort the list. */
  849. x    qsort (command_list, numcommands, sizeof (command_list[0]), fcompare);
  850. x
  851. x    /* get rid of multiple entries */
  852. x    for (i = 0, forward = 0; i < numcommands - 1; i++) {
  853. x    if (strcmp (command_list[i], command_list[i+1]) == 0) {    /* garbage */
  854. x        if (command_list[i] == 0) {
  855. x        printf ("tried to free a null, i = %d, previous = %s\n", i,
  856. x            command_list [i-1]);
  857. x        } else {
  858. x        free (command_list[i]);
  859. x        }
  860. x        forward++;        /* increase the forward ref. count */
  861. x    } else if (forward) {
  862. x        command_list[i-forward] = command_list[i];
  863. x    }
  864. x    }
  865. x    numcommands -= forward;
  866. x    command_list[numcommands] = (char *)NULL;
  867. x
  868. x    have_sorted = 1;
  869. x}
  870. x
  871. xtw_add_comm_name (name)      /* this is going to be called a LOT at startup */
  872. xchar *name;
  873. x{
  874. x    register int length;
  875. x    register long i;
  876. x    register char **ncl, **p1, **p2;
  877. x
  878. x    if (maxcommands == 0) {
  879. x    command_list = (char **)malloc(NUMCMDS_START * sizeof (command_list[0]));
  880. x    if (command_list == NULL) {
  881. x        printf ("\nYikes! malloc ran out of memory!!!\n");
  882. x        return;
  883. x    }
  884. x    maxcommands = NUMCMDS_START;
  885. x    for (i = 0, p2 = command_list; i < maxcommands; i++)
  886. x        *p2 = NULL;
  887. x    } else if (numcommands >= maxcommands) {
  888. x    ncl = (char **)malloc((maxcommands + NUMCMDS_INCR) *
  889. x                  sizeof (command_list[0]));
  890. x    if (ncl == NULL) {
  891. x        printf ("\nYikes! malloc ran out of memory!!!\n");
  892. x        return;
  893. x    }
  894. x    for (i = 0, p1 = command_list, p2 = ncl; i < numcommands; i++)
  895. x        *p2++ = *p1++;
  896. x    for (; i < maxcommands+NUMCMDS_INCR; i++)
  897. x        *p2++ = NULL;
  898. x    free(command_list);
  899. x    command_list = ncl;
  900. x#ifdef COMMENT
  901. x    command_list = (char **)realloc(command_list, (maxcommands +
  902. x               NUMCMDS_INCR) * sizeof (command_list[0]));
  903. x    if (command_list == NULL) {
  904. x        printf ("\nYikes! realloc ran out of memory!!!\n");
  905. x        return;
  906. x    }
  907. x#endif
  908. x    maxcommands += NUMCMDS_INCR;
  909. x    }
  910. x
  911. x    if (name[0] == '.') return;    /* no dot commands... */
  912. x    if (name[0] == '#') return;    /* no Emacs buffer checkpoints */
  913. x
  914. x    length = strlen(name) + 1;
  915. x
  916. x    if (name[length-2] == '~') return; /* and no Emacs backups either */
  917. x
  918. x    if ((command_list[numcommands] = (char *)malloc (length)) == NULL) {
  919. x        printf ("\nYikes!! I ran out of memory!!!\n");
  920. x        return;
  921. x    }
  922. x
  923. x    copyn (command_list[numcommands], name, MAXNAMLEN);
  924. x    numcommands++;
  925. x}
  926. x
  927. xtw_add_builtins() {
  928. x    register char *cp;
  929. x    register struct biltins *bptr;
  930. x
  931. x    for (bptr = bfunc; cp = bptr->bname; bptr++) {
  932. x    tw_add_comm_name (cp);
  933. x    }
  934. x}
  935. x
  936. xtw_add_aliases ()
  937. x{
  938. x    register struct varent *vp;
  939. x
  940. x    vp = &aliases;
  941. x
  942. x    for (vp = vp->link; vp != 0; vp = vp->link) {
  943. x    tw_add_comm_name(vp->name);
  944. x    }
  945. x
  946. x}
  947. \Rogue\Monster\
  948. else
  949.   echo "will not over write ./tw.init.c"
  950. fi
  951. if [ `wc -c ./tw.init.c | awk '{printf $1}'` -ne 3517 ]
  952. then
  953. echo `wc -c ./tw.init.c | awk '{print "Got " $1 ", Expected " 3517}'`
  954. fi
  955. if `test ! -s ./tw.parse.c`
  956. then
  957. echo "writing ./tw.parse.c"
  958. sed 's/^x//' > ./tw.parse.c << '\Rogue\Monster\'
  959. x#define MAKE_TWENEX        /* flag to include definitions */
  960. x#include "tw.h"
  961. x#include "sh.h"
  962. x
  963. xstatic int maxitems = 0;
  964. xchar **command_list = (char **)NULL;  /* the pre-digested list of commands
  965. x                     for speed and general usefullness */
  966. xint numcommands = 0;
  967. xint have_sorted = 0;
  968. x
  969. xint  dirctr;        /* -1 0 1 2 ... */
  970. xchar dirflag[5];        /*  ' nn\0' - dir #s -  . 1 2 ... */
  971. x
  972. x/* do the expand or list on the command line -- SHOULD BE REPLACED */
  973. xint fcompare();
  974. x
  975. xextern char NeedsRedraw;    /* from ed.h */
  976. x
  977. xtenematch (inputline, inputline_size, num_read, command)
  978. xchar   *inputline;        /* match string prefix */
  979. xint     inputline_size;        /* max size of string */
  980. xint    num_read;        /* # actually in inputline */
  981. xCOMMAND command;        /* LIST or RECOGNIZE or PRINT_HELP */
  982. x
  983. x{
  984. x    static char 
  985. x        *delims = " '\"\t;&<>()|^%";
  986. x    static char 
  987. x        *cmd_delims = ";&(|`";
  988. x    char word [FILSIZ + 1];
  989. x    register char *str_end, *word_start, *cmd_start, *wp;
  990. x    char *cmd_st;
  991. x    int space_left;
  992. x    int is_a_cmd;        /* UNIX command rather than filename */
  993. x    int search_ret;        /* what search returned for debugging */
  994. x
  995. x    str_end = &inputline[num_read];
  996. x
  997. x   /*
  998. x    * Find LAST occurence of a delimiter in the inputline.
  999. x    * The word start is one character past it.
  1000. x    */
  1001. x    for (word_start = str_end; word_start > inputline; --word_start)
  1002. x    if (index (delims, word_start[-1]))
  1003. x        break;
  1004. x
  1005. x                /* space backward looking for the beginning
  1006. x                   of this command */
  1007. x    for (cmd_st = str_end; cmd_st > inputline; --cmd_st)
  1008. x    if (index (cmd_delims, cmd_st[-1]))
  1009. x        break;
  1010. x                /* step forward over leading spaces */
  1011. x    while (*cmd_st != '\0' && (*cmd_st == ' ' || *cmd_st == '\t'))
  1012. x    cmd_st++;
  1013. x
  1014. x    space_left = inputline_size - (word_start - inputline) - 1;
  1015. x    
  1016. x    is_a_cmd = starting_a_command (word_start, inputline);
  1017. x
  1018. x    for (cmd_start = word_start, wp = word; cmd_start < str_end;
  1019. x         *wp++ = *cmd_start++);
  1020. x    *wp = 0;
  1021. x
  1022. x/*  printf ("\ncmd_st:%s:\nword_start:%s:\n", cmd_st, word_start); */
  1023. x                /* for debugging */
  1024. x    if (command == RECOGNIZE) {
  1025. x        search_ret = t_search (word, wp, command, space_left, is_a_cmd);
  1026. x    if (InsertStr(wp) < 0)    /* put it in the input buffer */
  1027. x        return 2;        /* error inserting */
  1028. x    return search_ret;
  1029. x    } else if (command == SPELL) {
  1030. x    search_ret = spell_me(word, sizeof(word), is_a_cmd);
  1031. x    DeleteBack(str_end-word_start);    /* get rid of old word */
  1032. x    if (InsertStr(word) < 0) /* insert newly spelled word */
  1033. x        return 2;        /* error inserting */
  1034. x    if (search_ret < 0)
  1035. x        return 2;
  1036. x    else
  1037. x        return 1;        /* force a beep */
  1038. x    } else if (command == PRINT_HELP) {
  1039. x    do_help (cmd_st);
  1040. x    return 1;
  1041. x    } else {            /* LIST */
  1042. x        search_ret = t_search (word, wp, command, space_left, is_a_cmd);
  1043. x    return search_ret;
  1044. x    }
  1045. x}
  1046. x
  1047. x
  1048. x
  1049. x/*
  1050. x * return true if check items initial chars in template
  1051. x * This differs from PWB imatch in that if check is null
  1052. x * it items anything
  1053. x */
  1054. x
  1055. xstatic
  1056. xis_prefix (check, template)
  1057. xchar   *check,
  1058. x       *template;
  1059. x{
  1060. x    register char  *check_char,
  1061. x                   *template_char;
  1062. x
  1063. x    check_char = check;
  1064. x    template_char = template;
  1065. x    do
  1066. x    if (*check_char == 0)
  1067. x        return (TRUE);
  1068. x    while (*check_char++ == *template_char++);
  1069. x    return (FALSE);
  1070. x}
  1071. x
  1072. x/* return true if the command starting at wordstart is a command */
  1073. x
  1074. xstarting_a_command (wordstart, inputline)
  1075. xregister char *wordstart, *inputline;
  1076. x{
  1077. x    static char
  1078. x        *cmdstart = ";&(|`",
  1079. x        *cmdalive = " \t'\"";
  1080. x    while (--wordstart >= inputline)
  1081. x    {
  1082. x    if (index (cmdstart, *wordstart))
  1083. x        break;
  1084. x    if (!index (cmdalive, *wordstart))
  1085. x        return (FALSE);
  1086. x    }
  1087. x    if (wordstart > inputline && *wordstart == '&')    /* Look for >& */
  1088. x    {
  1089. x    while (wordstart > inputline &&
  1090. x            (*--wordstart == ' ' || *wordstart == '\t'));
  1091. x    if (*wordstart == '>')
  1092. x        return (FALSE);
  1093. x    }
  1094. x    return (TRUE);
  1095. x}
  1096. x
  1097. x
  1098. x/*
  1099. x * Object: extend what user typed up to an ambiguity.
  1100. x * Algorithm:
  1101. x * On first match, copy full entry (assume it'll be the only match) 
  1102. x * On subsequent matches, shorten extended_name to the first
  1103. x * character mismatch between extended_name and entry.
  1104. x * If we shorten it back to the prefix length, stop searching.
  1105. x */
  1106. xrecognize (extended_name, entry, name_length, numitems)
  1107. xchar *extended_name, *entry;
  1108. x{
  1109. x    if (numitems == 1)                /* 1st match */
  1110. x    copyn (extended_name, entry, MAXNAMLEN);
  1111. x    else                    /* 2nd and subsequent matches */
  1112. x    {
  1113. x    register char *x, *ent;
  1114. x    register int len = 0;
  1115. x    for (x = extended_name, ent = entry; *x && *x == *ent++; x++, len++);
  1116. x    *x = '\0';                /* Shorten at 1st char diff */
  1117. x    if (len == name_length)            /* Ambiguous to prefix? */
  1118. x        return (-1);               /* So stop now and save time */
  1119. x    }
  1120. x    return (0);
  1121. x}
  1122. x
  1123. x
  1124. x/*
  1125. x * Perform a RECOGNIZE or LIST command on string "word".
  1126. x */
  1127. xt_search (word, wp, command, max_word_length, looking_for_command)
  1128. xchar   *word,
  1129. x       *wp;            /* original end-of-word */
  1130. xCOMMAND command;
  1131. x{
  1132. x    register numitems,
  1133. x        name_length,        /* Length of prefix (file name) */
  1134. x        looking_for_lognames;    /* True if looking for login names */
  1135. x    int        showpathn;            /* True if we want path number */
  1136. x    struct stat
  1137. x        dot_statb,            /* Stat buffer for "." */
  1138. x        curdir_statb;           /* Stat buffer for current directory */
  1139. x    int        dot_scan,            /* True if scanning "." */
  1140. x        dot_got;            /* True if have scanned dot already */
  1141. x    char    tilded_dir[FILSIZ + 1],    /* dir after ~ expansion */
  1142. x        dir[FILSIZ + 1],        /* /x/y/z/ part in /x/y/z/f */
  1143. x            name[MAXNAMLEN + 1],    /* f part in /d/d/d/f */
  1144. x            extended_name[MAXNAMLEN+1],    /* the recognized (extended) name */
  1145. x            *entry,               /* single directory entry or logname */
  1146. x        *path;            /* hacked PATH environment variable */
  1147. x    int     next_command = 0;        /* the next command to take out of */
  1148. x                    /* the list of commands */
  1149. x    int d = 4, nd;    /* distance and new distance to command for SPELL */
  1150. x
  1151. x    static DIR 
  1152. x        *dir_fd = NULL;
  1153. x    static char
  1154. x           **items = NULL;        /* file names when doing a LIST */
  1155. x
  1156. x    if (items != NULL)
  1157. x    FREE_ITEMS (items, numitems);
  1158. x    numitems = 0;
  1159. x    if (dir_fd != NULL)
  1160. x    FREE_DIR (dir_fd);
  1161. x
  1162. x    looking_for_lognames = (*word == '~') && (index (word, '/') == NULL);
  1163. x    looking_for_command &= (*word != '~') && (index (word, '/') == NULL);
  1164. x
  1165. x    dot_got = FALSE;
  1166. x    stat (".", &dot_statb);
  1167. x
  1168. x    if (looking_for_lognames) {            /* Looking for login names? */
  1169. x    setpwent ();                /* Open passwd file */
  1170. x    copyn (name, &word[1], MAXNAMLEN);    /* name sans ~ */
  1171. x    } else if (looking_for_command) {
  1172. x    if (!numcommands)    /* if we have no list of commands */
  1173. x        get_tw_comm_list();
  1174. x    if (!have_sorted) {    /* if we haven't sorted them yet */
  1175. x        tw_add_builtins();
  1176. x        tw_add_aliases();
  1177. x        tw_sort_comms ();    /* re-build the command path for twenex.c */
  1178. x    }
  1179. x    } else {            /* not looking for a command or logname */
  1180. x    /* Open the directory */
  1181. x    extract_dir_and_name (word, dir, name);
  1182. x    if ((tilde (tilded_dir, dir) == 0) ||    /* expand ~user/... stuff */
  1183. x        ((dir_fd = opendir (*tilded_dir ? tilded_dir : ".")) == NULL)) {
  1184. x        printf ("\n%s unreadable\n", *tilded_dir ? tilded_dir : ".");
  1185. x        NeedsRedraw = 1;
  1186. x        return (0);
  1187. x    }
  1188. x
  1189. x    dot_scan = FALSE;
  1190. x    }
  1191. x
  1192. x    name_length = strlen (name);
  1193. x    showpathn = looking_for_command && is_set("listpathnum");
  1194. x
  1195. x    while (1) {
  1196. x        if (!looking_for_command) {
  1197. x        if ((entry = getentry (dir_fd, looking_for_lognames)) == NULL) {
  1198. x        break;
  1199. x        }
  1200. x        
  1201. x            /*
  1202. x             * Don't match . files on null prefix match
  1203. x             */
  1204. x            if (name_length == 0 && entry[0] == '.' &&
  1205. x        !looking_for_lognames && !is_set("showdots"))
  1206. x                continue;
  1207. x
  1208. x    } else {
  1209. x        if (numcommands == 0) {
  1210. x        dohash ();
  1211. x        }
  1212. x        if (next_command >= numcommands) break; /* end of list */
  1213. x        if ((entry = command_list[next_command++]) == NULL)
  1214. x        break;
  1215. x        copyn (name, word, MAXNAMLEN);    /* so it can match things */
  1216. x    }
  1217. x
  1218. x    if (command == SPELL) {    /* correct the spelling of the last bit */
  1219. x        nd = spdist(entry, name); /* test the entry against original */
  1220. x        if (nd <= d && nd != 4) {
  1221. x        strcpy (extended_name, entry);
  1222. x        d = nd;
  1223. x        if (d == 0)    /* if found it exactly */
  1224. x            break;
  1225. x        }
  1226. x    } else if (command == LIST) { /* LIST command */
  1227. x            extern char *malloc ();
  1228. x            register int length;
  1229. x        register long i;
  1230. x        register char **ni, **p1, **p2;
  1231. x
  1232. x        if (!is_prefix (name, entry))
  1233. x        continue;
  1234. x
  1235. x        if (items == NULL || maxitems == 0) {
  1236. x            items = (char **) malloc (sizeof (items[0]) * (ITEMS_START+1));
  1237. x            if (items == NULL) {
  1238. x            printf("\nCannot malloc items!!\n");
  1239. x            NeedsRedraw = 1;
  1240. x                break;
  1241. x        }
  1242. x        maxitems = ITEMS_START;
  1243. x        for (i = 0, p2 = items; i < maxitems; i++)
  1244. x            *p2++ = NULL;
  1245. x        } else if (numitems >= maxitems) {
  1246. x        ni = (char **)malloc((sizeof (items[0])) *
  1247. x                     (maxitems + ITEMS_INCR));
  1248. x            if (ni == NULL) {
  1249. x            printf("\nCannot realloc items!!\n");
  1250. x            NeedsRedraw = 1;
  1251. x                break;
  1252. x        }
  1253. x        for (i = 0, p1 = items, p2 = ni; i < numitems; i++)
  1254. x            *p2++ = *p1++;
  1255. x        for (; i < numitems+ITEMS_INCR; i++)
  1256. x            *p2++ = NULL;
  1257. x        free (items);
  1258. x        items = ni;
  1259. x        maxitems += ITEMS_INCR;
  1260. x        }
  1261. x
  1262. x
  1263. x            length = strlen(entry) + 1;
  1264. x            if (showpathn)
  1265. x            length += strlen(dirflag);
  1266. x            if ((items[numitems] = malloc (length)) == NULL)
  1267. x            {
  1268. x            printf ("\nYikes!! I ran out of memory!!!\n");
  1269. x        NeedsRedraw = 1;
  1270. x            break;
  1271. x            }
  1272. x            copyn (items[numitems], entry, MAXNAMLEN);
  1273. x            if (showpathn)
  1274. x                catn (items[numitems], dirflag, MAXNAMLEN);
  1275. x            numitems++;
  1276. x        } else {                    /* RECOGNIZE command */
  1277. x        if (!is_prefix (name, entry))
  1278. x        continue;
  1279. x
  1280. x        if (adrof ("recexact")) {
  1281. x        if (strcmp (name, entry) == 0) {    /* EXACT match */
  1282. x                copyn (extended_name, entry, MAXNAMLEN);
  1283. x            numitems = 1;        /* fake into expanding */
  1284. x            break;
  1285. x        }
  1286. x        }
  1287. x            if (recognize (extended_name, entry, name_length, ++numitems))
  1288. x            break;
  1289. x    }
  1290. x    }
  1291. x
  1292. x    if (!looking_for_command) {        
  1293. x        if (looking_for_lognames)
  1294. x        endpwent ();
  1295. x        else
  1296. x        FREE_DIR (dir_fd);
  1297. x    }
  1298. x
  1299. x    if (command == RECOGNIZE && numitems > 0)
  1300. x    {
  1301. x    if (looking_for_lognames)
  1302. x        copyn (word, "~", 1);
  1303. x    else if (looking_for_command)
  1304. x        word[0] = '\0';
  1305. x    else
  1306. x        copyn (word, dir, max_word_length);           /* put back dir part */
  1307. x    catn (word, extended_name, max_word_length);   /* add extended name */
  1308. x    if (numitems == 1) {
  1309. x            if (looking_for_lognames) {            /* add / */
  1310. x                catn (word, "/", max_word_length);
  1311. x            }
  1312. x            else {
  1313. x                if (looking_for_command) {        /* add space */
  1314. x                    catn (word, " ", max_word_length);
  1315. x                }
  1316. x                else {
  1317. x                    if (isadirectory (tilded_dir, extended_name)) {
  1318. x                        catn (word, "/", max_word_length);
  1319. x                    }
  1320. x                    else {
  1321. x                        catn (word, " ", max_word_length);
  1322. x                    }
  1323. x                }
  1324. x            }
  1325. x    }
  1326. x    return (numitems);                /* at the end */
  1327. x    } else if (command == LIST) {
  1328. x    qsort (items, numitems, sizeof (items[1]), fcompare);
  1329. x    print_by_column (looking_for_lognames ? NULL:tilded_dir, items,
  1330. x             numitems, looking_for_command);
  1331. x    if (items != NULL)
  1332. x        FREE_ITEMS (items, numitems);
  1333. x    return (0);
  1334. x    } else if (command == SPELL) {
  1335. x    if (looking_for_lognames)
  1336. x        copyn (word, "~", 1);
  1337. x    else if (looking_for_command)
  1338. x        word[0] = '\0';
  1339. x    else
  1340. x        copyn (word, dir, max_word_length);           /* put back dir part */
  1341. x    catn (word, extended_name, max_word_length);   /* add extended name */
  1342. x    return d;
  1343. x    }
  1344. x}
  1345. x
  1346. x
  1347. x/* stuff for general command line hacking */
  1348. x
  1349. x/*
  1350. x * Strip next directory from path; return ptr to next unstripped directory.
  1351. x */
  1352. xchar *extract_dir_from_path (path, dir)
  1353. xchar *path, dir[];
  1354. x{
  1355. x    register char *d = dir;
  1356. x
  1357. x    while (*path && (*path == ' ' || *path == ':')) path++;
  1358. x    while (*path && (*path != ' ' && *path != ':')) *(d++) = *(path++);
  1359. x    while (*path && (*path == ' ' || *path == ':')) path++;
  1360. x
  1361. x    ++dirctr;
  1362. x    if (*dir == '.')
  1363. x        strcpy (dirflag, " .");
  1364. x    else
  1365. x    {
  1366. x        dirflag[0] = ' ';
  1367. x    if (dirctr <= 9)
  1368. x    {
  1369. x        dirflag[1] = '0' + dirctr;
  1370. x        dirflag[2] = '\0';
  1371. x    }
  1372. x    else
  1373. x    {
  1374. x        dirflag[1] = '0' + dirctr / 10;
  1375. x        dirflag[2] = '0' + dirctr % 10;
  1376. x        dirflag[3] = '\0';
  1377. x    }
  1378. x    }
  1379. x    *(d++) = '/';
  1380. x    *d = 0;
  1381. x
  1382. x    return path;
  1383. x}
  1384. x
  1385. x
  1386. xstatic
  1387. xfree_items (items, numitems)
  1388. xregister char **items;
  1389. xregister numitems;
  1390. x{
  1391. x    register int i;
  1392. x/*     for (i = 0; items[i] != (char *)NULL; i++) */
  1393. x    for (i = 0; i < numitems; i++)
  1394. x    free (items[i]);
  1395. x    free (items);
  1396. x    maxitems = 0;
  1397. x}
  1398. x
  1399. x
  1400. x/*
  1401. x * parse full path in file into 2 parts: directory and file names
  1402. x * Should leave final slash (/) at end of dir.
  1403. x */
  1404. xstatic
  1405. xextract_dir_and_name (path, dir, name)
  1406. xchar   *path, *dir, *name;
  1407. x{
  1408. x    extern char *rindex ();
  1409. x    register char  *p;
  1410. x    p = rindex (path, '/');
  1411. x    if (p == NULL)
  1412. x    {
  1413. x    copyn (name, path, MAXNAMLEN);
  1414. x    dir[0] = '\0';
  1415. x    }
  1416. x    else
  1417. x    {
  1418. x    p++;
  1419. x    copyn (name, p, MAXNAMLEN);
  1420. x    copyn (dir, path, p - path);
  1421. x    }
  1422. x}
  1423. x
  1424. x
  1425. xchar *
  1426. xgetentry (dir_fd, looking_for_lognames)
  1427. xDIR *dir_fd;
  1428. x{
  1429. x    if (looking_for_lognames)            /* Is it login names we want? */
  1430. x    {
  1431. x    extern struct passwd *getpwent ();
  1432. x    register struct passwd *pw;
  1433. x    if ((pw = getpwent ()) == NULL)
  1434. x        return (NULL);
  1435. x    return (pw -> pw_name);
  1436. x    }
  1437. x    else                    /* It's a dir entry we want */
  1438. x    {
  1439. x    register struct direct *dirp;
  1440. x    if (dirp = readdir (dir_fd))
  1441. x        return (dirp -> d_name);
  1442. x    return (NULL);
  1443. x    }
  1444. x}
  1445. x
  1446. x
  1447. x/*
  1448. x * expand "old" file name with possible tilde usage
  1449. x *        ~person/mumble
  1450. x * expands to
  1451. x *        home_directory_of_person/mumble
  1452. x * into string "new".
  1453. x */
  1454. x
  1455. xchar *
  1456. xtilde (new, old)
  1457. xchar *new, *old;
  1458. x{
  1459. x    extern struct passwd *getpwuid (), *getpwnam ();
  1460. x
  1461. x    register char *o, *p;
  1462. x    register struct passwd *pw;
  1463. x    static char person[40] = {0};
  1464. x
  1465. x    if ((old[0] != '~') && (old[0] != '='))
  1466. x    {
  1467. x    strcpy (new, old);
  1468. x    return (new);
  1469. x    }
  1470. x
  1471. x    for (p = person, o = &old[1]; *o && *o != '/'; *p++ = *o++);
  1472. x    *p = '\0';
  1473. x
  1474. x    if (old[0] == '~') {
  1475. x    if (person[0] == '\0')            /* then use current uid */
  1476. x        pw = getpwuid (getuid ());
  1477. x    else
  1478. x        pw = getpwnam (person);
  1479. x
  1480. x    if (pw == NULL)
  1481. x        return (NULL);
  1482. x
  1483. x    strcpy (new, pw -> pw_dir);
  1484. x    } else {                    /* '=' stack expansion */
  1485. x        new[0] = '\0';
  1486. x        if (!isdigit (old[1]) && old[1] != '-')
  1487. x        return (NULL);
  1488. x        getstakd (new, (old[1] == '-') ? -1 : old[1] - '0', 0);
  1489. x                    /* last "0" = don't call error */
  1490. x        if (new[0] == '\0')
  1491. x        return (NULL);
  1492. x    }
  1493. x    (void) strcat (new, o);
  1494. x    return (new);
  1495. x}
  1496. x
  1497. xchar
  1498. xfiletype (dir, file)        /* symbology from 4.3 ls command */
  1499. xchar *dir, *file;
  1500. x{
  1501. x    if (dir)
  1502. x    {
  1503. x    char path[512];
  1504. x    struct stat statb;
  1505. x    strcpy (path, dir);
  1506. x    catn (path, file, sizeof path);
  1507. x    if (lstat (path, &statb) >= 0) /* if no symlinks, change to stat() */
  1508. x    {
  1509. x        if ((statb.st_mode & S_IFLNK) == S_IFLNK) /* Symbolic link */
  1510. x        return ('@');
  1511. x        if ((statb.st_mode & S_IFSOCK) == S_IFSOCK)    /* Socket */
  1512. x        return ('=');
  1513. x#ifdef S_IFIFO
  1514. x        if ((statb.st_mode & S_IFIFO) == S_IFIFO)    /* Named Pipe */
  1515. x        return ('<');
  1516. x#endif
  1517. x        if ((statb.st_mode & S_IFDIR) == S_IFDIR) /* normal Directory */
  1518. x        return ('/');
  1519. x        if (statb.st_mode & 0111)
  1520. x        return ('*');
  1521. x    }
  1522. x    }
  1523. x    return (' ');
  1524. x}
  1525. x
  1526. xisadirectory (dir, file)    /* return 1 if dir/file is a directory */
  1527. xchar *dir, *file;        /* uses stat rather than lstat to get dest. */
  1528. x{
  1529. x    if (dir)
  1530. x    {
  1531. x    char path[512];
  1532. x    struct stat statb;
  1533. x    strcpy (path, dir);
  1534. x    catn (path, file, sizeof path);
  1535. x    if (stat (path, &statb) >= 0) /* if no symlinks, change to stat() */
  1536. x    {
  1537. x        if ((statb.st_mode & S_IFDIR) == S_IFDIR) /* normal Directory */
  1538. x        return 1;
  1539. x    }
  1540. x    }
  1541. x    return 0;
  1542. x}
  1543. x
  1544. x/*
  1545. x * Print sorted down columns
  1546. x */
  1547. xprint_by_column (dir, items, count, looking_for_command)
  1548. xregister char *dir, *items[];
  1549. x{
  1550. x    register int i, rows, r, c, maxwidth = 0, columns;
  1551. x    extern int TermH;        /* from the editor routines */
  1552. x    extern int lbuffed;        /* from sh.print.c */
  1553. x
  1554. x    /*    lbuffed = 0; */    /* turn off line buffering */
  1555. x
  1556. x    for (i = 0; i < count; i++)
  1557. x    maxwidth = max (maxwidth, strlen (items[i]));
  1558. x    maxwidth += looking_for_command ? 1:2;    /* for the file tag and space */
  1559. x    columns = (TermH+1) / maxwidth; /* PWP: terminal size change */
  1560. x    if (!columns) columns = 1;
  1561. x    rows = (count + (columns - 1)) / columns;
  1562. x    for (r = 0; r < rows; r++)
  1563. x    {
  1564. x    for (c = 0; c < columns; c++)
  1565. x    {
  1566. x        i = c * rows + r;
  1567. x        if (i < count)
  1568. x        {
  1569. x        register int w;
  1570. x        printf("%s", items[i]);
  1571. x        w = strlen (items[i]);
  1572. x        /* Print filename followed by '/' or '*' or ' ' */
  1573. x        if (!looking_for_command)
  1574. x            putchar (filetype (dir, items[i])), w++;
  1575. x        if (c < (columns - 1))            /* Not last column? */
  1576. x            for (; w < maxwidth; w++)
  1577. x            putchar (' ');
  1578. x        }
  1579. x    }
  1580. x    printf ("\n");
  1581. x    }
  1582. x
  1583. x    /* lbuffed = 1; */        /* turn back on line buffering */
  1584. x    flush();
  1585. x}
  1586. x
  1587. x/*
  1588. x * For qsort()
  1589. x */
  1590. xfcompare (file1, file2)
  1591. xchar  **file1, **file2;
  1592. x{
  1593. x    return (strcmp (*file1, *file2));
  1594. x}
  1595. x
  1596. x/*
  1597. x * Concatonate src onto tail of des.
  1598. x * Des is a string whose maximum length is count.
  1599. x * Always null terminate.
  1600. x */
  1601. x
  1602. xcatn (des, src, count)
  1603. xregister char *des, *src;
  1604. xregister count;
  1605. x{
  1606. x    while (--count >= 0 && *des)
  1607. x    des++;
  1608. x    while (--count >= 0)
  1609. x    if ((*des++ = *src++) == 0)
  1610. x        return;
  1611. x    *des = '\0';
  1612. x}
  1613. x
  1614. xmax (a, b)
  1615. x{
  1616. x    if (a > b)
  1617. x    return (a);
  1618. x    return (b);
  1619. x}
  1620. x
  1621. x/*
  1622. x * like strncpy but always leave room for trailing \0
  1623. x * and always null terminate.
  1624. x */
  1625. xcopyn (des, src, count)
  1626. xregister char *des, *src;
  1627. xregister count;
  1628. x{
  1629. x    while (--count >= 0)
  1630. x    if ((*des++ = *src++) == 0)
  1631. x        return;
  1632. x    *des = '\0';
  1633. x}
  1634. \Rogue\Monster\
  1635. else
  1636.   echo "will not over write ./tw.parse.c"
  1637. fi
  1638. if [ `wc -c ./tw.parse.c | awk '{printf $1}'` -ne 17506 ]
  1639. then
  1640. echo `wc -c ./tw.parse.c | awk '{print "Got " $1 ", Expected " 17506}'`
  1641. fi
  1642. echo "Finished archive 4 of 6"
  1643. # if you want to concatenate archives, remove anything after this line
  1644. exit
  1645.  
  1646. -- 
  1647.  
  1648. Rich $alz
  1649. Cronus Project, BBN Labs            rsalz@bbn.com
  1650. Moderator, comp.sources.unix            sources@uunet.uu.net
  1651.