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

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