Initial release of Maemo 5 port of gnuplot
[gnuplot] / src / plot.c
1 #ifndef lint
2 static char *RCSid() { return RCSid("$Id: plot.c,v 1.90.2.5 2008/12/12 06:57:50 sfeam Exp $"); }
3 #endif
4
5 /* GNUPLOT - plot.c */
6
7 /*[
8  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
9  *
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.
15  *
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,
20  * provided you
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
28  *    software.
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.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 #include "syscfg.h"
38 #include "plot.h"
39
40 #include "alloc.h"
41 #include "command.h"
42 #include "eval.h"
43 #include "fit.h"
44 #include "gp_hist.h"
45 #include "misc.h"
46 #include "readline.h"
47 #include "setshow.h"
48 #include "term_api.h"
49 #include "util.h"
50 #include "variable.h"
51 #include "version.h"
52
53 #include <signal.h>
54 #include <setjmp.h>
55
56 #ifdef OS2 /* os2.h required for gpexecute.h */
57 # define INCL_DOS
58 # define INCL_REXXSAA
59 # ifdef OS2_IPC
60 #  define INCL_DOSSEMAPHORES
61 # endif
62 # include <os2.h>
63 #endif /* OS2 */
64
65 #ifdef USE_MOUSE
66 # include "mouse.h" /* for mouse_setting */
67 # include "gpexecute.h"
68 #endif
69
70 /* on OS/2 this is needed even without USE_MOUSE */
71 #if defined(OS2_IPC) && !defined(USE_MOUSE)
72 # include "gpexecute.h"
73 #endif
74
75 /* Used nowhere else */
76 #ifdef HAVE_SYS_UTSNAME_H
77 # include <sys/utsname.h>
78 #endif
79
80 #if defined(MSDOS) || defined(DOS386) || defined(__EMX__)
81 # include <io.h>
82 #endif
83
84 #ifdef VMS
85 # ifndef __GNUC__
86 #  include <unixio.h>
87 # endif
88 # include <smgdef.h>
89 # include <ssdef.h>
90 extern int vms_vkid;
91 extern smg$create_virtual_keyboard();
92 extern int vms_ktid;
93 extern smg$create_key_table();
94 #endif /* VMS */
95
96 #ifdef AMIGA_SC_6_1
97 # include <proto/dos.h>
98 #endif
99
100 #ifdef _Windows
101 # include <windows.h>
102 # ifndef SIGINT
103 #  define SIGINT 2              /* for MSC */
104 # endif
105 # include "win/wgnuplib.h"
106 # include "win/wcommon.h"
107 #endif /* _Windows */
108
109 /* GNU readline
110  * Only required by two files directly,
111  * so I don't put this into a header file. -lh
112  */
113 #ifdef HAVE_LIBREADLINE
114 # ifdef GNUPLOT_HISTORY
115 #  include <readline/tilde.h>
116 # endif
117 extern int rl_complete_with_tilde_expansion;
118 #endif 
119
120 /* BSD editline
121 */
122 #ifdef HAVE_LIBEDITLINE
123 # include <editline/readline.h>
124 #endif
125
126 /* enable gnuplot history with readline */
127 #ifdef GNUPLOT_HISTORY
128 # ifndef GNUPLOT_HISTORY_FILE
129 #  define GNUPLOT_HISTORY_FILE "~/.gnuplot_history"
130 # endif
131 /*
132  * The next variable is a pointer to the value returned from 'tilde_expand()'.
133  * This function expands '~' to the user's home directory, or $HOME, with
134  * UN*X, AmigaOS, MSDOS.
135  * Depending on your OS you have to make sure that the "$HOME" environment
136  * variable exitsts.  You are responsible for valid values.
137  */
138 static char *expanded_history_filename;
139
140 static void wrapper_for_write_history __PROTO((void));
141
142 #endif                          /* GNUPLOT_HISTORY */
143
144 TBOOLEAN interactive = TRUE;    /* FALSE if stdin not a terminal */
145 static TBOOLEAN noinputfiles = TRUE; /* FALSE if there are script files */
146 TBOOLEAN persist_cl = FALSE; /* TRUE if -persist is parsed in the command line */
147
148 /* user home directory */
149 static const char *user_homedir = NULL;
150
151 /* user shell */
152 const char *user_shell = NULL;
153
154 #if defined(ATARI) || defined(MTOS)
155 const char *user_gnuplotpath = NULL;
156 #endif
157
158 #ifdef X11
159 extern int X11_args __PROTO((int, char **)); /* FIXME: defined in term/x11.trm */
160 #endif
161
162 /* patch to get home dir, see command.c */
163 #if (defined (__TURBOC__) && (defined (MSDOS) || defined(DOS386))) || defined(DJGPP)
164 # include <dir.h>               /* MAXPATH */
165 char HelpFile[MAXPATH];
166 #endif /*   - DJL */
167
168 /* a longjmp buffer to get back to the command line */
169 /* FIXME HBB 20001103: should probably just use GPFAR, rather than
170  * check for _Windows */
171 #ifdef _Windows
172 static JMP_BUF far command_line_env;
173 #else
174 static JMP_BUF command_line_env;
175 #endif
176
177 static void load_rcfile __PROTO((void));
178 static RETSIGTYPE inter __PROTO((int anint));
179 static void init_memory __PROTO((void));
180
181 static int exit_status = EXIT_SUCCESS;
182
183 #ifdef OS2
184 # include <process.h>
185 static ULONG RexxInterface(PRXSTRING, PUSHORT, PRXSTRING);
186 TBOOLEAN CallFromRexx = FALSE;
187 #endif /* OS2 */
188
189 #if defined(ATARI) || defined(MTOS)
190 /* For findfile () (?) */
191 # include <support.h>
192 void appl_exit(void);
193 void MTOS_open_pipe(void);
194 extern int aesid;
195 #endif
196
197 static RETSIGTYPE
198 inter(int anint)
199 {
200     (void) anint;               /* aovid -Wunused warning */
201     (void) signal(SIGINT, (sigfunc) inter);
202
203 #ifndef DOSX286
204     (void) signal(SIGFPE, SIG_DFL);     /* turn off FPE trapping */
205 #endif
206
207 #ifdef OS2
208     if (!strcmp(term->name,"pm")) {
209         PM_intc_cleanup();
210         /* ??
211           putc('\n', stderr);
212           LONGJMP(command_line_env, TRUE);
213          */
214     } else
215 #endif
216     {
217     term_reset();
218     (void) putc('\n', stderr);
219     LONGJMP(command_line_env, TRUE);    /* return to prompt */
220     }
221 }
222
223 #ifdef LINUXVGA
224 /* utility functions to ensure that setuid gnuplot
225  * assumes root privileges only for those parts
226  * of the code which require root rights.
227  *
228  * By "Dr. Werner Fink" <werner@suse.de>
229  */
230 static uid_t euid, ruid;
231 static gid_t egid, rgid;
232 static int asked_privi = 0;
233
234 void
235 drop_privilege()
236 {
237     if (!asked_privi) {
238         euid = geteuid();
239         egid = getegid();
240         ruid = getuid();
241         rgid = getgid();
242         asked_privi = 1;
243     }
244     if (setegid(rgid) == -1)
245         (void) fprintf(stderr, "setegid(%d): %s\n",
246                        (int) rgid, strerror(errno));
247     if (seteuid(ruid) == -1)
248         (void) fprintf(stderr, "seteuid(%d): %s\n",
249                        (int) ruid, strerror(errno));
250 }
251
252 void
253 take_privilege()
254 {
255     if (!asked_privi) {
256         euid = geteuid();
257         egid = getegid();
258         ruid = getuid();
259         rgid = getgid();
260         asked_privi = 1;
261     }
262     if (setegid(egid) == -1)
263         (void) fprintf(stderr, "setegid(%d): %s\n",
264                        (int) egid, strerror(errno));
265     if (seteuid(euid) == -1)
266         (void) fprintf(stderr, "seteuid(%d): %s\n",
267                        (int) euid, strerror(errno));
268 }
269
270 #endif /* LINUXVGA */
271
272 /* a wrapper for longjmp so we can keep everything local */
273 void
274 bail_to_command_line()
275 {
276 #ifdef _Windows
277     call_kill_pending_Pause_dialog();
278 #endif
279     LONGJMP(command_line_env, TRUE);
280 }
281
282 #if defined(_Windows) || defined(_Macintosh)
283 int
284 gnu_main(int argc, char **argv)
285 #else
286 int
287 main(int argc, char **argv)
288 #endif
289 {
290     int i;
291
292 #ifdef LINUXVGA
293     LINUX_setup();              /* setup VGA before dropping privilege DBT 4/5/99 */
294     drop_privilege();
295 #endif
296 /* make sure that we really have revoked root access, this might happen if
297    gnuplot is compiled without vga support but is installed suid by mistake */
298 #ifdef __linux__
299     setuid(getuid());
300 #endif
301
302 #if defined(MSDOS) && !defined(_Windows) && !defined(__GNUC__)
303     PC_setup();
304 #endif /* MSDOS !Windows */
305
306 /* HBB: Seems this isn't needed any more for DJGPP V2? */
307 /* HBB: disable all floating point exceptions, just keep running... */
308 #if defined(DJGPP) && (DJGPP!=2)
309     _control87(MCW_EM, MCW_EM);
310 #endif
311
312 #if defined(OS2)
313     int rc;
314 #ifdef OS2_IPC
315     char semInputReadyName[40];
316     sprintf( semInputReadyName, "\\SEM32\\GP%i_Input_Ready", getpid() );
317     rc = DosCreateEventSem(semInputReadyName,&semInputReady,0,0);
318     if (rc != 0)
319       fputs("DosCreateEventSem error\n",stderr);
320 #endif
321     rc = RexxRegisterSubcomExe("GNUPLOT", (PFN) RexxInterface, NULL);
322 #endif
323
324 /* malloc large blocks, otherwise problems with fragmented mem */
325 #ifdef OSK
326     _mallocmin(102400);
327 #endif
328
329 #ifdef MALLOCDEBUG
330     malloc_debug(7);
331 #endif
332
333 /* get helpfile from home directory */
334 #ifndef DOSX286
335 # ifndef _Windows
336 #  if defined (__TURBOC__) && (defined (MSDOS) || defined(DOS386))
337     strcpy(HelpFile, argv[0]);
338     strcpy(strrchr(HelpFile, DIRSEP1), "\\gnuplot.gih");
339 #  endif                        /*   - DJL */
340 # endif                         /* !_Windows */
341 #endif /* !DOSX286 */
342 #ifdef __DJGPP__
343     {
344         char *s;
345         strcpy(HelpFile, argv[0]);
346         for (s = HelpFile; *s; s++)
347             if (*s == DIRSEP1)
348                 *s = DIRSEP2;   /* '\\' to '/' */
349         strcpy(strrchr(HelpFile, DIRSEP2), "/gnuplot.gih");
350     }                   /* Add also some "paranoid" tests for '\\':  AP */
351 #endif /* DJGPP */
352
353 #ifdef VMS
354     unsigned int status[2] = { 1, 0 };
355 #endif
356
357 #if defined(HAVE_LIBEDITLINE)
358     rl_getc_function = getc_wrapper;
359 #endif
360 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
361     using_history();
362     /* T.Walter 1999-06-24: 'rl_readline_name' must be this fix name.
363      * It is used to parse a 'gnuplot' specific section in '~/.inputrc' */
364     rl_readline_name = "Gnuplot";
365     rl_terminal_name = getenv("TERM");
366 #endif
367 #if defined(HAVE_LIBREADLINE)
368     rl_complete_with_tilde_expansion = 1;
369 #endif
370
371     for (i = 1; i < argc; i++) {
372         if (!argv[i])
373             continue;
374         if (!strcmp(argv[i], "-V") || !strcmp(argv[i], "--version")) {
375             printf("gnuplot %s patchlevel %s\n",
376                     gnuplot_version, gnuplot_patchlevel);
377             return 0;
378         } else if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) {
379             printf( "Usage: gnuplot [OPTION]... [FILE]\n"
380 #ifdef X11
381                     "for X11 options see 'help X11->command-line-options'\n"
382 #endif
383                     "  -V, --version\n"
384                     "  -h, --help\n"
385                     "  -e  \"command1; command2; ...\"\n"
386                     "gnuplot %s patchlevel %s\n"
387                     "Report bugs to %s\n",
388                     gnuplot_version, gnuplot_patchlevel, bug_email);
389             return 0;
390         }
391     }
392
393     /* the X11 terminal removes tokens that it recognizes from argv.
394      * We have to parse -persist for the wxWidgets terminal before it happens, and
395      * keep that value for later use */
396     i=0;
397     while (i<argc) {
398         if (!argv[i]) {
399             ++i;
400             continue;
401         }
402         if (!strcmp(argv[i], "-persist")) {
403             FPRINTF((stderr,"'persist' command line option recognized"));
404             persist_cl = TRUE;
405 # ifdef X11
406             ++i;
407 # else
408             --argc;
409             ++argv;
410 # endif
411             break;
412         } else
413             ++i;
414     }
415
416 #ifdef X11
417     {
418         int n = X11_args(argc, argv);
419         argv += n;
420         argc -= n;
421     }
422 #endif
423
424 #ifdef APOLLO
425     apollo_pfm_catch();
426 #endif
427
428 /* moved to ATARI_init in atariaes.trm */
429 /* #ifdef ATARI
430    void application_init(void);
431    application_init();
432    #endif */
433
434 #ifdef MTOS
435     MTOS_open_pipe();
436 #endif
437
438     setbuf(stderr, (char *) NULL);
439
440 #ifdef HAVE_SETVBUF
441     /* this was once setlinebuf(). Docs say this is
442      * identical to setvbuf(,NULL,_IOLBF,0), but MS C
443      * faults this (size out of range), so we try with
444      * size of 1024 instead. [SAS/C does that, too. -lh]
445      * Failing this, I propose we just make the call and
446      * ignore the return : its probably not a big deal
447      */
448     if (setvbuf(stdout, (char *) NULL, _IOLBF, (size_t) 1024) != 0)
449         (void) fputs("Could not linebuffer stdout\n", stderr);
450
451 #ifdef X11
452     /* This call used to be in x11.trm, with the following comment:
453      *   Multi-character inputs like escape sequences but also mouse-pasted
454      *   text got buffered and therefore didn't trigger the select() function
455      *   in X11_waitforinput(). Switching to unbuffered input solved this.
456      *   23 Jan 2002 (joze)
457      * But switching to unbuffered mode causes all characters in the input
458      * buffer to be lost. So the only safe time to do it is on program entry.
459      * The #ifdef X11 is probably unnecessary, but makes the change minimal.
460      * Do any non-X platforms suffer from the same problem?
461      * EAM - Jan 2004.
462      */
463     setvbuf(stdin, (char *) NULL, _IONBF, 0);
464 #endif
465
466 #endif
467
468     gpoutfile = stdout;
469
470     /* Initialize pre-loaded user variables */
471     (void) Gcomplex(&udv_pi.udv_value, M_PI, 0.0);
472 #ifdef HAVE_ISNAN
473     udv_NaN = add_udv_by_name("NaN");
474     (void) Gcomplex(&(udv_NaN->udv_value), atof("NaN"), 0.0);
475     udv_NaN->udv_undef = FALSE;
476 #endif
477
478     init_memory();
479
480     interactive = FALSE;
481     init_terminal();            /* can set term type if it likes */
482     push_terminal(0);           /* remember the default terminal */
483
484     /* reset the terminal when exiting */
485     /* this is done through gp_atexit so that other terminal functions
486      * can be registered to be executed before the terminal is reset. */
487     GP_ATEXIT(term_reset);
488
489 #ifdef AMIGA_SC_6_1
490     if (IsInteractive(Input()) == DOSTRUE)
491         interactive = TRUE;
492     else
493         interactive = FALSE;
494 #else
495 # if (defined(__MSC__) && defined(_Windows)) || defined(__WIN32__)
496     interactive = TRUE;
497 # else
498     interactive = isatty(fileno(stdin));
499 # endif
500 #endif /* !AMIGA_SC_6_1 */
501
502     if (argc > 1)
503         interactive = noinputfiles = FALSE;
504     else
505         noinputfiles = TRUE;
506
507     /* Need this before show_version is called for the first time */
508
509 #ifdef HAVE_SYS_UTSNAME_H
510     {
511         struct utsname uts;
512
513         /* something is fundamentally wrong if this fails ... */
514         if (uname(&uts) > -1) {
515 # ifdef _AIX
516             strcpy(os_name, uts.sysname);
517             sprintf(os_name, "%s.%s", uts.version, uts.release);
518 # elif defined(SCO)
519             strcpy(os_name, "SCO");
520             strcpy(os_rel, uts.release);
521 # elif defined(DJGPP)
522             if (!strncmp(uts.sysname, "??Un", 4)) /* don't print ??Unknow" */
523                 strcpy(os_name, "Unknown");
524             else {
525                 strcpy(os_name, uts.sysname);
526                 strcpy(os_rel, uts.release);
527             }
528 # else
529             strcpy(os_name, uts.sysname);
530             strcpy(os_rel, uts.release);
531 # ifdef OS2
532             if (!strchr(os_rel,'.'))
533                 /* write either "2.40" or "4.0", or empty -- don't print "OS/2 1" */
534                 strcpy(os_rel, "");
535 # endif
536
537 # endif
538         }
539     }
540 #else /* ! HAVE_SYS_UTSNAME_H */
541
542     strcpy(os_name, OS);
543     strcpy(os_rel, "");
544
545 #endif /* HAVE_SYS_UTSNAME_H */
546
547     if (interactive)
548         show_version(stderr);
549     else
550         show_version(NULL); /* Only load GPVAL_COMPILE_OPTIONS */
551
552     update_gpval_variables(3);  /* update GPVAL_ variables available to user */
553
554 #ifdef VMS
555     /* initialise screen management routines for command recall */
556     if (status[1] = smg$create_virtual_keyboard(&vms_vkid) != SS$_NORMAL)
557         done(status[1]);
558     if (status[1] = smg$create_key_table(&vms_ktid) != SS$_NORMAL)
559         done(status[1]);
560 #endif /* VMS */
561
562     if (!SETJMP(command_line_env, 1)) {
563         /* first time */
564         interrupt_setup();
565         /* should move this stuff another initialisation routine,
566          * something like init_set() maybe */
567         get_user_env();
568         init_loadpath();
569         /*
570          * Now, init_fontpath is invoked when it is used first.
571         init_fontpath();
572         */
573         init_locale();
574         /* HBB: make sure all variables start in the same mode 'reset'
575          * would set them to. Since the axis variables aren't in
576          * initialized arrays any more, this is now necessary... */
577         reset_command();
578         init_color();  /*  Initialization of color  */
579         load_rcfile();
580         init_fit();             /* Initialization of fitting module */
581
582         if (interactive && term != 0) {         /* not unknown */
583 #ifdef GNUPLOT_HISTORY
584             FPRINTF((stderr, "Before read_history\n"));
585 #if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
586             expanded_history_filename = tilde_expand(GNUPLOT_HISTORY_FILE);
587 #else
588             expanded_history_filename = gp_strdup(GNUPLOT_HISTORY_FILE);
589             gp_expand_tilde(&expanded_history_filename);
590 #endif
591             FPRINTF((stderr, "expanded_history_filename = %s\n", expanded_history_filename));
592             read_history(expanded_history_filename);
593             {
594                 /* BEGIN: Go local to get environment variable */
595                 const char *temp_env = getenv ("GNUPLOT_HISTORY_SIZE");
596                 if (temp_env)
597                     gnuplot_history_size = strtol (temp_env, (char **) NULL, 10);
598             } /* END: Go local to get environment variable */
599
600             /*
601              * It is safe to ignore the return values of 'atexit()' and
602              * 'on_exit()'. In the worst case, there is no history of your
603              * currrent session and you have to type all again in your next
604              * session.
605              * This is the default behaviour (traditional reasons), too.
606              * In case you don't have one of these functions, or you don't
607              * want to use them, 'write_history()' is called directly.
608              */
609             GP_ATEXIT(wrapper_for_write_history);
610 #endif /* GNUPLOT_HISTORY */
611
612             fprintf(stderr, "\nTerminal type set to '%s'\n", term->name);
613         }                       /* if (interactive && term != 0) */
614     } else {
615         /* come back here from int_error() */
616         if (interactive == FALSE)
617             exit_status = EXIT_FAILURE;
618
619 #ifdef AMIGA_SC_6_1
620         (void) rawcon(0);
621 #endif
622         load_file_error();      /* if we were in load_file(), cleanup */
623         SET_CURSOR_ARROW;
624
625 #ifdef VMS
626         /* after catching interrupt */
627         /* VAX stuffs up stdout on SIGINT while writing to stdout,
628            so reopen stdout. */
629         if (gpoutfile == stdout) {
630             if ((stdout = freopen("SYS$OUTPUT", "w", stdout)) == NULL) {
631                 /* couldn't reopen it so try opening it instead */
632                 if ((stdout = fopen("SYS$OUTPUT", "w")) == NULL) {
633                     /* don't use int_error here - causes infinite loop! */
634                     fputs("Error opening SYS$OUTPUT as stdout\n", stderr);
635                 }
636             }
637             gpoutfile = stdout;
638         }
639 #endif /* VMS */
640         if (!interactive && !noinputfiles) {
641             term_reset();
642 #if defined(ATARI) || defined(MTOS)
643             if (aesid > -1)
644                 atexit(appl_exit);
645 #endif
646             exit(EXIT_FAILURE); /* exit on non-interactive error */
647         }
648     }
649
650     if (argc > 1) {
651 #ifdef _Windows
652         TBOOLEAN noend = persist_cl;
653 #endif
654
655         /* load filenames given as arguments */
656         while (--argc > 0) {
657             ++argv;
658             c_token = NO_CARET; /* in case of file not found */
659 #ifdef _Windows
660             if (stricmp(*argv, "-noend") == 0 || stricmp(*argv, "/noend") == 0
661                 || stricmp(*argv, "-persist") == 0)
662                 noend = TRUE;
663             else
664 #endif
665             if (strcmp(*argv, "-") == 0) {
666                 /* DBT 10-7-98  go interactive if "-" on command line */
667
668                 interactive = TRUE;
669                 /* will this work on all platforms? */
670
671                 while (!com_line());
672
673                 interactive = FALSE;
674
675             } else if (strcmp(*argv, "-e") == 0) {
676                 --argc; ++argv;
677                 if (argc <= 0) {
678                     fprintf(stderr, "syntax:  gnuplot -e \"commands\"\n");
679                     return 0;
680                 }
681                 do_string(*argv);
682
683             } else
684                 load_file(loadpath_fopen(*argv, "r"), *argv, FALSE);
685         }
686 #ifdef _Windows
687         if (noend) {
688             interactive = TRUE;
689             while (!com_line());
690         }
691 #endif
692     } else {
693         /* take commands from stdin */
694         while (!com_line());
695     }
696
697 #if (defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)) && defined(GNUPLOT_HISTORY)
698 #if !defined(HAVE_ATEXIT) && !defined(HAVE_ON_EXIT)
699     /* You should be here if you neither have 'atexit()' nor 'on_exit()' */
700     wrapper_for_write_history();
701 #endif /* !HAVE_ATEXIT && !HAVE_ON_EXIT */
702 #endif /* (HAVE_LIBREADLINE || HAVE_LIBEDITLINE) && GNUPLOT_HISTORY */
703
704 #ifdef OS2
705     RexxDeregisterSubcom("GNUPLOT", NULL);
706 #endif
707
708 #if defined(ATARI) || defined(MTOS)
709     if (aesid > -1)
710         atexit(appl_exit);
711 #endif
712     /* HBB 20040223: Not all compilers like exit() to end main() */
713     /* exit(exit_status); */
714     return exit_status;
715 }
716
717
718 /* Set up to catch interrupts */
719 void
720 interrupt_setup()
721 {
722 #ifdef __PUREC__
723     setmatherr(purec_matherr);
724 #endif
725
726     (void) signal(SIGINT, (sigfunc) inter);
727
728 #ifdef SIGPIPE
729     /* ignore pipe errors, this might happen with set output "|head" */
730     (void) signal(SIGPIPE, SIG_IGN);
731 #endif /* SIGPIPE */
732 }
733
734
735 /* Look for a gnuplot init file in current or home directory */
736 static void
737 load_rcfile()
738 {
739     FILE *plotrc = NULL;
740     char *rcfile = NULL;
741
742 #ifdef NOCWDRC
743     /* inhibit check of init file in current directory for security reasons */
744 #else
745     plotrc = fopen(PLOTRC, "r");
746 #endif /* !NOCWDRC */
747
748     if (plotrc == NULL) {
749         if (user_homedir) {
750             /* len of homedir + directory separator + len of file name + \0 */
751             rcfile = (char *) gp_alloc((user_homedir ? strlen(user_homedir) : 0) + 1 + strlen(PLOTRC) + 1, "rcfile");
752             strcpy(rcfile, user_homedir);
753             PATH_CONCAT(rcfile, PLOTRC);
754             plotrc = fopen(rcfile, "r");
755
756 #if defined(ATARI) || defined(MTOS)
757             if (plotrc == NULL) {
758                 char const *const ext[] = { NULL };
759                 char *ini_ptr = findfile(PLOTRC, user_gnuplotpath, ext);
760
761                 if (ini_ptr)
762                     plotrc = fopen(ini_ptr, "r");
763             }
764 #endif /* ATARI || MTOS */
765         }
766     }
767     if (plotrc) {
768         load_file(plotrc, (rcfile==NULL) ? PLOTRC : rcfile, FALSE);
769         push_terminal(0); /* needed if terminal or its options were changed */
770     }
771
772     free(rcfile);
773 }
774
775 void
776 get_user_env()
777 {
778     if (user_homedir == NULL) {
779         const char *env_home;
780
781         if ((env_home = getenv(HOME))
782 #ifdef WIN32
783             || (env_home = appdata_directory())
784             || (env_home = getenv("USERPROFILE"))
785 #endif
786 #ifndef VMS
787             || (env_home = getenv("HOME"))
788 #endif
789            )
790             user_homedir = (const char *) gp_strdup(env_home);
791         else if (interactive)
792             int_warn(NO_CARET, "no HOME found");
793     }
794     /* Hhm ... what about VMS? */
795     if (user_shell == NULL) {
796         const char *env_shell;
797
798         if ((env_shell = getenv("SHELL")) == NULL)
799 #if defined(MSDOS) || defined(_Windows) || defined(DOS386) || defined(OS2)
800             if ((env_shell = getenv("COMSPEC")) == NULL)
801 #endif
802                 env_shell = SHELL;
803
804         user_shell = (const char *) gp_strdup(env_shell);
805     }
806 #if defined(ATARI) || defined(MTOS)
807     if (user_gnuplotpath == NULL) {
808         char *env_gpp;
809
810         if (env_gpp = getenv("GNUPLOTPATH"))
811             user_gnuplotpath = (const char *) gp_strdup(env_gpp);
812     }
813 #endif
814 }
815
816 /* expand tilde in path
817  * path cannot be a static array!
818  * tilde must be the first character in *pathp;
819  * we may change that later
820  */
821 void
822 gp_expand_tilde(char **pathp)
823 {
824     if (!*pathp)
825         int_error(NO_CARET, "Cannot expand empty path");
826
827     if ((*pathp)[0] == '~' && (*pathp)[1] == DIRSEP1) {
828         if (user_homedir) {
829             size_t n = strlen(*pathp);
830
831             *pathp = gp_realloc(*pathp, n + strlen(user_homedir), "tilde expansion");
832             /* include null at the end ... */
833             memmove(*pathp + strlen(user_homedir) - 1, *pathp, n + 1);
834             memcpy(*pathp, user_homedir, strlen(user_homedir));
835         } else
836             int_warn(NO_CARET, "HOME not set - cannot expand tilde");
837     }
838 }
839
840
841 static void
842 init_memory()
843 {
844     extend_input_line();
845     extend_token_table();
846     replot_line = gp_alloc(1, "string");
847     *replot_line = NUL;
848 }
849
850
851 #ifdef OS2
852
853 int
854 ExecuteMacro(char *argv, int namelength)
855 {
856     RXSTRING rxRc;
857     RXSTRING rxArg[2];
858     int rxArgCount = 0;
859     char pszName[CCHMAXPATH];
860     char *rxArgStr;
861     short sRc;
862     long rc;
863
864     if (namelength >= sizeof(pszName))
865         return 1;
866     /* FIXME HBB 20010121: 3rd argument doesn't make sense. Either
867      * this should be sizeof(pszName), or it shouldn't use
868      * safe_strncpy(), here */
869     safe_strncpy(pszName, argv, namelength + 1);
870     rxArgStr = &argv[namelength];
871     RXSTRPTR(rxRc) = NULL;
872
873 #if 0
874     /*
875        C-like calling of function: program name is first
876        parameter.
877        In REXX you would have to use
878        Parse Arg param0, param1
879        to get the program name in param0 and the arguments in param1.
880
881        Some versions before gnuplot 3.7pl1 used a similar approach but
882        passed program name and arguments in a single string:
883        (==> Parse Arg param0 param1)
884      */
885
886     MAKERXSTRING(rxArg[0], pszName, strlen(pszName));
887     rxArgCount++;
888     if (*rxArgStr) {
889         MAKERXSTRING(rxArg[1], rxArgStr, strlen(rxArgStr));
890         rxArgCount++;
891     }
892 #else
893     /*
894        REXX standard calling (gnuplot 3.7pl1 and above):
895        The program name is not supplied and so all actual arguments
896        are in a single string:
897        Parse Arg param
898        We even handle blanks like cmd.exe when calling REXX programs.
899      */
900
901     if (*rxArgStr) {
902         MAKERXSTRING(rxArg[0], rxArgStr, strlen(rxArgStr));
903         rxArgCount++;
904     }
905 #endif
906
907     CallFromRexx = TRUE;
908     rc = RexxStart(
909                       rxArgCount,
910                       rxArg,
911                       pszName,
912                       NULL,
913                       "GNUPLOT",
914                       RXCOMMAND,
915                       NULL,
916                       &sRc,
917                       &rxRc);
918     CallFromRexx = FALSE;
919
920    /* am: a word WRT errors codes:
921       the negative ones don't seem to have symbolic names, you can get
922       them from the OREXX reference, they're not in REXX Programming Guide -
923       no idea where to retrieve them from a Warp 3 reference ??
924       The positive ones are somehow referenced in REXXPG
925    */
926     if (rc < 0) {
927         /* REXX error */
928     } else if (rc > 0) {
929         /* Interpreter couldn't be started */
930         if (rc == -4)
931            /* run was cancelled, but don't give error message */
932             rc = 0;
933     } else if (rc==0) {
934         /* all was fine */
935     }
936
937 /* We don't we try to use rxRc ?
938    BTW, don't use free() instead since it's allocated inside RexxStart()
939    and not in our executable using the EMX libraries */
940    if (RXSTRPTR(rxRc))
941        /* I guess it's NULL if something major went wrong,
942           NULL strings are usually not part of the REXX language ... */
943        DosFreeMem(rxRc.strptr);
944
945    return rc;
946 }
947
948 /* Rexx command line interface */
949 ULONG
950 RexxInterface(PRXSTRING rxCmd, PUSHORT pusErr, PRXSTRING rxRc)
951 {
952     int rc;
953     static JMP_BUF keepenv;
954     int cmdlen;
955
956     memcpy(keepenv, command_line_env, sizeof(JMP_BUF));
957     if (!SETJMP(command_line_env, 1)) {
958         /* Set variable gp_input_line.
959            Watch out for line length of NOT_ZERO_TERMINATED strings ! */
960         cmdlen = rxCmd->strlength + 1;
961         /* FIXME HBB 20010121: 3rd argument doesn't make sense. Either
962          * this should be gp_input_line_len, or it shouldn't use
963          * safe_strncpy(), here */
964         safe_strncpy(gp_input_line, rxCmd->strptr, cmdlen);
965         gp_input_line[cmdlen] = NUL;
966         rc = do_line();
967         *pusErr = RXSUBCOM_OK;
968         rxRc->strptr[0] = rc + '0';
969         rxRc->strptr[1] = NUL;
970         rxRc->strlength = strlen(rxRc->strptr);
971     } else {
972 /*
973    We end up here when bail_to_command_line() is called.
974    Therefore sometimes this call should be avoided when
975    executing a REXX program (e.g. 'Cancel' from
976    PM GUI after a 'pause -1' command)
977 */
978         *pusErr = RXSUBCOM_ERROR;
979         RexxSetHalt(getpid(), 1);
980     }
981     memcpy(command_line_env, keepenv, sizeof(JMP_BUF));
982     return 0;
983 }
984 #endif
985
986 #ifdef GNUPLOT_HISTORY
987 # if defined(HAVE_LIBREADLINE) || defined(HAVE_LIBEDITLINE)
988
989 static void
990 wrapper_for_write_history()
991 {
992 #if 1
993     /* Alternative code, saves one disk access */
994     if (history_is_stifled())
995         unstifle_history();
996     if (gnuplot_history_size >= 0)
997         stifle_history (gnuplot_history_size);
998
999     /* returns 0 on success */
1000     if (write_history(expanded_history_filename))
1001         fprintf (stderr, "Warning:  Could not write history file!!!\n");
1002
1003     unstifle_history();
1004 #else
1005     /* if writing was successful, truncate history
1006      *  to gnuplot_history_size lines
1007      */
1008     if (write_history(expanded_history_filename)) {
1009         if (gnuplot_history_size >= 0)
1010             history_truncate_file(expanded_history_filename, gnuplot_history_size);
1011     }
1012 #endif
1013 }
1014
1015 # else /* HAVE_LIBREADLINE || HAVE_LIBEDITLINE */
1016
1017 /* version for gnuplot's own write_history */
1018 static void
1019 wrapper_for_write_history()
1020 {
1021     /* What we really want to do is truncate(expanded_history_filename),
1022        but this is only available on BSD compatible systems */
1023     remove(expanded_history_filename);
1024     if (gnuplot_history_size < 0)
1025         write_history(expanded_history_filename);
1026     else
1027         write_history_n(gnuplot_history_size, expanded_history_filename, "w");
1028 }
1029
1030 # endif /* HAVE_LIBREADLINE || HAVE_LIBEDITLINE */
1031 #endif /* GNUPLOT_HISTORY */
1032