source: trunk/packages/vizservers/pymolproxy/pymolproxy.c @ 1213

Last change on this file since 1213 was 1213, checked in by gah, 16 years ago

fixed pymol input race condition

File size: 37.4 KB
Line 
1
2/*
3 * ----------------------------------------------------------------------
4 * proxypymol.c
5 *
6 *      This module creates the Tcl interface to the pymol server.  It acts as
7 *      a go-between establishing communication between a molvisviewer widget
8 *      and the pymol server. The communication protocol from the molvisviewer
9 *      widget is the Tcl language.  Commands are then relayed to the pymol
10 *      server.  Responses from the pymol server are translated into Tcl
11 *      commands * and send to the molvisviewer widget. For example, resulting
12 *      image rendered offscreen is returned as BMP-formatted image data.
13 *
14 *  Copyright (c) 2004-2006  Purdue Research Foundation
15 *
16 *  See the file "license.terms" for information on usage and
17 *  redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
18 * ======================================================================
19 */
20
21#include <stdio.h>
22#include <time.h>
23#include <assert.h>
24#include <unistd.h>
25#include <stdlib.h>
26#include <string.h>
27#include <signal.h>
28#include <sys/stat.h>
29#include <sys/types.h>
30#include <sys/socket.h>
31#include <sys/wait.h>
32#include <sys/select.h>
33#include <poll.h>
34#include <sys/time.h>
35#include <sys/times.h>
36#include <fcntl.h>
37#include <netinet/in.h>
38#include <getopt.h>
39#include <errno.h>
40#include <sys/ioctl.h>
41#include <net/if.h>
42#include <tcl.h>
43
44#undef INLINE
45#ifdef __GNUC__
46#  define INLINE __inline__
47#else
48#  define INLINE
49#endif
50
51#define FALSE 0
52#define TRUE  1
53
54#define IO_TIMEOUT (30000)
55#define KEEPSTATS       1
56#define CVT2SECS(x)  ((double)(x).tv_sec) + ((double)(x).tv_usec * 1.0e-6)
57
58typedef struct {
59    pid_t child;                /* Child process. */
60    size_t nFrames;             /* # of frames sent to client. */
61    size_t nBytes;              /* # of bytes for all frames. */
62    size_t nCommands;           /* # of commands executed */
63    double cmdTime;             /* Elasped time spend executing commands. */
64    struct timeval start;       /* Start of elapsed time. */
65} Stats;
66
67static Stats stats;
68
69static FILE *flog;
70static int debug = TRUE;
71
72typedef struct {
73    char *data;
74    int   used;
75    int   allocated;
76} DyBuffer;
77
78typedef struct {
79    int p_stdin;
80    int p_stdout;
81    int p_stderr;
82    int c_stdin;
83    int c_stdout;
84    DyBuffer image;
85    int need_update;
86    int can_update;
87    int immediate_update;
88    int sync;
89    int labels;
90    int frame;
91    int rock_offset;
92    int cacheid;
93    int invalidate_cache;
94    int error;
95    int status;
96} PymolProxy;
97
98static void
99trace TCL_VARARGS_DEF(char *, arg1)
100{
101    if (debug) {
102        char *format;
103        va_list args;
104
105        format = TCL_VARARGS_START(char *, arg1, args);
106        fprintf(flog, "pymolproxy: ");
107        vfprintf(flog, format, args);
108        fprintf(flog, "\n");
109        fflush(flog);
110    }
111}
112
113#if KEEPSTATS
114
115static int
116WriteStats(const char *who, int code)
117{
118    double start, finish;
119    pid_t pid;
120    char buf[BUFSIZ];
121    Tcl_DString ds;
122
123    {
124        struct timeval tv;
125
126        /* Get ending time.  */
127        gettimeofday(&tv, NULL);
128        finish = CVT2SECS(tv);
129        tv = stats.start;
130        start = CVT2SECS(tv);
131    }
132    /*
133     * Session information:
134     *   1. Start date of session in seconds.
135     *   2. Process ID
136     *   3. Number of frames returned.
137     *   4. Number of bytes total returned (in frames).
138     *   5. Total elapsed time of all commands.
139     *   6. Total elapsed time of session.
140     *   7. Exit code of pymol server.
141     *   8. User time. 
142     *   9. System time.
143     *  10. Maximum resident size.
144     */
145    pid = getpid();
146    Tcl_DStringInit(&ds);
147   
148    sprintf(buf, "<session server=\"%s\" ", who);
149    Tcl_DStringAppend(&ds, buf, -1);
150
151    strcpy(buf, ctime(&stats.start.tv_sec));
152
153    buf[strlen(buf) - 1] = '\0';
154    Tcl_DStringAppend(&ds, "date=\"", -1);
155    Tcl_DStringAppend(&ds, buf, -1);
156    Tcl_DStringAppend(&ds, "\" ", -1);
157
158    sprintf(buf, "date_secs=\"%ld\" ", stats.start.tv_sec);
159    Tcl_DStringAppend(&ds, buf, -1);
160
161    sprintf(buf, "pid=\"%d\" ", pid);
162    Tcl_DStringAppend(&ds, buf, -1);
163    sprintf(buf, "num_frames=\"%lu\" ", (unsigned long int)stats.nFrames);
164    Tcl_DStringAppend(&ds, buf, -1);
165    sprintf(buf, "frame_bytes=\"%lu\" ", (unsigned long int)stats.nBytes);
166    Tcl_DStringAppend(&ds, buf, -1);
167    sprintf(buf, "num_commands=\"%lu\" ", (unsigned long int)stats.nCommands);
168    Tcl_DStringAppend(&ds, buf, -1);
169    sprintf(buf, "cmd_time=\"%g\" ", stats.cmdTime);
170    Tcl_DStringAppend(&ds, buf, -1);
171    sprintf(buf, "session_time=\"%g\" ", finish - start);
172    Tcl_DStringAppend(&ds, buf, -1);
173    sprintf(buf, "status=\"%d\" ", code);
174    Tcl_DStringAppend(&ds, buf, -1);
175    {
176        long clocksPerSec = sysconf(_SC_CLK_TCK);
177        double clockRes = 1.0 / clocksPerSec;
178        struct tms tms;
179
180        memset(&tms, 0, sizeof(tms));
181        times(&tms);
182        sprintf(buf, "utime=\"%g\" ", tms.tms_utime * clockRes);
183        Tcl_DStringAppend(&ds, buf, -1);
184        sprintf(buf, "stime=\"%g\" ", tms.tms_stime * clockRes);
185        Tcl_DStringAppend(&ds, buf, -1);
186        sprintf(buf, "cutime=\"%g\" ", tms.tms_cutime * clockRes);
187        Tcl_DStringAppend(&ds, buf, -1);
188        sprintf(buf, "cstime=\"%g\" ", tms.tms_cstime * clockRes);
189        Tcl_DStringAppend(&ds, buf, -1);
190    }
191    Tcl_DStringAppend(&ds, "/>\n", -1);
192
193    {
194        int f;
195        ssize_t length;
196        int result;
197
198#define STATSDIR        "/var/tmp/visservers"
199#define STATSFILE       STATSDIR "/" "data.xml"
200        if (access(STATSDIR, X_OK) != 0) {
201            mkdir(STATSDIR, 0770);
202        }
203        length = Tcl_DStringLength(&ds);
204        f = open(STATSFILE, O_APPEND | O_CREAT | O_WRONLY, 0600);
205        result = FALSE;
206        if (f < 0) {
207            goto error;
208        }
209        if (write(f, Tcl_DStringValue(&ds), length) != length) {
210            goto error;
211        }
212        result = TRUE;
213 error:
214        if (f >= 0) {
215            close(f);
216        }
217        Tcl_DStringFree(&ds);
218        return result;
219    }
220}
221#endif
222
223static void
224DoExit(int code)
225{
226    char fileName[200];
227#if KEEPSTATS
228    WriteStats("pymolproxy", code);
229#endif
230    sprintf(fileName, "/tmp/pymol%d.pdb", getpid());
231    unlink(fileName);
232    exit(code);
233}
234
235static int
236ExecuteCommand(Tcl_Interp *interp, Tcl_DString *dsPtr)
237{
238    struct timeval tv;
239    double start, finish;
240    int result;
241
242    gettimeofday(&tv, NULL);
243    start = CVT2SECS(tv);
244
245    result = Tcl_Eval(interp, Tcl_DStringValue(dsPtr));
246    trace("Executed (%s)", Tcl_DStringValue(dsPtr));
247    Tcl_DStringSetLength(dsPtr, 0);
248
249    gettimeofday(&tv, NULL);
250    finish = CVT2SECS(tv);
251
252    stats.cmdTime += finish - start;
253    stats.nCommands++;
254    return result;
255}
256
257
258INLINE static void
259dyBufferInit(DyBuffer *buffer)
260{
261    buffer->data = NULL;
262    buffer->used = 0;
263    buffer->allocated = 0;
264}
265
266INLINE static void
267dyBufferFree(DyBuffer *buffer)
268{
269    assert(buffer != NULL);
270    free(buffer->data);
271    dyBufferInit(buffer);
272}
273
274static void
275dyBufferSetLength(DyBuffer *buffer, int length)
276{
277    assert(buffer != NULL);
278    if (length == 0) {
279        dyBufferFree(buffer);
280    } else if (length > buffer->used) {
281        char *newdata;
282       
283        newdata = realloc(buffer->data, length);
284        if (newdata != NULL) {
285            buffer->data = newdata;
286            buffer->used = length;
287            buffer->allocated = length;
288        }
289    } else {
290        buffer->used = length;
291    }
292}
293
294static void
295dyBufferAppend(DyBuffer *buffer, const char *data, int length)
296{
297    int offset;
298
299    assert(buffer != NULL);
300    offset = buffer->used;
301    dyBufferSetLength(buffer, offset + length);
302    memcpy(buffer->data + offset, data, length);
303}
304
305static int
306bwrite(int sock, char *buffer, int size)
307{
308    int result;
309    int total = 0;
310    int left = size;
311
312    trace("bwrite: want to write %d bytes.", size);
313    while(1) {
314        result = write(sock,buffer+total,left);
315
316        if (result <= 0)
317            break;
318
319        total += result;
320        left -= result;
321
322        if (total == size)
323            break;
324    }
325    trace("bwrite: wrote %d bytes.", total);
326    return total;
327}
328
329static int
330bread(int sock, char *buffer, int size)
331{
332    int result, total, left;
333
334    for( total = 0, left = size; left > 0; left -= result) {
335        result = read(sock,buffer+total,left);
336       
337        if (result > 0) {
338            total += result;
339            continue;
340        }
341       
342        if ((result < 0) && (errno != EAGAIN) && (errno != EINTR)) {
343            trace("Error reading sock(%d), %d/%s.", sock, errno,
344                  strerror(errno));
345            break;
346        }
347       
348        result = 0;
349    }
350    return total;
351}
352
353#ifdef notdef
354
355static int
356bflush(int sock, char *buffer, int size, int bytes)
357{
358    int bsize;
359
360    while(bytes) {
361        if (bytes > size)
362            bsize = size;
363        else
364            bsize = bytes;
365       
366        bsize = bread(sock,buffer,bsize);
367       
368        bytes -= bsize;     
369    }
370}
371
372#undef timersub
373static void
374timersub(struct timeval *a, struct timeval *b, struct timeval *result)
375{
376    result->tv_sec = a->tv_sec - b->tv_sec;
377    result->tv_usec = a->tv_usec - b->tv_usec;
378
379    while(result->tv_usec < 0) {
380        result->tv_sec -= 1;
381        result->tv_usec += 1000000;
382    }
383}
384
385#endif
386
387static void
388timersub_ms(struct timeval *a, struct timeval *b, int *result)
389{
390    struct timeval tmp;
391
392    tmp.tv_sec = a->tv_sec - b->tv_sec;
393    tmp.tv_usec = a->tv_usec - b->tv_usec;
394
395    while(tmp.tv_usec < 0) {
396        tmp.tv_sec -= 1;
397        tmp.tv_usec += 1000000;
398    }
399
400    *result = (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
401}
402
403#undef timeradd
404static void
405timeradd (struct timeval *a, struct timeval *b, struct timeval *result)
406{
407    result->tv_sec = a->tv_sec + b->tv_sec;
408    result->tv_usec = a->tv_usec + b->tv_usec;
409
410    while (result->tv_usec >= 1000000) {
411        result->tv_sec += 1;
412        result->tv_usec -= 1000000;
413    }
414}
415
416static void
417timerset_ms(struct timeval *result, int timeout)
418{
419    result->tv_sec = timeout / 1000;
420    result->tv_usec = (timeout % 1000) * 1000;
421}
422
423INLINE static void
424clear_error(PymolProxy *proxyPtr)
425{
426    proxyPtr->error = 0;
427    proxyPtr->status = TCL_OK;
428}
429
430static int
431getline(int sock, char *buffer, int size, int timeout)
432{
433    int pos = 0, status, timeo;
434    struct timeval now, end, tmo;
435    struct pollfd ufd;
436
437    gettimeofday(&now,NULL);
438    timerset_ms(&tmo, timeout);
439    timeradd(&now,&tmo,&end);
440
441    ufd.fd = sock;
442    ufd.events = POLLIN;
443
444    size--;
445
446    while(pos < size) {
447        if (timeout > 0) {
448            gettimeofday(&now,NULL);
449            timersub_ms(&now,&end,&timeo);
450        }
451        else
452            timeo = -1;
453
454        status = poll(&ufd, 1, timeo);
455
456        if (status > 0)
457            status = read(sock,&buffer[pos],1);
458
459        if ( (status < 0) && ( (errno == EINTR) || (errno == EAGAIN) ) )
460            continue; /* try again, if interrupted/blocking */
461
462        if (status <= 0) {
463            trace("getline: status=%d, errno=%d", status, errno);
464            break;
465        }
466        if (buffer[pos] == '\n') {
467            pos++;
468            break;
469        }
470        pos++;
471    }
472
473    buffer[pos]=0;
474    return pos;
475}
476
477static int
478Expect(PymolProxy *proxyPtr, char *match, char *buffer, int length)
479{
480    int sock;
481    char c;
482    size_t mlen;
483
484    assert(buffer != NULL);
485    if (proxyPtr->status != TCL_OK)
486        return proxyPtr->status;
487
488    sock = proxyPtr->p_stdout;
489    trace("Expect(%s)", match);
490    c = match[0];
491    mlen = strlen(match);
492    for (;;) {
493        if (getline(sock, buffer, length, IO_TIMEOUT) == 0) {
494            proxyPtr->error = 2;
495            proxyPtr->status = TCL_ERROR;
496            break;
497        }
498        trace("stdout-u>read(%s)", buffer);
499        if ((c == buffer[0]) && (strncmp(buffer, match, mlen) == 0)) {
500            trace("stdout-e> %s", buffer);
501            clear_error(proxyPtr);
502            break;
503        }
504    }
505
506    return proxyPtr->status;
507}
508
509static int
510Send(PymolProxy *proxyPtr, char *format, ...)
511{
512    va_list ap;
513    char iobuffer[BUFSIZ];
514
515    if (proxyPtr->error) {
516        return TCL_ERROR;
517    }
518    va_start(ap, format);
519    vsnprintf(iobuffer, 800, format, ap);
520    va_end(ap);
521
522    trace("to-pymol>(%s)", iobuffer);
523
524    /* Write the command out to the server. */
525    write(proxyPtr->p_stdin, iobuffer, strlen(iobuffer));
526
527    /* Now wait for the "PyMOL>" prompt. */
528    if (Expect(proxyPtr, "PyMOL>", iobuffer, BUFSIZ)) {
529        trace("timeout reading data (iobuffer=%s)", iobuffer);
530        proxyPtr->error = 1;
531        proxyPtr->status = TCL_ERROR;
532        return proxyPtr->status;
533    }
534    return  proxyPtr->status;
535}
536
537static int
538BallNStickCmd(ClientData clientData, Tcl_Interp *interp, int argc,
539              const char *argv[])
540{
541    float radius, transparency;
542    int ghost = 0, defer = 0, push = 0, arg;
543    const char *model = "all";
544    PymolProxy *proxyPtr = clientData;
545
546    clear_error(proxyPtr);
547
548    for(arg = 1; arg < argc; arg++) {
549        if ( strcmp(argv[arg],"-defer") == 0 )
550            defer = 1;
551        else if (strcmp(argv[arg],"-push") == 0)
552            push = 1;
553        else if (strcmp(argv[arg],"-ghost") == 0)
554            ghost = 1;
555        else if (strcmp(argv[arg],"-normal") == 0)
556            ghost = 0;
557        else if (strcmp(argv[arg],"-model") == 0) {
558            if (++arg < argc)
559                model = argv[arg];
560        }
561        else
562            model = argv[arg];
563    }
564
565    proxyPtr->invalidate_cache = 1;
566    proxyPtr->need_update = !defer || push;
567    proxyPtr->immediate_update |= push;
568
569    Send(proxyPtr, "hide everything,%s\n",model);
570    Send(proxyPtr, "set stick_color,white,%s\n",model);
571    if (ghost) {
572        radius = 0.1f;
573        transparency = 0.75f;
574    } else {
575        radius = 0.14f;
576        transparency = 0.0f;
577    }
578    Send(proxyPtr, "set stick_radius,%g,%s\n", radius, model);
579    Send(proxyPtr, "set sphere_scale=0.25,%s\n", model);
580    Send(proxyPtr, "set sphere_transparency,%g,%s\n", transparency, model);
581    Send(proxyPtr, "set stick_transparency,%g,%s\n", transparency, model);
582    Send(proxyPtr, "show sticks,%s\n",model);
583    Send(proxyPtr, "show spheres,%s\n",model);
584
585    if (proxyPtr->labels)
586        Send(proxyPtr, "show labels,%s\n", model);
587
588    return proxyPtr->status;
589}
590
591static int
592SpheresCmd(ClientData clientData, Tcl_Interp *interp, int argc,
593           const char *argv[])
594{
595    int defer = 0, ghost = 0, push = 0, arg;
596    const char *model = "all";
597    PymolProxy *proxyPtr = clientData;
598
599    clear_error(proxyPtr);
600
601    for(arg = 1; arg < argc; arg++) {
602        if ( strcmp(argv[arg],"-defer") == 0 )
603            defer = 1;
604        else if (strcmp(argv[arg],"-push") == 0)
605            push = 1;
606        else if (strcmp(argv[arg],"-ghost") == 0)
607            ghost = 1;
608        else if (strcmp(argv[arg],"-normal") == 0)
609            ghost = 0;
610        else if (strcmp(argv[arg],"-model") == 0) {
611            if (++arg < argc)
612                model = argv[arg];
613        }
614        else
615            model = argv[arg];
616    }
617
618    proxyPtr->invalidate_cache = 1;
619    proxyPtr->need_update = !defer || push;
620    proxyPtr->immediate_update |= push;
621
622    Send(proxyPtr, "hide everything, %s\n", model);
623    Send(proxyPtr, "set sphere_scale,0.41,%s\n", model);
624    //Send(proxyPtr, "set sphere_quality,2,%s\n", model);
625    Send(proxyPtr, "set ambient,.2,%s\n", model);
626
627    if (ghost)
628        Send(proxyPtr, "set sphere_transparency,.75,%s\n", model);
629    else
630        Send(proxyPtr, "set sphere_transparency,0,%s\n", model);
631
632    Send(proxyPtr, "show spheres,%s\n", model);
633
634    if (proxyPtr->labels)
635        Send(proxyPtr, "show labels,%s\n", model);
636
637    return proxyPtr->status;
638}
639
640static int
641LinesCmd(ClientData clientData, Tcl_Interp *interp, int argc,
642         const char *argv[])
643{
644    int ghost = 0, defer = 0, push = 0, arg;
645    const char *model = "all";
646    PymolProxy *proxyPtr = clientData;
647    float lineWidth;
648
649    clear_error(proxyPtr);
650
651    for(arg = 1; arg < argc; arg++) {
652        if ( strcmp(argv[arg],"-defer") == 0 )
653            defer = 1;
654        else if (strcmp(argv[arg],"-push") == 0)
655            push = 1;
656        else if (strcmp(argv[arg],"-ghost") == 0)
657            ghost = 1;
658        else if (strcmp(argv[arg],"-normal") == 0)
659            ghost = 0;
660        else if (strcmp(argv[arg],"-model") == 0) {
661            if (++arg < argc)
662                model = argv[arg];
663        }
664        else
665            model = argv[arg];
666    }
667
668    proxyPtr->invalidate_cache = 1;
669    proxyPtr->need_update = !defer || push;
670    proxyPtr->immediate_update |= push;
671
672    Send(proxyPtr, "hide everything,%s\n",model);
673
674    lineWidth = (ghost) ? 0.25f : 1.0f;
675    Send(proxyPtr, "set line_width,%g,%s\n", lineWidth, model);
676    Send(proxyPtr, "show lines,%s\n",model);
677    if (proxyPtr->labels)
678        Send(proxyPtr, "show labels,%s\n",model);
679
680    return proxyPtr->status;
681}
682
683static int
684DisableCmd(ClientData clientData, Tcl_Interp *interp, int argc,
685           const char *argv[])
686{
687    PymolProxy *proxyPtr = clientData;
688    const char *model = "all";
689    int arg, defer = 0, push = 0;
690
691    clear_error(proxyPtr);
692
693    for(arg = 1; arg < argc; arg++) {
694
695        if (strcmp(argv[arg], "-defer") == 0 )
696            defer = 1;
697        else if (strcmp(argv[arg], "-push") == 0 )
698            push = 1;
699        else
700            model = argv[arg];
701       
702    }
703
704    proxyPtr->need_update = !defer || push;
705    proxyPtr->immediate_update |= push;
706    proxyPtr->invalidate_cache = 1;
707
708    Send( proxyPtr, "disable %s\n", model);
709
710    return proxyPtr->status;
711}
712
713static int
714EnableCmd(ClientData clientData, Tcl_Interp *interp, int argc,
715          const char *argv[])
716{
717    PymolProxy *proxyPtr = clientData;
718    const char *model = "all";
719    int arg, defer = 0, push = 0;
720
721    clear_error(proxyPtr);
722
723    for(arg = 1; arg < argc; arg++) {
724               
725        if (strcmp(argv[arg],"-defer") == 0)
726            defer = 1;
727        else if (strcmp(argv[arg], "-push") == 0 )
728            push = 1;
729        else
730            model = argv[arg];
731
732    }
733
734    proxyPtr->need_update = !defer || push;
735    proxyPtr->immediate_update |= push;
736    proxyPtr->invalidate_cache = 1;
737
738    Send( proxyPtr, "enable %s\n", model);
739
740    return proxyPtr->status;
741}
742
743static int
744VMouseCmd(ClientData clientData, Tcl_Interp *interp, int argc,
745          const char *argv[])
746{
747    PymolProxy *proxyPtr = clientData;
748    int arg, defer = 0, push = 0, varg = 1;
749    int arg1 = 0, arg2 = 0, arg3 = 0, arg4 = 0, arg5 = 0;
750
751    clear_error(proxyPtr);
752
753    for(arg = 1; arg < argc; arg++) {
754        if (strcmp(argv[arg], "-defer") == 0)
755            defer = 1;
756        else if (strcmp(argv[arg], "-push") == 0)
757            push = 1;
758        else if (varg == 1) {
759            arg1 = atoi(argv[arg]);
760            varg++;
761        }
762        else if (varg == 2) {
763            arg2 = atoi(argv[arg]);
764            varg++;
765        }
766        else if (varg == 3) {
767            arg3 = atoi(argv[arg]);
768            varg++;
769        }
770        else if (varg == 4) {
771            arg4 = atoi(argv[arg]);
772            varg++;
773        }
774        else if (varg == 5) {
775            arg5 = atoi(argv[arg]);
776            varg++;
777        }
778    }
779
780    proxyPtr->need_update = !defer || push;
781    proxyPtr->immediate_update |= push;
782    proxyPtr->invalidate_cache = 1;
783
784    Send(proxyPtr, "vmouse %d,%d,%d,%d,%d\n", arg1, arg2, arg3,
785                    arg4, arg5);
786
787    return proxyPtr->status;
788}
789
790static int
791RawCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
792{
793    PymolProxy *proxyPtr = clientData;
794    DyBuffer buffer;
795    int arg, defer = 0, push = 0;
796    const char *cmd;
797    clear_error(proxyPtr);
798
799    dyBufferInit(&buffer);
800
801    cmd = NULL;
802    for(arg = 1; arg < argc; arg++) {
803        if (strcmp(argv[arg], "-defer") == 0)
804            defer = 1;
805        else if (strcmp(argv[arg], "-push") == 0)
806            push = 1;
807        else {
808            cmd = argv[arg];
809        }
810    }
811
812    proxyPtr->need_update = !defer || push;
813    proxyPtr->immediate_update |= push;
814    proxyPtr->invalidate_cache = 1;
815
816    Send(proxyPtr,"%s\n", cmd);
817    dyBufferFree(&buffer);
818
819    return proxyPtr->status;
820}
821
822static int
823LabelCmd(ClientData clientData, Tcl_Interp *interp, int argc,
824         const char *argv[])
825{
826    PymolProxy *proxyPtr = clientData;
827    int state = 1;
828    int arg, push = 0, defer = 0;
829
830    clear_error(proxyPtr);
831
832    for(arg = 1; arg < argc; arg++) {
833        if ( strcmp(argv[arg],"-defer") == 0 )
834            defer = 1;
835        else if (strcmp(argv[arg],"-push") == 0 )
836            push = 1;
837        else if (strcmp(argv[arg],"on") == 0 )
838            state = 1;
839        else if (strcmp(argv[arg],"off") == 0 )
840            state = 0;
841        else if (strcmp(argv[arg],"toggle") == 0 )
842            state =  !proxyPtr->labels;
843    }
844
845    proxyPtr->need_update = !defer || push;
846    proxyPtr->immediate_update |= push;
847    proxyPtr->invalidate_cache = 1;
848
849    if (state) {
850        Send(proxyPtr, "set label_color,white,all\n");
851        Send(proxyPtr, "set label_size,14,all\n");
852        Send(proxyPtr, "label all,\"%%s%%s\" %% (ID,name)\n");
853    }
854    else
855        Send(proxyPtr, "label all\n");
856
857    proxyPtr->labels = state;
858
859    return proxyPtr->status;
860}
861
862static int
863FrameCmd(ClientData clientData, Tcl_Interp *interp, int argc,
864         const char *argv[])
865{
866    PymolProxy *proxyPtr = clientData;
867    int frame = 0;
868    int arg, push = 0, defer = 0;
869
870    clear_error(proxyPtr);
871
872    for(arg = 1; arg < argc; arg++) {
873        if ( strcmp(argv[arg],"-defer") == 0 )
874            defer = 1;
875        else if (strcmp(argv[arg],"-push") == 0 )
876            push = 1;
877        else
878            frame = atoi(argv[arg]);
879    }
880               
881    proxyPtr->need_update = !defer || push;
882    proxyPtr->immediate_update |= push;
883
884    proxyPtr->frame = frame;
885
886    Send(proxyPtr,"frame %d\n", frame);
887       
888    return proxyPtr->status;
889}
890
891static int
892ResetCmd(ClientData clientData, Tcl_Interp *interp, int argc,
893         const char *argv[])
894{
895    PymolProxy *proxyPtr = clientData;
896    int arg, push = 0, defer = 0;
897
898    clear_error(proxyPtr);
899
900    for(arg = 1; arg < argc; arg++) {
901        if ( strcmp(argv[arg],"-defer") == 0 )
902            defer = 1;
903        else if (strcmp(argv[arg],"-push") == 0 )
904            push = 1;
905    }
906               
907    proxyPtr->need_update = !defer || push;
908    proxyPtr->immediate_update |= push;
909    proxyPtr->invalidate_cache = 1;
910       
911    Send(proxyPtr, "reset\n");
912    Send(proxyPtr, "zoom buffer=2\n");
913
914    return proxyPtr->status;
915}
916
917static int
918RockCmd(ClientData clientData, Tcl_Interp *interp, int argc,
919        const char *argv[])
920{
921    PymolProxy *proxyPtr = clientData;
922    float y = 0.0;
923    int arg, push = 0, defer = 0;
924
925    clear_error(proxyPtr);
926
927    for(arg = 1; arg < argc; arg++) {
928        if ( strcmp(argv[arg],"-defer") == 0 )
929            defer = 1;
930        else if (strcmp(argv[arg],"-push") == 0 )
931            push = 1;
932        else
933            y = atof( argv[arg] );
934    }
935               
936    proxyPtr->need_update = !defer || push;
937    proxyPtr->immediate_update |= push;
938
939    Send(proxyPtr,"turn y, %f\n", y - proxyPtr->rock_offset);
940
941    proxyPtr->rock_offset = y;
942
943    return proxyPtr->status;
944}
945
946static int
947ViewportCmd(ClientData clientData, Tcl_Interp *interp, int argc,
948            const char *argv[])
949{
950    PymolProxy *proxyPtr = clientData;
951    int width = 640, height = 480;
952    int defer = 0, push = 0, arg, varg = 1;
953
954    clear_error(proxyPtr);
955
956    for(arg = 1; arg < argc; arg++) {
957        if ( strcmp(argv[arg],"-defer") == 0 )
958            defer = 1;
959        else if ( strcmp(argv[arg], "-push") == 0 )
960            push = 1;
961        else if (varg == 1) {
962            width = atoi(argv[arg]);
963            height = width;
964            varg++;
965        }
966        else if (varg == 2) {
967            height = atoi(argv[arg]);
968            varg++;
969        }
970    }
971
972    proxyPtr->need_update = !defer || push;
973    proxyPtr->immediate_update |= push;
974    proxyPtr->invalidate_cache = 1;
975
976    Send(proxyPtr, "viewport %d,%d\n", width, height);
977
978    //usleep(205000); // .2s delay for pymol to update its geometry *HACK ALERT*
979       
980    return proxyPtr->status;
981}
982
983static int
984LoadPDBCmd(ClientData clientData, Tcl_Interp *interp, int argc,
985           const char *argv[])
986{
987    const char *pdbdata, *name;
988    PymolProxy *proxyPtr = clientData;
989    int state = 1;
990    int arg, defer = 0, push = 0, varg = 1;
991   
992    if (proxyPtr == NULL)
993        return TCL_ERROR;
994    clear_error(proxyPtr);
995    pdbdata = name = NULL;      /* Suppress compiler warning. */
996    for(arg = 1; arg < argc; arg++) {
997        if ( strcmp(argv[arg],"-defer") == 0 )
998            defer = 1;
999        else if (strcmp(argv[arg],"-push") == 0)
1000            push = 1;
1001        else if (varg == 1) {
1002            pdbdata = argv[arg];
1003            varg++;
1004        } else if (varg == 2) {
1005            name = argv[arg];
1006            varg++;
1007        } else if (varg == 3) {
1008            state = atoi( argv[arg] );
1009            varg++;
1010        }
1011    }
1012   
1013    proxyPtr->need_update = !defer || push;
1014    proxyPtr->immediate_update |= push;
1015
1016    {
1017        char fileName[200];
1018        FILE *f;
1019        ssize_t nBytes, nWritten;
1020
1021        sprintf(fileName, "/tmp/pymol%d.pdb", getpid());
1022        f = fopen(fileName, "w");
1023        if (f == NULL) {
1024            trace("can't open `%s': %s", fileName, strerror(errno));
1025            perror("pymolproxy");
1026        }
1027        nBytes = strlen(pdbdata);
1028        nWritten = fwrite(pdbdata, sizeof(char), nBytes, f);
1029        if (nBytes != nWritten) {
1030            trace("short write %d wanted %d bytes", nWritten, nBytes);
1031            perror("pymolproxy");
1032        }
1033        fclose(f);
1034        Send(proxyPtr, "load %s, %s, %d\n", fileName, name, state);
1035    }
1036    Send(proxyPtr, "zoom buffer=2\n");
1037    return proxyPtr->status;
1038}
1039
1040static int
1041RotateCmd(ClientData clientData, Tcl_Interp *interp, int argc,
1042          const char *argv[])
1043{
1044    double turnx = 0.0;
1045    double turny = 0.0;
1046    double turnz = 0.0;
1047    PymolProxy *proxyPtr = clientData;
1048    int defer = 0, push = 0, arg, varg = 1;
1049
1050    clear_error(proxyPtr);
1051
1052    for(arg = 1; arg < argc; arg++) {
1053        if (strcmp(argv[arg],"-defer") == 0) {
1054            defer = 1;
1055        } else if (strcmp(argv[arg],"-push") == 0) {
1056            push = 1;
1057        } else  if (varg == 1) {
1058            turnx = atof(argv[arg]);
1059            varg++;
1060        } else if (varg == 2) {
1061            turny = atof(argv[arg]);
1062            varg++;
1063        } else if (varg == 3) {
1064            turnz = atof(argv[arg]);
1065            varg++;
1066        }
1067    }
1068    proxyPtr->need_update = !defer || push;
1069    proxyPtr->immediate_update  |= push;
1070    proxyPtr->invalidate_cache = 1;
1071
1072    if (turnx != 0.0)
1073        Send(proxyPtr,"turn x, %f\n", turnx);
1074       
1075    if (turny != 0.0)
1076        Send(proxyPtr,"turn y, %f\n", turny);
1077       
1078    if (turnz != 0.0)
1079        Send(proxyPtr,"turn z, %f\n", turnz);
1080
1081    return proxyPtr->status;
1082}
1083
1084static int
1085ZoomCmd(ClientData clientData, Tcl_Interp *interp, int argc,
1086        const char *argv[])
1087{
1088    double factor = 0.0;
1089    double zmove = 0.0;
1090    PymolProxy *proxyPtr = clientData;
1091    int defer = 0, push = 0, arg, varg = 1;
1092
1093    clear_error(proxyPtr);
1094
1095    for(arg = 1; arg < argc; arg++) {
1096        if (strcmp(argv[arg],"-defer") == 0)
1097            defer = 1;
1098        else if (strcmp(argv[arg],"-push") == 0)
1099            push = 1;
1100        else if (varg == 1) {
1101            factor = atof(argv[arg]);
1102            varg++;
1103        }
1104    }
1105    zmove = factor * -75;
1106 
1107    proxyPtr->need_update = !defer || push;
1108    proxyPtr->immediate_update  |= push;
1109    proxyPtr->invalidate_cache = 1;
1110
1111    if (zmove != 0.0)
1112        Send(proxyPtr,"move z, %f\n", factor);
1113
1114    return proxyPtr->status;
1115}
1116
1117static int
1118PNGCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
1119{
1120    char buffer[800];
1121    unsigned int nBytes=0;
1122    float samples = 10.0;
1123    PymolProxy *proxyPtr = clientData;
1124
1125    clear_error(proxyPtr);
1126
1127    if (proxyPtr->invalidate_cache)
1128        proxyPtr->cacheid++;
1129
1130    proxyPtr->need_update = 0;
1131    proxyPtr->immediate_update = 0;
1132    proxyPtr->invalidate_cache = 0;
1133
1134    Send(proxyPtr,"png -\n");
1135
1136    Expect(proxyPtr, "image follows: ", buffer, 800);
1137
1138    sscanf(buffer, "image follows: %d\n", &nBytes);
1139 
1140    write(3, &samples, sizeof(samples));
1141 
1142    dyBufferSetLength(&proxyPtr->image, nBytes);
1143
1144    bread(proxyPtr->p_stdout, proxyPtr->image.data, proxyPtr->image.used);
1145
1146    Expect(proxyPtr, " ScenePNG", buffer,800);
1147
1148    if ((nBytes > 0) && (proxyPtr->image.used == nBytes)) {
1149        sprintf(buffer, "nv>image %d %d %d %d\n",
1150                nBytes, proxyPtr->cacheid, proxyPtr->frame, proxyPtr->rock_offset);
1151        trace("to-molvis> %s", buffer);
1152        write(proxyPtr->c_stdin, buffer, strlen(buffer));
1153        bwrite(proxyPtr->c_stdin, proxyPtr->image.data, nBytes);
1154        stats.nFrames++;
1155        stats.nBytes += nBytes;
1156    }
1157    return proxyPtr->status;
1158}
1159
1160static int
1161BMPCmd(ClientData clientData, Tcl_Interp *interp, int argc, const char *argv[])
1162{
1163    char buffer[800];
1164    unsigned int nBytes=0;
1165    float samples = 10.0;
1166    PymolProxy *proxyPtr = clientData;
1167
1168    clear_error(proxyPtr);
1169
1170    if (proxyPtr->invalidate_cache)
1171        proxyPtr->cacheid++;
1172
1173    proxyPtr->need_update = 0;
1174    proxyPtr->immediate_update = 0;
1175    proxyPtr->invalidate_cache = 0;
1176
1177    Send(proxyPtr,"bmp -\n");
1178
1179    Expect(proxyPtr, "image follows: ", buffer, 800);
1180
1181    sscanf(buffer, "image follows: %d\n", &nBytes);
1182    write(3,&samples,sizeof(samples));
1183
1184    dyBufferSetLength(&proxyPtr->image, nBytes);
1185
1186    bread(proxyPtr->p_stdout, proxyPtr->image.data, proxyPtr->image.used);
1187
1188    if ((nBytes > 0) && (proxyPtr->image.used == nBytes)) {
1189        sprintf(buffer, "nv>image %d %d %d %d\n",
1190                nBytes, proxyPtr->cacheid, proxyPtr->frame, proxyPtr->rock_offset);
1191        write(proxyPtr->c_stdin, buffer, strlen(buffer));
1192        trace("to-molvis buffer=%s", buffer);
1193        bwrite(proxyPtr->c_stdin, proxyPtr->image.data, nBytes);
1194        stats.nFrames++;
1195        stats.nBytes += nBytes;
1196    }
1197    return proxyPtr->status;
1198}
1199       
1200static int
1201ProxyInit(int c_in, int c_out, char *const *argv)
1202{
1203    int flags, status, result = 0;
1204    int pairIn[2];
1205    int pairOut[2];
1206    int pairErr[2];
1207    Tcl_Interp *interp;
1208    Tcl_DString cmdbuffer;
1209    DyBuffer dybuffer, dybuffer2;
1210    struct pollfd ufd[3];
1211    int pid;
1212    PymolProxy proxy;
1213    struct timeval now, end;
1214    int timeout;
1215
1216    /* Create three pipes for communication with the external application. One
1217     * each for the applications's: stdin, stdout, and stderr  */
1218
1219    if (pipe(pairIn) == -1)
1220        return -1;
1221
1222    if (pipe(pairOut) == -1) {
1223        close(pairIn[0]);
1224        close(pairIn[1]);
1225        return -1;
1226    }
1227
1228    if (pipe(pairErr) == -1) {
1229        close(pairIn[0]);
1230        close(pairIn[1]);
1231        close(pairOut[0]);
1232        close(pairOut[1]);
1233        return -1;
1234    }
1235
1236    /* Fork the new process.  Connect i/o to the new socket.  */
1237
1238    pid = fork();
1239       
1240    if (pid < 0) {
1241        fprintf(stderr, "can't fork process: %s\n", strerror(errno));
1242        return -3;
1243    }
1244    if (pid == 0) {
1245        int fd;
1246
1247        /* Child process */
1248       
1249        /*
1250         * Create a new process group, so we can later kill this process and
1251         * all its children without affecting the process that created this
1252         * one.
1253         */
1254        setpgid(pid, 0);
1255       
1256        /* Redirect stdin, stdout, and stderr to pipes before execing */
1257        dup2(pairIn[0] ,0);  // stdin
1258        dup2(pairOut[1],1);  // stdout
1259        dup2(pairErr[1],2);  // stderr
1260       
1261        for(fd = 3; fd < FD_SETSIZE; fd++)  /* close all other descriptors  */
1262            close(fd);
1263       
1264        execvp(argv[0], argv);
1265        trace("Failed to start pymol `%s'", argv[0]);
1266        exit(-1);
1267    }
1268    stats.child = pid;
1269
1270    /* close opposite end of pipe, these now belong to the child process        */
1271    close(pairIn[0]);
1272    close(pairOut[1]);
1273    close(pairErr[1]);
1274
1275    signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE (ie if nanoscale terminates)
1276
1277    proxy.p_stdin = pairIn[1];
1278    proxy.p_stdout = pairOut[0];
1279    proxy.p_stderr = pairErr[0];
1280    proxy.c_stdin  = c_in;
1281    proxy.c_stdout = c_out;
1282    proxy.labels = 0;
1283    proxy.need_update = 0;
1284    proxy.can_update = 1;
1285    proxy.immediate_update = 0;
1286    proxy.sync = 0;
1287    proxy.frame = 1;
1288    proxy.rock_offset = 0;
1289    proxy.cacheid = 0;
1290    proxy.invalidate_cache = 0;
1291
1292    ufd[0].fd = proxy.c_stdout;
1293    ufd[0].events = POLLIN | POLLHUP; /* ensure catching EOF */
1294    ufd[1].fd = proxy.p_stdout;
1295    ufd[1].events = POLLIN | POLLHUP;
1296    ufd[2].fd = proxy.p_stderr;
1297    ufd[2].events = POLLIN | POLLHUP;
1298
1299    flags = fcntl(proxy.p_stdout, F_GETFL);
1300    fcntl(proxy.p_stdout, F_SETFL, flags|O_NONBLOCK);
1301
1302    interp = Tcl_CreateInterp();
1303    Tcl_MakeSafe(interp);
1304
1305    Tcl_DStringInit(&cmdbuffer);
1306    dyBufferInit(&proxy.image);
1307    dyBufferInit(&dybuffer);
1308    dyBufferInit(&dybuffer2);
1309
1310    Tcl_CreateCommand(interp, "bmp",     BMPCmd,        &proxy, NULL);
1311    Tcl_CreateCommand(interp, "png",     PNGCmd,        &proxy, NULL);
1312    Tcl_CreateCommand(interp, "screen",  ViewportCmd,   &proxy, NULL);
1313    Tcl_CreateCommand(interp, "viewport",ViewportCmd,   &proxy, NULL);
1314    Tcl_CreateCommand(interp, "rotate",  RotateCmd,     &proxy, NULL);
1315    Tcl_CreateCommand(interp, "zoom",    ZoomCmd,       &proxy, NULL);
1316    Tcl_CreateCommand(interp, "loadpdb", LoadPDBCmd,    &proxy, NULL);
1317    Tcl_CreateCommand(interp, "ballnstick",BallNStickCmd, &proxy, NULL);
1318    Tcl_CreateCommand(interp, "spheres", SpheresCmd,    &proxy, NULL);
1319    Tcl_CreateCommand(interp, "lines",   LinesCmd,      &proxy, NULL);
1320    Tcl_CreateCommand(interp, "raw",     RawCmd,        &proxy, NULL);
1321    Tcl_CreateCommand(interp, "label",   LabelCmd,      &proxy, NULL);
1322    Tcl_CreateCommand(interp, "reset",   ResetCmd,      &proxy, NULL);
1323    Tcl_CreateCommand(interp, "rock",    RockCmd,       &proxy, NULL);
1324    Tcl_CreateCommand(interp, "frame",   FrameCmd,      &proxy, NULL);
1325    Tcl_CreateCommand(interp, "vmouse",  VMouseCmd,     &proxy, NULL);
1326    Tcl_CreateCommand(interp, "disable", DisableCmd,    &proxy, NULL);
1327    Tcl_CreateCommand(interp, "enable",  EnableCmd,     &proxy, NULL);
1328
1329    // Main Proxy Loop
1330    //  accept tcl commands from socket
1331    //  translate them into pyMol commands, and issue them to child proccess
1332    //  send images back
1333
1334    gettimeofday(&end, NULL);
1335    stats.start = end;
1336    while(1) {
1337        gettimeofday(&now,NULL);
1338       
1339        if ( (!proxy.need_update) )
1340            timeout = -1;
1341        else if ((now.tv_sec > end.tv_sec) || ( (now.tv_sec == end.tv_sec) && (now.tv_usec >= end.tv_usec)) )
1342            timeout = 0;
1343        else {
1344            timeout = (end.tv_sec - now.tv_sec) * 1000;
1345           
1346            if (end.tv_usec > now.tv_usec)
1347                timeout += (end.tv_usec - now.tv_usec) / 1000;
1348            else
1349                timeout += (((1000000 + end.tv_usec) - now.tv_usec) / 1000) - 1000;
1350           
1351        }
1352       
1353        status = 0;
1354        errno = 0;
1355        if (!proxy.immediate_update) {
1356            status = poll(ufd, 3, timeout);
1357            trace("result of poll = %d: %s", status, strerror(errno));
1358        }
1359        if ( status < 0 ) {
1360            trace("POLL ERROR: status = %d: %s", status, strerror(errno));
1361        } else if (status > 0) {
1362
1363            gettimeofday(&now,NULL);
1364            if (ufd[0].revents & POLLIN) {
1365                /* Client Stdout Connection: command input */
1366                ssize_t nRead;
1367                char ch;
1368
1369                nRead = read(ufd[0].fd, &ch, 1);
1370                if (nRead <= 0) {
1371                    trace("unexpected read error from client (stdout): %s",
1372                          strerror(errno));
1373                    if (errno != EINTR) {
1374                        trace("lost client connection: %s", strerror(errno));
1375                        break;
1376                    }
1377                } else {
1378                    Tcl_DStringAppend(&cmdbuffer, &ch, 1);
1379                   
1380                    if (ch == '\n' &&
1381                        Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) {
1382                        int result;
1383
1384                        result = ExecuteCommand(interp, &cmdbuffer);
1385                        if (timeout == 0) {
1386                            status = 0; // send update
1387                        }
1388                    }
1389                }
1390            } else if (ufd[0].revents & POLLHUP) {
1391                trace("received hangup on stdout from client.");
1392                break;
1393            }
1394
1395            if (ufd[1].revents & POLLIN) {
1396                ssize_t nRead;
1397                char ch;
1398
1399                /* This is supposed to suck up all the extra output from the
1400                 * pymol server output after we've matched the command
1401                 * prompt.  */
1402
1403                /* pyMol Stdout Connection: pymol (unexpected) output */
1404                nRead = read(ufd[1].fd, &ch, 1);
1405                if (nRead <= 0) {
1406                    /* It's possible to have already drained the channel in
1407                     * response to a client command (handled above). Skip
1408                     * it if we're blocking. */
1409                    if ((errno == EAGAIN) || (errno == EINTR)) {
1410                        trace("try again to read (stdout) to pymol server.");
1411                        goto nextchannel;
1412                    }
1413                    trace("lost connection (stdout) from pymol server.");
1414                    break;
1415                } else {
1416                    dyBufferAppend(&dybuffer, &ch, 1);
1417                   
1418                    if (ch == '\n') {
1419                        ch = 0;
1420                        dyBufferAppend(&dybuffer, &ch, 1);
1421                        trace("STDOUT>%s",dybuffer.data);
1422                        dyBufferSetLength(&dybuffer,0);
1423                    }
1424                }
1425            } else if (ufd[1].revents & POLLHUP) {
1426                trace("received hangup on stdout to pymol server.");
1427                break;
1428            }
1429        nextchannel:
1430            if (ufd[2].revents & POLLIN) {
1431                ssize_t nRead;
1432                char ch;
1433
1434                /* pyMol Stderr Connection: pymol standard error output */
1435
1436                nRead = read(ufd[2].fd, &ch, 1);
1437                if (nRead <= 0) {
1438                    trace("unexpected read error from server (stderr): %s",
1439                          strerror(errno));
1440                    if (errno != EINTR) {
1441                        trace("lost connection (stderr) to pymol server.");
1442                        break;
1443                    }
1444                } else {
1445                    dyBufferAppend(&dybuffer2, &ch, 1);
1446                    if (ch == '\n') {
1447                        ch = 0;
1448                        dyBufferAppend(&dybuffer2, &ch, 1);
1449                        trace("stderr>%s", dybuffer2.data);
1450                        dyBufferSetLength(&dybuffer2,0);
1451                    }
1452                }
1453            } else if (ufd[2].revents & POLLHUP) {
1454                trace("received hangup on stderr from pymol server.");
1455                break;
1456            }
1457        }
1458       
1459        if (status == 0) {
1460            gettimeofday(&now,NULL);
1461           
1462            if (proxy.need_update && proxy.can_update)
1463                Tcl_Eval(interp, "bmp -\n");
1464           
1465            end.tv_sec = now.tv_sec;
1466            end.tv_usec = now.tv_usec + 150000;
1467           
1468            if (end.tv_usec >= 1000000) {
1469                end.tv_sec++;
1470                end.tv_usec -= 1000000;
1471            }
1472           
1473        }
1474       
1475    }
1476   
1477    status = waitpid(pid, &result, WNOHANG);
1478    if (status == -1) {
1479        trace("error waiting on pymol server to exit: %s", strerror(errno));
1480    } else if (status == 0) {
1481        trace("attempting to signal (SIGTERM) pymol server.");
1482        kill(-pid, SIGTERM); // kill process group
1483        alarm(5);
1484        status = waitpid(pid, &result, 0);
1485        alarm(0);
1486       
1487        while ((status == -1) && (errno == EINTR)) {
1488            trace("Attempting to signal (SIGKILL) pymol server.");
1489            kill(-pid, SIGKILL); // kill process group
1490            alarm(10);
1491            status = waitpid(pid, &result, 0);
1492            alarm(0);
1493        }
1494    }
1495   
1496    trace("pymol server process ended (result=%d)", result);
1497   
1498    dyBufferFree(&proxy.image);
1499   
1500    Tcl_DeleteInterp(interp);
1501    if (WIFEXITED(result)) {
1502        result = WEXITSTATUS(result);
1503    }
1504    DoExit(result);
1505    return 0;
1506}
1507
1508#ifdef STANDALONE
1509
1510int
1511main(int argc, char *argv[])
1512{
1513    flog = stderr;
1514    if (debug) {
1515        char fileName[200];
1516        sprintf(fileName, "/tmp/pymolproxy%d.log", getpid());
1517        flog = fopen(fileName, "w");
1518    }   
1519    ProxyInit(fileno(stdout), fileno(stdin), argv + 1);
1520    return 0;
1521}
1522
1523#endif
1524
Note: See TracBrowser for help on using the repository browser.