home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume24 / gnuplot3 / part20 < prev    next >
Text File  |  1991-10-28  |  49KB  |  1,872 lines

  1. Newsgroups: comp.sources.misc
  2. From: gershon%gr@cs.utah.edu (Elber Gershon)
  3. Subject:  v24i042:  gnuplot3 - interactive function plotting utility, Part20/26
  4. Message-ID: <1991Oct29.030924.3984@sparky.imd.sterling.com>
  5. X-Md4-Signature: 8626dc11a59b66e8d5d5a2cf7da53f48
  6. Date: Tue, 29 Oct 1991 03:09:24 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: gershon%gr@cs.utah.edu (Elber Gershon)
  10. Posting-number: Volume 24, Issue 42
  11. Archive-name: gnuplot3/part20
  12. Environment: UNIX, MS-DOS, VMS
  13. Supersedes: gnuplot2: Volume 11, Issue 65-79
  14.  
  15. #!/bin/sh
  16. # this is Part.20 (part 20 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file gnuplot/term/apollo.trm continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 20; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping gnuplot/term/apollo.trm'
  34. else
  35. echo 'x - continuing file gnuplot/term/apollo.trm'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'gnuplot/term/apollo.trm' &&
  37. X
  38. X    Ray Lischner (uunet!mntgfx!lisch)
  39. X    4 October 1989    file created for GNUplot 1.1
  40. X    26 March 1990    updated for GNUplot 2.0
  41. */
  42. X
  43. #include <apollo/base.h>
  44. #include <apollo/error.h>
  45. #include <apollo/pad.h>
  46. #include <apollo/gpr.h>
  47. X
  48. /* default tick sizes for small windows */
  49. #define APOLLO_VTIC     6
  50. #define APOLLO_HTIC     6    
  51. X
  52. /* issue an error message, using additional text "s" */
  53. #define apollo_error(s)    error_$print_name(status, (s), strlen(s))
  54. X
  55. /* if "status" indicates an error, then issue an error message */
  56. #define apollo_check(s)    if (status.all != status_$ok) apollo_error(s)
  57. X
  58. static ios_$id_t stream = -1;           /* the stream for the pad */
  59. static gpr_$bitmap_desc_t screen_desc;  /* the screen's bitmap */
  60. static gpr_$bitmap_desc_t bitmap_desc;  /* the graphics bitmap */
  61. static gpr_$attribute_desc_t attr;      /* attribute block for saved bitmap */
  62. static short draw_width;                /* default GPR draw width */
  63. static name_$long_pname_t font_name;    /* font path name */
  64. static int APOLLO_XMAX, APOLLO_YMAX;    /* window size */
  65. static boolean use_bitmap;              /* use a separate bitmap? */
  66. X
  67. /* return whether stdout is a DM pad */
  68. apollo_isa_pad()
  69. {
  70. X    status_$t status;
  71. X    pad_$isa(1, &status);
  72. X    return (status.all == status_$ok);
  73. }
  74. X
  75. /*
  76. X    Find out what the default font is for the pad, and save the
  77. X    character height and width information.
  78. X
  79. X    Note that we must save the font file name because we need
  80. X    to reload the font file everytime the window changes size.
  81. */
  82. static void apollo_font_info(struct termentry* tbl, char* fname)
  83. {
  84. X    short fwidth, fheight, flen;
  85. X    status_$t status;
  86. X
  87. X    /* get the font size & update the termentry table */
  88. X    pad_$inq_font(stream, &fwidth, &fheight, fname, name_$long_pnamlen_max,
  89. X          &flen, &status);
  90. X    apollo_check("inq_font");
  91. X    fname[flen] = '\0';
  92. X
  93. X    tbl->v_char = fheight;
  94. X    tbl->h_char = fwidth;
  95. }
  96. X
  97. /*
  98. X    Initialize all the GPR stuff.  To save time, we draw into a separate
  99. X    bitmap, and then blt it onto the screen all at once.  This results
  100. X    in 5-10 times speed-up in the graphics, with only a little
  101. X    complication.  Most of the complication is right here, making sure
  102. X    we allocate the right bitmaps, etc., in the right order.  The rest
  103. X    is in APOLLO_text(), where we actually BLT the bitmap onto the screen.
  104. X    Everything else is the same.
  105. X
  106. X    The bitmaps have the same size as the window.  If the window changes
  107. X    size, then the bitmaps retain the same size, so the user sees part
  108. X    of the plot or a lot of space around the plot.  Drawing a new plot,
  109. X    or replotting the previous one causes APOLLO_graphics() to see if
  110. X    the window has changed size, in which case the GPR is terminated,
  111. X    and this routine is called again.  Thus, make sure any changes
  112. X    preserve this ability.  Anything that should only be done once
  113. X    to the pad should be handled by APOLLO_init().
  114. X
  115. X    By the way, we save the current draw width, to be used later
  116. X    for drawing extra wide lines.  This way we don't need to know
  117. X    anything about the current output device characteristics;
  118. X    we can just draw the default width, or twice the default width, etc.
  119. */
  120. static void apollo_gpr_init(struct termentry* tbl, pad_$window_desc_t* window)
  121. {
  122. X    gpr_$offset_t size;
  123. X    short fontid;
  124. X    status_$t status;
  125. X
  126. X    size.x_size = APOLLO_XMAX = tbl->xmax = window->width;
  127. X    size.y_size = APOLLO_YMAX = tbl->ymax = window->height;
  128. X
  129. X    /* now initialize GPR */
  130. X    gpr_$init(gpr_$frame, stream, size, 1, &screen_desc, &status);
  131. X    apollo_check("gpr_$init");
  132. X
  133. X    if (use_bitmap)
  134. X    {
  135. X    /* allocate the bitmap and its attribute block */
  136. X    gpr_$allocate_attribute_block(&attr, &status);
  137. X    apollo_check("allocate_attribute_block");
  138. X
  139. X    gpr_$allocate_bitmap(size, 1, attr, &bitmap_desc, &status);
  140. X    apollo_check("allocate_bitmap");
  141. X
  142. X    gpr_$set_bitmap(bitmap_desc, &status);
  143. X    apollo_check("set_bitmap");
  144. X    }
  145. X
  146. X    /* set the font file */
  147. X    gpr_$load_font_file(font_name, strlen(font_name), &fontid, &status);
  148. X    apollo_check(font_name);
  149. X
  150. X    gpr_$set_text_font(fontid, &status);
  151. X    apollo_check("set_text_font");
  152. X
  153. X    gpr_$inq_draw_width(&draw_width, &status);
  154. X    apollo_check("inq_draw_width");
  155. }
  156. X
  157. /*
  158. X    Determine the tick sizes to be used for labelling borders.
  159. X    By default, we use 1/50 of the window size, which looks nice to me.
  160. X    If this makes the ticks too small, however, we use a minimum
  161. X    size, to make sure they are visible.  The minimum size was also
  162. X    determined experimentally.
  163. X
  164. X    Feel free to changes the sizes to something you feel looks better.
  165. X
  166. X    This routine must be called after apollo_gpr_init(), because we
  167. X    need to know the window size, as stored in the termentry table.
  168. */
  169. static void apollo_tic_sizes(struct termentry* tbl)
  170. {
  171. X    /* base the tick size on the window size */
  172. X    tbl->v_tic = tbl->ymax / 50;
  173. X    if (tbl->v_tic < APOLLO_VTIC)
  174. X    tbl->v_tic = APOLLO_VTIC;
  175. X    tbl->h_tic = tbl->xmax / 50;
  176. X    if (tbl->v_tic < APOLLO_HTIC)
  177. X    tbl->v_tic = APOLLO_HTIC;
  178. }
  179. X
  180. /*
  181. X    Terminate the GPR.  This is called whenever the window size
  182. X    changes, and we need to reinitialize the GPR.  I assume that
  183. X    calling gpr_$terminate() also deallocates the bitmaps and
  184. X    attribute blocks because deallocating the screen's bitmap
  185. X    causes terminate() to think GPR has already been terminated.
  186. X
  187. X    Since this can be called many times, make sure nothing
  188. X    drastic is done here, like closing the stream to the pad.
  189. X    The only actions should be those that will be reinitialized
  190. X    by apollo_gpr_init().
  191. */
  192. static void apollo_gpr_terminate()
  193. {
  194. X    status_$t status;
  195. X
  196. X    gpr_$terminate(false, &status);
  197. X    apollo_check("terminate");
  198. }
  199. X
  200. /*
  201. X    Initialize the graphics.  This is called once, so we do things
  202. X    here that should be done exactly once, such as opening the window.
  203. X    I like to give windows names, so it is obvious what the window's
  204. X    contents are, but this causes a transcript to be kept in a file
  205. X    whose name is the window's name.  This might be nice in some
  206. X    circumstances, but to me it is a nuisance, so the file is
  207. X    deleted immediately.  The name is unlikely to appear normally,
  208. X    so there should be little interference with users' normal files.
  209. X    If the user has explicitly set the output file, however, then
  210. X    we use that name, and do not delete the file.  Thus, the
  211. X    user can get a metafile of the plot.  We can tell if the
  212. X    output file has been set because outstr is "STDOUT".  Otherwise,
  213. X    outstr is the filename, in single quotes.  We need to strip
  214. X    the quotes to make the file name.
  215. X
  216. X    The DM defaults are used for window sizes and positions.  If
  217. X    the user doesn't like it, he or she can change is and issue
  218. X    a replot command (assuming a plot has already been generated).
  219. X
  220. X    Note, also, that we must call pad_$set_scale() or else
  221. X    pad_$inq_windows() returns scaled values, which is not what
  222. X    we want.  Setting the scale to one (1) turns off the scaling,
  223. X    so we get real pixel sizes.
  224. X
  225. X    Finally, we get the name and size of the default font.  The
  226. X    name is kept, as explained earlier.  Then we can initialize
  227. X    the GPR stuff.
  228. X
  229. X    Note that there is a way that APOLLO_init() gets called more
  230. X    than once.  If the user issues the "set terminal apollo" command
  231. X    more than once, then this is called, so we need to make sure
  232. X    that we do not keep creating windows.
  233. X
  234. X    An alternative strategy would be to interpret multiple "set term
  235. X    apollo"s to mean create multiple windows.  The user could only
  236. X    access the most recent window because GNUplot has no concept of
  237. X    multiple terminals.  The user would, in fact, have no way of
  238. X    removing old windows because they are still active.  We could try
  239. X    catching keyboard events to see if the user presses EXIT, but I do
  240. X    not want to start getting into that mess.  If the user really
  241. X    wants this kind of functionality, then he or she can run gnuplot
  242. X    multiple times.  I think that is a lot cleaner, don't you?
  243. */
  244. APOLLO_init()
  245. {
  246. X    /* only initialize once */
  247. X    if (stream == -1)
  248. X    {
  249. X    extern char outstr[];
  250. X    struct termentry* tbl;
  251. X    pad_$window_desc_t window;
  252. X    name_$long_name_t wname;
  253. X    short wnum;            /* junk needed by pad_$inq_windows() */
  254. X    boolean unlink_wname;
  255. X    status_$t status;
  256. X
  257. X    tbl = &term_tbl[term];
  258. X
  259. X    /* make the window name unique, with "gnuplot" in the label */
  260. X    if (strcmp(outstr, "STDOUT") == 0)
  261. X    {
  262. X        sprintf(wname, "gnuplot-%d", getpid());
  263. X        unlink_wname = true;
  264. X    }
  265. X    else
  266. X    {
  267. X        /* strip the single quotes around the file name */
  268. X        strcpy(wname, outstr + 1);
  269. X        wname[strlen(wname) - 1] = '\0';
  270. X        unlink_wname = false;
  271. X    }
  272. X
  273. X    use_bitmap = unlink_wname;
  274. X
  275. X    /* use the default window position and size */
  276. X    window.top = window.left = window.width = window.height = 0;
  277. X    pad_$create_window(wname, strlen(wname), pad_$transcript, 1, window,
  278. X               &stream, &status);
  279. X    apollo_check("create_window");
  280. X
  281. X    /* if this is not the user's name, then delete the file */
  282. X    if (unlink_wname)
  283. X        unlink(wname);
  284. X
  285. X    /* remove all scaling, to revert to pixel units, not char. units */
  286. X    pad_$set_scale(stream, 1, 1, &status);
  287. X    apollo_check("set_scale");
  288. X
  289. X    /* get rid of the window when the program exits */
  290. X    pad_$set_auto_close(stream, 1, true, &status);
  291. X    apollo_check("set_auto_close");
  292. X
  293. X    /* now determine the window size & update the termentry table */
  294. X    pad_$inq_windows(stream, &window, 1, &wnum, &status);
  295. X    apollo_check("inq_windows");
  296. X
  297. X    /* the order of the next three calls is important */
  298. X    apollo_font_info(tbl, font_name);
  299. X    apollo_gpr_init(tbl, &window);
  300. X    apollo_tic_sizes(tbl);
  301. X    }
  302. }
  303. X
  304. /*
  305. X    Prepare for graphics output.  Since this is what the user wants to
  306. X    do when preparing a new plot, this is a meaningful time to see if
  307. X    the window has changed size.  Thus, we avoid mucking about with
  308. X    asynchronous traps, and we avoid the bigger problem of dealing
  309. X    with a half-finished plot when the window changes size.
  310. X
  311. X    Simply put, get the current window size, and if it has changed,
  312. X    then get rid of the old bitmaps, etc., and allocate new ones at
  313. X    the new size.  We also need to update the termentry table.
  314. X    If the window stays the same size, then just clear it.
  315. */
  316. static void apollo_redo_window(pad_$window_desc_t* window)
  317. {
  318. X    struct termentry* tbl = &term_tbl[term];
  319. X    status_$t status;
  320. X
  321. X    /* the order of the following calls is important */
  322. X    apollo_gpr_terminate();
  323. X    apollo_gpr_init(tbl, window);
  324. X    apollo_tic_sizes(tbl);
  325. }
  326. X
  327. APOLLO_graphics()
  328. {
  329. X    pad_$window_desc_t window;
  330. X    short wnum;
  331. X    status_$t status;
  332. X
  333. X    pad_$inq_windows(stream, &window, 1, &wnum, &status);
  334. X    apollo_check("inq_windows");
  335. X
  336. X    if (window.width != APOLLO_XMAX || window.height != APOLLO_YMAX)
  337. X    apollo_redo_window(&window);
  338. X    else
  339. X    {
  340. X    gpr_$clear(0, &status);
  341. X    apollo_check("clear");
  342. X    }
  343. }
  344. X
  345. /* set a line type:
  346. X   -2 heavy, solid    (border)
  347. X   -1 heavy, dotted    (axis)
  348. X   0  solid        (normal)
  349. X   1  dots        (other curves)
  350. X   2  short dash
  351. X   3  long dash
  352. X   4  dash dot
  353. X
  354. X   Apparently, GPUplot draws a lot of short line segments, and each
  355. X   one starts a new pattern.  This makes the patterns somewhat useless,
  356. X   but one can still tell the difference between solid, dotted, and
  357. X   dashed lines.  The utility of fancier styles is limited, however.
  358. X
  359. X   On a color workstation, we should use different colors, but I
  360. X   don't have one.
  361. */
  362. X
  363. /*
  364. X    To draw different line styles on an Apollo, we use two different
  365. X    parameters.  One is a line thickness, which is just an integral
  366. X    multiple of the default line thickness.  The second is a 16-bit
  367. X    pattern that is repeated.  We could use fancier patterns, since
  368. X    GPR supports up to 64-bits, but, as I explained earlier, this
  369. X    really does not buy us anything.
  370. X
  371. X    I used patterns that do not start with all bits on because
  372. X    GNUplot seems to use lots of short line segments to draw
  373. X    a curve, and this might make a very curvey plot seem like
  374. X    a solid line, regardless of pattern.  I don't want to start
  375. X    with too many zeros, however, or else the curve might not
  376. X    appear at all!  All the patterns, therefore, start with one
  377. X    bit on.  The rest of the bits determine the true pattern.
  378. X
  379. X    By examining graphics.c, we see that linetype -2 is used exclusively
  380. X    for the border, -1 for the axes, and the non-negative integers for
  381. X    the curves.  We use heavy lines for the border and axes, and normal
  382. X    width lines for the curves.
  383. X
  384. X    Since C arrays start at zero, make sure all the offsets are correct,
  385. X    so that it is easy to access the array with -2...n linetypes.
  386. */
  387. X
  388. typedef struct {
  389. X    short width;
  390. X    short pattern;
  391. } APOLLO_LINE;
  392. X
  393. static APOLLO_LINE apollo_lines[] = {
  394. X    { 2, ~0 },        /* heavy, solid */
  395. X    { 2, 0x6666 },    /* heavy, dotted */
  396. X    { 1, ~0 },        /* normal */
  397. X    { 1, 0xAAAA },    /* dotted */
  398. X    { 1, 0xC3C3 },    /* short dash */
  399. X    { 1, 0xE01F },    /* long dash */
  400. X    { 1, 0x87F8 },    /* dash dot */
  401. X    { 1, 0x6666 },    /* big dots */
  402. };
  403. X
  404. #define BITS_PER_LINETYPE    16
  405. X
  406. /* apollo_line(-2) is the border style, etc. */
  407. #define apollo_line(x)        apollo_lines[(x)+2]
  408. #define apollo_pattern(x)    &apollo_line(x).pattern
  409. #define apollo_width(x)        apollo_line(x).width
  410. X
  411. #define APOLLO_MIN_LINE        (-2)
  412. #define APOLLO_MAX_LINE        (sizeof(apollo_lines)/sizeof(*apollo_lines)-2)
  413. X
  414. /* set the line style */
  415. APOLLO_linetype(ltype)
  416. int ltype;
  417. {
  418. X    status_$t status;
  419. X
  420. X    if (ltype < APOLLO_MIN_LINE)
  421. X    ltype = APOLLO_MIN_LINE;
  422. X    if (ltype >= APOLLO_MAX_LINE)
  423. X    ltype %= APOLLO_MAX_LINE;
  424. X
  425. X    gpr_$set_line_pattern(1, apollo_pattern(ltype), BITS_PER_LINETYPE, &status);
  426. X    apollo_check("set_line_pattern");
  427. X
  428. X    gpr_$set_draw_width(draw_width * apollo_width(ltype), &status);
  429. X    apollo_check("set_draw_width");
  430. }
  431. X
  432. /* issue an error message that includes an (x, y) coordinate */
  433. static void apollo_xy_error(char* s, int x, int y, status_$t status)
  434. {
  435. X    char buffer[128];
  436. X
  437. X    sprintf(buffer, "%s(%d, %d)", s, x, y);
  438. X    apollo_error(buffer);
  439. }
  440. X
  441. #define apollo_xy_check(s)    \
  442. X    if (status.all != status_$ok) apollo_xy_error((s), x, y, status)
  443. X
  444. /*
  445. X    Note that GNUplot and GPR have reversed ideas of where the Y origin is.
  446. X    This means subtracting the Y coordinate from Y max.
  447. */
  448. #define plot_to_gpr(y)        (APOLLO_YMAX - (y))
  449. X
  450. /* move to a new position */
  451. APOLLO_move(unsigned int x, unsigned int y)
  452. {
  453. X    status_$t status;
  454. X
  455. X    gpr_$move((gpr_$coordinate_t) x, plot_to_gpr(y), &status);
  456. X    apollo_xy_check("move");
  457. }
  458. X
  459. /* draw a line to a new position */
  460. APOLLO_vector(unsigned int x, unsigned int y)
  461. {
  462. X    status_$t status;
  463. X
  464. X    gpr_$line((gpr_$coordinate_t) x, plot_to_gpr(y), &status);
  465. X    apollo_xy_check("line");
  466. }
  467. X
  468. /*
  469. X    On terminals, this switches to text mode.  The real meaning,
  470. X    however, is that the graphics are finished.  This means we can
  471. X    now display the saved bitmap.
  472. */
  473. APOLLO_text()
  474. {
  475. X    if (use_bitmap)
  476. X    {
  477. X    static gpr_$position_t pos;        /* always zero */
  478. X    gpr_$window_t window;
  479. X    status_$t status;
  480. X
  481. X    /* bitblt the entire bitmap to the entire window */
  482. X    window.window_base.x_coord = 0;
  483. X    window.window_base.y_coord = 0;
  484. X    window.window_size.x_size = APOLLO_XMAX;
  485. X    window.window_size.y_size = APOLLO_YMAX;
  486. X
  487. X    gpr_$set_bitmap(screen_desc, &status);
  488. X    apollo_check("set_bitmap(screen_desc)");
  489. X
  490. X    gpr_$pixel_blt(bitmap_desc, window, pos, &status);
  491. X    apollo_check("bitblt");
  492. X
  493. X    gpr_$set_bitmap(bitmap_desc, &status);
  494. X    apollo_check("set_bitmap(bitmap_desc)");
  495. X    }
  496. }
  497. X
  498. APOLLO_text_angle(ang)
  499. int ang;
  500. {
  501. X    status_$t status;
  502. X
  503. X    gpr_$set_text_path(ang ? gpr_$up : gpr_$right, &status);
  504. X    apollo_check("set_text_path");
  505. X    return TRUE;
  506. }
  507. X
  508. static enum JUSTIFY apollo_text_mode;
  509. X
  510. APOLLO_justify_text(mode)
  511. enum JUSTIFY mode;
  512. {
  513. X    apollo_text_mode = mode;
  514. X    return TRUE;
  515. }
  516. X
  517. /*
  518. X    Write "str" right justified on row "row".  A row is assumed to
  519. X    have whatever height the current text has.  Make sure the
  520. X    text does not cover the tick marks.
  521. */
  522. APOLLO_put_text(x, y, str)
  523. unsigned int x, y;
  524. char str[];
  525. {
  526. X    gpr_$offset_t size;
  527. X    status_$t status;
  528. X
  529. X    gpr_$inq_text_extent(str, strlen(str), &size, &status);
  530. X    apollo_check("inq_text_extent");
  531. X
  532. X    y -= size.y_size / 2;    /* center around "y" */
  533. X    switch (apollo_text_mode)
  534. X    {
  535. X    case LEFT:
  536. X    break;
  537. X    case CENTRE:
  538. X    x -= size.x_size / 2;
  539. X    break;
  540. X    case RIGHT:
  541. X    x -= size.x_size;
  542. X    break;
  543. X    }
  544. X    APOLLO_move(x, y);
  545. X
  546. X    gpr_$text(str, strlen(str), &status);
  547. X    apollo_check("put_text");
  548. }
  549. X
  550. /* reset the graphics state and terminate */
  551. APOLLO_reset()
  552. {
  553. X    if (stream != -1)
  554. X    {
  555. X    apollo_gpr_terminate();
  556. X    stream = -1;
  557. X    }
  558. }
  559. SHAR_EOF
  560. echo 'File gnuplot/term/apollo.trm is complete' &&
  561. chmod 0644 gnuplot/term/apollo.trm ||
  562. echo 'restore of gnuplot/term/apollo.trm failed'
  563. Wc_c="`wc -c < 'gnuplot/term/apollo.trm'`"
  564. test 17013 -eq "$Wc_c" ||
  565.     echo 'gnuplot/term/apollo.trm: original size 17013, current size' "$Wc_c"
  566. rm -f _shar_wnt_.tmp
  567. fi
  568. # ============= gnuplot/term/impcodes.h ==============
  569. if test -f 'gnuplot/term/impcodes.h' -a X"$1" != X"-c"; then
  570.     echo 'x - skipping gnuplot/term/impcodes.h (File already exists)'
  571.     rm -f _shar_wnt_.tmp
  572. else
  573. > _shar_wnt_.tmp
  574. echo 'x - extracting gnuplot/term/impcodes.h (Text)'
  575. sed 's/^X//' << 'SHAR_EOF' > 'gnuplot/term/impcodes.h' &&
  576. /*
  577. X * Copyright (c) 1985 Regents of the University of California.
  578. X * All rights reserved.  The Berkeley software License Agreement
  579. X * specifies the terms and conditions for redistribution.
  580. X *
  581. X *    @(#)imPcodes.h    5.1 (Berkeley) 9/21/85
  582. X */
  583. X
  584. #define    imP_SP    128
  585. #define    imP_SP1    129
  586. #define    imP_OLD_MMOVE    130
  587. #define    imP_MPLUS    131
  588. #define    imP_MMINUS    132
  589. #define    imP_MMOVE    133
  590. #define    imP_SMOVE    134
  591. X
  592. #define    imP_SET_ABS_H    135
  593. #define    imP_SET_REL_H    136
  594. #define    imP_SET_ABS_V    137
  595. #define    imP_SET_REL_V    138
  596. X
  597. #define    imP_SRULE    192
  598. #define    imP_BRULE    193
  599. X
  600. #define    imP_SET_HPOS    195
  601. #define    imP_SET_VPOS    196
  602. #define    imP_CRLF    197
  603. #define    imP_SGLY    198
  604. #define    imP_BGLY    199
  605. #define    imP_DELG    200
  606. #define    imP_DELC    201
  607. #define    imP_DELF    202
  608. X
  609. #define    imP_SET_HV_SYSTEM    205
  610. #define    imP_SET_ADV_DIRS    206
  611. #define    imP_SET_FAMILY    207
  612. #define    imP_SET_IL    208
  613. #define    imP_SET_BOL    209
  614. #define    imP_SET_SP    210
  615. #define    imP_PUSH    211
  616. #define    imP_POP    212
  617. #define    imP_PAGE    213
  618. #define    imP_SET_PUSH_MASK    214
  619. #define    imP_ENDPAGE    219
  620. X
  621. #define    imP_CREATE_FAMILY_TABLE    221
  622. #define    imP_CREATE_MAP    222
  623. X
  624. #define    imP_CREATE_PATH    230
  625. #define    imP_SET_TEXTURE    231
  626. #define    imP_SET_PEN    232
  627. #define    imP_FILL_PATH    233
  628. #define    imP_DRAW_PATH    234
  629. #define    imP_BITMAP    235
  630. #define    imP_SET_MAGN    236
  631. X
  632. #define    imP_EOF    255
  633. X
  634. X
  635. SHAR_EOF
  636. chmod 0666 gnuplot/term/impcodes.h ||
  637. echo 'restore of gnuplot/term/impcodes.h failed'
  638. Wc_c="`wc -c < 'gnuplot/term/impcodes.h'`"
  639. test 1260 -eq "$Wc_c" ||
  640.     echo 'gnuplot/term/impcodes.h: original size 1260, current size' "$Wc_c"
  641. rm -f _shar_wnt_.tmp
  642. fi
  643. # ============= gnuplot/parse.c ==============
  644. if test -f 'gnuplot/parse.c' -a X"$1" != X"-c"; then
  645.     echo 'x - skipping gnuplot/parse.c (File already exists)'
  646.     rm -f _shar_wnt_.tmp
  647. else
  648. > _shar_wnt_.tmp
  649. echo 'x - extracting gnuplot/parse.c (Text)'
  650. sed 's/^X//' << 'SHAR_EOF' > 'gnuplot/parse.c' &&
  651. /* GNUPLOT - parse.c */
  652. /*
  653. X * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  654. X *
  655. X * Permission to use, copy, and distribute this software and its
  656. X * documentation for any purpose with or without fee is hereby granted, 
  657. X * provided that the above copyright notice appear in all copies and 
  658. X * that both that copyright notice and this permission notice appear 
  659. X * in supporting documentation.
  660. X *
  661. X * Permission to modify the software is granted, but not the right to
  662. X * distribute the modified code.  Modifications are to be distributed 
  663. X * as patches to released version.
  664. X *  
  665. X * This software is provided "as is" without express or implied warranty.
  666. X * 
  667. X *
  668. X * AUTHORS
  669. X * 
  670. X *   Original Software:
  671. X *     Thomas Williams,  Colin Kelley.
  672. X * 
  673. X *   Gnuplot 2.0 additions:
  674. X *       Russell Lang, Dave Kotz, John Campbell.
  675. X *
  676. X *   Gnuplot 3.0 additions:
  677. X *       Gershon Elber and many others.
  678. X * 
  679. X * Send your comments or suggestions to 
  680. X *  pixar!info-gnuplot@sun.com.
  681. X * This is a mailing list; to join it send a note to 
  682. X *  pixar!info-gnuplot-request@sun.com.  
  683. X * Send bug reports to
  684. X *  pixar!bug-gnuplot@sun.com.
  685. X */
  686. X
  687. #include <stdio.h>
  688. #include <setjmp.h>
  689. #include <signal.h>
  690. #include <errno.h>
  691. #include <math.h>
  692. #include "plot.h"
  693. X
  694. #ifndef vms
  695. #ifndef __ZTC__
  696. extern int errno;
  697. #endif
  698. #endif
  699. X
  700. extern int num_tokens,c_token;
  701. extern struct lexical_unit token[];
  702. extern char c_dummy_var[MAX_NUM_VAR][MAX_ID_LEN+1];    /* name of current dummy vars */
  703. extern struct udft_entry *dummy_func;    /* pointer to dummy variable's func */
  704. X
  705. struct value *pop(),*integer(),*complex();
  706. struct at_type *temp_at(), *perm_at();
  707. struct udft_entry *add_udf();
  708. struct udvt_entry *add_udv();
  709. union argument *add_action();
  710. X
  711. struct at_type at;
  712. static jmp_buf fpe_env;
  713. X
  714. #define dummy (struct value *) 0
  715. X
  716. #ifdef __TURBOC__
  717. void fpe()
  718. #else
  719. #ifdef __ZTC__
  720. void fpe(an_int)
  721. int an_int;
  722. #else
  723. #ifdef _CRAY
  724. void fpe(an_int)
  725. int an_int;
  726. #else
  727. fpe()
  728. #endif
  729. #endif
  730. #endif
  731. {
  732. #ifdef PC    /* thanks to lotto@wjh12.UUCP for telling us about this  */
  733. X    _fpreset();
  734. #endif
  735. X    (void) signal(SIGFPE, fpe);
  736. X    undefined = TRUE;
  737. X    longjmp(fpe_env, TRUE);
  738. }
  739. X
  740. X
  741. #ifdef apollo
  742. #include <apollo/base.h>
  743. #include <apollo/pfm.h>
  744. #include <apollo/fault.h>
  745. X
  746. /*
  747. X  On an Apollo, the OS can signal a couple errors that are not mapped
  748. X  into SIGFPE, namely signalling NaN and branch on an unordered
  749. X  comparison.  I suppose there are others, but none of these are documented,
  750. X  so I handle them as they arise.
  751. X
  752. X  Anyway, we need to catch these faults and signal SIGFPE.
  753. */
  754. X
  755. pfm_$fh_func_val_t apollo_sigfpe(pfm_$fault_rec_t& fault_rec)
  756. {
  757. X    kill(getpid(), SIGFPE);
  758. X    return pfm_$continue_fault_handling;
  759. }
  760. X
  761. apollo_pfm_catch()
  762. {
  763. X    status_$t status;
  764. X    pfm_$establish_fault_handler(fault_$fp_bsun, pfm_$fh_backstop,
  765. X                 apollo_sigfpe, &status);
  766. X    pfm_$establish_fault_handler(fault_$fp_sig_nan, pfm_$fh_backstop,
  767. X                 apollo_sigfpe, &status);
  768. }
  769. #endif
  770. X
  771. X
  772. evaluate_at(at_ptr,val_ptr)
  773. struct at_type *at_ptr;
  774. struct value *val_ptr;
  775. {
  776. X    double temp, real();
  777. X
  778. X    undefined = FALSE;
  779. X    errno = 0;
  780. X    reset_stack();
  781. X    if (setjmp(fpe_env))
  782. X        return;                /* just bail out */
  783. X    (void) signal(SIGFPE, fpe);    /* catch core dumps on FPEs */
  784. X
  785. X    execute_at(at_ptr);
  786. X
  787. X    (void) signal(SIGFPE, SIG_DFL);
  788. X
  789. X    if (errno == EDOM || errno == ERANGE) {
  790. X        undefined = TRUE;
  791. X    } else {
  792. X        (void) pop(val_ptr);
  793. X        check_stack();
  794. X    }
  795. /* At least one machine (ATT 3b1) computes Inf without a SIGFPE */
  796. X    temp = real(val_ptr);
  797. X    if (temp > VERYLARGE || temp < -VERYLARGE) {
  798. X        undefined = TRUE;
  799. X    }
  800. }
  801. X
  802. X
  803. struct value *
  804. const_express(valptr)
  805. struct value *valptr;
  806. {
  807. register int tkn = c_token;
  808. X    if (END_OF_COMMAND)
  809. X        int_error("constant expression required",c_token);
  810. X    evaluate_at(temp_at(),valptr);    /* run it and send answer back */
  811. X    if (undefined) {
  812. X        int_error("undefined value",tkn);
  813. X    }
  814. X    return(valptr);
  815. }
  816. X
  817. X
  818. struct at_type *
  819. temp_at()    /* build a static action table and return its pointer */
  820. {
  821. X    at.a_count = 0;        /* reset action table !!! */
  822. X    express();
  823. X    return(&at);
  824. }
  825. X
  826. X
  827. /* build an action table, put it in dynamic memory, and return its pointer */
  828. X
  829. struct at_type *
  830. perm_at()
  831. {
  832. register struct at_type *at_ptr;
  833. register unsigned int len;
  834. X
  835. X    (void) temp_at();
  836. X    len = sizeof(struct at_type) -
  837. X        (MAX_AT_LEN - at.a_count)*sizeof(struct at_entry);
  838. X    at_ptr = (struct at_type *) alloc(len, "action table");
  839. X     (void) memcpy(at_ptr,&at,len);
  840. X    return(at_ptr);
  841. }
  842. X
  843. X
  844. #ifdef NOCOPY
  845. /*
  846. X * cheap and slow version of memcpy() in case you don't have one
  847. X */
  848. memcpy(dest,src,len)
  849. char *dest,*src;
  850. unsigned int len;
  851. {
  852. X    while (len--)
  853. X        *dest++ = *src++;
  854. }
  855. #endif /* NOCOPY */
  856. X
  857. X
  858. express()  /* full expressions */
  859. {
  860. X    xterm();
  861. X    xterms();
  862. }
  863. X
  864. xterm()  /* ? : expressions */
  865. {
  866. X    aterm();
  867. X    aterms();
  868. }
  869. X
  870. X
  871. aterm()
  872. {
  873. X    bterm();
  874. X    bterms();
  875. }
  876. X
  877. X
  878. bterm()
  879. {
  880. X    cterm();
  881. X    cterms();
  882. }
  883. X
  884. X
  885. cterm()
  886. {
  887. X    dterm();
  888. X    dterms();
  889. }
  890. X
  891. X
  892. dterm()
  893. {    
  894. X    eterm();
  895. X    eterms();
  896. }
  897. X
  898. X
  899. eterm()
  900. {
  901. X    fterm();
  902. X    fterms();
  903. }
  904. X
  905. X
  906. fterm()
  907. {
  908. X    gterm();
  909. X    gterms();
  910. }
  911. X
  912. X
  913. gterm()
  914. {
  915. X    hterm();
  916. X    hterms();
  917. }
  918. X
  919. X
  920. hterm()
  921. {
  922. X    unary(); /* - things */
  923. X    iterms(); /* * / % */
  924. }
  925. X
  926. X
  927. factor()
  928. {
  929. register int value;
  930. X
  931. X    if (equals(c_token,"(")) {
  932. X        c_token++;
  933. X        express();
  934. X        if (!equals(c_token,")"))
  935. X            int_error("')' expected",c_token);
  936. X        c_token++;
  937. X    }
  938. X    else if (isnumber(c_token)) {
  939. X        convert(&(add_action(PUSHC)->v_arg),c_token);
  940. X        c_token++;
  941. X    }
  942. X    else if (isletter(c_token)) {
  943. X        if ((c_token+1 < num_tokens)  && equals(c_token+1,"(")) {
  944. X            value = standard(c_token);
  945. X            if (value) {    /* it's a standard function */
  946. X                c_token += 2;
  947. X                express();
  948. X                if (!equals(c_token,")"))
  949. X                    int_error("')' expected",c_token);
  950. X                c_token++;
  951. X                (void) add_action(value);
  952. X            }
  953. X            else {
  954. X                int call_type = (int )CALL;
  955. X                value = c_token;
  956. X                c_token += 2;
  957. X                express();
  958. X                if (equals(c_token, ",")) {
  959. X                    c_token += 1;
  960. X                    express();
  961. X                    call_type = (int )CALL2;
  962. X                }
  963. X                if (!equals(c_token,")"))
  964. X                    int_error("')' expected",c_token);
  965. X                c_token++;
  966. X                add_action(call_type)->udf_arg = add_udf(value);
  967. X            }
  968. X        }
  969. X        else {
  970. X            if (equals(c_token,c_dummy_var[0])) {
  971. X                c_token++;
  972. X                add_action(PUSHD1)->udf_arg = dummy_func;
  973. X            }
  974. X            else if (equals(c_token,c_dummy_var[1])) {
  975. X                c_token++;
  976. X                add_action(PUSHD2)->udf_arg = dummy_func;
  977. X            }
  978. X            else {
  979. X                add_action(PUSH)->udv_arg = add_udv(c_token);
  980. X                c_token++;
  981. X            }
  982. X        }
  983. X    } /* end if letter */
  984. X    else
  985. X        int_error("invalid expression ",c_token);
  986. X
  987. X    /* add action code for ! (factorial) operator */
  988. X    while (equals(c_token,"!")) {
  989. X        c_token++;
  990. X        (void) add_action(FACTORIAL);
  991. X    }
  992. X    /* add action code for ** operator */
  993. X    if (equals(c_token,"**")) {
  994. X            c_token++;
  995. X            unary();
  996. X            (void) add_action(POWER);
  997. X    }
  998. X
  999. }
  1000. X
  1001. X
  1002. X
  1003. xterms()
  1004. {  /* create action code for ? : expressions */
  1005. X
  1006. X    if (equals(c_token,"?")) {
  1007. X        register int savepc1, savepc2;
  1008. X        register union argument *argptr1,*argptr2;
  1009. X        c_token++;
  1010. X        savepc1 = at.a_count;
  1011. X        argptr1 = add_action(JTERN);
  1012. X        express();
  1013. X        if (!equals(c_token,":"))
  1014. X            int_error("expecting ':'",c_token);
  1015. X        c_token++;
  1016. X        savepc2 = at.a_count;
  1017. X        argptr2 = add_action(JUMP);
  1018. X        argptr1->j_arg = at.a_count - savepc1;
  1019. X        express();
  1020. X        argptr2->j_arg = at.a_count - savepc2;
  1021. X    }
  1022. }
  1023. X
  1024. X
  1025. aterms()
  1026. {  /* create action codes for || operator */
  1027. X
  1028. X    while (equals(c_token,"||")) {
  1029. X        register int savepc;
  1030. X        register union argument *argptr;
  1031. X        c_token++;
  1032. X        savepc = at.a_count;
  1033. X        argptr = add_action(JUMPNZ);    /* short-circuit if already TRUE */
  1034. X        aterm();
  1035. X        argptr->j_arg = at.a_count - savepc;/* offset for jump */
  1036. #if defined(AMIGA_LC_5_1) || defined(AMIGA_AC_5)
  1037. X        (void) add_action(ABOOL);
  1038. #else
  1039. X        (void) add_action(BOOL);
  1040. #endif
  1041. X    }
  1042. }
  1043. X
  1044. X
  1045. bterms()
  1046. { /* create action code for && operator */
  1047. X
  1048. X    while (equals(c_token,"&&")) {
  1049. X        register int savepc;
  1050. X        register union argument *argptr;
  1051. X        c_token++;
  1052. X        savepc = at.a_count;
  1053. X        argptr = add_action(JUMPZ);    /* short-circuit if already FALSE */
  1054. X        bterm();
  1055. X        argptr->j_arg = at.a_count - savepc;/* offset for jump */
  1056. #if defined(AMIGA_LC_5_1) || defined(AMIGA_AC_5)
  1057. X        (void) add_action(ABOOL);
  1058. #else
  1059. X        (void) add_action(BOOL);
  1060. #endif
  1061. X    }
  1062. }
  1063. X
  1064. X
  1065. cterms()
  1066. { /* create action code for | operator */
  1067. X
  1068. X    while (equals(c_token,"|")) {
  1069. X        c_token++;
  1070. X        cterm();
  1071. X        (void) add_action(BOR);
  1072. X    }
  1073. }
  1074. X
  1075. X
  1076. dterms()
  1077. { /* create action code for ^ operator */
  1078. X
  1079. X    while (equals(c_token,"^")) {
  1080. X        c_token++;
  1081. X        dterm();
  1082. X        (void) add_action(XOR);
  1083. X    }
  1084. }
  1085. X
  1086. X
  1087. eterms()
  1088. { /* create action code for & operator */
  1089. X
  1090. X    while (equals(c_token,"&")) {
  1091. X        c_token++;
  1092. X        eterm();
  1093. X        (void) add_action(BAND);
  1094. X    }
  1095. }
  1096. X
  1097. X
  1098. fterms()
  1099. { /* create action codes for == and != operators */
  1100. X
  1101. X    while (TRUE) {
  1102. X        if (equals(c_token,"==")) {
  1103. X            c_token++;
  1104. X            fterm();
  1105. X            (void) add_action(EQ);
  1106. X        }
  1107. X        else if (equals(c_token,"!=")) {
  1108. X            c_token++;
  1109. X            fterm();
  1110. X            (void) add_action(NE);
  1111. X        }
  1112. X        else break;
  1113. X    }
  1114. }
  1115. X
  1116. X
  1117. gterms()
  1118. { /* create action code for < > >= or <= operators */
  1119. X    
  1120. X    while (TRUE) {
  1121. X        /* I hate "else if" statements */
  1122. X        if (equals(c_token,">")) {
  1123. X            c_token++;
  1124. X            gterm();
  1125. X            (void) add_action(GT);
  1126. X        }
  1127. X        else if (equals(c_token,"<")) {
  1128. X            c_token++;
  1129. X            gterm();
  1130. X            (void) add_action(LT);
  1131. X        }        
  1132. X        else if (equals(c_token,">=")) {
  1133. X            c_token++;
  1134. X            gterm();
  1135. X            (void) add_action(GE);
  1136. X        }
  1137. X        else if (equals(c_token,"<=")) {
  1138. X            c_token++;
  1139. X            gterm();
  1140. X            (void) add_action(LE);
  1141. X        }
  1142. X        else break;
  1143. X    }
  1144. X
  1145. }
  1146. X
  1147. X
  1148. X
  1149. hterms()
  1150. { /* create action codes for + and - operators */
  1151. X
  1152. X    while (TRUE) {
  1153. X            if (equals(c_token,"+")) {
  1154. X                c_token++;
  1155. X                hterm();
  1156. X                (void) add_action(PLUS);
  1157. X            }
  1158. X            else if (equals(c_token,"-")) {
  1159. X                c_token++;
  1160. X                hterm();
  1161. X                (void) add_action(MINUS);
  1162. X            }
  1163. X            else break;
  1164. X    }
  1165. }
  1166. X
  1167. X
  1168. iterms()
  1169. { /* add action code for * / and % operators */
  1170. X
  1171. X    while (TRUE) {
  1172. X            if (equals(c_token,"*")) {
  1173. X                c_token++;
  1174. X                unary();
  1175. X                (void) add_action(MULT);
  1176. X            }
  1177. X            else if (equals(c_token,"/")) {
  1178. X                c_token++;
  1179. X                unary();
  1180. X                (void) add_action(DIV);
  1181. X            }
  1182. X            else if (equals(c_token,"%")) {
  1183. X                c_token++;
  1184. X                unary();
  1185. X                (void) add_action(MOD);
  1186. X            }
  1187. X            else break;
  1188. X    }
  1189. }
  1190. X
  1191. X
  1192. unary()
  1193. { /* add code for unary operators */
  1194. X    if (equals(c_token,"!")) {
  1195. X        c_token++;
  1196. X        unary();
  1197. X        (void) add_action(LNOT);
  1198. X    }
  1199. X    else if (equals(c_token,"~")) {
  1200. X        c_token++;
  1201. X        unary();
  1202. X        (void) add_action(BNOT);
  1203. X    }
  1204. X    else if (equals(c_token,"-")) {
  1205. X        c_token++;
  1206. X        unary();
  1207. X        (void) add_action(UMINUS);
  1208. X    }
  1209. X    else
  1210. X        factor();
  1211. }
  1212. SHAR_EOF
  1213. chmod 0644 gnuplot/parse.c ||
  1214. echo 'restore of gnuplot/parse.c failed'
  1215. Wc_c="`wc -c < 'gnuplot/parse.c'`"
  1216. test 10144 -eq "$Wc_c" ||
  1217.     echo 'gnuplot/parse.c: original size 10144, current size' "$Wc_c"
  1218. rm -f _shar_wnt_.tmp
  1219. fi
  1220. # ============= gnuplot/makefile.msc ==============
  1221. if test -f 'gnuplot/makefile.msc' -a X"$1" != X"-c"; then
  1222.     echo 'x - skipping gnuplot/makefile.msc (File already exists)'
  1223.     rm -f _shar_wnt_.tmp
  1224. else
  1225. > _shar_wnt_.tmp
  1226. echo 'x - extracting gnuplot/makefile.msc (Text)'
  1227. sed 's/^X//' << 'SHAR_EOF' > 'gnuplot/makefile.msc' &&
  1228. # Make file for use with Microsoft C  Version 5.10
  1229. # and Microsoft Program Maintenance Utility  Version 4.07
  1230. X
  1231. # where to place gnuplot.gih helpfile
  1232. HELPFILE = gnuplot.gih
  1233. X
  1234. # /c  means don't link
  1235. # /AL means large memory model (large code, large data)
  1236. # /DPC means define symbol PC
  1237. CFLAGS = /c /AL /DPC #/DMSDOS #/Zi #/Od
  1238. X
  1239. # see other terminal defines in term.h
  1240. TERMFLAGS = 
  1241. X
  1242. # /NOE means NO EXTernal Dictionary
  1243. # /EX  means pack EXE file
  1244. # /ST:10000 means stack size 10000 bytes
  1245. LINKFLAGS = /NOE /EX /ST:10000 #/codeview 
  1246. X
  1247. OBJS =     bitmap.obj command.obj contour.obj eval.obj graphics.obj graph3d.obj \
  1248. X    help.obj internal.obj misc.obj parse.obj plot.obj readline.obj \
  1249. X    scanner.obj setshow.obj standard.obj term.obj util.obj version.obj \
  1250. X    pcgraph.obj hrcgraph.obj corgraph.obj
  1251. X
  1252. CSOURCE5 = term\aed.trm term\cgi.trm term/dumb.trm term/dxf.trm term\dxy.trm \
  1253. X    term\eepic.trm term\epson.trm term\fig.trm term\hp26.trm \
  1254. X    term\hp2648.trm term\hpgl.trm term\hpljii.trm 
  1255. CSOURCE6 = term\impcodes.h term\imagen.trm term\object.h \
  1256. X    term\iris4d.trm term\kyo.trm term\latex.trm term\pc.trm 
  1257. CSOURCE7 = term\post.trm term\qms.trm term\regis.trm term\sun.trm \
  1258. X    term\t410x.trm term\tek.trm term\unixpc.trm term\unixplot.trm \
  1259. X    term\v384.trm term\x11.trm
  1260. CSOURCE8 = contour.c
  1261. X
  1262. # default rules
  1263. .c.obj:
  1264. X    cl $(CFLAGS) $*.c
  1265. X
  1266. .asm.obj:
  1267. X    masm $*;
  1268. X
  1269. pcgraph.obj: pcgraph.asm header.mac lineproc.mac
  1270. X
  1271. corgraph.obj: corgraph.asm header.mac lineproc.mac
  1272. X
  1273. hrcgraph.obj: hrcgraph.asm header.mac lineproc.mac
  1274. X
  1275. bitmap.obj: bitmap.c bitmap.h plot.h
  1276. X
  1277. command.obj: command.c plot.h setshow.h help.h
  1278. X    cl $(CFLAGS) /DHELPFILE=\"$(HELPFILE)\" command.c
  1279. X
  1280. contour.obj: contour.c plot.h
  1281. X
  1282. eval.obj: eval.c plot.h
  1283. X
  1284. graphics.obj: graphics.c plot.h setshow.h
  1285. X
  1286. graph3d.obj: graphics.c plot.h setshow.h
  1287. X
  1288. help.obj: help.c plot.h help.h
  1289. X
  1290. internal.obj: internal.c plot.h
  1291. X
  1292. misc.obj: misc.c plot.h setshow.h
  1293. X
  1294. parse.obj: parse.c plot.h
  1295. X
  1296. plot.obj: plot.c plot.h setshow.h
  1297. X
  1298. readline.obj: readline.c
  1299. X
  1300. scanner.obj: scanner.c plot.h
  1301. X
  1302. setshow.obj: setshow.c plot.h setshow.h
  1303. X
  1304. standard.obj: standard.c plot.h
  1305. X
  1306. term.obj: term.c term.h plot.h setshow.h bitmap.h $(CSOURCE5) $(CSOURCE6) $(CSOURCE7)
  1307. X    cl $(CFLAGS) $(TERMFLAGS) /Iterm term.c
  1308. X
  1309. util.obj: util.c plot.h
  1310. X
  1311. version.obj: version.c
  1312. X
  1313. # convert gnuplot.doc to gnuplot.gih
  1314. doc2gih.exe: docs\doc2gih.c
  1315. X    cl docs\doc2gih.c
  1316. X
  1317. $(HELPFILE): doc2gih.exe docs\gnuplot.doc
  1318. X    doc2gih docs\gnuplot.doc $(HELPFILE)
  1319. X
  1320. # Object files in link command line are ordered to avoid far jumps.
  1321. # use linkopt.msc to avoid command-line overflow
  1322. X
  1323. gnuplot.exe: $(OBJS)
  1324. X link $(LINKFLAGS) @linkopt.msc
  1325. SHAR_EOF
  1326. chmod 0644 gnuplot/makefile.msc ||
  1327. echo 'restore of gnuplot/makefile.msc failed'
  1328. Wc_c="`wc -c < 'gnuplot/makefile.msc'`"
  1329. test 2572 -eq "$Wc_c" ||
  1330.     echo 'gnuplot/makefile.msc: original size 2572, current size' "$Wc_c"
  1331. rm -f _shar_wnt_.tmp
  1332. fi
  1333. # ============= gnuplot/copyright ==============
  1334. if test -f 'gnuplot/copyright' -a X"$1" != X"-c"; then
  1335.     echo 'x - skipping gnuplot/copyright (File already exists)'
  1336.     rm -f _shar_wnt_.tmp
  1337. else
  1338. > _shar_wnt_.tmp
  1339. echo 'x - extracting gnuplot/copyright (Text)'
  1340. sed 's/^X//' << 'SHAR_EOF' > 'gnuplot/copyright' &&
  1341. /*
  1342. X * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  1343. X *
  1344. X * Permission to use, copy, and distribute this software and its
  1345. X * documentation for any purpose with or without fee is hereby granted, 
  1346. X * provided that the above copyright notice appear in all copies and 
  1347. X * that both that copyright notice and this permission notice appear 
  1348. X * in supporting documentation.
  1349. X *
  1350. X * Permission to modify the software is granted, but not the right to
  1351. X * distribute the modified code.  Modifications are to be distributed 
  1352. X * as patches to released version.
  1353. X *  
  1354. X * This software is provided "as is" without express or implied warranty.
  1355. X * 
  1356. X *
  1357. X * AUTHORS
  1358. X * 
  1359. X *   Original Software:
  1360. X *     Thomas Williams,  Colin Kelley.
  1361. X * 
  1362. X *   Gnuplot 2.0 additions:
  1363. X *       Russell Lang, Dave Kotz, John Campbell.
  1364. X *
  1365. X *   Gnuplot 3.0 additions:
  1366. X *       Gershon Elber and many others.
  1367. X * 
  1368. X * Send your comments or suggestions to 
  1369. X *  pixar!info-gnuplot@sun.com.
  1370. X * This is a mailing list; to join it send a note to 
  1371. X *  pixar!info-gnuplot-request@sun.com.  
  1372. X * Send bug reports to
  1373. X *  pixar!bug-gnuplot@sun.com.
  1374. X */
  1375. SHAR_EOF
  1376. chmod 0644 gnuplot/copyright ||
  1377. echo 'restore of gnuplot/copyright failed'
  1378. Wc_c="`wc -c < 'gnuplot/copyright'`"
  1379. test 1114 -eq "$Wc_c" ||
  1380.     echo 'gnuplot/copyright: original size 1114, current size' "$Wc_c"
  1381. rm -f _shar_wnt_.tmp
  1382. fi
  1383. # ============= gnuplot/graph3d.c ==============
  1384. if test -f 'gnuplot/graph3d.c' -a X"$1" != X"-c"; then
  1385.     echo 'x - skipping gnuplot/graph3d.c (File already exists)'
  1386.     rm -f _shar_wnt_.tmp
  1387. else
  1388. > _shar_wnt_.tmp
  1389. echo 'x - extracting gnuplot/graph3d.c (Text)'
  1390. sed 's/^X//' << 'SHAR_EOF' > 'gnuplot/graph3d.c' &&
  1391. /* GNUPLOT - graph3d.c */
  1392. /*
  1393. X * Copyright (C) 1986, 1987, 1990, 1991   Thomas Williams, Colin Kelley
  1394. X *
  1395. X * Permission to use, copy, and distribute this software and its
  1396. X * documentation for any purpose with or without fee is hereby granted, 
  1397. X * provided that the above copyright notice appear in all copies and 
  1398. X * that both that copyright notice and this permission notice appear 
  1399. X * in supporting documentation.
  1400. X *
  1401. X * Permission to modify the software is granted, but not the right to
  1402. X * distribute the modified code.  Modifications are to be distributed 
  1403. X * as patches to released version.
  1404. X *
  1405. X * This software is provided "as is" without express or implied warranty.
  1406. X *
  1407. X *
  1408. X * AUTHORS
  1409. X *
  1410. X *   Original Software:
  1411. X *       Gershon Elber and many others.
  1412. X *
  1413. X * Send your comments or suggestions to 
  1414. X *  pixar!info-gnuplot@sun.com.
  1415. X * This is a mailing list; to join it send a note to 
  1416. X *  pixar!info-gnuplot-request@sun.com.  
  1417. X * Send bug reports to
  1418. X *  pixar!bug-gnuplot@sun.com.
  1419. X */
  1420. X
  1421. #include <stdio.h>
  1422. #include <math.h>
  1423. #include <assert.h>
  1424. #include <time.h>
  1425. #include "plot.h"
  1426. #include "setshow.h"
  1427. X
  1428. extern char *strcpy(),*strncpy(),*strcat(),*ctime(),*tdate;
  1429. #ifdef AMIGA_AC_5
  1430. extern time_t dated;
  1431. #else
  1432. #ifdef VMS
  1433. extern time_t dated,time();
  1434. #else
  1435. extern long dated,time();
  1436. #endif
  1437. #endif
  1438. X
  1439. static plot3d_impulses();
  1440. static plot3d_lines();
  1441. static plot3d_points();
  1442. static plot3d_dots();
  1443. static cntr3d_impulses();
  1444. static cntr3d_lines();
  1445. static cntr3d_points();
  1446. static cntr3d_dots();
  1447. static update_extrema_pts();
  1448. static draw_parametric_grid();
  1449. static draw_non_param_grid();
  1450. static draw_bottom_grid();
  1451. static draw_3dxtics();
  1452. static draw_3dytics();
  1453. static draw_3dztics();
  1454. static draw_series_3dxtics();
  1455. static draw_series_3dytics();
  1456. static draw_series_3dztics();
  1457. static draw_set_3dxtics();
  1458. static draw_set_3dytics();
  1459. static draw_set_3dztics();
  1460. static xtick();
  1461. static ytick();
  1462. static ztick();
  1463. X
  1464. #ifndef max        /* Lattice C has max() in math.h, but shouldn't! */
  1465. #define max(a,b) ((a > b) ? a : b)
  1466. #endif
  1467. X
  1468. #ifndef min
  1469. #define min(a,b) ((a < b) ? a : b)
  1470. #endif
  1471. X
  1472. #define inrange(z,min,max) ((min<max) ? ((z>=min)&&(z<=max)) : ((z>=max)&&(z<=min)) )
  1473. X
  1474. #define apx_eq(x,y) (fabs(x-y) < 0.001)
  1475. #define abs(x) ((x) >= 0 ? (x) : -(x))
  1476. #define sqr(x) ((x) * (x))
  1477. X
  1478. /* Define the boundary of the plot
  1479. X * These are computed at each call to do_plot, and are constant over
  1480. X * the period of one do_plot. They actually only change when the term
  1481. X * type changes and when the 'set size' factors change. 
  1482. X */
  1483. static int xleft, xright, ybot, ytop, xmiddle, ymiddle, xscaler, yscaler;
  1484. X
  1485. /* Boundary and scale factors, in user coordinates */
  1486. /* x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d are local to this
  1487. X * file and are not the same as variables of the same names in other files
  1488. X */
  1489. static double x_min3d, x_max3d, y_min3d, y_max3d, z_min3d, z_max3d;
  1490. static double xscale3d, yscale3d, zscale3d;
  1491. static double real_z_min3d, real_z_max3d;
  1492. static double min_sy_ox,min_sy_oy; /* obj. coords. for xy tics placement. */
  1493. static double min_sx_ox,min_sx_oy; /* obj. coords. for z tics placement. */
  1494. X
  1495. typedef double transform_matrix[4][4];
  1496. static transform_matrix trans_mat;
  1497. X
  1498. /* (DFK) Watch for cancellation error near zero on axes labels */
  1499. #define SIGNIF (0.01)        /* less than one hundredth of a tic mark */
  1500. #define CheckZero(x,tic) (fabs(x) < ((tic) * SIGNIF) ? 0.0 : (x))
  1501. #define NearlyEqual(x,y,tic) (fabs((x)-(y)) < ((tic) * SIGNIF))
  1502. X
  1503. /* And the functions to map from user to terminal coordinates */
  1504. #define map_x(x) (int)(x+0.5) /* maps floating point x to screen */ 
  1505. #define map_y(y) (int)(y+0.5)    /* same for y */
  1506. X
  1507. /* And the functions to map from user 3D space into normalized -1..1 */
  1508. #define map_x3d(x) ((x-x_min3d)*xscale3d-1.0)
  1509. #define map_y3d(y) ((y-y_min3d)*yscale3d-1.0)
  1510. #define map_z3d(z) ((z-z_min3d)*zscale3d-1.0)
  1511. X
  1512. static mat_unit(mat)
  1513. transform_matrix mat;
  1514. {
  1515. X    int i, j;
  1516. X
  1517. X    for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  1518. X    if (i == j)
  1519. X        mat[i][j] = 1.0;
  1520. X    else
  1521. X        mat[i][j] = 0.0;
  1522. }
  1523. X
  1524. static mat_trans(tx, ty, tz, mat)
  1525. double tx, ty, tz;
  1526. transform_matrix mat;
  1527. {
  1528. X     mat_unit(mat);                                 /* Make it unit matrix. */
  1529. X     mat[3][0] = tx;
  1530. X     mat[3][1] = ty;
  1531. X     mat[3][2] = tz;
  1532. }
  1533. X
  1534. static mat_scale(sx, sy, sz, mat)
  1535. double sx, sy, sz;
  1536. transform_matrix mat;
  1537. {
  1538. X     mat_unit(mat);                                 /* Make it unit matrix. */
  1539. X     mat[0][0] = sx;
  1540. X     mat[1][1] = sy;
  1541. X     mat[2][2] = sz;
  1542. }
  1543. X
  1544. static mat_rot_x(teta, mat)
  1545. double teta;
  1546. transform_matrix mat;
  1547. {
  1548. X    double cos_teta, sin_teta;
  1549. X
  1550. X    teta *= Pi / 180.0;
  1551. X    cos_teta = cos(teta);
  1552. X    sin_teta = sin(teta);
  1553. X
  1554. X    mat_unit(mat);                                  /* Make it unit matrix. */
  1555. X    mat[1][1] = cos_teta;
  1556. X    mat[1][2] = -sin_teta;
  1557. X    mat[2][1] = sin_teta;
  1558. X    mat[2][2] = cos_teta;
  1559. }
  1560. X
  1561. static mat_rot_y(teta, mat)
  1562. double teta;
  1563. transform_matrix mat;
  1564. {
  1565. X    double cos_teta, sin_teta;
  1566. X
  1567. X    teta *= Pi / 180.0;
  1568. X    cos_teta = cos(teta);
  1569. X    sin_teta = sin(teta);
  1570. X
  1571. X    mat_unit(mat);                                  /* Make it unit matrix. */
  1572. X    mat[0][0] = cos_teta;
  1573. X    mat[0][2] = -sin_teta;
  1574. X    mat[2][0] = sin_teta;
  1575. X    mat[2][2] = cos_teta;
  1576. }
  1577. X
  1578. static mat_rot_z(teta, mat)
  1579. double teta;
  1580. transform_matrix mat;
  1581. {
  1582. X    double cos_teta, sin_teta;
  1583. X
  1584. X    teta *= Pi / 180.0;
  1585. X    cos_teta = cos(teta);
  1586. X    sin_teta = sin(teta);
  1587. X
  1588. X    mat_unit(mat);                                  /* Make it unit matrix. */
  1589. X    mat[0][0] = cos_teta;
  1590. X    mat[0][1] = -sin_teta;
  1591. X    mat[1][0] = sin_teta;
  1592. X    mat[1][1] = cos_teta;
  1593. }
  1594. X
  1595. /* Multiply two transform_matrix. Result can be one of two operands. */
  1596. void mat_mult(mat_res, mat1, mat2)
  1597. transform_matrix mat_res, mat1, mat2;
  1598. {
  1599. X    int i, j, k;
  1600. X    transform_matrix mat_res_temp;
  1601. X
  1602. X    for (i = 0; i < 4; i++) for (j = 0; j < 4; j++) {
  1603. X        mat_res_temp[i][j] = 0;
  1604. X        for (k = 0; k < 4; k++) mat_res_temp[i][j] += mat1[i][k] * mat2[k][j];
  1605. X    }
  1606. X    for (i = 0; i < 4; i++) for (j = 0; j < 4; j++)
  1607. X    mat_res[i][j] = mat_res_temp[i][j];
  1608. }
  1609. X
  1610. /* And the functions to map from user 3D space to terminal coordinates */
  1611. static int map3d_xy(x, y, z, xt, yt)
  1612. double x, y, z;
  1613. int *xt, *yt;
  1614. {
  1615. X    int i,j;
  1616. X    double v[4], res[4],             /* Homogeneous coords. vectors. */
  1617. X    w = trans_mat[3][3];
  1618. X
  1619. X    v[0] = map_x3d(x); /* Normalize object space to -1..1 */
  1620. X    v[1] = map_y3d(y);
  1621. X    v[2] = map_z3d(z);
  1622. X    v[3] = 1.0;
  1623. X
  1624. X    for (i = 0; i < 2; i++) {                 /* Dont use the third axes (z). */
  1625. X        res[i] = trans_mat[3][i];     /* Initiate it with the weight factor. */
  1626. X        for (j = 0; j < 3; j++) res[i] += v[j] * trans_mat[j][i];
  1627. X    }
  1628. X
  1629. X    for (i = 0; i < 3; i++) w += v[i] * trans_mat[i][3];
  1630. X    if (w == 0) w = 1e-5;
  1631. X
  1632. X    *xt = ((int) (res[0] * xscaler / w)) + xmiddle;
  1633. X    *yt = ((int) (res[1] * yscaler / w)) + ymiddle;
  1634. }
  1635. X
  1636. /* Test a single point to be within the xleft,xright,ybot,ytop bbox.
  1637. X * Sets the returned integers 4 l.s.b. as follows:
  1638. X * bit 0 if to the left of xleft.
  1639. X * bit 1 if to the right of xright.
  1640. X * bit 2 if above of ytop.
  1641. X * bit 3 if below of ybot.
  1642. X * 0 is returned if inside.
  1643. X */
  1644. static int clip_point(x, y)
  1645. int x, y;
  1646. {
  1647. X    int ret_val = 0;
  1648. X
  1649. X    if (x < xleft) ret_val |= 0x01;
  1650. X    if (x > xright) ret_val |= 0x02;
  1651. X    if (y < ybot) ret_val |= 0x04;
  1652. X    if (y > ytop) ret_val |= 0x08;
  1653. X
  1654. X    return ret_val;
  1655. }
  1656. X
  1657. /* Clip the given line to drawing coords defined as xleft,xright,ybot,ytop.
  1658. X *   This routine uses the cohen & sutherland bit mapping for fast clipping -
  1659. X * see "Principles of Interactive Computer Graphics" Newman & Sproull page 65.
  1660. X */
  1661. static void draw_clip_line(x1, y1, x2, y2)
  1662. int x1, y1, x2, y2;
  1663. {
  1664. X    int x, y, dx, dy, x_intr[2], y_intr[2], count, pos1, pos2;
  1665. X    register struct termentry *t = &term_tbl[term];
  1666. X
  1667. X    pos1 = clip_point(x1, y1);
  1668. X    pos2 = clip_point(x2, y2);
  1669. X    if (pos1 || pos2) {
  1670. X    if (pos1 & pos2) return;          /* segment is totally out. */
  1671. X
  1672. X    /* Here part of the segment MAY be inside. test the intersection
  1673. X     * of this segment with the 4 boundaries for hopefully 2 intersections
  1674. X     * in. If non found segment is totaly out.
  1675. X     */
  1676. X    count = 0;
  1677. X    dx = x2 - x1;
  1678. X    dy = y2 - y1;
  1679. X
  1680. X    /* Find intersections with the x parallel bbox lines: */
  1681. X    if (dy != 0) {
  1682. X        x = (ybot - y2) * dx / dy + x2;        /* Test for ybot boundary. */
  1683. X        if (x >= xleft && x <= xright) {
  1684. X        x_intr[count] = x;
  1685. X        y_intr[count++] = ybot;
  1686. X        }
  1687. X        x = (ytop - y2) * dx / dy + x2;        /* Test for ytop boundary. */
  1688. X        if (x >= xleft && x <= xright) {
  1689. X        x_intr[count] = x;
  1690. X        y_intr[count++] = ytop;
  1691. X        }
  1692. X    }
  1693. X
  1694. X    /* Find intersections with the y parallel bbox lines: */
  1695. X    if (dx != 0) {
  1696. X        y = (xleft - x2) * dy / dx + y2;      /* Test for xleft boundary. */
  1697. X        if (y >= ybot && y <= ytop) {
  1698. X        x_intr[count] = xleft;
  1699. X        y_intr[count++] = y;
  1700. X        }
  1701. X        y = (xright - x2) * dy / dx + y2;    /* Test for xright boundary. */
  1702. X        if (y >= ybot && y <= ytop) {
  1703. X        x_intr[count] = xright;
  1704. X        y_intr[count++] = y;
  1705. X        }
  1706. X    }
  1707. X
  1708. X    if (count == 2) {
  1709. X        int x_max, x_min, y_max, y_min;
  1710. X
  1711. X        x_min = min(x1, x2);
  1712. X        x_max = max(x1, x2);
  1713. X        y_min = min(y1, y2);
  1714. X        y_max = max(y1, y2);
  1715. X
  1716. X        if (pos1 && pos2) {               /* Both were out - update both */
  1717. X        x1 = x_intr[0];
  1718. X        y1 = y_intr[0];
  1719. X        x2 = x_intr[1];
  1720. X        y2 = y_intr[1];
  1721. X        }
  1722. X        else if (pos1) {           /* Only x1/y1 was out - update only it */
  1723. X        if (dx * (x2 - x_intr[0]) + dy * (y2 - y_intr[0]) > 0) {
  1724. X            x1 = x_intr[0];
  1725. X            y1 = y_intr[0];
  1726. X        }
  1727. X        else {
  1728. X            x1 = x_intr[1];
  1729. X            y1 = y_intr[1];
  1730. X        }
  1731. X        }
  1732. X        else {                      /* Only x2/y2 was out - update only it */
  1733. X        if (dx * (x_intr[0] - x1) + dy * (y_intr[0] - x1) > 0) {
  1734. X            x2 = x_intr[0];
  1735. X            y2 = y_intr[0];
  1736. X        }
  1737. X        else {
  1738. X            x2 = x_intr[1];
  1739. X            y2 = y_intr[1];
  1740. X        }
  1741. X        }
  1742. X
  1743. X        if (x1 < x_min || x1 > x_max ||
  1744. X        x2 < x_min || x2 > x_max ||
  1745. X        y1 < y_min || y1 > y_max ||
  1746. X        y2 < y_min || y2 > y_max) return;
  1747. X    }
  1748. X    else
  1749. X        return;
  1750. X    }
  1751. X
  1752. X    (*t->move)(x1,y1);
  1753. X    (*t->vector)(x2,y2);
  1754. }
  1755. X
  1756. /* Two routine to emulate move/vector sequence using line drawing routine. */
  1757. static int move_pos_x, move_pos_y;
  1758. X
  1759. static void clip_move(x,y)
  1760. int x,y;
  1761. {
  1762. X    move_pos_x = x;
  1763. X    move_pos_y = y;
  1764. }
  1765. X
  1766. static void clip_vector(x,y)
  1767. int x,y;
  1768. {
  1769. X    draw_clip_line(move_pos_x,move_pos_y, x, y);
  1770. X    move_pos_x = x;
  1771. X    move_pos_y = y;
  1772. }
  1773. X
  1774. /* And text clipping routine. */
  1775. static void clip_put_text(x, y, str)
  1776. int x,y;
  1777. char *str;
  1778. {
  1779. X    register struct termentry *t = &term_tbl[term];
  1780. X
  1781. X    if (clip_point(x, y)) return;
  1782. X
  1783. X    (*t->put_text)(x,y,str);
  1784. }
  1785. X
  1786. /* (DFK) For some reason, the Sun386i compiler screws up with the CheckLog 
  1787. X * macro, so I write it as a function on that machine.
  1788. X */
  1789. #ifndef sun386
  1790. /* (DFK) Use 10^x if logscale is in effect, else x */
  1791. #define CheckLog(log, x) ((log) ? pow(10., (x)) : (x))
  1792. #else
  1793. static double
  1794. CheckLog(log, x)
  1795. X     BOOLEAN log;
  1796. X     double x;
  1797. {
  1798. X  if (log)
  1799. X    return(pow(10., x));
  1800. X  else
  1801. X    return(x);
  1802. }
  1803. #endif /* sun386 */
  1804. X
  1805. static double
  1806. LogScale(coord, islog, what, axis)
  1807. X    double coord;            /* the value */
  1808. X    BOOLEAN islog;            /* is this axis in logscale? */
  1809. X    char *what;            /* what is the coord for? */
  1810. X    char *axis;            /* which axis is this for ("x" or "y")? */
  1811. {
  1812. X    if (islog) {
  1813. X       if (coord <= 0.0) {
  1814. X          char errbuf[100];        /* place to write error message */
  1815. X        (void) sprintf(errbuf,"%s has %s coord of %g; must be above 0 for log scale!",
  1816. X                what, axis, coord);
  1817. X          (*term_tbl[term].text)();
  1818. X          (void) fflush(outfile);
  1819. X          int_error(errbuf, NO_CARET);
  1820. X       } else
  1821. X        return(log10(coord));
  1822. X    }
  1823. X    return(coord);
  1824. }
  1825. X
  1826. /* borders of plotting area */
  1827. /* computed once on every call to do_plot */
  1828. static boundary3d(scaling)
  1829. X    BOOLEAN scaling;        /* TRUE if terminal is doing the scaling */
  1830. {
  1831. X    register struct termentry *t = &term_tbl[term];
  1832. X    xleft = (t->h_char)*2 + (t->h_tic);
  1833. X    xright = (scaling ? 1 : xsize) * (t->xmax) - (t->h_char)*2 - (t->h_tic);
  1834. X    ybot = (t->v_char)*5/2 + 1;
  1835. X    ytop = (scaling ? 1 : ysize) * (t->ymax) - (t->v_char)*5/2 - 1;
  1836. X    xmiddle = (xright + xleft) / 2;
  1837. X    ymiddle = (ytop + ybot) / 2;
  1838. X    xscaler = (xright - xleft) / 2;
  1839. X    yscaler = (ytop - ybot) / 2;
  1840. }
  1841. X
  1842. static double dbl_raise(x,y)
  1843. double x;
  1844. int y;
  1845. {
  1846. register int i;
  1847. double val;
  1848. X
  1849. X    val = 1.0;
  1850. X    for (i=0; i < abs(y); i++)
  1851. X        val *= x;
  1852. X    if (y < 0 ) return (1.0/val);
  1853. X    return(val);
  1854. }
  1855. X
  1856. X
  1857. SHAR_EOF
  1858. true || echo 'restore of gnuplot/graph3d.c failed'
  1859. fi
  1860. echo 'End of  part 20'
  1861. echo 'File gnuplot/graph3d.c is continued in part 21'
  1862. echo 21 > _shar_seq_.tmp
  1863. exit 0
  1864.  
  1865. exit 0 # Just in case...
  1866. -- 
  1867. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1868. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1869. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1870. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1871.