Mercurial > hg > octave-nkf
view src/__gnuplot_raw__.l @ 5915:b2e1be30c8e9 ss-2-9-7
[project @ 2006-07-28 18:08:56 by jwe]
author | jwe |
---|---|
date | Fri, 28 Jul 2006 18:08:56 +0000 |
parents | 080c08b192d8 |
children |
line wrap: on
line source
/* Copyright (C) 2004 John W. Eaton and Teemu Ikonen This file is part of Octave. Octave is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. Octave is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Octavee; see the file COPYING. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ %option prefix="gpt" %option noyywrap %{ // PKG_ADD: mark_as_rawcommand ("__gnuplot_plot__"); // PKG_ADD: mark_as_rawcommand ("__gnuplot_set__"); // PKG_ADD: mark_as_rawcommand ("__gnuplot_splot__"); // PKG_ADD: mark_as_rawcommand ("__gnuplot_replot__"); // PKG_ADD: mark_as_command ("__gnuplot_show__"); // PKG_ADD: atexit ("closeplot"); #ifdef HAVE_CONFIG_H #include <config.h> #endif #include <map> #include <string> #include <fstream> #include <iostream> #include <sstream> #ifdef HAVE_UNISTD_H #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> #endif #include <unistd.h> #endif #include "file-ops.h" #include "oct-env.h" #include "defun.h" #include "file-io.h" #include "gripes.h" #include "load-save.h" #include "parse.h" #include "procstream.h" #include "sighandlers.h" #include "utils.h" #include "variables.h" enum _toktype { START_PAREN = 1, END_PAREN, START_BRACE, END_BRACE, START_BRACKET, END_BRACKET, COLON, SEMICOLON, COMMA, QUOTE, IDENT, NUMBER, BINOP, UNOP, STRING, OTHER, TITLE, USING, WITH, AXES, CLEAR }; typedef bool (*pred) (const int); class gpt_parse_error { public: gpt_parse_error (void) : msg () { } gpt_parse_error (std::string errmsg) : msg (errmsg) { } std::string msg; }; static bool gpt_quote_is_transpose; static bool gpt_allow_plotkw; static int gpt_parens; static int gpt_brackets; static int gpt_braces; static bool can_be_plotkw (void); static int is_plot_keyword (const std::string& s); static int handle_string (char delim); static std::string strbuf; %} D [0-9] S [ \t] IDENT ([_a-zA-Z@][_a-zA-Z0-9]*) EXPON ([DdEe][+-]?{D}+) NUMBER (({D}+\.?{D}*{EXPON}?)|(\.{D}+{EXPON}?)|(0[xX][0-9a-fA-F]+)) NOT ((\~)|(\!)) /* NOT is not strictly a binary operator, but is close enough for us. */ BINOP (({NOT})|(\.?([\*/\\^+-]|\*\*)=?)|([<=~!>&|]=)|([=&|<>]{1,2})|(<<=)|(>>=)|(\.)) /* single quote (') transpose operator is handled separately. */ UNOP ((\+\+)|(\-\-)|(\.')) %% "(" { gpt_quote_is_transpose = false; gpt_parens++; return START_PAREN; } ")" { gpt_quote_is_transpose = true; gpt_parens--; return END_PAREN; } "{" { gpt_quote_is_transpose = false; gpt_braces++; return START_BRACE; } "}" { gpt_quote_is_transpose = true; gpt_braces--; return END_BRACE; } "[" { gpt_quote_is_transpose = false; gpt_brackets++; return START_BRACKET; } "]" { gpt_quote_is_transpose = true; gpt_brackets--; return END_BRACKET; } ":" { gpt_quote_is_transpose = false; return COLON; } ";" { gpt_quote_is_transpose = false; return SEMICOLON; } "," { gpt_quote_is_transpose = false; return COMMA; } "'" { if (gpt_quote_is_transpose) { gpt_allow_plotkw = true; return QUOTE; } else { gpt_quote_is_transpose = true; gpt_allow_plotkw = true; return handle_string ('\''); } } "\"" { return handle_string ('"'); } {IDENT} { int itok = 0; if (can_be_plotkw () && (itok = is_plot_keyword (yytext))) { gpt_quote_is_transpose = false; gpt_allow_plotkw = true; return itok; } else if (std::string (yytext) == "function") throw gpt_parse_error ("function keyword not allowed in plot commands"); else { gpt_quote_is_transpose = true; gpt_allow_plotkw = true; return IDENT; } } {D}+/\.[\*/\\^'] | /* ' */ {NUMBER} { gpt_quote_is_transpose = true; gpt_allow_plotkw = true; return NUMBER; } {BINOP} { gpt_quote_is_transpose = false; gpt_allow_plotkw = false; return BINOP; } {UNOP} { gpt_quote_is_transpose = false; gpt_allow_plotkw = true; return UNOP; } {S} { /* Ignore spaces and tabs outside of character strings. */ } . { gpt_quote_is_transpose = false; gpt_allow_plotkw = true; warning ("unknown token = \"%s\" in plot command", yytext); return OTHER; } %% // ------------------------------------------------------------ // Interface to external gnuplot process(es), including gnuplot // command parser. // ------------------------------------------------------------ // The name of the shell command to execute to start gnuplot. static std::string Vgnuplot_binary; // Append -title "Figure NN" to the gnuplot command? static bool Vgnuplot_use_title_option = octave_env::have_x11_display (); // Gnuplot command strings that we use. static std::string Vgnuplot_command_plot; static std::string Vgnuplot_command_replot; static std::string Vgnuplot_command_splot; static std::string Vgnuplot_command_using; static std::string Vgnuplot_command_with; static std::string Vgnuplot_command_axes; static std::string Vgnuplot_command_title; static std::string Vgnuplot_command_end; // If TRUE, a replot command is issued automatically each time a plot // changes in some way. static bool Vautomatic_replot; // Check if the parser state is such that a plot keyword can occur. static bool can_be_plotkw (void) { return (gpt_allow_plotkw && (gpt_braces == 0) && (gpt_brackets == 0) && (gpt_parens == 0)); } // Check to see if a character string matches any one of the plot // option keywords. Don't match abbreviations for clear, since that's // not a gnuplot keyword (users will probably only expect to be able // to abbreviate actual gnuplot keywords). static int is_plot_keyword (const std::string& s) { if (almost_match ("title", s, 1)) return TITLE; else if (almost_match ("using", s, 1)) return USING; else if (almost_match ("with", s, 1)) return WITH; else if (almost_match ("axes", s, 2) || almost_match ("axis", s, 2)) return AXES; else if ("clear" == s) return CLEAR; else return 0; } // This is used to handle character strings. Kludge alert. static int handle_string (char delim) { int c; bool escape_pending = false; strbuf = std::string (1, delim); while ((c = yyinput ()) != EOF) { if (c == '\\') { if (escape_pending) { strbuf += static_cast<char> (c); escape_pending = false; } else { strbuf += static_cast<char> (c); escape_pending = true; } continue; } else if (c == '\n') { error ("unterminated string constant"); break; } else if (c == delim) { if (escape_pending) strbuf += static_cast<char> (c); else { c = yyinput (); if (c == delim) { strbuf += static_cast<char> (c); strbuf += static_cast<char> (c); } else { yyunput (c, yytext); strbuf += static_cast<char> (delim); return STRING; } } } else strbuf += static_cast<char> (c); escape_pending = false; } throw gpt_parse_error ("unterminated string"); return 0; } // (Probably not necessesary, but current Matlab style plot functions // break without this (they emit too short gnuplot commands)) static std::string plot_style_token (const std::string& s) { std::string retval; // FIXME -- specify minimum match length for these. static const char *plot_styles[] = { "boxes", "boxerrorbars", "boxxyerrorbars", "candlesticks", "dots", "errorbars", "financebars", "fsteps", "histeps", "impulses", "lines", "linespoints", "points", "steps", "vector", "xerrorbars", "xyerrorbars", "yerrorbars", 0, }; const char * const *tmp = plot_styles; while (*tmp) { if (almost_match (*tmp, s.c_str ())) { retval = *tmp; break; } tmp++; } return retval; } // Some predicates on tokens // Return true for ":". static bool colonp (const int tok) { return (tok == COLON); } // Return TRUE for "]". static bool endbracketp (const int tok) { return (tok == END_BRACKET); } // Return TRUE for plot token, comma or end of input. static bool plottok_or_end_p (const int tok) { return (tok == TITLE || tok == USING || tok == WITH || tok == AXES || tok == CLEAR || tok == COMMA || tok == 0); } // Equivalent to (colonp (tok) || plottok_or_end_p (tok)). static bool colon_plottok_or_end_p (const int tok) { return (tok == COLON || plottok_or_end_p (tok)); } // read until test is true and delimiters are balanced, or end of input. // Return the last token in lasttok static std::string read_until (pred test, int& lasttok) throw (gpt_parse_error) { int tok; // We have to maintain balanced delimiters per subexpression too. int brackets = 0; int parens = 0; int braces = 0; std::string s; tok = gptlex (); while (tok && ! (test (tok) && brackets == 0 && parens == 0 && braces == 0)) { switch (tok) { case START_BRACKET: brackets++; break; case END_BRACKET: brackets--; break; case START_PAREN: parens++; break; case END_PAREN: parens--; break; case START_BRACE: braces++; break; case END_BRACE: braces--; break; default: break; } s += (tok == STRING ? strbuf : std::string (yytext)) + " "; tok = gptlex (); } // Throw error only if we've reached the end token and the test // doesn't accept it. if (! test (tok) && ! tok) throw gpt_parse_error ("unexpected end of input"); lasttok = tok; return s; } // Eval the two expressions giving limits of range and print it. static std::string printrange (std::string starts, std::string ends) { octave_value startv, endv; int status; std::string s; std::ostringstream range_buf; range_buf << "["; if (! starts.empty ()) { startv = eval_string (starts, true, status); if (! startv.is_real_scalar ()) throw gpt_parse_error (); startv.print_raw (range_buf); } range_buf << ":"; if (! ends.empty ()) { endv = eval_string (ends, true, status); if (! endv.is_real_scalar ()) throw gpt_parse_error (); endv.print_raw (range_buf); } range_buf << "]"; s = range_buf.str (); return s; } // Handle plot parameters. // Parse, evaluate and print colon separated expressions in the using // plot parameter. The use of trailing format string is not supported. static std::string handle_using (int& lasttok) { int tok; std::string expr_str; std::string retstr = Vgnuplot_command_using + " "; bool out = false; octave_value tmp_data; int status; while (! out) { expr_str = read_until (colon_plottok_or_end_p, tok); tmp_data = eval_string (expr_str, true, status); if (status != 0 || ! tmp_data.is_real_scalar ()) throw gpt_parse_error (); std::ostringstream tmp_buf; tmp_data.print_raw (tmp_buf); retstr += tmp_buf.str (); if (tok == COLON) retstr += ":"; else out = true; } lasttok = tok; return retstr; } // Presently just passes the linewidth, pointtype etc. tokens as they are. static std::string handle_style (int& lasttok) { std::string retstr = Vgnuplot_command_with + " "; std::string style; lasttok = gptlex (); if (lasttok != IDENT) throw gpt_parse_error ("expected plot style token"); style = std::string (yytext); style = plot_style_token (style); if (! style.empty ()) retstr += style; else retstr += std::string (yytext); // FIXME -- should evaluate the remaining tokens, but this // needs changes in the parser. retstr += " " + read_until (plottok_or_end_p, lasttok); return retstr; } // Axes has only one qualifier keyword, which is not evaluated. static std::string handle_axes (int& lasttok) { return Vgnuplot_command_axes + " " + read_until (plottok_or_end_p, lasttok); } static std::string save_in_tmp_file (const octave_value& t, int ndim = 2, bool parametric = false) { std::string name = file_ops::tempnam ("", "oct-"); if (! name.empty ()) { std::ofstream file (name.c_str ()); if (file) { switch (ndim) { case 2: save_ascii_data_for_plotting (file, t, name); break; case 3: save_three_d (file, t, parametric); break; default: gripe_2_or_3_dim_plot (); break; } } else { error ("couldn't open temporary output file `%s'", name.c_str ()); name.resize (0); } } return name; } static int get_current_figure (void) { int retval = 1; octave_value cf = get_global_value ("__current_figure__", true); if (cf.is_defined ()) retval = cf.int_value (); else set_global_value ("__current_figure__", retval); return retval; } class gnuplot { protected: gnuplot (void) : plot_line_count (0), parametric_plot (false), use_title_option (Vgnuplot_use_title_option), gnuplot_exe (Vgnuplot_binary), gnuplot_terminal_type (), plot_stream () { do_init (); } public: ~gnuplot (void) { } static bool have_instance (void); static bool ensure_instance (void); static bool ensure_plot_stream (void); static void open (void); static void close (void); static void close_all (void); static bool plot_stream_event_handler (pid_t pid, int status); static void send (const std::string& cmd) { if (ensure_plot_stream ()) instance->do_send (cmd); } static void send_raw (const std::string& cmd) { if (ensure_plot_stream ()) instance->do_send_raw (cmd); } static void clear (void) { if (ensure_plot_stream ()) instance->do_clear (); } static void set (const string_vector& argv) { if (ensure_plot_stream ()) instance->do_set (argv); } static void show (const string_vector& argv) { if (ensure_plot_stream ()) instance->do_show (argv); } static void set_gnuplot_exe (const std::string& exe) { if (ensure_instance ()) instance->do_set_gnuplot_exe (exe); } static void set_gnuplot_use_title_option (bool opt) { if (ensure_instance ()) instance->do_set_gnuplot_use_title_option (opt); } // FIXME -- should only remove tmp files associated with // gnuplot? static void cleanup_tmp_files (void) { ::cleanup_tmp_files (); } static void plot (const string_vector& argv) { if (ensure_plot_stream ()) instance->do_plot (argv); } private: static gnuplot *instance; static std::map<int, gnuplot *> instance_map; // The number of lines we've plotted so far. int plot_line_count; // Is this a parametric plot? Makes a difference for 3D plotting. bool parametric_plot; // Should we append '-title "TITLE"' to the gnuplot command? bool use_title_option; // The executable program to run. std::string gnuplot_exe; // The gnuplot terminal type. std::string gnuplot_terminal_type; // Pipe to gnuplot. oprocstream *plot_stream; pid_t pid (void) const; static gnuplot *lookup_by_pid (pid_t pid); void do_open (void); void do_close (void); void delete_plot_stream (void); void reset_plot_stream (void); void do_send (const std::string& cmd); void do_send_raw (const std::string& cmd); void do_clear (void); void do_set (const string_vector& argv); void do_show (const string_vector& argv); void do_set_gnuplot_exe (const std::string& exe) { gnuplot_exe = exe; } void do_set_gnuplot_use_title_option (bool opt) { use_title_option = opt; } void do_plot (const string_vector& argv); void do_init (void); std::string makeplot (std::string caller, std::string args) throw (gpt_parse_error); std::string handle_title (int& lasttok); }; gnuplot *gnuplot::instance = 0; std::map<int, gnuplot *> gnuplot::instance_map; bool gnuplot::have_instance (void) { int current_figure = get_current_figure (); if (instance_map.find (current_figure) != instance_map.end ()) { instance = instance_map[current_figure]; return true; } else return false; } bool gnuplot::ensure_instance (void) { if (! have_instance ()) { instance = new gnuplot (); if (! instance) { ::error ("unable to create gnuplot object!"); return false; } else instance_map[get_current_figure ()] = instance; } return true; } bool gnuplot::ensure_plot_stream (void) { if (ensure_instance ()) { instance->do_open (); if (error_state) return false; } return true; } void gnuplot::close (void) { if (have_instance ()) { instance->do_close (); instance_map.erase (get_current_figure ()); } } void gnuplot::close_all (void) { for (std::map<int, gnuplot *>::const_iterator p = instance_map.begin (); p != instance_map.end (); p++) { gnuplot *elt = p->second; elt->do_close (); } } pid_t gnuplot::pid (void) const { return plot_stream ? plot_stream->pid () : -1; } gnuplot * gnuplot::lookup_by_pid (pid_t pid) { gnuplot *retval = 0; for (std::map<int, gnuplot *>::const_iterator p = instance_map.begin (); p != instance_map.end (); p++) { gnuplot *elt = p->second; if (elt && elt->pid () == pid) { retval = elt; break; } } return retval; } void gnuplot::do_open (void) { static bool initialized = false; if (plot_stream && ! *plot_stream) do_close (); if (! plot_stream) { initialized = false; plot_line_count = 0; std::string cmd; if (gnuplot_exe.empty ()) cmd = "gnuplot"; else cmd = "\"" + gnuplot_exe + "\""; // FIXME -- I'm not sure this is the right thing to do, // but without it, C-c at the octave prompt will kill gnuplot... #if defined (HAVE_POSIX_SIGNALS) sigset_t nset, oset; sigemptyset (&nset); sigaddset (&nset, SIGINT); sigprocmask (SIG_BLOCK, &nset, &oset); #else volatile octave_interrupt_handler old_interrupt_handler = octave_ignore_interrupts (); #endif if (use_title_option) { std::ostringstream buf; buf << cmd << " -title \"Figure " << get_current_figure () << "\""; cmd = buf.str (); } plot_stream = new oprocstream (cmd.c_str ()); if (plot_stream && *plot_stream) octave_child_list::insert (plot_stream->pid (), plot_stream_event_handler); else { delete_plot_stream (); error ("plot: unable to open pipe to `%s'", cmd.c_str ()); } #if defined (HAVE_POSIX_SIGNALS) sigprocmask (SIG_SETMASK, &oset, 0); #else octave_set_interrupt_handler (old_interrupt_handler); #endif } if (! error_state && plot_stream && *plot_stream && ! initialized) { initialized = true; do_send_raw ("set style data lines\n"); if (! gnuplot_terminal_type.empty ()) do_send_raw ("set term " + gnuplot_terminal_type + Vgnuplot_command_end + "\n"); } } void gnuplot::delete_plot_stream (void) { do_send_raw ("\nquit\n"); delete plot_stream; plot_stream = 0; } void gnuplot::reset_plot_stream (void) { delete_plot_stream (); plot_line_count = 0; parametric_plot = false; } void gnuplot::do_close (void) { if (plot_stream) { octave_child_list::remove (plot_stream->pid ()); delete_plot_stream (); } plot_line_count = 0; } bool gnuplot::plot_stream_event_handler (pid_t pid, int status) { bool retval = false; if (pid > 0) { if (WIFEXITED (status) || WIFSIGNALLED (status)) { gnuplot *plotter = gnuplot::lookup_by_pid (pid); // We should only print a warning or request removal of the // process from the child list if the process died // unexpectedly. If do_close is responsible for // gnuplot's death, then plotter will be 0 here and we don't // need to do anything. if (plotter) { plotter->reset_plot_stream (); warning ("connection to external plotter (pid = %d) lost --", pid); // Request removal of this PID from the list of child // processes. retval = true; } } } return retval; } void gnuplot::do_send (const std::string& cmd) { int replot_len = Vgnuplot_command_replot.length (); bool is_replot = (Vgnuplot_command_replot == cmd.substr (0, replot_len)); if (! (plot_line_count == 0 && is_replot)) do_send_raw (cmd); } void gnuplot::do_send_raw (const std::string& cmd) { if (plot_stream && *plot_stream) { *plot_stream << cmd; plot_stream->flush (); } } void gnuplot::do_clear (void) { do_send_raw ("clear\n"); // FIXME -- instead of just clearing these things, it would // be nice if we could reset things to a user-specified default // state. do_send_raw ("set title\n"); do_send_raw ("set xlabel\n"); do_send_raw ("set ylabel\n"); do_send_raw ("set nogrid\n"); do_send_raw ("set nolabel\n"); // This makes a simple `replot' not work after a `clearplot' command // has been issued. plot_line_count = 0; } void gnuplot::do_set (const string_vector& argv) { int argc = argv.length (); std::ostringstream plot_buf; if (argc > 1) { if (almost_match ("parametric", argv[1], 3)) parametric_plot = true; else if (almost_match ("noparametric", argv[1], 5)) parametric_plot = false; else if (almost_match ("term", argv[1], 1)) { gnuplot_terminal_type = ""; std::ostringstream buf; int i; for (i = 2; i < argc-1; i++) buf << argv[i] << " "; if (i < argc) buf << argv[i]; buf << Vgnuplot_command_end; gnuplot_terminal_type = buf.str (); } } int i; for (i = 0; i < argc-1; i++) plot_buf << argv[i] << " "; if (i < argc) plot_buf << argv[i]; plot_buf << Vgnuplot_command_end; do_send_raw (plot_buf.str ()); } void gnuplot::do_show (const string_vector& argv) { int argc = argv.length (); std::ostringstream plot_buf; int i; for (i = 0; i < argc-1; i++) plot_buf << argv[i] << " "; if (i < argc) plot_buf << argv[i]; plot_buf << Vgnuplot_command_end; do_send (plot_buf.str ()); } void gnuplot::do_plot (const string_vector& argv) { std::string s; for (int i = 1; i < argv.length (); i++) s += argv[i] + " "; try { std::string cmd = makeplot (argv[0], s); do_send (cmd); } catch (gpt_parse_error& e) { if (e.msg.empty ()) error ("could not parse plot command"); else error (e.msg.c_str ()); } } // Parse and evaluate parameter string and pass it to gnuplot pipe. std::string gnuplot::makeplot (std::string caller, std::string args) throw (gpt_parse_error) { std::string retval; YY_BUFFER_STATE bstate; bstate = yy_scan_string (args.c_str ()); yy_switch_to_buffer (bstate); std::string outstr; int ndim = 2; if (caller == "replot") { ndim = 1; outstr += Vgnuplot_command_replot + " "; } else if (caller == "plot") { ndim = 2; plot_line_count = 0; outstr += Vgnuplot_command_plot + " "; } else if (caller == "splot") { ndim = 3; plot_line_count = 0; outstr += Vgnuplot_command_splot + " "; } else throw gpt_parse_error ("unknown plot command"); gpt_quote_is_transpose = false; gpt_allow_plotkw = false; gpt_parens = 0; gpt_braces = 0; gpt_brackets = 0; int tok; tok = gptlex (); if (plottok_or_end_p (tok) && caller != "replot") throw gpt_parse_error ("must have something to plot"); while (tok) { bool title_set = false; bool using_set = false; bool style_set = false; bool axes_set = false; if (tok == START_BRACKET) { if (caller == "replot") throw gpt_parse_error ("can't specify new plot ranges with `replot' or while hold is on"); std::string xrange_start_str = read_until (colonp, tok); std::string xrange_end_str = read_until (endbracketp, tok); outstr += printrange (xrange_start_str, xrange_end_str) + " "; tok = gptlex (); if (tok == START_BRACKET) { std::string yrange_start_str = read_until (colonp, tok); std::string yrange_end_str = read_until (endbracketp, tok); outstr += printrange (yrange_start_str, yrange_end_str) + " "; tok = gptlex (); if (tok == START_BRACKET && caller == "gsplot") { std::string zrange_start_str = read_until (colonp, tok); std::string zrange_end_str = read_until (endbracketp, tok); outstr += printrange (zrange_start_str, zrange_end_str) + " "; tok = gptlex (); } } } if (plottok_or_end_p (tok)) return std::string (); else { std::string file; plot_line_count++; std::string plot_expr_str; plot_expr_str += std::string (yytext) + " "; plot_expr_str += read_until (plottok_or_end_p, tok); int status = 0; octave_value tmp_data = eval_string (plot_expr_str, true, status); if (status != 0 || ! tmp_data.is_defined ()) throw gpt_parse_error (); std::ostringstream tmp_buf; tmp_data.print_raw (tmp_buf); if (tmp_data.is_string ()) { file = file_ops::tilde_expand (tmp_data.string_value ()); // FIXME -- perhaps should check if the file exists? outstr += file + " "; } else { switch (ndim) { case 2: file = save_in_tmp_file (tmp_data, ndim); break; case 3: file = save_in_tmp_file (tmp_data, ndim, parametric_plot); break; default: gripe_2_or_3_dim_plot (); break; } if (file.length () > 0) { mark_for_deletion (file); outstr += "'" + file + "' "; } } } std::string title_str; std::string using_str; std::string style_str; std::string axes_str; bool out = false; while (tok && ! out) { switch (tok) { case COMMA: out = true; break; case TITLE: if (! title_set) title_str += handle_title (tok) + " "; else throw gpt_parse_error ("only one title option may be specified"); title_set = true; break; case USING: if (! using_set) using_str += handle_using (tok) + " "; else throw gpt_parse_error ("only one using option may be specified"); using_set = true; break; case WITH: if (! style_set) style_str += handle_style (tok) + " "; else throw gpt_parse_error ("only one style option may be specified"); style_set = true; break; case AXES: if (! axes_set) axes_str += handle_axes (tok) + " "; else throw gpt_parse_error ("only one axes option may be specified"); axes_set = true; break; default: tok = 0; break; } } if (! title_set) { std::ostringstream tmp_buf; tmp_buf << Vgnuplot_command_title << " \"line " << plot_line_count << "\" "; title_str = tmp_buf.str (); title_set = true; } // Plot parameters have to be output in this order. if (using_set) outstr += using_str; if (axes_set) outstr += axes_str; if (title_set) outstr += title_str; if (style_set) outstr += style_str; if (out) { // Saw comma on while loop. outstr += ", "; gpt_quote_is_transpose = false; gpt_allow_plotkw = false; gpt_parens = 0; gpt_braces = 0; gpt_brackets = 0; tok = gptlex (); } } outstr += Vgnuplot_command_end; return outstr; } // Title has one string expression which is evaluated and printed to the // gnuplot command string. std::string gnuplot::handle_title (int& lasttok) { int tok; std::string retstr = Vgnuplot_command_title + " "; std::string title_expr_str; title_expr_str += read_until (plottok_or_end_p, tok); int status; octave_value tmp_data = eval_string (title_expr_str, true, status); if (status != 0 || ! tmp_data.is_defined ()) throw gpt_parse_error (); std::ostringstream tmp_buf; if (tmp_data.is_string ()) { tmp_buf << '"'; tmp_data.print_raw (tmp_buf); tmp_buf << '"'; } else { warning ("line title must be a string"); tmp_buf << '"' << "line " << plot_line_count << '"'; } retstr += tmp_buf.str (); lasttok = tok; return retstr; } // The static instance of this class is here so that // gnuplot::close_all will be called when the .oct file is unloaded. class gnuplot_X { public: gnuplot_X (void) { } ~gnuplot_X (void) { gnuplot::close_all (); } }; static gnuplot_X X; static int automatic_replot (void) { Vautomatic_replot = check_preference ("automatic_replot"); return 0; } static int set_string_var (std::string& var, const char *nm) { int retval = 0; std::string s = builtin_string_variable (nm); if (s.empty ()) { gripe_invalid_value_specified (nm); retval = -1; } else var = s; return retval; } static int gnuplot_binary (void) { int status = set_string_var (Vgnuplot_binary, "gnuplot_binary"); if (status == 0) gnuplot::set_gnuplot_exe (Vgnuplot_binary); return status; } static int gnuplot_command_plot (void) { return set_string_var (Vgnuplot_command_plot, "gnuplot_command_plot"); } static int gnuplot_command_replot (void) { return set_string_var (Vgnuplot_command_replot, "gnuplot_command_replot"); } static int gnuplot_command_splot (void) { return set_string_var (Vgnuplot_command_splot, "gnuplot_command_splot"); } static int gnuplot_command_using (void) { return set_string_var (Vgnuplot_command_using, "gnuplot_command_using"); } static int gnuplot_command_with (void) { return set_string_var (Vgnuplot_command_with, "gnuplot_command_with"); } static int gnuplot_command_axes (void) { return set_string_var (Vgnuplot_command_axes, "gnuplot_command_axes"); } static int gnuplot_command_title (void) { return set_string_var (Vgnuplot_command_title, "gnuplot_command_title"); } static int gnuplot_command_end (void) { return set_string_var (Vgnuplot_command_end, "gnuplot_command_end"); } static int gnuplot_use_title_option (void) { Vgnuplot_use_title_option = check_preference ("gnuplot_use_title_option"); gnuplot::set_gnuplot_use_title_option (Vgnuplot_use_title_option); return 0; } void gnuplot::do_init (void) { // Do nothing. } void symbols_of___gnuplot_raw__ (void) { static bool gnuplot_initialized = false; if (gnuplot_initialized) return; gnuplot_initialized = true; // This is temporary. mark_as_rawcommand ("__gnuplot_plot__"); mark_as_rawcommand ("__gnuplot_set__"); mark_as_rawcommand ("__gnuplot_splot__"); mark_as_rawcommand ("__gnuplot_replot__"); if (is_builtin_variable ("automatic_replot")) automatic_replot (); else DEFVAR (automatic_replot, true, automatic_replot, "-*- texinfo -*-\n\ @defvr {Built-in Variable} automatic_replot\n\ You can tell Octave to redisplay the plot each time anything about it\n\ changes by setting the value of the builtin variable\n\ @code{automatic_replot} to a nonzero value. Although it is fairly\n\ inefficient, especially for large plots, the default value is 1 for\n\ compatibility with Matlab.\n\ @end defvr"); if (is_builtin_variable ("gnuplot_binary")) gnuplot_binary (); else DEFVAR (gnuplot_binary, GNUPLOT_BINARY, gnuplot_binary, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_binary\n\ The name of the program invoked by the plot command. The default value\n\ is @code{\"gnuplot\"}. @xref{Installation}.\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_plot")) gnuplot_command_plot (); else DEFVAR (gnuplot_command_plot, "pl", gnuplot_command_plot, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_plot\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_replot")) gnuplot_command_replot (); else DEFVAR (gnuplot_command_replot, "rep", gnuplot_command_replot, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_replot\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_splot")) gnuplot_command_splot (); else DEFVAR (gnuplot_command_splot, "sp", gnuplot_command_splot, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_splot\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_using")) gnuplot_command_using (); else DEFVAR (gnuplot_command_using, "u", gnuplot_command_using, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_using\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_with")) gnuplot_command_with (); else DEFVAR (gnuplot_command_with, "w", gnuplot_command_with, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_with\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_axes")) gnuplot_command_axes (); else DEFVAR (gnuplot_command_axes, "ax", gnuplot_command_axes, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_axes\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_title")) gnuplot_command_title (); else DEFVAR (gnuplot_command_title, "t", gnuplot_command_title, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_title\n\ @end defvr"); if (is_builtin_variable ("gnuplot_command_end")) gnuplot_command_end (); else DEFVAR (gnuplot_command_end, "\n", gnuplot_command_end, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_command_end\n\ @end defvr"); if (is_builtin_variable ("gnuplot_use_title_option")) gnuplot_use_title_option (); else DEFVAR (gnuplot_use_title_option, octave_env::have_x11_display (), gnuplot_use_title_option, "-*- texinfo -*-\n\ @defvr {Built-in Variable} gnuplot_use_title_option\n\ If nonzero, append @samp{-title \"Figure NN\"} to the gnuplot command.\n\ @end defvr"); } // ----------------------- // User-callable functions // ----------------------- DEFUN (clearplot, , , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} clearplot\n\ @deftypefnx {Built-in Function} {} clg\n\ Clear the plot window and any titles or axis labels. The name\n\ @code{clg} is aliased to @code{clearplot} for compatibility with\n\ @sc{Matlab}.\n\ @end deftypefn") { gnuplot::clear (); octave_value_list args; args(0) = "off"; feval ("hold", args); return octave_value_list (); } DEFUN (closeplot, , , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} closeplot\n\ Close stream to the @code{gnuplot} subprocess. If you are using X11,\n\ this will close the plot window.\n\ @end deftypefn") { gnuplot::close (); return octave_value_list (); } DEFUN (purge_tmp_files, , , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} purge_tmp_files\n\ Delete the temporary files created by the plotting commands.\n\ \n\ Octave creates temporary data files for @code{gnuplot} and then sends\n\ commands to @code{gnuplot} through a pipe. Octave will delete the\n\ temporary files on exit, but if you are doing a lot of plotting you may\n\ want to clean up in the middle of a session.\n\ \n\ A future version of Octave will eliminate the need to use temporary\n\ files to hold the plot data.\n\ @end deftypefn") { gnuplot::cleanup_tmp_files (); return octave_value_list (); } DEFUN (__gnuplot_raw__, args, , "-*- texinfo -*-\n\ @deftypefn {Built-in Function} {} __gnuplot_raw__ (@var{string})\n\ Send @var{string} directly to gnuplot subprocess.\n\ @end deftypefn") { if (args.length () == 1 && args(0).is_string ()) { std::string cmd = args(0).string_value (); gnuplot::send_raw (cmd); } else print_usage (); return octave_value_list (); } DEFUN (__gnuplot_set__, args, , "-*- texinfo -*-\n\ @deffn {Command} __gnuplot_set__ options\n\ Set plotting options for gnuplot\n\ @end deffn") { string_vector argv = args.make_argv ("set"); if (! error_state) gnuplot::set (argv); return octave_value_list (); } DEFCMD (__gnuplot_show__, args, , "-*- texinfo -*-\n\ @deffn {Command} __gnuplot_show__ options\n\ Show plotting options.\n\ @end deffn") { string_vector argv = args.make_argv ("show"); if (! error_state) gnuplot::show (argv); return octave_value_list (); } DEFUN (__gnuplot_plot__, args, , "Plot with gnuplot.\n") { string_vector argv = args.make_argv ("plot"); if (! error_state) gnuplot::plot (argv); return octave_value_list (); } DEFUN (__gnuplot_splot__, args, , "Plot with gnuplot.\n") { string_vector argv = args.make_argv ("splot"); if (! error_state) gnuplot::plot (argv); return octave_value_list (); } DEFUN (__gnuplot_replot__, args, , "Plot with gnuplot.\n") { string_vector argv = args.make_argv ("replot"); if (! error_state) gnuplot::plot (argv); return octave_value_list (); } /* ;;; Local Variables: *** ;;; mode: C++ *** ;;; End: *** */