home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume11 / gnuplot2 / part06 < prev    next >
Encoding:
Text File  |  1990-03-25  |  64.9 KB  |  2,662 lines

  1. Newsgroups: comp.sources.misc
  2. organization: Pixar -- Marin County, California
  3. subject: v11i071: Gnuplot 2.0 - 6 of 14
  4. From: thaw@ucbvax.Berkeley.EDU@pixar.UUCP (Tom Williams)
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 11, Issue 71
  8. Submitted-by: thaw@ucbvax.Berkeley.EDU@pixar.UUCP (Tom Williams)
  9. Archive-name: gnuplot2/part06
  10.  
  11. This is gnuplot.sh06
  12.  
  13. --- CUT HERE ---
  14. #! /bin/sh
  15. echo x - help.c
  16. sed 's/^X//' >help.c <<'*-*-END-of-help.c-*-*'
  17. X#include <stdio.h>
  18. X
  19. Xextern int errno;
  20. X
  21. Xextern int strcmp();
  22. Xextern int strlen();
  23. Xextern char *strcpy();
  24. Xextern char *strncpy();
  25. Xextern char *strcat();
  26. Xextern char *strncat();
  27. Xextern char *getenv();
  28. Xextern FILE *fopen();
  29. Xextern char *malloc();
  30. X
  31. Xextern int instring();
  32. X
  33. X#define    SAME    0    /* for strcmp() */
  34. X
  35. X#include "help.h"    /* values passed back */
  36. X
  37. X/* help -- help subsystem that understands defined keywords
  38. X**
  39. X** Looks for the desired keyword in the help file at runtime, so you
  40. X** can give extra help or supply local customizations by merely editing
  41. X** the help file.
  42. X**
  43. X** The original (single-file) idea and algorithm is by John D. Johnson,
  44. X** Hewlett-Packard Company.  Thanx and a tip of the Hatlo hat!
  45. X**
  46. X** Much extension by David Kotz for use in gnutex, and then in gnuplot.
  47. X** Added output paging support, both unix and builtin. Rewrote completely
  48. X** to read helpfile into memory, avoiding reread of help file. 12/89.
  49. X**
  50. X** The help file looks like this (the question marks are really in column 1):
  51. X**
  52. X**     ?topic
  53. X**     This line is printed when the user wants help on "topic".
  54. X**     ?keyword
  55. X**     ?Keyword
  56. X**     ?KEYWORD
  57. X**     These lines will be printed on the screen if the user wanted
  58. X**     help on "keyword", "Keyword", or "KEYWORD".  No casefolding is
  59. X**    done on the keywords.
  60. X**     ?subject
  61. X**     ?alias
  62. X**     This line is printed for help on "subject" and "alias".
  63. X**     ?
  64. X**    ??
  65. X**     Since there is a null keyword for this line, this section
  66. X**     is printed when the user wants general help (when a help
  67. X**     keyword isn't given).  A command summary is usually here.
  68. X**    Notice that the null keyword is equivalent to a "?" keyword
  69. X**    here, because of the '?' and '??' topic lines above.
  70. X**   If multiple keywords are given, the first is considered the 
  71. X**   'primary' keyword. This affects a listing of available topics.
  72. X**     ?last-subject
  73. X**     Note that help sections are terminated by the start of the next
  74. X**     '?' entry or by EOF.  So you can't have a leading '?' on a line
  75. X**     of any help section.  You can re-define the magic character to
  76. X**    recognize in column 1, though, if '?' is too useful.  (Try ^A.)
  77. X*/
  78. X
  79. X#define    KEYFLAG    '?'    /* leading char in help file topic lines */
  80. X
  81. X/*
  82. X** Calling sequence:
  83. X**    int result;        # 0 == success
  84. X**    char *keyword;        # topic to give help on
  85. X**    char *pathname;        # path of help file
  86. X**    result = help(keyword, pathname);
  87. X** Sample:
  88. X**    cmd = "search\n";
  89. X**    helpfile = "/usr/local/lib/program/program.help";
  90. X**    if (help(cmd, helpfile) != H_FOUND)
  91. X**        printf("Sorry, no help for %s", cmd);
  92. X**
  93. X**
  94. X** Speed this up by replacing the stdio calls with open/close/read/write.
  95. X*/
  96. X#ifdef    WDLEN
  97. X#  define    PATHSIZE    WDLEN
  98. X#else
  99. X#  define    PATHSIZE    BUFSIZ
  100. X#endif
  101. X
  102. Xtypedef int boolean;
  103. X#ifndef TRUE
  104. X#define TRUE (1)
  105. X#define FALSE (0)
  106. X#endif
  107. X
  108. Xtypedef struct line_s LINEBUF;
  109. Xstruct line_s {
  110. X    char *line;            /* the text of this line */
  111. X    LINEBUF *next;            /* the next line */
  112. X};
  113. X
  114. Xtypedef struct linkey_s LINKEY;
  115. Xstruct linkey_s {
  116. X    char *key;                /* the name of this key */
  117. X    LINEBUF *text;            /* the text for this key */
  118. X    boolean primary;        /* TRUE -> is a primary name for a text block */
  119. X    LINKEY *next;            /* the next key in linked list */
  120. X};
  121. X
  122. Xtypedef struct key_s KEY;
  123. Xstruct key_s {
  124. X    char *key;                /* the name of this key */
  125. X    LINEBUF *text;            /* the text for this key */
  126. X    boolean primary;        /* TRUE -> is a primary name for a text block */
  127. X};
  128. Xstatic LINKEY *keylist;        /* linked list of keys */
  129. Xstatic KEY *keys = NULL;        /* array of keys */
  130. Xstatic int keycount = 0;        /* number of keys */
  131. X
  132. Xstatic int LoadHelp();
  133. Xstatic void sortkeys();
  134. Xstatic int keycomp();
  135. Xstatic LINEBUF *storeline();
  136. Xstatic void storekey();
  137. Xstatic KEY *FindHelp();
  138. Xstatic boolean Ambiguous();
  139. X
  140. X/* Help output */
  141. Xstatic void PrintHelp();
  142. Xstatic void ShowSubtopics();
  143. Xstatic void StartOutput();
  144. Xstatic void OutLine();
  145. Xstatic void EndOutput();
  146. Xstatic FILE *outfile;        /* for unix pager, if any */
  147. Xstatic int pagelines;        /* count for builtin pager */
  148. X#define SCREENSIZE 24        /* lines on screen (most have at least 24) */
  149. X
  150. X/* help:
  151. X * print a help message 
  152. X * also print available subtopics, if subtopics is TRUE
  153. X */
  154. Xhelp(keyword, path, subtopics)
  155. X    char *keyword;            /* on this topic */
  156. X    char *path;            /* from this file */
  157. X    boolean *subtopics;        /* (in) - subtopics only? */
  158. X                        /* (out) - are there subtopics? */
  159. X{
  160. X    static char oldpath[PATHSIZE] = "";    /* previous help file */
  161. X    char *oldpathp = oldpath;    /* pointer to same */
  162. X    int status;            /* result of LoadHelp */
  163. X    KEY *key;                /* key that matches keyword */
  164. X
  165. X    /*
  166. X    ** Load the help file if necessary (say, first time we enter this routine,
  167. X    ** or if the help file changes from the last time we were called).
  168. X    ** Also may occur if in-memory copy was freed. 
  169. X    ** Calling routine may access errno to determine cause of H_ERROR.
  170. X    */
  171. X    errno = 0;
  172. X    if (strncmp(oldpathp, path, sizeof oldpath) != SAME)
  173. X     FreeHelp();
  174. X    if (keys == NULL) {
  175. X       status = LoadHelp(path);
  176. X       if (status == H_ERROR)
  177. X        return(status);
  178. X
  179. X       /* save the new path in oldpath */
  180. X       if (strlen(path) < sizeof oldpath)
  181. X        (void) strcpy(oldpathp, path);
  182. X       else {                /* not enough room in oldpath, sigh */
  183. X          (void) strncpy(oldpathp, path, sizeof oldpath);
  184. X          oldpath[sizeof oldpath] = NULL;
  185. X       }
  186. X    }
  187. X
  188. X    /* look for the keyword in the help file */
  189. X    key = FindHelp(keyword);
  190. X    if (key != NULL) {
  191. X       /* found the keyword: print help and return */
  192. X       PrintHelp(key, subtopics);
  193. X       status = H_FOUND;
  194. X    } else {
  195. X       status = H_NOTFOUND;
  196. X    }
  197. X
  198. X    return(status);
  199. X}
  200. X
  201. X/* we only read the file once, into memory */
  202. Xstatic int
  203. XLoadHelp(path)
  204. X    char *path;
  205. X{
  206. X    FILE *helpfp = NULL;
  207. X    char buf[BUFSIZ];        /* line from help file */
  208. X    LINEBUF *head;            /* head of text list  */
  209. X    boolean primary;        /* first ? line of a set is primary */
  210. X
  211. X    if ((helpfp = fopen(path, "r")) == NULL) {
  212. X       /* can't open help file, so error exit */
  213. X       return (H_ERROR);
  214. X    }
  215. X    
  216. X    /*
  217. X    ** The help file is open.  Look in there for the keyword.
  218. X    */
  219. X    (void) fgets(buf, sizeof buf, helpfp);
  220. X    while (!feof(helpfp)) {
  221. X       /*
  222. X        ** Make an entry for each synonym keyword, pointing
  223. X        ** to same buffer. 
  224. X        */
  225. X       head = storeline( (char *)NULL ); /* make a dummy text entry */
  226. X       primary = TRUE;
  227. X       while (buf[0] == KEYFLAG) {
  228. X          storekey(buf+1, head, primary);    /* store this key */
  229. X          primary = FALSE;
  230. X          if (fgets(buf, sizeof buf, helpfp) == (char *)NULL)
  231. X            break;
  232. X       }
  233. X       /*
  234. X        ** Now store the text for this entry.
  235. X        ** buf already contains the first line of text.
  236. X        */
  237. X       while (buf[0] != KEYFLAG) {
  238. X          /* save text line */
  239. X          head->next = storeline(buf);
  240. X          head = head->next;
  241. X          if (fgets(buf, sizeof buf, helpfp) == (char *)NULL)
  242. X            break;
  243. X       }
  244. X    }
  245. X
  246. X    (void) fclose(helpfp);
  247. X
  248. X    /* we sort the keys so we can use binary search later */
  249. X    sortkeys();
  250. X    return(H_FOUND); /* ok */
  251. X}
  252. X
  253. X/* make a new line buffer and save this string there */
  254. Xstatic LINEBUF *
  255. Xstoreline(text)
  256. X    char *text;
  257. X{
  258. X    LINEBUF *new;
  259. X
  260. X    new = (LINEBUF *)malloc(sizeof(LINEBUF));
  261. X    if (new == NULL)
  262. X     int_error("not enough memory to store help file", -1);
  263. X    if (text != NULL) {
  264. X       new->line = (char *) malloc((unsigned int)(strlen(text)+1));
  265. X       if (new->line == NULL)
  266. X        int_error("not enough memory to store help file", -1);
  267. X       (void) strcpy(new->line, text);
  268. X    } else
  269. X     new->line = NULL;
  270. X
  271. X    new->next = NULL;
  272. X
  273. X    return(new);
  274. X}
  275. X
  276. X/* Add this keyword to the keys list, with the given text */
  277. Xstatic void
  278. Xstorekey(key, buffer, primary)
  279. X    char *key;
  280. X    LINEBUF *buffer;
  281. X    boolean primary;
  282. X{
  283. X    LINKEY *new;
  284. X
  285. X    key[strlen(key)-1] = '\0'; /* cut off \n  */
  286. X    
  287. X    new = (LINKEY *)malloc(sizeof(LINKEY));
  288. X    if (new == NULL)
  289. X     int_error("not enough memory to store help file", -1);
  290. X    new->key = (char *) malloc((unsigned int)(strlen(key)+1));
  291. X    if (new->key == NULL)
  292. X     int_error("not enough memory to store help file", -1);
  293. X    (void) strcpy(new->key, key);
  294. X    new->text = buffer;
  295. X    new->primary = primary;
  296. X
  297. X    /* add to front of list */
  298. X    new->next = keylist;
  299. X    keylist = new;
  300. X    keycount++;
  301. X}
  302. X
  303. X/* we sort the keys so we can use binary search later */
  304. X/* We have a linked list of keys and the number.
  305. X * to sort them we need an array, so we reform them into an array,
  306. X * and then throw away the list.
  307. X */
  308. Xstatic void
  309. Xsortkeys()
  310. X{
  311. X    LINKEY *p,*n;            /* pointers to linked list */
  312. X    int i;                /* index into key array */
  313. X    
  314. X    /* allocate the array */
  315. X    keys = (KEY *)malloc((unsigned int)((keycount+1) * sizeof(KEY)));
  316. X    if (keys == NULL)
  317. X     int_error("not enough memory to store help file", -1);
  318. X    
  319. X    /* copy info from list to array, freeing list */
  320. X    for (p = keylist, i = 0; p != NULL; p = n, i++) {
  321. X       keys[i].key = p->key;
  322. X       keys[i].text = p->text;
  323. X       keys[i].primary = p->primary;
  324. X       n = p->next;
  325. X       free( (char *)p );
  326. X    }
  327. X    
  328. X    /* a null entry to terminate subtopic searches */
  329. X    keys[keycount].key = NULL;
  330. X    keys[keycount].text = NULL;
  331. X
  332. X    /* sort the array */
  333. X    /* note that it only moves objects of size (two pointers) */
  334. X    /* it moves no data */
  335. X    qsort((char *)keys, keycount, sizeof(KEY), keycomp);
  336. X}
  337. X
  338. Xstatic int
  339. Xkeycomp(a, b)
  340. X    KEY *a,*b;
  341. X{
  342. X    return (strcmp(a->key, b->key));
  343. X}
  344. X
  345. X/* Free the help file from memory. */
  346. X/* May be called externally if space is needed */
  347. Xvoid
  348. XFreeHelp()
  349. X{
  350. X    int i;                /* index into keys[] */
  351. X    LINEBUF *t, *next;
  352. X
  353. X    if (keys == NULL)
  354. X     return;
  355. X
  356. X    for (i = 0; i < keycount; i++) {
  357. X       free( (char *)keys[i].key );
  358. X       for (t = keys[i].text; t != NULL; t = next) {
  359. X          free( (char *)t->line );
  360. X          next = t->next;
  361. X          free( (char *)t );
  362. X       }
  363. X       free( (char *)keys[i].text );
  364. X    }
  365. X    free( (char *)keys );
  366. X    keys = NULL;
  367. X    keycount = 0;
  368. X}
  369. X
  370. X/* FindHelp:
  371. X *  Find the key that matches the keyword.
  372. X *  The keys[] array is sorted by key.
  373. X *  We could use a binary search, but a linear search will aid our
  374. X *  attempt to allow abbreviations. We search for the first thing that
  375. X *  matches all the text we're given. If not an exact match, then
  376. X *  it is an abbreviated match, and there must be no other abbreviated
  377. X *  matches -- for if there are, the abbreviation is ambiguous. 
  378. X *  We print the ambiguous matches in that case, and return not found.
  379. X */
  380. Xstatic KEY *                /* NULL if not found */
  381. XFindHelp(keyword)
  382. X    char *keyword;            /* string we look for */
  383. X{
  384. X    KEY *key;
  385. X    int len = strlen(keyword);
  386. X    int compare;
  387. X
  388. X    for (key = keys, compare = 1; key->key != NULL && compare > 0; key++) {
  389. X       compare = strncmp(keyword, key->key, len);
  390. X       if (compare == 0)    /* we have a match! */
  391. X        if (!Ambiguous(key, len)) {
  392. X            /* non-ambiguous abbreviation */
  393. X            (void) strcpy(keyword, key->key); /* give back the full spelling */
  394. X            return(key);        /* found!! */
  395. X        }
  396. X    }
  397. X    
  398. X    /* not found, or ambiguous */
  399. X    return(NULL);
  400. X}
  401. X
  402. X/* Ambiguous:
  403. X * Check the key for ambiguity up to the given length.
  404. X * It is ambiguous if it is not a complete string and there are other
  405. X * keys following it with the same leading substring.
  406. X */
  407. Xstatic boolean
  408. XAmbiguous(key, len)
  409. X    KEY *key;
  410. X    int len;
  411. X{
  412. X    char *first;
  413. X    char *prev;
  414. X    boolean status = FALSE;    /* assume not ambiguous */
  415. X    int compare;
  416. X    int sublen;
  417. X
  418. X    if (key->key[len] == '\0')
  419. X     return(FALSE);
  420. X    
  421. X    for (prev = first = key->key, compare = 0, key++;
  422. X        key->key != NULL && compare == 0; key++) {
  423. X       compare = strncmp(first, key->key, len);
  424. X       if (compare == 0) {
  425. X          /* So this key matches the first one, up to len.
  426. X           * But is it different enough from the previous one
  427. X           * to bother printing it as a separate choice?
  428. X           */
  429. X          sublen = instring(prev+len, ' ');
  430. X          if (strncmp(key->key, prev, len+sublen) != 0) {
  431. X             /* yup, this is different up to the next space */
  432. X             if (!status) {
  433. X                /* first one we have printed is special */
  434. X                fprintf(stderr, 
  435. X                       "Ambiguous request '%.*s'; possible matches:\n",
  436. X                       len, first);
  437. X                fprintf(stderr, "\t%s\n", prev);
  438. X                status = TRUE;
  439. X             }
  440. X             fprintf(stderr, "\t%s\n", key->key);
  441. X             prev = key->key;
  442. X          }
  443. X       }
  444. X    }
  445. X    
  446. X    return(status);
  447. X}
  448. X
  449. X/* PrintHelp:
  450. X * print the text for key
  451. X */
  452. Xstatic void
  453. XPrintHelp(key, subtopics)
  454. X    KEY *key;
  455. X    boolean *subtopics;        /* (in) - subtopics only? */
  456. X                        /* (out) - are there subtopics? */
  457. X{
  458. X    LINEBUF *t;
  459. X
  460. X    StartOutput();
  461. X
  462. X    if (subtopics == NULL || !*subtopics) {
  463. X       /* the first linebuf is a dummy, so we skip it */
  464. X       for (t = key->text->next; t != NULL; t = t->next)
  465. X        OutLine(t->line);        /* print text line */
  466. X    }
  467. X
  468. X    ShowSubtopics(key, subtopics);
  469. X    OutLine("\n");
  470. X
  471. X    EndOutput();
  472. X}
  473. X
  474. X/* ShowSubtopics:
  475. X *  Print a list of subtopic names
  476. X */
  477. X#define PER_LINE 4
  478. X
  479. Xstatic void
  480. XShowSubtopics(key, subtopics)
  481. X    KEY *key;                /* the topic */
  482. X    boolean *subtopics;        /* (out) are there any subtopics */
  483. X{
  484. X    int subt = 0;            /* printed any subtopics yet? */
  485. X    KEY *subkey;            /* subtopic key */
  486. X    int len;                /* length of key name */
  487. X    char line[BUFSIZ];        /* subtopic output line */
  488. X    char *start;            /* position of subname in key name */
  489. X    int sublen;            /* length of subname */
  490. X    int pos;
  491. X    char *prev = NULL;        /* the last thing we put on the list */
  492. X
  493. X    *line = '\0';
  494. X    len = strlen(key->key);
  495. X
  496. X    for (subkey = key+1; subkey->key != NULL; subkey++) {
  497. X       if (strncmp(subkey->key, key->key, len) == 0) {
  498. X          /* find this subtopic name */
  499. X          start = subkey->key + len;
  500. X          if (len > 0)
  501. X            if (*start == ' ')
  502. X             start++;        /* skip space */
  503. X            else
  504. X             break;        /* not the same topic after all  */
  505. X          else            /* here we are looking for main topics */
  506. X            if (!subkey->primary)
  507. X             continue;    /* not a main topic */
  508. X          sublen = instring(start, ' ');
  509. X          if (prev == NULL || strncmp(start, prev, sublen) != 0) {
  510. X             if (subt == 0) {
  511. X                subt++;
  512. X                if (len)
  513. X                  (void) sprintf(line, "\nSubtopics available for %s:\n", 
  514. X                        key->key);
  515. X                else
  516. X                  (void) sprintf(line, "\nHelp topics available:\n");
  517. X                OutLine(line);
  518. X                *line = '\0';
  519. X                pos = 0;
  520. X             }
  521. X             if (pos == PER_LINE) {
  522. X                (void) strcat(line, "\n");
  523. X                OutLine(line);
  524. X                *line = '\0';
  525. X                pos = 0;
  526. X             }
  527. X             (void) strcat(line, "\t");
  528. X             (void) strncat(line, start, sublen);
  529. X             pos++;
  530. X             prev = start;
  531. X          }
  532. X       } else {
  533. X          /* new topic */
  534. X          break;
  535. X       }
  536. X    }
  537. X    
  538. X    /* put out the last line */
  539. X    if (subt > 0 && pos > 0) {
  540. X       (void) strcat(line, "\n");
  541. X       OutLine(line);
  542. X    }
  543. X    
  544. X/*
  545. X    if (subt == 0) {
  546. X       OutLine("\n");
  547. X       OutLine("No subtopics available\n");
  548. X    }
  549. X*/
  550. X    
  551. X    if (subtopics)
  552. X     *subtopics = (subt != 0);
  553. X}
  554. X
  555. X
  556. X/* StartOutput:
  557. X * Open a file pointer to a pipe to user's $PAGER, if there is one,
  558. X * otherwise use our own pager.
  559. X */
  560. Xstatic void
  561. XStartOutput()
  562. X{
  563. X#ifdef unix
  564. X    char *pager_name = getenv("PAGER");
  565. X    extern FILE *popen();
  566. X
  567. X    if (pager_name != NULL && *pager_name != '\0')
  568. X     if ((outfile = popen(pager_name, "w")) != (FILE *)NULL)
  569. X       return;            /* success */
  570. X    outfile = stderr;
  571. X    /* fall through to built-in pager */
  572. X#endif
  573. X
  574. X    /* built-in pager */
  575. X    pagelines = 0;
  576. X}
  577. X
  578. X/* write a line of help output  */
  579. X/* line should contain only one \n, at the end */
  580. Xstatic void
  581. XOutLine(line)
  582. X    char *line;
  583. X{
  584. X    int c;                /* dummy input char */
  585. X#ifdef unix
  586. X    if (outfile != stderr) {
  587. X       fputs(line, outfile);
  588. X       return;
  589. X    }
  590. X#endif
  591. X
  592. X    /* built-in dumb pager */
  593. X    /* leave room for prompt line */
  594. X    if (pagelines >= SCREENSIZE - 2) {
  595. X       printf("Press return for more: ");
  596. X       do 
  597. X        c = getchar();
  598. X       while (c != EOF && c != '\n');
  599. X       pagelines = 0;
  600. X    }
  601. X    fputs(line, stderr);
  602. X    pagelines++;
  603. X}
  604. X
  605. Xstatic void
  606. XEndOutput()
  607. X{
  608. X#ifdef unix
  609. X    extern int pclose();
  610. X
  611. X    if (outfile != stderr)
  612. X     (void) pclose(outfile);
  613. X#endif
  614. X}
  615. *-*-END-of-help.c-*-*
  616. echo x - graphics.c
  617. sed 's/^X//' >graphics.c <<'*-*-END-of-graphics.c-*-*'
  618. X/* GNUPLOT - graphics.c */
  619. X/*
  620. X * Copyright (C) 1986, 1987, 1990   Thomas Williams, Colin Kelley
  621. X *
  622. X * Permission to use, copy, and distribute this software and its
  623. X * documentation for any purpose with or without fee is hereby granted, 
  624. X * provided that the above copyright notice appear in all copies and 
  625. X * that both that copyright notice and this permission notice appear 
  626. X * in supporting documentation.
  627. X *
  628. X * Permission to modify the software is granted, but not the right to
  629. X * distribute the modified code.  Modifications are to be distributed 
  630. X * as patches to released version.
  631. X *  
  632. X * This software  is provided "as is" without express or implied warranty.
  633. X * 
  634. X *
  635. X * AUTHORS
  636. X * 
  637. X *   Original Software:
  638. X *     Thomas Williams,  Colin Kelley.
  639. X * 
  640. X *   Gnuplot 2.0 additions:
  641. X *       Russell Lang, Dave Kotz, John Campbell.
  642. X * 
  643. X * send your comments or suggestions to (pixar!info-gnuplot@sun.com).
  644. X * 
  645. X */
  646. X
  647. X#include <stdio.h>
  648. X#include <math.h>
  649. X#include <assert.h>
  650. X#include "plot.h"
  651. X#include "setshow.h"
  652. X
  653. Xextern char *strcpy(),*strncpy(),*strcat();
  654. X
  655. Xvoid plot_impulses();
  656. Xvoid plot_lines();
  657. Xvoid plot_points();
  658. Xvoid plot_dots();
  659. Xvoid edge_intersect();
  660. XBOOLEAN two_edge_intersect();
  661. X
  662. X#ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  663. X#define max(a,b) ((a > b) ? a : b)
  664. X#endif
  665. X
  666. X#ifndef min
  667. X#define min(a,b) ((a < b) ? a : b)
  668. X#endif
  669. X
  670. X#define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  671. X
  672. X/* Define the boundary of the plot
  673. X * These are computed at each call to do_plot, and are constant over
  674. X * the period of one do_plot. They actually only change when the term
  675. X * type changes and when the 'set size' factors change. 
  676. X */
  677. Xstatic int xleft, xright, ybot, ytop;
  678. X
  679. X/* Boundary and scale factors, in user coordinates */
  680. Xstatic double xmin, xmax, ymin, ymax;
  681. Xstatic double xscale, yscale;
  682. X
  683. X/* And the functions to map from user to terminal coordinates */
  684. X#define map_x(x) (int)(xleft+(x-xmin)*xscale+0.5) /* maps floating point x to screen */ 
  685. X#define map_y(y) (int)(ybot+(y-ymin)*yscale+0.5)    /* same for y */
  686. X
  687. X/* (DFK) Watch for cancellation error near zero on axes labels */
  688. X#define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  689. X#define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  690. X#define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  691. X
  692. X/* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  693. X * macro, so I write it as a function on that machine.
  694. X */
  695. X#ifndef sun386
  696. X/* (DFK) Use 10^x if logscale is in effect, else x */
  697. X#define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
  698. X#else
  699. Xstatic double
  700. XCheckLog(log, x)
  701. X     BOOLEAN log;
  702. X     double x;
  703. X{
  704. X  if (log)
  705. X    return(pow(10., x));
  706. X  else
  707. X    return(x);
  708. X}
  709. X#endif /* sun386 */
  710. X
  711. Xdouble
  712. XLogScale(coord, islog, what, axis)
  713. X    double coord;            /* the value */
  714. X    BOOLEAN islog;            /* is this axis in logscale? */
  715. X    char *what;            /* what is the coord for? */
  716. X    char *axis;            /* which axis is this for ("x" or "y")? */
  717. X{
  718. X    if (islog) {
  719. X       if (coord <= 0.0) {
  720. X          char errbuf[100];        /* place to write error message */
  721. X        (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  722. X                what, axis, coord);
  723. X          (*term_tbl[term].text)();
  724. X          (void) fflush(outfile);
  725. X          int_error(errbuf, NO_CARET);
  726. X       } else
  727. X        return(log10(coord));
  728. X    } else {
  729. X       return(coord);
  730. X    }
  731. X    return((double)NULL); /* shut lint up */
  732. X}
  733. X
  734. X/* borders of plotting area */
  735. X/* computed once on every call to do_plot */
  736. Xboundary(scaling)
  737. X    BOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  738. X{
  739. X    register struct termentry *t = &term_tbl[term];
  740. X    xleft = (t->h_char)*12;
  741. X    xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  742. X    ybot = (t->v_char)*5/2 + 1;
  743. X    ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*3/2 - 1;
  744. X}
  745. X
  746. X
  747. Xdouble dbl_raise(x,y)
  748. Xdouble x;
  749. Xint y;
  750. X{
  751. Xregister int i;
  752. Xdouble val;
  753. X
  754. X    val = 1.0;
  755. X    for (i=0; i < abs(y); i++)
  756. X        val *= x;
  757. X    if (y < 0 ) return (1.0/val);
  758. X    return(val);
  759. X}
  760. X
  761. X
  762. Xdouble make_tics(tmin,tmax,logscale)
  763. Xdouble tmin,tmax;
  764. XBOOLEAN logscale;
  765. X{
  766. Xregister double xr,xnorm,tics,tic,l10;
  767. X
  768. X    xr = fabs(tmin-tmax);
  769. X    
  770. X    l10 = log10(xr);
  771. X    if (logscale) {
  772. X        tic = dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  773. X        if (tic < 1.0)
  774. X            tic = 1.0;
  775. X    } else {
  776. X        xnorm = pow(10.0,l10-(double)((l10 >= 0.0 ) ? (int)l10 : ((int)l10-1)));
  777. X        if (xnorm <= 2)
  778. X            tics = 0.2;
  779. X        else if (xnorm <= 5)
  780. X            tics = 0.5;
  781. X        else tics = 1.0;    
  782. X        tic = tics * dbl_raise(10.0,(l10 >= 0.0 ) ? (int)l10 : ((int)l10-1));
  783. X    }
  784. X    return(tic);
  785. X}
  786. X
  787. X
  788. Xdo_plot(plots, pcount, min_x, max_x, min_y, max_y)
  789. Xstruct curve_points *plots;
  790. Xint pcount;            /* count of plots in linked list */
  791. Xdouble min_x, max_x;
  792. Xdouble min_y, max_y;
  793. X{
  794. Xregister struct termentry *t = &term_tbl[term];
  795. Xregister int curve, xaxis_y, yaxis_x;
  796. Xregister struct curve_points *this_plot;
  797. Xregister double ytic, xtic;
  798. Xregister int xl, yl;
  799. X            /* only a Pyramid would have this many registers! */
  800. Xdouble xtemp, ytemp;
  801. Xstruct text_label *this_label;
  802. Xstruct arrow_def *this_arrow;
  803. XBOOLEAN scaling;
  804. X
  805. X/* store these in variables global to this file */
  806. X/* otherwise, we have to pass them around a lot */
  807. X     xmin = min_x;
  808. X     xmax = max_x; 
  809. X     ymin = min_y;
  810. X     ymax = max_y;
  811. X
  812. X    if (polar) {
  813. X        /* will possibly change xmin, xmax, ymin, ymax */
  814. X        polar_xform(plots,pcount);
  815. X    }
  816. X
  817. X    if (ymin == VERYLARGE || ymax == -VERYLARGE)
  818. X        int_error("all points undefined!", NO_CARET);
  819. X
  820. X    if (xmin == VERYLARGE || xmax == -VERYLARGE)
  821. X        int_error("all points undefined!", NO_CARET);
  822. X
  823. X/*    Apply the desired viewport offsets. */
  824. X     if (ymin < ymax) {
  825. X        ymin -= boff;
  826. X        ymax += toff;
  827. X    } else {
  828. X        ymax -= boff;
  829. X        ymin += toff;
  830. X    }
  831. X     if (xmin < xmax) {
  832. X        xmin -= loff;
  833. X        xmax += roff;
  834. X    } else {
  835. X        xmax -= loff;
  836. X        xmin += roff;
  837. X    }
  838. X
  839. X/* SETUP RANGES, SCALES AND TIC PLACES */
  840. X    if (ytics && yticdef.type == TIC_COMPUTED) {
  841. X       ytic = make_tics(ymin,ymax,log_y);
  842. X    
  843. X       if (autoscale_ly) {
  844. X          if (ymin < ymax) {
  845. X             ymin = ytic * floor(ymin/ytic);       
  846. X             ymax = ytic * ceil(ymax/ytic);
  847. X          }
  848. X          else {            /* reverse axis */
  849. X             ymin = ytic * ceil(ymin/ytic);       
  850. X             ymax = ytic * floor(ymax/ytic);
  851. X          }
  852. X       }
  853. X    }
  854. X
  855. X    if (xtics && xticdef.type == TIC_COMPUTED) {
  856. X       xtic = make_tics(xmin,xmax,log_x);
  857. X       
  858. X       if (autoscale_lx) {
  859. X          if (xmin < xmax) {
  860. X             xmin = xtic * floor(xmin/xtic);    
  861. X             xmax = xtic * ceil(xmax/xtic);
  862. X          } else {
  863. X             xmin = xtic * ceil(xmin/xtic);
  864. X             xmax = xtic * floor(xmax/xtic);    
  865. X          }
  866. X       }
  867. X    }
  868. X
  869. X/*    This used be xmax == xmin, but that caused an infinite loop once. */
  870. X    if (fabs(xmax - xmin) < zero)
  871. X        int_error("xmin should not equal xmax!",NO_CARET);
  872. X    if (fabs(ymax - ymin) < zero)
  873. X        int_error("ymin should not equal ymax!",NO_CARET);
  874. X
  875. X/* INITIALIZE TERMINAL */
  876. X    if (!term_init) {
  877. X        (*t->init)();
  878. X        term_init = TRUE;
  879. X    }
  880. X    screen_ok = FALSE;
  881. X     scaling = (*t->scale)(xsize, ysize);
  882. X    (*t->graphics)();
  883. X
  884. X     /* now compute boundary for plot (xleft, xright, ytop, ybot) */
  885. X     boundary(scaling);
  886. X
  887. X/* SCALE FACTORS */
  888. X    yscale = (ytop - ybot)/(ymax - ymin);
  889. X    xscale = (xright - xleft)/(xmax - xmin);
  890. X    
  891. X/* DRAW AXES */
  892. X    (*t->linetype)(-1);    /* axis line type */
  893. X    xaxis_y = map_y(0.0);
  894. X    yaxis_x = map_x(0.0); 
  895. X
  896. X    if (xaxis_y < ybot)
  897. X        xaxis_y = ybot;                /* save for impulse plotting */
  898. X    else if (xaxis_y >= ytop)
  899. X        xaxis_y = ytop ;
  900. X    else if (!log_y) {
  901. X        (*t->move)(xleft,xaxis_y);
  902. X        (*t->vector)(xright,xaxis_y);
  903. X    }
  904. X
  905. X    if (!log_x && yaxis_x >= xleft && yaxis_x < xright ) {
  906. X        (*t->move)(yaxis_x,ybot);
  907. X        (*t->vector)(yaxis_x,ytop);
  908. X    }
  909. X
  910. X/* DRAW TICS */
  911. X    (*t->linetype)(-2); /* border linetype */
  912. X
  913. X    /* label y axis tics */
  914. X     if (ytics) {
  915. X        switch (yticdef.type) {
  916. X           case TIC_COMPUTED: {
  917. X               if (ymin < ymax)
  918. X                draw_ytics(ytic * floor(ymin/ytic),
  919. X                        ytic,
  920. X                        ytic * ceil(ymax/ytic));
  921. X              else
  922. X                draw_ytics(ytic * floor(ymax/ytic),
  923. X                        ytic,
  924. X                        ytic * ceil(ymin/ytic));
  925. X
  926. X              break;
  927. X           }
  928. X           case TIC_SERIES: {
  929. X              draw_ytics(yticdef.def.series.start, 
  930. X                      yticdef.def.series.incr, 
  931. X                      yticdef.def.series.end);
  932. X              break;
  933. X           }
  934. X           case TIC_USER: {
  935. X              draw_user_ytics(yticdef.def.user);
  936. X              break;
  937. X           }
  938. X           default: {
  939. X              (*t->text)();
  940. X                (void) fflush(outfile);
  941. X              int_error("unknown tic type in yticdef in do_plot", NO_CARET);
  942. X              break;        /* NOTREACHED */
  943. X           }
  944. X        }
  945. X    }
  946. X
  947. X    /* label x axis tics */
  948. X     if (xtics) {
  949. X        switch (xticdef.type) {
  950. X           case TIC_COMPUTED: {
  951. X               if (xmin < xmax)
  952. X                draw_xtics(xtic * floor(xmin/xtic),
  953. X                        xtic,
  954. X                        xtic * ceil(xmax/xtic));
  955. X              else
  956. X                draw_xtics(xtic * floor(xmax/xtic),
  957. X                        xtic,
  958. X                        xtic * ceil(xmin/xtic));
  959. X
  960. X              break;
  961. X           }
  962. X           case TIC_SERIES: {
  963. X              draw_xtics(xticdef.def.series.start, 
  964. X                      xticdef.def.series.incr, 
  965. X                      xticdef.def.series.end);
  966. X              break;
  967. X           }
  968. X           case TIC_USER: {
  969. X              draw_user_xtics(xticdef.def.user);
  970. X              break;
  971. X           }
  972. X           default: {
  973. X              (*t->text)();
  974. X              (void) fflush(outfile);
  975. X              int_error("unknown tic type in xticdef in do_plot", NO_CARET);
  976. X              break;        /* NOTREACHED */
  977. X           }
  978. X        }
  979. X    }
  980. X
  981. X/* DRAW PLOT BORDER */
  982. X    (*t->linetype)(-2); /* border linetype */
  983. X    (*t->move)(xleft,ybot);    
  984. X    (*t->vector)(xright,ybot);    
  985. X    (*t->vector)(xright,ytop);    
  986. X    (*t->vector)(xleft,ytop);    
  987. X    (*t->vector)(xleft,ybot);
  988. X
  989. X/* PLACE YLABEL */
  990. X    if (*ylabel != NULL) {
  991. X       if ((*t->text_angle)(1)) { 
  992. X          if ((*t->justify_text)(CENTRE)) { 
  993. X             (*t->put_text)((t->v_char),
  994. X                         (ytop+ybot)/2, ylabel);
  995. X          }
  996. X          else {
  997. X             (*t->put_text)((t->v_char),
  998. X                         (ytop+ybot)/2-(t->h_char)*strlen(ylabel)/2, 
  999. X                         ylabel);
  1000. X          }
  1001. X       }
  1002. X       else {
  1003. X          (void)(*t->justify_text)(LEFT);
  1004. X          (*t->put_text)(0,ytop+(t->v_char), ylabel);
  1005. X       }
  1006. X       (void)(*t->text_angle)(0);
  1007. X    }
  1008. X
  1009. X/* PLACE XLABEL */
  1010. X    if (*xlabel != NULL) {
  1011. X       if ((*t->justify_text)(CENTRE)) 
  1012. X        (*t->put_text)( (xleft+xright)/2,
  1013. X                    ybot-2*(t->v_char), xlabel);
  1014. X       else
  1015. X        (*t->put_text)( (xleft+xright)/2 - strlen(xlabel)*(t->h_char)/2,
  1016. X                    ybot-2*(t->v_char), xlabel);
  1017. X    }
  1018. X
  1019. X/* PLACE TITLE */
  1020. X    if (*title != NULL) {
  1021. X       if ((*t->justify_text)(CENTRE)) 
  1022. X        (*t->put_text)( (xleft+xright)/2, 
  1023. X                    ytop+(t->v_char), title);
  1024. X       else
  1025. X        (*t->put_text)( (xleft+xright)/2 - strlen(title)*(t->h_char)/2,
  1026. X                    ytop+(t->v_char), title);
  1027. X    }
  1028. X
  1029. X/* PLACE LABELS */
  1030. X    for (this_label = first_label; this_label!=NULL;
  1031. X            this_label=this_label->next ) {
  1032. X         xtemp = LogScale(this_label->x, log_x, "label", "x");
  1033. X         ytemp = LogScale(this_label->y, log_y, "label", "y");
  1034. X        if ((*t->justify_text)(this_label->pos)) {
  1035. X            (*t->put_text)(map_x(xtemp),map_y(ytemp),this_label->text);
  1036. X        }
  1037. X        else {
  1038. X            switch(this_label->pos) {
  1039. X                case  LEFT:
  1040. X                    (*t->put_text)(map_x(xtemp),map_y(ytemp),
  1041. X                        this_label->text);
  1042. X                    break;
  1043. X                case CENTRE:
  1044. X                    (*t->put_text)(map_x(xtemp)-
  1045. X                        (t->h_char)*strlen(this_label->text)/2,
  1046. X                        map_y(ytemp), this_label->text);
  1047. X                    break;
  1048. X                case RIGHT:
  1049. X                    (*t->put_text)(map_x(xtemp)-
  1050. X                        (t->h_char)*strlen(this_label->text),
  1051. X                        map_y(ytemp), this_label->text);
  1052. X                    break;
  1053. X            }
  1054. X         }
  1055. X     }
  1056. X
  1057. X/* PLACE ARROWS */
  1058. X    (*t->linetype)(0);    /* arrow line type */
  1059. X    for (this_arrow = first_arrow; this_arrow!=NULL;
  1060. X        this_arrow = this_arrow->next ) {
  1061. X       int sx = map_x(LogScale(this_arrow->sx, log_x, "arrow", "x"));
  1062. X       int sy = map_y(LogScale(this_arrow->sy, log_y, "arrow", "y"));
  1063. X       int ex = map_x(LogScale(this_arrow->ex, log_x, "arrow", "x"));
  1064. X       int ey = map_y(LogScale(this_arrow->ey, log_y, "arrow", "y"));
  1065. X       
  1066. X       (*t->arrow)(sx, sy, ex, ey);
  1067. X    }
  1068. X
  1069. X
  1070. X/* DRAW CURVES */
  1071. X    if (key == -1) {
  1072. X        xl = xright  - (t->h_tic) - (t->h_char)*5;
  1073. X        yl = ytop - (t->v_tic) - (t->v_char);
  1074. X    }
  1075. X    if (key == 1) {
  1076. X        xl = map_x( LogScale(key_x, log_x, "key", "x") );
  1077. X        yl = map_y( LogScale(key_y, log_y, "key", "y") );
  1078. X    }
  1079. X
  1080. X    this_plot = plots;
  1081. X    for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1082. X        (*t->linetype)(this_plot->line_type);
  1083. X        if (key != 0) {
  1084. X            if ((*t->justify_text)(RIGHT)) {
  1085. X                (*t->put_text)(xl,
  1086. X                    yl,this_plot->title);
  1087. X            }
  1088. X            else {
  1089. X                if (inrange(xl-(t->h_char)*strlen(this_plot->title), 
  1090. X                         xleft, xright))
  1091. X                 (*t->put_text)(xl-(t->h_char)*strlen(this_plot->title),
  1092. X                             yl,this_plot->title);
  1093. X            }
  1094. X        }
  1095. X
  1096. X        switch(this_plot->plot_style) {
  1097. X            case IMPULSES: {
  1098. X               if (key != 0) {
  1099. X                  (*t->move)(xl+(t->h_char),yl);
  1100. X                  (*t->vector)(xl+4*(t->h_char),yl);
  1101. X               }
  1102. X               plot_impulses(this_plot, xaxis_y);
  1103. X               break;
  1104. X            }
  1105. X            case LINES: {
  1106. X               if (key != 0) {
  1107. X                  (*t->move)(xl+(int)(t->h_char),yl);
  1108. X                  (*t->vector)(xl+(int)(4*(t->h_char)),yl);
  1109. X               }
  1110. X               plot_lines(this_plot);
  1111. X               break;
  1112. X            }
  1113. X            case POINTS: {
  1114. X               if (key != 0) {
  1115. X                  (*t->point)(xl+2*(t->h_char),yl,
  1116. X                            this_plot->point_type);
  1117. X               }
  1118. X               plot_points(this_plot);
  1119. X               break;
  1120. X            }
  1121. X            case LINESPOINTS: {
  1122. X               /* put lines */
  1123. X               if (key != 0) {
  1124. X                  (*t->move)(xl+(t->h_char),yl);
  1125. X                  (*t->vector)(xl+4*(t->h_char),yl);
  1126. X               }
  1127. X               plot_lines(this_plot);
  1128. X
  1129. X               /* put points */
  1130. X               if (key != 0) {
  1131. X                  (*t->point)(xl+2*(t->h_char),yl,
  1132. X                            this_plot->point_type);
  1133. X               }
  1134. X               plot_points(this_plot);
  1135. X               break;
  1136. X            }
  1137. X            case DOTS: {
  1138. X               if (key != 0) {
  1139. X                  (*t->point)(xl+2*(t->h_char),yl, -1);
  1140. X               }
  1141. X               plot_dots(this_plot);
  1142. X               break;
  1143. X            }
  1144. X        }
  1145. X        yl = yl - (t->v_char);
  1146. X    }
  1147. X    (*t->text)();
  1148. X    (void) fflush(outfile);
  1149. X}
  1150. X
  1151. X/* plot_impulses:
  1152. X * Plot the curves in IMPULSES style
  1153. X */
  1154. Xvoid
  1155. Xplot_impulses(plot, xaxis_y)
  1156. X    struct curve_points *plot;
  1157. X    int xaxis_y;
  1158. X{
  1159. X    int i;
  1160. X    int x,y;
  1161. X    struct termentry *t = &term_tbl[term];
  1162. X
  1163. X    for (i = 0; i < plot->p_count; i++) {
  1164. X       switch (plot->points[i].type) {
  1165. X          case INRANGE: {
  1166. X             x = map_x(plot->points[i].x);
  1167. X             y = map_y(plot->points[i].y);
  1168. X             break;
  1169. X          }
  1170. X          case OUTRANGE: {
  1171. X             if (!inrange(plot->points[i].x, xmin,xmax))
  1172. X               continue;
  1173. X             x = map_x(plot->points[i].x);
  1174. X             if ((ymin < ymax 
  1175. X                 && plot->points[i].y < ymin)
  1176. X                || (ymax < ymin 
  1177. X                    && plot->points[i].y > ymin))
  1178. X               y = map_y(ymin);
  1179. X             if ((ymin < ymax 
  1180. X                 && plot->points[i].y > ymax)
  1181. X                || (ymax<ymin 
  1182. X                    && plot->points[i].y < ymax))
  1183. X               y = map_y(ymax);
  1184. X             break;
  1185. X          }
  1186. X          default:        /* just a safety */
  1187. X          case UNDEFINED: {
  1188. X             continue;
  1189. X          }
  1190. X       }
  1191. X                    
  1192. X       (*t->move)(x,xaxis_y);
  1193. X       (*t->vector)(x,y);
  1194. X    }
  1195. X
  1196. X}
  1197. X
  1198. X/* plot_lines:
  1199. X * Plot the curves in LINES style
  1200. X */
  1201. Xvoid
  1202. Xplot_lines(plot)
  1203. X    struct curve_points *plot;
  1204. X{
  1205. X    int i;                /* point index */
  1206. X    int x,y;                /* point in terminal coordinates */
  1207. X    struct termentry *t = &term_tbl[term];
  1208. X    enum coord_type prev = UNDEFINED; /* type of previous point */
  1209. X    double ex, ey;            /* an edge point */
  1210. X    double lx[2], ly[2];        /* two edge points */
  1211. X
  1212. X    for (i = 0; i < plot->p_count; i++) {
  1213. X       switch (plot->points[i].type) {
  1214. X          case INRANGE: {
  1215. X             x = map_x(plot->points[i].x);
  1216. X             y = map_y(plot->points[i].y);
  1217. X
  1218. X             if (prev == INRANGE) {
  1219. X                (*t->vector)(x,y);
  1220. X             } else if (prev == OUTRANGE) {
  1221. X                /* from outrange to inrange */
  1222. X                if (!clip_lines1) {
  1223. X                    (*t->move)(x,y);
  1224. X                } else {
  1225. X                    edge_intersect(plot->points, i, &ex, &ey);
  1226. X                    (*t->move)(map_x(ex), map_y(ey));
  1227. X                    (*t->vector)(x,y);
  1228. X                }
  1229. X             } else {        /* prev == UNDEFINED */
  1230. X                (*t->move)(x,y);
  1231. X                (*t->vector)(x,y);
  1232. X             }
  1233. X                    
  1234. X             break;
  1235. X          }
  1236. X          case OUTRANGE: {
  1237. X             if (prev == INRANGE) {
  1238. X                /* from inrange to outrange */
  1239. X                if (clip_lines1) {
  1240. X                    edge_intersect(plot->points, i, &ex, &ey);
  1241. X                    (*t->vector)(map_x(ex), map_y(ey));
  1242. X                }
  1243. X             } else if (prev == OUTRANGE) {
  1244. X                /* from outrange to outrange */
  1245. X                if (clip_lines2) {
  1246. X                    if (two_edge_intersect(plot->points, i, lx, ly)) {
  1247. X                       (*t->move)(map_x(lx[0]), map_y(ly[0]));
  1248. X                       (*t->vector)(map_x(lx[1]), map_y(ly[1]));
  1249. X                    }
  1250. X                }
  1251. X             }
  1252. X             break;
  1253. X          }
  1254. X          default:        /* just a safety */
  1255. X          case UNDEFINED: {
  1256. X             break;
  1257. X          }
  1258. X       }
  1259. X       prev = plot->points[i].type;
  1260. X    }
  1261. X}
  1262. X
  1263. X/* plot_points:
  1264. X * Plot the curves in POINTS style
  1265. X */
  1266. Xvoid
  1267. Xplot_points(plot)
  1268. X    struct curve_points *plot;
  1269. X{
  1270. X    int i;
  1271. X    int x,y;
  1272. X    struct termentry *t = &term_tbl[term];
  1273. X
  1274. X    for (i = 0; i < plot->p_count; i++) {
  1275. X       if (plot->points[i].type == INRANGE) {
  1276. X          x = map_x(plot->points[i].x);
  1277. X          y = map_y(plot->points[i].y);
  1278. X          /* do clipping if necessary */
  1279. X          if (!clip_points ||
  1280. X             (   x >= xleft + t->h_tic  && y >= ybot + t->v_tic 
  1281. X              && x <= xright - t->h_tic && y <= ytop - t->v_tic))
  1282. X            (*t->point)(x,y, plot->point_type);
  1283. X       }
  1284. X    }
  1285. X}
  1286. X
  1287. X/* plot_dots:
  1288. X * Plot the curves in DOTS style
  1289. X */
  1290. Xvoid
  1291. Xplot_dots(plot)
  1292. X    struct curve_points *plot;
  1293. X{
  1294. X    int i;
  1295. X    int x,y;
  1296. X    struct termentry *t = &term_tbl[term];
  1297. X
  1298. X    for (i = 0; i < plot->p_count; i++) {
  1299. X       if (plot->points[i].type == INRANGE) {
  1300. X          x = map_x(plot->points[i].x);
  1301. X          y = map_y(plot->points[i].y);
  1302. X          /* point type -1 is a dot */
  1303. X          (*t->point)(x,y, -1);
  1304. X       }
  1305. X    }
  1306. X}
  1307. X
  1308. X/* single edge intersection algorithm */
  1309. X/* Given two points, one inside and one outside the plot, return
  1310. X * the point where an edge of the plot intersects the line segment defined 
  1311. X * by the two points.
  1312. X */
  1313. Xvoid
  1314. Xedge_intersect(points, i, ex, ey)
  1315. X    struct coordinate *points; /* the points array */
  1316. X    int i;                /* line segment from point i-1 to point i */
  1317. X    double *ex, *ey;        /* the point where it crosses an edge */
  1318. X{
  1319. X    /* global xmin, xmax, ymin, xmax */
  1320. X    double ax = points[i-1].x;
  1321. X    double ay = points[i-1].y;
  1322. X    double bx = points[i].x;
  1323. X    double by = points[i].y;
  1324. X    double x, y;            /* possible intersection point */
  1325. X
  1326. X    if (by == ay) {
  1327. X       /* horizontal line */
  1328. X       /* assume inrange(by, ymin, ymax) */
  1329. X       *ey = by;        /* == ay */
  1330. X
  1331. X       if (inrange(xmax, ax, bx))
  1332. X        *ex = xmax;
  1333. X       else if (inrange(xmin, ax, bx))
  1334. X        *ex = xmin;
  1335. X       else {
  1336. X        (*term_tbl[term].text)();
  1337. X        (void) fflush(outfile);
  1338. X        int_error("error in edge_intersect", NO_CARET);
  1339. X       }
  1340. X       return;
  1341. X    } else if (bx == ax) {
  1342. X       /* vertical line */
  1343. X       /* assume inrange(bx, xmin, xmax) */
  1344. X       *ex = bx;        /* == ax */
  1345. X
  1346. X       if (inrange(ymax, ay, by))
  1347. X        *ey = ymax;
  1348. X       else if (inrange(ymin, ay, by))
  1349. X        *ey = ymin;
  1350. X       else {
  1351. X        (*term_tbl[term].text)();
  1352. X        (void) fflush(outfile);
  1353. X        int_error("error in edge_intersect", NO_CARET);
  1354. X       }
  1355. X       return;
  1356. X    }
  1357. X
  1358. X    /* slanted line of some kind */
  1359. X
  1360. X    /* does it intersect ymin edge */
  1361. X    if (inrange(ymin, ay, by) && ymin != ay && ymin != by) {
  1362. X       x = ax + (ymin-ay) * ((bx-ax) / (by-ay));
  1363. X       if (inrange(x, xmin, xmax)) {
  1364. X          *ex = x;
  1365. X          *ey = ymin;
  1366. X          return;            /* yes */
  1367. X       }
  1368. X    }
  1369. X    
  1370. X    /* does it intersect ymax edge */
  1371. X    if (inrange(ymax, ay, by) && ymax != ay && ymax != by) {
  1372. X       x = ax + (ymax-ay) * ((bx-ax) / (by-ay));
  1373. X       if (inrange(x, xmin, xmax)) {
  1374. X          *ex = x;
  1375. X          *ey = ymax;
  1376. X          return;            /* yes */
  1377. X       }
  1378. X    }
  1379. X
  1380. X    /* does it intersect xmin edge */
  1381. X    if (inrange(xmin, ax, bx) && xmin != ax && xmin != bx) {
  1382. X       y = ay + (xmin-ax) * ((by-ay) / (bx-ax));
  1383. X       if (inrange(y, ymin, ymax)) {
  1384. X          *ex = xmin;
  1385. X          *ey = y;
  1386. X          return;
  1387. X       }
  1388. X    }
  1389. X
  1390. X    /* does it intersect xmax edge */
  1391. X    if (inrange(xmax, ax, bx) && xmax != ax && xmax != bx) {
  1392. X       y = ay + (xmax-ax) * ((by-ay) / (bx-ax));
  1393. X       if (inrange(y, ymin, ymax)) {
  1394. X          *ex = xmax;
  1395. X          *ey = y;
  1396. X          return;
  1397. X       }
  1398. X    }
  1399. X
  1400. X    /* It is possible for one or two of the [ab][xy] values to be -VERYLARGE.
  1401. X    * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned 
  1402. X    * FALSE above. Otherwise we fall through all the tests above. 
  1403. X    * If two are -VERYLARGE, it is ax=ay=-VERYLARGE or bx=by=-VERYLARGE 
  1404. X    * since either a or b must be INRANGE. 
  1405. X    * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1406. X    * Handle them carefully here. As yet we have no way for them to be 
  1407. X    * +VERYLARGE.
  1408. X    */
  1409. X    if (ax == -VERYLARGE) {
  1410. X       if (ay != -VERYLARGE) {
  1411. X          *ex = min(xmin, xmax);
  1412. X          *ey = by;
  1413. X          return;
  1414. X       }
  1415. X    } else if (bx == -VERYLARGE) {
  1416. X       if (by != -VERYLARGE) {
  1417. X          *ex = min(xmin, xmax);
  1418. X          *ey = ay;
  1419. X          return;
  1420. X       }
  1421. X    } else if (ay == -VERYLARGE) {
  1422. X       /* note we know ax != -VERYLARGE */
  1423. X       *ex = bx;
  1424. X       *ey = min(ymin, ymax);
  1425. X       return;
  1426. X    } else if (by == -VERYLARGE) {
  1427. X       /* note we know bx != -VERYLARGE */
  1428. X       *ex = ax;
  1429. X       *ey = min(ymin, ymax);
  1430. X       return;
  1431. X    }
  1432. X
  1433. X    /* If we reach here, then either one point is (-VERYLARGE,-VERYLARGE), 
  1434. X    * or the inrange point is on the edge, and
  1435. X     * the line segment from the outrange point does not cross any 
  1436. X    * other edges to get there. In either case, we return the inrange 
  1437. X    * point as the 'edge' intersection point. This will basically draw
  1438. X    * line.
  1439. X    */
  1440. X    if (points[i].type == INRANGE) {
  1441. X       *ex = bx; 
  1442. X       *ey = by;
  1443. X    } else {
  1444. X       *ex = ax; 
  1445. X       *ey = ay;
  1446. X    }
  1447. X    return;
  1448. X}
  1449. X
  1450. X/* double edge intersection algorithm */
  1451. X/* Given two points, both outside the plot, return
  1452. X * the points where an edge of the plot intersects the line segment defined 
  1453. X * by the two points. There may be zero, one, two, or an infinite number
  1454. X * of intersection points. (One means an intersection at a corner, infinite
  1455. X * means overlaying the edge itself). We return FALSE when there is nothing
  1456. X * to draw (zero intersections), and TRUE when there is something to 
  1457. X * draw (the one-point case is a degenerate of the two-point case and we do 
  1458. X * not distinguish it - we draw it anyway).
  1459. X */
  1460. XBOOLEAN                /* any intersection? */
  1461. Xtwo_edge_intersect(points, i, lx, ly)
  1462. X    struct coordinate *points; /* the points array */
  1463. X    int i;                /* line segment from point i-1 to point i */
  1464. X    double *lx, *ly;        /* lx[2], ly[2]: points where it crosses edges */
  1465. X{
  1466. X    /* global xmin, xmax, ymin, xmax */
  1467. X    double ax = points[i-1].x;
  1468. X    double ay = points[i-1].y;
  1469. X    double bx = points[i].x;
  1470. X    double by = points[i].y;
  1471. X    double x, y;            /* possible intersection point */
  1472. X    BOOLEAN intersect = FALSE;
  1473. X
  1474. X    if (by == ay) {
  1475. X       /* horizontal line */
  1476. X       /* y coord must be in range, and line must span both xmin and xmax */
  1477. X       /* note that spanning xmin implies spanning xmax */
  1478. X       if (inrange(by, ymin, ymax) && inrange(xmin, ax, bx)) {
  1479. X          *lx++ = xmin;
  1480. X          *ly++ = by;
  1481. X          *lx++ = xmax;
  1482. X          *ly++ = by;
  1483. X          return(TRUE);
  1484. X       } else
  1485. X        return(FALSE);
  1486. X    } else if (bx == ax) {
  1487. X       /* vertical line */
  1488. X       /* x coord must be in range, and line must span both ymin and ymax */
  1489. X       /* note that spanning ymin implies spanning ymax */
  1490. X       if (inrange(bx, xmin, xmax) && inrange(ymin, ay, by)) {
  1491. X          *lx++ = bx;
  1492. X          *ly++ = ymin;
  1493. X          *lx++ = bx;
  1494. X          *ly++ = ymax;
  1495. X          return(TRUE);
  1496. X       } else
  1497. X        return(FALSE);
  1498. X    }
  1499. X
  1500. X    /* slanted line of some kind */
  1501. X    /* there can be only zero or two intersections below */
  1502. X
  1503. X    /* does it intersect ymin edge */
  1504. X    if (inrange(ymin, ay, by)) {
  1505. X       x = ax + (ymin-ay) * ((bx-ax) / (by-ay));
  1506. X       if (inrange(x, xmin, xmax)) {
  1507. X          *lx++ = x;
  1508. X          *ly++ = ymin;
  1509. X          intersect = TRUE;
  1510. X       }
  1511. X    }
  1512. X    
  1513. X    /* does it intersect ymax edge */
  1514. X    if (inrange(ymax, ay, by)) {
  1515. X       x = ax + (ymax-ay) * ((bx-ax) / (by-ay));
  1516. X       if (inrange(x, xmin, xmax)) {
  1517. X          *lx++ = x;
  1518. X          *ly++ = ymax;
  1519. X          intersect = TRUE;
  1520. X       }
  1521. X    }
  1522. X
  1523. X    /* does it intersect xmin edge */
  1524. X    if (inrange(xmin, ax, bx)) {
  1525. X       y = ay + (xmin-ax) * ((by-ay) / (bx-ax));
  1526. X       if (inrange(y, ymin, ymax)) {
  1527. X          *lx++ = xmin;
  1528. X          *ly++ = y;
  1529. X          intersect = TRUE;
  1530. X       }
  1531. X    }
  1532. X
  1533. X    /* does it intersect xmax edge */
  1534. X    if (inrange(xmax, ax, bx)) {
  1535. X       y = ay + (xmax-ax) * ((by-ay) / (bx-ax));
  1536. X       if (inrange(y, ymin, ymax)) {
  1537. X          *lx++ = xmax;
  1538. X          *ly++ = y;
  1539. X          intersect = TRUE;
  1540. X       }
  1541. X    }
  1542. X
  1543. X    if (intersect)
  1544. X     return(TRUE);
  1545. X
  1546. X    /* It is possible for one or more of the [ab][xy] values to be -VERYLARGE.
  1547. X    * If ax=bx=-VERYLARGE or ay=by=-VERYLARGE we have already returned
  1548. X    * FALSE above.
  1549. X    * Note that for ax=ay=-VERYLARGE or bx=by=-VERYLARGE we can do nothing.
  1550. X    * Otherwise we fall through all the tests above. 
  1551. X    * Handle them carefully here. As yet we have no way for them to be +VERYLARGE.
  1552. X    */
  1553. X    if (ax == -VERYLARGE) {
  1554. X       if (ay != -VERYLARGE
  1555. X          && inrange(by, ymin, ymax) && inrange(xmax, ax, bx)) {
  1556. X          *lx++ = xmin;
  1557. X          *ly = by;
  1558. X          *lx++ = xmax;
  1559. X          *ly = by;
  1560. X          intersect = TRUE;
  1561. X       }
  1562. X    } else if (bx == -VERYLARGE) {
  1563. X       if (by != -VERYLARGE
  1564. X          && inrange(ay, ymin, ymax) && inrange(xmax, ax, bx)) {
  1565. X          *lx++ = xmin;
  1566. X          *ly = ay;
  1567. X          *lx++ = xmax;
  1568. X          *ly = ay;
  1569. X          intersect = TRUE;
  1570. X       }
  1571. X    } else if (ay == -VERYLARGE) {
  1572. X       /* note we know ax != -VERYLARGE */
  1573. X       if (inrange(bx, xmin, xmax) && inrange(ymax, ay, by)) {
  1574. X          *lx++ = bx;
  1575. X          *ly = ymin;
  1576. X          *lx++ = bx;
  1577. X          *ly = ymax;
  1578. X          intersect = TRUE;
  1579. X       }
  1580. X    } else if (by == -VERYLARGE) {
  1581. X       /* note we know bx != -VERYLARGE */
  1582. X       if (inrange(ax, xmin, xmax) && inrange(ymax, ay, by)) {
  1583. X          *lx++ = ax;
  1584. X          *ly = ymin;
  1585. X          *lx++ = ax;
  1586. X          *ly = ymax;
  1587. X          intersect = TRUE;
  1588. X       }
  1589. X    }
  1590. X
  1591. X    return(intersect);
  1592. X}
  1593. X
  1594. X/* Polar transform of all curves */
  1595. X/* Original code by John Campbell (CAMPBELL@NAUVAX.bitnet) */
  1596. Xpolar_xform (plots, pcount)
  1597. X    struct curve_points *plots;
  1598. X    int pcount;            /* count of curves in plots array */
  1599. X{
  1600. X     struct curve_points *this_plot;
  1601. X     int curve;            /* loop var, for curves */
  1602. X     register int i, p_cnt;    /* loop/limit var, for points */
  1603. X     struct coordinate *pnts;    /* abbrev. for points array */
  1604. X    double x, y;            /* new cartesian value */
  1605. X    BOOLEAN anydefined = FALSE;
  1606. X
  1607. X/*
  1608. X    Cycle through all the plots converting polar to rectangular.
  1609. X     If autoscaling, adjust max and mins. Ignore previous values.
  1610. X    If not autoscaling, use the yrange for both x and y ranges.
  1611. X*/
  1612. X    if (autoscale_ly) {
  1613. X        xmin = VERYLARGE;
  1614. X        ymin = VERYLARGE;
  1615. X        xmax = -VERYLARGE;
  1616. X        ymax = -VERYLARGE;
  1617. X        autoscale_lx = TRUE;
  1618. X    } else {
  1619. X        xmin = ymin;
  1620. X        xmax = ymax;
  1621. X    }
  1622. X    
  1623. X    this_plot = plots;
  1624. X    for (curve = 0; curve < pcount; this_plot = this_plot->next_cp, curve++) {
  1625. X        p_cnt = this_plot->p_count;
  1626. X        pnts = &(this_plot->points[0]);
  1627. X
  1628. X    /*    Convert to cartesian all points in this curve. */
  1629. X        for (i = 0; i < p_cnt; i++) {
  1630. X            if (pnts[i].type != UNDEFINED) {
  1631. X                 anydefined = TRUE;
  1632. X                x = pnts[i].y*cos(pnts[i].x);
  1633. X                y = pnts[i].y*sin(pnts[i].x);
  1634. X                pnts[i].x = x;
  1635. X                pnts[i].y = y;
  1636. X                if (autoscale_ly) {
  1637. X                    if (xmin > x) xmin = x;
  1638. X                    if (xmax < x) xmax = x;
  1639. X                    if (ymin > y) ymin = y;
  1640. X                    if (ymax < y) ymax = y;
  1641. X                    pnts[i].type = INRANGE;
  1642. X                } else if(inrange(x, xmin, xmax) && inrange(y, ymin, ymax))
  1643. X                  pnts[i].type = INRANGE;
  1644. X                else
  1645. X                  pnts[i].type = OUTRANGE;
  1646. X            }
  1647. X        }    
  1648. X    }
  1649. X
  1650. X    if (autoscale_lx && anydefined && fabs(xmax - xmin) < zero) {
  1651. X        /* This happens at least for the plot of 1/cos(x) (vertical line). */
  1652. X        fprintf(stderr, "Warning: empty x range [%g:%g], ", xmin,xmax);
  1653. X        if (xmin == 0.0) {
  1654. X           xmin = -1; 
  1655. X           xmax = 1;
  1656. X        } else {
  1657. X           xmin *= 0.9;
  1658. X           xmax *= 1.1;
  1659. X        }
  1660. X        fprintf(stderr, "adjusting to [%g:%g]\n", xmin,xmax);
  1661. X    }
  1662. X    if (autoscale_ly && anydefined && fabs(ymax - ymin) < zero) {
  1663. X        /* This happens at least for the plot of 1/sin(x) (horiz. line). */
  1664. X        fprintf(stderr, "Warning: empty y range [%g:%g], ", ymin, ymax);
  1665. X        if (ymin == 0.0) {
  1666. X           ymin = -1;
  1667. X           ymax = 1;
  1668. X        } else {
  1669. X           ymin *= 0.9;
  1670. X           ymax *= 1.1;
  1671. X        }
  1672. X        fprintf(stderr, "adjusting to [%g:%g]\n", ymin, ymax);
  1673. X    }
  1674. X}
  1675. X
  1676. X/* DRAW_YTICS: draw a regular tic series, y axis */
  1677. Xdraw_ytics(start, incr, end)
  1678. X        double start, incr, end; /* tic series definition */
  1679. X        /* assume start < end, incr > 0 */
  1680. X{
  1681. X    double ticplace;
  1682. X    int ltic;            /* for mini log tics */
  1683. X    double lticplace;    /* for mini log tics */
  1684. X    double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1685. X
  1686. X    if (end == VERYLARGE)            /* for user-def series */
  1687. X        end = max(ymin,ymax);
  1688. X
  1689. X    /* limit to right side of plot */
  1690. X    end = min(end, max(ymin,ymax));
  1691. X
  1692. X    /* to allow for rounding errors */
  1693. X    ticmin = min(ymin,ymax) - SIGNIF*incr;
  1694. X    ticmax = max(ymin,ymax) + SIGNIF*incr;
  1695. X    end = end + SIGNIF*incr; 
  1696. X
  1697. X    for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1698. X        if ( inrange(ticplace,ticmin,ticmax) )
  1699. X            ytick(ticplace, yformat, incr, 1.0);
  1700. X        if (log_y && incr == 1.0) {
  1701. X            /* add mini-ticks to log scale ticmarks */
  1702. X            for (ltic = 2; ltic <= 9; ltic++) {
  1703. X                lticplace = ticplace+log10((double)ltic);
  1704. X                if ( inrange(lticplace,ticmin,ticmax) )
  1705. X                    ytick(lticplace, (char *)NULL, incr, 0.5);
  1706. X            }
  1707. X        }
  1708. X    }
  1709. X}
  1710. X
  1711. X
  1712. X/* DRAW_XTICS: draw a regular tic series, x axis */
  1713. Xdraw_xtics(start, incr, end)
  1714. X        double start, incr, end; /* tic series definition */
  1715. X        /* assume start < end, incr > 0 */
  1716. X{
  1717. X    double ticplace;
  1718. X    int ltic;            /* for mini log tics */
  1719. X    double lticplace;    /* for mini log tics */
  1720. X    double ticmin, ticmax;    /* for checking if tic is almost inrange */
  1721. X
  1722. X    if (end == VERYLARGE)            /* for user-def series */
  1723. X        end = max(xmin,xmax);
  1724. X
  1725. X    /* limit to right side of plot */
  1726. X    end = min(end, max(xmin,xmax));
  1727. X
  1728. X    /* to allow for rounding errors */
  1729. X    ticmin = min(xmin,xmax) - SIGNIF*incr;
  1730. X    ticmax = max(xmin,xmax) + SIGNIF*incr;
  1731. X    end = end + SIGNIF*incr; 
  1732. X
  1733. X    for (ticplace = start; ticplace <= end; ticplace +=incr) {
  1734. X        if ( inrange(ticplace,ticmin,ticmax) )
  1735. X            xtick(ticplace, xformat, incr, 1.0);
  1736. X        if (log_x && incr == 1.0) {
  1737. X            /* add mini-ticks to log scale ticmarks */
  1738. X            for (ltic = 2; ltic <= 9; ltic++) {
  1739. X                lticplace = ticplace+log10((double)ltic);
  1740. X                if ( inrange(lticplace,ticmin,ticmax) )
  1741. X                    xtick(lticplace, (char *)NULL, incr, 0.5);
  1742. X            }
  1743. X        }
  1744. X    }
  1745. X}
  1746. X
  1747. X/* DRAW_USER_YTICS: draw a user tic series, y axis */
  1748. Xdraw_user_ytics(list)
  1749. X    struct ticmark *list;    /* list of tic marks */
  1750. X{
  1751. X    double ticplace;
  1752. X    double incr = (ymax - ymin) / 10;
  1753. X    /* global xmin, xmax, xscale, ymin, ymax, yscale */
  1754. X
  1755. X    while (list != NULL) {
  1756. X       ticplace = list->position;
  1757. X       if ( inrange(ticplace, ymin, ymax)         /* in range */
  1758. X          || NearlyEqual(ticplace, ymin, incr)    /* == ymin */
  1759. X          || NearlyEqual(ticplace, ymax, incr))    /* == ymax */
  1760. X        ytick(ticplace, list->label, incr, 1.0);
  1761. X
  1762. X       list = list->next;
  1763. X    }
  1764. X}
  1765. X
  1766. X/* DRAW_USER_XTICS: draw a user tic series, x axis */
  1767. Xdraw_user_xtics(list)
  1768. X    struct ticmark *list;    /* list of tic marks */
  1769. X{
  1770. X    double ticplace;
  1771. X    double incr = (xmax - xmin) / 10;
  1772. X    /* global xmin, xmax, xscale, ymin, ymax, yscale */
  1773. X
  1774. X    while (list != NULL) {
  1775. X       ticplace = list->position;
  1776. X       if ( inrange(ticplace, xmin, xmax)         /* in range */
  1777. X          || NearlyEqual(ticplace, xmin, incr)    /* == xmin */
  1778. X          || NearlyEqual(ticplace, xmax, incr))    /* == xmax */
  1779. X        xtick(ticplace, list->label, incr, 1.0);
  1780. X
  1781. X       list = list->next;
  1782. X    }
  1783. X}
  1784. X
  1785. X/* draw and label a y-axis ticmark */
  1786. Xytick(place, text, spacing, ticscale)
  1787. X        double place;                   /* where on axis to put it */
  1788. X        char *text;                     /* optional text label */
  1789. X        double spacing;         /* something to use with checkzero */
  1790. X        float ticscale;         /* scale factor for tic mark (0..1] */
  1791. X{
  1792. X    register struct termentry *t = &term_tbl[term];
  1793. X    char ticlabel[101];
  1794. X    int ticsize = (int)((t->h_tic) * ticscale);
  1795. X
  1796. X    place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1797. X    if (grid) {
  1798. X           (*t->linetype)(-1);  /* axis line type */
  1799. X           (*t->move)(xleft, map_y(place));
  1800. X           (*t->vector)(xright, map_y(place));
  1801. X           (*t->linetype)(-2); /* border linetype */
  1802. X    }
  1803. X    if (tic_in) {
  1804. X           (*t->move)(xleft, map_y(place));
  1805. X           (*t->vector)(xleft + ticsize, map_y(place));
  1806. X           (*t->move)(xright, map_y(place));
  1807. X           (*t->vector)(xright - ticsize, map_y(place));
  1808. X    } else {
  1809. X           (*t->move)(xleft, map_y(place));
  1810. X           (*t->vector)(xleft - ticsize, map_y(place));
  1811. X    }
  1812. X
  1813. X    /* label the ticmark */
  1814. X    if (text) {
  1815. X        (void) sprintf(ticlabel, text, CheckLog(log_y, place));
  1816. X        if ((*t->justify_text)(RIGHT)) {
  1817. X           (*t->put_text)(xleft-(t->h_char),
  1818. X                       map_y(place), ticlabel);
  1819. X        } else {
  1820. X           (*t->put_text)(xleft-(t->h_char)*(strlen(ticlabel)+1),
  1821. X                       map_y(place), ticlabel);
  1822. X        }
  1823. X    }
  1824. X}
  1825. X
  1826. X/* draw and label an x-axis ticmark */
  1827. Xxtick(place, text, spacing, ticscale)
  1828. X        double place;                   /* where on axis to put it */
  1829. X        char *text;                     /* optional text label */
  1830. X        double spacing;         /* something to use with checkzero */
  1831. X        float ticscale;         /* scale factor for tic mark (0..1] */
  1832. X{
  1833. X    register struct termentry *t = &term_tbl[term];
  1834. X    char ticlabel[101];
  1835. X    int ticsize = (int)((t->v_tic) * ticscale);
  1836. X
  1837. X    place = CheckZero(place,spacing); /* to fix rounding error near zero */
  1838. X    if (grid) {
  1839. X           (*t->linetype)(-1);  /* axis line type */
  1840. X           (*t->move)(map_x(place), ybot);
  1841. X           (*t->vector)(map_x(place), ytop);
  1842. X           (*t->linetype)(-2); /* border linetype */
  1843. X    }
  1844. X    if (tic_in) {
  1845. X           (*t->move)(map_x(place), ybot);
  1846. X           (*t->vector)(map_x(place), ybot + ticsize);
  1847. X           (*t->move)(map_x(place), ytop);
  1848. X           (*t->vector)(map_x(place), ytop - ticsize);
  1849. X    } else {
  1850. X           (*t->move)(map_x(place), ybot);
  1851. X           (*t->vector)(map_x(place), ybot - ticsize);
  1852. X    }
  1853. X
  1854. X    /* label the ticmark */
  1855. X    if (text) {
  1856. X       (void) sprintf(ticlabel, text, CheckLog(log_x, place));
  1857. X       if ((*t->justify_text)(CENTRE)) {
  1858. X          (*t->put_text)(map_x(place),
  1859. X                      ybot-(t->v_char), ticlabel);
  1860. X       } else {
  1861. X          (*t->put_text)(map_x(place)-(t->h_char)*strlen(ticlabel)/2,
  1862. X                      ybot-(t->v_char), ticlabel);
  1863. X       }
  1864. X    }
  1865. X}
  1866. *-*-END-of-graphics.c-*-*
  1867. echo x - internal.c
  1868. sed 's/^X//' >internal.c <<'*-*-END-of-internal.c-*-*'
  1869. X/* GNUPLOT - internal.c */
  1870. X/*
  1871. X * Copyright (C) 1986, 1987, 1990   Thomas Williams, Colin Kelley
  1872. X *
  1873. X * Permission to use, copy, and distribute this software and its
  1874. X * documentation for any purpose with or without fee is hereby granted, 
  1875. X * provided that the above copyright notice appear in all copies and 
  1876. X * that both that copyright notice and this permission notice appear 
  1877. X * in supporting documentation.
  1878. X *
  1879. X * Permission to modify the software is granted, but not the right to
  1880. X * distribute the modified code.  Modifications are to be distributed 
  1881. X * as patches to released version.
  1882. X *  
  1883. X * This software  is provided "as is" without express or implied warranty.
  1884. X * 
  1885. X *
  1886. X * AUTHORS
  1887. X * 
  1888. X *   Original Software:
  1889. X *     Thomas Williams,  Colin Kelley.
  1890. X * 
  1891. X *   Gnuplot 2.0 additions:
  1892. X *       Russell Lang, Dave Kotz, John Campbell.
  1893. X * 
  1894. X * send your comments or suggestions to (pixar!info-gnuplot@sun.com).
  1895. X * 
  1896. X */
  1897. X
  1898. X#include <math.h>
  1899. X#include <stdio.h>
  1900. X#include "plot.h"
  1901. X
  1902. XBOOLEAN undefined;
  1903. X
  1904. Xchar *strcpy();
  1905. X
  1906. Xstruct value *pop(), *complex(), *integer();
  1907. Xdouble magnitude(), angle(), real();
  1908. X
  1909. Xstruct value stack[STACK_DEPTH];
  1910. X
  1911. Xint s_p = -1;   /* stack pointer */
  1912. X
  1913. X
  1914. X/*
  1915. X * System V and MSC 4.0 call this when they wants to print an error message.
  1916. X * Don't!
  1917. X */
  1918. X#ifdef MSDOS
  1919. X#ifdef __TURBOC__
  1920. Xint matherr()    /* Turbo C */
  1921. X#else
  1922. Xint matherr(x)    /* MSC 5.1 */
  1923. Xstruct exception *x;
  1924. X#endif /* TURBOC */
  1925. X#else /* MSDOS */
  1926. Xint matherr()
  1927. X#endif /* MSDOS */
  1928. X{
  1929. X    return (undefined = TRUE);        /* don't print error message */
  1930. X}
  1931. X
  1932. X
  1933. Xreset_stack()
  1934. X{
  1935. X    s_p = -1;
  1936. X}
  1937. X
  1938. X
  1939. Xcheck_stack()    /* make sure stack's empty */
  1940. X{
  1941. X    if (s_p != -1)
  1942. X        fprintf(stderr,"\nwarning:  internal error--stack not empty!\n");
  1943. X}
  1944. X
  1945. X
  1946. Xstruct value *pop(x)
  1947. Xstruct value *x;
  1948. X{
  1949. X    if (s_p  < 0 )
  1950. X        int_error("stack underflow",NO_CARET);
  1951. X    *x = stack[s_p--];
  1952. X    return(x);
  1953. X}
  1954. X
  1955. X
  1956. Xpush(x)
  1957. Xstruct value *x;
  1958. X{
  1959. X    if (s_p == STACK_DEPTH - 1)
  1960. X        int_error("stack overflow",NO_CARET);
  1961. X    stack[++s_p] = *x;
  1962. X}
  1963. X
  1964. X
  1965. X#define ERR_VAR "undefined variable: "
  1966. X
  1967. Xf_push(x)
  1968. Xunion argument *x;        /* contains pointer to value to push; */
  1969. X{
  1970. Xstatic char err_str[sizeof(ERR_VAR) + MAX_ID_LEN] = ERR_VAR;
  1971. Xstruct udvt_entry *udv;
  1972. X
  1973. X    udv = x->udv_arg;
  1974. X    if (udv->udv_undef) {     /* undefined */
  1975. X        (void) strcpy(&err_str[sizeof(ERR_VAR) - 1], udv->udv_name);
  1976. X        int_error(err_str,NO_CARET);
  1977. X    }
  1978. X    push(&(udv->udv_value));
  1979. X}
  1980. X
  1981. X
  1982. Xf_pushc(x)
  1983. Xunion argument *x;
  1984. X{
  1985. X    push(&(x->v_arg));
  1986. X}
  1987. X
  1988. X
  1989. Xf_pushd(x)
  1990. Xunion argument *x;
  1991. X{
  1992. X    push(&(x->udf_arg->dummy_value));
  1993. X}
  1994. X
  1995. X
  1996. X#define ERR_FUN "undefined function: "
  1997. X
  1998. Xf_call(x)  /* execute a udf */
  1999. Xunion argument *x;
  2000. X{
  2001. Xstatic char err_str[sizeof(ERR_FUN) + MAX_ID_LEN] = ERR_FUN;
  2002. Xregister struct udft_entry *udf;
  2003. X
  2004. X    udf = x->udf_arg;
  2005. X    if (!udf->at) { /* undefined */
  2006. X        (void) strcpy(&err_str[sizeof(ERR_FUN) - 1],
  2007. X                udf->udf_name);
  2008. X        int_error(err_str,NO_CARET);
  2009. X    }
  2010. X    (void) pop(&(udf->dummy_value));
  2011. X
  2012. X    execute_at(udf->at);
  2013. X}
  2014. X
  2015. X
  2016. Xstatic int_check(v)
  2017. Xstruct value *v;
  2018. X{
  2019. X    if (v->type != INT)
  2020. X        int_error("non-integer passed to boolean operator",NO_CARET);
  2021. X}
  2022. X
  2023. X
  2024. Xf_lnot()
  2025. X{
  2026. Xstruct value a;
  2027. X    int_check(pop(&a));
  2028. X    push(integer(&a,!a.v.int_val) );
  2029. X}
  2030. X
  2031. X
  2032. Xf_bnot()
  2033. X{
  2034. Xstruct value a;
  2035. X    int_check(pop(&a));
  2036. X    push( integer(&a,~a.v.int_val) );
  2037. X}
  2038. X
  2039. X
  2040. Xf_bool()
  2041. X{            /* converts top-of-stack to boolean */
  2042. X    int_check(&top_of_stack);
  2043. X    top_of_stack.v.int_val = !!top_of_stack.v.int_val;
  2044. X}
  2045. X
  2046. X
  2047. Xf_lor()
  2048. X{
  2049. Xstruct value a,b;
  2050. X    int_check(pop(&b));
  2051. X    int_check(pop(&a));
  2052. X    push( integer(&a,a.v.int_val || b.v.int_val) );
  2053. X}
  2054. X
  2055. Xf_land()
  2056. X{
  2057. Xstruct value a,b;
  2058. X    int_check(pop(&b));
  2059. X    int_check(pop(&a));
  2060. X    push( integer(&a,a.v.int_val && b.v.int_val) );
  2061. X}
  2062. X
  2063. X
  2064. Xf_bor()
  2065. X{
  2066. Xstruct value a,b;
  2067. X    int_check(pop(&b));
  2068. X    int_check(pop(&a));
  2069. X    push( integer(&a,a.v.int_val | b.v.int_val) );
  2070. X}
  2071. X
  2072. X
  2073. Xf_xor()
  2074. X{
  2075. Xstruct value a,b;
  2076. X    int_check(pop(&b));
  2077. X    int_check(pop(&a));
  2078. X    push( integer(&a,a.v.int_val ^ b.v.int_val) );
  2079. X}
  2080. X
  2081. X
  2082. Xf_band()
  2083. X{
  2084. Xstruct value a,b;
  2085. X    int_check(pop(&b));
  2086. X    int_check(pop(&a));
  2087. X    push( integer(&a,a.v.int_val & b.v.int_val) );
  2088. X}
  2089. X
  2090. X
  2091. Xf_uminus()
  2092. X{
  2093. Xstruct value a;
  2094. X    (void) pop(&a);
  2095. X    switch(a.type) {
  2096. X        case INT:
  2097. X            a.v.int_val = -a.v.int_val;
  2098. X            break;
  2099. X        case CMPLX:
  2100. X            a.v.cmplx_val.real =
  2101. X                -a.v.cmplx_val.real;
  2102. X            a.v.cmplx_val.imag =
  2103. X                -a.v.cmplx_val.imag;
  2104. X    }
  2105. X    push(&a);
  2106. X}
  2107. X
  2108. X
  2109. Xf_eq() /* note: floating point equality is rare because of roundoff error! */
  2110. X{
  2111. Xstruct value a, b;
  2112. X    register int result;
  2113. X    (void) pop(&b);
  2114. X    (void) pop(&a);
  2115. X    switch(a.type) {
  2116. X        case INT:
  2117. X            switch (b.type) {
  2118. X                case INT:
  2119. X                    result = (a.v.int_val ==
  2120. X                        b.v.int_val);
  2121. X                    break;
  2122. X                case CMPLX:
  2123. X                    result = (a.v.int_val ==
  2124. X                        b.v.cmplx_val.real &&
  2125. X                       b.v.cmplx_val.imag == 0.0);
  2126. X            }
  2127. X            break;
  2128. X        case CMPLX:
  2129. X            switch (b.type) {
  2130. X                case INT:
  2131. X                    result = (b.v.int_val == a.v.cmplx_val.real &&
  2132. X                       a.v.cmplx_val.imag == 0.0);
  2133. X                    break;
  2134. X                case CMPLX:
  2135. X                    result = (a.v.cmplx_val.real==
  2136. X                        b.v.cmplx_val.real &&
  2137. X                        a.v.cmplx_val.imag==
  2138. X                        b.v.cmplx_val.imag);
  2139. X            }
  2140. X    }
  2141. X    push(integer(&a,result));
  2142. X}
  2143. X
  2144. X
  2145. Xf_ne()
  2146. X{
  2147. Xstruct value a, b;
  2148. X    register int result;
  2149. X    (void) pop(&b);
  2150. X    (void) pop(&a);
  2151. X    switch(a.type) {
  2152. X        case INT:
  2153. X            switch (b.type) {
  2154. X                case INT:
  2155. X                    result = (a.v.int_val !=
  2156. X                        b.v.int_val);
  2157. X                    break;
  2158. X                case CMPLX:
  2159. X                    result = (a.v.int_val !=
  2160. X                        b.v.cmplx_val.real ||
  2161. X                       b.v.cmplx_val.imag != 0.0);
  2162. X            }
  2163. X            break;
  2164. X        case CMPLX:
  2165. X            switch (b.type) {
  2166. X                case INT:
  2167. X                    result = (b.v.int_val !=
  2168. X                        a.v.cmplx_val.real ||
  2169. X                       a.v.cmplx_val.imag != 0.0);
  2170. X                    break;
  2171. X                case CMPLX:
  2172. X                    result = (a.v.cmplx_val.real !=
  2173. X                        b.v.cmplx_val.real ||
  2174. X                        a.v.cmplx_val.imag !=
  2175. X                        b.v.cmplx_val.imag);
  2176. X            }
  2177. X    }
  2178. X    push(integer(&a,result));
  2179. X}
  2180. X
  2181. X
  2182. Xf_gt()
  2183. X{
  2184. Xstruct value a, b;
  2185. X    register int result;
  2186. X    (void) pop(&b);
  2187. X    (void) pop(&a);
  2188. X    switch(a.type) {
  2189. X        case INT:
  2190. X            switch (b.type) {
  2191. X                case INT:
  2192. X                    result = (a.v.int_val >
  2193. X                        b.v.int_val);
  2194. X                    break;
  2195. X                case CMPLX:
  2196. X                    result = (a.v.int_val >
  2197. X                        b.v.cmplx_val.real);
  2198. X            }
  2199. X            break;
  2200. X        case CMPLX:
  2201. X            switch (b.type) {
  2202. X                case INT:
  2203. X                    result = (a.v.cmplx_val.real >
  2204. X                        b.v.int_val);
  2205. X                    break;
  2206. X                case CMPLX:
  2207. X                    result = (a.v.cmplx_val.real >
  2208. X                        b.v.cmplx_val.real);
  2209. X            }
  2210. X    }
  2211. X    push(integer(&a,result));
  2212. X}
  2213. X
  2214. X
  2215. Xf_lt()
  2216. X{
  2217. Xstruct value a, b;
  2218. X    register int result;
  2219. X    (void) pop(&b);
  2220. X    (void) pop(&a);
  2221. X    switch(a.type) {
  2222. X        case INT:
  2223. X            switch (b.type) {
  2224. X                case INT:
  2225. X                    result = (a.v.int_val <
  2226. X                        b.v.int_val);
  2227. X                    break;
  2228. X                case CMPLX:
  2229. X                    result = (a.v.int_val <
  2230. X                        b.v.cmplx_val.real);
  2231. X            }
  2232. X            break;
  2233. X        case CMPLX:
  2234. X            switch (b.type) {
  2235. X                case INT:
  2236. X                    result = (a.v.cmplx_val.real <
  2237. X                        b.v.int_val);
  2238. X                    break;
  2239. X                case CMPLX:
  2240. X                    result = (a.v.cmplx_val.real <
  2241. X                        b.v.cmplx_val.real);
  2242. X            }
  2243. X    }
  2244. X    push(integer(&a,result));
  2245. X}
  2246. X
  2247. X
  2248. Xf_ge()
  2249. X{
  2250. Xstruct value a, b;
  2251. X    register int result;
  2252. X    (void) pop(&b);
  2253. X    (void) pop(&a);
  2254. X    switch(a.type) {
  2255. X        case INT:
  2256. X            switch (b.type) {
  2257. X                case INT:
  2258. X                    result = (a.v.int_val >=
  2259. X                        b.v.int_val);
  2260. X                    break;
  2261. X                case CMPLX:
  2262. X                    result = (a.v.int_val >=
  2263. X                        b.v.cmplx_val.real);
  2264. X            }
  2265. X            break;
  2266. X        case CMPLX:
  2267. X            switch (b.type) {
  2268. X                case INT:
  2269. X                    result = (a.v.cmplx_val.real >=
  2270. X                        b.v.int_val);
  2271. X                    break;
  2272. X                case CMPLX:
  2273. X                    result = (a.v.cmplx_val.real >=
  2274. X                        b.v.cmplx_val.real);
  2275. X            }
  2276. X    }
  2277. X    push(integer(&a,result));
  2278. X}
  2279. X
  2280. X
  2281. Xf_le()
  2282. X{
  2283. Xstruct value a, b;
  2284. X    register int result;
  2285. X    (void) pop(&b);
  2286. X    (void) pop(&a);
  2287. X    switch(a.type) {
  2288. X        case INT:
  2289. X            switch (b.type) {
  2290. X                case INT:
  2291. X                    result = (a.v.int_val <=
  2292. X                        b.v.int_val);
  2293. X                    break;
  2294. X                case CMPLX:
  2295. X                    result = (a.v.int_val <=
  2296. X                        b.v.cmplx_val.real);
  2297. X            }
  2298. X            break;
  2299. X        case CMPLX:
  2300. X            switch (b.type) {
  2301. X                case INT:
  2302. X                    result = (a.v.cmplx_val.real <=
  2303. X                        b.v.int_val);
  2304. X                    break;
  2305. X                case CMPLX:
  2306. X                    result = (a.v.cmplx_val.real <=
  2307. X                        b.v.cmplx_val.real);
  2308. X            }
  2309. X    }
  2310. X    push(integer(&a,result));
  2311. X}
  2312. X
  2313. X
  2314. Xf_plus()
  2315. X{
  2316. Xstruct value a, b, result;
  2317. X    (void) pop(&b);
  2318. X    (void) pop(&a);
  2319. X    switch(a.type) {
  2320. X        case INT:
  2321. X            switch (b.type) {
  2322. X                case INT:
  2323. X                    (void) integer(&result,a.v.int_val +
  2324. X                        b.v.int_val);
  2325. X                    break;
  2326. X                case CMPLX:
  2327. X                    (void) complex(&result,a.v.int_val +
  2328. X                        b.v.cmplx_val.real,
  2329. X                       b.v.cmplx_val.imag);
  2330. X            }
  2331. X            break;
  2332. X        case CMPLX:
  2333. X            switch (b.type) {
  2334. X                case INT:
  2335. X                    (void) complex(&result,b.v.int_val +
  2336. X                        a.v.cmplx_val.real,
  2337. X                       a.v.cmplx_val.imag);
  2338. X                    break;
  2339. X                case CMPLX:
  2340. X                    (void) complex(&result,a.v.cmplx_val.real+
  2341. X                        b.v.cmplx_val.real,
  2342. X                        a.v.cmplx_val.imag+
  2343. X                        b.v.cmplx_val.imag);
  2344. X            }
  2345. X    }
  2346. X    push(&result);
  2347. X}
  2348. X
  2349. X
  2350. Xf_minus()
  2351. X{
  2352. Xstruct value a, b, result;
  2353. X    (void) pop(&b);
  2354. X    (void) pop(&a);        /* now do a - b */
  2355. X    switch(a.type) {
  2356. X        case INT:
  2357. X            switch (b.type) {
  2358. X                case INT:
  2359. X                    (void) integer(&result,a.v.int_val -
  2360. X                        b.v.int_val);
  2361. X                    break;
  2362. X                case CMPLX:
  2363. X                    (void) complex(&result,a.v.int_val -
  2364. X                        b.v.cmplx_val.real,
  2365. X                       -b.v.cmplx_val.imag);
  2366. X            }
  2367. X            break;
  2368. X        case CMPLX:
  2369. X            switch (b.type) {
  2370. X                case INT:
  2371. X                    (void) complex(&result,a.v.cmplx_val.real -
  2372. X                        b.v.int_val,
  2373. X                        a.v.cmplx_val.imag);
  2374. X                    break;
  2375. X                case CMPLX:
  2376. X                    (void) complex(&result,a.v.cmplx_val.real-
  2377. X                        b.v.cmplx_val.real,
  2378. X                        a.v.cmplx_val.imag-
  2379. X                        b.v.cmplx_val.imag);
  2380. X            }
  2381. X    }
  2382. X    push(&result);
  2383. X}
  2384. X
  2385. X
  2386. Xf_mult()
  2387. X{
  2388. Xstruct value a, b, result;
  2389. X    (void) pop(&b);
  2390. X    (void) pop(&a);    /* now do a*b */
  2391. X
  2392. X    switch(a.type) {
  2393. X        case INT:
  2394. X            switch (b.type) {
  2395. X                case INT:
  2396. X                    (void) integer(&result,a.v.int_val *
  2397. X                        b.v.int_val);
  2398. X                    break;
  2399. X                case CMPLX:
  2400. X                    (void) complex(&result,a.v.int_val *
  2401. X                        b.v.cmplx_val.real,
  2402. X                        a.v.int_val *
  2403. X                        b.v.cmplx_val.imag);
  2404. X            }
  2405. X            break;
  2406. X        case CMPLX:
  2407. X            switch (b.type) {
  2408. X                case INT:
  2409. X                    (void) complex(&result,b.v.int_val *
  2410. X                        a.v.cmplx_val.real,
  2411. X                        b.v.int_val *
  2412. X                        a.v.cmplx_val.imag);
  2413. X                    break;
  2414. X                case CMPLX:
  2415. X                    (void) complex(&result,a.v.cmplx_val.real*
  2416. X                        b.v.cmplx_val.real-
  2417. X                        a.v.cmplx_val.imag*
  2418. X                        b.v.cmplx_val.imag,
  2419. X                        a.v.cmplx_val.real*
  2420. X                        b.v.cmplx_val.imag+
  2421. X                        a.v.cmplx_val.imag*
  2422. X                        b.v.cmplx_val.real);
  2423. X            }
  2424. X    }
  2425. X    push(&result);
  2426. X}
  2427. X
  2428. X
  2429. Xf_div()
  2430. X{
  2431. Xstruct value a, b, result;
  2432. Xregister double square;
  2433. X    (void) pop(&b);
  2434. X    (void) pop(&a);    /* now do a/b */
  2435. X
  2436. X    switch(a.type) {
  2437. X        case INT:
  2438. X            switch (b.type) {
  2439. X                case INT:
  2440. X                    if (b.v.int_val)
  2441. X                      (void) integer(&result,a.v.int_val /
  2442. X                        b.v.int_val);
  2443. X                    else {
  2444. X                      (void) integer(&result,0);
  2445. X                      undefined = TRUE;
  2446. X                    }
  2447. X                    break;
  2448. X                case CMPLX:
  2449. X                    square = b.v.cmplx_val.real*
  2450. X                        b.v.cmplx_val.real +
  2451. X                        b.v.cmplx_val.imag*
  2452. X                        b.v.cmplx_val.imag;
  2453. X                    if (square)
  2454. X                        (void) complex(&result,a.v.int_val*
  2455. X                        b.v.cmplx_val.real/square,
  2456. X                        -a.v.int_val*
  2457. X                        b.v.cmplx_val.imag/square);
  2458. X                    else {
  2459. X                        (void) complex(&result,0.0,0.0);
  2460. X                        undefined = TRUE;
  2461. X                    }
  2462. X            }
  2463. X            break;
  2464. X        case CMPLX:
  2465. X            switch (b.type) {
  2466. X                case INT:
  2467. X                    if (b.v.int_val)
  2468. X                      
  2469. X                      (void) complex(&result,a.v.cmplx_val.real/
  2470. X                        b.v.int_val,
  2471. X                        a.v.cmplx_val.imag/
  2472. X                        b.v.int_val);
  2473. X                    else {
  2474. X                        (void) complex(&result,0.0,0.0);
  2475. X                        undefined = TRUE;
  2476. X                    }
  2477. X                    break;
  2478. X                case CMPLX:
  2479. X                    square = b.v.cmplx_val.real*
  2480. X                        b.v.cmplx_val.real +
  2481. X                        b.v.cmplx_val.imag*
  2482. X                        b.v.cmplx_val.imag;
  2483. X                    if (square)
  2484. X                    (void) complex(&result,(a.v.cmplx_val.real*
  2485. X                        b.v.cmplx_val.real+
  2486. X                        a.v.cmplx_val.imag*
  2487. X                        b.v.cmplx_val.imag)/square,
  2488. X                        (a.v.cmplx_val.imag*
  2489. X                        b.v.cmplx_val.real-
  2490. X                        a.v.cmplx_val.real*
  2491. X                        b.v.cmplx_val.imag)/
  2492. X                            square);
  2493. X                    else {
  2494. X                        (void) complex(&result,0.0,0.0);
  2495. X                        undefined = TRUE;
  2496. X                    }
  2497. X            }
  2498. X    }
  2499. X    push(&result);
  2500. X}
  2501. X
  2502. X
  2503. Xf_mod()
  2504. X{
  2505. Xstruct value a, b;
  2506. X    (void) pop(&b);
  2507. X    (void) pop(&a);    /* now do a%b */
  2508. X
  2509. X    if (a.type != INT || b.type != INT)
  2510. X        int_error("can only mod ints",NO_CARET);
  2511. X    if (b.v.int_val)
  2512. X        push(integer(&a,a.v.int_val % b.v.int_val));
  2513. X    else {
  2514. X        push(integer(&a,0));
  2515. X        undefined = TRUE;
  2516. X    }
  2517. X}
  2518. X
  2519. X
  2520. Xf_power()
  2521. X{
  2522. Xstruct value a, b, result;
  2523. Xregister int i, t, count;
  2524. Xregister double mag, ang;
  2525. X    (void) pop(&b);
  2526. X    (void) pop(&a);    /* now find a**b */
  2527. X
  2528. X    switch(a.type) {
  2529. X        case INT:
  2530. X            switch (b.type) {
  2531. X                case INT:
  2532. X                    count = abs(b.v.int_val);
  2533. X                    t = 1;
  2534. X                    for(i = 0; i < count; i++)
  2535. X                        t *= a.v.int_val;
  2536. X                    if (b.v.int_val >= 0)
  2537. X                        (void) integer(&result,t);
  2538. X                    else
  2539. X                        (void) complex(&result,1.0/t,0.0);
  2540. X                    break;
  2541. X                case CMPLX:
  2542. X                    mag =
  2543. X                      pow(magnitude(&a),fabs(b.v.cmplx_val.real));
  2544. X                    if (b.v.cmplx_val.real < 0.0)
  2545. X                        mag = 1.0/mag;
  2546. X                    ang = angle(&a)*b.v.cmplx_val.real+
  2547. X                      b.v.cmplx_val.imag;
  2548. X                    (void) complex(&result,mag*cos(ang),
  2549. X                        mag*sin(ang));
  2550. X            }
  2551. X            break;
  2552. X        case CMPLX:
  2553. X            switch (b.type) {
  2554. X                case INT:
  2555. X                    if (a.v.cmplx_val.imag == 0.0) {
  2556. X                        mag = pow(a.v.cmplx_val.real,(double)abs(b.v.int_val));
  2557. X                        if (b.v.int_val < 0)
  2558. X                            mag = 1.0/mag;
  2559. X                        (void) complex(&result,mag,0.0);
  2560. X                    }
  2561. X                    else {
  2562. X                        /* not so good, but...! */
  2563. X                        mag = pow(magnitude(&a),(double)abs(b.v.int_val));
  2564. X                        if (b.v.int_val < 0)
  2565. X                            mag = 1.0/mag;
  2566. X                        ang = angle(&a)*b.v.int_val;
  2567. X                        (void) complex(&result,mag*cos(ang),
  2568. X                            mag*sin(ang));
  2569. X                    }
  2570. X                    break;
  2571. X                case CMPLX:
  2572. X                    mag = pow(magnitude(&a),fabs(b.v.cmplx_val.real));
  2573. X                    if (b.v.cmplx_val.real < 0.0)
  2574. X                      mag = 1.0/mag;
  2575. X                    ang = angle(&a)*b.v.cmplx_val.real+ b.v.cmplx_val.imag;
  2576. X                    (void) complex(&result,mag*cos(ang),
  2577. X                        mag*sin(ang));
  2578. X            }
  2579. X    }
  2580. X    push(&result);
  2581. X}
  2582. X
  2583. X
  2584. Xf_factorial()
  2585. X{
  2586. Xstruct value a;
  2587. Xregister int i;
  2588. Xregister double val;
  2589. X
  2590. X    (void) pop(&a);    /* find a! (factorial) */
  2591. X
  2592. X    switch (a.type) {
  2593. X        case INT:
  2594. X            val = 1.0;
  2595. X            for (i = a.v.int_val; i > 1; i--)  /*fpe's should catch overflows*/
  2596. X                val *= i;
  2597. X            break;
  2598. X        default:
  2599. X            int_error("factorial (!) argument must be an integer",
  2600. X            NO_CARET);
  2601. X        }
  2602. X
  2603. X    push(complex(&a,val,0.0));
  2604. X            
  2605. X}
  2606. X
  2607. X
  2608. Xint
  2609. Xf_jump(x)
  2610. Xunion argument *x;
  2611. X{
  2612. X    return(x->j_arg);
  2613. X}
  2614. X
  2615. X
  2616. Xint
  2617. Xf_jumpz(x)
  2618. Xunion argument *x;
  2619. X{
  2620. Xstruct value a;
  2621. X    int_check(&top_of_stack);
  2622. X    if (top_of_stack.v.int_val) {    /* non-zero */
  2623. X        (void) pop(&a);
  2624. X        return 1;                /* no jump */
  2625. X    }
  2626. X    else
  2627. X        return(x->j_arg);        /* leave the argument on TOS */
  2628. X}
  2629. X
  2630. X
  2631. Xint
  2632. Xf_jumpnz(x)
  2633. Xunion argument *x;
  2634. X{
  2635. Xstruct value a;
  2636. X    int_check(&top_of_stack);
  2637. X    if (top_of_stack.v.int_val)    /* non-zero */
  2638. X        return(x->j_arg);        /* leave the argument on TOS */
  2639. X    else {
  2640. X        (void) pop(&a);
  2641. X        return 1;                /* no jump */
  2642. X    }
  2643. X}
  2644. X
  2645. X
  2646. Xint
  2647. Xf_jtern(x)
  2648. Xunion argument *x;
  2649. X{
  2650. Xstruct value a;
  2651. X
  2652. X    int_check(pop(&a));
  2653. X    if (a.v.int_val)
  2654. X        return(1);                /* no jump; fall through to TRUE code */
  2655. X    else
  2656. X        return(x->j_arg);        /* go jump to FALSE code */
  2657. X}
  2658. *-*-END-of-internal.c-*-*
  2659. exit
  2660.  
  2661.  
  2662.