source: trunk/vizservers/pymolproxy/pymolproxy.c @ 951

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

More Makefile cleanup

File size: 34.8 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
827LoadPDBCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
828{
829    const char *pdbdata, *name;
830    PymolProxy *pymol = (PymolProxy *) cdata;
831    int state = 1;
832    int arg, defer = 0, push = 0, varg = 1;
833
834    clear_error(pymol);
835
836    pdbdata = name = NULL;      /* Suppress compiler warning. */
837    for(arg = 1; arg < argc; arg++) {
838        if ( strcmp(argv[arg],"-defer") == 0 )
839            defer = 1;
840        else if (strcmp(argv[arg],"-push") == 0)
841            push = 1;
842        else if (varg == 1) {
843            pdbdata = argv[arg];
844            varg++;
845        }
846        else if (varg == 2) {
847            name = argv[arg];
848            varg++;
849        }
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        int count;
861        const char *p;
862        char *q, *newdata;
863
864        count = 0;
865        for (p = pdbdata; *p != '\0'; p++) {
866            if (*p == '\n') {
867                count++;
868            }
869            count++;
870        }
871       
872        q = newdata = malloc(count + 100);
873        strcpy(newdata, "cmd.read_pdbstr(\"\"\"\\\n");
874        q = newdata + strlen(newdata);
875        for (p = pdbdata; *p != '\0'; p++, q++) {
876            if (*p == '\n') {
877                *q++ = '\\';
878            }
879            *q = *p;
880        }
881        sprintf(q, "\\\n\"\"\",\"%s\",%d)\n", name, state);
882        {
883            char expect[800];
884
885            sprintf(expect, "PyMOL>\"\"\",\"%s\",%d)\n", name, state);
886            send_expect(pymol, expect, newdata);
887        }
888        free(newdata);
889    }
890    sendf(pymol, "zoom buffer=2\n");
891
892    return pymol->status;
893}
894
895static int
896RotateCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
897{
898    double turnx = 0.0;
899    double turny = 0.0;
900    double turnz = 0.0;
901    PymolProxy *pymol = (PymolProxy *) cdata;
902    int defer = 0, push = 0, arg, varg = 1;
903
904    clear_error(pymol);
905
906    for(arg = 1; arg < argc; arg++)
907        {
908            if (strcmp(argv[arg],"-defer") == 0)
909                defer = 1;
910            else if (strcmp(argv[arg],"-push") == 0)
911                push = 1;
912            else  if (varg == 1) {
913                turnx = atof(argv[arg]);
914                varg++;
915            }
916            else if (varg == 2) {
917                turny = atof(argv[arg]);
918                varg++;
919            }
920            else if (varg == 3) {
921                turnz = atof(argv[arg]);
922                varg++;
923            }
924        }
925 
926    pymol->need_update = !defer || push;
927    pymol->immediate_update  |= push;
928    pymol->invalidate_cache = 1;
929
930    if (turnx != 0.0)
931        sendf(pymol,"turn x, %f\n", turnx);
932       
933    if (turny != 0.0)
934        sendf(pymol,"turn y, %f\n", turny);
935       
936    if (turnz != 0.0)
937        sendf(pymol,"turn z, %f\n", turnz);
938
939    return pymol->status;
940}
941
942static int
943ZoomCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
944{
945    double factor = 0.0;
946    double zmove = 0.0;
947    PymolProxy *pymol = (PymolProxy *) cdata;
948    int defer = 0, push = 0, arg, varg = 1;
949
950    clear_error(pymol);
951
952    for(arg = 1; arg < argc; arg++)
953        {
954            if (strcmp(argv[arg],"-defer") == 0)
955                defer = 1;
956            else if (strcmp(argv[arg],"-push") == 0)
957                push = 1;
958            else if (varg == 1) {
959                factor = atof(argv[arg]);
960                varg++;
961            }
962        }
963
964    zmove = factor * -75;
965 
966    pymol->need_update = !defer || push;
967    pymol->immediate_update  |= push;
968    pymol->invalidate_cache = 1;
969
970    if (zmove != 0.0)
971        sendf(pymol,"move z, %f\n", factor);
972
973    return pymol->status;
974}
975
976static int
977PNGCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
978{
979    char buffer[800];
980    unsigned int bytes=0;
981    float samples = 0.0;
982    PymolProxy *pymol = (PymolProxy *) cdata;
983
984    clear_error(pymol);
985
986    if (pymol->invalidate_cache)
987        pymol->cacheid++;
988
989    pymol->need_update = 0;
990    pymol->immediate_update = 0;
991    pymol->invalidate_cache = 0;
992
993    sendf(pymol,"png -\n");
994
995    waitForString(pymol, "image follows: ", buffer, 800);
996
997    sscanf(buffer, "image follows: %d %f\n", &bytes, &samples);
998 
999    write(3,&samples,sizeof(samples));
1000 
1001    dyBufferSetLength(&pymol->image, bytes);
1002
1003    bread(pymol->p_stdout, pymol->image.data, pymol->image.used);
1004
1005    waitForString(pymol, " ScenePNG", buffer,800);
1006
1007    if (bytes && (pymol->image.used == bytes)) {
1008        sprintf(buffer, "nv>image %d %d %d %d\n",
1009                bytes, pymol->cacheid, pymol->frame, pymol->rock_offset);
1010        trace("to-molvis> %s", buffer);
1011        write(pymol->c_stdin, buffer, strlen(buffer));
1012        bwrite(pymol->c_stdin, pymol->image.data, bytes);
1013    }
1014    return pymol->status;
1015}
1016
1017static int
1018BMPCmd(ClientData cdata, Tcl_Interp *interp, int argc, const char *argv[])
1019{
1020    char buffer[800];
1021    unsigned int bytes=0;
1022    float samples = 0.0;
1023    PymolProxy *pymol = (PymolProxy *) cdata;
1024
1025    clear_error(pymol);
1026
1027    if (pymol->invalidate_cache)
1028        pymol->cacheid++;
1029
1030    pymol->need_update = 0;
1031    pymol->immediate_update = 0;
1032    pymol->invalidate_cache = 0;
1033
1034    sendf(pymol,"bmp -\n");
1035
1036    waitForString(pymol, "image follows: ", buffer, 800);
1037
1038    sscanf(buffer, "image follows: %d %f\n", &bytes, &samples);
1039    write(3,&samples,sizeof(samples));
1040
1041    dyBufferSetLength(&pymol->image, bytes);
1042
1043    bread(pymol->p_stdout, pymol->image.data, pymol->image.used);
1044
1045    if (bytes && (pymol->image.used == bytes)) {
1046        sprintf(buffer, "nv>image %d %d %d %d\n",
1047                bytes, pymol->cacheid, pymol->frame, pymol->rock_offset);
1048        write(pymol->c_stdin, buffer, strlen(buffer));
1049        trace("to-molvis buffer=%s\n", buffer);
1050        bwrite(pymol->c_stdin, pymol->image.data, bytes);
1051    }
1052    return pymol->status;
1053}
1054       
1055static int
1056ProxyInit(int c_in, int c_out, char *const *argv)
1057{
1058    int flags, status, result = 0;
1059    int pairIn[2];
1060    int pairOut[2];
1061    int pairErr[2];
1062    Tcl_Interp *interp;
1063    Tcl_DString cmdbuffer;
1064    DyBuffer dybuffer, dybuffer2;
1065    struct pollfd ufd[3];
1066    int pid;
1067    PymolProxy pymol;
1068    struct timeval now,end;
1069    int timeout;
1070
1071    /* Create three pipes for communication with the external application. One
1072     * each for the applications's: stdin, stdout, and stderr  */
1073
1074    if (pipe(pairIn) == -1)
1075        return(-1);
1076
1077    if (pipe(pairOut) == -1) {
1078        close(pairIn[0]);
1079        close(pairIn[1]);
1080        return(-1);
1081    }
1082
1083    if (pipe(pairErr) == -1) {
1084        close(pairIn[0]);
1085        close(pairIn[1]);
1086        close(pairOut[0]);
1087        close(pairOut[1]);
1088        return(-1);
1089    }
1090
1091    /* Fork the new process.  Connect i/o to the new socket.  */
1092
1093    pid = fork();
1094       
1095    if (pid < 0) {
1096        fprintf(stderr, "can't fork process: %s\n", strerror(errno));
1097        return(-3);
1098    }
1099    if (pid == 0) {
1100        int fd;
1101
1102        /* Child process */
1103       
1104        /*
1105         * Create a new process group, so we can later kill this process and
1106         * all its children without affecting the process that created this
1107         * one.
1108         */
1109        setpgid(pid, 0);
1110       
1111        /* Redirect stdin, stdout, and stderr to pipes before execing */
1112        dup2(pairIn[0] ,0);  // stdin
1113        dup2(pairOut[1],1);  // stdout
1114        dup2(pairErr[1],2);  // stderr
1115       
1116        for(fd = 3; fd < FD_SETSIZE; fd++)  /* close all other descriptors  */
1117            close(fd);
1118       
1119        execvp(argv[0], argv);
1120        trace("pymolproxy: Failed to start pyMol %s\n", argv[0]);
1121        exit(-1);
1122    }
1123       
1124    /* close opposite end of pipe, these now belong to the child process        */
1125    close(pairIn[0]);
1126    close(pairOut[1]);
1127    close(pairErr[1]);
1128
1129    signal(SIGPIPE, SIG_IGN); // ignore SIGPIPE (ie if nanoscale terminates)
1130
1131    pymol.p_stdin = pairIn[1];
1132    pymol.p_stdout = pairOut[0];
1133    pymol.p_stderr = pairErr[0];
1134    pymol.c_stdin  = c_in;
1135    pymol.c_stdout = c_out;
1136    pymol.labels = 0;
1137    pymol.need_update = 0;
1138    pymol.can_update = 1;
1139    pymol.immediate_update = 0;
1140    pymol.sync = 0;
1141    pymol.frame = 1;
1142    pymol.rock_offset = 0;
1143    pymol.cacheid = 0;
1144    pymol.invalidate_cache = 0;
1145
1146    ufd[0].fd = pymol.c_stdout;
1147    ufd[0].events = POLLIN | POLLHUP; /* ensure catching EOF */
1148    ufd[1].fd = pymol.p_stdout;
1149    ufd[1].events = POLLIN | POLLHUP;
1150    ufd[2].fd = pymol.p_stderr;
1151    ufd[2].events = POLLIN | POLLHUP;
1152
1153    flags = fcntl(pymol.p_stdout, F_GETFL);
1154    fcntl(pymol.p_stdout, F_SETFL, flags|O_NONBLOCK);
1155
1156    interp = Tcl_CreateInterp();
1157    Tcl_MakeSafe(interp);
1158
1159    Tcl_DStringInit(&cmdbuffer);
1160    dyBufferInit(&pymol.image);
1161    dyBufferInit(&dybuffer);
1162    dyBufferInit(&dybuffer2);
1163
1164    Tcl_CreateCommand(interp, "bmp",     BMPCmd,        &pymol, NULL);
1165    Tcl_CreateCommand(interp, "png",     PNGCmd,        &pymol, NULL);
1166    Tcl_CreateCommand(interp, "screen",  ViewportCmd,   &pymol, NULL);
1167    Tcl_CreateCommand(interp, "viewport",ViewportCmd,   &pymol, NULL);
1168    Tcl_CreateCommand(interp, "rotate",  RotateCmd,     &pymol, NULL);
1169    Tcl_CreateCommand(interp, "zoom",    ZoomCmd,       &pymol, NULL);
1170    Tcl_CreateCommand(interp, "loadpdb", LoadPDBCmd,    &pymol, NULL);
1171    Tcl_CreateCommand(interp, "ballnstick",BallNStickCmd, &pymol, NULL);
1172    Tcl_CreateCommand(interp, "spheres", SpheresCmd,    &pymol, NULL);
1173    Tcl_CreateCommand(interp, "lines",   LinesCmd,      &pymol, NULL);
1174    Tcl_CreateCommand(interp, "raw",     RawCmd,        &pymol, NULL);
1175    Tcl_CreateCommand(interp, "label",   LabelCmd,      &pymol, NULL);
1176    Tcl_CreateCommand(interp, "reset",   ResetCmd,      &pymol, NULL);
1177    Tcl_CreateCommand(interp, "rock",    RockCmd,       &pymol, NULL);
1178    Tcl_CreateCommand(interp, "frame",   FrameCmd,      &pymol, NULL);
1179    Tcl_CreateCommand(interp, "vmouse",  VMouseCmd,     &pymol, NULL);
1180    Tcl_CreateCommand(interp, "disable", DisableCmd,    &pymol, NULL);
1181    Tcl_CreateCommand(interp, "enable",  EnableCmd,     &pymol, NULL);
1182
1183    // Main Proxy Loop
1184    //  accept tcl commands from socket
1185    //  translate them into pyMol commands, and issue them to child proccess
1186    //  send images back
1187
1188    gettimeofday(&end, NULL);
1189
1190    while(1)
1191        {
1192            char ch;
1193
1194            gettimeofday(&now,NULL);
1195
1196            if ( (!pymol.need_update) )
1197                timeout = -1;
1198            else if ((now.tv_sec > end.tv_sec) || ( (now.tv_sec == end.tv_sec) && (now.tv_usec >= end.tv_usec)) )
1199                timeout = 0;
1200            else
1201                {
1202                    timeout = (end.tv_sec - now.tv_sec) * 1000;
1203
1204                    if (end.tv_usec > now.tv_usec)
1205                        timeout += (end.tv_usec - now.tv_usec) / 1000;
1206                    else
1207                        timeout += (((1000000 + end.tv_usec) - now.tv_usec) / 1000) - 1000;
1208
1209                }
1210
1211            if (!pymol.immediate_update)
1212                status = poll(ufd, 3, timeout);
1213            else
1214                status = 0;
1215
1216            if ( status < 0 )
1217                {
1218                    trace("pymolproxy: POLL ERROR: status = %d, errno = %d, %s \n", status,errno,strerror(errno));
1219                }
1220            else if (status > 0)
1221                {
1222                    gettimeofday(&now,NULL);
1223
1224                    if (ufd[0].revents) { /* Client Stdout Connection: command input */
1225                        if (read(ufd[0].fd,&ch,1) <= 0)
1226                            {
1227                                if (errno != EINTR)
1228                                    {
1229                                        trace("pymolproxy: lost client connection (%d).\n", errno);
1230                                        break;
1231                                    }
1232                            }
1233                        else
1234                            {
1235                                Tcl_DStringAppend(&cmdbuffer, &ch, 1);
1236
1237                                if (ch == '\n' && Tcl_CommandComplete(Tcl_DStringValue(&cmdbuffer))) {
1238                                    Tcl_Eval(interp, Tcl_DStringValue(&cmdbuffer));
1239                                    trace("Executed(%d,%d): %s", pymol.need_update, pymol.immediate_update, Tcl_DStringValue(&cmdbuffer));
1240                                    Tcl_DStringSetLength(&cmdbuffer, 0);
1241
1242                                    if (timeout == 0) status = 0; // send update
1243                                }
1244                            }
1245                    }
1246
1247                    if (ufd[1].revents ) { /* pyMol Stdout Connection: pymol (unexpected) output */
1248                        if (read(ufd[1].fd, &ch, 1) <= 0)
1249                            {
1250                                if (errno != EINTR) {
1251                                    trace("pymolproxy: lost connection (stdout) to pymol server\n");
1252                                    break;
1253                                }
1254                            }
1255                        else
1256                            {
1257                                dyBufferAppend(&dybuffer, &ch, 1);
1258
1259                                if (ch == '\n') {
1260                                    ch = 0;
1261                                    dyBufferAppend(&dybuffer, &ch, 1);
1262                                    trace("STDOUT>%s",dybuffer.data);
1263                                    dyBufferSetLength(&dybuffer,0);
1264                                }
1265                            }
1266                    }
1267
1268                    if (ufd[2].revents) { /* pyMol Stderr Connection: pymol standard error output */
1269                        if (read(ufd[2].fd, &ch, 1) <= 0)
1270                            {
1271                                if (errno != EINTR) {
1272                                    trace("pymolproxy: lost connection (stderr) to pymol server\n");
1273                                    break;
1274                                }
1275                            }
1276                        else {
1277                            dyBufferAppend(&dybuffer2, &ch, 1);
1278
1279                            if (ch == '\n') {
1280                                ch = 0;
1281                                dyBufferAppend(&dybuffer2, &ch, 1);
1282                                trace("stderr>%s", dybuffer2.data);
1283                                dyBufferSetLength(&dybuffer2,0);
1284                            }
1285                        }
1286                    }
1287                }
1288
1289            if (status == 0)
1290                {
1291                    gettimeofday(&now,NULL);
1292
1293                    if (pymol.need_update && pymol.can_update)
1294                        Tcl_Eval(interp, "bmp -\n");
1295
1296                    end.tv_sec = now.tv_sec;
1297                    end.tv_usec = now.tv_usec + 150000;
1298
1299                    if (end.tv_usec >= 1000000)
1300                        {
1301                            end.tv_sec++;
1302                            end.tv_usec -= 1000000;
1303                        }
1304
1305                }
1306
1307        }
1308
1309    status = waitpid(pid, &result, WNOHANG);
1310
1311    if (status == -1) {
1312        trace("pymolproxy: error waiting on pymol server to exit (%d)\n", errno);
1313    } else if (status == 0) {
1314        trace("pymolproxy: attempting to SIGTERM pymol server\n");
1315        kill(-pid, SIGTERM); // kill process group
1316        alarm(5);
1317        status = waitpid(pid, &result, 0);
1318        alarm(0);
1319
1320        while ((status == -1) && (errno == EINTR))
1321            {
1322                trace("pymolproxy: Attempting to SIGKILL process.\n");
1323                kill(-pid, SIGKILL); // kill process group
1324                alarm(10);
1325                status = waitpid(pid, &result, 0);
1326                alarm(0);
1327            }
1328    }
1329
1330    trace("pymolproxy: pymol server process ended (%d)\n", result);
1331
1332    dyBufferFree(&pymol.image);
1333
1334    Tcl_DeleteInterp(interp);
1335
1336    return( (status == pid) ? 0 : 1);
1337}
1338
1339#ifdef STANDALONE
1340
1341int
1342main(int argc, char *argv[])
1343{
1344    if (debug) {
1345        flog = stderr;
1346        flog = fopen("/tmp/pymolproxy.log", "w");
1347    }   
1348    ProxyInit(fileno(stdout), fileno(stdin), argv + 1);
1349    return 0;
1350}
1351
1352#endif
1353
Note: See TracBrowser for help on using the repository browser.