1 #ifndef lint
RCSid()2 static char *RCSid() { return RCSid("$Id: gpexecute.c,v 1.17 2010/08/31 12:57:32 mikulik Exp $"); }
3 #endif
4 
5 /* GNUPLOT - gpexecute.c */
6 
7 /*[
8  * Permission to use, copy, and distribute this software and its
9  * documentation for any purpose with or without fee is hereby granted,
10  * provided that the above copyright notice appear in all copies and
11  * that both that copyright notice and this permission notice appear
12  * in supporting documentation.
13  *
14  * Permission to modify the software is granted, but not the right to
15  * distribute the complete modified source code.  Modifications are to
16  * be distributed as patches to the released version.  Permission to
17  * distribute binaries produced by compiling modified sources is granted,
18  * provided you
19  *   1. distribute the corresponding source modifications from the
20  *    released version in the form of a patch file along with the binaries,
21  *   2. add special version identification to distinguish your version
22  *    in addition to the base release version number,
23  *   3. provide your name and address as the primary contact for the
24  *    support of your modified version, and
25  *   4. retain our contact information in regard to use of the base
26  *    software.
27  * Permission to distribute the released version of the source code along
28  * with corresponding source modifications in the form of a patch file is
29  * granted with same provisions 2 through 4 for binary distributions.
30  *
31  * This software is provided "as is" without express or implied warranty
32  * to the extent permitted by applicable law.
33 ]*/
34 
35 /*
36  * AUTHORS
37  *
38  *   Original Software (October 1999 - January 2000):
39  *     Pieter-Tjerk de Boer <ptdeboer@cs.utwente.nl>
40  *     Petr Mikulik <mikulik@physics.muni.cz>
41  *     Johannes Zellner <johannes@zellner.org>
42  */
43 
44 #include "gpexecute.h"
45 
46 #include "stdfn.h"
47 
48 #ifdef OS2_IPC
49 # include <stdio.h>
50 #endif
51 
52 #ifdef PIPE_IPC
53 # include <unistd.h>	/* open(), write() */
54 # include <stdlib.h>
55 # include <assert.h>
56 # include <errno.h>
57 int pipe_died = 0;
58 #endif /* PIPE_IPC */
59 
60 #ifdef WIN_IPC
61 # include <stdlib.h>
62 # include <assert.h>
63 # include "mouse.h"	/* do_event() */
64 #endif
65 
66 #if defined(PIPE_IPC) /* || defined(WIN_IPC) */
67 static gpe_fifo_t *gpe_init __PROTO((void));
68 static void gpe_push __PROTO((gpe_fifo_t ** base, struct gp_event_t * ge));
69 static struct gp_event_t *gpe_front __PROTO((gpe_fifo_t ** base));
70 static int gpe_pop __PROTO((gpe_fifo_t ** base));
71 #endif /* PIPE_IPC || WIN_IPC */
72 
73 /*
74  * gp_execute functions
75  */
76 
77 #ifdef OS2_IPC
78 char mouseShareMemName[40];
79 PVOID input_from_PM_Terminal;
80   /* pointer to shared memory for storing the command to be executed */
81 HEV semInputReady = 0;
82   /* handle to event semaphore (post an event to gnuplot that the shared
83      memory contains a command to be executed) */
84 int pausing = 0;
85   /* avoid passing data back to gnuplot in `pause' mode */
86   /* gplt_x11.c */
87 ULONG ppidGnu = 0;
88 
89 
90 /*
91  * Let the command in the shared memory be executed.
92  */
93 void
gp_post_shared_mem()94 gp_post_shared_mem()
95 {
96     APIRET rc;
97     if (semInputReady == 0) {	/* but it must be open for the first time */
98 	char semInputReadyName[40];
99 	sprintf(semInputReadyName, "\\SEM32\\GP%i_Input_Ready", (int) ppidGnu);
100 	DosOpenEventSem(semInputReadyName, &semInputReady);
101     }
102     rc = DosPostEventSem(semInputReady);
103     DosSleep(10);
104     /* dirty trick: wait a little bit; otherwise problems to
105      * distinguish mouse button down and up, for instance
106      * (info sent to shared memory was too fast; maybe a blocking
107      * semaphore would help, but no fun to implement it...)
108      &*/
109 }
110 
111 /* Copy the command (given by the input string) to the shared memory
112  * and let gnuplot execute it.
113  * If this routine is called during a 'pause', then the command is
114  * ignored (shared memory is cleared). Needed for actions launched by a
115  * hotkey.
116  * Firstly, the command is copied from shared memory to clipboard
117  * if this option is set on.
118  * Secondly, gnuplot is informed that shared memory contains a command
119  * by posting semInputReady event semaphore.
120  *
121  * OS/2 specific: if (!s), then the command has been already sprintf'ed to
122  * the shared memory.
123  */
124 void
gp_execute(char * s)125 gp_execute(char *s)
126 {
127     if (input_from_PM_Terminal == NULL)
128 	return;
129     if (s)			/* copy the command to shared memory */
130 	strcpy(input_from_PM_Terminal, s);
131     if (((char *) input_from_PM_Terminal)[0] == 0)
132 	return;
133     if (pausing) {		/* no communication during pause */
134 	/* DosBeep(440,111); */
135 	((char *) input_from_PM_Terminal)[0] = 0;
136 	return;
137     }
138     gp_post_shared_mem();
139 }
140 
141 #endif /* OS2_IPC */
142 
143 #if defined(PIPE_IPC) /* || defined(WIN_IPC) */
144 
145 int buffered_output_pending = 0;
146 
147 static gpe_fifo_t *
gpe_init()148 gpe_init()
149 {
150     gpe_fifo_t *base = malloc(sizeof(gpe_fifo_t));
151     /* fprintf(stderr, "(gpe_init) \n"); */
152     assert(base);
153     base->next = (gpe_fifo_t *) 0;
154     base->prev = (gpe_fifo_t *) 0;
155     return base;
156 }
157 
158 static void
gpe_push(gpe_fifo_t ** base,struct gp_event_t * ge)159 gpe_push(gpe_fifo_t ** base, struct gp_event_t *ge)
160 {
161     buffered_output_pending++;
162     if ((*base)->prev) {
163 	gpe_fifo_t *new = malloc(sizeof(gpe_fifo_t));
164 	/* fprintf(stderr, "(gpe_push) \n"); */
165 	assert(new);
166 	(*base)->prev->next = new;
167 	new->prev = (*base)->prev;
168 	(*base)->prev = new;
169 	new->next = (gpe_fifo_t *) 0;
170     } else {
171 	/* first element, this is the case, if the pipe isn't clogged */
172 	(*base)->next = (gpe_fifo_t *) 0;	/* tail */
173 	(*base)->prev = (*base);	/* points to itself */
174     }
175     (*base)->prev->ge = *ge;
176 }
177 
178 static struct gp_event_t *
gpe_front(gpe_fifo_t ** base)179 gpe_front(gpe_fifo_t ** base)
180 {
181     return &((*base)->ge);
182 }
183 
184 static int
gpe_pop(gpe_fifo_t ** base)185 gpe_pop(gpe_fifo_t ** base)
186 {
187     buffered_output_pending--;
188     if ((*base)->prev == (*base)) {
189 	(*base)->prev = (gpe_fifo_t *) 0;
190 	return 0;
191     } else {
192 	gpe_fifo_t *save = *base;
193 	/* fprintf(stderr, "(gpe_pop) \n"); */
194 	(*base)->next->prev = (*base)->prev;
195 	(*base) = (*base)->next;
196 	free(save);
197 	return 1;
198     }
199 }
200 #endif /* PIPE_IPC || WIN_IPC */
201 
202 #ifdef PIPE_IPC
203 RETSIGTYPE
pipe_died_handler(int signum)204 pipe_died_handler(int signum)
205 {
206     (void) signum;		/* avoid -Wunused warning. */
207     /* fprintf(stderr, "\n*******(pipe_died_handler)*******\n"); */
208     close(1);
209     pipe_died = 1;
210 }
211 #endif /* PIPE_IPC */
212 
213 void
gp_exec_event(char type,int mx,int my,int par1,int par2,int winid)214 gp_exec_event(char type, int mx, int my, int par1, int par2, int winid)
215 {
216     struct gp_event_t ge;
217 #if defined(PIPE_IPC) /* || defined(WIN_IPC) */
218     static struct gpe_fifo_t *base = (gpe_fifo_t *) 0;
219 #endif
220 
221     ge.type = type;
222     ge.mx = mx;
223     ge.my = my;
224     ge.par1 = par1;
225     ge.par2 = par2;
226     ge.winid = winid;
227 #ifdef PIPE_IPC
228     if (pipe_died)
229 	return;
230 #endif
231     /* HBB 20010218: commented this out for WIN_IPC. We don't actually use the stack,
232      * there */
233 #if defined(PIPE_IPC) /* || defined(WIN_IPC) */
234     if (!base) {
235 	base = gpe_init();
236     }
237     if (GE_pending != type) {
238 	gpe_push(&base, &ge);
239     } else if (!buffered_output_pending) {
240 	return;
241     }
242 #endif
243 #ifdef WIN_IPC
244     do_event(&ge);
245     return;
246 #endif
247 #ifdef PIPE_IPC
248     do {
249 	int status = write(1, gpe_front(&base), sizeof(ge));
250 	if (-1 == status) {
251 	    switch (errno) {
252 	    case EAGAIN:
253 		/* do nothing */
254 		FPRINTF((stderr, "(gp_exec_event) EAGAIN\n"));
255 		break;
256 	    default:
257 		FPRINTF((stderr, "(gp_exec_event) errno = %d\n", errno));
258 		break;
259 	    }
260 	    break;
261 	}
262     } while (gpe_pop(&base));
263 #endif /* PIPE_IPC */
264 
265 #ifdef OS2_IPC			/* OS/2 communication via shared memory; coded according to gp_execute() */
266     if (input_from_PM_Terminal == NULL)
267 	return;
268     ((char *) input_from_PM_Terminal)[0] = '%';	/* flag that passing gp_event_t */
269     memcpy(((char *) input_from_PM_Terminal) + 1, &ge, sizeof(ge));	/* copy the command to shared memory */
270     if (pausing) {		/* no communication during pause */
271 	/* DosBeep(440,111); */
272 	((char *) input_from_PM_Terminal)[0] = 0;
273 	return;
274     }
275     gp_post_shared_mem();
276 #endif
277 }
278