home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 334_01 / command2.c < prev    next >
Text File  |  1991-02-05  |  28KB  |  1,067 lines

  1. /*
  2.  *
  3.  *    gnutex/gnuplot translator  --  command.c
  4.  *
  5.  * By David Kotz, 1990.
  6.  * Department of Computer Science, Duke University, Durham, NC 27706.
  7.  * Mail to dfk@cs.duke.edu.
  8.  */
  9.  
  10. #include <stdio.h>
  11. #include <math.h>
  12. #include "plot.h"
  13.  
  14. #ifndef STDOUT
  15. #define STDOUT 1
  16. #endif
  17.  
  18. extern char *malloc();
  19.  
  20. /*
  21.  * global variables to hold status of 'set' options
  22.  *
  23.  */
  24. BOOLEAN            autoscale_x = TRUE;
  25. BOOLEAN            autoscale_y = TRUE;
  26. BOOLEAN            autoscale_lx = TRUE; /* local to this plot */
  27. BOOLEAN            autoscale_ly = TRUE; /* local to this plot */
  28. enum PLOT_STYLE data_style    = POINTS,
  29.                 func_style    = LINES;
  30. BOOLEAN            log_x        = FALSE,
  31.                 log_y        = FALSE;
  32. FILE*            infile;
  33. FILE*            outfile;
  34. char            outstr[MAX_ID_LEN+1] = "STDOUT";
  35. int                samples        = SAMPLES;
  36. int                term        = 0;                /* unknown term is 0 */
  37. double            xmin        = -10,
  38.                 xmax        = 10,
  39.                 ymin        = -10,
  40.                 ymax        = 10;
  41. double            zero = ZERO;            /* zero threshold, not 0! */
  42.  
  43. BOOLEAN xtics = TRUE;
  44. BOOLEAN ytics = TRUE;
  45.  
  46. BOOLEAN clipping = TRUE;
  47.  
  48. BOOLEAN undefined;
  49.  
  50. char title_string[MAX_LINE_LEN] = "";
  51. char xlabel_string[MAX_LINE_LEN] = "";
  52. char ylabel_string[MAX_LINE_LEN] = "";
  53. char xformat[MAX_ID_LEN] = "";
  54. char yformat[MAX_ID_LEN] = "";
  55. int y_skip_factor = 0;
  56. double plot_width = 4;        /* width  in inches, for latex */
  57. double plot_height = 3;        /* height in inches, for latex */
  58.  
  59. /*
  60.  * instead of <strings.h>
  61.  */
  62.  
  63. char *gets(),*getenv();
  64. char *strcpy(),*strcat();
  65.  
  66. double magnitude(),angle(),real(),imag();
  67. struct value *const_express(), *pop(), *complex();
  68.  
  69.  
  70. extern struct vt_entry vt[];
  71. extern struct st_entry st[];
  72. extern struct udft_entry udft[];
  73.  
  74. extern int inline;            /* line number of current input line */
  75. char input_line[MAX_LINE_LEN],dummy_var[MAX_ID_LEN + 1];
  76. struct at_type *curr_at;
  77. int c_token;
  78. int next_value = (int)NEXT_VALUE,next_function = 0,c_function = 0;
  79. int num_tokens;
  80.  
  81. struct curve_points plot[MAX_PLOTS];
  82. int plot_count = 0;
  83. char plot_ranges[MAX_LINE_LEN+1];
  84. BOOLEAN pending_plot = FALSE;    /* TRUE if a plot command is pending output */
  85. int plot_line;                /* input line number of pending plot */
  86. BOOLEAN key_on = TRUE;        /* will a key be displayed */
  87. BOOLEAN plot_key = FALSE;    /* did we want a key for this plot? */
  88. BOOLEAN label_on = FALSE;    /* will labels be displayed */
  89. BOOLEAN arrow_on = FALSE;    /* will arrows be displayed */
  90. BOOLEAN plot_label = FALSE;    /* do we want labels displayed? */
  91. BOOLEAN plot_arrow = FALSE;    /* do we want arrows displayed? */
  92. BOOLEAN plot_format = FALSE;    /* have we seen a set format? */
  93.  
  94. BOOLEAN was_output;            /* was there any output from command? */
  95.  
  96. int inline = 0;            /* input line number */
  97.  
  98. com_line()
  99. {
  100.     read_line();
  101.  
  102. #ifdef vms
  103.     if (input_line[0] == '!' || input_line[0] == '$')
  104.      fprintf(outfile, "%s\n", input_line);
  105.     else
  106.       do_line();
  107. #else /* vms */
  108.     if (input_line[0] == '!')
  109.      fprintf(outfile, "%s\n", input_line);
  110.     else
  111.       do_line();
  112. #endif
  113.  
  114. }
  115.  
  116. /* Read a line of input; much simplified by the fact that infile is 
  117.  * never a terminal. Handles line continuation and EOF.
  118.  */
  119. read_line()
  120. {
  121.     int len, left;
  122.     int start = 0;
  123.     BOOLEAN more, stop;
  124.     int last;
  125.  
  126.     /* read one command */
  127.     left = MAX_LINE_LEN;
  128.     start = 0;
  129.     more = TRUE;
  130.     stop = FALSE;
  131.  
  132.     while (more) {
  133.        if (fgets(&(input_line[start]), left, infile) == NULL) {
  134.           stop = TRUE;        /* EOF in file */
  135.           input_line[start] = '\0';
  136.           more = FALSE;    
  137.        } else {
  138.           inline++;
  139.           len = strlen(input_line) - 1;
  140.           if (input_line[len] == '\n') { /* remove any newline */
  141.              input_line[len] = '\0';
  142.              len--;
  143.           } else if (len+1 >= left)
  144.             int_error("Input line too long",NO_CARET);
  145.                  
  146.           if (input_line[len] == '\\') { /* line continuation */
  147.              start = len;
  148.              left -= len;
  149.           } else
  150.             more = FALSE;
  151.        }
  152.     }
  153.  
  154.     if (stop && input_line[0] == '\0')
  155.      done(0);
  156. }
  157.  
  158. do_line()
  159. {
  160.     extern int comment_pos;    /* from scanner */
  161.     BOOLEAN nonempty;        /* TRUE if output was nonempty */
  162.  
  163.     num_tokens = scanner(input_line);
  164.     c_token = 0;
  165.     nonempty = FALSE;
  166.     while(c_token < num_tokens) {
  167.        was_output = FALSE;
  168.  
  169.        command();            /* parse the next command */
  170.  
  171.        if (c_token < num_tokens) /* something after command */
  172.         if (equals(c_token,";")) {
  173.             c_token++;
  174.             if (was_output)
  175.              fprintf(outfile, "; ");
  176.         } else
  177.           int_error("';' expected",c_token);
  178.        nonempty = was_output || nonempty;
  179.     }
  180.  
  181.     /* write out any comment */
  182.     if (comment_pos >= 0) {
  183.        if (nonempty)
  184.         putc(' ', outfile);
  185.        fputs(input_line+comment_pos, outfile);
  186.        nonempty = TRUE;
  187.     }
  188.     if (nonempty || num_tokens == 0)
  189.      putc('\n', outfile);
  190. }
  191.  
  192.  
  193. command()
  194. {
  195.     int start_token = c_token;
  196.  
  197.     if (is_definition(c_token)) {
  198.        define();
  199.        copy_command(start_token, c_token-1);
  200.     }
  201.     else if (almost_equals(c_token,"h$elp") || equals(c_token,"?")) {
  202.        c_token++;
  203.        while (!(END_OF_COMMAND))
  204.         c_token++;
  205.        err_msg("help command ignored (removed)");
  206.     }
  207.     else if (almost_equals(c_token,"pr$int")) {
  208.        struct value a;
  209.        c_token++;
  210.        (void) const_express(&a);
  211.        copy_command(start_token, c_token-1);
  212.     }
  213.     else if (almost_equals(c_token,"p$lot")) {
  214.        if (pending_plot)
  215.         write_plot();
  216.        c_token++;
  217.        plotrequest();
  218.        pending_plot = TRUE;
  219.        plot_line = inline;
  220.        /* we defer output until eof or next plot command */
  221.     }
  222.     else if (almost_equals(c_token,"la$bel")) {
  223.        c_token++;
  224.        labelrequest();
  225.     }
  226.     else if (almost_equals(c_token,"k$ey")) {
  227.        c_token++;
  228.        keyrequest();
  229.     }
  230.     else if (almost_equals(c_token,"se$t")) {
  231.        c_token++;
  232.        if (almost_equals(c_token,"t$erminal")) {
  233.           c_token++;
  234.           if (!END_OF_COMMAND)
  235.             c_token++;
  236.           copy_command(start_token, c_token-1);
  237.        }
  238.        else if (almost_equals(c_token,"sa$mples")) {
  239.           struct value a;
  240.           c_token++;
  241.           (void)magnitude(const_express(&a));
  242.           copy_command(start_token, c_token-1);
  243.        }
  244.        else if (almost_equals(c_token,"o$utput")) {
  245.           c_token++;
  246.           if (!END_OF_COMMAND) { /* no file specified */
  247.              if (!isstring(c_token)) 
  248.                int_error("expecting filename",c_token);
  249.              else
  250.                c_token++;
  251.           }
  252.           copy_command(start_token, c_token-1);
  253.        }
  254.        else if (almost_equals(c_token,"a$utoscale")) {
  255.           c_token++;
  256.           if (END_OF_COMMAND) {
  257.           } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  258.              c_token++;
  259.           } else if (equals(c_token, "x")) {
  260.              c_token++;
  261.           } else if (equals(c_token, "y")) {
  262.              c_token++;
  263.           } else
  264.             int_error("expecting axes specification", c_token);
  265.           copy_command(start_token, c_token-1);
  266.        } 
  267.        else if (almost_equals(c_token,"noa$utoscale")) {
  268.           c_token++;
  269.           if (END_OF_COMMAND) {
  270.           } else if (equals(c_token, "xy") || equals(c_token, "yx")) {
  271.              c_token++;
  272.           } else if (equals(c_token, "x")) {
  273.              c_token++;
  274.           } else if (equals(c_token, "y")) {
  275.              c_token++;
  276.           } else
  277.             int_error("expecting axes specification", c_token);
  278.           copy_command(start_token, c_token-1);
  279.        } 
  280.        else if (almost_equals(c_token,"l$ogscale")) {
  281.           c_token++;
  282.           if (equals(c_token,"x")) {
  283.              c_token++;
  284.           } else if (equals(c_token,"y")) {
  285.              c_token++;
  286.           } else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  287.              c_token++;
  288.           } else
  289.             int_error("expecting 'x', 'y', or 'xy'", c_token);
  290.           copy_command(start_token, c_token-1);
  291.        }
  292.        else if (almost_equals(c_token,"nol$ogscale")) {
  293.           copy_command(start_token, c_token++);
  294.        }
  295.        else if (almost_equals(c_token,"z$ero")) {
  296.           struct value a;
  297.           c_token++;
  298.           (void) magnitude(const_express(&a)); 
  299.           copy_command(start_token, c_token-1);
  300.        }
  301.        else if (almost_equals(c_token,"x$range")) {
  302.           c_token++;
  303.           if (!equals(c_token,"["))
  304.             int_error("expecting '['",c_token);
  305.           c_token++;
  306.           load_range();
  307.           if (!equals(c_token,"]"))
  308.             int_error("expecting ']'",c_token);
  309.           c_token++;
  310.           copy_command(start_token, c_token-1);
  311.        }
  312.        else if (almost_equals(c_token,"y$range")) {
  313.           c_token++;
  314.           if (!equals(c_token,"["))
  315.             int_error("expecting '['",c_token);
  316.           c_token++;
  317.           load_range();
  318.           if (!equals(c_token,"]"))
  319.             int_error("expecting ']'",c_token);
  320.           c_token++;
  321.           copy_command(start_token, c_token-1);
  322.        }
  323.        else if (almost_equals(c_token,"d$ata")) {
  324.           c_token++;
  325.           if (!almost_equals(c_token,"s$tyle")) 
  326.             int_error("expecting keyword 'style'",c_token);
  327.           c_token++;
  328.           if (END_OF_COMMAND)
  329.             int_error("expecting style name", c_token);
  330.           c_token++;
  331.           copy_command(start_token, c_token-1);
  332.        }
  333.        else if (almost_equals(c_token,"f$unction")) {
  334.           c_token++;
  335.           if (!almost_equals(c_token,"s$tyle")) 
  336.             int_error("expecting keyword 'style'",c_token);
  337.           c_token++;
  338.           if (END_OF_COMMAND)
  339.             int_error("expecting style name", c_token);
  340.           c_token++;
  341.           copy_command(start_token, c_token-1);
  342.        }
  343.        else if (almost_equals(c_token,"st$yle")) {
  344.           c_token++;
  345.           add_style();
  346.           err_msg("'set style' command obsolete (removed)");
  347.        }
  348.        else if (almost_equals(c_token,"xl$abel")) {
  349.           c_token++;
  350.           if (!isstring(c_token)) 
  351.             int_error("expecting x label string",c_token);
  352.           c_token++;
  353.           copy_command(start_token, c_token-1);
  354.        }
  355.        else if (almost_equals(c_token,"xt$ics")) {
  356.           copy_command(start_token, c_token++);
  357.        } 
  358.        else if (almost_equals(c_token,"noxt$ics")) {
  359.           copy_command(start_token, c_token++);
  360.        } 
  361.        else if (almost_equals(c_token,"yl$abel")) {
  362.           c_token++;
  363.           if (!isstring(c_token)) {
  364.              int_error("expecting y label string",c_token);
  365.           } else {
  366.              c_token++;
  367.              if (!END_OF_COMMAND) { /* skip factor specified */
  368.                 err_msg("ignoring skip factor on ylabel");
  369.                 copy_command(start_token, c_token-1);
  370.                 c_token++;
  371.              } else
  372.                copy_command(start_token, c_token-1);
  373.           }
  374.        }
  375.        else if (almost_equals(c_token,"yt$ics")) {
  376.           copy_command(start_token, c_token++);
  377.        } 
  378.        else if (almost_equals(c_token,"noyt$ics")) {
  379.           copy_command(start_token, c_token++);
  380.        } 
  381.        else if (almost_equals(c_token,"fo$rmat")) {
  382.           c_token++;
  383.           if (equals(c_token,"x")) {
  384.              c_token++;
  385.           } else if (equals(c_token,"y")) {
  386.              c_token++;
  387.           } else if (equals(c_token,"xy") || equals(c_token,"yx")) {
  388.              c_token++;
  389.           } else if (isstring(c_token)) {
  390.           } else
  391.             int_error("expecting 'x', 'y', or 'xy'",c_token);
  392.           if (!isstring(c_token))
  393.             int_error("expecting format string",c_token);
  394.           c_token++;
  395.           copy_command(start_token, c_token-1);
  396.           plot_format = TRUE;
  397.        }
  398.        else if (almost_equals(c_token,"ti$tle")) {
  399.           c_token++;
  400.           if (!isstring(c_token)) 
  401.             int_error("expecting title string",c_token);
  402.           c_token++;
  403.           copy_command(start_token, c_token-1);
  404.        }
  405.        else if (almost_equals(c_token,"si$ze")) {
  406.           struct value a;
  407.           c_token++;
  408.           plot_width = magnitude(const_express(&a));
  409.           if (!equals(c_token, ","))
  410.             int_error("expecting comma between width and height", c_token);
  411.           c_token++;        /* comma */
  412.           plot_height = magnitude(const_express(&a));
  413.           err_msg("'set size' command translated");
  414.           fprintf(outfile, "set size %.3g, %.3g", 
  415.                 (plot_width + 1.096)/5., /* adjust for margins too */
  416.                 (plot_height + 0.616)/3.);
  417.           was_output = TRUE;
  418.        }
  419.        else if (almost_equals(c_token,"cl$ip")) {
  420.           c_token++;
  421.           fprintf(outfile, "set clip points");
  422.           was_output = TRUE;
  423.        } 
  424.        else if (almost_equals(c_token,"nocl$ip")) {
  425.           c_token++;
  426.           fprintf(outfile, "set noclip points");
  427.           was_output = TRUE;
  428.        } 
  429.        else
  430.         int_error("unknown set option (try 'help set')",c_token);
  431.     }
  432.     else if (almost_equals(c_token,"sh$ow")) {
  433.        if (almost_equals(++c_token,"f$unctions")) {
  434.           c_token++;
  435.           if (almost_equals(c_token,"s$tyle")) 
  436.             c_token++;
  437.           copy_command(start_token, c_token-1);
  438.        }
  439.        else if (almost_equals(c_token,"v$ariables")) {
  440.           copy_command(start_token, c_token++);
  441.        }
  442.        else if (almost_equals(c_token,"ac$tion_table") ||
  443.               equals(c_token,"at") ) {
  444.           c_token++;
  445.           show_at();
  446.           copy_command(start_token, c_token-1);
  447.        } 
  448.        else if (almost_equals(c_token,"d$ata")) {
  449.           c_token++;
  450.           if (!almost_equals(c_token,"s$tyle")) 
  451.             int_error("expecting keyword 'style'",c_token);
  452.           c_token++;
  453.           copy_command(start_token, c_token-1);
  454.        }
  455.        else if (almost_equals(c_token,"x$range")) {
  456.           copy_command(start_token, c_token++);
  457.        } 
  458.        else if (almost_equals(c_token,"y$range")) {
  459.           copy_command(start_token, c_token++);
  460.        } 
  461.        else if (almost_equals(c_token,"z$ero")) {
  462.           copy_command(start_token, c_token++);
  463.        }
  464.        else if (almost_equals(c_token,"sa$mples")) {
  465.           copy_command(start_token, c_token++);
  466.        }
  467.        else if (almost_equals(c_token,"o$utput")) {
  468.           copy_command(start_token, c_token++);
  469.        }
  470.        else if (almost_equals(c_token,"t$erminal")) {
  471.           copy_command(start_token, c_token++);
  472.        }
  473.        else if (almost_equals(c_token,"au$toscale")) {
  474.           copy_command(start_token, c_token++);
  475.        }
  476.        else if (almost_equals(c_token,"ve$rsion")) {
  477.           copy_command(start_token, c_token++);
  478.        } 
  479.        else if (almost_equals(c_token,"l$ogscale")) {
  480.           copy_command(start_token, c_token++);
  481.        }
  482.        else if (almost_equals(c_token,"cl$ipping")) {
  483.           copy_command(start_token, c_token++);
  484.        }
  485.        else if (almost_equals(c_token,"xl$abel")) {
  486.           copy_command(start_token, c_token++);
  487.        }
  488.        else if (almost_equals(c_token,"yl$abel")) {
  489.           copy_command(start_token, c_token++);
  490.        }
  491.        else if (almost_equals(c_token,"fo$rmat")) {
  492.           copy_command(start_token, c_token++);
  493.        }
  494.        else if (almost_equals(c_token,"ti$tle")) {
  495.           copy_command(start_token, c_token++);
  496.        }
  497.        else if (almost_equals(c_token,"si$ze")) {
  498.           copy_command(start_token, c_token++);
  499.        }
  500.        else if (almost_equals(c_token,"st$yle")) {
  501.           c_token++;
  502.           add_style();
  503.           err_msg("'show style' command ignored (removed)");
  504.        }
  505.        else if (almost_equals(c_token,"a$ll")) {
  506.           copy_command(start_token, c_token++);
  507.        }
  508.        else
  509.         int_error("unknown show option (try 'help show')",c_token);
  510.     }
  511.     else if (almost_equals(c_token,"cl$ear")) {
  512.        copy_command(start_token, c_token++);
  513.     }
  514.     else if (almost_equals(c_token,"she$ll")) {
  515.        copy_command(start_token, c_token++);
  516.     }
  517.     else if (almost_equals(c_token,"sa$ve")) {
  518.        c_token++;
  519.        if (almost_equals(c_token,"f$unctions")
  520.           || almost_equals(c_token,"v$ariables")) {
  521.           c_token++;
  522.           if (!isstring(c_token))
  523.             int_error("expecting filename",c_token);
  524.        } else if (!isstring(c_token)) {
  525.           int_error("filename or keyword 'functions' or 'variables' expected",c_token);
  526.        }
  527.        c_token++;
  528.        copy_command(start_token, c_token-1);
  529.     }
  530.     else if (almost_equals(c_token,"lo$ad")) {
  531.        if (!isstring(++c_token))
  532.         int_error("expecting filename",c_token);
  533.        c_token++;
  534.        copy_command(start_token, c_token-1);
  535.     }
  536.     else if (almost_equals(c_token,"ex$it") ||
  537.            almost_equals(c_token,"q$uit")) {
  538.        copy_command(start_token, c_token++);
  539.        /* done(IO_SUCCESS); */
  540.     }
  541.     else if (equals(c_token,";")) { /* null statement */
  542.        copy_command(start_token, c_token++);
  543.     } else {
  544.        int_error("invalid command",c_token);
  545.     }
  546. }
  547.  
  548. load_range()
  549. {
  550. struct value t;
  551. double a,b;
  552.  
  553.     if (equals(c_token,"]"))
  554.         return;
  555.     if (END_OF_COMMAND) {
  556.         int_error("starting range value or 'to' expected",c_token);
  557.     } else if (!equals(c_token,"to") && !equals(c_token,":"))  {
  558.         a = real(const_express(&t));
  559.     }    
  560.     if (!equals(c_token,"to") && !equals(c_token,":")) 
  561.         int_error("Keyword 'to' or ':' expected",c_token);
  562.     c_token++; 
  563.     if (!equals(c_token,"]"))
  564.         b = real(const_express(&t));
  565. }
  566.  
  567.  
  568. plotrequest()
  569. {
  570.     int start_token = c_token;
  571.  
  572.     if (equals(c_token,"[")) {
  573.        c_token++;
  574.        if (isletter(c_token)) {
  575.           c_token++;
  576.           if (equals(c_token,"="))
  577.             c_token++;
  578.           else
  579.             int_error("'=' expected",c_token);
  580.        }
  581.        load_range();
  582.        if (!equals(c_token,"]"))
  583.         int_error("']' expected",c_token);
  584.        c_token++;
  585.     }
  586.  
  587.     if (equals(c_token,"[")) { /* set optional y ranges */
  588.        c_token++;
  589.        load_range();
  590.        if (!equals(c_token,"]"))
  591.         int_error("']' expected",c_token);
  592.        c_token++;
  593.     }
  594.  
  595.     capture(plot_ranges, start_token, c_token-1);
  596.  
  597.     eval_plots();
  598. }
  599.  
  600. /* Parse the definition of a style and add to table */
  601. add_style()
  602. {
  603.     register int i;
  604.     int style = -1;                /* the new style number */
  605.     struct value a;
  606.     register struct st_entry *stp;    /* quick access to new entry */
  607.     int null_definition = TRUE; /* watch out for missing definitions */
  608.  
  609.     /* check if it's already in the table... */
  610.  
  611.     style = -1;
  612.     for (i = 0; i < next_value; i++) {
  613.         if (equals(c_token,st[i].st_name))
  614.             style = i;
  615.     }
  616.     /* Not found - assign a new one */
  617.     if (style < 0)
  618.      style = next_style;
  619.     /* Found - redefine it */
  620.     if (style <= FIXED_STYLES)
  621.      int_error("cannot redefine this style", c_token);
  622.     if (style == MAX_STYLES)
  623.      int_error("user defined style space full",NO_CARET);
  624.     else
  625.      next_style++;
  626.  
  627.     stp = &st[style];
  628.  
  629.     /* Copy in the name of the style */
  630.     copy_str(stp->st_name,c_token);
  631.     stp->st_undef = TRUE;
  632.     c_token++;
  633.  
  634.     /* Point type */
  635.     if(!isstring(c_token)) {
  636.        *stp->st_point = '\0'; /* null point definition */
  637.     } else {
  638.        quote_str(stp->st_point, c_token);
  639.        c_token++;
  640.        null_definition = FALSE;
  641.     }
  642.  
  643.      /* Spacing */
  644.     if(END_OF_COMMAND) {
  645.        stp->st_spacing = 0;
  646.        stp->st_length = 0;
  647.     } else {
  648.        /* read dot spacing */
  649.        if (!isnumber(c_token)) {
  650.           next_value--;
  651.           int_error("expecting spacing (in points) for style", c_token);
  652.        }
  653.        convert(&a, c_token);
  654.        stp->st_spacing = magnitude(&a);
  655.        if (stp->st_spacing < 0.1) {
  656.           next_value--;
  657.           int_error("unreasonable spacing value", c_token);
  658.        }
  659.        c_token++;
  660.  
  661.        /* build dot sequence */
  662.        stp->st_length = 0;
  663.        
  664.        while(!(END_OF_COMMAND)) {
  665.           if (!isstring(c_token))
  666.             int_error("expecting a string defining a sequence style", c_token);
  667.           quote_str(stp->st_seq[stp->st_length++], c_token);
  668.           c_token++;
  669.           if (stp->st_length >= MAX_STYLE_SEQ_LENGTH)
  670.             int_error("style sequence too long", c_token);
  671.        }
  672.        null_definition = FALSE;
  673.  
  674.        if (stp->st_length == 0)
  675.         int_error("expecting dot sequence", c_token);
  676.     }
  677.  
  678.     if (null_definition)
  679.      int_error("expecting definition of style", c_token);
  680.  
  681.     c_token++;
  682. }
  683.  
  684.  
  685. labelrequest()
  686. {
  687.     struct value a;
  688.     double x,y;            /* the point */
  689.     char pos[MAX_ID_LEN+1];    /* optional argument */
  690.     char text[MAX_ID_LEN+1];    /* text of the label */
  691.     double length = 0;        /* length of arrow */
  692.     int dx = 0, dy = 0;        /* slope of arrow */
  693.  
  694.     /* x coordinate */
  695.     const_express(&a);
  696.     x = real(&a);
  697.     if (log_x)        /* handle coords on logscale plot. PEM 01/17/89 */
  698.     x = log10(x);
  699.  
  700.     if (!equals(c_token, ","))
  701.      int_error("comma expected", c_token);
  702.     c_token++;
  703.  
  704.     /* y coordinate */
  705.     const_express(&a);
  706.     y = real(&a);
  707.     if (log_y)        /* handle coords on logscale plot. PEM 01/17/89 */
  708.     y = log10(y);
  709.  
  710.     /* text */
  711.     if (isstring(c_token))
  712.      quote_str(text, c_token++);
  713.     else
  714.      int_error("expecting text of the label", c_token);
  715.  
  716.     /* optional pos */
  717.     pos[0] = '\0';
  718.     if (!(END_OF_COMMAND)) {
  719.        copy_str(pos, c_token++);
  720.        
  721.        /* optional length for optional arrow  */
  722.        if (!(END_OF_COMMAND)) {
  723.           const_express(&a);
  724.           length = real(&a);
  725.  
  726.           if (!(END_OF_COMMAND)) {
  727.              if (!equals(c_token, ","))
  728.                int_error("comma expected", c_token);
  729.              c_token++;
  730.           
  731.              const_express(&a);
  732.              dx = (int) real(&a);
  733.  
  734.              if (!equals(c_token, ","))
  735.                int_error("comma expected", c_token);
  736.              c_token++;
  737.  
  738.              const_express(&a);
  739.              dy = (int) real(&a);
  740.           }
  741.        }
  742.     }
  743.  
  744.     save_label(x,y, text, pos, length, dx, dy);
  745. }
  746.  
  747. /* translate the label  */
  748. save_label(x,y, text, pos, length, dx, dy)
  749.     double x,y;            /* the point */
  750.     char text[MAX_ID_LEN+1];    /* text of the label */
  751.     char pos[MAX_ID_LEN+1];    /* optional argument */
  752.     double length;            /* length of arrow */
  753.     int dx, dy;            /* slope of arrow */
  754. {
  755.     char *where = NULL;
  756.     BOOLEAN adjust = FALSE;
  757.     double ex, ey;
  758.  
  759.     if (instring(pos, 'l'))
  760.      where = "left";
  761.     else if (instring(pos, 'r'))
  762.      where = "right";
  763.     else
  764.      where = "center";
  765.  
  766.     if (instring(pos, 't') || instring(pos, 'b'))
  767.      adjust = TRUE;
  768.  
  769.     fprintf(outfile, "set label \"%s\" at %g,%g %s\n", text, x, y, where);
  770.  
  771.     if (length != 0) {
  772.        /* arrow option. Compute destination */
  773.        if (dx == 0 && dy == 0) {
  774.           if (instring(pos, 'l'))
  775.             dx = -1;
  776.           else if (instring(pos, 'r')) 
  777.             dx = 1;
  778.           else
  779.             dx = 0;
  780.           if (instring(pos, 't'))
  781.             dy = 1;
  782.           else if (instring(pos, 'b')) 
  783.             dy = -1;
  784.           else
  785.             dy = 0;
  786.        }
  787.        ex = x + (dx ? length : 0);
  788.        ey = y + (dx ? ((float)dy/dx * length) : length);
  789.  
  790.        fprintf(outfile, "set arrow from %g,%g to %g,%g\n", x, y, ex, ey);
  791.        arrow_on = TRUE;
  792.        plot_arrow = TRUE;
  793.     }
  794.  
  795.     label_on = TRUE;
  796.     plot_label = TRUE;
  797.     was_output = TRUE;
  798. }
  799.  
  800. keyrequest()
  801. {
  802.     struct value a;
  803.     double x,y;            /* the point */
  804.     int styles[MAX_KEYS+1];    /* the style for each plot */
  805.     char *text[MAX_KEYS+1];    /* text of each key entry */
  806.     int style;
  807.     int curve = 0;            /* index of the entry */
  808.  
  809.     /* x coordinate */
  810.     const_express(&a);
  811.     x = real(&a);
  812.  
  813.     if (!equals(c_token, ","))
  814.      int_error("comma expected", c_token);
  815.     c_token++;
  816.  
  817.     /* y coordinate */
  818.     const_express(&a);
  819.     y = real(&a);
  820.  
  821.     do {                    /* scan the entries in the key */
  822.        /* text */
  823.        if (isstring(c_token)) {
  824.           text[curve] = (char *) malloc(MAX_ID_LEN);
  825.           quote_str(text[curve], c_token++);
  826.        } else
  827.         int_error("expecting text of the key entry", c_token);
  828.        
  829.        if (almost_equals(c_token, "w$ith"))
  830.         c_token++;
  831.        else
  832.         int_error("expecting 'with' style for key entry", c_token);
  833.  
  834.        for (style = 0; style < next_style; style++)
  835.         if (equals(c_token, st[style].st_name))
  836.           break;
  837.        if (style == next_style)
  838.         int_error("unknown plot style; type 'show style'", 
  839.                 c_token);
  840.        else
  841.         styles[curve] = style;
  842.        c_token++;
  843.  
  844.        if (!END_OF_COMMAND)
  845.         if (!equals(c_token, ","))
  846.           int_error("expecting ',' between key entries", c_token);
  847.         else
  848.           c_token++;
  849.  
  850.        curve++;
  851.        if (curve > MAX_KEYS)
  852.         int_error("too many lines in the key", c_token);
  853.     } while (!END_OF_COMMAND);
  854.  
  855.     text[curve] = NULL;        /* acts as terminator */
  856.  
  857.     save_key (x,y, styles, text);
  858.  
  859.     for (curve--; curve >= 0; curve--)
  860.      free(text[curve]);
  861. }
  862.  
  863. save_key (x,y, styles, text)
  864.     double x,y;            /* the position of the key */
  865.     int styles[MAX_KEYS+1];    /* the style for each plot */
  866.     char *text[MAX_KEYS+1];    /* text of each key entry */
  867. {
  868.     int curve;                /* index of the entry */
  869.  
  870.     for (curve = 0; text[curve] != NULL; curve++) {
  871.        strcpy(plot[curve].title, text[curve]);
  872.     }
  873.     fprintf(outfile, "set key %g,%g", x,y);
  874.     was_output = TRUE;
  875.     key_on = TRUE;
  876.     plot_key = TRUE;
  877.  
  878.     err_msg("'key' command translated; position needs adjusting");
  879. }
  880.  
  881. define()
  882. {
  883. register int value,start_token;  /* start_token is the 1st token in the    */
  884.                                 /* function definition.            */
  885.  
  886.     if (equals(c_token+1,"(")) {
  887.         /* function ! */
  888.         start_token = c_token;
  889.         copy_str(dummy_var, c_token + 2);
  890.         c_token += 5; /* skip (, dummy, ) and = */
  891.         value = c_function = user_defined(start_token);
  892.         build_at(&(udft[value].at));
  893.                 /* define User Defined Function (parse.c)*/
  894.         capture(udft[value].definition,start_token,c_token-1);
  895.     }
  896.     else {
  897.         /* variable ! */
  898.         c_token +=2;
  899.         (void) const_express(&vt[value = add_value(c_token - 2) ].vt_value);
  900.         vt[value].vt_undef = FALSE;
  901.     }
  902. }
  903.  
  904. /* This parses the plot command after any range specifications. 
  905.  * We revert to one-pass parsing here. That's all we need.
  906.  */
  907. eval_plots()
  908. {
  909. register int plot_num, start_token;
  910. struct value a;
  911. int style;
  912.  
  913.     c_function = MAX_UDFS;        /* last udft[] entry used for plots */
  914.  
  915.     plot_num = 0;
  916.  
  917.     while (TRUE) {
  918.         if (END_OF_COMMAND)
  919.             int_error("function to plot expected",c_token);
  920.         if (plot_num == MAX_PLOTS)
  921.             int_error("maximum number of plots exceeded",NO_CARET);
  922.  
  923.         start_token = c_token;
  924.  
  925.         if (is_definition(c_token)) {
  926.             define();
  927.         } else {
  928.             if (isstring(c_token)) {            /* data file to plot */
  929.                 plot[plot_num].plot_type = DATA;
  930.                 style = (int)data_style;
  931.                 c_token++; /* skip file name */
  932.             } 
  933.             else {                            /* function to plot */
  934.                 plot[plot_num].plot_type = FUNC;
  935.                 style = (int)func_style;
  936.                 build_at(&udft[MAX_UDFS].at);
  937.                 /* that's all */
  938.             }
  939.             capture(plot[plot_num].def,start_token,c_token-1);
  940.             plot[plot_num].title[0] = '\0';
  941.  
  942.             if (almost_equals(c_token,"w$ith")) {
  943.                 c_token++;
  944.                 for (style = 0; style < next_style; style++)
  945.                   if (equals(c_token, st[style].st_name))
  946.                     break;
  947.                 if (style == next_style)
  948.                   int_error("unknown plot style; type 'show style'", 
  949.                           c_token);
  950.                 else
  951.                   c_token++;
  952.             }
  953.             plot[plot_num].plot_style = equiv_style(style);
  954.             plot_num++;
  955.         }
  956.  
  957.         if (equals(c_token,",")) 
  958.             c_token++;
  959.         else  
  960.             break;
  961.     }
  962.  
  963.     plot_count = plot_num;
  964. }
  965.  
  966. /* return a standard style close to the given style */
  967. int
  968. equiv_style(style)
  969.     int style;            /* may be a user-def style */
  970. {
  971.     BOOLEAN line, point;
  972.     char message[MAX_LINE_LEN+1];
  973.  
  974.     if (style <= FIXED_STYLES)
  975.      return(style);
  976.  
  977.     point = (st[style].st_point[0] != '\0');
  978.     line = (st[style].st_length > 0);
  979.  
  980.     sprintf(message,
  981.           "user-defined style %s replaced by similar standard style",
  982.           st[style].st_name);
  983.     err_msg(message);
  984.  
  985.     if (point && line)
  986.      return((int)LINESPOINTS);
  987.     if (point)
  988.      return((int)POINTS);
  989.     if (line)
  990.      return((int)LINES);
  991.  
  992.     /* should not happen */
  993.     err_msg("no standard style corresponds to this style");
  994.     return((int)LINES);
  995. }
  996.  
  997.  
  998. /* write out the plot command now that we know titles */
  999. write_plot()
  1000. {
  1001.     int plot_num;
  1002.  
  1003.     if (!plot_key && key_on) {
  1004.        fprintf(outfile, "set nokey\n");
  1005.        key_on = FALSE;
  1006.     }
  1007.  
  1008.     if (!plot_label && label_on) {
  1009.        fprintf(outfile, "set nolabel\n");
  1010.        label_on = FALSE;
  1011.     }
  1012.  
  1013.     if (!plot_arrow && arrow_on) {
  1014.        fprintf(outfile, "set noarrow\n");
  1015.        arrow_on = FALSE;
  1016.     }
  1017.  
  1018.     if (!plot_format) {
  1019.        fprintf(outfile, "set format xy \"$%%g$\"\n");
  1020.        plot_format = TRUE;
  1021.     }
  1022.  
  1023.     fprintf(outfile, "plot %s ", plot_ranges);
  1024.  
  1025.     for (plot_num = 0; plot_num < plot_count; plot_num++) {
  1026.        if (plot_num > 0)
  1027.         fputs(", ", outfile);
  1028.        fprintf(outfile, "%s", plot[plot_num].def);
  1029.        if (plot[plot_num].title[0] != '\0')
  1030.         fprintf(outfile, " title \"%s\"", plot[plot_num].title);
  1031.  
  1032.        fprintf(outfile, " with %s", st[plot[plot_num].plot_style].st_name);
  1033.     }
  1034.  
  1035.     fprintf(outfile, "\n");
  1036.     /* we don't set was_output since we have the newline already */
  1037.  
  1038.     fprintf(stderr, 
  1039.           "\n***%d: plot command moved, watch out for use of variables\n", 
  1040.           plot_line);
  1041.  
  1042.     pending_plot = FALSE;
  1043.     plot_key = FALSE;
  1044.     plot_label = FALSE;
  1045.     plot_arrow = FALSE;
  1046. }
  1047.  
  1048. /* copy a command from input to output */
  1049. copy_command(start, end)
  1050.     int start, end;        /* inclusive token numbers */
  1051. {
  1052.     char command_line[MAX_LINE_LEN+1];
  1053.  
  1054.     capture(command_line, start, end);
  1055.     fputs(command_line, outfile);
  1056.     was_output = TRUE;
  1057. }
  1058.  
  1059. done(status)
  1060. int status;
  1061. {
  1062.     if (pending_plot)
  1063.      write_plot();
  1064.  
  1065.     exit(status);
  1066. }
  1067.