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

  1. Newsgroups: comp.sources.misc
  2. From: gershon%gr@cs.utah.edu (Elber Gershon)
  3. Subject:  v24i035:  gnuplot3 - interactive function plotting utility, Part13/26
  4. Message-ID: <1991Oct28.002221.12268@sparky.imd.sterling.com>
  5. X-Md4-Signature: 93f50cac37b5b1fd89d0424c73f82ec2
  6. Date: Mon, 28 Oct 1991 00:22:21 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 35
  11. Archive-name: gnuplot3/part13
  12. Environment: UNIX, MS-DOS, VMS
  13. Supersedes: gnuplot2: Volume 11, Issue 65-79
  14.  
  15. #!/bin/sh
  16. # this is Part.13 (part 13 of a multipart archive)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file gnuplot/command.c 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" != 13; 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/command.c'
  34. else
  35. echo 'x - continuing file gnuplot/command.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'gnuplot/command.c' &&
  37. X        /* function ! */
  38. X        start_token = c_token;
  39. X        copy_str(c_dummy_var[0], c_token + 2);
  40. X        if(equals(c_token+3,",")) {
  41. X            copy_str(c_dummy_var[1], c_token + 4);
  42. X            c_token += 2;  /* skip the  , dummy2 */
  43. X        }
  44. X        c_token += 5; /* skip (, dummy, ) and = */
  45. X        if (END_OF_COMMAND)
  46. X            int_error("function definition expected",c_token);
  47. X        udf = dummy_func = add_udf(start_token);
  48. X        if (udf->at)                /* already a dynamic a.t. there */
  49. X            free((char *)udf->at);    /* so free it first */
  50. X        if ((udf->at = perm_at()) == (struct at_type *)NULL)
  51. X            int_error("not enough memory for function",start_token);
  52. X        m_capture(&(udf->definition),start_token,c_token-1);
  53. X    }
  54. X    else {
  55. X        /* variable ! */
  56. X        start_token = c_token;
  57. X        c_token +=2;
  58. X        udv = add_udv(start_token);
  59. X        (void) const_express(&(udv->udv_value));
  60. X        udv->udv_undef = FALSE;
  61. X    }
  62. }
  63. X
  64. X
  65. get_data(this_plot)
  66. struct curve_points *this_plot;
  67. {
  68. register int i, l_num, datum;
  69. register FILE *fp;
  70. float x, y;
  71. float ylow, yhigh;            /* for error bars */
  72. float temp;
  73. BOOLEAN yfirst;
  74. char format[MAX_LINE_LEN+1], data_file[MAX_LINE_LEN+1], line[MAX_LINE_LEN+1];
  75. char *float_format = "%f", *float_skip = "%*f";
  76. int xcol = 1, ycol = 2, yemin = 3, yemax = 4;
  77. struct value colvalue;
  78. #ifdef AMIGA_LC_5_1
  79. int num_perc_ast;
  80. char *start_search;
  81. #endif /* AMIGA_LC_5_1 */
  82. X
  83. X    quote_str(data_file, c_token);
  84. X    this_plot->plot_type = DATA;
  85. X    if ((fp = fopen(data_file, "r")) == (FILE *)NULL)
  86. X        os_error("can't open data file", c_token);
  87. X
  88. X    format[0] = '\0';
  89. X    yfirst = FALSE;
  90. X    c_token++;    /* skip data file name */
  91. X    if (almost_equals(c_token,"u$sing")) {
  92. X        c_token++;      /* skip "using" */
  93. X        if (!END_OF_COMMAND && !isstring(c_token)) {
  94. X            struct value a;
  95. X            ycol = (int)magnitude(const_express(&a));
  96. X            if (equals(c_token,":")) {
  97. X                c_token++;      /* skip ":" */
  98. X                xcol = ycol;
  99. X                ycol = (int)magnitude(const_express(&a));
  100. X                if (equals(c_token,":")) {
  101. X                    c_token++;      /* skip ":" */
  102. X                    yemin = (int)magnitude(const_express(&a));
  103. X                    if (equals(c_token,":")) {
  104. X                        c_token++;      /* skip ":" */
  105. X                        yemax = (int)magnitude(const_express(&a));
  106. X                    }
  107. X                    else
  108. X                            yemax = -1;
  109. X                }
  110. X                else {
  111. X                        yemin = -1;
  112. X                        yemax = -1;
  113. X                }
  114. X            }
  115. X            else {
  116. X                    yemin = -1;
  117. X                    yemax = -1;
  118. X            }
  119. X            if (xcol > ycol) yfirst = TRUE;
  120. X        }
  121. X        if (!END_OF_COMMAND && isstring(c_token)) {
  122. X            quotel_str(format, c_token);
  123. X            c_token++;    /* skip format */
  124. X        }
  125. X    }
  126. X    if (strlen(format) == 0) {
  127. X        for(i = 1; i <= ((xcol > ycol) ? xcol : ycol); i++)
  128. X            if ((i == xcol) || (i == ycol))
  129. X                (void) strcat(format,float_format);
  130. X            else
  131. X                (void) strcat(format,float_skip);
  132. X
  133. X        if (yemin > 0) {
  134. X            /* We have error bars - handle them. */
  135. X            yemin -= (xcol > ycol) ? xcol : ycol;
  136. X            yemax -= (xcol > ycol) ? xcol : ycol;
  137. X            if (yemin > yemax && yemax > 0) {
  138. X                i = yemin;
  139. X                yemin = yemax;
  140. X                yemax = i;
  141. X            }
  142. X
  143. X            if (yemin == yemax)
  144. X                int_error("Two error bar columns are the same",
  145. X                      NO_CARET);
  146. X
  147. X            if (yemin <= 0)
  148. X                int_error("Error bar columns must follow data columns",
  149. X                      NO_CARET);
  150. X
  151. X            for (i = 1; i < yemin; i++)
  152. X                (void) strcat(format,float_skip);
  153. X            (void) strcat(format,float_format);
  154. X
  155. X            if (yemax > 0) {
  156. X                for (i = 1; i < yemax - yemin; i++)
  157. X                    (void) strcat(format,float_skip);
  158. X                (void) strcat(format,float_format);
  159. X            }
  160. X        }
  161. X    }
  162. X
  163. X    l_num = 0;
  164. X     datum = 0;
  165. X    i = 0;
  166. #ifdef AMIGA_LC_5_1
  167. X    num_perc_ast = 0;
  168. X    start_search = format;
  169. X    while (*start_search != '\0') {
  170. X        if (start_search[0] == '%')
  171. X            if (start_search[1] == '*') num_perc_ast++;
  172. X        start_search++;
  173. X    }
  174. #endif /* AMIGA_LC_5_1 */
  175. X    while ( fgets(line, MAX_LINE_LEN, fp) != (char *)NULL ) {
  176. X        l_num++;
  177. X        if (is_comment(line[0]))
  178. X            continue;        /* ignore comments */
  179. X        if (i >= this_plot->p_max) {
  180. X            /* overflow about to occur. Extend size of points[]
  181. X            * array. We either double the size, or add 1000 points,
  182. X            * whichever is a smaller increment. Note i=p_max.
  183. X            */
  184. X            cp_extend(this_plot, i + (i < 1000 ? i : 1000));
  185. X        }
  186. X        if (!line[1]) { /* is it blank line ? */
  187. X            /* break in data, make next point undefined */
  188. X            this_plot->points[i].type = UNDEFINED;
  189. X            i++;
  190. X            continue;
  191. X        }
  192. X
  193. #ifdef AMIGA_LC_5_1
  194. X        switch (sscanf(line, format, &x, &y, &ylow, &yhigh) -
  195. X             num_perc_ast) {
  196. #else /* AMIGA_LC_5_1 */
  197. X        switch (sscanf(line, format, &x, &y, &ylow, &yhigh)) {
  198. #endif /* AMIGA_LC_5_1 */
  199. X            case 1: {        /* only one number on the line */
  200. X               y = x;        /* assign that number to y */
  201. X               x = datum;    /* and make the index into x */
  202. X               /* no break; !!! */
  203. X            }
  204. X            case 2: {
  205. X               if (yfirst) { /* exchange x and y */
  206. X                  temp = y;
  207. X                  y = x;
  208. X                  x = temp;
  209. X               }
  210. X               datum++;
  211. X
  212. X               /* ylow and yhigh are same as y */
  213. X               store2d_point(this_plot, i++, x, y, y, y);
  214. X               break;
  215. X            }
  216. X            case 3: {        /* x, y, ydelta */
  217. X               if (yfirst) { /* exchange x and y */
  218. X                  temp = y;
  219. X                  y = x;
  220. X                  x = temp;
  221. X               }
  222. X               datum++;
  223. X
  224. X               /* ydelta is in the ylow variable */
  225. X               store2d_point(this_plot, i++, x, y, y-ylow, y+ylow);
  226. X               break;
  227. X            }
  228. X            case 4: {        /* x, y, ylow, yhigh */
  229. X               if (yfirst) { /* exchange x and y */
  230. X                  temp = y;
  231. X                  y = x;
  232. X                  x = temp;
  233. X               }
  234. X               datum++;
  235. X
  236. X               store2d_point(this_plot, i++, x, y, ylow, yhigh);
  237. X               break;
  238. X            }
  239. X            default: {
  240. X               (void) sprintf(line, "bad data on line %d", l_num);
  241. X               int_error(line,c_token);
  242. X            }
  243. X        }
  244. X    }
  245. X    this_plot->p_count = i;
  246. X    cp_extend(this_plot, i);    /* shrink to fit */
  247. X    (void) fclose(fp);
  248. }
  249. X
  250. /* called by get_data for each point */
  251. store2d_point(this_plot, i, x, y, ylow, yhigh)
  252. struct curve_points *this_plot;
  253. int i;                    /* point number */
  254. #ifdef AMIGA_LC_5_1
  255. double x, y;
  256. double ylow, yhigh;
  257. #else
  258. float x, y;
  259. float ylow, yhigh;
  260. #endif
  261. {
  262. X    struct coordinate *cp = &(this_plot->points[i]);
  263. X
  264. X    /* the easy part: */
  265. X    cp->type = INRANGE;
  266. X    cp->x = x;
  267. X    cp->y = y;
  268. X    cp->ylow = ylow;
  269. X    cp->yhigh = yhigh;
  270. X    
  271. X    /* Adjust for log scale. */
  272. X    if (log_x)
  273. X     cp->type = adjustlog(cp->type, &(cp->x));
  274. X    if (log_y) {
  275. X       cp->type = adjustlog(cp->type, &(cp->y));
  276. X       /* Note ylow,yhigh can't affect cp->type. */
  277. X       (void)     adjustlog(cp->type, &(cp->ylow));
  278. X       (void)     adjustlog(cp->type, &(cp->yhigh));
  279. X    }
  280. X
  281. X    /* Now adjust the xrange, or declare the point out of range */
  282. X    /* The yrange is handled later, once we know whether to 
  283. X    * include ylow, yhigh in the calculation. See adjust_yrange()
  284. X    */
  285. X    if (cp->type == INRANGE)
  286. X     if (autoscale_lx || inrange(x,xmin,xmax)) {
  287. X        if (autoscale_lx) {
  288. X            if (x < xmin) xmin = x;
  289. X            if (x > xmax) xmax = x;
  290. X        }
  291. X     } else {
  292. X        cp->type = OUTRANGE;
  293. X     }
  294. }
  295. X
  296. /* Adjust for log scale:
  297. X * take the log of the second parameter, in place, if possible. 
  298. X * If not possible, return new type for point; if possible, then 
  299. X * return old type for point.
  300. X */
  301. static enum coord_type
  302. adjustlog(type, val)
  303. X    enum coord_type type;
  304. X    coordval *val;
  305. {
  306. X    if (*val < 0.0) {
  307. X       return(UNDEFINED);
  308. X    } else if (*val == 0.0) {
  309. X       *val = -VERYLARGE;
  310. X       return(OUTRANGE);
  311. X    } else {
  312. X       *val = log10(*val);
  313. X       return(type);
  314. X    }
  315. }
  316. X
  317. X
  318. /* now adjust the yrange, or declare the point out of range */
  319. /* this does all points in a curve */
  320. adjust_yrange(curve)
  321. X    struct curve_points *curve;
  322. {
  323. X    BOOLEAN ebars = (curve->plot_style == ERRORBARS);
  324. X    int npoints = curve->p_count; /* number of points */
  325. X    coordval y, ylow, yhigh;    /* one point value */
  326. X    struct coordinate *cp;    /* one coordinate */
  327. X    int i;                /* index into points */
  328. X
  329. X    for (i = 0; i < npoints; i++) {
  330. X       cp = &(curve->points[i]);
  331. X       if (cp->type == INRANGE) {
  332. X          y = cp->y;
  333. X          if ((autoscale_ly ||
  334. X               inrange(log_y ? pow(10.0, y) : y, ymin, ymax) ||
  335. X               polar)) {
  336. X             if (autoscale_ly) {
  337. X                if (y < ymin) ymin = y;
  338. X                if (y > ymax) ymax = y;
  339. X                if (ebars) {
  340. X                    ylow = cp->ylow;
  341. X                    yhigh = cp->yhigh;
  342. X                    if (ylow < ymin) ymin = ylow;
  343. X                    if (ylow > ymax) ymax = ylow;
  344. X                    if (yhigh < ymin) ymin = yhigh;
  345. X                    if (yhigh > ymax) ymax = yhigh;
  346. X                }
  347. X             }
  348. X          } else {
  349. X             cp->type = OUTRANGE;
  350. X          }
  351. X       }
  352. X    }
  353. }
  354. X
  355. X
  356. get_3ddata(this_plot)
  357. struct surface_points *this_plot;
  358. {
  359. register int i, j, l_num, xdatum, ydatum;
  360. register FILE *fp;
  361. float x, y, z;
  362. BOOLEAN only_z = FALSE;
  363. char format[MAX_LINE_LEN+1], data_file[MAX_LINE_LEN+1], line[MAX_LINE_LEN+1];
  364. char *float_format = "%f", *float_skip = "%*f";
  365. int xcol = 1, ycol = 2, zcol = 3, pt_in_iso_crv = 0, maxcol;
  366. enum XYZ_order_type {XYZ, YXZ, ZXY, XZY, ZYX, YZX, XY, YX} xyz_order;
  367. struct iso_curve *this_iso;
  368. #ifdef AMIGA_LC_5_1
  369. int num_perc_ast;
  370. char *start_search;
  371. #endif /* AMIGA_LC_5_1 */
  372. X        
  373. X    quote_str(data_file, c_token);
  374. X    this_plot->plot_type = DATA3D;
  375. X    this_plot->has_grid_topology = TRUE;
  376. X    if ((fp = fopen(data_file, "r")) == (FILE *)NULL)
  377. X        os_error("can't open data file", c_token);
  378. X
  379. X    format[0] = '\0';
  380. X    c_token++;    /* skip data file name */
  381. X    if (almost_equals(c_token,"u$sing")) {
  382. X        c_token++;      /* skip "using" */
  383. X        if (!END_OF_COMMAND && !isstring(c_token)) {
  384. X            struct value a;
  385. X            zcol = (int)magnitude(const_express(&a));
  386. X            only_z = TRUE;
  387. X            if (equals(c_token,":")) {
  388. X                c_token++;    /* skip ":" */
  389. X                only_z = FALSE;
  390. X                ycol = zcol;
  391. X                zcol = (int)magnitude(const_express(&a));
  392. X                if (equals(c_token,":")) {
  393. X                    c_token++;    /* skip ":" */
  394. X                    xcol = ycol;
  395. X                    ycol = zcol;
  396. X                    zcol = (int)magnitude(const_express(&a));
  397. X                }
  398. X                else {
  399. X                    if (mapping3d == MAP3D_CARTESIAN)
  400. X                        int_error("Must specify 1 or 3 columns",c_token);
  401. X                    xcol = ycol;
  402. X                    ycol = zcol;
  403. X                }
  404. X            }
  405. X            if (!only_z)
  406. X                if ( (xcol == ycol) || (ycol == zcol) || (xcol == zcol))
  407. X                    int_error("Columns must be distinct",c_token);
  408. X        }
  409. X        if (!END_OF_COMMAND && isstring(c_token)) {
  410. X            quotel_str(format, c_token);
  411. X            c_token++;    /* skip format */
  412. X        }
  413. X    }
  414. X
  415. X    switch (mapping3d) {
  416. X        case MAP3D_CARTESIAN:
  417. X        maxcol = (xcol > ycol) ? xcol : ycol;
  418. X        maxcol = (maxcol > zcol) ? maxcol : zcol;
  419. X        if (!only_z) {    /* Determine ordering of input columns */
  420. X             if (zcol == maxcol) {
  421. X                 if (xcol < ycol)
  422. X                     xyz_order = XYZ;  /* scanf(x,y,z) */
  423. X                 else
  424. X                     xyz_order = YXZ;  /* scanf(y,x,z) */
  425. X             }
  426. X             else if (ycol == maxcol) {
  427. X                 if (xcol < zcol)
  428. X                     xyz_order = XZY;  /* scanf(x,z,y) */
  429. X                 else
  430. X                     xyz_order = ZXY;  /* scanf(z,x,y) */
  431. X             }
  432. X             else {
  433. X                 if (ycol < zcol)
  434. X                     xyz_order = YZX;  /* scanf(y,z,x) */
  435. X                 else
  436. X                     xyz_order = ZYX;  /* scanf(z,y,x) */
  437. X             }
  438. X        }
  439. X        if (strlen(format) == 0) {
  440. X            if (only_z) {
  441. X                for(i = 1; i <= zcol; i++)
  442. X                    if (i == zcol)
  443. X                        (void) strcat(format,float_format);
  444. X                    else
  445. X                        (void) strcat(format,float_skip);
  446. X            }
  447. X            else {
  448. X                for(i = 1; i <= maxcol; i++)
  449. X                    if ((i == xcol) || (i == ycol) || (i == zcol))
  450. X                        (void) strcat(format,float_format);
  451. X                    else
  452. X                        (void) strcat(format,float_skip);
  453. X            }
  454. X        }
  455. X            break;
  456. X        case MAP3D_SPHERICAL:
  457. X        case MAP3D_CYLINDRICAL:
  458. X        if (only_z)
  459. X            int_error("Two columns for spherical/cylindrical coords.",c_token);
  460. X        maxcol = (xcol > ycol) ? xcol : ycol;
  461. X        xyz_order = (xcol < ycol) ? XY : YX;
  462. X        for(i = 1; i <= maxcol; i++)
  463. X            if ((i == xcol) || (i == ycol))
  464. X                (void) strcat(format,float_format);
  465. X            else
  466. X                (void) strcat(format,float_skip);
  467. X    }
  468. #ifdef AMIGA_LC_5_1
  469. X    num_perc_ast = 0;
  470. X    start_search = format;
  471. X    while (*start_search != '\0') {
  472. X        if (start_search[0] == '%')
  473. X            if (start_search[1] == '*') num_perc_ast++;
  474. X        start_search++;
  475. X    }
  476. #endif /* AMIGA_LC_5_1 */
  477. X
  478. X    l_num = 0;
  479. X    xdatum = 0;
  480. X    ydatum = 0;
  481. X    this_plot->num_iso_read = 0;
  482. X    this_plot->has_grid_topology = TRUE;
  483. X    if ( this_plot->iso_crvs != NULL ) {
  484. X        struct iso_curve *icrv, *icrvs = this_plot->iso_crvs;
  485. X
  486. X        while ( icrvs ) {
  487. X        icrv = icrvs;
  488. X        icrvs = icrvs->next;
  489. X        iso_free( icrv );
  490. X        }
  491. X        this_plot->iso_crvs = NULL;
  492. X    }
  493. X    this_iso = iso_alloc( samples );
  494. X
  495. X    while ( fgets(line, MAX_LINE_LEN, fp) != (char *)NULL ) {
  496. X        l_num++;
  497. X        if (is_comment(line[0]))
  498. X            continue;        /* ignore comments */
  499. X        if (!line[1]) {            /* is it blank line ? */
  500. X                if (pt_in_iso_crv == 0) {
  501. X                    if (xdatum == 0)
  502. X                    continue;
  503. X                    pt_in_iso_crv = xdatum;
  504. X            }
  505. X
  506. X            if (xdatum > 0) {
  507. X                this_iso->p_count = xdatum;
  508. X                this_iso->next = this_plot->iso_crvs;
  509. X                this_plot->iso_crvs = this_iso;
  510. X                this_plot->num_iso_read++;
  511. X
  512. X                if (xdatum != pt_in_iso_crv)
  513. X                    this_plot->has_grid_topology = FALSE;
  514. X
  515. X                this_iso = iso_alloc(pt_in_iso_crv);
  516. X                xdatum = 0;
  517. X                ydatum++;
  518. X            }
  519. X            continue;
  520. X        }
  521. X
  522. X        if (xdatum >= this_iso->p_max)
  523. X        {
  524. X            /* overflow about to occur. Extend size of points[]
  525. X            * array. We either double the size, or add 1000 points,
  526. X            * whichever is a smaller increment. Note i=p_max.
  527. X            */
  528. X            iso_extend(this_iso,
  529. X                   xdatum + (xdatum < 1000 ? xdatum : 1000));
  530. X        }
  531. X
  532. #ifdef AMIGA_LC_5_1
  533. X        switch (sscanf(line, format, &x, &y, &z) - num_perc_ast) {
  534. #else
  535. X        switch (sscanf(line, format, &x, &y, &z)) {
  536. #endif
  537. X            case 3:         /* All parameter are specified. */
  538. X               if (!only_z) {
  539. X                switch (xyz_order) {
  540. X                   case XYZ:    /* scanf(x,y,z) */
  541. X                    this_iso->points[xdatum].x = x;
  542. X                    this_iso->points[xdatum].y = y;
  543. X                    this_iso->points[xdatum].z = z;
  544. X                    break;
  545. X                   case XZY:    /* scanf(x,z,y) */
  546. X                    this_iso->points[xdatum].x = x;
  547. X                    this_iso->points[xdatum].y = z;
  548. X                    this_iso->points[xdatum].z = y;
  549. X                    break;
  550. X                   case YXZ:     /* scanf(y,x,z) */
  551. X                    this_iso->points[xdatum].x = y;
  552. X                    this_iso->points[xdatum].y = x;
  553. X                    this_iso->points[xdatum].z = z;
  554. X                    break;
  555. X                   case ZXY:    /* scanf(z,x,y) */
  556. X                    this_iso->points[xdatum].x = y;
  557. X                    this_iso->points[xdatum].y = z;
  558. X                    this_iso->points[xdatum].z = x;
  559. X                    break;
  560. X                   case YZX:    /* scanf(y,z,x) */
  561. X                    this_iso->points[xdatum].x = z;
  562. X                    this_iso->points[xdatum].y = x;
  563. X                    this_iso->points[xdatum].z = y;
  564. X                    break;
  565. X                   case ZYX:    /* scanf(z,y,x) */
  566. X                    this_iso->points[xdatum].x = z;
  567. X                    this_iso->points[xdatum].y = y;
  568. X                    this_iso->points[xdatum].z = x;
  569. X                    break;
  570. X                }
  571. X                if (xyz_order != XYZ) {
  572. X                    x = this_iso->points[xdatum].x;
  573. X                    y = this_iso->points[xdatum].y;
  574. X                    z = this_iso->points[xdatum].z;
  575. X                }
  576. X                if (!parametric)
  577. X                    int_error("Must be in parametric mode.",
  578. X                          NO_CARET);
  579. X                   break;
  580. X               }
  581. X            case 1:         /* only one number on the line */
  582. X               if (!only_z)
  583. X                int_error("3 columns expected, only 1 found", c_token);
  584. X               /* assign that number to z */
  585. X               this_iso->points[xdatum].z = x;
  586. X               z = x;
  587. X               this_iso->points[xdatum].x = xdatum;
  588. X               x = this_iso->points[xdatum].x;
  589. X               this_iso->points[xdatum].y = ydatum;
  590. X               y = this_iso->points[xdatum].y;
  591. X               if (parametric)
  592. X                int_error("Must be in non parametric mode.",
  593. X                      NO_CARET);
  594. X               break;
  595. X            case 2:
  596. X               switch (xyz_order) {
  597. X                   case YX:
  598. X                   z = x;    /* Use z as temp */
  599. X                   x = y;
  600. X                   y = z;
  601. X                   break;
  602. X                   default:
  603. X                   break;
  604. X               }
  605. X               switch (mapping3d) {
  606. X                   case MAP3D_CARTESIAN:
  607. X                       int_error("2 columns found, 3 expected",
  608. X                         c_token);
  609. X                   break;
  610. X                   case MAP3D_SPHERICAL:
  611. X                   if (angles_format == ANGLES_DEGREES) {
  612. X                       x *= DEG2RAD; /* Convert to radians. */
  613. X                       y *= DEG2RAD;
  614. X                   }
  615. X                   this_iso->points[xdatum].x = cos(x) * cos(y);
  616. X                   this_iso->points[xdatum].y = sin(x) * cos(y);
  617. X                   this_iso->points[xdatum].z = sin(y);
  618. X                   break;
  619. X                   case MAP3D_CYLINDRICAL:
  620. X                   if (angles_format == ANGLES_DEGREES)
  621. X                       x *= DEG2RAD; /* Convert to radians. */
  622. X                   this_iso->points[xdatum].x = cos(x);
  623. X                   this_iso->points[xdatum].y = sin(x);
  624. X                   this_iso->points[xdatum].z = y;
  625. X                   break;
  626. X               }
  627. X               x = this_iso->points[xdatum].x;
  628. X               y = this_iso->points[xdatum].y;
  629. X               z = this_iso->points[xdatum].z;
  630. X               break;
  631. X            default:
  632. X               (void) sprintf(line, "bad data on line %d", l_num);
  633. X               int_error(line,c_token);
  634. X        }
  635. X
  636. X        if (log_x) {
  637. X            if (x < 0.0)
  638. X            int_error("X value must be above 0 for log scale!",
  639. X                  NO_CARET);
  640. X            else
  641. X            this_iso->points[xdatum].x =
  642. X                log10(this_iso->points[xdatum].x);
  643. X        }
  644. X        if (log_y) {
  645. X            if (y < 0.0)
  646. X            int_error("Y value must be above 0 for log scale!",
  647. X                  NO_CARET);
  648. X            else
  649. X            this_iso->points[xdatum].y =
  650. X                log10(this_iso->points[xdatum].y);
  651. X        }
  652. X        if (log_z) {
  653. X            if (z < 0.0)
  654. X            int_error("Z value must be above 0 for log scale!",
  655. X                  NO_CARET);
  656. X            else
  657. X            this_iso->points[xdatum].z =
  658. X                log10(this_iso->points[xdatum].z);
  659. X        }
  660. X
  661. X        if (autoscale_lx) {
  662. X            if (x < xmin) xmin = x;
  663. X            if (x > xmax) xmax = x;
  664. X        }
  665. X        if (autoscale_ly) {
  666. X            if (y < ymin) ymin = y;
  667. X            if (y > ymax) ymax = y;
  668. X        }
  669. X        if (autoscale_lz) {
  670. X            if (z < zmin) zmin = z;
  671. X            if (z > zmax) zmax = z;
  672. X        }
  673. X
  674. X        xdatum++;
  675. X    }
  676. X
  677. X    if (xdatum > 0) {
  678. X        this_plot->num_iso_read++; /* Update last iso. */
  679. X        this_iso->p_count = xdatum;
  680. X
  681. X        this_iso->next = this_plot->iso_crvs; 
  682. X        this_plot->iso_crvs = this_iso;
  683. X
  684. X        if (xdatum != pt_in_iso_crv)
  685. X            this_plot->has_grid_topology = FALSE;
  686. X
  687. X    }
  688. X    else {
  689. X        iso_free(this_iso);/* Free last allocation. */
  690. X    }
  691. X
  692. X    (void) fclose(fp);
  693. X
  694. X    if (this_plot->has_grid_topology) {
  695. X            struct iso_curve *new_icrvs = NULL;
  696. X        int num_new_iso = this_plot->iso_crvs->p_count,
  697. X            len_new_iso = this_plot->num_iso_read;
  698. X
  699. X        /* Now we need to set the other direction (pseudo) isolines. */
  700. X            for (i = 0; i < num_new_iso; i++) {
  701. X            struct iso_curve *new_icrv = iso_alloc(len_new_iso);
  702. X
  703. X            new_icrv->p_count = len_new_iso;
  704. X
  705. X            for (j = 0, this_iso = this_plot->iso_crvs;
  706. X                 this_iso != NULL;
  707. X             j++, this_iso = this_iso->next) {
  708. X            new_icrv->points[j].x = this_iso->points[i].x;
  709. X                 new_icrv->points[j].y = this_iso->points[i].y;
  710. X                 new_icrv->points[j].z = this_iso->points[i].z;
  711. X            }
  712. X
  713. X            new_icrv->next = new_icrvs;
  714. X            new_icrvs = new_icrv;
  715. X        }
  716. X
  717. X        /* Append the new iso curves after the read ones. */
  718. X        for (this_iso = this_plot->iso_crvs;
  719. X             this_iso->next != NULL;
  720. X             this_iso = this_iso->next);
  721. X        this_iso->next = new_icrvs;
  722. X    }
  723. }
  724. X
  725. /* print_points:
  726. X * a debugging routine to print out the points of a curve,
  727. X * and the curve structure. If curve<0, then we print the 
  728. X * list of curves.
  729. X */
  730. static char *plot_type_names[4] = {
  731. X    "Function", "Data", "3D Function", "3d data"
  732. };
  733. static char *plot_style_names[6] = {
  734. X    "Lines", "Points", "Impulses", "LinesPoints", "Dots", "Errorbars"
  735. };
  736. X
  737. print_points(curve)
  738. X    int curve;            /* which curve to print */
  739. {
  740. X    register struct curve_points *this_plot;
  741. X    int i;
  742. X
  743. X    if (curve < 0) {
  744. X       for (this_plot = first_plot, i=0; 
  745. X           this_plot != NULL; 
  746. X           i++, this_plot = this_plot->next_cp) {
  747. X          printf("Curve %d:\n", i);
  748. X          if ((int)this_plot->plot_type >= 0 && (int)(this_plot->plot_type) < 4)
  749. X            printf("Plot type %d: %s\n", (int)(this_plot->plot_type),
  750. X                 plot_type_names[(int)(this_plot->plot_type)]);
  751. X          else
  752. X            printf("Plot type %d: BAD\n", (int)(this_plot->plot_type));
  753. X          if ((int)this_plot->plot_style >= 0 && (int)(this_plot->plot_style) < 6)
  754. X            printf("Plot style %d: %s\n", (int)(this_plot->plot_style),
  755. X                 plot_style_names[(int)(this_plot->plot_style)]);
  756. X          else
  757. X            printf("Plot style %d: BAD\n", (int)(this_plot->plot_style));
  758. X          printf("Plot title: '%s'\n", this_plot->title);
  759. X          printf("Line type %d\n", this_plot->line_type);
  760. X          printf("Point type %d\n", this_plot->point_type);
  761. X          printf("max points %d\n", this_plot->p_max);
  762. X          printf("current points %d\n", this_plot->p_count);
  763. X          printf("\n");
  764. X       }
  765. X    } else {
  766. X       for (this_plot = first_plot, i = 0; 
  767. X           i < curve && this_plot != NULL; 
  768. X           i++, this_plot = this_plot->next_cp)
  769. X        ;
  770. X       if (this_plot == NULL)
  771. X        printf("Curve %d does not exist; list has %d curves\n", curve, i);
  772. X       else {
  773. X          printf ("Curve %d, %d points\n", curve, this_plot->p_count);
  774. X          for (i = 0; i < this_plot->p_count; i++) {
  775. X             printf("%c x=%g y=%g z=%g ylow=%g yhigh=%g\n", 
  776. X                   this_plot->points[i].type == INRANGE ? 'i'
  777. X                   : this_plot->points[i].type == OUTRANGE ? 'o'
  778. X                   : 'u',
  779. X                   this_plot->points[i].x,
  780. X                   this_plot->points[i].y,
  781. X                   this_plot->points[i].z,
  782. X                   this_plot->points[i].ylow,
  783. X                   this_plot->points[i].yhigh);
  784. X          }
  785. X          printf("\n");
  786. X       }
  787. X    }    
  788. }
  789. X
  790. X
  791. /* This parses the plot command after any range specifications. 
  792. X * To support autoscaling on the x axis, we want any data files to 
  793. X * define the x range, then to plot any functions using that range. 
  794. X * We thus parse the input twice, once to pick up the data files, 
  795. X * and again to pick up the functions. Definitions are processed 
  796. X * twice, but that won't hurt.
  797. X */
  798. eval_plots()
  799. {
  800. register int i;
  801. register struct curve_points *this_plot, **tp_ptr;
  802. register int start_token, end_token;
  803. register int begin_token;
  804. double x_min, x_max, y_min, y_max;
  805. register double x, xdiff, temp;
  806. static struct value a;
  807. BOOLEAN ltmp, some_data_files = FALSE;
  808. int plot_num, line_num, point_num, xparam=0;
  809. char *xtitle;
  810. void parametric_fixup();
  811. X
  812. X    if (autoscale_ly) {
  813. X        ymin = VERYLARGE;
  814. X        ymax = -VERYLARGE;
  815. X    } else if (log_y && (ymin <= 0.0 || ymax <= 0.0))
  816. X            int_error("y range must be above 0 for log scale!",
  817. X                NO_CARET);
  818. X
  819. X    tp_ptr = &(first_plot);
  820. X    plot_num = 0;
  821. X    line_num = 0;     /* default line type */
  822. X    point_num = 0;    /* default point type */
  823. X
  824. X    xtitle = NULL;
  825. X
  826. X    begin_token = c_token;
  827. X
  828. /*** First Pass: Read through data files ***/
  829. /* This pass serves to set the xrange and to parse the command, as well 
  830. X * as filling in every thing except the function data. That is done after
  831. X * the xrange is defined.
  832. X */
  833. X    while (TRUE) {
  834. X        if (END_OF_COMMAND)
  835. X            int_error("function to plot expected",c_token);
  836. X
  837. X        start_token = c_token;
  838. X
  839. X        if (is_definition(c_token)) {
  840. X            define();
  841. X        } else {
  842. X            plot_num++;
  843. X
  844. X            if (isstring(c_token)) {            /* data file to plot */
  845. X                if (parametric && xparam) 
  846. X                    int_error("previous parametric function not fully specified",
  847. X                                                                    c_token);
  848. X
  849. X                if (!some_data_files && autoscale_lx) {
  850. X                    xmin = VERYLARGE;
  851. X                    xmax = -VERYLARGE;
  852. X                }
  853. X                some_data_files = TRUE;
  854. X
  855. X                if (*tp_ptr)
  856. X                  this_plot = *tp_ptr;
  857. X                else {        /* no memory malloc()'d there yet */
  858. X                    this_plot = cp_alloc(MIN_CRV_POINTS);
  859. X                    *tp_ptr = this_plot;
  860. X                }
  861. X                this_plot->plot_type = DATA;
  862. X                this_plot->plot_style = data_style;
  863. X                end_token = c_token;
  864. X                get_data(this_plot); /* this also parses the using option */
  865. X            } 
  866. X            else {                            /* function to plot */
  867. X                if (parametric)            /* working on x parametric function */
  868. X                    xparam = 1 - xparam;
  869. X                if (*tp_ptr) {
  870. X                    this_plot = *tp_ptr;
  871. X                    cp_extend(this_plot, samples+1);
  872. X                } else {        /* no memory malloc()'d there yet */
  873. X                    this_plot = cp_alloc(samples+1);
  874. X                    *tp_ptr = this_plot;
  875. X                }
  876. X                this_plot->plot_type = FUNC;
  877. X                this_plot->plot_style = func_style;
  878. X                dummy_func = &plot_func;
  879. X                plot_func.at = temp_at();
  880. X                /* ignore it for now */
  881. X                end_token = c_token-1;
  882. X            }
  883. X
  884. X            if (almost_equals(c_token,"t$itle")) {
  885. X                if (parametric) {
  886. X                    if (xparam) 
  887. X                        int_error(
  888. X        "\"title\" allowed only after parametric function fully specified",
  889. X                                                                    c_token);
  890. X                    else if (xtitle != NULL)
  891. X                        xtitle[0] = '\0';  /* Remove default title .*/
  892. X                }
  893. X                c_token++;
  894. X                if ( isstring( c_token ) ) {
  895. X                    m_quote_capture(&(this_plot->title),c_token,c_token);
  896. X                }
  897. X                else {
  898. X                    int_error("expecting \"title\" for plot",c_token);
  899. X                }
  900. X                c_token++;
  901. X            }
  902. X              else {
  903. X                  m_capture(&(this_plot->title),start_token,end_token);
  904. X                 if (xparam) xtitle = this_plot->title;
  905. X              }
  906. X  
  907. X              this_plot->line_type = line_num;
  908. X            this_plot->point_type = point_num;
  909. X
  910. X            if (almost_equals(c_token,"w$ith")) {
  911. X                if (parametric && xparam) 
  912. X                    int_error("\"with\" allowed only after parametric function fully specified",
  913. X                                    c_token);
  914. X                this_plot->plot_style = get_style();
  915. X            }
  916. X
  917. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  918. X                struct value t;
  919. X                this_plot->line_type = (int)real(const_express(&t))-1;
  920. X            }
  921. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  922. X                struct value t;
  923. X                this_plot->point_type = (int)real(const_express(&t))-1;
  924. X            }
  925. X            if ( (this_plot->plot_style == POINTS) ||
  926. X                 (this_plot->plot_style == LINESPOINTS) ||
  927. X                 (this_plot->plot_style == ERRORBARS) )
  928. X                    if (!xparam) point_num++;
  929. X            if (!xparam) line_num++;
  930. X
  931. X            if (this_plot->plot_type == DATA) 
  932. X              /* now that we know the plot style, adjust the yrange */
  933. X              adjust_yrange(this_plot);
  934. X
  935. X            tp_ptr = &(this_plot->next_cp);
  936. X        }
  937. X
  938. X        if (equals(c_token,",")) 
  939. X            c_token++;
  940. X        else  
  941. X            break;
  942. X    }
  943. X
  944. X    if (parametric && xparam) 
  945. X        int_error("parametric function not fully specified", NO_CARET);
  946. X
  947. X    if (parametric) {
  948. X    /* Swap t and x ranges for duration of these eval_plot computations. */
  949. X        ltmp = autoscale_lx; autoscale_lx = autoscale_lt; autoscale_lt = ltmp;
  950. X        temp = xmin; xmin = tmin; tmin = temp;
  951. X        temp = xmax; xmax = tmax; tmax = temp;
  952. X    }
  953. X
  954. /*** Second Pass: Evaluate the functions ***/
  955. /* Everything is defined now, except the function data. We expect
  956. X * no syntax errors, etc, since the above parsed it all. This makes 
  957. X * the code below simpler. If autoscale_ly, the yrange may still change.
  958. X */
  959. X     if (fabs(xmax-xmin) < zero)
  960. X      if (autoscale_lx) {
  961. X         fprintf(stderr, "Warning: empty %c range [%g:%g], ", 
  962. X            parametric ? 't' : 'x', xmin,xmax);
  963. X         if (fabs(xmin) < zero) {
  964. X            /* completely arbitary */
  965. X            xmin = -1.;
  966. X            xmax = 1.;
  967. X         } else {
  968. X            /* expand range by 10% in either direction */
  969. X            xmin = xmin * 0.9;
  970. X            xmax = xmax * 1.1;
  971. X         }
  972. X         fprintf(stderr, "adjusting to [%g:%g]\n", xmin,xmax);
  973. X      } else {
  974. X         int_error("x range is less than `zero`", c_token);
  975. X      }
  976. X
  977. X    /* give error if xrange badly set from missing datafile error */
  978. X    if (xmin == VERYLARGE || xmax == -VERYLARGE) {
  979. X        int_error("x range is invalid", c_token);
  980. X    }
  981. X
  982. X    if (log_x) {
  983. X       if (xmin <= 0.0 || xmax <= 0.0)
  984. X        int_error("x range must be greater than 0 for log scale!",NO_CARET);
  985. X       x_min = log10(xmin);
  986. X       x_max = log10(xmax);
  987. X    } else {
  988. X       x_min = xmin;
  989. X       x_max = xmax;
  990. X    }
  991. X
  992. X    xdiff = (x_max - x_min) / (samples - 1);
  993. X
  994. X    tp_ptr = &(first_plot);
  995. X    plot_num = 0;
  996. X    this_plot = first_plot;
  997. X    c_token = begin_token;    /* start over */
  998. X
  999. X    /* Read through functions */
  1000. X    while (TRUE) {
  1001. X        if (is_definition(c_token)) {
  1002. X            define();
  1003. X        } else {
  1004. X            plot_num++;
  1005. X            if (isstring(c_token)) {            /* data file to plot */
  1006. X                /* ignore this now */
  1007. X                c_token++;
  1008. X                if (almost_equals(c_token,"u$sing")) {
  1009. X                    c_token++;      /* skip "using" */
  1010. X                        if (!isstring(c_token)) {
  1011. X                        struct value a;
  1012. X                        (void)magnitude(const_express(&a)); /* skip xcol */
  1013. X                        if (equals(c_token,":")) {
  1014. X                            c_token++;      /* skip ":" */
  1015. X                            (void)magnitude(const_express(&a)); /* skip ycol */
  1016. X                        }
  1017. X                        if (equals(c_token,":")) {
  1018. X                            c_token++;      /* skip ":" */
  1019. X                            (void)magnitude(const_express(&a)); /* skip yemin */
  1020. X                        }
  1021. X                        if (equals(c_token,":")) {
  1022. X                            c_token++;      /* skip ":" */
  1023. X                            (void)magnitude(const_express(&a)); /* skip yemax */
  1024. X                        }
  1025. X                    }
  1026. X                    if (isstring(c_token))
  1027. X                        c_token++;      /* skip format string */
  1028. X                }
  1029. X            }
  1030. X            else {                    /* function to plot */
  1031. X                if (parametric)            /* working on x parametric function */
  1032. X                    xparam = 1 - xparam;
  1033. X                dummy_func = &plot_func;
  1034. X                plot_func.at = temp_at(); /* reparse function */
  1035. X
  1036. X                for (i = 0; i < samples; i++) {
  1037. X                    x = x_min + i*xdiff;
  1038. X                    /* if (log_x) PEM fix logscale x axis */
  1039. X                    /* x = pow(10.0,x); 26-Sep-89 */
  1040. X                    (void) complex(&plot_func.dummy_values[0],
  1041. X                                log_x ? pow(10.0,x) : x,
  1042. X                                0.0);
  1043. X
  1044. X                    evaluate_at(plot_func.at,&a);
  1045. X
  1046. X                    if (undefined || (fabs(imag(&a)) > zero)) {
  1047. X                       this_plot->points[i].type = UNDEFINED;
  1048. X                       continue;
  1049. X                    }
  1050. X
  1051. X                    temp = real(&a);
  1052. X
  1053. X                    if (log_y && temp < 0.0) {
  1054. X                       this_plot->points[i].type = UNDEFINED;
  1055. X                       continue;
  1056. X                    }
  1057. X
  1058. X                    this_plot->points[i].x = x;
  1059. X                    if (log_y) {
  1060. X                       if (temp == 0.0) {
  1061. X                          this_plot->points[i].type = OUTRANGE;
  1062. X                          this_plot->points[i].y = -VERYLARGE;
  1063. X                          continue;
  1064. X                       } else {
  1065. X                          this_plot->points[i].y = log10(temp);
  1066. X                       }
  1067. X                    } else
  1068. X                     this_plot->points[i].y = temp;
  1069. X
  1070. X                    if (autoscale_ly || polar
  1071. X                       || inrange(temp, ymin, ymax)) {
  1072. X                       this_plot->points[i].type = INRANGE;
  1073. X                    /* When xparam is 1 we are not really computing y's! */
  1074. X                        if (!xparam && autoscale_ly) {
  1075. X                           if (temp < ymin) ymin = temp;
  1076. X                           if (temp > ymax) ymax = temp;
  1077. X                        }
  1078. X                    } else
  1079. X                     this_plot->points[i].type = OUTRANGE;
  1080. X                }
  1081. X                this_plot->p_count = i; /* samples */
  1082. X             }
  1083. X
  1084. X            /* title was handled above */
  1085. X            if (almost_equals(c_token,"t$itle")) {
  1086. X                c_token++;
  1087. X                c_token++;
  1088. X            }
  1089. X
  1090. X            /* style was handled above */
  1091. X            if (almost_equals(c_token,"w$ith")) {
  1092. X                c_token++;
  1093. X                c_token++;
  1094. X            }
  1095. X
  1096. X            /* line and point types were handled above */
  1097. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1098. X                struct value t;
  1099. X                (void)real(const_express(&t));
  1100. X            }
  1101. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1102. X                struct value t;
  1103. X                (void)real(const_express(&t));
  1104. X            }
  1105. X
  1106. X             tp_ptr = &(this_plot->next_cp); /* used below */
  1107. X            this_plot = this_plot->next_cp;
  1108. X         }
  1109. X        
  1110. X        if (equals(c_token,",")) 
  1111. X          c_token++;
  1112. X        else  
  1113. X          break;
  1114. X     }
  1115. X
  1116. X    /* throw out all curve_points at end of list, that we don't need  */
  1117. X    cp_free(*tp_ptr);
  1118. X    *tp_ptr = NULL;
  1119. X
  1120. X    if (fabs(ymax - ymin) < zero)
  1121. X     /* if autoscale, widen range */
  1122. X     if (autoscale_ly) {
  1123. X        fprintf(stderr, "Warning: empty y range [%g:%g], ", ymin, ymax);
  1124. X        if (fabs(ymin) < zero) {
  1125. X            ymin = -1.;
  1126. X            ymax = 1.;
  1127. X        } else {
  1128. X            /* expand range by 10% in either direction */
  1129. X            ymin = ymin * 0.9;
  1130. X            ymax = ymax * 1.1;
  1131. X        }
  1132. X        fprintf(stderr, "adjusting to [%g:%g]\n", ymin, ymax);
  1133. X     } else {
  1134. X        int_error("y range is less than `zero`", c_token);
  1135. X     }
  1136. X
  1137. /* Now we finally know the real ymin and ymax */
  1138. X    if (log_y) {
  1139. X        y_min = log10(ymin);
  1140. X        y_max = log10(ymax);
  1141. X    } else {
  1142. X        y_min = ymin;
  1143. X        y_max = ymax;
  1144. X    }
  1145. X    capture(replot_line,plot_token,c_token);
  1146. X
  1147. X    if (parametric) {
  1148. X    /* Now put t and x ranges back before we actually plot anything. */
  1149. X        ltmp = autoscale_lx; autoscale_lx = autoscale_lt; autoscale_lt = ltmp;
  1150. X        temp = xmin; xmin = tmin; tmin = temp;
  1151. X        temp = xmax; xmax = tmax; tmax = temp;
  1152. X        if (some_data_files && autoscale_lx) {
  1153. X        /* 
  1154. X            Stop any further autoscaling in this case (may be a mistake, have
  1155. X              to consider what is really wanted some day in the future--jdc). 
  1156. X        */
  1157. X            autoscale_lx = 0;
  1158. X        }
  1159. X    /* Now actually fix the plot pairs to be single plots. */
  1160. X        parametric_fixup (first_plot, &plot_num, &x_min, &x_max);
  1161. X    }
  1162. X
  1163. X    do_plot(first_plot,plot_num,x_min,x_max,y_min,y_max);
  1164. X    cp_free(first_plot);
  1165. X    first_plot = NULL;
  1166. }
  1167. X
  1168. /* This parses the splot command after any range specifications. 
  1169. X * To support autoscaling on the x/z axis, we want any data files to 
  1170. X * define the x/y range, then to plot any functions using that range. 
  1171. X * We thus parse the input twice, once to pick up the data files, 
  1172. X * and again to pick up the functions. Definitions are processed 
  1173. X * twice, but that won't hurt.
  1174. X */
  1175. eval_3dplots()
  1176. {
  1177. register int i,j,k;
  1178. register struct surface_points *this_plot, **tp_3d_ptr;
  1179. register int start_token, end_token;
  1180. register int begin_token;
  1181. double x_min, x_max, y_min, y_max, z_min, z_max;
  1182. register double x, xdiff, xisodiff, y, ydiff, yisodiff, temp;
  1183. static struct value a;
  1184. BOOLEAN ltmp, some_data_files = FALSE;
  1185. int plot_num, line_num, point_num,
  1186. X    crnt_param = 0; /* 0=x, 1=y, 2=z */
  1187. char *xtitle;
  1188. char *ytitle;
  1189. void parametric_3dfixup();
  1190. X
  1191. X    if (autoscale_lz) {
  1192. X        zmin = VERYLARGE;
  1193. X        zmax = -VERYLARGE;
  1194. X    } else if (log_z && (zmin <= 0.0 || zmax <= 0.0))
  1195. X            int_error("z range must be above 0 for log scale!",
  1196. X                NO_CARET);
  1197. X
  1198. X    tp_3d_ptr = &(first_3dplot);
  1199. X    plot_num = 0;
  1200. X    line_num = 0;     /* default line type */
  1201. X    point_num = 0;    /* default point type */
  1202. X
  1203. X    xtitle = NULL;
  1204. X    ytitle = NULL;
  1205. X
  1206. X    begin_token = c_token;
  1207. X
  1208. /*** First Pass: Read through data files ***/
  1209. /* This pass serves to set the x/yranges and to parse the command, as well 
  1210. X * as filling in every thing except the function data. That is done after
  1211. X * the x/yrange is defined.
  1212. X */
  1213. X    while (TRUE) {
  1214. X        if (END_OF_COMMAND)
  1215. X            int_error("function to plt3d expected",c_token);
  1216. X
  1217. X        start_token = c_token;
  1218. X
  1219. X        if (is_definition(c_token)) {
  1220. X            define();
  1221. X        } else {
  1222. X            plot_num++;
  1223. X
  1224. X            if (isstring(c_token)) {            /* data file to plot */
  1225. X                if (parametric && crnt_param != 0)
  1226. X                    int_error("previous parametric function not fully specified",
  1227. X                                                                    c_token);
  1228. X
  1229. X                if (!some_data_files) {
  1230. X                    if (autoscale_lx) {
  1231. X                        xmin = VERYLARGE;
  1232. X                        xmax = -VERYLARGE;
  1233. X                    }
  1234. X                    if (autoscale_ly) {
  1235. X                        ymin = VERYLARGE;
  1236. X                        ymax = -VERYLARGE;
  1237. X                    }
  1238. X                }
  1239. X
  1240. X                some_data_files = TRUE;
  1241. X
  1242. X                if (*tp_3d_ptr)
  1243. X                    this_plot = *tp_3d_ptr;
  1244. X                else {    /* no memory malloc()'d there yet */
  1245. X                    /* Allocate samples * iso_samples twice for */
  1246. X                    /* Each of the isoparametric direction. */
  1247. X                    this_plot = sp_alloc(0,0);
  1248. X                    *tp_3d_ptr = this_plot;
  1249. X                }
  1250. X
  1251. X                this_plot->plot_type = DATA3D;
  1252. X                this_plot->plot_style = data_style;
  1253. X                end_token = c_token;
  1254. X                get_3ddata(this_plot); /* this also parses the using option */
  1255. X            } 
  1256. X            else {                        /* function to plot */
  1257. X                if (parametric) /* Rotate between x/y/z axes */
  1258. X                    crnt_param = (crnt_param+1) % 3;
  1259. X                if (*tp_3d_ptr) {
  1260. X                    this_plot = *tp_3d_ptr;
  1261. X                    sp_replace(this_plot,samples,2*iso_samples);
  1262. X                }
  1263. X                else {    /* no memory malloc()'d there yet */
  1264. X                    /* Allocate samples * iso_samples twice for */
  1265. X                    /* Each of the isoparametric direction. */
  1266. X                    this_plot = sp_alloc(samples,2*iso_samples);
  1267. X                    *tp_3d_ptr = this_plot;
  1268. X                }
  1269. X
  1270. X                this_plot->plot_type = FUNC3D;
  1271. X                this_plot->has_grid_topology = TRUE;
  1272. X                this_plot->plot_style = func_style;
  1273. X                dummy_func = &plot_func;
  1274. X                plot_func.at = temp_at();
  1275. X                /* ignore it for now */
  1276. X                end_token = c_token-1;
  1277. X            }
  1278. X
  1279. X            if (almost_equals(c_token,"t$itle")) {
  1280. X                if (parametric) {
  1281. X                        if (crnt_param)
  1282. X                        int_error(
  1283. X        "\"title\" allowed only after parametric function fully specified",
  1284. X                                                                    c_token);
  1285. X                    else {
  1286. X                        /* Remove default title */
  1287. X                        if (xtitle != NULL)
  1288. X                            xtitle[0] = '\0';
  1289. X                        if (ytitle != NULL)
  1290. X                            ytitle[0] = '\0';
  1291. X                    }
  1292. X                    }
  1293. X                c_token++;
  1294. X                if ( isstring( c_token ) ) {
  1295. X                    m_quote_capture(&(this_plot->title),c_token,c_token);
  1296. X                }
  1297. X                else {
  1298. X                    int_error("expecting \"title\" for plot",c_token);
  1299. X                }
  1300. X                c_token++;
  1301. X            }
  1302. X              else {
  1303. X                  m_capture(&(this_plot->title),start_token,end_token);
  1304. X                if (crnt_param == 1) xtitle = this_plot->title;
  1305. X                if (crnt_param == 2) ytitle = this_plot->title;
  1306. X              }
  1307. X  
  1308. X              this_plot->line_type = line_num;
  1309. X            this_plot->point_type = point_num;
  1310. X
  1311. X            if (almost_equals(c_token,"w$ith")) {
  1312. X                this_plot->plot_style = get_style();
  1313. X            }
  1314. X
  1315. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1316. X                struct value t;
  1317. X                this_plot->line_type = (int)real(const_express(&t))-1;
  1318. X            }
  1319. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1320. X                struct value t;
  1321. X                this_plot->point_type = (int)real(const_express(&t))-1;
  1322. X            }
  1323. X            if ( (this_plot->plot_style == POINTS) ||
  1324. X                 (this_plot->plot_style == LINESPOINTS) ||
  1325. X                 (this_plot->plot_style == ERRORBARS) )
  1326. X                    if (crnt_param == 0)
  1327. X                        point_num +=
  1328. X                            1 + (draw_contour != 0);
  1329. X            if (crnt_param == 0)
  1330. X                line_num += 1 + (draw_contour != 0);
  1331. X
  1332. X            tp_3d_ptr = &(this_plot->next_sp);
  1333. X        }
  1334. X
  1335. X        if (equals(c_token,",")) 
  1336. X            c_token++;
  1337. X        else  
  1338. X            break;
  1339. X    }
  1340. X
  1341. X    if (parametric && crnt_param != 0)
  1342. X        int_error("parametric function not fully specified", NO_CARET);
  1343. X
  1344. X    if (parametric) {
  1345. X    /* Swap u/v and x/y ranges for duration of these eval_plot computations. */
  1346. X        ltmp = autoscale_lx; autoscale_lx = autoscale_lu; autoscale_lu = ltmp;
  1347. X        ltmp = autoscale_ly; autoscale_ly = autoscale_lv; autoscale_lv = ltmp;
  1348. X        temp = xmin; xmin = umin; umin = temp;
  1349. X        temp = xmax; xmax = umax; umax = temp;
  1350. X        temp = ymin; ymin = vmin; vmin = temp;
  1351. X        temp = ymax; ymax = vmax; vmax = temp;
  1352. X    }
  1353. /*** Second Pass: Evaluate the functions ***/
  1354. /* Everything is defined now, except the function data. We expect
  1355. X * no syntax errors, etc, since the above parsed it all. This makes 
  1356. X * the code below simpler. If autoscale_ly, the yrange may still change.
  1357. X */
  1358. X     if (xmin == xmax)
  1359. X      if (autoscale_lx) {
  1360. X         fprintf(stderr, "Warning: empty x range [%g:%g], ", 
  1361. X             xmin,xmax);
  1362. X         if (xmin == 0.0) {
  1363. X            /* completely arbitary */
  1364. X            xmin = -1.;
  1365. X            xmax = 1.;
  1366. X         } else {
  1367. X            /* expand range by 10% in either direction */
  1368. X            xmin = xmin * 0.9;
  1369. X            xmax = xmax * 1.1;
  1370. X         }
  1371. X         fprintf(stderr, "adjusting to [%g:%g]\n", xmin,xmax);
  1372. X      } else {
  1373. X         int_error("x range is empty", c_token);
  1374. X      }
  1375. X
  1376. X     if (ymin == ymax)
  1377. X      if (autoscale_ly) {
  1378. X         fprintf(stderr, "Warning: empty y range [%g:%g], ", 
  1379. X            ymin,ymax);
  1380. X         if (ymin == 0.0) {
  1381. X            /* completely arbitary */
  1382. X            ymin = -1.;
  1383. X            ymax = 1.;
  1384. X         } else {
  1385. X            /* expand range by 10% in either direction */
  1386. X            ymin = ymin * 0.9;
  1387. X            ymax = ymax * 1.1;
  1388. X         }
  1389. X         fprintf(stderr, "adjusting to [%g:%g]\n", ymin,ymax);
  1390. X      } else {
  1391. X         int_error("y range is empty", c_token);
  1392. X      }
  1393. X
  1394. X    /* give error if xrange badly set from missing datafile error */
  1395. X    if (xmin == VERYLARGE || xmax == -VERYLARGE) {
  1396. X    int_error("x range is invalid", c_token);
  1397. X    }
  1398. X
  1399. X    if (log_x) {
  1400. X       if (xmin <= 0.0 || xmax <= 0.0)
  1401. X        int_error("x range must be greater than 0 for log scale!",NO_CARET);
  1402. X       x_min = log10(xmin);
  1403. X       x_max = log10(xmax);
  1404. X    } else {
  1405. X       x_min = xmin;
  1406. X       x_max = xmax;
  1407. X    }
  1408. X
  1409. X    if (log_y) {
  1410. X       if (ymin <= 0.0 || ymax <= 0.0)
  1411. X        int_error("y range must be greater than 0 for log scale!",NO_CARET);
  1412. X       y_min = log10(ymin);
  1413. X       y_max = log10(ymax);
  1414. X    } else {
  1415. X       y_min = ymin;
  1416. X       y_max = ymax;
  1417. X    }
  1418. X
  1419. X    if (samples < 2 || iso_samples < 2)
  1420. X    int_error("samples or iso_samples < 2. Must be at least 2.\n");
  1421. X
  1422. X    xdiff = (x_max - x_min) / (samples - 1);
  1423. X    ydiff = (y_max - y_min) / (samples - 1);
  1424. X    xisodiff = (x_max - x_min) / (iso_samples - 1);
  1425. X    yisodiff = (y_max - y_min) / (iso_samples - 1);
  1426. X
  1427. X    plot_num = 0;
  1428. X    this_plot = first_3dplot;
  1429. X    c_token = begin_token;    /* start over */
  1430. X
  1431. X    /* Read through functions */
  1432. X    while (TRUE) {
  1433. X        if (is_definition(c_token)) {
  1434. X            define();
  1435. X        } else {
  1436. X            plot_num++;
  1437. X            if (isstring(c_token)) {            /* data file to plot */
  1438. X                /* ignore this now */
  1439. X                c_token++;
  1440. X                if (almost_equals(c_token,"u$sing")) {
  1441. X                    c_token++;      /* skip "using" */
  1442. X                                if (!isstring(c_token)) {
  1443. X                        struct value a;
  1444. X                        (void)magnitude(const_express(&a));    /* skip xcol */
  1445. X                        if (equals(c_token,":")) {
  1446. X                            c_token++;    /* skip ":" */
  1447. X                            (void)magnitude(const_express(&a));    /* skip ycol */
  1448. X                            if (equals(c_token,":")) {
  1449. X                                c_token++;    /* skip ":" */
  1450. X                                (void)magnitude(const_express(&a));    /* skip zcol */
  1451. X                            }
  1452. X                        }
  1453. X                    }
  1454. X                                if (isstring(c_token))
  1455. X                        c_token++;    /* skip format string */
  1456. X                }
  1457. X            }
  1458. X            else {                    /* function to plot */
  1459. X                struct iso_curve *this_iso = this_plot->iso_crvs;
  1460. X                struct coordinate *points = this_iso->points;
  1461. X                
  1462. X                if (parametric)
  1463. X                    crnt_param = (crnt_param+1) % 3;
  1464. X                dummy_func = &plot_func;
  1465. X                plot_func.at = temp_at(); /* reparse function */
  1466. X
  1467. X                for (j = 0; j < iso_samples; j++) {
  1468. X                    y = y_min + j*yisodiff;
  1469. X                    /* if (log_y) PEM fix logscale y axis */
  1470. X                    /* y = pow(10.0,y); 26-Sep-89 */
  1471. X                    (void) complex(&plot_func.dummy_values[1],
  1472. X                                log_y ? pow(10.0,y) : y,
  1473. X                                0.0);
  1474. X
  1475. X                    for (i = 0; i < samples; i++) {
  1476. X                        x = x_min + i*xdiff;
  1477. X                        /* if (log_x) PEM fix logscale x axis */
  1478. X                        /* x = pow(10.0,x); 26-Sep-89 */
  1479. X                        (void) complex(&plot_func.dummy_values[0],
  1480. X                                log_x ? pow(10.0,x) : x,
  1481. X                                0.0);
  1482. X
  1483. X                        points[i].x = x;
  1484. X                        points[i].y = y;
  1485. X
  1486. X                        evaluate_at(plot_func.at,&a);
  1487. X
  1488. X                        if (undefined || (fabs(imag(&a)) > zero)) {
  1489. X                       points[i].type = UNDEFINED;
  1490. X                       continue;
  1491. X                        }
  1492. X
  1493. X                        temp = real(&a);
  1494. X
  1495. X                        if (log_z && temp < 0.0) {
  1496. X                       points[i].type = UNDEFINED;
  1497. X                       continue;
  1498. X                        }
  1499. X
  1500. X                        if (log_z) {
  1501. X                       if (temp == 0.0) {
  1502. X                          points[i].type = OUTRANGE;
  1503. X                          points[i].z = -VERYLARGE;
  1504. X                          continue;
  1505. X                       } else {
  1506. X                          points[i].z = log10(temp);
  1507. X                       }
  1508. X                        } else
  1509. X                       points[i].z = temp;
  1510. X
  1511. X                        if (autoscale_lz
  1512. X                       || inrange(temp, zmin, zmax)) {
  1513. X                       points[i].type = INRANGE;
  1514. X                       if (autoscale_lz) {
  1515. X                          if (temp < zmin) zmin = temp;
  1516. X                          if (temp > zmax) zmax = temp;
  1517. X                       }
  1518. X                        } else
  1519. X                       points[i].type = OUTRANGE;
  1520. X                    }
  1521. X                    this_iso->p_count = samples;
  1522. X                    this_iso = this_iso->next;
  1523. X                    points = this_iso->points;
  1524. X                }
  1525. X
  1526. X                for (i = 0; i < iso_samples; i++) {
  1527. X                    x = x_min + i*xisodiff;
  1528. X                    /* if (log_x) PEM fix logscale x axis */
  1529. X                    /* x = pow(10.0,x); 26-Sep-89 */
  1530. X                    (void) complex(&plot_func.dummy_values[0],
  1531. X                                log_x ? pow(10.0,x) : x,
  1532. X                                0.0);
  1533. X
  1534. X                    for (j = 0; j < samples; j++) {
  1535. X                        y = y_min + j*ydiff;
  1536. X                        /* if (log_y) PEM fix logscale y axis */
  1537. X                        /* y = pow(10.0,y); 26-Sep-89 */
  1538. X                        (void) complex(&plot_func.dummy_values[1],
  1539. X                                log_y ? pow(10.0,y) : y,
  1540. X                                0.0);
  1541. X
  1542. X                        points[j].x = x;
  1543. X                        points[j].y = y;
  1544. X
  1545. X                        evaluate_at(plot_func.at,&a);
  1546. X
  1547. X                        if (undefined || (fabs(imag(&a)) > zero)) {
  1548. X                       points[j].type = UNDEFINED;
  1549. X                       continue;
  1550. X                        }
  1551. X
  1552. X                        temp = real(&a);
  1553. X
  1554. X                        if (log_z && temp < 0.0) {
  1555. X                       points[j].type = UNDEFINED;
  1556. X                       continue;
  1557. X                        }
  1558. X
  1559. X                        if (log_z) {
  1560. X                       if (temp == 0.0) {
  1561. X                          points[j].type = OUTRANGE;
  1562. X                          points[j].z = -VERYLARGE;
  1563. X                          continue;
  1564. X                       } else {
  1565. X                          points[j].z = log10(temp);
  1566. X                       }
  1567. X                        } else
  1568. X                       points[j].z = temp;
  1569. X
  1570. X                        if (autoscale_lz
  1571. X                       || inrange(temp, zmin, zmax)) {
  1572. X                       points[j].type = INRANGE;
  1573. X                       if (autoscale_lz) {
  1574. X                          if (temp < zmin) zmin = temp;
  1575. X                          if (temp > zmax) zmax = temp;
  1576. X                       }
  1577. X                        } else
  1578. X                       points[j].type = OUTRANGE;
  1579. X                    }
  1580. X                        this_iso->p_count = samples;
  1581. X                    this_iso = this_iso->next;
  1582. X                    points = this_iso ? this_iso->points : NULL;
  1583. X                }
  1584. X             }
  1585. X
  1586. X            /* title was handled above */
  1587. X            if (almost_equals(c_token,"t$itle")) {
  1588. X                c_token++;
  1589. X                c_token++;
  1590. X            }
  1591. X
  1592. X            /* style was handled above */
  1593. X            if (almost_equals(c_token,"w$ith")) {
  1594. X                c_token++;
  1595. X                c_token++;
  1596. X            }
  1597. X
  1598. X            /* line and point types were handled above */
  1599. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1600. X                struct value t;
  1601. X                (void)real(const_express(&t));
  1602. X            }
  1603. X            if ( !equals(c_token,",") && !END_OF_COMMAND ) {
  1604. X                struct value t;
  1605. X                (void)real(const_express(&t));
  1606. X            }
  1607. X
  1608. X            this_plot = this_plot->next_sp;
  1609. X         }
  1610. X
  1611. X        if (equals(c_token,","))
  1612. X          c_token++;
  1613. X        else
  1614. X          break;
  1615. X     }
  1616. X
  1617. X    if (fabs(zmax - zmin) < zero)
  1618. X     /* if autoscale, widen range */
  1619. X     if (autoscale_lz) {
  1620. X        fprintf(stderr, "Warning: empty z range [%g:%g], ", zmin, zmax);
  1621. X        if (fabs(zmin) < zero ) {
  1622. X            zmin = -1.;
  1623. X            zmax = 1.;
  1624. X        } else {
  1625. X            /* expand range by 10% in either direction */
  1626. X            zmin = zmin * 0.9;
  1627. X            zmax = zmax * 1.1;
  1628. X        }
  1629. X        fprintf(stderr, "adjusting to [%g:%g]\n", zmin, zmax);
  1630. X     } else {
  1631. X        int_error("z range is less than `zero`", c_token);
  1632. X     }
  1633. X
  1634. /* Now we finally know the real zmin and zmax */
  1635. X    if (log_z) {
  1636. X        if (zmin <= 0.0 || zmax <= 0.0)
  1637. X            int_error("z range must be greater than 0 for log scale!",NO_CARET);
  1638. X        z_min = log10(zmin);
  1639. X        z_max = log10(zmax);
  1640. X    } else {
  1641. X        z_min = zmin;
  1642. X        z_max = zmax;
  1643. X    }
  1644. X    capture(replot_line,plot_token,c_token);
  1645. X
  1646. X    if (parametric) {
  1647. X    /* Now put u/v and x/y ranges back before we actually plot anything. */
  1648. X        ltmp = autoscale_lx; autoscale_lx = autoscale_lu; autoscale_lu = ltmp;
  1649. X        ltmp = autoscale_ly; autoscale_ly = autoscale_lv; autoscale_lv = ltmp;
  1650. X        temp = xmin; xmin = umin; umin = temp;
  1651. X        temp = xmax; xmax = umax; umax = temp;
  1652. X        temp = ymin; ymin = vmin; vmin = temp;
  1653. X        temp = ymax; ymax = vmax; vmax = temp;
  1654. X
  1655. X    /* Now actually fix the plot triplets to be single plots. */
  1656. X        parametric_3dfixup(first_3dplot, &plot_num,
  1657. X                   &x_min, &x_max, &y_min, &y_max,
  1658. X                   &z_min, &z_max);
  1659. X        if (log_x) {
  1660. X            if (x_min <= 0.0 || x_max <= 0.0)
  1661. X                int_error("x range must be greater than 0 for log scale!",NO_CARET);
  1662. X            x_min = log10(x_min);
  1663. X            x_max = log10(x_max);
  1664. X        }
  1665. X
  1666. X        if (log_y) {
  1667. X            if (y_min <= 0.0 || y_max <= 0.0)
  1668. X                int_error("y range must be greater than 0 for log scale!",NO_CARET);
  1669. X            y_min = log10(y_min);
  1670. X            y_max = log10(y_max);
  1671. X        }
  1672. X
  1673. X        if (log_z) {
  1674. X            if (z_min <= 0.0 || z_max <= 0.0)
  1675. X                int_error("z range must be greater than 0 for log scale!",NO_CARET);
  1676. X            z_min = log10(z_min);
  1677. X            z_max = log10(z_max);
  1678. X        }
  1679. X    }
  1680. X
  1681. X
  1682. X    /* Creates contours if contours are to be plotted as well. */
  1683. X    if (draw_contour) {
  1684. X        for (this_plot=first_3dplot, i=0;
  1685. X             i < plot_num;
  1686. X             this_plot=this_plot->next_sp, i++) {
  1687. X            if (this_plot->contours) {
  1688. X                struct gnuplot_contours *cntr, *cntrs = this_plot->contours;
  1689. X
  1690. X                while (cntrs) {
  1691. X                    cntr = cntrs;
  1692. X                    cntrs = cntrs->next;
  1693. X                    free(cntr->coords);
  1694. X                    free(cntr);
  1695. X                }
  1696. X            }
  1697. X            /* Make sure this one can be contoured. */
  1698. X            if (!this_plot->has_grid_topology) {
  1699. X                this_plot->contours = NULL;
  1700. X                int_error("Can not contour non grid data!",NO_CARET);
  1701. X            }
  1702. X            if (this_plot->plot_type == DATA3D)
  1703. X                this_plot->contours = contour(
  1704. X                           this_plot->num_iso_read,
  1705. X                           this_plot->iso_crvs,
  1706. X                           contour_levels, contour_pts,
  1707. X                           contour_kind, contour_order);
  1708. X            else
  1709. X                this_plot->contours = contour(iso_samples,
  1710. X                           this_plot->iso_crvs,
  1711. X                           contour_levels, contour_pts,
  1712. X                           contour_kind, contour_order);
  1713. X        }
  1714. X    }
  1715. X
  1716. X    do_3dplot(first_3dplot,plot_num,x_min,x_max,y_min,y_max,z_min,z_max);
  1717. X    sp_free(first_3dplot);
  1718. X    first_3dplot = NULL;
  1719. }
  1720. X
  1721. done(status)
  1722. int status;
  1723. {
  1724. X    if (term && term_init)
  1725. X        (*term_tbl[term].reset)();
  1726. #ifdef vms
  1727. X    vms_reset();
  1728. #endif
  1729. X    exit(status);
  1730. }
  1731. X
  1732. void parametric_fixup (start_plot, plot_num, x_min, x_max)
  1733. struct curve_points *start_plot;
  1734. int *plot_num;
  1735. double *x_min, *x_max;
  1736. /*
  1737. X    The hardest part of this routine is collapsing the FUNC plot types
  1738. X   in the list (which are gauranteed to occur in (x,y) pairs while 
  1739. X    preserving the non-FUNC type plots intact.  This means we have to
  1740. X    work our way through various lists.  Examples (hand checked):
  1741. X        start_plot:F1->F2->NULL ==> F2->NULL
  1742. X        start_plot:F1->F2->F3->F4->F5->F6->NULL ==> F2->F4->F6->NULL
  1743. X        start_plot:F1->F2->D1->D2->F3->F4->D3->NULL ==> F2->D1->D2->F4->D3->NULL
  1744. SHAR_EOF
  1745. true || echo 'restore of gnuplot/command.c failed'
  1746. fi
  1747. echo 'End of  part 13'
  1748. echo 'File gnuplot/command.c is continued in part 14'
  1749. echo 14 > _shar_seq_.tmp
  1750. exit 0
  1751.  
  1752. exit 0 # Just in case...
  1753. -- 
  1754. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1755. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1756. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1757. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1758.