2 static char *RCSid() { return RCSid("$Id: command.c,v 1.144.2.11 2008/12/12 06:57:50 sfeam Exp $"); }
5 /* GNUPLOT - command.c */
8 * Copyright 1986 - 1993, 1998, 2004 Thomas Williams, Colin Kelley
10 * Permission to use, copy, and distribute this software and its
11 * documentation for any purpose with or without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and
13 * that both that copyright notice and this permission notice appear
14 * in supporting documentation.
16 * Permission to modify the software is granted, but not the right to
17 * distribute the complete modified source code. Modifications are to
18 * be distributed as patches to the released version. Permission to
19 * distribute binaries produced by compiling modified sources is granted,
21 * 1. distribute the corresponding source modifications from the
22 * released version in the form of a patch file along with the binaries,
23 * 2. add special version identification to distinguish your version
24 * in addition to the base release version number,
25 * 3. provide your name and address as the primary contact for the
26 * support of your modified version, and
27 * 4. retain our contact information in regard to use of the base
29 * Permission to distribute the released version of the source code along
30 * with corresponding source modifications in the form of a patch file is
31 * granted with same provisions 2 through 4 for binary distributions.
33 * This software is provided "as is" without express or implied warranty
34 * to the extent permitted by applicable law.
40 * Feb 5, 1992 Jack Veenstra (veenstra@cs.rochester.edu) Added support to
41 * filter data values read from a file through a user-defined function before
42 * plotting. The keyword "thru" was added to the "plot" command. Example
43 * syntax: f(x) = x / 100 plot "test.data" thru f(x) This example divides all
44 * the y values by 100 before plotting. The filter function processes the
45 * data before any log-scaling occurs. This capability should be generalized
46 * to filter x values as well and a similar feature should be added to the
49 * 19 September 1992 Lawrence Crowl (crowl@cs.orst.edu)
50 * Added user-specified bases for log scaling.
52 * April 1999 Franz Bakan (bakan@ukezyk.desy.de)
53 * Added code to support mouse-input from OS/2 PM window
54 * Changes marked by USE_MOUSE
56 * May 1999, update by Petr Mikulik
57 * Use gnuplot's pid in shared mem name
59 * August 1999 Franz Bakan and Petr Mikulik
60 * Encapsulating read_line into a thread, acting on input when thread or
61 * gnupmdrv posts an event semaphore. Thus mousing works even when gnuplot
62 * is used as a plotting device (commands passed via pipe).
93 #define PROMPT "gnuplot> "
95 #if (defined(MSDOS) || defined(DOS386)) && defined(__TURBOC__) && !defined(_Windows)
96 unsigned _stklen = 16394; /* increase stack size */
97 #endif /* MSDOS && TURBOC */
100 # define INCL_DOSMEMMGR
101 # define INCL_DOSPROCESS
102 # define INCL_DOSSEMAPHORES
104 PVOID input_from_PM_Terminal = NULL;
105 char mouseSharedMemName[40] = "";
106 HEV semInputReady = 0; /* semaphore to be created in plot.c */
107 int thread_rl_Running = 0; /* running status */
108 int thread_rl_RetCode = -1; /* return code from readline in a thread */
115 # ifdef USE_OWN_WINSYSTEM_FUNCTION
116 static int winsystem __PROTO((const char *));
118 #endif /* _Windows */
121 # include <windows.h>
124 # include <direct.h> /* getcwd() */
128 # include <dir.h> /* setdisk() */
131 # include "win/winmain.h"
132 #endif /* _Windows */
135 int vms_vkid; /* Virtual keyboard id */
136 int vms_ktid; /* key table id, for translating keystrokes */
140 /* static prototypes */
141 static void command __PROTO((void));
142 static int changedir __PROTO((char *path));
143 static char* fgets_ipc __PROTO((char* dest, int len));
144 static int read_line __PROTO((const char *prompt));
145 static void do_system __PROTO((const char *));
146 static void test_palette_subcommand __PROTO((void));
147 static void test_time_subcommand __PROTO((void));
150 static void getparms __PROTO((char *, char **));
153 static int string_expand __PROTO((void));
154 TBOOLEAN expand_macros = FALSE;
157 struct lexical_unit *token;
158 int token_table_size;
162 size_t gp_input_line_len;
163 int inline_num; /* input line number */
165 struct udft_entry *dummy_func;
167 /* support for replot command */
169 int plot_token; /* start of 'plot' command */
171 /* flag to disable `replot` when some data are sent through stdin;
172 * used by mouse/hotkey capable terminals */
173 TBOOLEAN replot_disabled = FALSE;
176 int paused_for_mouse = 0;
179 /* output file for the print command */
180 FILE *print_out = NULL;
181 char *print_out_name = NULL;
183 /* input data, parsing variables */
185 __far int num_tokens, c_token;
187 int num_tokens, c_token;
190 static int if_depth = 0;
191 static TBOOLEAN if_condition = FALSE;
193 static int command_exit_status = 0;
195 /* support for dynamic size of input line */
199 if (gp_input_line_len == 0) {
201 gp_input_line = gp_alloc(MAX_LINE_LEN, "gp_input_line");
202 gp_input_line_len = MAX_LINE_LEN;
203 gp_input_line[0] = NUL;
206 sprintf( mouseSharedMemName, "\\SHAREMEM\\GP%i_Mouse_Input", getpid() );
207 if (DosAllocSharedMem((PVOID) & input_from_PM_Terminal,
208 mouseSharedMemName, MAX_LINE_LEN, PAG_WRITE | PAG_COMMIT))
209 fputs("command.c: DosAllocSharedMem ERROR\n",stderr);
213 gp_input_line = gp_realloc(gp_input_line, gp_input_line_len + MAX_LINE_LEN,
214 "extend input line");
215 gp_input_line_len += MAX_LINE_LEN;
216 FPRINTF((stderr, "extending input line to %d chars\n",
221 /* constant by which token table grows */
222 #define MAX_TOKENS 400
227 if (token_table_size == 0) {
229 token = (struct lexical_unit *) gp_alloc(MAX_TOKENS * sizeof(struct lexical_unit), "token table");
230 token_table_size = MAX_TOKENS;
231 /* HBB: for checker-runs: */
232 memset(token, 0, MAX_TOKENS * sizeof(*token));
234 token = gp_realloc(token, (token_table_size + MAX_TOKENS) * sizeof(struct lexical_unit), "extend token table");
235 memset(token+token_table_size, 0, MAX_TOKENS * sizeof(*token));
236 token_table_size += MAX_TOKENS;
237 FPRINTF((stderr, "extending token table to %d elements\n", token_table_size));
243 void thread_read_line()
245 thread_rl_Running = 1;
246 thread_rl_RetCode = ( read_line(PROMPT) );
247 thread_rl_Running = 0;
248 DosPostEventSem(semInputReady);
257 static char *input_line_SharedMem = NULL;
259 if (input_line_SharedMem == NULL) { /* get shared mem only once */
260 if (DosGetNamedSharedMem((PVOID) &input_line_SharedMem,
261 mouseSharedMemName, PAG_WRITE | PAG_READ))
262 fputs("readline.c: DosGetNamedSharedMem ERROR\n", stderr);
264 *input_line_SharedMem = 0;
269 /* calls int_error() if it is not happy */
270 term_check_multiplot_okay(interactive);
272 if (read_line("multiplot> "))
277 if (read_line(PROMPT))
282 if (thread_rl_Running == 0) {
283 int res = _beginthread(thread_read_line,NULL,32768,NULL);
285 fputs("error command.c could not begin thread\n",stderr);
287 /* wait until a line is read or gnupmdrv makes shared mem available */
288 DosWaitEventSem(semInputReady,SEM_INDEFINITE_WAIT);
289 DosResetEventSem(semInputReady,&u);
290 if (thread_rl_Running) {
291 if (input_line_SharedMem == NULL || !*input_line_SharedMem)
293 if (*input_line_SharedMem=='%') {
294 do_event( (struct gp_event_t*)(input_line_SharedMem+1) ); /* pass terminal's event */
295 input_line_SharedMem[0] = 0; /* discard the whole command line */
296 thread_rl_RetCode = 0;
299 if (*input_line_SharedMem &&
300 strstr(input_line_SharedMem,"plot") != NULL &&
301 (strcmp(term->name,"pm") && strcmp(term->name,"x11"))) {
302 /* avoid plotting if terminal is not PM or X11 */
303 fprintf(stderr,"\n\tCommand(s) ignored for other than PM and X11 terminals\a\n");
304 if (interactive) fputs(PROMPT,stderr);
305 input_line_SharedMem[0] = 0; /* discard the whole command line */
309 fprintf(stderr,"shared mem received: |%s|\n",input_line_SharedMem);
310 if (*input_line_SharedMem && input_line_SharedMem[strlen(input_line_SharedMem)-1] != '\n') fprintf(stderr,"\n");
312 strcpy(gp_input_line, input_line_SharedMem);
313 input_line_SharedMem[0] = 0;
314 thread_rl_RetCode = 0;
316 if (thread_rl_RetCode)
319 if (read_line(PROMPT))
321 # endif /* OS2_IPC */
322 #endif /* USE_MOUSE */
325 /* So we can flag any new output: if false at time of error,
326 * we reprint the command line before printing caret.
327 * TRUE for interactive terminals, since the command line is typed.
328 * FALSE for non-terminal stdin, so command line is printed anyway.
331 screen_ok = interactive;
343 /* Line continuation has already been handled
345 char *inlptr = gp_input_line;
347 /* Skip leading whitespace */
348 while (isspace((unsigned char) *inlptr))
351 if (inlptr != gp_input_line) {
352 /* If there was leading whitespace, copy the actual
353 * command string to the front. use memmove() because
354 * source and target may overlap */
355 memmove(gp_input_line, inlptr, strlen(inlptr));
356 /* Terminate resulting string */
357 gp_input_line[strlen(inlptr)] = NUL;
359 FPRINTF((stderr, "Input line: \"%s\"\n", gp_input_line));
362 /* Expand any string variables in the current input line.
363 * Allow up to 4 levels of recursion */
365 if (string_expand() && string_expand() && string_expand() && string_expand() && string_expand())
366 int_error(NO_CARET, "Too many levels of nested macros");
369 /* also used in load_file */
370 if (is_system(gp_input_line[0])) {
371 do_system(gp_input_line + 1);
372 if (interactive) /* 3.5 did it unconditionally */
373 (void) fputs("!\n", stderr); /* why do we need this ? */
379 num_tokens = scanner(&gp_input_line, &gp_input_line_len);
381 while (c_token < num_tokens) {
383 if (command_exit_status) {
384 command_exit_status = 0;
387 if (c_token < num_tokens) { /* something after command */
388 if (equals(c_token, ";"))
391 int_error(c_token, "';' expected");
401 char *orig_input_line = gp_strdup(gp_input_line);
403 while (gp_input_line_len < strlen(s) + 1)
405 strcpy(gp_input_line, s);
408 if (display_ipc_commands())
409 fprintf(stderr, "%s\n", s);
414 strcpy(gp_input_line, orig_input_line);
415 free(orig_input_line);
421 toggle_display_of_ipc_commands()
423 if (mouse_setting.verbose)
424 mouse_setting.verbose = 0;
426 mouse_setting.verbose = 1;
430 display_ipc_commands()
432 return mouse_setting.verbose;
436 do_string_replot(char *s)
438 char *orig_input_line = gp_strdup(gp_input_line);
440 while (gp_input_line_len < strlen(s) + 1)
442 strcpy(gp_input_line, s);
443 if (display_ipc_commands())
444 fprintf(stderr, "%s\n", s);
447 if (!replot_disabled)
450 strcpy(gp_input_line, orig_input_line);
451 free(orig_input_line);
458 #if defined(HAVE_LIBREADLINE)
459 rl_forced_update_display();
461 #if defined(HAVE_LIBEDITLINE)
462 /* FIXME: editline does not support forced update,
463 so this is probably not enough */
466 fputs(PROMPT, stderr);
471 #endif /* USE_MOUSE */
477 int start_token; /* the 1st token in the function definition */
478 struct udvt_entry *udv;
479 struct udft_entry *udf;
482 if (equals(c_token + 1, "(")) {
485 struct at_type *at_tmp;
486 char save_dummy[MAX_NUM_VAR][MAX_ID_LEN+1];
487 memcpy(save_dummy, c_dummy_var, sizeof(save_dummy));
488 start_token = c_token;
490 c_token += 2; /* skip to the next dummy */
491 copy_str(c_dummy_var[dummy_num++], c_token, MAX_ID_LEN);
492 } while (equals(c_token + 1, ",") && (dummy_num < MAX_NUM_VAR));
493 if (equals(c_token + 1, ","))
494 int_error(c_token + 2, "function contains too many parameters");
495 c_token += 3; /* skip (, dummy, ) and = */
497 int_error(c_token, "function definition expected");
498 udf = dummy_func = add_udf(start_token);
499 udf->dummy_num = dummy_num;
500 if ((at_tmp = perm_at()) == (struct at_type *) NULL)
501 int_error(start_token, "not enough memory for function");
502 if (udf->at) /* already a dynamic a.t. there */
503 free_at(udf->at); /* so free it first */
504 udf->at = at_tmp; /* before re-assigning it. */
505 memcpy(c_dummy_var, save_dummy, sizeof(save_dummy));
506 m_capture(&(udf->definition), start_token, c_token - 1);
507 dummy_func = NULL; /* dont let anyone else use our workspace */
510 char *varname = gp_input_line + token[c_token].start_index;
511 if (!strncmp(varname, "GPVAL_", 6) || !strncmp(varname, "MOUSE_", 6))
512 int_error(c_token, "Cannot set internal variables GPVAL_ and MOUSE_");
513 start_token = c_token;
515 udv = add_udv(start_token);
516 (void) const_express(&result);
517 #ifdef GP_STRING_VARS
518 /* Prevents memory leak if the variable name is re-used */
520 gpfree_string(&udv->udv_value);
522 udv->udv_value = result;
523 udv->udv_undef = FALSE;
531 char key[MAX_ID_LEN+1];
532 struct udvt_entry **udv_ptr = &first_udv;
534 while (!END_OF_COMMAND) {
535 copy_str(key, c_token, MAX_ID_LEN);
536 if (strncmp(key, "GPVAL_", 6) && strncmp(key, "MOUSE_", 6)) {
537 udv_ptr = &first_udv;
539 if (!strcmp(key, (*udv_ptr)->udv_name)) {
540 (*udv_ptr)->udv_undef = TRUE;
541 gpfree_string(&((*udv_ptr)->udv_value));
544 udv_ptr = &((*udv_ptr)->next_udv);
557 for (i = 0; i < MAX_NUM_VAR; i++)
558 c_dummy_var[i][0] = NUL; /* no dummy variables */
560 if (is_definition(c_token))
563 (*lookup_ftable(&command_ftbl[0],c_token))();
569 /* process the 'raise' or 'lower' command */
571 raise_lower_command(int lower)
575 if (END_OF_COMMAND) {
578 pm_lower_terminal_window();
581 x11_lower_terminal_group();
584 win_lower_terminal_window();
587 wxt_lower_terminal_group();
591 pm_raise_terminal_window();
594 x11_raise_terminal_group();
597 win_raise_terminal_window();
600 wxt_raise_terminal_group();
606 int negative = equals(c_token, "-");
608 if (negative || equals(c_token, "+")) c_token++;
609 if (!END_OF_COMMAND && isanumber(c_token)) {
611 number = real(const_express(&a));
616 pm_lower_terminal_window();
619 x11_lower_terminal_window(number);
622 win_lower_terminal_window();
625 wxt_lower_terminal_window(number);
629 pm_raise_terminal_window();
632 x11_raise_terminal_window(number);
635 win_raise_terminal_window();
638 wxt_raise_terminal_window(number);
645 int_error(c_token, "usage: raise {x11_plot_n}");
651 raise_lower_command(0);
657 raise_lower_command(1);
663 #define WHITE_AFTER_TOKEN(x) \
664 (' ' == gp_input_line[token[x].start_index + token[x].length] \
665 || '\t' == gp_input_line[token[x].start_index + token[x].length] \
666 || '\0' == gp_input_line[token[x].start_index + token[x].length])
668 /* process the 'bind' command */
672 char* lhs = (char*) 0;
673 char* rhs = (char*) 0;
674 TBOOLEAN allwindows = FALSE;
677 if (!END_OF_COMMAND && equals(c_token,"!")) {
683 if (!END_OF_COMMAND && almost_equals(c_token,"all$windows")) {
688 /* get left hand side: the key or key sequence */
689 if (!END_OF_COMMAND) {
690 char* first = gp_input_line + token[c_token].start_index;
691 int size = (int) (strchr(first, ' ') - first);
693 size = (int) (strchr(first, '\0') - first);
696 fprintf(stderr, "(bind_command) %s:%d\n", __FILE__, __LINE__);
699 lhs = (char*) gp_alloc(size + 1, "bind_command->lhs");
700 if (isstring(c_token)) {
701 quote_str(lhs, c_token, token_len(c_token));
704 while (!END_OF_COMMAND) {
705 copy_str(ptr, c_token, token_len(c_token) + 1);
706 ptr += token_len(c_token);
707 if (WHITE_AFTER_TOKEN(c_token)) {
716 /* get right hand side: the command. allocating the size
717 * of gp_input_line is too big, but shouldn't hurt too much. */
718 if (!END_OF_COMMAND) {
719 rhs = (char*) gp_alloc(strlen(gp_input_line) + 1, "bind_command->rhs");
720 if (isstring(c_token)) {
721 /* bind <lhs> "..." */
722 quote_str(rhs, c_token, token_len(c_token));
726 while (!END_OF_COMMAND) {
727 /* bind <lhs> ... ... ... */
728 copy_str(ptr, c_token, token_len(c_token) + 1);
729 ptr += token_len(c_token);
730 if (WHITE_AFTER_TOKEN(c_token)) {
739 FPRINTF((stderr, "(bind_command) |%s| |%s|\n", lhs, rhs));
741 /* bind_process() will eventually free lhs / rhs ! */
742 bind_process(lhs, rhs, allwindows);
745 #endif /* USE_MOUSE */
749 * Command parser functions
752 /* process the 'call' command */
756 char *save_file = NULL;
759 save_file = try_to_get_string();
762 int_error(c_token, "expecting filename");
764 gp_expand_tilde(&save_file);
765 /* Argument list follows filename */
766 load_file(loadpath_fopen(save_file, "r"), save_file, TRUE);
767 /* gp_input_line[] and token[] now destroyed! */
774 /* process the 'cd' command */
778 char *save_file = NULL;
781 save_file = try_to_get_string();
783 int_error(c_token, "expecting directory name");
785 gp_expand_tilde(&save_file);
786 if (changedir(save_file))
787 int_error(c_token, "Can't change to this directory");
792 /* process the 'clear' command */
799 if (multiplot && term->fillbox) {
800 unsigned int xx1 = (unsigned int) (xoffset * term->xmax);
801 unsigned int yy1 = (unsigned int) (yoffset * term->ymax);
802 unsigned int width = (unsigned int) (xsize * term->xmax);
803 unsigned int height = (unsigned int) (ysize * term->ymax);
804 (*term->fillbox) (0, xx1, yy1, width, height);
814 /* process the 'exit' and 'quit' commands */
818 /* If the command is "exit gnuplot" then do so */
819 if (equals(c_token+1,"gnuplot"))
822 /* else graphics will be tidied up in main */
823 command_exit_status = 1;
827 /* fit_command() is in fit.c */
830 /* help_command() is below */
833 /* process the 'history' command */
837 #if defined(READLINE) || defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
840 if (!END_OF_COMMAND && equals(c_token,"?")) {
841 static char *search_str = NULL; /* string from command line to search for */
843 /* find and show the entries */
845 m_capture(&search_str, c_token, c_token); /* reallocates memory */
846 printf ("history ?%s\n", search_str);
847 if (!history_find_all(search_str))
848 int_error(c_token,"not in history");
851 } else if (!END_OF_COMMAND && equals(c_token,"!")) {
852 char *search_str = NULL; /* string from command line to search for */
853 const char *line_to_do = NULL; /* command to execute at end if necessary */
855 static char *gpil_copy = NULL;
858 m_capture(&search_str, c_token, c_token);
859 line_to_do = history_find(search_str);
861 if (line_to_do == NULL)
862 int_error(c_token, "not in history");
864 /* Must keep current input line in case there are some remaining lines
865 * to process after a semicolon. However, could int_error() some where
866 * during do_line() so a static copy is kept.
869 gpil_copy = gp_strdup(gp_input_line);
870 c_token_copy = c_token;
872 while (gp_input_line_len < strlen(line_to_do) + 1)
874 strcpy(gp_input_line, line_to_do);
875 if (scanner(&gp_input_line, &gp_input_line_len)) {
876 if (almost_equals(0, "hi$story") && equals(1, "!"))
877 int_error(c_token-1,"petitio principii"); /* Oops... infinite loop */
879 printf(" Executing:\n\t%s\n", line_to_do);
883 /* Restore previous state of line and parser, gpil_copy will be freed next time */
884 strcpy(gp_input_line, gpil_copy);
885 num_tokens = scanner(&gp_input_line, &gp_input_line_len);
886 c_token = c_token_copy + 1;
890 int n = 0; /* print only <last> entries */
891 TBOOLEAN append = FALSE; /* rewrite output file or append it */
892 static char *name = NULL; /* name of the output file; NULL for stdout */
894 TBOOLEAN quiet = FALSE;
895 if (!END_OF_COMMAND && almost_equals(c_token,"q$uiet")) {
896 /* option quiet to suppress history entry numbers */
900 /* show history entries */
901 if (!END_OF_COMMAND && isanumber(c_token)) {
902 n = (int)real(const_express(&a));
905 if ((name = try_to_get_string())) {
906 if (!END_OF_COMMAND && almost_equals(c_token, "ap$pend")) {
911 write_history_n(n, (quiet ? "" : name), (append ? "a" : "w"));
916 int_warn(NO_CARET, "You have to compile gnuplot with builtin readline or GNU readline to enable history support.");
917 #endif /* defined(READLINE) || defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE) */
920 #define REPLACE_ELSE(tok) \
922 int idx = token[tok].start_index; \
923 token[tok].length = 1; \
924 gp_input_line[idx++] = ';'; /* e */ \
925 gp_input_line[idx++] = ' '; /* l */ \
926 gp_input_line[idx++] = ' '; /* s */ \
927 gp_input_line[idx++] = ' '; /* e */ \
931 #define PRINT_TOKEN(tok) \
934 int end_index = token[tok].start_index + token[tok].length; \
935 for (i = token[tok].start_index; i < end_index && gp_input_line[i]; i++) { \
936 fputc(gp_input_line[i], stderr); \
938 fputc('\n', stderr); \
943 /* process the 'if' command */
952 if (!equals(++c_token, "(")) /* no expression */
953 int_error(c_token, "expecting (expression)");
954 exprval = real(const_express(&t));
955 if (exprval != 0.0) {
956 /* fake the condition of a ';' between commands */
957 int eolpos = token[num_tokens - 1].start_index + token[num_tokens - 1].length;
959 token[c_token].length = 1;
960 token[c_token].start_index = eolpos + 2;
961 gp_input_line[eolpos + 2] = ';';
962 gp_input_line[eolpos + 3] = NUL;
966 while (c_token < num_tokens) {
967 /* skip over until the next command */
968 while (!END_OF_COMMAND) {
971 if (++c_token < num_tokens && (equals(c_token, "else"))) {
972 /* break if an "else" was found */
973 if_condition = FALSE;
974 --c_token; /* go back to ';' */
979 c_token = num_tokens = 0;
983 /* process the 'else' command */
988 int_error(c_token, "else without if");
994 if (TRUE == if_condition) {
995 /* First part of line was true so
996 * discard the rest of the line. */
997 c_token = num_tokens = 0;
999 REPLACE_ELSE(c_token);
1000 if_condition = TRUE;
1005 /* process the 'load' command */
1013 save_file = try_to_get_string();
1015 int_error(c_token, "expecting filename");
1016 if (c_token < num_tokens) { /* not EOL */
1017 if (!equals(c_token, ";"))
1018 int_error(c_token, "expecting end of line");
1019 else if ( c_token + 1 < num_tokens ) /* not EOL even after ';' */
1020 int_warn(c_token + 1, "ignoring rest of line");
1023 gp_expand_tilde(&save_file);
1024 fp = strcmp(save_file, "-") ? loadpath_fopen(save_file, "r") : stdout;
1025 load_file(fp, save_file, FALSE);
1026 /* gp_input_line[] and token[] now destroyed! */
1027 c_token = num_tokens = 0;
1041 /* process the 'pause' command */
1048 char *buf = gp_alloc(MAX_LINE_LEN+1, "pause argument");
1055 paused_for_mouse = 0;
1056 if (equals(c_token,"mouse")) {
1060 /* EAM FIXME - This is not the correct test; what we really want */
1061 /* to know is whether or not the terminal supports mouse feedback */
1062 /* if (term_initialised) { */
1063 if (mouse_setting.on && term) {
1064 struct udvt_entry *current;
1065 int end_condition = 0;
1067 while (!(END_OF_COMMAND)) {
1068 if (almost_equals(c_token,"key$press")) {
1069 end_condition |= PAUSE_KEYSTROKE;
1071 } else if (equals(c_token,",")) {
1073 } else if (equals(c_token,"any")) {
1074 end_condition |= PAUSE_ANY;
1076 } else if (equals(c_token,"button1")) {
1077 end_condition |= PAUSE_BUTTON1;
1079 } else if (equals(c_token,"button2")) {
1080 end_condition |= PAUSE_BUTTON2;
1082 } else if (equals(c_token,"button3")) {
1083 end_condition |= PAUSE_BUTTON3;
1085 } else if (equals(c_token,"close")) {
1086 end_condition |= PAUSE_WINCLOSE;
1093 paused_for_mouse = end_condition;
1095 paused_for_mouse = PAUSE_CLICK;
1097 /* Set the pause mouse return codes to -1 */
1098 current = add_udv_by_name("MOUSE_KEY");
1099 current->udv_undef = FALSE;
1100 Ginteger(¤t->udv_value,-1);
1101 current = add_udv_by_name("MOUSE_BUTTON");
1102 current->udv_undef = FALSE;
1103 Ginteger(¤t->udv_value,-1);
1105 int_warn(NO_CARET,"Mousing not active");
1108 sleep_time = real(const_express(&a));
1110 if (!(END_OF_COMMAND)) {
1111 if (!isstring(c_token))
1112 int_error(c_token, "expecting string");
1114 quote_str(buf, c_token, MAX_LINE_LEN);
1117 if (sleep_time >= 0)
1119 if (strcmp(term->name, "pm") != 0 || sleep_time >= 0)
1121 if (strcmp(term->name, "mtos") != 0 || sleep_time >= 0)
1122 #endif /* _Windows */
1127 if (sleep_time < 0) {
1129 if (paused_for_mouse && !graphwin.hWndGraph) {
1130 if (interactive) { /* cannot wait for Enter in a non-interactive session without the graph window */
1132 if (buf) fprintf(stderr,"%s\n", buf);
1133 fgets(tmp, 512, stdin); /* graphical window not yet initialized, wait for any key here */
1135 } else { /* pausing via graphical windows */
1136 int tmp = paused_for_mouse;
1137 if (buf && paused_for_mouse) fprintf(stderr,"%s\n", buf);
1141 bail_to_command_line();
1143 if (!graphwin.hWndGraph)
1144 bail_to_command_line();
1149 if (strcmp(term->name, "pm") == 0 && sleep_time < 0) {
1151 if ((rc = PM_pause(buf)) == 0) {
1152 /* if (!CallFromRexx)
1153 * would help to stop REXX programs w/o raising an error message
1154 * in RexxInterface() ...
1157 bail_to_command_line();
1158 } else if (rc == 2) {
1161 (void) fgets(buf, strlen(buf), stdin);
1164 #elif defined(_Macintosh)
1165 if (strcmp(term->name, "macintosh") == 0 && sleep_time < 0)
1166 Pause( (int)sleep_time );
1168 if (strcmp(term->name, "mtos") == 0) {
1169 int MTOS_pause(char *buf);
1171 if ((rc = MTOS_pause(buf)) == 0)
1173 bail_to_command_line();
1177 (void) fgets(buf, strlen(buf), stdin);
1179 } else if (strcmp(term->name, "atari") == 0) {
1180 char *line = readline("");
1184 (void) fgets(buf, strlen(buf), stdin);
1185 #elif defined(ATARI)
1186 if (strcmp(term->name, "atari") == 0) {
1187 char *line = readline("");
1191 (void) fgets(buf, strlen(buf), stdin);
1192 #else /* !(_Windows || OS2 || _Macintosh || MTOS || ATARI) */
1194 if (term && term->waitforinput) {
1195 /* term->waitforinput() will return,
1197 term->waitforinput();
1199 #endif /* USE_MOUSE */
1200 (void) fgets(buf, sizeof(buf), stdin);
1201 /* Hold until CR hit. */
1204 #endif /* USE_MOUSE */
1205 #endif /* !(_Windows || OS2 || _Macintosh || MTOS || ATARI) */
1208 GP_SLEEP(sleep_time);
1210 if (text != 0 && sleep_time >= 0)
1211 fputc('\n', stderr);
1219 /* process the 'plot' command */
1223 plot_token = c_token++;
1224 plotted_data_from_stdin = FALSE;
1227 plot_mode(MODE_PLOT);
1228 add_udv_by_name("MOUSE_X")->udv_undef = TRUE;
1229 add_udv_by_name("MOUSE_Y")->udv_undef = TRUE;
1230 add_udv_by_name("MOUSE_X2")->udv_undef = TRUE;
1231 add_udv_by_name("MOUSE_Y2")->udv_undef = TRUE;
1232 add_udv_by_name("MOUSE_BUTTON")->udv_undef = TRUE;
1233 add_udv_by_name("MOUSE_SHIFT")->udv_undef = TRUE;
1234 add_udv_by_name("MOUSE_ALT")->udv_undef = TRUE;
1235 add_udv_by_name("MOUSE_CTRL")->udv_undef = TRUE;
1243 print_set_output(char *name, TBOOLEAN append_p)
1245 if (print_out && print_out != stderr && print_out != stdout) {
1247 if (print_out_name[0] == '|') {
1248 if (0 > pclose(print_out))
1249 perror(print_out_name);
1252 if (0 > fclose(print_out))
1253 perror(print_out_name);
1257 free(print_out_name);
1259 print_out_name = NULL;
1266 if (! strcmp(name, "-")) {
1273 print_out = popen(name + 1, "w");
1277 print_out_name = name;
1282 print_out = fopen(name, append_p ? "a" : "w");
1288 print_out_name = name;
1294 if (print_out==stdout)
1296 if (!print_out || print_out==stderr || !print_out_name)
1298 return print_out_name;
1301 /* process the 'print' command */
1306 /* space printed between two expressions only */
1314 #ifdef GP_STRING_VARS
1317 if (a.type == STRING) {
1318 fputs(a.v.string_val, print_out);
1323 putc(' ', print_out);
1324 disp_value(print_out, &a, FALSE);
1330 s = try_to_get_string();
1332 fputs(s, print_out);
1336 (void) const_express(&a);
1338 putc(' ', print_out);
1339 disp_value(print_out, &a, FALSE);
1343 } while (!END_OF_COMMAND && equals(c_token, ","));
1345 (void) putc('\n', print_out);
1350 /* process the 'pwd' command */
1354 char *save_file = NULL;
1356 save_file = (char *) gp_alloc(PATH_MAX, "print current dir");
1358 GP_GETCWD(save_file, PATH_MAX);
1359 fprintf(stderr, "%s\n", save_file);
1366 /* process the 'replot' command */
1371 int_error(c_token, "no previous plot");
1372 /* Disable replot for some reason; currently used by the mouse/hotkey
1373 capable terminals to avoid replotting when some data come from stdin,
1374 i.e. when plotted_data_from_stdin==1 after plot "-".
1376 if (replot_disabled) {
1377 replot_disabled = FALSE;
1379 bail_to_command_line(); /* be silent --- don't mess the screen */
1381 int_error(c_token, "cannot replot data coming from stdin");
1384 if (!term) /* unknown terminal */
1385 int_error(c_token, "use 'set term' to set terminal type first");
1389 if (term->flags & TERM_INIT_ON_REPLOT)
1396 /* process the 'reread' command */
1400 FILE *fp = lf_top();
1402 if (fp != (FILE *) NULL)
1408 /* process the 'save' command */
1413 char *save_file = NULL;
1414 char *save_locale = NULL;
1418 what = lookup_table(&save_tbl[0], c_token);
1431 save_file = try_to_get_string();
1433 int_error(c_token, "expecting filename");
1435 if (save_file[0]=='|')
1436 fp = popen(save_file+1,"w");
1440 gp_expand_tilde(&save_file);
1441 fp = strcmp(save_file,"-") ? loadpath_fopen(save_file,"w") : stdout;
1445 os_error(c_token, "Cannot open save file");
1447 #ifdef HAVE_LOCALE_H
1448 /* Make sure that numbers in the saved gnuplot commands use standard form */
1449 if (strcmp(localeconv()->decimal_point,".")) {
1450 save_locale = gp_strdup(setlocale(LC_NUMERIC,NULL));
1451 setlocale(LC_NUMERIC,"C");
1472 #ifdef HAVE_LOCALE_H
1474 setlocale(LC_NUMERIC,save_locale);
1476 fprintf(fp, "set decimalsign locale \"%s\"\n", setlocale(LC_NUMERIC,NULL));
1477 fprintf(fp, "set decimalsign '%s'\n", decimalsign);
1483 if (save_file[0] == '|')
1494 /* process the 'screendump' command */
1496 screendump_command()
1502 fputs("screendump not implemented\n", stderr);
1507 /* set_command() is in set.c */
1509 /* 'shell' command is processed by do_shell(), see below */
1511 /* show_command() is in show.c */
1514 /* process the 'splot' command */
1518 plot_token = c_token++;
1519 plotted_data_from_stdin = FALSE;
1522 plot_mode(MODE_SPLOT);
1523 add_udv_by_name("MOUSE_X")->udv_undef = TRUE;
1524 add_udv_by_name("MOUSE_Y")->udv_undef = TRUE;
1525 add_udv_by_name("MOUSE_X2")->udv_undef = TRUE;
1526 add_udv_by_name("MOUSE_Y2")->udv_undef = TRUE;
1527 add_udv_by_name("MOUSE_BUTTON")->udv_undef = TRUE;
1534 /* process the 'system' command */
1540 cmd = try_to_get_string();
1546 /* process the 'test palette' command
1548 * note 1: it works on terminals supporting as well as not supporting pm3d
1549 * note 2: due to the call to load_file(), the rest of the current command
1550 * line after 'test palette ;' is discarded
1553 test_palette_subcommand()
1555 enum {test_palette_colors = 256};
1557 double gray, z[test_palette_colors];
1558 rgb_color rgb1[test_palette_colors];
1560 static const char pre1[] = "\
1562 uns border;uns key;set tic out;uns xtics;uns ytics;\
1563 se cbtic 0,0.1,1;se cbtic nomirr;\
1564 se xr[0:1];se yr[0:1];se zr[0:1];se cbr[0:1];\
1565 se pm3d map;set colorbox hor user orig 0.08,0.07 size 0.79,0.12;";
1566 static const char pre2[] = "splot 1/0;\n\n\n";
1567 /* note: those \n's are because of x11 terminal problems with blocking pipe */
1568 static const char pre3[] = "\
1569 se size 1,0.8;se orig 0,0.2;uns pm3d;\
1570 se key outside;se grid;se tics in;se xtics 0,0.1;se ytics 0,0.1;\
1571 se tit'R,G,B profiles of the current color palette';";
1572 static const char post[] = "\
1573 \n\n\nuns multi;se orig 0,0;se size 1,1;\n"; /* no final 'reset' in favour of mousing */
1574 int can_pm3d = (term->make_palette && term->set_color);
1575 char *order = "rgb";
1576 char *save_replot_line;
1577 TBOOLEAN save_is_3d_plot;
1579 TBOOLEAN save_is_cb_plot;
1581 FILE *f = tmpfile();
1582 char *save_locale = NULL;
1585 /* parse optional option */
1586 if (!END_OF_COMMAND) {
1587 int err = (token[c_token].length != 3);
1589 order = gp_input_line + token[c_token].start_index;
1591 err += (memchr(order, 'r', 3) == NULL);
1592 err += (memchr(order, 'g', 3) == NULL);
1593 err += (memchr(order, 'b', 3) == NULL);
1596 int_error(c_token, "combination rgb or gbr or brg etc. expected");
1600 int_error(NO_CARET, "cannot write temporary file");
1602 #ifdef HAVE_LOCALE_H
1603 /* Make sure that numbers in the saved gnuplot commands use standard form */
1604 if (strcmp(localeconv()->decimal_point,".")) {
1605 save_locale = gp_strdup(setlocale(LC_NUMERIC,NULL));
1606 setlocale(LC_NUMERIC,"C");
1610 /* generate r,g,b curves */
1611 for (i = 0; i < test_palette_colors; i++) {
1612 /* colours equidistantly from [0,1] */
1613 z[i] = (double)i / (test_palette_colors - 1);
1614 gray = (sm_palette.positive == SMPAL_NEGATIVE) ? 1-z[i] : z[i];
1615 rgb1_from_gray(gray, &rgb1[i]);
1618 /* commands to setup the test palette plot */
1619 enable_reset_palette = 0;
1620 save_replot_line = gp_strdup(replot_line);
1621 save_is_3d_plot = is_3d_plot;
1623 save_is_cb_plot = is_cb_plot;
1629 /* put inline data of the r,g,b curves */
1631 for (i=0; i<strlen(order); i++) {
1634 fputs("'-'tit'", f);
1637 fputs("red'w l 1", f);
1640 fputs("green'w l 2", f);
1643 fputs("blue'w l 3", f);
1645 } /* switch(order[i]) */
1648 for (i = 0; i < 3; i++) {
1649 int k, c = order[i];
1651 for (k = 0; k < test_palette_colors; k++) {
1652 double rgb = (c=='r')
1654 ((c=='g') ? rgb1[k].g : rgb1[k].b);
1656 fprintf(f, "%0.4f\t%0.4f\n", z[k], rgb);
1662 /* save current gnuplot 'set' status because of the tricky sets
1663 * for our temporary testing plot.
1667 #ifdef HAVE_LOCALE_H
1669 setlocale(LC_NUMERIC,save_locale);
1671 fprintf(f, "set decimalsign locale \"%s\"\n", setlocale(LC_NUMERIC,NULL));
1672 fprintf(f, "set decimalsign '%s'\n", decimalsign);
1676 /* execute all commands from the temporary file */
1678 load_file(f, NULL, FALSE); /* note: it does fclose(f) */
1680 /* enable reset_palette() and restore replot line */
1681 enable_reset_palette = 1;
1683 replot_line = save_replot_line;
1684 is_3d_plot = save_is_3d_plot;
1686 is_cb_plot = save_is_cb_plot;
1689 /* further, gp_input_line[] and token[] now destroyed! */
1690 c_token = num_tokens = 0;
1694 /* process the undocumented 'test time' command
1695 * test time 'format' 'string'
1696 * to assist testing of time routines
1699 test_time_subcommand()
1701 char *format = NULL;
1702 char *string = NULL;
1706 /* given a format and a time string, exercise the time code */
1708 if (isstring(++c_token)) {
1709 m_quote_capture(&format, c_token, c_token);
1710 if (isstring(++c_token)) {
1711 m_quote_capture(&string, c_token, c_token);
1712 memset(&tm, 0, sizeof(tm));
1713 gstrptime(string, format, &tm);
1714 secs = gtimegm(&tm);
1715 fprintf(stderr, "internal = %f - %d/%d/%d::%d:%d:%d , wday=%d, yday=%d\n",
1716 secs, tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100,
1717 tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday,
1719 memset(&tm, 0, sizeof(tm));
1721 gstrftime(string, strlen(string), format, secs);
1722 fprintf(stderr, "convert back \"%s\" - %d/%d/%d::%d:%d:%d , wday=%d, yday=%d\n",
1723 string, tm.tm_mday, tm.tm_mon + 1, tm.tm_year % 100,
1724 tm.tm_hour, tm.tm_min, tm.tm_sec, tm.tm_wday,
1728 } /* else: expecting time string */
1730 } /* else: expecting format string */
1734 /* process the 'test' command */
1740 if (END_OF_COMMAND) {
1745 what = lookup_table(&test_tbl[0], c_token);
1747 case TEST_TERMINAL: test_term(); break;
1748 case TEST_PALETTE: test_palette_subcommand(); break;
1749 case TEST_TIME: test_time_subcommand(); break;
1752 int_error(c_token, "none or keyword 'terminal' or 'palette' expected");
1754 /* don't document undocumented command :-) */
1755 int_error(c_token, "none or keyword 'terminal', 'palette' or 'time' expected");
1761 /* unset_command is in unset.c */
1764 /* process the 'update' command */
1768 /* old parameter filename */
1769 char *opfname = NULL;
1770 /* new parameter filename */
1771 char *npfname = NULL;
1774 if (!(opfname = try_to_get_string()))
1775 int_error(c_token, "Parameter filename expected");
1776 if (!END_OF_COMMAND && !(npfname = try_to_get_string()))
1777 int_error(c_token, "New parameter filename expected");
1779 update(opfname, npfname);
1785 /* process invalid commands and, on OS/2, REXX commands */
1790 if (token[c_token].is_token) {
1792 rc = ExecuteMacro(gp_input_line + token[c_token].start_index,
1793 token[c_token].length);
1795 c_token = num_tokens = 0;
1800 int_error(c_token, "invalid command");
1805 * Auxiliary routines
1808 /* used by changedir_command() */
1810 changedir(char *path)
1812 #if defined(MSDOS) || defined(WIN16) || defined(ATARI) || defined(DOS386)
1813 # if defined(__ZTC__)
1814 unsigned dummy; /* it's a parameter needed for dos_setdrive */
1817 /* first deal with drive letter */
1819 if (isalpha(path[0]) && (path[1] == ':')) {
1820 int driveno = toupper(path[0]) - 'A'; /* 0=A, 1=B, ... */
1823 (void) Dsetdrv(driveno);
1826 # if defined(__ZTC__)
1827 (void) dos_setdrive(driveno + 1, &dummy);
1830 # if (defined(MSDOS) && defined(__EMX__)) || defined(__MSC__)
1831 (void) _chdrive(driveno + 1);
1835 /* HBB: recent versions of DJGPP also have setdisk():,
1836 * so I del'ed the special code */
1837 # if ((defined(MSDOS) || defined(_Windows)) && defined(__TURBOC__)) || defined(DJGPP)
1838 (void) setdisk(driveno);
1840 path += 2; /* move past drive letter */
1842 /* then change to actual directory */
1847 return 0; /* should report error with setdrive also */
1849 #elif defined(WIN32)
1850 return !(SetCurrentDirectory(path));
1851 #elif defined(__EMX__) && defined(OS2)
1852 return _chdir2(path);
1855 #endif /* MSDOS, ATARI etc. */
1859 /* used by replot_command() */
1863 if (equals(c_token, "["))
1864 int_error(c_token, "cannot set range with replot");
1866 /* do not store directly into the replot_line string, until the
1867 * new plot line has been successfully plotted. This way,
1868 * if user makes a typo in a replot line, they do not have
1869 * to start from scratch. The replot_line will be committed
1870 * after do_plot has returned, whence we know all is well
1872 if (END_OF_COMMAND) {
1873 char *rest_args = &gp_input_line[token[c_token].start_index];
1874 size_t replot_len = strlen(replot_line);
1875 size_t rest_len = strlen(rest_args);
1877 /* preserve commands following 'replot ;' */
1878 /* move rest of input line to the start
1879 * necessary because of realloc() in extend_input_line() */
1880 memmove(gp_input_line,rest_args,rest_len+1);
1881 /* reallocs if necessary */
1882 while (gp_input_line_len < replot_len+rest_len+1)
1883 extend_input_line();
1884 /* move old rest args off begin of input line to
1885 * make space for replot_line */
1886 memmove(gp_input_line+replot_len,gp_input_line,rest_len+1);
1887 /* copy previous plot command to start of input line */
1888 memcpy(gp_input_line, replot_line, replot_len);
1890 char *replot_args = NULL; /* else m_capture will free it */
1891 int last_token = num_tokens - 1;
1893 /* length = length of old part + length of new part + ", " + \0 */
1894 size_t newlen = strlen(replot_line) + token[last_token].start_index +
1895 token[last_token].length - token[c_token].start_index + 3;
1897 m_capture(&replot_args, c_token, last_token); /* might be empty */
1898 while (gp_input_line_len < newlen)
1899 extend_input_line();
1900 strcpy(gp_input_line, replot_line);
1901 strcat(gp_input_line, ", ");
1902 strcat(gp_input_line, replot_args);
1905 plot_token = 0; /* whole line to be saved as replot line */
1908 num_tokens = scanner(&gp_input_line, &gp_input_line_len);
1909 c_token = 1; /* skip the 'plot' part */
1917 /* Is 'set view map' currently working inside 'splot' or not? Calculation of
1918 * mouse coordinates and the corresponding routines must know it, because
1919 * 'splot' can be either true 3D plot or a 2D map.
1920 * This flag is set when entering splot command and 'set view map', i.e. by
1921 * splot_map_activate(), and reset when calling splot_map_deactivate().
1923 static int splot_map_active = 0;
1924 /* Store values reset by 'set view map' during splot, used by those two
1927 static float splot_map_surface_rot_x;
1928 static float splot_map_surface_rot_z;
1929 static float splot_map_surface_scale;
1931 /* This routine is called at the beginning of 'splot'. It sets up some splot
1932 * parameters needed to present the 'set view map'.
1935 splot_map_activate()
1937 if (splot_map_active)
1939 splot_map_active = 1;
1940 /* save current values */
1941 splot_map_surface_rot_x = surface_rot_x;
1942 splot_map_surface_rot_z = surface_rot_z ;
1943 splot_map_surface_scale = surface_scale;
1944 /* set new values */
1945 surface_rot_x = 180;
1947 surface_scale = 1.3;
1948 axis_array[FIRST_Y_AXIS].range_flags ^= RANGE_REVERSE;
1949 axis_array[SECOND_Y_AXIS].range_flags ^= RANGE_REVERSE;
1950 /* note: ^ is xor */
1954 /* This routine is called when the current 'set view map' is no more needed,
1955 * i.e., when calling "plot" --- the reversed y-axis et al must still be
1956 * available for mousing.
1959 splot_map_deactivate()
1961 if (!splot_map_active)
1963 splot_map_active = 0;
1964 /* restore the original values */
1965 surface_rot_x = splot_map_surface_rot_x;
1966 surface_rot_z = splot_map_surface_rot_z;
1967 surface_scale = splot_map_surface_scale;
1968 axis_array[FIRST_Y_AXIS].range_flags ^= RANGE_REVERSE;
1969 axis_array[SECOND_Y_AXIS].range_flags ^= RANGE_REVERSE;
1970 /* note: ^ is xor */
1974 /* Support for input, shell, and help for various systems */
1978 # include <descrip.h>
1979 # include <rmsdef.h>
1980 # include <smgdef.h>
1981 # include <smgmsg.h>
1984 extern lib$get_input(), lib$put_output();
1985 extern smg$read_composed_line();
1986 extern sys$putmsg();
1987 extern lbr$output_help();
1992 unsigned int status[2] = { 1, 0 };
1994 static char Help[MAX_LINE_LEN+1] = "gnuplot";
1996 $DESCRIPTOR(prompt_desc, PROMPT);
1997 /* temporary fix until change to variable length */
1998 struct dsc$descriptor_s line_desc =
1999 {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, NULL};
2001 $DESCRIPTOR(help_desc, Help);
2002 $DESCRIPTOR(helpfile_desc, "GNUPLOT$HELP");
2004 /* HBB 990829: confirmed this to be used on VMS, only --> moved into
2005 * the VMS-specific section */
2013 /* please note that the vms version of read_line doesn't support variable line
2017 read_line(const char *prompt)
2019 int more, start = 0;
2020 char expand_prompt[40];
2022 current_prompt = prompt; /* HBB NEW 20040727 */
2024 prompt_desc.dsc$w_length = strlen(prompt);
2025 prompt_desc.dsc$a_pointer = (char *) prompt;
2026 strcpy(expand_prompt, "_");
2027 strncat(expand_prompt, prompt, 38);
2029 line_desc.dsc$w_length = MAX_LINE_LEN - start;
2030 line_desc.dsc$a_pointer = &gp_input_line[start];
2031 switch (status[1] = smg$read_composed_line(&vms_vkid, &vms_ktid, &line_desc, &prompt_desc, &vms_len)) {
2033 done(EXIT_SUCCESS); /* ^Z isn't really an error */
2035 case RMS$_TNS: /* didn't press return in time */
2036 vms_len--; /* skip the last character */
2037 break; /* and parse anyway */
2038 case RMS$_BES: /* Bad Escape Sequence */
2039 case RMS$_PES: /* Partial Escape Sequence */
2041 vms_len = 0; /* ignore the line */
2044 break; /* everything's fine */
2046 done(status[1]); /* give the error message */
2049 gp_input_line[start] = NUL;
2051 if (gp_input_line[start - 1] == '\\') {
2052 /* Allow for a continuation line. */
2053 prompt_desc.dsc$w_length = strlen(expand_prompt);
2054 prompt_desc.dsc$a_pointer = expand_prompt;
2058 line_desc.dsc$w_length = strlen(gp_input_line);
2059 line_desc.dsc$a_pointer = gp_input_line;
2071 int first = c_token;
2073 while (!END_OF_COMMAND)
2076 strcpy(Help, "GNUPLOT ");
2077 capture(Help + 8, first, c_token - 1, sizeof(Help) - 9);
2078 help_desc.dsc$w_length = strlen(Help);
2079 if ((vaxc$errno = lbr$output_help(lib$put_output, 0, &help_desc,
2080 &helpfile_desc, 0, lib$get_input)) != SS$_NORMAL)
2081 os_error(NO_CARET, "can't open GNUPLOT$HELP");
2083 # endif /* NO_GIH */
2092 if ((vaxc$errno = lib$spawn()) != SS$_NORMAL) {
2093 os_error(NO_CARET, "spawn error");
2099 do_system(const char *cmd)
2105 /* gp_input_line is filled by read_line or load_file, but
2106 * line_desc length is set only by read_line; adjust now
2108 line_desc.dsc$w_length = strlen(cmd);
2109 line_desc.dsc$a_pointer = (char *) cmd;
2111 if ((vaxc$errno = lib$spawn(&line_desc)) != SS$_NORMAL)
2112 os_error(NO_CARET, "spawn error");
2114 (void) putc('\n', stderr);
2127 WinHelp(textwin.hWndParent, (LPSTR) winhelpname, HELP_INDEX, (DWORD) NULL);
2130 int start = ++c_token;
2131 while (!(END_OF_COMMAND))
2133 capture(buf, start, c_token - 1, 128);
2134 WinHelp(textwin.hWndParent, (LPSTR) winhelpname, HELP_PARTIALKEY, (DWORD) buf);
2137 # endif /* NO_GIH */
2138 #endif /* _Windows */
2142 * help_command: (not VMS, although it would work) Give help to the user. It
2143 * parses the command line into helpbuf and supplies help for that string.
2144 * Then, if there are subtopics available for that key, it prompts the user
2145 * with this string. If more input is given, help_command is called
2146 * recursively, with argument 0. Thus a more specific help can be supplied.
2147 * This can be done repeatedly. If null input is given, the function returns,
2148 * effecting a backward climb up the tree.
2149 * David Kotz (David.Kotz@Dartmouth.edu) 10/89
2150 * drd - The help buffer is first cleared when called with toplevel=1.
2151 * This is to fix a bug where help is broken if ^C is pressed whilst in the
2153 * Lars - The "int toplevel" argument is gone. I have converted it to a
2156 * FIXME - helpbuf is never free()'d
2163 static char *helpbuf = NULL;
2164 static char *prompt = NULL;
2165 static int toplevel = 1;
2166 int base; /* index of first char AFTER help string */
2167 int len; /* length of current help string */
2169 TBOOLEAN only; /* TRUE if only printing subtopics */
2170 TBOOLEAN subtopics; /* 0 if no subtopics for this topic */
2171 int start; /* starting token of help string */
2172 char *help_ptr; /* name of help file */
2173 # if defined(SHELFIND)
2174 static char help_fname[256] = ""; /* keep helpfilename across calls */
2177 # if defined(ATARI) || defined(MTOS)
2178 char const *const ext[] = { NULL };
2181 if ((help_ptr = getenv("GNUHELP")) == (char *) NULL)
2183 /* if can't find environment variable then just use HELPFILE */
2185 /* patch by David J. Liu for getting GNUHELP from home directory */
2186 # if (defined(__TURBOC__) && (defined(MSDOS) || defined(DOS386))) || defined(__DJGPP__)
2187 help_ptr = HelpFile;
2189 # if defined(ATARI) || defined(MTOS)
2191 /* I hope findfile really can accept a NULL argument ... */
2192 if ((help_ptr = findfile(HELPFILE, user_gnuplotpath, ext)) == NULL)
2193 help_ptr = findfile(HELPFILE, getenv("PATH"), ext);
2195 help_ptr = HELPFILE;
2198 help_ptr = HELPFILE;
2199 # endif /* ATARI || MTOS */
2200 # endif /* __TURBOC__ */
2203 /* look in the path where the executable lives */
2204 static char buf[MAXPATHLEN];
2207 _execname(buf, sizeof(buf));
2209 ptr=strrchr(buf, '/');
2212 strcat(buf, HELPFILE);
2216 help_ptr = HELPFILE;
2219 /* end of patch - DJL */
2221 # else /* !SHELFIND */
2222 /* try whether we can find the helpfile via shell_find. If not, just
2223 use the default. (tnx Andreas) */
2225 if (!strchr(HELPFILE, ':') && !strchr(HELPFILE, '/') &&
2226 !strchr(HELPFILE, '\\')) {
2227 if (strlen(help_fname) == 0) {
2228 strcpy(help_fname, HELPFILE);
2229 if (shel_find(help_fname) == 0) {
2230 strcpy(help_fname, HELPFILE);
2233 help_ptr = help_fname;
2235 help_ptr = HELPFILE;
2237 # endif /* !SHELFIND */
2239 /* Since MSDOS DGROUP segment is being overflowed we can not allow such */
2240 /* huge static variables (1k each). Instead we dynamically allocate them */
2241 /* on the first call to this function... */
2242 if (helpbuf == NULL) {
2243 helpbuf = gp_alloc(MAX_LINE_LEN, "help buffer");
2244 prompt = gp_alloc(MAX_LINE_LEN, "help prompt");
2245 helpbuf[0] = prompt[0] = 0;
2248 helpbuf[0] = prompt[0] = 0; /* in case user hit ^c last time */
2250 /* if called recursively, toplevel == 0; toplevel must == 1 if called
2251 * from command() to get the same behaviour as before when toplevel
2252 * supplied as function argument
2256 len = base = strlen(helpbuf);
2260 /* find the end of the help command */
2261 while (!(END_OF_COMMAND))
2264 /* copy new help input into helpbuf */
2266 helpbuf[len++] = ' '; /* add a space */
2267 capture(helpbuf + len, start, c_token - 1, MAX_LINE_LEN - len);
2268 squash_spaces(helpbuf + base); /* only bother with new stuff */
2269 lower_case(helpbuf + base); /* only bother with new stuff */
2270 len = strlen(helpbuf);
2272 /* now, a lone ? will print subtopics only */
2273 if (strcmp(helpbuf + (base ? base + 1 : 0), "?") == 0) {
2274 /* subtopics only */
2277 helpbuf[base] = NUL; /* cut off question mark */
2279 /* normal help request */
2284 switch (help(helpbuf, help_ptr, &subtopics)) {
2286 /* already printed the help info */
2287 /* subtopics now is true if there were any subtopics */
2291 if (subtopics && !only) {
2292 /* prompt for subtopic with current help string */
2294 strcpy (prompt, "Subtopic of ");
2295 strncat (prompt, helpbuf, MAX_LINE_LEN - 16);
2296 strcat (prompt, ": ");
2298 strcpy(prompt, "Help topic: ");
2300 num_tokens = scanner(&gp_input_line, &gp_input_line_len);
2302 more_help = !(END_OF_COMMAND);
2306 /* base for next level is all of current helpbuf */
2311 } while (more_help);
2316 printf("Sorry, no help for '%s'\n", helpbuf);
2322 int_error(NO_CARET, "Impossible case in switch");
2326 helpbuf[base] = NUL; /* cut it off where we started */
2328 #endif /* !NO_GIH */
2333 do_system(const char *cmd)
2336 static char *parms[80];
2339 getparms(input_line + 1, parms);
2340 fexecv(parms[0], parms);
2341 # elif (defined(ATARI) && defined(__GNUC__))
2342 /* || (defined(MTOS) && defined(__GNUC__)) */
2343 /* use preloaded shell, if available */
2344 short (*shell_p) (char *command);
2350 ssp = (void *) Super(NULL);
2351 shell_p = *(short (**)(char *)) 0x4f6;
2354 /* this is a bit strange, but we have to have a single if */
2359 # elif defined(_Windows) && defined(USE_OWN_WINSYSTEM_FUNCTION)
2363 # else /* !(AMIGA_AC_5 || ATARI && __GNUC__ || _Windows) */
2365 * OS/2 related note: cmd.exe returns 255 if called w/o argument.
2366 * i.e. calling a shell by "!" will always end with an error message.
2367 * A workaround has to include checking for EMX,OS/2, two environment
2373 # endif /* !(AMIGA_AC_5 || ATARI&&__GNUC__ || _Windows) */
2378 /******************************************************************************
2379 * Parses the command string (for fexecv use) and converts the first token
2381 *****************************************************************************/
2383 getparms(char *command, char **parms)
2385 static char strg0[256];
2386 int i = 0, j = 0, k = 0; /* A bunch of indices */
2388 while (command[j] != NUL) { /* Loop on string characters */
2389 parms[k++] = strg0 + i;
2390 while (command[j] == ' ')
2392 while (command[j] != ' ' && command[j] != NUL) {
2393 if (command[j] == '"') { /* Get quoted string */
2395 strg0[i++] = command[j++];
2396 } while (command[j] != '"' && command[j] != NUL);
2398 strg0[i++] = command[j++];
2400 if (strg0[i] != NUL)
2401 strg0[i++] = NUL; /* NUL terminate every token */
2405 /* Convert to lower case */
2406 /* FIXME HBB 20010621: do we really want to stop on char *before*
2407 * the actual end of the string strg0[]? */
2408 for (k=0; strg0[k+1] != NUL; k++)
2409 if (strg0[k] >= 'A' && (strg0[k] <= 'Z'))
2410 strg0[k] += ('a' - 'A');
2413 # endif /* AMIGA_AC_5 */
2416 # if defined(READLINE) || defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
2417 /* keep some compilers happy */
2418 static char *rlgets __PROTO((char *s, size_t n, const char *prompt));
2421 rlgets(char *s, size_t n, const char *prompt)
2423 static char *line = (char *) NULL;
2424 static int leftover = -1; /* index of 1st char leftover from last call */
2426 if (leftover == -1) {
2427 /* If we already have a line, first free it */
2428 if (line != (char *) NULL) {
2431 /* so that ^C or int_error during readline() does
2432 * not result in line being free-ed twice */
2434 line = readline_ipc((interactive) ? prompt : "");
2436 /* If it's not an EOF */
2437 if (line && *line) {
2438 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
2440 /* Initialize readline history functions */
2443 /* search in the history for entries containing line.
2444 * They may have other tokens before and after line, hence
2445 * the check on strcmp below. */
2446 found = history_search(line, -1);
2447 if (found != -1 && !strcmp(current_history()->line,line)) {
2448 /* this line is already in the history, remove the earlier entry */
2449 #if defined(HAVE_LIBREADLINE)
2450 HIST_ENTRY *removed = remove_history(where_history());
2451 /* according to history docs we are supposed to free the stuff */
2452 if (removed->line) free(removed->line);
2453 if (removed->data) free(removed->data);
2456 remove_history(where_history());
2457 #endif /* !HAVE_LIBREADLINE */
2460 # else /* !HAVE_LIBREADLINE && !HAVE_LIBEDITLINE */
2466 /* s will be NUL-terminated here */
2467 safe_strncpy(s, line + leftover, n);
2468 leftover += strlen(s);
2469 if (line[leftover] == NUL)
2475 # endif /* READLINE || HAVE_LIBREADLINE */
2478 # if defined(MSDOS) || defined(_Windows) || defined(DOS386)
2486 # if defined(_Windows)
2487 if (WinExec(user_shell, SW_SHOWNORMAL) <= 32)
2488 # elif defined(DJGPP)
2489 if (system(user_shell) == -1)
2491 if (spawnl(P_WAIT, user_shell, NULL) == -1)
2492 # endif /* !(_Windows || DJGPP) */
2493 os_error(NO_CARET, "unable to spawn shell");
2497 # elif defined(AMIGA_SC_6_1)
2506 if (system(user_shell))
2507 os_error(NO_CARET, "system() failed");
2509 (void) putc('\n', stderr);
2521 if (system(user_shell) == -1)
2522 os_error(NO_CARET, "system() failed");
2525 (void) putc('\n', stderr);
2530 /* plain old Unix */
2532 #define EXEC "exec "
2536 static char exec[100] = EXEC;
2542 if (system(safe_strncpy(&exec[sizeof(EXEC) - 1], user_shell,
2543 sizeof(exec) - sizeof(EXEC) - 1)))
2544 os_error(NO_CARET, "system() failed");
2546 (void) putc('\n', stderr);
2549 # endif /* !MSDOS */
2551 /* read from stdin, everything except VMS */
2553 # if !defined(READLINE) && !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDITLINE)
2554 # if (defined(MSDOS) || defined(DOS386)) && !defined(_Windows) && !defined(__EMX__) && !defined(DJGPP)
2556 /* if interactive use console IO so CED will work */
2558 #define PUT_STRING(s) cputs(s)
2559 #define GET_STRING(s,l) ((interactive) ? cgets_emu(s,l) : fgets(s,l,stdin))
2562 /* cgets implemented using dos functions */
2563 /* Maurice Castro 22/5/91 */
2564 static char *doscgets __PROTO((char *));
2571 /* protect and preserve segments - call dos to do the dirty work */
2580 /* check for a carriage return and then clobber it with a null */
2581 if (s[s[1] + 2] == '\r')
2584 /* return the input string */
2587 # endif /* __TURBOC__ */
2595 bdos(0x02, s[i++], NULL);
2601 bdosx(0x0A, s, NULL);
2603 if (s[s[1] + 2] == '\r')
2606 /* return the input string */
2609 # endif /* __ZTC__ */
2611 /* emulate a fgets like input function with DOS cgets */
2613 cgets_emu(char *str, int len)
2615 static char buffer[128] = "";
2616 static int leftover = 0;
2618 if (buffer[leftover] == NUL) {
2625 fputc('\n', stderr);
2626 if (buffer[2] == 26)
2630 safe_strncpy(str, buffer + leftover, len);
2631 leftover += strlen(str);
2634 # else /* !plain DOS */
2636 # define PUT_STRING(s) fputs(s, stderr)
2637 # define GET_STRING(s,l) fgets(s, l, stdin)
2639 # endif /* !plain DOS */
2640 # endif /* !READLINE && !HAVE_LIBREADLINE) */
2642 /* this function is called for non-interactive operation. Its usage is
2643 * like fgets(), but additionally it checks for ipc events from the
2644 * terminals waitforinput() (if USE_MOUSE, and terminal is
2645 * mouseable). This function will be used when reading from a pipe.
2646 * fgets() reads in at most one less than size characters from stream and
2647 * stores them into the buffer pointed to by s.
2648 * Reading stops after an EOF or a newline. If a newline is read, it is
2649 * stored into the buffer. A '\0' is stored after the last character in
2653 char *dest, /* string to fill */
2654 int len) /* size of it */
2657 if (term && term->waitforinput) {
2658 /* This a mouseable terminal --- must expect input from it */
2659 int c; /* char got from waitforinput() */
2660 size_t i=0; /* position inside dest */
2663 for (i=0; i < len-1; i++) {
2664 c = term->waitforinput();
2669 } else if (EOF == c) {
2680 return fgets(dest, len, stdin);
2683 /* Non-VMS version */
2685 read_line(const char *prompt)
2688 TBOOLEAN more = FALSE;
2691 current_prompt = prompt; /* HBB NEW 20040727 */
2693 # if !defined(READLINE) && !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDITLINE)
2696 # endif /* no READLINE */
2699 /* grab some input */
2700 # if defined(READLINE) || defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
2702 ? rlgets(gp_input_line + start, gp_input_line_len - start,
2703 ((more) ? "> " : prompt))
2704 : fgets_ipc(gp_input_line + start, gp_input_line_len - start)
2706 # else /* !(READLINE || HAVE_LIBREADLINE) */
2707 if (GET_STRING(gp_input_line + start, gp_input_line_len - start)
2709 # endif /* !(READLINE || HAVE_LIBREADLINE) */
2713 (void) putc('\n', stderr);
2714 gp_input_line[start] = NUL;
2716 if (start > 0) /* don't quit yet - process what we have */
2719 return (1); /* exit gnuplot */
2721 /* normal line input */
2722 /* gp_input_line must be NUL-terminated for strlen not to pass the
2723 * the bounds of this array */
2724 last = strlen(gp_input_line) - 1;
2726 if (gp_input_line[last] == '\n') { /* remove any newline */
2727 gp_input_line[last] = NUL;
2728 /* Watch out that we don't backup beyond 0 (1-1-1) */
2731 } else if (last + 2 >= gp_input_line_len) {
2732 extend_input_line();
2733 /* read rest of line, don't print "> " */
2737 /* else fall through to continuation handling */
2738 } /* if(grow buffer?) */
2739 if (gp_input_line[last] == '\\') {
2740 /* line continuation */
2748 # if !defined(READLINE) && !defined(HAVE_LIBREADLINE) && !defined(HAVE_LIBEDITLINE)
2749 if (more && interactive)
2758 #if defined(_Windows)
2759 # if defined(USE_OWN_WINSYSTEM_FUNCTION)
2760 /* there is a system like call on MS Windows but it is a bit difficult to
2761 use, so we will invoke the command interpreter and use it to execute the
2764 winsystem(const char *s)
2770 /* get COMSPEC environment variable */
2773 GetEnvironmentVariable("COMSPEC", envbuf, 80);
2775 comspec = "\\command.com";
2779 p = GetDOSEnvironment();
2780 comspec = "\\command.com";
2782 if (!strncmp(p, "COMSPEC=", 8)) {
2789 /* if the command is blank we must use command.com */
2791 while ((*p == ' ') || (*p == '\n') || (*p == '\r'))
2794 WinExec(comspec, SW_SHOWNORMAL);
2796 /* attempt to run the windows/dos program via windows */
2797 if (WinExec(s, SW_SHOWNORMAL) <= 32) {
2798 /* attempt to run it as a dos program from command line */
2799 execstr = gp_alloc(strlen(s) + strlen(comspec) + 6,
2800 "winsystem cmdline");
2801 strcpy(execstr, comspec);
2802 strcat(execstr, " /c ");
2804 WinExec(execstr, SW_SHOWNORMAL);
2809 /* regardless of the reality return OK - the consequences of */
2810 /* failure include shutting down Windows */
2811 return (0); /* success */
2813 # endif /* USE_OWN_WINSYSTEM_FUNCTION */
2816 call_kill_pending_Pause_dialog()
2818 kill_pending_Pause_dialog();
2820 #endif /* _Windows */
2824 * Walk through the input line looking for string variables preceded by @.
2825 * Replace the characters @<varname> with the contents of the string.
2826 * Anything inside quotes is not expanded.
2829 #define COPY_CHAR gp_input_line[o++] = *c; \
2830 after_backslash = FALSE;
2834 TBOOLEAN in_squote = FALSE;
2835 TBOOLEAN in_dquote = FALSE;
2836 TBOOLEAN after_backslash = FALSE;
2837 TBOOLEAN in_comment= FALSE;
2845 struct udvt_entry *udv;
2847 /* Most lines have no macros */
2848 if (!strchr(gp_input_line,'@'))
2851 temp_string = gp_alloc(gp_input_line_len,"string variable");
2852 len = strlen(gp_input_line);
2853 if (len >= gp_input_line_len) len = gp_input_line_len-1;
2854 strncpy(temp_string,gp_input_line,len);
2855 temp_string[len] = '\0';
2857 for (c=temp_string; len && c && *c; c++, len--) {
2859 case '@': /* The only tricky bit */
2860 if (!in_squote && !in_dquote && !in_comment && isalpha(c[1])) {
2861 /* Isolate the udv key as a null-terminated substring */
2863 while (isalnum(*c) || (*c=='_')) c++;
2864 temp_char = *c; *c = '\0';
2865 /* Look up the key and restore the original following char */
2866 udv = add_udv_by_name(m);
2867 if (udv && udv->udv_value.type == STRING) {
2869 m = udv->udv_value.v.string_val;
2870 FPRINTF((stderr,"Replacing @%s with \"%s\"\n",udv->udv_name,m));
2871 while (strlen(m) + o + len > gp_input_line_len)
2872 extend_input_line();
2874 gp_input_line[o++] = (*m++);
2876 int_warn( NO_CARET, "%s is not a string variable",m);
2884 if (!after_backslash)
2885 in_dquote = !in_dquote;
2888 in_squote = !in_squote;
2892 after_backslash = !after_backslash;
2893 gp_input_line[o++] = *c; break;
2895 if (!in_squote && !in_dquote)
2901 gp_input_line[o] = '\0';
2906 "After string substitution command line is:\n\t%s\n",
2913 /* much more than what can be useful */
2914 #define MAX_TOTAL_LINE_LEN (1024 * MAX_LINE_LEN)
2917 do_system_func(const char *cmd, char **output)
2920 #if defined(VMS) || defined(PIPES) || (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
2924 int result_allocated, result_pos;
2929 # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
2930 char *atari_tmpfile, *atari_cmd;
2933 struct dsc$descriptor_s pgmdsc = {0, DSC$K_DTYPE_T, DSC$K_CLASS_S, 0};
2934 static $DESCRIPTOR(lognamedsc, "PLOT$MAILBOX");
2937 cmd_len = strlen(cmd);
2941 pgmdsc.dsc$a_pointer = cmd;
2942 pgmdsc.dsc$w_length = cmd_len;
2943 if (!((vaxc$errno = sys$crembx(0, &chan, 0, 0, 0, 0, &lognamedsc)) & 1))
2944 os_error(NO_CARET, "sys$crembx failed");
2946 if (!((vaxc$errno = lib$spawn(&pgmdsc, 0, &lognamedsc, &one)) & 1))
2947 os_error(NO_CARET, "lib$spawn failed");
2949 if ((f = fopen("PLOT$MAILBOX", "r")) == NULL)
2950 os_error(NO_CARET, "mailbox open failed");
2951 # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
2952 if (system(NULL) == 0)
2953 os_error(NO_CARET, "no command shell");
2954 atari_tmpfile = tmpnam(NULL);
2955 atari_cmd = gp_alloc(cmd_len + 5 + strlen(atari_tmpfile),
2957 strcpy(atari_cmd, cmd);
2958 strcat(atari_cmd, " >> ");
2959 strcat(atari_cmd, atari_tmpfile);
2962 if ((f = fopen(atari_tmpfile, "r")) == NULL)
2963 # elif defined(AMIGA_AC_5)
2964 if ((fd = open(cmd, "O_RDONLY")) == -1)
2965 # else /* everyone else */
2966 if ((f = popen(cmd, "r")) == NULL)
2967 os_error(NO_CARET, "popen failed");
2968 # endif /* everyone else */
2972 result_allocated = MAX_LINE_LEN;
2973 result = gp_alloc(MAX_LINE_LEN, "do_system_func");
2976 # if defined(AMIGA_AC_5)
2978 if (read(fd, &ch, 1) != 1)
2982 if ((c = getc(f)) == EOF)
2984 # endif /* !AMIGA_AC_5 */
2986 result[result_pos++] = c;
2987 if ( result_pos == result_allocated ) {
2988 if ( result_pos >= MAX_TOTAL_LINE_LEN ) {
2991 "*very* long system call output has been truncated");
2994 result = gp_realloc(result, result_allocated + MAX_LINE_LEN,
2995 "extend in do_system_func");
2996 result_allocated += MAX_LINE_LEN;
3000 result[result_pos] = NUL;
3005 # elif (defined(ATARI) || defined(MTOS)) && defined(__PUREC__)
3007 (void) unlink(atari_tmpfile);
3008 # else /* Rest of the world */
3012 result = gp_realloc(result, strlen(result)+1, "do_system_func");
3016 #else /* VMS || PIPES || ATARI && PUREC */
3018 int_warn(NO_CARET, "system evaluation not supported by %s", OS);
3019 *output = gp_strdup("");
3022 #endif /* VMS || PIPES || ATARI && PUREC */