home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume27 / calc-2.9.0 / part04 < prev    next >
Text File  |  1993-12-07  |  60KB  |  2,311 lines

  1. Newsgroups: comp.sources.unix
  2. From: dbell@canb.auug.org.au (David I. Bell)
  3. Subject: v27i131: calc-2.9.0 - arbitrary precision C-like programmable calculator, Part04/19
  4. References: <1.755316719.21314@gw.home.vix.com>
  5. Sender: unix-sources-moderator@gw.home.vix.com
  6. Approved: vixie@gw.home.vix.com
  7.  
  8. Submitted-By: dbell@canb.auug.org.au (David I. Bell)
  9. Posting-Number: Volume 27, Issue 131
  10. Archive-Name: calc-2.9.0/part04
  11.  
  12. #!/bin/sh
  13. # this is part 4 of a multipart archive
  14. # do not concatenate these parts, unpack them in order with /bin/sh
  15. # file calc2.9.0/config.c continued
  16. #
  17. CurArch=4
  18. if test ! -r s2_seq_.tmp
  19. then echo "Please unpack part 1 first!"
  20.      exit 1; fi
  21. ( read Scheck
  22.   if test "$Scheck" != $CurArch
  23.   then echo "Please unpack part $Scheck next!"
  24.        exit 1;
  25.   else exit 0; fi
  26. ) < s2_seq_.tmp || exit 1
  27. echo "x - Continuing file calc2.9.0/config.c"
  28. sed 's/^X//' << 'SHAR_EOF' >> calc2.9.0/config.c
  29. X            maxprint = temp;
  30. X            break;
  31. X
  32. X        case CONFIG_MUL2:
  33. X            if (vp->v_type != V_NUM)
  34. X                math_error("Non-numeric for mul2");
  35. X            q = vp->v_num;
  36. X            temp = qtoi(q);
  37. X            if (qisfrac(q) || qisneg(q))
  38. X                temp = -1;
  39. X            if (temp == 0)
  40. X                temp = MUL_ALG2;
  41. X            if (temp < 2)
  42. X                math_error("Illegal mul2 value");
  43. X            _mul2_ = temp;
  44. X            break;
  45. X
  46. X        case CONFIG_SQ2:
  47. X            if (vp->v_type != V_NUM)
  48. X                math_error("Non-numeric for sq2");
  49. X            q = vp->v_num;
  50. X            temp = qtoi(q);
  51. X            if (qisfrac(q) || qisneg(q))
  52. X                temp = -1;
  53. X            if (temp == 0)
  54. X                temp = SQ_ALG2;
  55. X            if (temp < 2)
  56. X                math_error("Illegal sq2 value");
  57. X            _sq2_ = temp;
  58. X            break;
  59. X
  60. X        case CONFIG_POW2:
  61. X            if (vp->v_type != V_NUM)
  62. X                math_error("Non-numeric for pow2");
  63. X            q = vp->v_num;
  64. X            temp = qtoi(q);
  65. X            if (qisfrac(q) || qisneg(q))
  66. X                temp = -1;
  67. X            if (temp == 0)
  68. X                temp = POW_ALG2;
  69. X            if (temp < 1)
  70. X                math_error("Illegal pow2 value");
  71. X            _pow2_ = temp;
  72. X            break;
  73. X
  74. X        case CONFIG_REDC2:
  75. X            if (vp->v_type != V_NUM)
  76. X                math_error("Non-numeric for redc2");
  77. X            q = vp->v_num;
  78. X            temp = qtoi(q);
  79. X            if (qisfrac(q) || qisneg(q))
  80. X                temp = -1;
  81. X            if (temp == 0)
  82. X                temp = REDC_ALG2;
  83. X            if (temp < 1)
  84. X                math_error("Illegal redc2 value");
  85. X            _redc2_ = temp;
  86. X            break;
  87. X
  88. X        default:
  89. X            math_error("Setting illegal config parameter");
  90. X    }
  91. X}
  92. X
  93. X
  94. X/*
  95. X * Get the current value of the specified configuration type.
  96. X * An error is generated if the type number is illegal.
  97. X */
  98. Xvoid
  99. Xgetconfig(type, vp)
  100. X    VALUE *vp;
  101. X{
  102. X    switch (type) {
  103. X        case CONFIG_TRACE:
  104. X            vp->v_type = V_NUM;
  105. X            vp->v_num = itoq((long) traceflags);
  106. X            break;
  107. X
  108. X        case CONFIG_DISPLAY:
  109. X            vp->v_type = V_NUM;
  110. X            vp->v_num = itoq(_outdigits_);
  111. X            break;
  112. X
  113. X        case CONFIG_MODE:
  114. X            vp->v_type = V_STR;
  115. X            vp->v_subtype = V_STRLITERAL;
  116. X            vp->v_str = modename(_outmode_);
  117. X            break;
  118. X
  119. X        case CONFIG_EPSILON:
  120. X            vp->v_type = V_NUM;
  121. X            vp->v_num = qlink(_epsilon_);
  122. X            break;
  123. X
  124. X        case CONFIG_MAXPRINT:
  125. X            vp->v_type = V_NUM;
  126. X            vp->v_num = itoq(maxprint);
  127. X            break;
  128. X
  129. X        case CONFIG_MUL2:
  130. X            vp->v_type = V_NUM;
  131. X            vp->v_num = itoq(_mul2_);
  132. X            break;
  133. X
  134. X        case CONFIG_SQ2:
  135. X            vp->v_type = V_NUM;
  136. X            vp->v_num = itoq(_sq2_);
  137. X            break;
  138. X
  139. X        case CONFIG_POW2:
  140. X            vp->v_type = V_NUM;
  141. X            vp->v_num = itoq(_pow2_);
  142. X            break;
  143. X
  144. X        case CONFIG_REDC2:
  145. X            vp->v_type = V_NUM;
  146. X            vp->v_num = itoq(_redc2_);
  147. X            break;
  148. X
  149. X        default:
  150. X            math_error("Getting illegal config parameter");
  151. X    }
  152. X}
  153. X
  154. X/* END CODE */
  155. SHAR_EOF
  156. echo "File calc2.9.0/config.c is complete"
  157. chmod 0644 calc2.9.0/config.c || echo "restore of calc2.9.0/config.c fails"
  158. set `wc -c calc2.9.0/config.c`;Sum=$1
  159. if test "$Sum" != "5922"
  160. then echo original size 5922, current size $Sum;fi
  161. echo "x - extracting calc2.9.0/const.c (Text)"
  162. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/const.c &&
  163. X/*
  164. X * Copyright (c) 1993 David I. Bell
  165. X * Permission is granted to use, distribute, or modify this source,
  166. X * provided that this copyright notice remains intact.
  167. X *
  168. X * Constant number storage module.
  169. X */
  170. X
  171. X#include "calc.h"
  172. X
  173. X#define CONSTALLOCSIZE 400    /* number of constants to allocate */
  174. X
  175. X
  176. Xstatic long constcount;        /* number of constants defined */
  177. Xstatic long constavail;        /* number of constants available */
  178. Xstatic NUMBER **consttable;    /* table of constants */
  179. X
  180. X
  181. X/*
  182. X * Read in a constant number and add it to the table of constant numbers,
  183. X * creating a new entry if necessary.  The incoming number is a string
  184. X * value which must have a correct format, otherwise an undefined number
  185. X * will result.  Returns the index of the number in the constant table.
  186. X * Returns zero if the number could not be saved.
  187. X */
  188. Xlong
  189. Xaddnumber(str)
  190. X    char *str;        /* string representation of number */
  191. X{
  192. X    NUMBER *q;
  193. X
  194. X    q = atoq(str);
  195. X    if (q == NULL)
  196. X        return 0;
  197. X    return addqconstant(q);
  198. X}
  199. X
  200. X
  201. X/*
  202. X * Add a particular number to the constant table.
  203. X * Returns the index of the number in the constant table, or zero
  204. X * if the number could not be saved.  The incoming number if freed
  205. X * if it is already in the table.
  206. X */
  207. Xlong
  208. Xaddqconstant(q)
  209. X    register NUMBER *q;    /* number to be added */
  210. X{
  211. X    register NUMBER **tp;    /* pointer to current number */
  212. X    register NUMBER *t;    /* number being tested */
  213. X    long index;        /* index into constant table */
  214. X    long numlen;        /* numerator length */
  215. X    long denlen;        /* denominator length */
  216. X    HALF numlow;        /* bottom value of numerator */
  217. X    HALF denlow;        /* bottom value of denominator */
  218. X
  219. X    numlen = q->num.len;
  220. X    denlen = q->den.len;
  221. X    numlow = q->num.v[0];
  222. X    denlow = q->den.v[0];
  223. X    tp = &consttable[1];
  224. X    for (index = 1; index <= constcount; index++) {
  225. X        t = *tp++;
  226. X        if ((numlen != t->num.len) || (numlow != t->num.v[0]))
  227. X            continue;
  228. X        if ((denlen != t->den.len) || (denlow != t->den.v[0]))
  229. X            continue;
  230. X        if (q->num.sign != t->num.sign)
  231. X            continue;
  232. X        if (qcmp(q, t) == 0) {
  233. X            qfree(q);
  234. X            return index;
  235. X        }
  236. X    }
  237. X    if (constavail <= 0) {
  238. X        if (consttable == NULL) {
  239. X            tp = (NUMBER **)
  240. X                malloc(sizeof(NUMBER *) * (CONSTALLOCSIZE + 1));
  241. X            *tp = NULL;
  242. X        } else
  243. X            tp = (NUMBER **) realloc((char *) consttable,
  244. X            sizeof(NUMBER *) * (constcount+CONSTALLOCSIZE + 1));
  245. X        if (tp == NULL)
  246. X            return 0;
  247. X        consttable = tp;
  248. X        constavail = CONSTALLOCSIZE;
  249. X    }
  250. X    constavail--;
  251. X    constcount++;
  252. X    consttable[constcount] = q;
  253. X    return constcount;
  254. X}
  255. X
  256. X
  257. X/*
  258. X * Return the value of a constant number given its index.
  259. X * Returns address of the number, or NULL if the index is illegal.
  260. X */
  261. XNUMBER *
  262. Xconstvalue(index)
  263. X    long index;
  264. X{
  265. X    if ((index <= 0) || (index > constcount))
  266. X        return NULL;
  267. X    return consttable[index];
  268. X}
  269. X
  270. X/* END CODE */
  271. SHAR_EOF
  272. chmod 0644 calc2.9.0/const.c || echo "restore of calc2.9.0/const.c fails"
  273. set `wc -c calc2.9.0/const.c`;Sum=$1
  274. if test "$Sum" != "2709"
  275. then echo original size 2709, current size $Sum;fi
  276. echo "x - extracting calc2.9.0/endian.c (Text)"
  277. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/endian.c &&
  278. X/*
  279. X * endian - Determine the byte order of a long on your machine.
  280. X *
  281. X * Big Endian:        Amdahl, 68k, Pyramid, Mips, Sparc, ...
  282. X * Little Endian:   Vax, 32k, Spim (Dec Mips), i386, i486, ...
  283. X */
  284. X/*
  285. X * Copyright (c) 1993 by Landon Curt Noll.  All Rights Reserved.
  286. X *
  287. X * Permission to use, copy, modify, and distribute this software and
  288. X * its documentation for any purpose and without fee is hereby granted,
  289. X * provided that the above copyright, this permission notice and text
  290. X * this comment, and the disclaimer below appear in all of the following:
  291. X *
  292. X *    supporting documentation
  293. X *    source copies
  294. X *    source works derived from this source
  295. X *    binaries derived from this source or from derived source
  296. X *
  297. X * LANDON CURT NOLL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  298. X * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
  299. X * EVENT SHALL LANDON CURT NOLL BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  300. X * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  301. X * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  302. X * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  303. X * PERFORMANCE OF THIS SOFTWARE.
  304. X *
  305. X * chongo was here    /\../\
  306. X */
  307. X
  308. X#include <stdio.h>
  309. X
  310. X/* byte order array */
  311. Xchar byte[8] = { (char)0x12, (char)0x36, (char)0x48, (char)0x59,
  312. X         (char)0x01, (char)0x23, (char)0x45, (char)0x67 };
  313. X
  314. Xmain()
  315. X{
  316. X    /* pointers into the byte order array */
  317. X    int *intp = (int *)byte;
  318. X#if defined(DEBUG)
  319. X    short *shortp = (short *)byte;
  320. X    long *longp = (long *)byte;
  321. X
  322. X    printf("byte: %02x %02x %02x %02x %02x %02x %02x %02x\n",
  323. X    byte[0], byte[1], byte[2], byte[3],
  324. X    byte[4], byte[5], byte[6], byte[7]);
  325. X    printf("short: %04x %04x %04x %04x\n",
  326. X    shortp[0], shortp[1], shortp[2], shortp[3]);
  327. X    printf("int: %08x %08x\n",
  328. X    intp[0], intp[1]);
  329. X    printf("long: %08x %08x\n",
  330. X    longp[0], longp[1]);
  331. X#endif
  332. X
  333. X    /* Print the standard <machine/endian.h> defines */
  334. X    printf("#define BIG_ENDIAN\t4321\n");
  335. X    printf("#define LITTLE_ENDIAN\t1234\n");
  336. X
  337. X    /* Determine byte order */
  338. X    if (intp[0] == 0x12364859) {
  339. X    /* Most Significant Byte first */
  340. X    printf("#define BYTE_ORDER\tBIG_ENDIAN\n");
  341. X    } else if (intp[0] == 0x59483612) {
  342. X    /* Least Significant Byte first */
  343. X    printf("#define BYTE_ORDER\tLITTLE_ENDIAN\n");
  344. X    } else {
  345. X    fprintf(stderr, "Unknown int Byte Order, set BYTE_ORDER in Makefile\n");
  346. X    exit(1);
  347. X    }
  348. X    exit(0);
  349. X}
  350. SHAR_EOF
  351. chmod 0444 calc2.9.0/endian.c || echo "restore of calc2.9.0/endian.c fails"
  352. set `wc -c calc2.9.0/endian.c`;Sum=$1
  353. if test "$Sum" != "2412"
  354. then echo original size 2412, current size $Sum;fi
  355. echo "x - extracting calc2.9.0/file.c (Text)"
  356. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/file.c &&
  357. X/*
  358. X * Copyright (c) 1993 David I. Bell
  359. X * Permission is granted to use, distribute, or modify this source,
  360. X * provided that this copyright notice remains intact.
  361. X *
  362. X * File I/O routines callable by users.
  363. X */
  364. X
  365. X#include "stdarg.h"
  366. X#include "calc.h"
  367. X
  368. X
  369. X#define    READSIZE    1024    /* buffer size for reading */
  370. X
  371. X/*
  372. X * Definition of opened files.
  373. X */
  374. Xtypedef struct {
  375. X    FILEID id;        /* id to identify this file */
  376. X    FILE *fp;        /* real file structure for I/O */
  377. X    char *name;        /* file name */
  378. X    BOOL reading;        /* TRUE if opened for reading */
  379. X    BOOL writing;        /* TRUE if opened for writing */
  380. X    char *mode;        /* open mode */
  381. X} FILEIO;
  382. X
  383. X
  384. X/*
  385. X * Table of opened files.
  386. X * The first three entries always correspond to stdin, stdout, and stderr,
  387. X * and cannot be closed.  Their file ids are always 0, 1, and 2.
  388. X */
  389. Xstatic FILEIO files[MAXFILES] = {
  390. X    FILEID_STDIN,  stdin,  "(stdin)",  TRUE, FALSE, "reading",
  391. X    FILEID_STDOUT, stdout, "(stdout)", FALSE, TRUE, "writing",
  392. X    FILEID_STDERR, stderr, "(stderr)", FALSE, TRUE, "writing"
  393. X};
  394. X
  395. Xstatic FILEID lastid = FILEID_STDERR;        /* last allocated file id */
  396. X
  397. X
  398. X
  399. X/*
  400. X * Open the specified file name for reading or writing as determined by
  401. X * the specified mode ("r", "w", or "a").  Returns a file id which can be
  402. X * used to do I/O to the file, or else FILEID_NONE if the open failed.
  403. X * Aborts with an error if too many files are opened or the mode is illegal.
  404. X */
  405. XFILEID
  406. Xopenid(name, mode)
  407. X    char *name;        /* file name */
  408. X    char *mode;        /* open mode */
  409. X{
  410. X    FILEIO *fiop;        /* file structure */
  411. X    FILEID id;        /* new file id */
  412. X    int count;
  413. X
  414. X    if (((*mode != 'r') && (*mode != 'w') && (*mode != 'a')) || mode[1])
  415. X        math_error("Illegal mode for fopen");
  416. X
  417. X    count = MAXFILES;
  418. X    do {
  419. X        if (--count < 0)
  420. X            math_error("Too many open files");
  421. X        id = ++lastid;
  422. X        fiop = &files[id % MAXFILES];
  423. X
  424. X    } while (fiop->reading || fiop->writing);
  425. X
  426. X    fiop->name = (char *)malloc(strlen(name) + 1);
  427. X    if (fiop->name == NULL) {
  428. X        lastid--;
  429. X        math_error("No memory for filename");
  430. X    }
  431. X    strcpy(fiop->name, name);
  432. X
  433. X    fiop->fp = f_open(name, mode);
  434. X    if (fiop->fp == NULL) {
  435. X        free(fiop->name);
  436. X        fiop->name = NULL;
  437. X        lastid--;
  438. X        return FILEID_NONE;
  439. X    }
  440. X
  441. X    switch (*mode) {
  442. X        case 'r':
  443. X            fiop->mode = "reading";
  444. X            fiop->reading = TRUE;
  445. X            break;
  446. X        case 'w':
  447. X            fiop->mode = "writing";
  448. X            fiop->writing = TRUE;
  449. X            break;
  450. X        case 'a':
  451. X            fiop->mode = "appending";
  452. X            fiop->writing = TRUE;
  453. X            break;
  454. X    }
  455. X
  456. X    fiop->id = id;
  457. X
  458. X    return id;
  459. X}
  460. X
  461. X
  462. X/*
  463. X * Find the file I/O structure for the specified file id, and verify that
  464. X * it is opened in the required manner ('r' for reading or 'w' for writing).
  465. X * If mode is 0, then no open checks are made at all, and NULL is then
  466. X * returned if the id represents a closed file.
  467. X */
  468. Xstatic FILEIO *
  469. Xfindid(id, mode)
  470. X    FILEID id;
  471. X{
  472. X    FILEIO *fiop;        /* file structure */
  473. X    char *msg;
  474. X    BOOL flag;
  475. X
  476. X    if ((id < 0) || (id > lastid))
  477. X        math_error("Illegal file id");
  478. X
  479. X    fiop = &files[id % MAXFILES];
  480. X
  481. X    switch (mode) {
  482. X        case 'r':
  483. X            msg = "Reading from";
  484. X            flag = fiop->reading;
  485. X            break;
  486. X        case 'w':
  487. X            msg = "Writing to";
  488. X            flag = fiop->writing;
  489. X            break;
  490. X        case 0:
  491. X            msg = NULL;
  492. X            break;
  493. X        default:
  494. X            math_error("Unknown findid mode");
  495. X    }
  496. X
  497. X    if (fiop->id != id) {
  498. X        if (msg)
  499. X            math_error("%s closed file", msg);
  500. X        return NULL;
  501. X    }
  502. X
  503. X    if (msg && !flag)
  504. X        math_error("%s file not opened that way", msg);
  505. X    
  506. X    return fiop;
  507. X}
  508. X
  509. X
  510. X/*
  511. X * Return whether or not a file id is valid.  This is used for if tests.
  512. X */
  513. XBOOL
  514. Xvalidid(id)
  515. X    FILEID id;
  516. X{
  517. X    return (findid(id, 0) != NULL);
  518. X}
  519. X
  520. X
  521. X/*
  522. X * Return the file id for the entry in the file table at the specified index.
  523. X * Returns FILEID_NONE if the index is illegal or the file is closed.
  524. X */
  525. XFILEID
  526. Xindexid(index)
  527. X    long index;
  528. X{
  529. X    FILEIO *fiop;        /* file structure */
  530. X
  531. X    if ((index < 0) || (index >= MAXFILES))
  532. X        return FILEID_NONE;
  533. X
  534. X    fiop = &files[index];
  535. X    if (fiop->reading || fiop->writing)
  536. X        return fiop->id;
  537. X
  538. X    return FILEID_NONE;
  539. X}
  540. X
  541. X
  542. X/*
  543. X * Close the specified file id.  Returns TRUE if there was an error.
  544. X * Closing of stdin, stdout, or stderr is illegal, but closing of already
  545. X * closed files is allowed.
  546. X */
  547. XBOOL
  548. Xcloseid(id)
  549. X    FILEID id;
  550. X{
  551. X    FILEIO *fiop;        /* file structure */
  552. X    int err;
  553. X
  554. X    if ((id == FILEID_STDIN) || (id == FILEID_STDOUT) ||
  555. X        (id == FILEID_STDERR))
  556. X            math_error("Cannot close stdin, stdout, or stderr");
  557. X
  558. X    fiop = findid(id, 0);
  559. X    if (fiop == NULL)
  560. X        return FALSE;
  561. X
  562. X    fiop->id = FILEID_NONE;
  563. X    if (!fiop->reading && !fiop->writing)
  564. X        math_error("Closing non-opened file");
  565. X    fiop->reading = FALSE;
  566. X    fiop->writing = FALSE;
  567. X
  568. X    if (fiop->name)
  569. X        free(fiop->name);
  570. X    fiop->name = NULL;
  571. X
  572. X    err = ferror(fiop->fp);
  573. X    err |= fclose(fiop->fp);
  574. X    fiop->fp = NULL;
  575. X
  576. X    return (err != 0);
  577. X}
  578. X
  579. X
  580. X/*
  581. X * Return whether or not an error occurred to a file.
  582. X */
  583. XBOOL
  584. Xerrorid(id)
  585. X    FILEID id;
  586. X{
  587. X    FILEIO *fiop;        /* file structure */
  588. X
  589. X    fiop = findid(id, 0);
  590. X    if (fiop == NULL)
  591. X        math_error("Closed file for ferror");
  592. X    return (ferror(fiop->fp) != 0);
  593. X}
  594. X
  595. X
  596. X/*
  597. X * Return whether or not end of file occurred to a file.
  598. X */
  599. XBOOL
  600. Xeofid(id)
  601. X    FILEID id;
  602. X{
  603. X    FILEIO *fiop;        /* file structure */
  604. X
  605. X    fiop = findid(id, 0);
  606. X    if (fiop == NULL)
  607. X        math_error("Closed file for feof");
  608. X    return (feof(fiop->fp) != 0);
  609. X}
  610. X
  611. X
  612. X/*
  613. X * Flush output to an opened file.
  614. X */
  615. Xvoid
  616. Xflushid(id)
  617. X    FILEID id;
  618. X{
  619. X    FILEIO *fiop;        /* file structure */
  620. X
  621. X    fiop = findid(id, 'w');
  622. X    fflush(fiop->fp);
  623. X}
  624. X
  625. X
  626. X/*
  627. X * Read the next line from an opened file.
  628. X * Returns a pointer to an allocated string holding the null-terminated
  629. X * line (without any terminating newline), or else a NULL pointer on an
  630. X * end of file or error.
  631. X */
  632. Xvoid
  633. Xreadid(id, retptr)
  634. X    FILEID    id;        /* file to read from */
  635. X    char **retptr;        /* returned pointer to string */
  636. X{
  637. X    FILEIO *fiop;        /* file structure */
  638. X    char *str;        /* current string */
  639. X    int len;        /* current length of string */
  640. X    int totlen;        /* total length of string */
  641. X    char buf[READSIZE];    /* temporary buffer */
  642. X
  643. X    totlen = 0;
  644. X    str = NULL;
  645. X
  646. X    fiop = findid(id, 'r');
  647. X
  648. X    while (fgets(buf, READSIZE, fiop->fp) && buf[0]) {
  649. X        len = strlen(buf);
  650. X        if (totlen)
  651. X            str = (char *)realloc(str, totlen + len + 1);
  652. X        else
  653. X            str = (char *)malloc(len + 1);
  654. X        if (str == NULL)
  655. X            math_error("No memory in freadline");
  656. X        strcpy(&str[totlen], buf);
  657. X        totlen += len;
  658. X        if (buf[len - 1] == '\n') {
  659. X            str[totlen - 1] = '\0';
  660. X            *retptr = str;
  661. X            return;
  662. X        }
  663. X    }
  664. X    if (totlen && ferror(fiop->fp)) {
  665. X        free(str);
  666. X        str = NULL;
  667. X    }
  668. X    *retptr = str;
  669. X}
  670. X
  671. X
  672. X/*
  673. X * Return the next character from an opened file.
  674. X * Returns EOF if there was an error or end of file.
  675. X */
  676. Xint
  677. Xgetcharid(id)
  678. X    FILEID id;
  679. X{
  680. X    return fgetc(findid(id, 'r')->fp);
  681. X}
  682. X
  683. X
  684. X/*
  685. X * Print out the name of an opened file.
  686. X * If the file has been closed, a null name is printed.
  687. X * If flags contain PRINT_UNAMBIG then extra information is printed
  688. X * identifying the output as a file and some data about it.
  689. X */
  690. Xvoid
  691. Xprintid(id, flags)
  692. X    FILEID id;
  693. X{
  694. X    FILEIO *fiop;        /* file structure */
  695. X    FILE *fp;
  696. X
  697. X    fiop = findid(id, 0);
  698. X    if (fiop == NULL) {
  699. X        math_str((flags & PRINT_UNAMBIG) ? "FILE (closed)" : "\"\"");
  700. X        return;
  701. X    }
  702. X    if ((flags & PRINT_UNAMBIG) == 0) {
  703. X        math_chr('"');
  704. X        math_str(fiop->name);
  705. X        math_chr('"');
  706. X        return;
  707. X    }
  708. X
  709. X    fp = fiop->fp;
  710. X    math_fmt("FILE \"%s\" (%s, pos %ld", fiop->name,  fiop->mode,
  711. X        ftell(fp));
  712. X    if (ferror(fp))
  713. X        math_str(", error");
  714. X    if (feof(fp))
  715. X        math_str(", eof");
  716. X    math_chr(')');
  717. X}
  718. X
  719. X
  720. X/*
  721. X * Print a formatted string similar to printf.  Various formats of output
  722. X * are possible, depending on the format string AND the actual types of the
  723. X * values.  Mismatches do not cause errors, instead something reasonable is
  724. X * printed instead.  The output goes to the file with the specified id.
  725. X */
  726. Xvoid
  727. Xidprintf(id, fmt, count, vals)
  728. X    FILEID id;            /* file id to print to */
  729. X    char *fmt;            /* standard format string */
  730. X    VALUE **vals;            /* table of values to print */
  731. X{
  732. X    FILEIO *fiop;
  733. X    VALUE *vp;
  734. X    char *str;
  735. X    int ch, len;
  736. X    int oldmode, newmode;
  737. X    long olddigits, newdigits;
  738. X    long width, precision;
  739. X    BOOL didneg, didprecision;
  740. X
  741. X    fiop = findid(id, 'w');
  742. X
  743. X    math_setfp(fiop->fp);
  744. X
  745. X    while ((ch = *fmt++) != '\0') {
  746. X        if (ch == '\\') {
  747. X            ch = *fmt++;
  748. X            switch (ch) {
  749. X                case 'n': ch = '\n'; break;
  750. X                case 'r': ch = '\r'; break;
  751. X                case 't': ch = '\t'; break;
  752. X                case 'f': ch = '\f'; break;
  753. X                case 'v': ch = '\v'; break;
  754. X                case 'b': ch = '\b'; break;
  755. X                case 0:
  756. X                    math_setfp(stdout);
  757. X                    return;
  758. X            }
  759. X            math_chr(ch);
  760. X            continue;
  761. X        }
  762. X
  763. X        if (ch != '%') {
  764. X            math_chr(ch);
  765. X            continue;
  766. X        }
  767. X
  768. X        /*
  769. X         * Here to handle formats.
  770. X         */
  771. X        didneg = FALSE;
  772. X        didprecision = FALSE;
  773. X        width = 0;
  774. X        precision = 0;
  775. X
  776. X        ch = *fmt++;
  777. X        if (ch == '-') {
  778. X            didneg = TRUE;
  779. X            ch = *fmt++;
  780. X        }
  781. X        while ((ch >= '0') && (ch <= '9')) {
  782. X            width = width * 10 + (ch - '0');
  783. X            ch = *fmt++;
  784. X        }
  785. X        if (ch == '.') {
  786. X            didprecision = TRUE;
  787. X            ch = *fmt++;
  788. X            while ((ch >= '0') && (ch <= '9')) {
  789. X                precision = precision * 10 + (ch - '0');
  790. X                ch = *fmt++;
  791. X            }
  792. X        }
  793. X        if (ch == 'l')
  794. X            ch = *fmt++;
  795. X
  796. X        oldmode = _outmode_;
  797. X        newmode = oldmode;
  798. X        olddigits = _outdigits_;
  799. X        newdigits = olddigits;
  800. X        if (didprecision)
  801. X            newdigits = precision;
  802. X
  803. X        switch (ch) {
  804. X            case 'd':
  805. X            case 's':
  806. X            case 'c':
  807. X                break;
  808. X            case 'f':
  809. X                newmode = MODE_REAL;
  810. X                break;
  811. X            case 'e':
  812. X                newmode = MODE_EXP;
  813. X                break;
  814. X            case 'r':
  815. X                newmode = MODE_FRAC;
  816. X                break;
  817. X            case 'o':
  818. X                newmode = MODE_OCTAL;
  819. X                break;
  820. X            case 'x':
  821. X                newmode = MODE_HEX;
  822. X                break;
  823. X            case 'b':
  824. X                newmode = MODE_BINARY;
  825. X                break;
  826. X            case 0:
  827. X                math_setfp(stdout);
  828. X                return;
  829. X            default:
  830. X                math_chr(ch);
  831. X                continue;
  832. X        }
  833. X
  834. X        if (--count < 0)
  835. X            math_error("Not enough arguments for fprintf");
  836. X        vp = *vals++;
  837. X
  838. X        math_setdigits(newdigits);
  839. X        math_setmode(newmode);
  840. X
  841. X        /*
  842. X         * If there is no width specification, or if the type of
  843. X         * value requires multiple lines, then just output the
  844. X         * value directly.
  845. X         */
  846. X        if ((width == 0) ||
  847. X            (vp->v_type == V_MAT) || (vp->v_type == V_LIST))
  848. X        {
  849. X            printvalue(vp, PRINT_NORMAL);
  850. X            math_setmode(oldmode);
  851. X            math_setdigits(olddigits);
  852. X            continue;
  853. X        }
  854. X
  855. X        /*
  856. X         * There is a field width.  Collect the output in a string,
  857. X         * print it padded appropriately with spaces, and free it.
  858. X         * However, if the output contains a newline, then ignore
  859. X         * the field width.
  860. X         */
  861. X        math_divertio();
  862. X        printvalue(vp, PRINT_NORMAL);
  863. X        str = math_getdivertedio();
  864. X        if (strchr(str, '\n'))
  865. X            width = 0;
  866. X        len = strlen(str);
  867. X        while (!didneg && (width > len)) {
  868. X            width--;
  869. X            math_chr(' ');
  870. X        }
  871. X        math_str(str);
  872. X        free(str);
  873. X        while (didneg && (width > len)) {
  874. X            width--;
  875. X            math_chr(' ');
  876. X        }
  877. X        math_setmode(oldmode);
  878. X        math_setdigits(olddigits);
  879. X    }
  880. X    math_setfp(stdout);
  881. X}
  882. X
  883. X/* END CODE */
  884. SHAR_EOF
  885. chmod 0644 calc2.9.0/file.c || echo "restore of calc2.9.0/file.c fails"
  886. set `wc -c calc2.9.0/file.c`;Sum=$1
  887. if test "$Sum" != "10532"
  888. then echo original size 10532, current size $Sum;fi
  889. echo "x - extracting calc2.9.0/func.c (Text)"
  890. sed 's/^X//' << 'SHAR_EOF' > calc2.9.0/func.c &&
  891. X/*
  892. X * Copyright (c) 1993 David I. Bell
  893. X * Permission is granted to use, distribute, or modify this source,
  894. X * provided that this copyright notice remains intact.
  895. X *
  896. X * Built-in functions implemented here
  897. X */
  898. X
  899. X#include <sys/types.h>
  900. X#include <sys/times.h>
  901. X#include <time.h>
  902. X
  903. X#include "calc.h"
  904. X#include "opcodes.h"
  905. X#include "token.h"
  906. X#include "func.h"
  907. X#include "string.h"
  908. X#include "symbol.h"
  909. X
  910. X
  911. X/* if HZ & CLK_TCK are not defined, pick typical values, hope for the best */
  912. X#if !defined(HZ)
  913. X#  define HZ 60
  914. X#endif
  915. X#if !defined(CLK_TCK)
  916. X# undef CLK_TCK
  917. X# define CLK_TCK HZ
  918. X#endif
  919. X
  920. Xextern int errno;
  921. X
  922. X
  923. X/*
  924. X * Totally numeric functions.
  925. X */
  926. Xstatic NUMBER *f_cfsim();    /* simplify number using continued fractions */
  927. Xstatic NUMBER *f_ilog();    /* return log of one number to another */
  928. Xstatic NUMBER *f_faccnt();    /* count of divisions */
  929. Xstatic NUMBER *f_min();        /* minimum of several arguments */
  930. Xstatic NUMBER *f_max();        /* maximum of several arguments */
  931. Xstatic NUMBER *f_hmean();    /* harmonic mean */
  932. Xstatic NUMBER *f_trunc();    /* truncate number to specified decimal places */
  933. Xstatic NUMBER *f_btrunc();    /* truncate number to specified binary places */
  934. Xstatic NUMBER *f_gcd();        /* greatest common divisor */
  935. Xstatic NUMBER *f_lcm();        /* least common multiple */
  936. Xstatic NUMBER *f_xor();        /* xor of several arguments */
  937. Xstatic NUMBER *f_ceil();    /* ceiling of a fraction */
  938. Xstatic NUMBER *f_floor();    /* floor of a fraction */
  939. Xstatic NUMBER *f_meq();        /* numbers are same modular value */
  940. Xstatic NUMBER *f_isrel();    /* two numbers are relatively prime */
  941. Xstatic NUMBER *f_ismult();    /* whether one number divides another */
  942. Xstatic NUMBER *f_mne();        /* whether a and b are not equal modulo c */
  943. Xstatic NUMBER *f_isset();    /* tests if a bit of a num (base 2) is set */
  944. Xstatic NUMBER *f_highbit();    /* high bit number in base 2 representation */
  945. Xstatic NUMBER *f_lowbit();    /* low bit number in base 2 representation */
  946. Xstatic NUMBER *f_near();    /* whether two numbers are near each other */
  947. Xstatic NUMBER *f_legtoleg();    /* positive form of leg to leg */
  948. Xstatic NUMBER *f_ilog10();    /* integer log of number base 10 */
  949. Xstatic NUMBER *f_ilog2();    /* integer log of number base 2 */
  950. Xstatic NUMBER *f_digits();    /* number of digits of number */
  951. Xstatic NUMBER *f_digit();    /* digit at specified decimal place of number */
  952. Xstatic NUMBER *f_places();    /* number of decimal places of number */
  953. Xstatic NUMBER *f_primetest();    /* primality test */
  954. Xstatic NUMBER *f_issquare();    /* whether number is a square */
  955. Xstatic NUMBER *f_runtime();    /* user runtime in seconds */
  956. X
  957. X
  958. X/*
  959. X * General functions.
  960. X */
  961. Xstatic VALUE f_hash();        /* produce hash from values */
  962. Xstatic VALUE f_bround();    /* round number to specified binary places */
  963. Xstatic VALUE f_round();        /* round number to specified decimal places */
  964. Xstatic VALUE f_det();        /* determinant of matrix */
  965. Xstatic VALUE f_mattrans();    /* return transpose of matrix */
  966. Xstatic VALUE f_matdim();    /* dimension of matrix */
  967. Xstatic VALUE f_matmax();    /* maximum index of matrix dimension */
  968. Xstatic VALUE f_matmin();    /* minimum index of matrix dimension */
  969. Xstatic VALUE f_matfill();    /* fill matrix with values */
  970. Xstatic VALUE f_listpush();    /* push element onto front of list */
  971. Xstatic VALUE f_listpop();    /* pop element from front of list */
  972. Xstatic VALUE f_listappend();    /* append element to end of list */
  973. Xstatic VALUE f_listremove();    /* remove element from end of list */
  974. Xstatic VALUE f_listinsert();    /* insert element into list */
  975. Xstatic VALUE f_listdelete();    /* delete element from list */
  976. Xstatic VALUE f_strlen();    /* length of string */
  977. Xstatic VALUE f_char();        /* character value of integer */
  978. Xstatic VALUE f_substr();    /* extract substring */
  979. Xstatic VALUE f_strcat();    /* concatenate strings */
  980. Xstatic VALUE f_ord();        /* get ordinal value for character */
  981. Xstatic VALUE f_avg();        /* average of several arguments */
  982. Xstatic VALUE f_ssq();        /* sum of squares */
  983. Xstatic VALUE f_poly();        /* result of evaluating polynomial */
  984. Xstatic VALUE f_sqrt();        /* square root of a number */
  985. Xstatic VALUE f_root();        /* number taken to root of another */
  986. Xstatic VALUE f_exp();        /* complex exponential */
  987. Xstatic VALUE f_ln();        /* complex natural logarithm */
  988. Xstatic VALUE f_power();        /* one value to another power */
  989. Xstatic VALUE f_cos();        /* complex cosine */
  990. Xstatic VALUE f_sin();        /* complex sine */
  991. Xstatic VALUE f_polar();        /* polar representation of complex number */
  992. Xstatic VALUE f_arg();        /* argument of complex number */
  993. Xstatic VALUE f_list();        /* create a list */
  994. Xstatic VALUE f_size();        /* number of elements in object */
  995. Xstatic VALUE f_search();    /* search matrix or list for match */
  996. Xstatic VALUE f_rsearch();    /* search matrix or list backwards for match */
  997. Xstatic VALUE f_cp();        /* cross product of vectors */
  998. Xstatic VALUE f_dp();        /* dot product of vectors */
  999. Xstatic VALUE f_prompt();    /* prompt for input line */
  1000. Xstatic VALUE f_eval();        /* evaluate string into value */
  1001. Xstatic VALUE f_str();        /* convert value to string */
  1002. Xstatic VALUE f_fopen();        /* open file for reading or writing */
  1003. Xstatic VALUE f_fprintf();    /* print data to file */
  1004. Xstatic VALUE f_strprintf();    /* return printed data as a string */
  1005. Xstatic VALUE f_fgetline();    /* read next line from file */
  1006. Xstatic VALUE f_fgetc();        /* read next char from file */
  1007. Xstatic VALUE f_fflush();    /* flush output to file */
  1008. Xstatic VALUE f_printf();    /* print data to stdout */
  1009. Xstatic VALUE f_fclose();    /* close file */
  1010. Xstatic VALUE f_ferror();    /* whether error occurred */
  1011. Xstatic VALUE f_feof();        /* whether end of file reached */
  1012. Xstatic VALUE f_files();        /* return file handle or number of files */
  1013. Xstatic VALUE f_assoc();        /* return a new association value */
  1014. X
  1015. X
  1016. X#define IN 100        /* maximum number of arguments */
  1017. X#define    FE 0x01        /* flag to indicate default epsilon argument */
  1018. X#define    FA 0x02        /* preserve addresses of variables */
  1019. X
  1020. X
  1021. X/*
  1022. X * List of primitive built-in functions
  1023. X */
  1024. Xstatic struct builtin {
  1025. X    char *b_name;        /* name of built-in function */
  1026. X    short b_minargs;    /* minimum number of arguments */
  1027. X    short b_maxargs;    /* maximum number of arguments */
  1028. X    short b_flags;        /* special handling flags */
  1029. X    short b_opcode;        /* opcode which makes the call quick */
  1030. X    NUMBER *(*b_numfunc)();    /* routine to calculate numeric function */
  1031. X    VALUE (*b_valfunc)();    /* routine to calculate general values */
  1032. X    char *b_desc;        /* description of function */
  1033. X} builtins[] = {
  1034. X    "abs", 1, 2, 0, OP_ABS, 0, 0, "absolute value within accuracy b",
  1035. X    "acos", 1, 2, FE, OP_NOP, qacos, 0, "arccosine of a within accuracy b",
  1036. X    "acosh", 1, 2, FE, OP_NOP, qacosh, 0, "hyperbolic arccosine of a within accuracy b",
  1037. X    "append", 2, 2, FA, OP_NOP, 0, f_listappend, "append value to end of list",
  1038. X    "appr", 1, 2, FE, OP_NOP, qbappr, 0, "approximate a with simpler fraction to within b",
  1039. X    "arg", 1, 2, 0, OP_NOP, 0, f_arg, "argument (the angle) of complex number",
  1040. X    "asin", 1, 2, FE, OP_NOP, qasin, 0, "arcsine of a within accuracy b",
  1041. X    "asinh", 1, 2, FE, OP_NOP, qasinh, 0, "hyperbolic arcsine of a within accuracy b",
  1042. X    "assoc", 0, 0, 0, OP_NOP, 0, f_assoc, "create new association array",
  1043. X    "atan", 1, 2, FE, OP_NOP, qatan, 0, "arctangent of a within accuracy b",
  1044. X    "atan2", 2, 3, FE, OP_NOP, qatan2, 0, "angle to point (b,a) within accuracy c",
  1045. X    "atanh", 1, 2, FE, OP_NOP, qatanh, 0, "hyperbolic arctangent of a within accuracy b",
  1046. X    "avg", 1, IN, 0, OP_NOP, 0, f_avg, "arithmetic mean of values",
  1047. X    "bround", 1, 2, 0, OP_NOP, 0, f_bround, "round value a to b number of binary places",
  1048. X    "btrunc", 1, 2, 0, OP_NOP, f_btrunc, 0, "truncate a to b number of binary places",
  1049. X    "ceil", 1, 1, 0, OP_NOP, f_ceil, 0, "smallest integer greater than or equal to number",
  1050. X    "cfappr", 1, 2, FE, OP_NOP, qcfappr, 0, "approximate a within accuracy b using continued fractions",
  1051. X    "cfsim", 1, 1, 0, OP_NOP, f_cfsim, 0, "simplify number using continued fractions",
  1052. X    "char", 1, 1, 0, OP_NOP, 0, f_char, "character corresponding to integer value",
  1053. X    "cmp", 2, 2, 0, OP_CMP, 0, 0, "compare values returning -1, 0, or 1",
  1054. X    "comb", 2, 2, 0, OP_NOP, qcomb, 0, "combinatorial number a!/b!(a-b)!",
  1055. X    "config", 1, 2, 0, OP_SETCONFIG, 0, 0, "set or read configuration value",
  1056. X    "conj", 1, 1, 0, OP_CONJUGATE, 0, 0, "complex conjugate of value",
  1057. X    "cos", 1, 2, 0, OP_NOP, 0, f_cos, "cosine of value a within accuracy b",
  1058. X    "cosh", 1, 2, FE, OP_NOP, qcosh, 0, "hyperbolic cosine of a within accuracy b",
  1059. X    "cp", 2, 2, 0, OP_NOP, 0, f_cp, "Cross product of two vectors",
  1060. X    "delete", 2, 2, FA, OP_NOP, 0, f_listdelete, "delete element from list a at position b",
  1061. X    "den", 1, 1, 0, OP_DENOMINATOR, qden, 0, "denominator of fraction",
  1062. X    "det", 1, 1, 0, OP_NOP, 0, f_det, "determinant of matrix",
  1063. X    "digit", 2, 2, 0, OP_NOP, f_digit, 0, "digit at specified decimal place of number",
  1064. X    "digits", 1, 1, 0, OP_NOP, f_digits, 0, "number of digits in number",
  1065. X    "dp", 2, 2, 0, OP_NOP, 0, f_dp, "Dot product of two vectors",
  1066. X    "epsilon", 0, 1, 0, OP_SETEPSILON, 0, 0, "set or read allowed error for real calculations",
  1067. X    "eval", 1, 1, 0, OP_NOP, 0, f_eval, "Evaluate expression from string to value",
  1068. X    "exp", 1, 2, 0, OP_NOP, 0, f_exp, "exponential of value a within accuracy b",
  1069. X    "fcnt", 2, 2, 0, OP_NOP, f_faccnt, 0, "count of times one number divides another",
  1070. X    "fib", 1, 1, 0, OP_NOP, qfib, 0, "fibonacci number F(n)",
  1071. X    "frem", 2, 2, 0, OP_NOP, qfacrem, 0, "number with all occurances of factor removed",
  1072. X    "fact", 1, 1, 0, OP_NOP, qfact, 0, "factorial",
  1073. X    "fclose", 1, 1, 0, OP_NOP, 0, f_fclose, "close file",
  1074. X    "feof", 1, 1, 0, OP_NOP, 0, f_feof, "whether EOF reached for file",
  1075. X    "ferror", 1, 1, 0, OP_NOP, 0, f_ferror, "whether error occurred for file",
  1076. X    "fflush", 1, 1, 0, OP_NOP, 0, f_fflush, "flush output to file",
  1077. X    "fgetc", 1, 1, 0, OP_NOP, 0, f_fgetc, "read next char from file",
  1078. X    "fgetline", 1, 1, 0, OP_NOP, 0, f_fgetline, "read next line from file",
  1079. X    "files", 0, 1, 0, OP_NOP, 0, f_files, "return opened file or max number of opened files",
  1080. X    "floor", 1, 1, 0, OP_NOP, f_floor, 0, "greatest integer less than or equal to number",
  1081. X    "fopen", 2, 2, 0, OP_NOP, 0, f_fopen, "open file name a in mode b",
  1082. X    "fprintf", 2, IN, 0, OP_NOP, 0, f_fprintf, "print formatted output to opened file",
  1083. X    "frac", 1, 1, 0, OP_FRAC, qfrac, 0, "fractional part of value",
  1084. X    "gcd", 1, IN, 0, OP_NOP, f_gcd, 0, "greatest common divisor",
  1085. X    "gcdrem", 2, 2, 0, OP_NOP, qgcdrem, 0, "a divided repeatedly by gcd with b",
  1086. X    "hash", 1, IN, 0, OP_NOP, 0, f_hash, "return non-negative hash value for one or more values",
  1087. X    "highbit", 1, 1, 0, OP_NOP, f_highbit, 0, "high bit number in base 2 representation",
  1088. X    "hmean", 1, IN, 0, OP_NOP, f_hmean, 0, "harmonic mean of values",
  1089. X    "hypot", 2, 3, FE, OP_NOP, qhypot, 0, "hypotenuse of right triangle within accuracy c",
  1090. X    "ilog", 2, 2, 0, OP_NOP, f_ilog, 0, "integral log of one number with another",
  1091. X    "ilog10", 1, 1, 0, OP_NOP, f_ilog10, 0, "integral log of a number base 10",
  1092. X    "ilog2", 1, 1, 0, OP_NOP, f_ilog2, 0, "integral log of a number base 2",
  1093. X    "im", 1, 1, 0, OP_IM, 0, 0, "imaginary part of complex number",
  1094. X    "insert", 3, 3, FA, OP_NOP, 0, f_listinsert, "insert value c into list a at position b",
  1095. X     "int", 1, 1, 0, OP_INT, qint, 0, "integer part of value",
  1096. X    "inverse", 1, 1, 0, OP_INVERT, 0, 0, "multiplicative inverse of value",
  1097. X    "iroot", 2, 2, 0, OP_NOP, qiroot, 0, "integer b'th root of a",
  1098. X    "isassoc", 1, 1, 0, OP_ISASSOC, 0, 0, "whether a value is an association",
  1099. X    "iseven", 1, 1, 0, OP_ISEVEN, 0, 0, "whether a value is an even integer",
  1100. X    "isfile", 1, 1, 0, OP_ISFILE, 0, 0, "whether a value is a file",
  1101. X    "isint", 1, 1, 0, OP_ISINT, 0, 0, "whether a value is an integer",
  1102. X    "islist", 1, 1, 0, OP_ISLIST, 0, 0, "whether a value is a list",
  1103. X    "ismat", 1, 1, 0, OP_ISMAT, 0, 0, "whether a value is a matrix",
  1104. X    "ismult", 2, 2, 0, OP_NOP, f_ismult, 0, "whether a is a multiple of b",
  1105. X    "isnull", 1, 1, 0, OP_ISNULL, 0, 0, "whether a value is the null value",
  1106. X    "isnum", 1, 1, 0, OP_ISNUM, 0, 0, "whether a value is a number",
  1107. X    "isobj", 1, 1, 0, OP_ISOBJ, 0, 0, "whether a value is an object",
  1108. X    "isodd", 1, 1, 0, OP_ISODD, 0, 0, "whether a value is an odd integer",
  1109. X    "isqrt", 1, 1, 0, OP_NOP, qisqrt, 0, "integer part of square root",
  1110. X    "isreal", 1, 1, 0, OP_ISREAL, 0, 0, "whether a value is a real number",
  1111. X    "isset", 2, 2, 0, OP_NOP, f_isset, 0, "whether bit b of abs(a) (in base 2) is set",
  1112. X    "isstr", 1, 1, 0, OP_ISSTR, 0, 0, "whether a value is a string",
  1113. X    "isrel", 2, 2, 0, OP_NOP, f_isrel, 0, "whether two numbers are relatively prime",
  1114. X    "issimple", 1, 1, 0, OP_ISSIMPLE, 0, 0, "whether value is a simple type",
  1115. X    "issq", 1, 1, 0, OP_NOP, f_issquare, 0, "whether or not number is a square",
  1116. X     "istype", 2, 2, 0, OP_ISTYPE, 0, 0, "whether the type of a is same as the type of b",
  1117. X    "jacobi", 2, 2, 0, OP_NOP, qjacobi, 0, "-1 => a is not quadratic residue mod b\n\t\t 1 => b is composite, or a is quad residue of b",
  1118. X    "lcm", 1, IN, 0, OP_NOP, f_lcm, 0, "least common multiple",
  1119. X    "lcmfact", 1, 1, 0, OP_NOP, qlcmfact, 0, "lcm of all integers up till number",
  1120. X    "lfactor", 2, 2, 0, OP_NOP, qlowfactor, 0, "lowest prime factor of a in first b primes",
  1121. X    "list", 0, IN, 0, OP_NOP, 0, f_list, "create list of specified values",
  1122. X    "ln", 1, 2, 0, OP_NOP, 0, f_ln, "natural logarithm of value a within accuracy b",
  1123. X    "lowbit", 1, 1, 0, OP_NOP, f_lowbit, 0, "low bit number in base 2 representation",
  1124. X    "ltol", 1, 2, FE, OP_NOP, f_legtoleg, 0, "leg-to-leg of unit right triangle (sqrt(1 - a^2))",
  1125. X    "matdim", 1, 1, 0, OP_NOP, 0, f_matdim, "number of dimensions of matrix",
  1126. X    "matfill", 2, 3, FA, OP_NOP, 0, f_matfill, "fill matrix with value b (value c on diagonal)",
  1127. X    "matmax", 2, 2, 0, OP_NOP, 0, f_matmax, "maximum index of matrix a dim b",
  1128. X    "matmin", 2, 2, 0, OP_NOP, 0, f_matmin, "minimum index of matrix a dim b",
  1129. X    "mattrans", 1, 1, 0, OP_NOP, 0, f_mattrans, "transpose of matrix",
  1130. X    "max", 1, IN, 0, OP_NOP, f_max, 0, "maximum value",
  1131. X    "meq", 3, 3, 0, OP_NOP, f_meq, 0, "whether a and b are equal modulo c",
  1132. X    "min", 1, IN, 0, OP_NOP, f_min, 0, "minimum value",
  1133. X    "minv", 2, 2, 0, OP_NOP, qminv, 0, "inverse of a modulo b",
  1134. X    "mmin", 2, 2, 0, OP_NOP, qminmod, 0, "a mod b value with smallest abs value",
  1135. X    "mne", 3, 3, 0, OP_NOP, f_mne, 0, "whether a and b are not equal modulo c",
  1136. X    "near", 2, 3, 0, OP_NOP, f_near, 0, "sign of (abs(a-b) - c)",
  1137. X    "norm", 1, 1, 0, OP_NORM, 0, 0, "norm of a value (square of absolute value)",
  1138. X    "null", 0, 0, 0, OP_UNDEF, 0, 0, "null value",
  1139. X    "num", 1, 1, 0, OP_NUMERATOR, qnum, 0, "numerator of fraction",
  1140. X    "ord", 1, 1, 0, OP_NOP, 0, f_ord, "integer corresponding to character value",
  1141. X    "param", 1, 1, 0, OP_ARGVALUE, 0, 0, "value of parameter n (or parameter count if n is zero)",
  1142. X    "perm", 2, 2, 0, OP_NOP, qperm, 0, "permutation number a!/(a-b)!",
  1143. X    "pfact", 1, 1, 0, OP_NOP, qpfact, 0, "product of primes up till number",
  1144. X    "pi", 0, 1, FE, OP_NOP, qpi, 0, "value of pi accurate to within epsilon",
  1145. X    "places", 1, 1, 0, OP_NOP, f_places, 0, "places after decimal point (-1 if infinite)",
  1146. X    "pmod", 3, 3, 0, OP_NOP, qpowermod,0, "mod of a power (a ^ b (mod c))",
  1147. X    "polar", 2, 3, 0, OP_NOP, 0, f_polar, "complex value of polar coordinate (a * exp(b*1i))",
  1148. X    "poly", 2, IN, 0, OP_NOP, 0, f_poly, "(a1,a2,...,an,x) = a1*x^n+a2*x^(n-1)+...+an",
  1149. X    "pop", 1, 1, FA, OP_NOP, 0, f_listpop, "pop value from front of list",
  1150. X    "power", 2, 3, 0, OP_NOP, 0, f_power, "value a raised to the power b within accuracy c",
  1151. X    "ptest", 2, 2, 0, OP_NOP, f_primetest, 0, "probabilistic primality test",
  1152. X    "printf", 1, IN, 0, OP_NOP, 0, f_printf, "print formatted output to stdout",
  1153. X    "prompt", 1, 1, 0, OP_NOP, 0, f_prompt, "prompt for input line using value a",
  1154. X    "push", 2, 2, FA, OP_NOP, 0, f_listpush, "push value onto front of list",
  1155. X    "quomod", 4, 4, 0, OP_QUOMOD, 0, 0, "set c and d to quotient and remainder of a divided by b",
  1156. X    "rcin", 2, 2, 0, OP_NOP, qredcin, 0, "convert normal number a to REDC number mod b",
  1157. X    "rcmul", 3, 3, 0, OP_NOP, qredcmul, 0, "multiply REDC numbers a and b mod c",
  1158. X    "rcout", 2, 2, 0, OP_NOP, qredcout, 0, "convert REDC number a mod b to normal number",
  1159. X    "rcpow", 3, 3, 0, OP_NOP, qredcpower, 0, "raise REDC number a to power b mod c",
  1160. X    "rcsq", 2, 2, 0, OP_NOP, qredcsquare, 0, "square REDC number a mod b",
  1161. X    "re", 1, 1, 0, OP_RE, 0, 0, "real part of complex number",
  1162. X    "remove", 1, 1, FA, OP_NOP, 0, f_listremove, "remove value from end of list",
  1163. X    "root", 2, 3, 0, OP_NOP, 0, f_root, "value a taken to the b'th root within accuracy c",
  1164. X    "round", 1, 2, 0, OP_NOP, 0, f_round, "round value a to b number of decimal places",
  1165. X    "rsearch", 2, 3, 0, OP_NOP, 0, f_rsearch, "reverse search matrix or list for value b starting at index c",
  1166. X    "runtime", 0, 0, 0, OP_NOP, f_runtime, 0, "user mode cpu time in seconds",
  1167. X    "scale", 2, 2, 0, OP_SCALE, 0, 0, "scale value up or down by a power of two",
  1168. X    "search", 2, 3, 0, OP_NOP, 0, f_search, "search matrix or list for value b starting at index c",
  1169. X    "sgn", 1, 1, 0, OP_SGN, qsign, 0, "sign of value (-1, 0, 1)",
  1170. X    "sin", 1, 2, 0, OP_NOP, 0, f_sin, "sine of value a within accuracy b",
  1171. X    "sinh", 1, 2, FE, OP_NOP, qsinh, 0, "hyperbolic sine of a within accuracy b",
  1172. X    "size", 1, 1, 0, OP_NOP, 0, f_size, "total number of elements in value",
  1173. X    "sqrt", 1, 2, 0, OP_NOP, 0, f_sqrt, "square root of value a within accuracy b",
  1174. X    "ssq", 1, IN, 0, OP_NOP, 0, f_ssq, "sum of squares of values",
  1175. X    "str", 1, 1, 0, OP_NOP, 0, f_str, "simple value converted to string",
  1176. X    "strcat", 1,IN, 0, OP_NOP, 0, f_strcat, "concatenate strings together",
  1177. X    "strlen", 1, 1, 0, OP_NOP, 0, f_strlen, "length of string",
  1178. X    "strprintf", 1, IN, 0, OP_NOP, 0, f_strprintf, "return formatted output as a string",
  1179. X    "substr", 3, 3, 0, OP_NOP, 0, f_substr, "substring of a from position b for c chars",
  1180. X    "swap", 2, 2, 0, OP_SWAP, 0, 0, "swap values of variables a and b (can be dangerous)",
  1181. X    "tan", 1, 2, FE, OP_NOP, qtan, 0, "tangent of a within accuracy b",
  1182. X    "tanh", 1, 2, FE, OP_NOP, qtanh, 0, "hyperbolic tangent of a within accuracy b",
  1183. X    "trunc", 1, 2, 0, OP_NOP, f_trunc, 0, "truncate a to b number of decimal places",
  1184. X    "xor", 1, IN, 0, OP_NOP, f_xor, 0, "logical xor",
  1185. X    NULL, 0, 0, 0, OP_NOP, 0, 0, NULL /* end of table */
  1186. X};
  1187. X
  1188. X
  1189. X/*
  1190. X * Call a built-in function.
  1191. X * Arguments to the function are on the stack, but are not removed here.
  1192. X * Functions are either purely numeric, or else can take any value type.
  1193. X */
  1194. XVALUE
  1195. Xbuiltinfunc(index, argcount, stck)
  1196. X    long index;
  1197. X    VALUE *stck;        /* arguments on the stack */
  1198. X{
  1199. X    VALUE *sp;        /* pointer to stack entries */
  1200. X    VALUE **vpp;        /* pointer to current value address */
  1201. X    struct builtin *bp;    /* builtin function to be called */
  1202. X    long i;            /* index */
  1203. X    NUMBER *numargs[IN];    /* numeric arguments for function */
  1204. X    VALUE *valargs[IN];    /* addresses of actual arguments */
  1205. X    VALUE result;        /* general result of function */
  1206. X
  1207. X    if ((unsigned long)index >= (sizeof(builtins) / sizeof(builtins[0])) - 1)
  1208. X        math_error("Bad built-in function index");
  1209. X    bp = &builtins[index];
  1210. X    if (argcount < bp->b_minargs)
  1211. X        math_error("Too few arguments for builtin function \"%s\"", bp->b_name);
  1212. X    if ((argcount > bp->b_maxargs) || (argcount > IN))
  1213. X        math_error("Too many arguments for builtin function \"%s\"", bp->b_name);
  1214. X    /*
  1215. X     * If an address was passed, then point at the real variable,
  1216. X     * otherwise point at the stack value itself (unless the function
  1217. X     * is very special).
  1218. X     */
  1219. X    sp = stck - argcount + 1;
  1220. X    vpp = valargs;
  1221. X    for (i = argcount; i > 0; i--) {
  1222. X        if ((sp->v_type != V_ADDR) || (bp->b_flags & FA))
  1223. X            *vpp = sp;
  1224. X        else
  1225. X            *vpp = sp->v_addr;
  1226. X        sp++;
  1227. X        vpp++;
  1228. X    }
  1229. X    /*
  1230. X     * Handle general values if the function accepts them.
  1231. X     */
  1232. X    if (bp->b_valfunc) {
  1233. X        vpp = valargs;
  1234. X        if ((bp->b_minargs == 1) && (bp->b_maxargs == 1))
  1235. X            result = (*bp->b_valfunc)(vpp[0]);
  1236. X        else if ((bp->b_minargs == 2) && (bp->b_maxargs == 2))
  1237. X            result = (*bp->b_valfunc)(vpp[0], vpp[1]);
  1238. X        else if ((bp->b_minargs == 3) && (bp->b_maxargs == 3))
  1239. X            result = (*bp->b_valfunc)(vpp[0], vpp[1], vpp[2]);
  1240. X        else
  1241. X            result = (*bp->b_valfunc)(argcount, vpp);
  1242. X        return result;
  1243. X    }
  1244. X    /*
  1245. X     * Function must be purely numeric, so handle that.
  1246. X     */
  1247. X    vpp = valargs;
  1248. X    for (i = 0; i < argcount; i++) {
  1249. X        if ((*vpp)->v_type != V_NUM)
  1250. X            math_error("Non-real argument for builtin function %s", bp->b_name);
  1251. X        numargs[i] = (*vpp)->v_num;
  1252. X        vpp++;
  1253. X    }
  1254. X    result.v_type = V_NUM;
  1255. X    if (!(bp->b_flags & FE) && (bp->b_minargs != bp->b_maxargs)) {
  1256. X        result.v_num = (*bp->b_numfunc)(argcount, numargs);
  1257. X        return result;
  1258. X    }
  1259. X    if ((bp->b_flags & FE) && (argcount < bp->b_maxargs))
  1260. X        numargs[argcount++] = _epsilon_;
  1261. X
  1262. X    switch (argcount) {
  1263. X        case 0:
  1264. X            result.v_num = (*bp->b_numfunc)();
  1265. X            break;
  1266. X        case 1:
  1267. X            result.v_num = (*bp->b_numfunc)(numargs[0]);
  1268. X            break;
  1269. X        case 2:
  1270. X            result.v_num = (*bp->b_numfunc)(numargs[0], numargs[1]);
  1271. X            break;
  1272. X        case 3:
  1273. X            result.v_num = (*bp->b_numfunc)(numargs[0], numargs[1], numargs[2]);
  1274. X            break;
  1275. X        default:
  1276. X            math_error("Bad builtin function call");
  1277. X    }
  1278. X    return result;
  1279. X}
  1280. X
  1281. X
  1282. Xstatic VALUE
  1283. Xf_eval(vp)
  1284. X    VALUE *vp;
  1285. X{
  1286. X    FUNC    *oldfunc;
  1287. X    FUNC    *newfunc;
  1288. X    VALUE    result;
  1289. X
  1290. X    if (vp->v_type != V_STR)
  1291. X        math_error("Evaluating non-string argument");
  1292. X    (void) openstring(vp->v_str);
  1293. X    oldfunc = curfunc;
  1294. X    enterfilescope();
  1295. X    if (evaluate(TRUE)) {
  1296. X        exitfilescope();
  1297. X        freevalue(stack--);
  1298. X        newfunc = curfunc;
  1299. X        curfunc = oldfunc;
  1300. X        result = newfunc->f_savedvalue;
  1301. X        newfunc->f_savedvalue.v_type = V_NULL;
  1302. X        if (newfunc != oldfunc)
  1303. X            free(newfunc);
  1304. X        return result;
  1305. X    }
  1306. X    exitfilescope();
  1307. X    newfunc = curfunc;
  1308. X    curfunc = oldfunc;
  1309. X    freevalue(&newfunc->f_savedvalue);
  1310. X    newfunc->f_savedvalue.v_type = V_NULL;
  1311. X    if (newfunc != oldfunc)
  1312. X        free(newfunc);
  1313. X    math_error("Evaluation error");
  1314. X    /*NOTREACHED*/
  1315. X}
  1316. X
  1317. X
  1318. Xstatic VALUE
  1319. Xf_prompt(vp)
  1320. X    VALUE *vp;
  1321. X{
  1322. X    VALUE result;
  1323. X    char *cp;
  1324. X    char *newcp;
  1325. X
  1326. X    if (inputisterminal()) {
  1327. X        printvalue(vp, PRINT_SHORT);
  1328. X        math_flush();
  1329. X    }
  1330. X    cp = nextline();
  1331. X    if (cp == NULL)
  1332. X        math_error("End of file while prompting");
  1333. X    if (*cp == '\0') {
  1334. X        result.v_type = V_STR;
  1335. X        result.v_subtype = V_STRLITERAL;
  1336. X        result.v_str = "";
  1337. X        return result;
  1338. X    }
  1339. X    newcp = (char *)malloc(strlen(cp) + 1);
  1340. X    if (newcp == NULL)
  1341. X        math_error("Cannot allocate string");
  1342. X    strcpy(newcp, cp);
  1343. X    result.v_str = newcp;
  1344. X    result.v_type = V_STR;
  1345. X    result.v_subtype = V_STRALLOC;
  1346. X    return result;
  1347. X}
  1348. X
  1349. X
  1350. Xstatic VALUE
  1351. Xf_str(vp)
  1352. X    VALUE *vp;
  1353. X{
  1354. X    VALUE result;
  1355. X    char *cp;
  1356. X
  1357. X    switch (vp->v_type) {
  1358. X        case V_STR:
  1359. X            copyvalue(vp, &result);
  1360. X            return result;
  1361. X        case V_NULL:
  1362. X            result.v_str = "";
  1363. X            result.v_type = V_STR;
  1364. X            result.v_subtype = V_STRLITERAL;
  1365. X            return result;
  1366. X        case V_NUM:
  1367. X            math_divertio();
  1368. X            qprintnum(vp->v_num, MODE_DEFAULT);
  1369. X            cp = math_getdivertedio();
  1370. X            break;
  1371. X        case V_COM:
  1372. X            math_divertio();
  1373. X            comprint(vp->v_com);
  1374. X            cp = math_getdivertedio();
  1375. X            break;
  1376. X        default:
  1377. X            math_error("Non-simple type for string conversion");
  1378. X    }
  1379. X    result.v_str = cp;
  1380. X    result.v_type = V_STR;
  1381. X    result.v_subtype = V_STRALLOC;
  1382. X    return result;
  1383. X}
  1384. X
  1385. X
  1386. Xstatic VALUE
  1387. Xf_poly(count, vals)
  1388. X    VALUE **vals;
  1389. X{
  1390. X    VALUE *x;
  1391. X    VALUE result, tmp;
  1392. X
  1393. X    x = vals[--count];
  1394. X    copyvalue(*vals++, &result);
  1395. X    while (--count > 0) {
  1396. X        mulvalue(&result, x, &tmp);
  1397. X        freevalue(&result);
  1398. X        addvalue(*vals++, &tmp, &result);
  1399. X        freevalue(&tmp);
  1400. X    }
  1401. X    return result;
  1402. X}
  1403. X
  1404. X
  1405. Xstatic NUMBER *
  1406. Xf_mne(val1, val2, val3)
  1407. X    NUMBER *val1, *val2, *val3;
  1408. X{
  1409. X    return itoq((long) qcmpmod(val1, val2, val3));
  1410. X}
  1411. X
  1412. X
  1413. Xstatic NUMBER *
  1414. Xf_isrel(val1, val2)
  1415. X    NUMBER *val1, *val2;
  1416. X{
  1417. X    if (qisfrac(val1) || qisfrac(val2))
  1418. X        math_error("Non-integer for isrel");
  1419. X    return itoq((long) zrelprime(val1->num, val2->num));
  1420. X}
  1421. X
  1422. X
  1423. Xstatic NUMBER *
  1424. Xf_issquare(vp)
  1425. X    NUMBER *vp;
  1426. X{
  1427. X    return itoq((long) qissquare(vp));
  1428. X}
  1429. X
  1430. X
  1431. Xstatic NUMBER *
  1432. Xf_primetest(val1, val2)
  1433. X    NUMBER *val1, *val2;
  1434. X{
  1435. X    return itoq((long) qprimetest(val1, val2));
  1436. X}
  1437. X
  1438. X
  1439. Xstatic NUMBER *
  1440. Xf_isset(val1, val2)
  1441. X    NUMBER *val1, *val2;
  1442. X{
  1443. X    if (qisfrac(val2))
  1444. X        math_error("Non-integral bit position");
  1445. X    if (qiszero(val1) || (qisint(val1) && qisneg(val2)))
  1446. X        return qlink(&_qzero_);
  1447. X    if (zisbig(val2->num)) {
  1448. X        if (qisneg(val2))
  1449. X            math_error("Very large bit position");
  1450. X        return qlink(&_qzero_);
  1451. X    }
  1452. X    return itoq((long) qisset(val1, qtoi(val2)));
  1453. X}
  1454. X
  1455. X
  1456. Xstatic NUMBER *
  1457. Xf_digit(val1, val2)
  1458. X    NUMBER *val1, *val2;
  1459. X{
  1460. X    if (qisfrac(val2))
  1461. X        math_error("Non-integral digit position");
  1462. X    if (qiszero(val1) || (qisint(val1) && qisneg(val2)))
  1463. X        return qlink(&_qzero_);
  1464. X    if (zisbig(val2->num)) {
  1465. X        if (qisneg(val2))
  1466. X            math_error("Very large digit position");
  1467. X        return qlink(&_qzero_);
  1468. X    }
  1469. X    return itoq((long) qdigit(val1, qtoi(val2)));
  1470. X}
  1471. X
  1472. X
  1473. Xstatic NUMBER *
  1474. Xf_digits(val)
  1475. X    NUMBER *val;
  1476. X{
  1477. X    return itoq((long) qdigits(val));
  1478. X}
  1479. X
  1480. X
  1481. Xstatic NUMBER *
  1482. Xf_places(val)
  1483. X    NUMBER *val;
  1484. X{
  1485. X    return itoq((long) qplaces(val));
  1486. X}
  1487. X
  1488. X
  1489. Xstatic NUMBER *
  1490. Xf_xor(count, vals)
  1491. X    NUMBER **vals;
  1492. X{
  1493. X    NUMBER *val, *tmp;
  1494. X
  1495. X    val = qlink(*vals);
  1496. X    while (--count > 0) {
  1497. X        tmp = qxor(val, *++vals);
  1498. X        qfree(val);
  1499. X        val = tmp;
  1500. X    }
  1501. X    return val;
  1502. X}
  1503. X
  1504. X
  1505. Xstatic NUMBER *
  1506. Xf_min(count, vals)
  1507. X    NUMBER **vals;
  1508. X{
  1509. X    NUMBER *val, *tmp;
  1510. X
  1511. X    val = qlink(*vals);
  1512. X    while (--count > 0) {
  1513. X        tmp = qmin(val, *++vals);
  1514. X        qfree(val);
  1515. X        val = tmp;
  1516. X    }
  1517. X    return val;
  1518. X}
  1519. X
  1520. X
  1521. Xstatic NUMBER *
  1522. Xf_max(count, vals)
  1523. X    NUMBER **vals;
  1524. X{
  1525. X    NUMBER *val, *tmp;
  1526. X
  1527. X    val = qlink(*vals);
  1528. X    while (--count > 0) {
  1529. X        tmp = qmax(val, *++vals);
  1530. X        qfree(val);
  1531. X        val = tmp;
  1532. X    }
  1533. X    return val;
  1534. X}
  1535. X
  1536. X
  1537. Xstatic NUMBER *
  1538. Xf_gcd(count, vals)
  1539. X    NUMBER **vals;
  1540. X{
  1541. X    NUMBER *val, *tmp;
  1542. X
  1543. X    val = qlink(*vals);
  1544. X    while (--count > 0) {
  1545. X        tmp = qgcd(val, *++vals);
  1546. X        qfree(val);
  1547. X        val = tmp;
  1548. X        if (qisunit(val))
  1549. X            break;
  1550. X    }
  1551. X    return val;
  1552. X}
  1553. X
  1554. X
  1555. Xstatic NUMBER *
  1556. Xf_lcm(count, vals)
  1557. X    NUMBER **vals;
  1558. X{
  1559. X    NUMBER *val, *tmp;
  1560. X
  1561. X    val = qlink(*vals);
  1562. X    while (--count > 0) {
  1563. X        tmp = qlcm(val, *++vals);
  1564. X        qfree(val);
  1565. X        val = tmp;
  1566. X    }
  1567. X    return val;
  1568. X}
  1569. X
  1570. X
  1571. Xstatic VALUE
  1572. Xf_hash(count, vals)
  1573. X    VALUE **vals;
  1574. X{
  1575. X    HASH hash;
  1576. X    long lhash;
  1577. X    VALUE result;
  1578. X
  1579. X    hash = 0;
  1580. X    while (count-- > 0)
  1581. X        hash = hash * 947369 + hashvalue(*vals++);
  1582. X    lhash = (long) hash;
  1583. X    if (lhash < 0)
  1584. X        lhash = -lhash;
  1585. X    if (lhash < 0)
  1586. X        lhash = 0;
  1587. X    result.v_num = itoq(lhash);
  1588. X    result.v_type = V_NUM;
  1589. X    return result;
  1590. X}
  1591. X
  1592. X
  1593. Xstatic VALUE
  1594. Xf_avg(count, vals)
  1595. X    VALUE **vals;
  1596. X{
  1597. X    int i;
  1598. X    VALUE result;
  1599. X    VALUE tmp;
  1600. X    VALUE div;
  1601. X
  1602. X    result.v_num = qlink(&_qzero_);
  1603. X    result.v_type = V_NUM;
  1604. X    for (i = count; i > 0; i--) {
  1605. X        addvalue(&result, *vals++, &tmp);
  1606. X        freevalue(&result);
  1607. X        result = tmp;
  1608. X    }
  1609. X    if (count <= 1)
  1610. X        return result;
  1611. X    div.v_num = itoq((long) count);
  1612. X    div.v_type = V_NUM;
  1613. X    divvalue(&result, &div, &tmp);
  1614. X    qfree(div.v_num);
  1615. X    return tmp;
  1616. X}
  1617. X
  1618. X
  1619. Xstatic NUMBER *
  1620. Xf_hmean(count, vals)
  1621. X    NUMBER **vals;
  1622. X{
  1623. X    NUMBER *val, *tmp, *tmp2;
  1624. X
  1625. X    val = qinv(*vals);
  1626. X    while (--count > 0) {
  1627. X        tmp2 = qinv(*++vals);
  1628. X        tmp = qadd(val, tmp2);
  1629. X        qfree(tmp2);
  1630. X        qfree(val);
  1631. X        val = tmp;
  1632. X    }
  1633. X    tmp = qinv(val);
  1634. X    qfree(val);
  1635. X    return tmp;
  1636. X}
  1637. X
  1638. X
  1639. Xstatic VALUE
  1640. Xf_ssq(count, vals)
  1641. X    VALUE **vals;
  1642. X{
  1643. X    VALUE result, tmp1, tmp2;
  1644. X
  1645. X    squarevalue(*vals++, &result);
  1646. X    while (--count > 0) {
  1647. X        squarevalue(*vals++, &tmp1);
  1648. X        addvalue(&tmp1, &result, &tmp2);
  1649. X        freevalue(&tmp1);
  1650. X        freevalue(&result);
  1651. X        result = tmp2;
  1652. X    }
  1653. X    return result;
  1654. X}
  1655. X
  1656. X
  1657. Xstatic NUMBER *
  1658. Xf_ismult(val1, val2)
  1659. X    NUMBER *val1, *val2;
  1660. X{
  1661. X    return itoq((long) qdivides(val1, val2));
  1662. X}
  1663. X
  1664. X
  1665. Xstatic NUMBER *
  1666. Xf_meq(val1, val2, val3)
  1667. X    NUMBER *val1, *val2, *val3;
  1668. X{
  1669. X    NUMBER *tmp, *res;
  1670. X
  1671. X    tmp = qsub(val1, val2);
  1672. X    res = itoq((long) qdivides(tmp, val3));
  1673. X    qfree(tmp);
  1674. X    return res;
  1675. X}
  1676. X
  1677. X
  1678. Xstatic VALUE
  1679. Xf_exp(count, vals)
  1680. X    VALUE **vals;
  1681. X{
  1682. X    VALUE result;
  1683. X    NUMBER *err;
  1684. X
  1685. X    err = _epsilon_;
  1686. X    if (count == 2) {
  1687. X        if (vals[1]->v_type != V_NUM)
  1688. X            math_error("Non-real epsilon value for exp");
  1689. X        err = vals[1]->v_num;
  1690. X    }
  1691. X    switch (vals[0]->v_type) {
  1692. X        case V_NUM:
  1693. X            result.v_num = qexp(vals[0]->v_num, err);
  1694. X            result.v_type = V_NUM;
  1695. X            break;
  1696. X        case V_COM:
  1697. X            result.v_com = cexp(vals[0]->v_com, err);
  1698. X            result.v_type = V_COM;
  1699. X            break;
  1700. X        default:
  1701. X            math_error("Bad argument type for exp");
  1702. X    }
  1703. X    return result;
  1704. X}
  1705. X
  1706. X
  1707. Xstatic VALUE
  1708. Xf_ln(count, vals)
  1709. X    VALUE **vals;
  1710. X{
  1711. X    VALUE result;
  1712. X    COMPLEX ctmp;
  1713. X    NUMBER *err;
  1714. X
  1715. X    err = _epsilon_;
  1716. X    if (count == 2) {
  1717. X        if (vals[1]->v_type != V_NUM)
  1718. X            math_error("Non-real epsilon value for ln");
  1719. X        err = vals[1]->v_num;
  1720. X    }
  1721. X    switch (vals[0]->v_type) {
  1722. X        case V_NUM:
  1723. X            if (!qisneg(vals[0]->v_num) && !qiszero(vals[0]->v_num)) {
  1724. X                result.v_num = qln(vals[0]->v_num, err);
  1725. X                result.v_type = V_NUM;
  1726. X                break;
  1727. X            }
  1728. X            ctmp.real = vals[0]->v_num;
  1729. X            ctmp.imag = &_qzero_;
  1730. X            ctmp.links = 1;
  1731. X            result.v_com = cln(&ctmp, err);
  1732. X            result.v_type = V_COM;
  1733. X            break;
  1734. X        case V_COM:
  1735. X            result.v_com = cln(vals[0]->v_com, err);
  1736. X            result.v_type = V_COM;
  1737. X            break;
  1738. X        default:
  1739. X            math_error("Bad argument type for ln");
  1740. X    }
  1741. X    return result;
  1742. X}
  1743. X
  1744. X
  1745. Xstatic VALUE
  1746. Xf_cos(count, vals)
  1747. X    VALUE **vals;
  1748. X{
  1749. X    VALUE result;
  1750. X    COMPLEX *c;
  1751. X    NUMBER *err;
  1752. X
  1753. X    err = _epsilon_;
  1754. X    if (count == 2) {
  1755. X        if (vals[1]->v_type != V_NUM)
  1756. X            math_error("Non-real epsilon value for cos");
  1757. X        err = vals[1]->v_num;
  1758. X    }
  1759. X    switch (vals[0]->v_type) {
  1760. X        case V_NUM:
  1761. X            result.v_num = qcos(vals[0]->v_num, err);
  1762. X            result.v_type = V_NUM;
  1763. X            break;
  1764. X        case V_COM:
  1765. X            c = ccos(vals[0]->v_com, err);
  1766. X            result.v_com = c;
  1767. X            result.v_type = V_COM;
  1768. X            if (cisreal(c)) {
  1769. X                result.v_num = qlink(c->real);
  1770. X                result.v_type = V_NUM;
  1771. X                comfree(c);
  1772. X            }
  1773. X            break;
  1774. X        default:
  1775. X            math_error("Bad argument type for cos");
  1776. X    }
  1777. X    return result;
  1778. X}
  1779. X
  1780. X
  1781. Xstatic VALUE
  1782. Xf_sin(count, vals)
  1783. X    VALUE **vals;
  1784. X{
  1785. X    VALUE result;
  1786. X    COMPLEX *c;
  1787. X    NUMBER *err;
  1788. X
  1789. X    err = _epsilon_;
  1790. X    if (count == 2) {
  1791. X        if (vals[1]->v_type != V_NUM)
  1792. X            math_error("Non-real epsilon value for sin");
  1793. X        err = vals[1]->v_num;
  1794. X    }
  1795. X    switch (vals[0]->v_type) {
  1796. X        case V_NUM:
  1797. X            result.v_num = qsin(vals[0]->v_num, err);
  1798. X            result.v_type = V_NUM;
  1799. X            break;
  1800. X        case V_COM:
  1801. X            c = csin(vals[0]->v_com, err);
  1802. X            result.v_com = c;
  1803. X            result.v_type = V_COM;
  1804. X            if (cisreal(c)) {
  1805. X                result.v_num = qlink(c->real);
  1806. X                result.v_type = V_NUM;
  1807. X                comfree(c);
  1808. X            }
  1809. X            break;
  1810. X        default:
  1811. X            math_error("Bad argument type for sin");
  1812. X    }
  1813. X    return result;
  1814. X}
  1815. X
  1816. X
  1817. Xstatic VALUE
  1818. Xf_arg(count, vals)
  1819. X    VALUE **vals;
  1820. X{
  1821. X    VALUE result;
  1822. X    COMPLEX *c;
  1823. X    NUMBER *err;
  1824. X
  1825. X    err = _epsilon_;
  1826. X    if (count == 2) {
  1827. X        if (vals[1]->v_type != V_NUM)
  1828. X            math_error("Non-real epsilon value for arg");
  1829. X        err = vals[1]->v_num;
  1830. X    }
  1831. X    result.v_type = V_NUM;
  1832. X    switch (vals[0]->v_type) {
  1833. X        case V_NUM:
  1834. X            if (qisneg(vals[0]->v_num))
  1835. X                result.v_num = qpi(err);
  1836. X            else
  1837. X                result.v_num = qlink(&_qzero_);
  1838. X            break;
  1839. X        case V_COM:
  1840. X            c = vals[0]->v_com;
  1841. X            if (ciszero(c))
  1842. X                result.v_num = qlink(&_qzero_);
  1843. X            else
  1844. X                result.v_num = qatan2(c->imag, c->real, err);
  1845. X            break;
  1846. X        default:
  1847. X            math_error("Bad argument type for arg");
  1848. X    }
  1849. X    return result;
  1850. X}
  1851. X
  1852. X
  1853. Xstatic NUMBER *
  1854. Xf_legtoleg(val1, val2)
  1855. X    NUMBER *val1, *val2;
  1856. X{
  1857. X    return qlegtoleg(val1, val2, FALSE);
  1858. X}
  1859. X
  1860. X
  1861. Xstatic NUMBER *
  1862. Xf_trunc(count, vals)
  1863. X    NUMBER **vals;
  1864. X{
  1865. X    NUMBER *val;
  1866. X
  1867. X    val = &_qzero_;
  1868. X    if (count == 2)
  1869. X        val = vals[1];
  1870. X    return qtrunc(*vals, val);
  1871. X}
  1872. X
  1873. X
  1874. Xstatic VALUE
  1875. Xf_bround(count, vals)
  1876. X    VALUE **vals;
  1877. X{
  1878. X    VALUE *vp, tmp, res;
  1879. X
  1880. X    if (count > 1)
  1881. X        vp = vals[1];
  1882. X    else {
  1883. X        tmp.v_type = V_INT;
  1884. X        tmp.v_num = 0;
  1885. X        vp = &tmp;
  1886. X    }
  1887. X    broundvalue(vals[0], vp, &res);
  1888. X    return res;
  1889. X}
  1890. X
  1891. X
  1892. Xstatic VALUE
  1893. Xf_round(count, vals)
  1894. X    VALUE **vals;
  1895. X{
  1896. X    VALUE *vp, tmp, res;
  1897. X
  1898. X    if (count > 1)
  1899. X        vp = vals[1];
  1900. X    else {
  1901. X        tmp.v_type = V_INT;
  1902. X        tmp.v_num = 0;
  1903. X        vp = &tmp;
  1904. X    }
  1905. X    roundvalue(vals[0], vp, &res);
  1906. X    return res;
  1907. X}
  1908. X
  1909. X
  1910. Xstatic NUMBER *
  1911. Xf_btrunc(count, vals)
  1912. X    NUMBER **vals;
  1913. X{
  1914. X    NUMBER *val;
  1915. X
  1916. X    val = &_qzero_;
  1917. X    if (count == 2)
  1918. X        val = vals[1];
  1919. X    return qbtrunc(*vals, val);
  1920. X}
  1921. X
  1922. X
  1923. Xstatic NUMBER *
  1924. Xf_near(count, vals)
  1925. X    NUMBER **vals;
  1926. X{
  1927. X    NUMBER *val;
  1928. X
  1929. X    val = _epsilon_;
  1930. X    if (count == 3)
  1931. X        val = vals[2];
  1932. X    return itoq((long) qnear(vals[0], vals[1], val));
  1933. X}
  1934. X
  1935. X
  1936. Xstatic NUMBER *
  1937. Xf_cfsim(val)
  1938. X    NUMBER *val;
  1939. X{
  1940. X    return qcfappr(val, NULL);
  1941. X}
  1942. X
  1943. X
  1944. Xstatic NUMBER *
  1945. Xf_ceil(val)
  1946. X    NUMBER *val;
  1947. X{
  1948. X    NUMBER *val2;
  1949. X
  1950. X    if (qisint(val))
  1951. X        return qlink(val);
  1952. X    val2 = qint(val);
  1953. X    if (qisneg(val2))
  1954. X        return val2;
  1955. X    val = qinc(val2);
  1956. X    qfree(val2);
  1957. X    return val;
  1958. X}
  1959. X
  1960. X
  1961. Xstatic NUMBER *
  1962. Xf_floor(val)
  1963. X    NUMBER *val;
  1964. X{
  1965. X    NUMBER *val2;
  1966. X
  1967. X    if (qisint(val))
  1968. X        return qlink(val);
  1969. X    val2 = qint(val);
  1970. X    if (!qisneg(val2))
  1971. X        return val2;
  1972. X    val = qdec(val2);
  1973. X    qfree(val2);
  1974. X    return val;
  1975. X}
  1976. X
  1977. X
  1978. Xstatic NUMBER *
  1979. Xf_highbit(val)
  1980. X    NUMBER *val;
  1981. X{
  1982. X    if (qiszero(val))
  1983. X        math_error("Highbit of zero");
  1984. X    if (qisfrac(val))
  1985. X        math_error("Highbit of non-integer");
  1986. X    return itoq(zhighbit(val->num));
  1987. X}
  1988. X
  1989. X
  1990. Xstatic NUMBER *
  1991. Xf_lowbit(val)
  1992. X    NUMBER *val;
  1993. X{
  1994. X    if (qiszero(val))
  1995. X        math_error("Lowbit of zero");
  1996. X    if (qisfrac(val))
  1997. X        math_error("Lowbit of non-integer");
  1998. X    return itoq(zlowbit(val->num));
  1999. X}
  2000. X
  2001. X
  2002. Xstatic VALUE
  2003. Xf_sqrt(count, vals)
  2004. X    VALUE **vals;
  2005. X{
  2006. X    VALUE *vp, err, result;
  2007. X
  2008. X    if (count > 1)
  2009. X        vp = vals[1];
  2010. X    else {
  2011. X        err.v_num = _epsilon_;
  2012. X        err.v_type = V_NUM;
  2013. X        vp = &err;
  2014. X    }
  2015. X    sqrtvalue(vals[0], vp, &result);
  2016. X    return result;
  2017. X}
  2018. X
  2019. X
  2020. Xstatic VALUE
  2021. Xf_root(count, vals)
  2022. X    VALUE **vals;
  2023. X{
  2024. X    VALUE *vp, err, result;
  2025. X
  2026. X    if (count > 2)
  2027. X        vp = vals[3];
  2028. X    else {
  2029. X        err.v_num = _epsilon_;
  2030. X        err.v_type = V_NUM;
  2031. X        vp = &err;
  2032. X    }
  2033. X    rootvalue(vals[0], vals[1], vp, &result);
  2034. X    return result;
  2035. X}
  2036. X
  2037. X
  2038. Xstatic VALUE
  2039. Xf_power(count, vals)
  2040. X    VALUE **vals;
  2041. X{
  2042. X    VALUE *vp, err, result;
  2043. X
  2044. X    if (count > 2)
  2045. X        vp = vals[2];
  2046. X    else {
  2047. X        err.v_num = _epsilon_;
  2048. X        err.v_type = V_NUM;
  2049. X        vp = &err;
  2050. X    }
  2051. X    powervalue(vals[0], vals[1], vp, &result);
  2052. X    return result;
  2053. X}
  2054. X
  2055. X
  2056. Xstatic VALUE
  2057. Xf_polar(count, vals)
  2058. X    VALUE **vals;
  2059. X{
  2060. X    VALUE *vp, err, result;
  2061. X    COMPLEX *c;
  2062. X
  2063. X    if (count > 2)
  2064. X        vp = vals[2];
  2065. X    else {
  2066. X        err.v_num = _epsilon_;
  2067. X        err.v_type = V_NUM;
  2068. X        vp = &err;
  2069. X    }
  2070. X    if ((vals[0]->v_type != V_NUM) || (vals[1]->v_type != V_NUM))
  2071. X        math_error("Non-real argument for polar");
  2072. X    if ((vp->v_type != V_NUM) || qisneg(vp->v_num) || qiszero(vp->v_num))
  2073. X        math_error("Bad epsilon value for polar");
  2074. X    c = cpolar(vals[0]->v_num, vals[1]->v_num, vp->v_num);
  2075. X    result.v_com = c;
  2076. X    result.v_type = V_COM;
  2077. X    if (cisreal(c)) {
  2078. X        result.v_num = qlink(c->real);
  2079. X        result.v_type = V_NUM;
  2080. X        comfree(c);
  2081. X    }
  2082. X    return result;
  2083. X}
  2084. X
  2085. X
  2086. Xstatic NUMBER *
  2087. Xf_ilog(val1, val2)
  2088. X    NUMBER *val1, *val2;
  2089. X{
  2090. X    return itoq(qilog(val1, val2));
  2091. X}
  2092. X
  2093. X
  2094. Xstatic NUMBER *
  2095. Xf_ilog2(val)
  2096. X    NUMBER *val;
  2097. X{
  2098. X    return itoq(qilog2(val));
  2099. X}
  2100. X
  2101. X
  2102. Xstatic NUMBER *
  2103. Xf_ilog10(val)
  2104. X    NUMBER *val;
  2105. X{
  2106. X    return itoq(qilog10(val));
  2107. X}
  2108. X
  2109. X
  2110. Xstatic NUMBER *
  2111. Xf_faccnt(val1, val2)
  2112. X    NUMBER *val1, *val2;
  2113. X{
  2114. X    return itoq(qdivcount(val1, val2));
  2115. X}
  2116. X
  2117. X
  2118. Xstatic VALUE
  2119. Xf_matfill(count, vals)
  2120. X    VALUE **vals;
  2121. X{
  2122. X    VALUE *v1, *v2, *v3;
  2123. X    VALUE result;
  2124. X
  2125. X    v1 = vals[0];
  2126. X    v2 = vals[1];
  2127. X    v3 = (count == 3) ? vals[2] : NULL;
  2128. X    if (v1->v_type != V_ADDR)
  2129. X        math_error("Non-variable argument for matfill");
  2130. X    v1 = v1->v_addr;
  2131. X    if (v1->v_type != V_MAT)
  2132. X        math_error("Non-matrix for matfill");
  2133. X    if (v2->v_type == V_ADDR)
  2134. X        v2 = v2->v_addr;
  2135. X    if (v3 && (v3->v_type == V_ADDR))
  2136. X        v3 = v3->v_addr;
  2137. X    matfill(v1->v_mat, v2, v3);
  2138. X    result.v_type = V_NULL;
  2139. X    return result;
  2140. X}
  2141. X
  2142. X
  2143. Xstatic VALUE
  2144. Xf_mattrans(vp)
  2145. X    VALUE *vp;
  2146. X{
  2147. X    VALUE result;
  2148. X
  2149. X    if (vp->v_type != V_MAT)
  2150. X        math_error("Non-matrix argument for mattrans");
  2151. X    result.v_type = V_MAT;
  2152. X    result.v_mat = mattrans(vp->v_mat);
  2153. X    return result;
  2154. X}
  2155. X
  2156. X
  2157. Xstatic VALUE
  2158. Xf_det(vp)
  2159. X    VALUE *vp;
  2160. X{
  2161. X    if (vp->v_type != V_MAT)
  2162. X        math_error("Non-matrix argument for det");
  2163. X    return matdet(vp->v_mat);
  2164. X}
  2165. X
  2166. X
  2167. Xstatic VALUE
  2168. Xf_matdim(vp)
  2169. X    VALUE *vp;
  2170. X{
  2171. X    VALUE result;
  2172. X
  2173. X    if (vp->v_type != V_MAT)
  2174. X        math_error("Non-matrix argument for matdim");
  2175. X    result.v_type = V_NUM;
  2176. X    result.v_num = itoq((long) vp->v_mat->m_dim);
  2177. X    return result;
  2178. X}
  2179. X
  2180. X
  2181. Xstatic VALUE
  2182. Xf_matmin(v1, v2)
  2183. X    VALUE *v1, *v2;
  2184. X{
  2185. X    VALUE result;
  2186. X    NUMBER *q;
  2187. X    long i;
  2188. X
  2189. X    if ((v1->v_type != V_MAT) || (v2->v_type != V_NUM))
  2190. X        math_error("Bad argument type for matmin");
  2191. X    q = v2->v_num;
  2192. X    i = qtoi(q);
  2193. X    if (qisfrac(q) || qisneg(q) || (i <= 0) || (i > v1->v_mat->m_dim))
  2194. X        math_error("Bad dimension value for matmin");
  2195. X    result.v_type = V_NUM;
  2196. X    result.v_num = itoq(v1->v_mat->m_min[i - 1]);
  2197. X    return result;
  2198. X}
  2199. X
  2200. X
  2201. Xstatic VALUE
  2202. Xf_matmax(v1, v2)
  2203. X    VALUE *v1, *v2;
  2204. X{
  2205. X    VALUE result;
  2206. X    NUMBER *q;
  2207. X    long i;
  2208. X
  2209. X    if ((v1->v_type != V_MAT) || (v2->v_type != V_NUM))
  2210. X        math_error("Bad argument type for matmax");
  2211. X    q = v2->v_num;
  2212. X    i = qtoi(q);
  2213. X    if (qisfrac(q) || qisneg(q) || (i <= 0) || (i > v1->v_mat->m_dim))
  2214. X        math_error("Bad dimension value for matmax");
  2215. X    result.v_type = V_NUM;
  2216. X    result.v_num = itoq(v1->v_mat->m_max[i - 1]);
  2217. X    return result;
  2218. X}
  2219. X
  2220. X
  2221. Xstatic VALUE
  2222. Xf_cp(v1, v2)
  2223. X    VALUE *v1, *v2;
  2224. X{
  2225. X    VALUE result;
  2226. X
  2227. X    if ((v1->v_type != V_MAT) || (v2->v_type != V_MAT))
  2228. X        math_error("Non-matrix argument for cross product");
  2229. X    result.v_type = V_MAT;
  2230. X    result.v_mat = matcross(v1->v_mat, v2->v_mat);
  2231. X    return result;
  2232. X}
  2233. X
  2234. X
  2235. Xstatic VALUE
  2236. Xf_dp(v1, v2)
  2237. X    VALUE *v1, *v2;
  2238. X{
  2239. X    if ((v1->v_type != V_MAT) || (v2->v_type != V_MAT))
  2240. X        math_error("Non-matrix argument for dot product");
  2241. X    return matdot(v1->v_mat, v2->v_mat);
  2242. X}
  2243. X
  2244. X
  2245. Xstatic VALUE
  2246. Xf_strlen(vp)
  2247. X    VALUE *vp;
  2248. X{
  2249. X    VALUE result;
  2250. X
  2251. X    if (vp->v_type != V_STR)
  2252. X        math_error("Non-string argument for strlen");
  2253. X    result.v_type = V_NUM;
  2254. X    result.v_num = itoq((long) strlen(vp->v_str));
  2255. X    return result;
  2256. X}
  2257. X
  2258. X
  2259. Xstatic VALUE
  2260. Xf_strcat(count, vals)
  2261. X    VALUE **vals;
  2262. X{
  2263. X    register VALUE **vp;
  2264. X    register char *cp;
  2265. X    int i;
  2266. X    long len;
  2267. X    long lengths[IN];
  2268. X    VALUE result;
  2269. X
  2270. X    len = 1;
  2271. X    vp = vals;
  2272. X    for (i = 0; i < count; i++) {
  2273. X        if ((*vp)->v_type != V_STR)
  2274. X            math_error("Non-string argument for strcat");
  2275. X        lengths[i] = strlen((*vp)->v_str);
  2276. X        len += lengths[i];
  2277. X        vp++;
  2278. X    }
  2279. X    cp = (char *)malloc(len);
  2280. X    if (cp == NULL)
  2281. X        math_error("No memory for strcat");
  2282. X    result.v_str = cp;
  2283. X    result.v_type = V_STR;
  2284. X    result.v_subtype = V_STRALLOC;
  2285. X    i = 0;
  2286. X    for (vp = vals; count-- > 0; vp++) {
  2287. X        strcpy(cp, (*vp)->v_str);
  2288. X        cp += lengths[i++];
  2289. X    }
  2290. X    return result;
  2291. X}
  2292. X
  2293. X
  2294. Xstatic VALUE
  2295. Xf_substr(v1, v2, v3)
  2296. X    VALUE *v1, *v2, *v3;
  2297. X{
  2298. X    NUMBER *q1, *q2;
  2299. X    long i1, i2, len;
  2300. X    char *cp;
  2301. X    VALUE result;
  2302. X
  2303. X    if (v1->v_type != V_STR)
  2304. X        math_error("Non-string argument for substr");
  2305. X    if ((v2->v_type != V_NUM) || (v3->v_type != V_NUM))
  2306. SHAR_EOF
  2307. echo "End of part 4"
  2308. echo "File calc2.9.0/func.c is continued in part 5"
  2309. echo "5" > s2_seq_.tmp
  2310. exit 0
  2311.