home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / unix / volume26 / calc / part07 < prev    next >
Encoding:
Text File  |  1992-05-09  |  46.0 KB  |  1,734 lines

  1. Newsgroups: comp.sources.unix
  2. From: dbell@pdact.pd.necisa.oz.au (David I. Bell)
  3. Subject: v26i033: CALC - An arbitrary precision C-like calculator, Part07/21
  4. Sender: unix-sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: dbell@pdact.pd.necisa.oz.au (David I. Bell)
  8. Posting-Number: Volume 26, Issue 33
  9. Archive-Name: calc/part07
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 7 (of 21)."
  18. # Contents:  alloc.c math.h obj.c
  19. # Wrapped by dbell@elm on Tue Feb 25 15:21:02 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'alloc.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'alloc.c'\"
  23. else
  24. echo shar: Extracting \"'alloc.c'\" \(13396 characters\)
  25. sed "s/^X//" >'alloc.c' <<'END_OF_FILE'
  26. X/*
  27. X * Copyright (c) 1992 David I. Bell
  28. X * Permission is granted to use, distribute, or modify this source,
  29. X * provided that this copyright notice remains intact.
  30. X *
  31. X * Description:
  32. X *    This is a very fast storage allocator. It allocates blocks of a small
  33. X *    number of different sizes, and keeps free lists of each size.  Blocks
  34. X *    that don't exactly fit are passed up to the next larger size.  In this
  35. X *    implementation, the available sizes are 2^n-4 (or 2^n-12) bytes long.
  36. X *    This is designed for use in a program that uses vast quantities of
  37. X *    memory, but bombs when it runs out.
  38. X *
  39. X * Abnormal Conditions
  40. X *    This is a public domain storage allocator.
  41. X *
  42. X * Modifications:
  43. X *    Date        Programmer        Description of modification
  44. X *    27-FEB-90    Landon Curt Noll    unix does not need most of this
  45. X *    2-OCT-89    David I. Bell        Add free list. Sbrk now optional
  46. X *    30-JUN-87    Peter Miller        Made it work on Slimos.
  47. X *    21-FEB-82    Chris Kingsley        Initial Coding
  48. X *            kingsley@cit-20        Caltech
  49. X */
  50. X
  51. X#include <stdio.h>
  52. X#include "alloc.h"
  53. X#include "have_stdlib.h"
  54. X
  55. X#if 0
  56. X#define DEBUG    1        /* defined if debugging code enabled */
  57. X#define MSTATS    1        /* defined if memory statistics kept */
  58. X#endif
  59. X#define    NO_SBRK    1        /* defined if cannot use sbrk */
  60. X
  61. X
  62. X#if !defined(UNIX_MALLOC)
  63. X/*
  64. X * Make these functions really accessible here.
  65. X */
  66. X#undef    malloc
  67. X#undef    realloc
  68. X#undef    free
  69. X
  70. X
  71. X#ifdef DEBUG
  72. X#define assert(x,v) if ((x)==0) assertfailed(v)
  73. X#else
  74. X#define assert(x,v)
  75. X#endif
  76. X
  77. Xtypedef unsigned char u_char;
  78. Xtypedef unsigned short u_short;
  79. Xtypedef unsigned int u_int;
  80. Xtypedef char * caddr_t;
  81. X
  82. X#ifdef NO_SBRK
  83. Xextern char * malloc();
  84. Xextern char * realloc();
  85. X#else
  86. Xextern char * sbrk();
  87. X#endif
  88. X
  89. X
  90. X/*
  91. X * The overhead on a block is at least 4 bytes.  When free, this space
  92. X * contains a pointer to the next free block, and the bottom two bits must
  93. X * be zero.  When in use, the first byte is set to MAGIC, and the second
  94. X * byte is the size index.  The remaining bytes are for alignment.
  95. X * If range checking (RCHECK) is enabled and the size of the block fits
  96. X * in two bytes, then the top two bytes hold the size of the requested block
  97. X * plus the range checking words, and the header word MINUS ONE.
  98. X */
  99. X
  100. Xunion overhead
  101. X{
  102. X    union overhead * ov_next;    /* when free */
  103. X    struct
  104. X    {
  105. X        u_char ovu_magic;    /* magic number */
  106. X        u_char ovu_index;    /* bucket # */
  107. X#define ov_magic ovu.ovu_magic
  108. X#define ov_index ovu.ovu_index
  109. X#ifdef RCHECK
  110. X        u_short ovu_size;    /* actual block size */
  111. X        u_int ovu_rmagic;    /* range magic number */
  112. X#define ov_size ovu.ovu_size
  113. X#define ov_rmagic ovu.ovu_rmagic
  114. X#endif
  115. X    } ovu;
  116. X};
  117. X
  118. X#define QUANTUM_NBITS    4
  119. X#define QUANTUM        (1<<QUANTUM_NBITS)
  120. X
  121. X#define MAGIC    0xff        /* magic # on accounting info */
  122. X#define RMAGIC    0x55555555    /* magic # on range info */
  123. X#ifdef RCHECK
  124. X#define RSLOP    sizeof(u_int)
  125. X#else
  126. X#define RSLOP    0
  127. X#endif
  128. X
  129. X/*
  130. X * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  131. X * smallest allocatable block is 8 bytes.  The overhead information
  132. X * precedes the data area returned to the user.
  133. X */
  134. X
  135. X#define NBUCKETS    32    /* we can't run out on a 32 bit machine! */
  136. Xstatic union overhead * nextf[NBUCKETS];
  137. Xstatic union overhead *watchloc = 0;    /* location to be watched */
  138. X
  139. X#ifdef MSTATS
  140. X
  141. X/*
  142. X * nmalloc[i] is the difference between the number of mallocs and frees
  143. X * for a given block size.
  144. X */
  145. X
  146. Xstatic u_int nmalloc[NBUCKETS];
  147. X
  148. X#endif
  149. X
  150. X
  151. X/*
  152. X * Watch some allocated memory to see if it gets blasted.
  153. X */
  154. Xallocwatch(cp)
  155. X    char *cp;
  156. X{
  157. X    if (cp == NULL) {
  158. X        watchloc = NULL;
  159. X        return;
  160. X    }
  161. X    watchloc = (union overhead *)cp - 1;
  162. X    assert(watchloc->ov_magic == MAGIC, 10);
  163. X}
  164. X
  165. X
  166. Xalloccheck()
  167. X{
  168. X    assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 11);
  169. X}
  170. X
  171. X
  172. X/*
  173. X * NAME
  174. X *    morecore - get more memory
  175. X *
  176. X * SYNOPSIS
  177. X *    void
  178. X *    morecore(bucket)
  179. X *    int bucket;
  180. X *
  181. X * DESCRIPTION
  182. X *    Morecore is used to allocate more memory to the indicated bucket.
  183. X *
  184. X * RETURNS
  185. X *    void
  186. X */
  187. Xstatic void
  188. Xmorecore(bucket)
  189. X    register u_int    bucket;
  190. X{
  191. X    register union overhead * op;
  192. X    register u_int    rnu;    /* 2^rnu bytes will be requested */
  193. X    register u_int    nblks;    /* become nblks blocks of the desired size */
  194. X    register u_int    siz;
  195. X
  196. X    assert(bucket >= QUANTUM_NBITS, 1);
  197. X    assert(bucket < NBUCKETS, 2);
  198. X    assert(!nextf[bucket], 3);
  199. X#ifndef NO_SBRK
  200. X    /*
  201. X     * Insure memory is allocated on a page boundary.
  202. X     * Should make getpageize() call?
  203. X     */
  204. X#define PAGE_SIZE (1<<10)
  205. X    siz = (u_int)sbrk(0);
  206. X    if(siz & (PAGE_SIZE-1))
  207. X        sbrk(PAGE_SIZE - (siz & (PAGE_SIZE-1)));
  208. X#endif
  209. X
  210. X    /* take 2k unless the block is bigger than that */
  211. X    rnu = (bucket <= 11) ? 11 : bucket;
  212. X    assert(rnu >= bucket, 4);
  213. X    nblks = 1L << (rnu - bucket); /* how many blocks to get */
  214. X    siz = 1L << rnu;
  215. X
  216. X#ifndef NO_SBRK
  217. X    op = (union overhead *)sbrk(siz);
  218. X    /* no more room! */
  219. X    if ((int)op == -1)
  220. X        return;
  221. X    /*
  222. X     * Round up to minimum allocation size boundary
  223. X     * and deduct from block count to reflect.
  224. X     */
  225. X    if((int)op & (QUANTUM-1))
  226. X    {
  227. X        op = (union overhead *)(((int)op + QUANTUM) &~ (QUANTUM-1));
  228. X        nblks--;
  229. X    }
  230. X#else
  231. X    op = (union overhead *)malloc(siz);
  232. X    /* no more room! */
  233. X    if (!op)
  234. X        return;
  235. X#endif
  236. X    /*
  237. X     * Add new memory allocated to the
  238. X     * free list for this hash bucket.
  239. X     */
  240. X    nextf[bucket] = op;
  241. X    siz = 1L << bucket;
  242. X    while (--nblks)
  243. X    {
  244. X        op->ov_next = (union overhead *)((caddr_t)op + siz);
  245. X        op = op->ov_next;
  246. X    }
  247. X}
  248. X
  249. X
  250. X/*
  251. X * NAME
  252. X *    mem_alloc - memory allocator
  253. X *
  254. X * SYNOPSIS
  255. X *    char *
  256. X *    mem_alloc()
  257. X *
  258. X * DESCRIPTION
  259. X *    Mem_alloc is used to allocate memory large enought to fit the requested
  260. X *    size, and on a boundary suitable for placing any value.
  261. X *
  262. X * RETURNS
  263. X *    char *, pointer to base of dynamic memory allocated
  264. X *
  265. X * CAVEAT
  266. X *    Use mem_free() when you are finished with the space.
  267. X */
  268. Xchar *
  269. Xmem_alloc(nbytes)
  270. X    register unsigned long int nbytes;
  271. X{
  272. X    register union overhead *p;
  273. X    register int    bucket;
  274. X    register unsigned long int shiftr;
  275. X
  276. X    if (nbytes > ((unsigned int) -1))
  277. X        return NULL;
  278. X    assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 12);
  279. X    /*
  280. X     * Convert amount of memory requested into
  281. X     * closest block size stored in hash buckets
  282. X     * which satisfies request.  Account for
  283. X     * space used per block for accounting.
  284. X     */
  285. X    nbytes = (nbytes + sizeof (union overhead) + RSLOP + (QUANTUM-1)) &~ (QUANTUM-1);
  286. X    shiftr = (nbytes - 1) >> QUANTUM_NBITS;
  287. X    /* apart from this loop, this is O(1) */
  288. X    bucket = QUANTUM_NBITS;
  289. X    while(shiftr)
  290. X    {
  291. X        shiftr >>= 1;
  292. X        bucket++;
  293. X    }
  294. X
  295. X    /*
  296. X     * If nothing in hash bucket right now,
  297. X     * request more memory from the system.
  298. X     */
  299. X    if (!nextf[bucket])
  300. X        morecore(bucket);
  301. X    if (!(p = nextf[bucket]))
  302. X        return (char*)0;
  303. X    /* remove from linked list */
  304. X    nextf[bucket] = p->ov_next;
  305. X    p->ov_magic = MAGIC;
  306. X    p->ov_index = bucket;
  307. X#ifdef MSTATS
  308. X    nmalloc[bucket]++;
  309. X#endif
  310. X#ifdef RCHECK
  311. X    /*
  312. X     * Record allocated size of block and
  313. X     * bound space with magic numbers
  314. X     */
  315. X    if (nbytes <= (1L<<16))
  316. X        p->ov_size = nbytes - 1;
  317. X    p->ov_rmagic = RMAGIC;
  318. X    *((u_int *)((caddr_t)p + nbytes - RSLOP)) = RMAGIC;
  319. X#endif
  320. X    return ((char *)(p + 1));
  321. X}
  322. X
  323. X
  324. X/*
  325. X * NAME
  326. X *    mem_free - free memory
  327. X *
  328. X * SYNOPSIS
  329. X *    int
  330. X *    mem_free(cp)
  331. X *    char * cp;
  332. X *
  333. X * DESCRIPTION
  334. X *    Mem_free is used to release space allocated by mem_alloc
  335. X *    or mem_realloc.
  336. X *
  337. X * RETURNS
  338. X *    int
  339. X *
  340. X * CAVEAT
  341. X *    do not pass mem_free() an argument that was returned by mem_alloc()
  342. X *    or mem_realloc().
  343. X */
  344. Xint
  345. Xmem_free(cp)
  346. X    char *    cp;
  347. X{
  348. X    register u_int    bucket;
  349. X    register union overhead *op;
  350. X
  351. X    assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 13);
  352. X    if (!cp)
  353. X        return;
  354. X    op = (union overhead *)cp - 1;
  355. X    assert(op->ov_magic == MAGIC, 5);    /* make sure it was in use */
  356. X    assert(op->ov_index < NBUCKETS, 6);
  357. X    assert(op->ov_index >= QUANTUM_NBITS, 7);
  358. X#ifdef RCHECK
  359. X    assert(op->ov_index > 16 || op->ov_size == (1L<<op->ov_index)-1, 8);
  360. X    assert(op->ov_rmagic == RMAGIC, 9);
  361. X    assert(op->ov_index > 16 || *(u_int *)((caddr_t)op + op->ov_size + 1 - RSLOP) == RMAGIC, 10);
  362. X#endif
  363. X#ifndef DEBUG
  364. X    if(op->ov_magic != MAGIC)
  365. X        return;        /* sanity */
  366. X#endif
  367. X    bucket = op->ov_index;
  368. X    op->ov_next = nextf[bucket];
  369. X    nextf[bucket] = op;
  370. X#ifdef MSTATS
  371. X    nmalloc[bucket]--;
  372. X#endif
  373. X}
  374. X
  375. X
  376. X/*
  377. X * NAME
  378. X *    findbucket - find a bucket
  379. X *
  380. X * SYNOPSIS
  381. X *    int
  382. X *    findbucket(freep, srchlen)
  383. X *    union overhead * freep;
  384. X *    int srchlen;
  385. X *
  386. X * DESCRIPTION
  387. X *    Findbucket is used to find the bucket a free block is in.
  388. X *    Search ``srchlen'' elements of each free list for a block whose
  389. X *    header starts at ``freep''.  If srchlen is -1 search the whole list.
  390. X *
  391. X * RETURNS
  392. X *    bucket number, or -1 if not found.
  393. X */
  394. Xstatic int
  395. Xfindbucket(freep, srchlen)
  396. X    union overhead *    freep;
  397. X    int    srchlen;
  398. X{
  399. X    register union overhead *p;
  400. X    register int    i, j;
  401. X
  402. X    for (i = 0; i < NBUCKETS; i++)
  403. X    {
  404. X        j = 0;
  405. X        for (p = nextf[i]; p && j != srchlen; p = p->ov_next)
  406. X        {
  407. X            if (p == freep)
  408. X                return i;
  409. X            j++;
  410. X        }
  411. X    }
  412. X    return -1;
  413. X}
  414. X
  415. X
  416. X/*
  417. X * When a program attempts "storage compaction" as mentioned in the
  418. X * old malloc man page, it realloc's an already freed block.  Usually
  419. X * this is the last block it freed; occasionally it might be farther
  420. X * back.  We have to search all the free lists for the block in order
  421. X * to determine its bucket: first we make one pass thru the lists
  422. X * checking only the first block in each; if that fails we search
  423. X * ``realloc_srchlen'' blocks in each list for a match (the variable
  424. X * is extern so the caller can modify it).  If that fails we just copy
  425. X * however many bytes was given to realloc() and hope it's not huge.
  426. X */
  427. X
  428. Xstatic int realloc_srchlen = 4;    /* 4 should be plenty, -1 =>'s whole list */
  429. X
  430. X/*
  431. X * NAME
  432. X *    mem_realloc - change size
  433. X *
  434. X * SYNOPSIS
  435. X *    char
  436. X *    mem_realloc(cp, nbytes)
  437. X *    char * cp;
  438. X *    u_int nbytes;
  439. X *
  440. X * DESCRIPTION
  441. X *    Mem_realloc is used to enlarge a chunk of memory
  442. X *    returned by mem_alloc() or mem_realloc().
  443. X *
  444. X * RETURNS
  445. X *    char *, pointer to base of dynamic memory allocated
  446. X *
  447. X * CAVEAT
  448. X *    Use mem_free() when you are finished with the space.
  449. X */
  450. Xchar *
  451. Xmem_realloc(cp, nbytes)
  452. X    char *cp;
  453. X    unsigned long    nbytes;
  454. X{
  455. X    register u_int    old_nbytes;
  456. X    register union overhead *op;
  457. X    char *    res;
  458. X    register u_int    old_bucket;
  459. X    short    was_alloced = 0;
  460. X
  461. X    if (nbytes > ((unsigned int) -1))
  462. X        return NULL;
  463. X    assert((watchloc == NULL) || (watchloc->ov_magic == MAGIC), 14);
  464. X    if (!cp)
  465. X        return mem_alloc(nbytes);
  466. X    op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
  467. X    if (op->ov_magic == MAGIC)
  468. X    {
  469. X        was_alloced++;
  470. X        old_bucket = op->ov_index;
  471. X    }
  472. X    else
  473. X    {
  474. X        /*
  475. X         * Already free, doing "compaction".
  476. X         *
  477. X         * Search for the old block of memory on the
  478. X         * free list. First, check the most common
  479. X         * case (last element free'd), then (this failing)
  480. X         * the last ``realloc_srchlen'' items free'd.
  481. X         * If all lookups fail, then assume the size of
  482. X         * the memory block being realloc'd is the
  483. X         * smallest possible.
  484. X         */
  485. X        if
  486. X        (
  487. X            (old_bucket = findbucket(op, 1)) == -1
  488. X        &&
  489. X            (old_bucket = findbucket(op, realloc_srchlen)) == -1
  490. X        )
  491. X            old_bucket = QUANTUM_NBITS;
  492. X    }
  493. X    old_nbytes = (1L << old_bucket) - sizeof(union overhead) - RSLOP;
  494. X
  495. X    /*
  496. X     * avoid the copy if same size block
  497. X     */
  498. X    if
  499. X    (
  500. X        was_alloced
  501. X    &&
  502. X        nbytes <= old_nbytes
  503. X    &&
  504. X        nbytes > (old_nbytes >> 1) - sizeof(union overhead) - RSLOP
  505. X    )
  506. X        return cp;
  507. X
  508. X    /*
  509. X     * grab another chunk
  510. X     */
  511. X    if(!(res = mem_alloc(nbytes)))
  512. X        return (char*)0;
  513. X    assert(cp != res, 11);
  514. X    memcpy(res, cp, (nbytes < old_nbytes) ? nbytes : old_nbytes);
  515. X    if(was_alloced)
  516. X        mem_free(cp);
  517. X    return res;
  518. X}
  519. X
  520. X#else /*!UNIX_MALLOC*/
  521. X
  522. X#undef MSTATS
  523. X
  524. X#endif /*!UNIX_MALLOC*/
  525. X
  526. X
  527. X
  528. X/*
  529. X * Allocate a new item from the specified free list.
  530. X * Returns NULL if no item can be allocated.
  531. X */
  532. XALLOCITEM *
  533. Xallocitem(fp)
  534. X    FREELIST *fp;        /* free list header */
  535. X{
  536. X    FREEITEM *ip;        /* allocated item */
  537. X
  538. X    if (fp->curfree > 0) {
  539. X        fp->curfree--;
  540. X        ip = fp->freelist;
  541. X        fp->freelist = ip->next;
  542. X        return (ALLOCITEM *) ip;
  543. X    }
  544. X    ip = (FREEITEM *) malloc(fp->itemsize);
  545. X    if (ip == NULL)
  546. X        return NULL;
  547. X    return (ALLOCITEM *) ip;
  548. X}
  549. X
  550. X
  551. X/*
  552. X * Free an item by placing it back on a free list.
  553. X * If too many items are on the list, it is really freed.
  554. X */
  555. Xvoid
  556. Xfreeitem(fp, ip)
  557. X    FREELIST *fp;        /* freelist header */
  558. X    FREEITEM *ip;        /* item to be freed */
  559. X{
  560. X    if (ip == NULL)
  561. X        return;
  562. X    if (fp->curfree >= fp->maxfree) {
  563. X        free((char *) ip);
  564. X        return;
  565. X    }
  566. X    ip->next = fp->freelist;
  567. X    fp->freelist = ip;
  568. X    fp->curfree++;
  569. X}
  570. X
  571. X
  572. X/*
  573. X * NAME
  574. X *    mem_stats - print memory statistics
  575. X *
  576. X * SYNOPSIS
  577. X *    void
  578. X *    mem_stats(s)
  579. X *    char * s;
  580. X *
  581. X * DESCRIPTION
  582. X *    Mem_stats is used to print out statistics about current memory usage.
  583. X *    ``s'' is the title string
  584. X *
  585. X *    Prints two lines of numbers, one showing the length of the free list
  586. X *    for each size category, the second showing the number of mallocs -
  587. X *    frees for each size category.
  588. X *
  589. X * RETURNS
  590. X *    void
  591. X */
  592. X/*ARGSUSED*/
  593. Xvoid
  594. Xmem_stats(s)
  595. X    char *    s;
  596. X{
  597. X#ifdef MSTATS
  598. X    register int    i, j;
  599. X    register union overhead *p;
  600. X    int    totfree = 0;
  601. X    int    totused = 0;
  602. X
  603. X    fprintf(stderr, "Memory allocation statistics %s\n", s);
  604. X    fprintf(stderr, "%11s:%12s%12s%12s\n", "Bucket", "In Use", "Free", "Sum");
  605. X    for (i = 0; i < NBUCKETS; i++)
  606. X    {
  607. X        for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
  608. X            ;
  609. X        if(!j && !nmalloc[i])
  610. X            continue;
  611. X        fprintf(stderr, "%11d:%12d%12d%12d\n", (1L<<i), nmalloc[i], j, j+nmalloc[i]);
  612. X        totfree += j * (1L << i);
  613. X        totused += nmalloc[i] * (1L << i);
  614. X    }
  615. X    fprintf(stderr, "%11s:%12d%12d%12d\n", "Totals", totused, totfree, totused+totfree);
  616. X#else
  617. X    fprintf(stderr, 
  618. X        "Memory allocation stats were not compiled into calc\n");
  619. X#endif
  620. X}
  621. X
  622. X#ifdef DEBUG
  623. Xvoid
  624. Xassertfailed(n)
  625. X{
  626. X    printf("Assertion %d failed\n", n);
  627. X    exit(1);
  628. X}
  629. X#endif
  630. X
  631. X/* END CODE */
  632. END_OF_FILE
  633. if test 13396 -ne `wc -c <'alloc.c'`; then
  634.     echo shar: \"'alloc.c'\" unpacked with wrong size!
  635. fi
  636. # end of 'alloc.c'
  637. fi
  638. if test -f 'math.h' -a "${1}" != "-c" ; then 
  639.   echo shar: Will not clobber existing file \"'math.h'\"
  640. else
  641. echo shar: Extracting \"'math.h'\" \(15034 characters\)
  642. sed "s/^X//" >'math.h' <<'END_OF_FILE'
  643. X/*
  644. X * Copyright (c) 1992 David I. Bell
  645. X * Permission is granted to use, distribute, or modify this source,
  646. X * provided that this copyright notice remains intact.
  647. X *
  648. X * Data structure declarations for extended precision arithmetic.
  649. X * The assumption made is that a long is 32 bits and shorts are 16 bits,
  650. X * and longs must be addressible on word boundaries.
  651. X */
  652. X
  653. X#include "alloc.h"
  654. X
  655. X#include "have_stdlib.h"
  656. X#ifdef HAVE_STDLIB_H
  657. X# include <stdlib.h>
  658. X#endif
  659. X
  660. X
  661. X#ifndef    NULL
  662. X#define    NULL    0
  663. X#endif
  664. X
  665. X/*#define ALLOCTEST 1*/
  666. X
  667. X#ifndef ALLOCTEST
  668. X# if defined(UNIX_MALLOC)
  669. X#  define freeh(p) { if ((p != _zeroval_) && (p != _oneval_)) free((void *)p); }
  670. X# else
  671. X#  define freeh(p) ((p == _zeroval_) || (p == _oneval_) || free(p))
  672. X# endif
  673. X#endif
  674. X
  675. Xtypedef    short FLAG;            /* small value (e.g. comparison) */
  676. Xtypedef unsigned short BOOL;        /* TRUE or FALSE value */
  677. X
  678. X#if !defined(TRUE)
  679. X#define    TRUE    ((BOOL) 1)            /* booleans */
  680. X#endif
  681. X#if !defined(FALSE)
  682. X#define    FALSE    ((BOOL) 0)
  683. X#endif
  684. X
  685. X
  686. X/*
  687. X * NOTE: FULL must be twice the storage size of a HALF
  688. X *     LEN storage size must be <= FULL storage size
  689. X */
  690. Xtypedef unsigned short HALF;        /* unit of number storage */
  691. Xtypedef unsigned long FULL;        /* double unit of number storage */
  692. Xtypedef long LEN;            /* unit of length storage */
  693. X
  694. X#define BASE    ((FULL) 65536)        /* base for calculations (2^16) */
  695. X#define BASE1    ((FULL) (BASE - 1))    /* one less than base */
  696. X#define BASEB    16            /* number of bits in base */
  697. X#define    BASEDIG    5            /* number of digits in base */
  698. X#define    MAXHALF    ((FULL) 0x7fff)        /* largest positive half value */
  699. X#define    MAXFULL    ((FULL) 0x7fffffff)    /* largest positive full value */
  700. X#define    TOPHALF    ((FULL) 0x8000)        /* highest bit in half value */
  701. X#define    TOPFULL    ((FULL) 0x80000000)    /* highest bit in full value */
  702. X#define MAXLEN    ((LEN)    0x7fffffff)    /* longest value allowed */
  703. X#define    MAXREDC    5            /* number of entries in REDC cache */
  704. X#define    SQ_ALG2    20            /* size for alternative squaring */
  705. X#define    MUL_ALG2 20            /* size for alternative multiply */
  706. X#define    POW_ALG2 40            /* size for using REDC for powers */
  707. X#define    REDC_ALG2 50            /* size for using alternative REDC */
  708. X
  709. X
  710. X
  711. Xtypedef union {
  712. X    FULL    ivalue;
  713. X    struct {
  714. X        HALF Svalue1;
  715. X        HALF Svalue2;
  716. X    } sis;
  717. X} SIUNION;
  718. X
  719. X
  720. X#ifdef LITTLE_ENDIAN
  721. X
  722. X#define silow    sis.Svalue1    /* low order half of full value */
  723. X#define sihigh    sis.Svalue2    /* high order half of full value */
  724. X
  725. X#else
  726. X
  727. X#define silow    sis.Svalue2    /* low order half of full value */
  728. X#define sihigh    sis.Svalue1    /* high order half of full value */
  729. X
  730. X#endif
  731. X
  732. X
  733. Xtypedef struct {
  734. X    HALF    *v;        /* pointer to array of values */
  735. X    LEN    len;        /* number of values in array */
  736. X    BOOL    sign;        /* sign, nonzero is negative */
  737. X} ZVALUE;
  738. X
  739. X
  740. X
  741. X/*
  742. X * Function prototypes for integer math routines.
  743. X */
  744. X#if defined(__STDC__)
  745. X#define proto(a) a
  746. X#else
  747. X#define proto(a) ()
  748. X#endif
  749. X
  750. Xextern HALF * alloc proto((LEN len));
  751. X#ifdef    ALLOCTEST
  752. Xextern void freeh proto((HALF *));
  753. X#endif
  754. X
  755. X
  756. Xextern long iigcd proto((long i1, long i2));
  757. Xextern void itoz proto((long i, ZVALUE * res));
  758. Xextern long ztoi proto((ZVALUE z));
  759. Xextern void zcopy proto((ZVALUE z, ZVALUE * res));
  760. Xextern void zadd proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  761. Xextern void zsub proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  762. Xextern void zmul proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  763. Xextern void zsquare proto((ZVALUE z, ZVALUE * res));
  764. Xextern void zreduce proto((ZVALUE z1, ZVALUE z2,
  765. X    ZVALUE * z1res, ZVALUE * z2res));
  766. Xextern void zdiv proto((ZVALUE z1, ZVALUE z2,
  767. X    ZVALUE * res, ZVALUE * rem));
  768. Xextern void zquo proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  769. Xextern void zmod proto((ZVALUE z1, ZVALUE z2, ZVALUE * rem));
  770. Xextern BOOL zdivides proto((ZVALUE z1, ZVALUE z2));
  771. Xextern void zor proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  772. Xextern void zand proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  773. Xextern void zxor proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  774. Xextern void zshift proto((ZVALUE z, long n, ZVALUE * res));
  775. Xextern long zlowbit proto((ZVALUE z));
  776. Xextern long zhighbit proto((ZVALUE z));
  777. Xextern BOOL zisset proto((ZVALUE z, long n));
  778. Xextern BOOL zisonebit proto((ZVALUE z));
  779. Xextern BOOL zisallbits proto((ZVALUE z));
  780. Xextern void zbitvalue proto((long n, ZVALUE * res));
  781. Xextern FLAG ztest proto((ZVALUE z));
  782. Xextern FLAG zrel proto((ZVALUE z1, ZVALUE z2));
  783. Xextern BOOL zcmp proto((ZVALUE z1, ZVALUE z2));
  784. Xextern void trim proto((ZVALUE * z));
  785. Xextern void shiftr proto((ZVALUE z, long n));
  786. Xextern void shiftl proto((ZVALUE z, long n));
  787. Xextern void zfact proto((ZVALUE z, ZVALUE * dest));
  788. Xextern void zpfact proto((ZVALUE z, ZVALUE * dest));
  789. Xextern void zlcmfact proto((ZVALUE z, ZVALUE * dest));
  790. Xextern void zperm proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  791. Xextern void zcomb proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  792. Xextern BOOL zprimetest proto((ZVALUE z, long count));
  793. Xextern FLAG zjacobi proto((ZVALUE z1, ZVALUE z2));
  794. Xextern void zfib proto((ZVALUE z, ZVALUE * res));
  795. Xextern void zpowi proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  796. Xextern void ztenpow proto((long power, ZVALUE * res));
  797. Xextern void zpowermod proto((ZVALUE z1, ZVALUE z2,
  798. X    ZVALUE z3, ZVALUE * res));
  799. Xextern BOOL zmodinv proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  800. Xextern void zgcd proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  801. Xextern void zlcm proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  802. Xextern BOOL zrelprime proto((ZVALUE z1, ZVALUE z2));
  803. Xextern long zlog proto((ZVALUE z1, ZVALUE z2));
  804. Xextern long zlog10 proto((ZVALUE z));
  805. Xextern long zdivcount proto((ZVALUE z1, ZVALUE z2));
  806. Xextern long zfacrem proto((ZVALUE z1, ZVALUE z2, ZVALUE * rem));
  807. Xextern void zgcdrem proto((ZVALUE z1, ZVALUE z2, ZVALUE * res));
  808. Xextern long zlowfactor proto((ZVALUE z, long count));
  809. Xextern long zdigits proto((ZVALUE z1));
  810. Xextern FLAG zdigit proto((ZVALUE z1, long n));
  811. Xextern BOOL zsqrt proto((ZVALUE z1, ZVALUE * dest));
  812. Xextern void zroot proto((ZVALUE z1, ZVALUE z2, ZVALUE * dest));
  813. Xextern BOOL zissquare proto((ZVALUE z));
  814. Xextern void zmuli proto((ZVALUE z, long n, ZVALUE *res));
  815. Xextern long zmodi proto((ZVALUE z, long n));
  816. Xextern long zdivi proto((ZVALUE z, long n, ZVALUE * res));
  817. Xextern HALF *zalloctemp proto((LEN len));
  818. X
  819. X#if 0
  820. Xextern void zapprox proto((ZVALUE z1, ZVALUE z2, ZVALUE* res1, ZVALUE* res2));
  821. X#endif
  822. X
  823. X
  824. X/*
  825. X * Modulo arithmetic definitions.
  826. X * Structure holding state of REDC initialization.
  827. X * Multiple instances of this structure can be used allowing
  828. X * calculations with more than one modulus at the same time.
  829. X * Len of zero means the structure is not initialized.
  830. X */
  831. Xtypedef    struct {
  832. X    LEN len;        /* number of words in binary modulus */
  833. X    ZVALUE mod;        /* modulus REDC is computing with */
  834. X    ZVALUE inv;        /* inverse of modulus in binary modulus */
  835. X    ZVALUE one;        /* REDC format for the number 1 */
  836. X} REDC;
  837. X
  838. X#if 0
  839. Xextern void zmulmod proto((ZVALUE z1, ZVALUE z2, ZVALUE z3, ZVALUE *res));
  840. Xextern void zsquaremod proto((ZVALUE z1, ZVALUE z2, ZVALUE *res));
  841. Xextern void zsubmod proto((ZVALUE z1, ZVALUE z2, ZVALUE z3, ZVALUE *res));
  842. X#endif
  843. Xextern void zminmod proto((ZVALUE z1, ZVALUE z2, ZVALUE *res));
  844. Xextern BOOL zcmpmod proto((ZVALUE z1, ZVALUE z2, ZVALUE z3));
  845. Xextern REDC *zredcalloc proto((ZVALUE z1));
  846. Xextern void zredcfree proto((REDC *rp));
  847. Xextern void zredcencode proto((REDC *rp, ZVALUE z1, ZVALUE *res));
  848. Xextern void zredcdecode proto((REDC *rp, ZVALUE z1, ZVALUE *res));
  849. Xextern void zredcmul proto((REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res));
  850. Xextern void zredcsquare proto((REDC *rp, ZVALUE z1, ZVALUE *res));
  851. Xextern void zredcpower proto((REDC *rp, ZVALUE z1, ZVALUE z2, ZVALUE *res));
  852. X
  853. X
  854. X/*
  855. X * Rational arithmetic definitions.
  856. X */
  857. Xtypedef struct {
  858. X    ZVALUE num, den;
  859. X    long links;
  860. X} NUMBER;
  861. X
  862. Xextern NUMBER *qadd(), *qsub(), *qmul(), *qdiv(), *qquo(), *qmod(), *qcomb();
  863. Xextern NUMBER *qsquare(), *qgcd(), *qlcm(), *qmin(), *qmax(), *qand(), *qor();
  864. Xextern NUMBER *qxor(), *qpowermod(), *qpowi(), *qpower(), *qneg(), *qsign();
  865. Xextern NUMBER *qfact(), *qpfact(), *qsqrt(), *qshift(), *qminv();
  866. Xextern NUMBER *qint(), *qfrac(), *qnum(), *qden(), *qinv(), *qabs(), *qroot();
  867. Xextern NUMBER *qfacrem(), *qcopy(), *atoq(), *itoq(), *iitoq();
  868. Xextern NUMBER *qperm(), *qgcdrem(), *qtrunc(), *qround(), *qalloc();
  869. Xextern NUMBER *qlowfactor(), *qfib(), *qcfappr(), *qcos(), *qsin(), *qexp();
  870. Xextern NUMBER *qscale(), *qln(), *qbtrunc(), *qbround(), *qisqrt();
  871. Xextern NUMBER *qtan(), *qacos(), *qasin(), *qatan(), *qatan2(), *qjacobi();
  872. Xextern NUMBER *qinc(), *qdec(), *qhypot(), *qcosh(), *qsinh(), *qtanh();
  873. Xextern NUMBER *qacosh(), *qasinh(), *qatanh(), *qlegtoleg(), *qiroot();
  874. Xextern NUMBER *qpi(), *qbappr(), *qdivi(), *qlcmfact(), *qminmod();
  875. Xextern NUMBER *qredcin(), *qredcout(), *qredcmul(), *qredcsquare();
  876. Xextern NUMBER *qredcpower();
  877. Xextern BOOL qcmp(), qcmpi(), qprimetest(), qissquare();
  878. Xextern BOOL qisset(), qcmpmod(), qquomod();
  879. Xextern FLAG qrel(), qreli(), qnear(), qdigit();
  880. Xextern long qtoi(), qprecision(), qplaces(), qdigits();
  881. Xextern long qilog2(), qilog10(), qparse();
  882. Xextern void qfreenum();
  883. Xextern void qprintnum();
  884. Xextern void setepsilon();
  885. X
  886. X#if 0
  887. Xextern NUMBER *qbitvalue(), *qmuli(), *qmulmod(), *qsquaremod();
  888. Xextern NUMBER *qaddmod(), *qsubmod(), *qreadval(), *qnegmod();
  889. Xextern BOOL qbittest();
  890. Xextern FLAG qtest();
  891. X#endif
  892. X
  893. X#ifdef CODE
  894. Xextern NUMBER *qaddi();
  895. X#endif
  896. X
  897. X
  898. X/*
  899. X * Complex arithmetic definitions.
  900. X */
  901. Xtypedef struct {
  902. X    NUMBER *real;        /* real part of number */
  903. X    NUMBER *imag;        /* imaginary part of number */
  904. X    long links;        /* link count */
  905. X} COMPLEX;
  906. X
  907. Xextern COMPLEX *cadd(), *csub(), *cmul(), *cdiv(), *csquare();
  908. Xextern COMPLEX *cneg(), *cinv();
  909. Xextern COMPLEX *comalloc(), *caddq(), *csubq(), *cmulq(), *cdivq();
  910. Xextern COMPLEX *cpowi(), *csqrt(), *cscale(), *cshift(), *cround();
  911. Xextern COMPLEX *cbround(), *cint(), *cfrac(), *croot(), *cexp(), *cln();
  912. Xextern COMPLEX *ccos(), *csin(), *cpolar(), *cpower(), *cmodq(), *cquoq();
  913. Xextern void comfree(), comprint();
  914. Xextern BOOL ccmp();
  915. Xextern void cprintfr();
  916. X
  917. X#if 0
  918. Xextern COMPLEX *cconj(), *creal(), *cimag(), *qqtoc();
  919. X#endif
  920. X
  921. X
  922. X/*
  923. X * macro expansions to speed this thing up
  924. X */
  925. X#define iseven(z)    (!(*(z).v & 01))
  926. X#define isodd(z)    (*(z).v & 01)
  927. X#define iszero(z)    ((*(z).v == 0) && ((z).len == 1))
  928. X#define isneg(z)    ((z).sign)
  929. X#define ispos(z)    (((z).sign == 0) && (*(z).v || ((z).len > 1)))
  930. X#define isunit(z)    ((*(z).v == 1) && ((z).len == 1))
  931. X#define isone(z)    ((*(z).v == 1) && ((z).len == 1) && !(z).sign)
  932. X#define isnegone(z)    ((*(z).v == 1) && ((z).len == 1) && (z).sign)
  933. X#define istwo(z)    ((*(z).v == 2) && ((z).len == 1) && !(z).sign)
  934. X#define isleone(z)    ((*(z).v <= 1) && ((z).len == 1))
  935. X#define istiny(z)    ((z).len == 1)
  936. X#define issmall(z)    (((z).len < 2) || (((z).len == 2) && (((short)(z).v[1]) >= 0)))
  937. X#define isbig(z)    (((z).len > 2) || (((z).len == 2) && (((short)(z).v[1]) < 0)))
  938. X#define z1tol(z)    ((long)((z).v[0]))
  939. X#define z2tol(z)    (((long)((z).v[0])) + \
  940. X                (((long)((z).v[1] & MAXHALF)) << BASEB))
  941. X
  942. X#define qiszero(q)    (iszero((q)->num))
  943. X#define qisneg(q)    (isneg((q)->num))
  944. X#define qispos(q)    (ispos((q)->num))
  945. X#define qisint(q)    (isunit((q)->den))
  946. X#define qisfrac(q)    (!isunit((q)->den))
  947. X#define qisunit(q)    (isunit((q)->num) && isunit((q)->den))
  948. X#define qisone(q)    (isone((q)->num) && isunit((q)->den))
  949. X#define qisnegone(q)    (isnegone((q)->num) && isunit((q)->den))
  950. X#define qistwo(q)    (istwo((q)->num) && isunit((q)->den))
  951. X#define qiseven(q)    (isunit((q)->den) && iseven((q)->num))
  952. X#define qisodd(q)    (isunit((q)->den) && isodd((q)->num))
  953. X#define qistwopower(q)    (isunit((q)->den) && zistwopower((q)->num))
  954. X#define qhighbit(q)    (zhighbit((q)->num))
  955. X#define qlowbit(q)    (zlowbit((q)->num))
  956. X#define qdivides(q1, q2)    (zdivides((q1)->num, (q2)->num))
  957. X#define qdivcount(q1, q2)    (zdivcount((q1)->num, (q2)->num))
  958. X#define qilog(q1, q2)    (zlog((q1)->num, (q2)->num))
  959. X#define qlink(q)    ((q)->links++, (q))
  960. X
  961. X#define qfree(q)    {if (--((q)->links) <= 0) qfreenum(q);}
  962. X#define quicktrim(z)    {if (((z).len > 1) && ((z).v[(z).len-1] == 0)) (z).len--;}
  963. X
  964. X#define cisreal(c)    (qiszero((c)->imag))
  965. X#define cisimag(c)    (qiszero((c)->real) && !cisreal(c))
  966. X#define ciszero(c)    (cisreal(c) && qiszero((c)->real))
  967. X#define cisone(c)    (cisreal(c) && qisone((c)->real))
  968. X#define cisnegone(c)    (cisreal(c) && qisnegone((c)->real))
  969. X#define cisrunit(c)    (cisreal(c) && qisunit((c)->real))
  970. X#define cisiunit(c)    (qiszero((c)->real) && qisunit((c)->imag))
  971. X#define cistwo(c)    (cisreal(c) && qistwo((c)->real))
  972. X#define cisint(c)    (qisint((c)->real) && qisint((c)->imag))
  973. X#define ciseven(c)    (qiseven((c)->real) && qiseven((c)->imag))
  974. X#define cisodd(c)    (qisodd((c)->real) || qisodd((c)->imag))
  975. X#define clink(c)    ((c)->links++, (c))
  976. X
  977. X#define    clearval(z)    memset((z).v, 0, (z).len * sizeof(HALF))
  978. X#define    copyval(z1, z2)    memcpy((z2).v, (z1).v, (z1).len * sizeof(HALF))
  979. X
  980. X
  981. X/*
  982. X * Flags for qparse calls
  983. X */
  984. X#define QPF_SLASH    0x1    /* allow slash for fractional number */
  985. X#define QPF_IMAG    0x2    /* allow trailing 'i' for imaginary number */
  986. X
  987. X
  988. X/*
  989. X * Output modes for numeric displays.
  990. X */
  991. X#define MODE_DEFAULT    0
  992. X#define MODE_FRAC    1
  993. X#define MODE_INT    2
  994. X#define MODE_REAL    3
  995. X#define MODE_EXP    4
  996. X#define MODE_HEX    5
  997. X#define MODE_OCTAL    6
  998. X#define MODE_BINARY    7
  999. X#define MODE_MAX    7
  1000. X
  1001. X#define MODE_INITIAL    MODE_REAL
  1002. X
  1003. X
  1004. X/*
  1005. X * Output routines for either FILE handles or strings.
  1006. X */
  1007. Xextern void math_chr(), math_str(), math_flush();
  1008. Xextern void divertio(), cleardiversions(), setfp();
  1009. Xextern char *getdivertedio();
  1010. Xextern void setmode();        /* set output mode for numeric output */
  1011. Xextern void setdigits();    /* set # of digits for float or exp output */
  1012. X
  1013. X#ifdef VARARGS
  1014. Xextern void math_fmt();
  1015. X#else
  1016. X# ifdef __STDC__
  1017. Xextern void math_fmt(char *, ...);
  1018. X# else
  1019. Xextern void math_fmt();
  1020. X# endif
  1021. X#endif
  1022. X
  1023. X/*
  1024. X * Print a formatted string containing arbitrary numbers, similar to printf.
  1025. X */
  1026. X#ifdef VARARGS
  1027. Xextern void qprintf();
  1028. X#else
  1029. X# ifdef __STDC__
  1030. Xextern void qprintf(char *, ...);
  1031. X# else
  1032. Xextern void qprintf();
  1033. X# endif
  1034. X#endif
  1035. X
  1036. X/*
  1037. X * constants used often by the arithmetic routines
  1038. X */
  1039. Xextern HALF _zeroval_[], _oneval_[], _twoval_[], _tenval_[];
  1040. Xextern ZVALUE _zero_, _one_, _ten_;
  1041. Xextern NUMBER _qzero_, _qone_, _qnegone_, _qonehalf_;
  1042. Xextern COMPLEX _czero_, _cone_;
  1043. X
  1044. X#if 0
  1045. Xextern NUMBER _conei_;
  1046. X#endif
  1047. X
  1048. Xextern BOOL _sinisneg_;        /* whether sin(x) < 0 (set by cos(x)) */
  1049. Xextern BOOL _math_abort_;    /* nonzero to abort calculations */
  1050. Xextern long _epsilonprec_;    /* binary precision of epsilon */
  1051. Xextern NUMBER *_epsilon_;    /* default error for real functions */
  1052. Xextern ZVALUE _tenpowers_[32];    /* table of 10^2^n */
  1053. Xextern long _outdigits_;    /* current output digits for float or exp */
  1054. Xextern int _outmode_;        /* current output mode */
  1055. Xextern LEN _mul2_;        /* size of number to use multiply algorithm 2 */
  1056. Xextern LEN _sq2_;        /* size of number to use square algorithm 2 */
  1057. Xextern LEN _pow2_;        /* size of modulus to use REDC for powers */
  1058. Xextern LEN _redc2_;        /* size of modulus to use REDC algorithm 2 */
  1059. Xextern HALF *bitmask;        /* bit rotation, norm 0 */
  1060. X
  1061. X#if 0
  1062. Xextern char *_mallocptr_;    /* pointer for malloc calls */
  1063. X#endif
  1064. X
  1065. X/*
  1066. X * misc function declarations - most to keep lint happy
  1067. X */
  1068. Xextern void initmasks();    /* init the bitmask rotation arrays */
  1069. X
  1070. X#ifdef VARARGS
  1071. Xvoid error();
  1072. X#else
  1073. X# ifdef __STDC__
  1074. Xvoid error(char *, ...);
  1075. X# else
  1076. Xvoid error();
  1077. X# endif
  1078. X#endif
  1079. X
  1080. X
  1081. X/* END CODE */
  1082. END_OF_FILE
  1083. if test 15034 -ne `wc -c <'math.h'`; then
  1084.     echo shar: \"'math.h'\" unpacked with wrong size!
  1085. fi
  1086. # end of 'math.h'
  1087. fi
  1088. if test -f 'obj.c' -a "${1}" != "-c" ; then 
  1089.   echo shar: Will not clobber existing file \"'obj.c'\"
  1090. else
  1091. echo shar: Extracting \"'obj.c'\" \(14633 characters\)
  1092. sed "s/^X//" >'obj.c' <<'END_OF_FILE'
  1093. X/*
  1094. X * Copyright (c) 1992 David I. Bell
  1095. X * Permission is granted to use, distribute, or modify this source,
  1096. X * provided that this copyright notice remains intact.
  1097. X *
  1098. X * "Object" handling primatives.
  1099. X * This simply means that user-specified routines are called to perform
  1100. X * the indicated operations.
  1101. X */
  1102. X
  1103. X#include "calc.h"
  1104. X#include "opcodes.h"
  1105. X#include "func.h"
  1106. X#include "symbol.h"
  1107. X#include "string.h"
  1108. X
  1109. X
  1110. X/*
  1111. X * Types of values returned by calling object routines.
  1112. X */
  1113. X#define A_VALUE    0    /* returns arbitrary value */
  1114. X#define A_INT    1    /* returns integer value */
  1115. X#define A_UNDEF    2    /* returns no value */
  1116. X
  1117. X/*
  1118. X * Error handling actions for when the function is undefined.
  1119. X */
  1120. X#define E_NONE    0    /* no special action */
  1121. X#define E_PRINT    1    /* print element */
  1122. X#define E_CMP    2    /* compare two values */
  1123. X#define E_TEST    3    /* test value for nonzero */
  1124. X#define E_POW    4    /* call generic power routine */
  1125. X#define E_ONE    5    /* return number 1 */
  1126. X#define E_INC    6    /* increment by one */
  1127. X#define E_DEC    7    /* decrement by one */
  1128. X#define E_SQUARE 8    /* square value */
  1129. X
  1130. X
  1131. Xstatic struct objectinfo {
  1132. X    short args;    /* number of arguments */
  1133. X    short retval;    /* type of return value */
  1134. X    short error;    /* special action on errors */
  1135. X    char *name;    /* name of function to call */
  1136. X    char *comment;    /* useful comment if any */
  1137. X} objectinfo[] = {
  1138. X    1, A_UNDEF, E_PRINT, "print",    "print value, default prints elements",
  1139. X    1, A_VALUE, E_ONE,   "one",    "multiplicative identity, default is 1",
  1140. X    1, A_INT,   E_TEST,  "test",    "logical test (false,true => 0,1), default tests elements",
  1141. X    2, A_VALUE, E_NONE,  "add",    NULL,
  1142. X    2, A_VALUE, E_NONE,  "sub",    NULL,
  1143. X    1, A_VALUE, E_NONE,  "neg",    "negative",
  1144. X    2, A_VALUE, E_NONE,  "mul",    NULL,
  1145. X    2, A_VALUE, E_NONE,  "div",    "non-integral division",
  1146. X    1, A_VALUE, E_NONE,  "inv",    "multiplicative inverse",
  1147. X    2, A_VALUE, E_NONE,  "abs",    "absolute value within given error",
  1148. X    1, A_VALUE, E_NONE,  "norm",    "square of absolute value",
  1149. X    1, A_VALUE, E_NONE,  "conj",    "conjugate",
  1150. X    2, A_VALUE, E_POW,   "pow",    "integer power, default does multiply, square, inverse",
  1151. X    1, A_INT,   E_NONE,  "sgn",    "sign of value (-1, 0, 1)",
  1152. X    2, A_INT,   E_CMP,   "cmp",    "equality (equal,nonequal => 0,1), default tests elements",
  1153. X    2, A_INT,   E_NONE,  "rel",    "inequality (less,equal,greater => -1,0,1)",
  1154. X    2, A_VALUE, E_NONE,  "quo",    "integer quotient",
  1155. X    2, A_VALUE, E_NONE,  "mod",    "remainder of division",
  1156. X    1, A_VALUE, E_NONE,  "int",    "integer part",
  1157. X    1, A_VALUE, E_NONE,  "frac",    "fractional part",
  1158. X    1, A_VALUE, E_INC,   "inc",    "increment, default adds 1",
  1159. X    1, A_VALUE, E_DEC,   "dec",    "decrement, default subtracts 1",
  1160. X    1, A_VALUE, E_SQUARE,"square",    "default multiplies by itself",
  1161. X    2, A_VALUE, E_NONE,  "scale",    "multiply by power of 2",
  1162. X    2, A_VALUE, E_NONE,  "shift",    "shift left by n bits (right if negative)",
  1163. X    2, A_VALUE, E_NONE,  "round",    "round to given number of decimal places",
  1164. X    2, A_VALUE, E_NONE,  "bround",    "round to given number of binary places",
  1165. X    3, A_VALUE, E_NONE,  "root",    "root of value within given error",
  1166. X    2, A_VALUE, E_NONE,  "sqrt",    "square root within given error",
  1167. X    0, 0, 0, NULL
  1168. X};
  1169. X
  1170. X
  1171. Xstatic STRINGHEAD objectnames;    /* names of objects */
  1172. Xstatic STRINGHEAD elements;    /* element names for parts of objects */
  1173. Xstatic OBJECTACTIONS *objects[MAXOBJECTS]; /* table of actions for objects */
  1174. X
  1175. X
  1176. X/*
  1177. X * Free list of usual small objects.
  1178. X */
  1179. Xstatic FREELIST    freelist = {
  1180. X    sizeof(OBJECT),        /* size of typical objects */
  1181. X    100            /* number of free objects to keep */
  1182. X};
  1183. X
  1184. X
  1185. Xstatic VALUE objpowi();
  1186. Xstatic BOOL objtest(), objcmp();
  1187. Xstatic void objprint();
  1188. X
  1189. X
  1190. X/*
  1191. X * Show all the routine names available for objects.
  1192. X */
  1193. Xvoid
  1194. Xshowobjfuncs()
  1195. X{
  1196. X    register struct objectinfo *oip;
  1197. X
  1198. X    printf("\nThe following object routines are definable.\n");
  1199. X    printf("Note: xx represents the actual object type name.\n\n");
  1200. X    printf("Name    Args    Comments\n");
  1201. X    for (oip = objectinfo; oip->name; oip++) {
  1202. X        printf("xx_%-8s %d    %s\n", oip->name, oip->args,
  1203. X            oip->comment ? oip->comment : "");
  1204. X    }
  1205. X    printf("\n");
  1206. X}
  1207. X
  1208. X
  1209. X/*
  1210. X * Call the appropriate user-defined routine to handle an object action.
  1211. X * Returns the value that the routine returned.
  1212. X */
  1213. X/*VARARGS*/
  1214. XVALUE
  1215. Xobjcall(action, v1, v2, v3)
  1216. X    VALUE *v1, *v2, *v3;
  1217. X{
  1218. X    FUNC *fp;        /* function to call */
  1219. X    OBJECTACTIONS *oap;    /* object to call for */
  1220. X    struct objectinfo *oip;    /* information about action */
  1221. X    long index;        /* index of function (negative if undefined) */
  1222. X    VALUE val;        /* return value */
  1223. X    VALUE tmp;        /* temp value */
  1224. X    char name[SYMBOLSIZE+1];    /* full name of user routine to call */
  1225. X
  1226. X    if ((unsigned)action > OBJ_MAXFUNC)
  1227. X        error("Illegal action for object call");
  1228. X    oip = &objectinfo[action];
  1229. X    if (v1->v_type == V_OBJ)
  1230. X        oap = v1->v_obj->o_actions;
  1231. X    else if (v2->v_type == V_OBJ)
  1232. X        oap = v2->v_obj->o_actions;
  1233. X    else
  1234. X        error("Object routine called with non-object");
  1235. X    index = oap->actions[action];
  1236. X    if (index == 0) {
  1237. X        strcpy(name, oap->name);
  1238. X        strcat(name, "_");
  1239. X        strcat(name, oip->name);
  1240. X        index = adduserfunc(name);
  1241. X        oap->actions[action] = index;
  1242. X    }
  1243. X    fp = NULL;
  1244. X    if (index > 0)
  1245. X        fp = findfunc(index);
  1246. X    if (fp == NULL) {
  1247. X        switch (oip->error) {
  1248. X            case E_PRINT:
  1249. X                objprint(v1->v_obj);
  1250. X                val.v_type = V_NULL;
  1251. X                break;
  1252. X            case E_CMP:
  1253. X                val.v_type = V_INT;
  1254. X                if (v1->v_type != v2->v_type) {
  1255. X                    val.v_int = 1;
  1256. X                    return val;
  1257. X                }
  1258. X                val.v_int = objcmp(v1->v_obj, v2->v_obj);
  1259. X                break;
  1260. X            case E_TEST:
  1261. X                val.v_type = V_INT;
  1262. X                val.v_int = objtest(v1->v_obj);
  1263. X                break;
  1264. X            case E_POW:
  1265. X                if (v2->v_type != V_NUM)
  1266. X                    error("Non-real power");
  1267. X                val = objpowi(v1, v2->v_num);
  1268. X                break;
  1269. X            case E_ONE:
  1270. X                val.v_type = V_NUM;
  1271. X                val.v_num = qlink(&_qone_);
  1272. X                break;
  1273. X            case E_INC:
  1274. X                tmp.v_type = V_NUM;
  1275. X                tmp.v_num = &_qone_;
  1276. X                val = objcall(OBJ_ADD, v1, &tmp);
  1277. X                break;
  1278. X            case E_DEC:
  1279. X                tmp.v_type = V_NUM;
  1280. X                tmp.v_num = &_qone_;
  1281. X                val = objcall(OBJ_SUB, v1, &tmp);
  1282. X                break;
  1283. X            case E_SQUARE:
  1284. X                val = objcall(OBJ_MUL, v1, v1);
  1285. X                break;
  1286. X            default:
  1287. X                error("Function \"%s\" is undefined", namefunc(index));
  1288. X        }
  1289. X        return val;
  1290. X    }
  1291. X    switch (oip->args) {
  1292. X        case 0:
  1293. X            break;
  1294. X        case 1:
  1295. X            ++stack;
  1296. X            stack->v_addr = v1;
  1297. X            stack->v_type = V_ADDR;
  1298. X            break;
  1299. X        case 2:
  1300. X            ++stack;
  1301. X            stack->v_addr = v1;
  1302. X            stack->v_type = V_ADDR;
  1303. X            ++stack;
  1304. X            stack->v_addr = v2;
  1305. X            stack->v_type = V_ADDR;
  1306. X            break;
  1307. X        case 3:
  1308. X            ++stack;
  1309. X            stack->v_addr = v1;
  1310. X            stack->v_type = V_ADDR;
  1311. X            ++stack;
  1312. X            stack->v_addr = v2;
  1313. X            stack->v_type = V_ADDR;
  1314. X            ++stack;
  1315. X            stack->v_addr = v3;
  1316. X            stack->v_type = V_ADDR;
  1317. X            break;
  1318. X        default:
  1319. X            error("Bad number of args to calculate");
  1320. X    }
  1321. X    calculate(fp, oip->args);
  1322. X    switch (oip->retval) {
  1323. X        case A_VALUE:
  1324. X            return *stack--;
  1325. X        case A_UNDEF:
  1326. X            freevalue(stack--);
  1327. X            val.v_type = V_NULL;
  1328. X            break;
  1329. X        case A_INT:
  1330. X            if ((stack->v_type != V_NUM) || qisfrac(stack->v_num))
  1331. X                error("Integer return value required");
  1332. X            index = qtoi(stack->v_num);
  1333. X            qfree(stack->v_num);
  1334. X            stack--;
  1335. X            val.v_type = V_INT;
  1336. X            val.v_int = index;
  1337. X            break;
  1338. X        default:
  1339. X            error("Bad object return");
  1340. X    }
  1341. X    return val;
  1342. X}
  1343. X
  1344. X
  1345. X/*
  1346. X * Routine called to clear the cache of known undefined functions for
  1347. X * the objects.  This changes negative indices back into positive ones
  1348. X * so that they will all be checked for existence again.
  1349. X */
  1350. Xvoid
  1351. Xobjuncache()
  1352. X{
  1353. X    register int *ip;
  1354. X    int i, j;
  1355. X
  1356. X    i = objectnames.h_count;
  1357. X    while (--i >= 0) {
  1358. X        ip = objects[i]->actions;
  1359. X        for (j = OBJ_MAXFUNC; j-- >= 0; ip++)
  1360. X            if (*ip < 0)
  1361. X                *ip = -*ip;
  1362. X    }
  1363. X}
  1364. X
  1365. X
  1366. X/*
  1367. X * Print the elements of an object in short and unambiguous format.
  1368. X * This is the default routine if the user's is not defined.
  1369. X */
  1370. Xstatic void
  1371. Xobjprint(op)
  1372. X    OBJECT *op;        /* object being printed */
  1373. X{
  1374. X    int count;        /* number of elements */
  1375. X    int i;            /* index */
  1376. X
  1377. X    count = op->o_actions->count;
  1378. X    math_fmt("obj %s {", op->o_actions->name);
  1379. X    for (i = 0; i < count; i++) {
  1380. X        if (i)
  1381. X            math_str(", ");
  1382. X        printvalue(&op->o_table[i], PRINT_SHORT | PRINT_UNAMBIG);
  1383. X    }
  1384. X    math_chr('}');
  1385. X}
  1386. X
  1387. X
  1388. X/*
  1389. X * Test an object for being "nonzero".
  1390. X * This is the default routine if the user's is not defined.
  1391. X * Returns TRUE if any of the elements are "nonzero".
  1392. X */
  1393. Xstatic BOOL
  1394. Xobjtest(op)
  1395. X    OBJECT *op;
  1396. X{
  1397. X    int i;            /* loop counter */
  1398. X
  1399. X    i = op->o_actions->count;
  1400. X    while (--i >= 0) {
  1401. X        if (testvalue(&op->o_table[i]))
  1402. X            return TRUE;
  1403. X    }
  1404. X    return FALSE;
  1405. X}
  1406. X
  1407. X
  1408. X/*
  1409. X * Compare two objects for equality, returning TRUE if they differ.
  1410. X * This is the default routine if the user's is not defined.
  1411. X * For equality, all elements must be equal.
  1412. X */
  1413. Xstatic BOOL
  1414. Xobjcmp(op1, op2)
  1415. X    OBJECT *op1, *op2;
  1416. X{
  1417. X    int i;            /* loop counter */
  1418. X
  1419. X    if (op1->o_actions != op2->o_actions)
  1420. X        return TRUE;
  1421. X    i = op1->o_actions->count;
  1422. X    while (--i >= 0) {
  1423. X        if (comparevalue(&op1->o_table[i], &op2->o_table[i]))
  1424. X            return TRUE;
  1425. X    }
  1426. X    return FALSE;
  1427. X}
  1428. X
  1429. X
  1430. X/*
  1431. X * Raise an object to an integral power.
  1432. X * This is the default routine if the user's is not defined.
  1433. X * Negative powers mean the positive power of the inverse.
  1434. X * Zero means the multiplicative identity.
  1435. X */
  1436. Xstatic VALUE
  1437. Xobjpowi(vp, q)
  1438. X    VALUE *vp;        /* value to be powered */
  1439. X    NUMBER *q;        /* power to raise number to */
  1440. X{
  1441. X    VALUE res, tmp;
  1442. X    long power;        /* power to raise to */
  1443. X    unsigned long bit;    /* current bit value */
  1444. X
  1445. X    if (qisfrac(q))
  1446. X        error("Raising object to non-integral power");
  1447. X    if (isbig(q->num))
  1448. X        error("Raising object to very large power");
  1449. X    power = (istiny(q->num) ? z1tol(q->num) : z2tol(q->num));
  1450. X    if (qisneg(q))
  1451. X        power = -power;
  1452. X    /*
  1453. X     * Handle some low powers specially
  1454. X     */
  1455. X    if ((power <= 2) && (power >= -2)) {
  1456. X        switch ((int) power) {
  1457. X            case 0:
  1458. X                return objcall(OBJ_ONE, vp);
  1459. X            case 1:
  1460. X                res.v_obj = objcopy(vp->v_obj);
  1461. X                res.v_type = V_OBJ;
  1462. X                return res;
  1463. X            case -1:
  1464. X                return objcall(OBJ_INV, vp);
  1465. X            case 2:
  1466. X                return objcall(OBJ_SQUARE, vp);
  1467. X        }
  1468. X    }
  1469. X    if (power < 0)
  1470. X        power = -power;
  1471. X    /*
  1472. X     * Compute the power by squaring and multiplying.
  1473. X     * This uses the left to right method of power raising.
  1474. X     */
  1475. X    bit = TOPFULL;
  1476. X    while ((bit & power) == 0)
  1477. X        bit >>= 1L;
  1478. X    bit >>= 1L;
  1479. X    res = objcall(OBJ_SQUARE, vp);
  1480. X    if (bit & power) {
  1481. X        tmp = objcall(OBJ_MUL, &res, vp);
  1482. X        objfree(res.v_obj);
  1483. X        res = tmp;
  1484. X    }
  1485. X    bit >>= 1L;
  1486. X    while (bit) {
  1487. X        tmp = objcall(OBJ_SQUARE, &res);
  1488. X        objfree(res.v_obj);
  1489. X        res = tmp;
  1490. X        if (bit & power) {
  1491. X            tmp = objcall(OBJ_MUL, &res, vp);
  1492. X            objfree(res.v_obj);
  1493. X            res = tmp;
  1494. X        }
  1495. X        bit >>= 1L;
  1496. X    }
  1497. X    if (qisneg(q)) {
  1498. X        tmp = objcall(OBJ_INV, &res);
  1499. X        objfree(res.v_obj);
  1500. X        return tmp;
  1501. X    }
  1502. X    return res;
  1503. X}
  1504. X
  1505. X
  1506. X/*
  1507. X * Define a (possibly) new class of objects.
  1508. X * Returns the index of the object name which identifies it.
  1509. X * This index can then be used to reference the object actions.
  1510. X * The list of indexes for the element names is also specified here,
  1511. X * and the number of elements defined for the object.
  1512. X */
  1513. Xdefineobject(name, indices, count)
  1514. X    char *name;        /* name of object type */
  1515. X    int indices[];        /* table of indices for elements */
  1516. X{
  1517. X    OBJECTACTIONS *oap;    /* object definition structure */
  1518. X    STRINGHEAD *hp;
  1519. X    int index;
  1520. X
  1521. X    hp = &objectnames;
  1522. X    if (hp->h_list == NULL)
  1523. X        initstr(hp);
  1524. X    index = findstr(hp, name);
  1525. X    if (index >= 0)
  1526. X        error("Object type \"%s\" is already defined", name);
  1527. X    if (hp->h_count >= MAXOBJECTS)
  1528. X        error("Too many object types in use");
  1529. X    oap = (OBJECTACTIONS *) malloc(objectactionsize(count));
  1530. X    if (oap)
  1531. X        name = addstr(hp, name);
  1532. X    if ((oap == NULL) || (name == NULL))
  1533. X        error("Cannot allocate object type");
  1534. X    oap->name = name;
  1535. X    oap->count = count;
  1536. X    for (index = OBJ_MAXFUNC; index >= 0; index--)
  1537. X        oap->actions[index] = 0;
  1538. X    for (index = 0; index < count; index++)
  1539. X        oap->elements[index] = indices[index];
  1540. X    index = findstr(hp, name);
  1541. X    objects[index] = oap;
  1542. X    return index;
  1543. X}
  1544. X
  1545. X
  1546. X/*
  1547. X * Check an object name to see if it is currently defined.
  1548. X * If so, the index for the object type is returned.
  1549. X * If the object name is currently unknown, then -1 is returned.
  1550. X */
  1551. Xcheckobject(name)
  1552. X    char *name;
  1553. X{
  1554. X    STRINGHEAD *hp;
  1555. X
  1556. X    hp = &objectnames;
  1557. X    if (hp->h_list == NULL)
  1558. X        return -1;
  1559. X    return findstr(hp, name);
  1560. X}
  1561. X
  1562. X
  1563. X/*
  1564. X * Define a (possibly) new element name for an object.
  1565. X * Returns an index which identifies the element name.
  1566. X */
  1567. Xaddelement(name)
  1568. X    char *name;
  1569. X{
  1570. X    STRINGHEAD *hp;
  1571. X    int index;
  1572. X
  1573. X    hp = &elements;
  1574. X    if (hp->h_list == NULL)
  1575. X        initstr(hp);
  1576. X    index = findstr(hp, name);
  1577. X    if (index >= 0)
  1578. X        return index;
  1579. X    if (addstr(hp, name) == NULL)
  1580. X        error("Cannot allocate element name");
  1581. X    return findstr(hp, name);
  1582. X}
  1583. X
  1584. X
  1585. X/*
  1586. X * Return the index which identifies an element name.
  1587. X * Returns minus one if the element name is unknown.
  1588. X */
  1589. Xfindelement(name)
  1590. X    char *name;        /* element name */
  1591. X{
  1592. X    if (elements.h_list == NULL)
  1593. X        return -1;
  1594. X    return findstr(&elements, name);
  1595. X}
  1596. X
  1597. X
  1598. X/*
  1599. X * Return the value table offset to be used for an object element name.
  1600. X * This converts the element index from the element table into an offset
  1601. X * into the object value array.  Returns -1 if the element index is unknown.
  1602. X */
  1603. Xobjoffset(op, index)
  1604. X    OBJECT *op;
  1605. X    long index;
  1606. X{
  1607. X    register OBJECTACTIONS *oap;
  1608. X    int offset;            /* offset into value array */
  1609. X
  1610. X    oap = op->o_actions;
  1611. X    for (offset = oap->count - 1; offset >= 0; offset--) {
  1612. X        if (oap->elements[offset] == index)
  1613. X            return offset;
  1614. X    }
  1615. X    return -1;
  1616. X}
  1617. X
  1618. X
  1619. X/*
  1620. X * Allocate a new object structure with the specified index.
  1621. X */
  1622. XOBJECT *
  1623. Xobjalloc(index)
  1624. X    long index;
  1625. X{
  1626. X    OBJECTACTIONS *oap;
  1627. X    OBJECT *op;
  1628. X    VALUE *vp;
  1629. X    int i;
  1630. X
  1631. X    if ((unsigned) index >= MAXOBJECTS)
  1632. X        error("Allocating bad object index");
  1633. X    oap = objects[index];
  1634. X    if (oap == NULL)
  1635. X        error("Object type not defined");
  1636. X    i = oap->count;
  1637. X    if (i < USUAL_ELEMENTS)
  1638. X        i = USUAL_ELEMENTS;
  1639. X    if (i == USUAL_ELEMENTS)
  1640. X        op = (OBJECT *) allocitem(&freelist);
  1641. X    else
  1642. X        op = (OBJECT *) malloc(objectsize(i));
  1643. X    if (op == NULL)
  1644. X        error("Cannot allocate object");
  1645. X    op->o_actions = oap;
  1646. X    vp = op->o_table;
  1647. X    for (i = oap->count; i-- > 0; vp++)
  1648. X        vp->v_type = V_NULL;
  1649. X    return op;
  1650. X}
  1651. X
  1652. X
  1653. X/*
  1654. X * Free an object structure.
  1655. X */
  1656. Xvoid
  1657. Xobjfree(op)
  1658. X    register OBJECT *op;
  1659. X{
  1660. X    VALUE *vp;
  1661. X    int i;
  1662. X
  1663. X    vp = op->o_table;
  1664. X    for (i = op->o_actions->count; i-- > 0; vp++) {
  1665. X        if (vp->v_type == V_NUM) {
  1666. X            qfree(vp->v_num);
  1667. X        } else
  1668. X            freevalue(vp);
  1669. X    }
  1670. X    if (op->o_actions->count <= USUAL_ELEMENTS)
  1671. X        freeitem(&freelist, (FREEITEM *) op);
  1672. X    else
  1673. X        free((char *) op);
  1674. X}
  1675. X
  1676. X
  1677. X/*
  1678. X * Copy an object value
  1679. X */
  1680. XOBJECT *
  1681. Xobjcopy(op)
  1682. X    OBJECT *op;
  1683. X{
  1684. X    VALUE *v1, *v2;
  1685. X    OBJECT *np;
  1686. X    int i;
  1687. X
  1688. X    i = op->o_actions->count;
  1689. X    if (i < USUAL_ELEMENTS)
  1690. X        i = USUAL_ELEMENTS;
  1691. X    if (i == USUAL_ELEMENTS)
  1692. X        np = (OBJECT *) allocitem(&freelist);
  1693. X    else
  1694. X        np = (OBJECT *) malloc(objectsize(i));
  1695. X    if (np == NULL)
  1696. X        error("Cannot allocate object");
  1697. X    np->o_actions = op->o_actions;
  1698. X    v1 = op->o_table;
  1699. X    v2 = np->o_table;
  1700. X    for (i = op->o_actions->count; i-- > 0; v1++, v2++) {
  1701. X        if (v1->v_type == V_NUM) {
  1702. X            v2->v_num = qlink(v1->v_num);
  1703. X            v2->v_type = V_NUM;
  1704. X        } else
  1705. X            copyvalue(v1, v2);
  1706. X    }
  1707. X    return np;
  1708. X}
  1709. X
  1710. X/* END CODE */
  1711. END_OF_FILE
  1712. if test 14633 -ne `wc -c <'obj.c'`; then
  1713.     echo shar: \"'obj.c'\" unpacked with wrong size!
  1714. fi
  1715. # end of 'obj.c'
  1716. fi
  1717. echo shar: End of archive 7 \(of 21\).
  1718. cp /dev/null ark7isdone
  1719. MISSING=""
  1720. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 ; do
  1721.     if test ! -f ark${I}isdone ; then
  1722.     MISSING="${MISSING} ${I}"
  1723.     fi
  1724. done
  1725. if test "${MISSING}" = "" ; then
  1726.     echo You have unpacked all 21 archives.
  1727.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  1728. else
  1729.     echo You still need to unpack the following archives:
  1730.     echo "        " ${MISSING}
  1731. fi
  1732. ##  End of shell archive.
  1733. exit 0
  1734.