Switched to FFTW-3.
[grace.git] / grace_np / grace_np.c
blobe75a51dfdf8f6f7bfe0d33d63158211a6c58749e
1 /*
2 * grace_np - a library for interfacing with Grace using pipes
3 *
4 * Copyright (c) 1997-1998 Henrik Seidel
5 * Copyright (c) 1999-2003 Grace Development Team
8 * All Rights Reserved
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Library General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Library General Public License for more details.
20 * You should have received a copy of the GNU Library General Public
21 * License along with this library; if not, write to the Free
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <config.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <unistd.h>
32 #include <signal.h>
33 #include <errno.h>
34 #ifdef HAVE_SYS_PARAM_H
35 # include <sys/param.h>
36 #endif
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #ifdef HAVE_FCNTL_H
40 # include <fcntl.h>
41 #endif
42 #ifdef HAVE_SYS_WAIT_H
43 # include <sys/wait.h>
44 #endif
45 #include <limits.h>
46 #ifndef OPEN_MAX
47 # define OPEN_MAX 256
48 #endif
50 #include "grace_np.h"
52 /* static global variables */
53 static char* buf = NULL; /* global write buffer */
54 static int bufsize; /* size of the global write buffer */
55 static int bufsizeforce; /* threshold for forcing a flush */
56 static int fd_pipe = -1; /* file descriptor of the pipe */
57 static pid_t pid = (pid_t) -1; /* pid of grace */
60 * notify grace when finished
62 static void
63 #ifdef HAVE_ON_EXIT
64 notify_grace_on_exit(int status, void* arg)
65 #else
66 notify_grace_on_exit(void)
67 #endif
69 if (fd_pipe != -1) {
70 GraceClosePipe();
75 * default function for reporting errors
77 static void
78 GraceDefaultError(const char *msg)
80 fprintf(stderr, "%s\n", msg);
84 * variable holding user function for reporting errors
86 static GraceErrorFunctionType error_function = GraceDefaultError;
89 * function for reporting system errors
91 static void
92 GracePerror(const char *prefix)
94 char msg[1024];
96 #ifdef HAVE_STRERROR
97 sprintf(msg, "%s: %s", prefix, strerror(errno));
98 #else
99 # ifdef HAVE_SYS_ERRLIST_IN_STDIO_H
100 sprintf(msg, "%s: %s", prefix, sys_errlist[errno]);
101 # else
102 if (errno == EPIPE) {
103 /* this one deserve special attention here */
104 sprintf(msg, "%s: Broken pipe", prefix);
105 } else {
106 sprintf(msg, "%s: System error (errno = %d)", prefix, errno);
108 # endif
109 #endif
111 error_function(msg);
114 /* Close the pipe and free the buffer */
115 static void
116 GraceCleanup(void)
118 if (fd_pipe != -1) {
119 if (close(fd_pipe) != 0) {
120 GracePerror("GraceCleanup");
122 fd_pipe = -1;
125 free(buf);
126 buf = NULL;
130 * try to send data to grace (one pass only)
132 static int
133 GraceOneWrite(int left)
135 int written;
137 written = write(fd_pipe, buf, left);
139 if (written > 0) {
141 left -= written;
143 if (left > 0) {
144 /* move the remaining characters (and the final '\0') */
145 #ifdef HAVE_MEMMOVE
146 memmove(buf, buf + written, left + 1);
147 #else
148 bcopy(buf + written, buf, left + 1);
149 #endif
150 } else {
151 /* clear the buffer */
152 *buf = '\0';
155 } else if (written < 0) {
156 if (errno == EPIPE) {
157 /* Grace has closed the pipe : we cannot write anymore */
158 GraceCleanup();
159 } else {
160 GracePerror("GraceOneWrite");
162 return (-1);
165 return (left);
170 * register an user function to report errors
172 GraceErrorFunctionType
173 GraceRegisterErrorFunction(GraceErrorFunctionType f)
175 GraceErrorFunctionType old = error_function;
176 if (f != (GraceErrorFunctionType) NULL) {
177 error_function = f;
179 return old;
182 static void
183 handle_sigchld(int signum)
185 int status;
186 int retval;
188 if (fd_pipe != -1) {
189 retval = waitpid(pid, &status, WNOHANG);
190 if (retval == pid) {
191 /* Grace just died */
192 GraceCleanup();
198 GraceOpenVA(char* exe, int bs, ...)
200 int i, fd[2];
201 char fd_number[4];
202 va_list ap;
203 char **arglist;
204 char *s;
205 int numarg;
207 if (fd_pipe != -1) {
208 error_function("Grace subprocess already running");
209 return (-1);
212 /* Set the buffer sizes according to arg */
213 if (bs < 64) {
214 error_function("The buffer size in GraceOpenVA should be >= 64");
215 return (-1);
217 bufsize = bs;
218 bufsizeforce = bs / 2;
220 /* make sure the grace subprocess is notified at the end */
221 #ifdef HAVE_ON_EXIT
222 on_exit(notify_grace_on_exit, NULL);
223 #else
224 atexit(notify_grace_on_exit);
225 #endif
227 /* Don't exit on SIGPIPE */
228 signal(SIGPIPE, SIG_IGN);
230 /* Don't exit when our child "grace" exits */
231 signal(SIGCHLD, handle_sigchld);
233 /* Make the pipe */
234 if (pipe(fd)) {
235 GracePerror("GraceOpenVA");
236 return (-1);
239 /* Fork a subprocess for starting grace */
240 pid = fork();
241 if (pid == (pid_t) (-1)) {
242 GracePerror("GraceOpenVA");
243 close(fd[0]);
244 close(fd[1]);
245 return (-1);
248 /* If we are the child, replace ourselves with grace */
249 if (pid == (pid_t) 0) {
250 for (i = 0; i < OPEN_MAX; i++) {
251 /* we close everything except stdin, stdout, stderr
252 and the read part of the pipe */
253 if (i != fd[0] &&
254 i != STDIN_FILENO &&
255 i != STDOUT_FILENO &&
256 i != STDERR_FILENO) {
257 close(i);
261 /* build the argument list */
262 va_start(ap, bs);
263 numarg = 3;
264 arglist = malloc((numarg + 1)*SIZEOF_VOID_P);
265 arglist[0] = exe;
266 arglist[1] = "-dpipe";
267 sprintf(fd_number, "%d", fd[0]);
268 arglist[2] = fd_number;
269 while ((s = va_arg(ap, char *)) != NULL) {
270 numarg++;
271 arglist = realloc(arglist, (numarg + 1)*SIZEOF_VOID_P);
272 arglist[numarg - 1] = s;
274 arglist[numarg] = NULL;
275 va_end(ap);
277 execvp(exe, arglist);
279 /* if we get here execvp failed */
280 fprintf(stderr, "GraceOpenVA: Could not start %s\n", exe);
282 _exit(EXIT_FAILURE);
285 /* We are the parent -> keep the write part of the pipe
286 and allocate the write buffer */
287 buf = malloc(bufsize);
288 if (buf == NULL) {
289 error_function("GraceOpenVA: Not enough memory");
290 close(fd[0]);
291 close(fd[1]);
292 return (-1);
294 *buf = '\0';
296 close(fd[0]);
297 fd_pipe = fd[1];
299 return (0);
303 GraceOpen(int bs)
305 return GraceOpenVA("xmgrace", bs, "-nosafe", "-noask", NULL);
309 GraceIsOpen(void)
311 return (fd_pipe >= 0) ? 1 : 0;
315 GraceClose(void)
317 if (fd_pipe == -1) {
318 error_function("No grace subprocess");
319 return (-1);
322 /* Tell grace to close the pipe */
323 if (GraceCommand ("exit") == -1 || GraceFlush() != 0){
324 kill(pid, SIGTERM);
327 GraceCleanup();
329 return (0);
333 GraceClosePipe(void)
335 if (fd_pipe == -1) {
336 error_function("No grace subprocess");
337 return (-1);
340 /* Tell grace to close the pipe */
341 if (GraceCommand ("close") == -1)
342 return (-1);
343 if (GraceFlush() != 0)
344 return (-1);
346 GraceCleanup();
348 return (0);
352 GraceFlush(void)
354 int loop, left;
356 if (fd_pipe == -1) {
357 error_function("No grace subprocess");
358 return (-1);
361 left = strlen(buf);
363 for (loop = 0; loop < 30; loop++) {
364 left = GraceOneWrite(left);
365 if (left < 0) {
366 return (-1);
367 } else if (left == 0) {
368 return (0);
372 error_function("GraceFlush: ran into eternal loop");
374 return (-1);
378 GracePrintf(const char* fmt, ...)
380 va_list ap;
381 char* str;
382 int nchar;
384 if (fd_pipe == -1) {
385 error_function("No grace subprocess");
386 return (0);
389 /* Allocate a new string buffer for the function arguments */
390 str = (char *) malloc ((size_t) bufsize);
391 if (str == (char *) NULL) {
392 error_function("GracePrintf: Not enough memory");
393 return (0);
395 /* Print to the string buffer according to the function arguments */
396 va_start (ap, fmt);
397 #if defined(HAVE_VSNPRINTF)
398 nchar = vsnprintf (str, bufsize - 2, fmt, ap);
399 #else
400 nchar = vsprintf (str, fmt, ap);
401 #endif
402 va_end (ap);
403 nchar++; /* This is for the appended "\n" */
404 if (GraceCommand (str) == -1) {
405 nchar = 0;
407 free (str);
408 return (nchar);
412 GraceCommand(const char* cmd)
414 int left;
416 if (fd_pipe == -1) {
417 error_function("No grace subprocess");
418 return (-1);
421 /* Append the new string to the global write buffer */
422 if (strlen(buf) + strlen(cmd) + 2 > bufsize) {
423 error_function("GraceCommand: Buffer full");
424 return (-1);
426 strcat(buf, cmd);
427 strcat(buf, "\n");
428 left = strlen(buf);
430 /* Try to send the global write buffer to grace */
431 left = GraceOneWrite(left);
432 if (left >= bufsizeforce) {
433 if (GraceFlush() != 0) {
434 return (-1);
436 } else if (left < 0) {
437 return (-1);
440 return (0);