PLplot: tcpip.c Source File

PLplot 5.15.0

tcpip.c
Go to the documentation of this file.
1 // Maurice LeBrun
2 // 6-Jan-94
3 //
4 // Functions to handle a variety of TPC-IP related chores, in particular
5 // socket i/o for data transfer to the Tcl-DP driver. For the latter, the
6 // Tcl-DP routines were modified to use binary records; copyright follows:
7 //
8 // Copyright 1992 Telecom Finland
9 //
10 // Permission to use, copy, modify, and distribute this
11 // software and its documentation for any purpose and without
12 // fee is hereby granted, provided that this copyright
13 // notice appears in all copies. Telecom Finland
14 // makes no representations about the suitability of this
15 // software for any purpose. It is provided "as is" without
16 // express or implied warranty.
17 //
18 // Copyright (c) 1993 The Regents of the University of California.
19 // All rights reserved.
20 //
21 // Permission to use, copy, modify, and distribute this software and its
22 // documentation for any purpose, without fee, and without written agreement is
23 // hereby granted, provided that the above copyright notice and the following
24 // two paragraphs appear in all copies of this software.
25 //
26 // IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
27 // DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
28 // OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
29 // CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 //
31 // THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
32 // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
33 // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
34 // ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
35 // PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
36 //
37 //
38 // Copyright (C) 2004 Joao Cardoso
39 //
40 // This file is part of PLplot.
41 //
42 // PLplot is free software; you can redistribute it and/or modify
43 // it under the terms of the GNU Library General Public License as published
44 // by the Free Software Foundation; either version 2 of the License, or
45 // (at your option) any later version.
46 //
47 // PLplot is distributed in the hope that it will be useful,
48 // but WITHOUT ANY WARRANTY; without even the implied warranty of
49 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50 // GNU Library General Public License for more details.
51 //
52 // You should have received a copy of the GNU Library General Public License
53 // along with PLplot; if not, write to the Free Software
54 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
55 //
56
57 //
58 // #define DEBUG
59 //
60
61 #include "plDevs.h"
62 #include "plConfig.h"
63
64 #if defined ( PLD_tk ) || defined ( ENABLE_tkX )
65
66 // This file is meant to be compiled with non-ANSI compilers ("cc").
67 // The reason for doing it this way is to ensure that the full C
68 // environment of the target machine is visible (at the time of writing
69 // this, parts of this code are not covered by any international
70 // standard). ANSI compilers are required to omit these extra symbols,
71 // and at the moment there is no way to get them back except for by
72 // vendor-specific defines, e.g. _HPUX_SOURCE (HP), _ALL_SOURCE (AIX),
73 // _DGUX_SOURCE (DGUX). This is an omission in the POSIX standard more
74 // than anything else, and will probably be rectified at some point. So
75 // for now, instead of relying on a hodgepodge of vendor specific symbols
76 // I forego the ANSI compiler here and go with good (bad) old "cc".
77 //
78
79 #ifdef _POSIX_SOURCE
80 #undef _POSIX_SOURCE
81 #endif
82 #ifdef caddr_t
83 #undef caddr_t
84 #endif
85
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <math.h>
89 #include <string.h>
90 #if defined ( __sgi ) && !defined ( SVR3 )
91 #include <sys/select.h>
92 #endif
93 #ifdef PL_HAVE_UNISTD_H
94 #include <unistd.h>
95 #endif
96
97 #include "plplot.h"
98 #include "tcpip.h"
99 #include <tcl.h>
100 #include <tk.h>
101
102 #include <sys/stat.h>
103 #include <sys/types.h>
104 #include <fcntl.h>
105 #include <ctype.h>
106 #if !defined ( _WIN32 )
107 #include <sys/uio.h>
108 #endif
109 #include <errno.h>
110
111 #if defined ( _WIN32 )
112 // This is the source of the WSAEWOULDBLOCK macro on Windows platforms.
113 #include <winerror.h>
114 #endif
115
116 #if defined ( EWOULDBLOCK )
117 #define PLPLOT_EWOULDBLOCK EWOULDBLOCK
118 #elif defined ( WSAEWOULDBLOCK )
119 #define PLPLOT_EWOULDBLOCK WSAEWOULDBLOCK
120 #else
121 #error broken system where neither EWOULDBLOCK nor WSAEWOULDBLOCK macros are #defined
122 #endif
123
124 // Supply dummy macros for the low-level I/O functions - Windows
125 #if defined ( _WIN32 )
126 #define read( a, b, c ) 0
127 #define close( a )
128 #define write( a, b, c ) 0
129 #endif
130
131 //extern int errno;
132
133 #ifndef MIN
134 #define MIN( a, b ) ( ( ( a ) < ( b ) ) ? ( a ) : ( b ) )
135 #endif
136
137 //
138 // This is a "magic number" prepended to the beginning of the packet
139 // Used to help resync the packet machanism in the event of errors.
140 //
141 #define PACKET_MAGIC 0x6feeddcc
142
143 //
144 // For TCP, it's possible to get a line in pieces. In case everything we
145 // want isn't there, we need a place to store partial results when we're
146 // in non-blocking mode. The partial buffers below are created
147 // dynamically to store incomplete data in these cases.
148 //
149
150 typedef struct PartialRead
151 {
152 char *buffer; // Buffer of characters
153 int bufSize; // Size of buffer
154 int offset; // Offset of current character within buffer
155 struct PartialRead *next; // Next buffer in chain
156 } PartialRead;
157
158 #define MAX_OPEN_FILES 128
159
160 static PartialRead *partial[MAX_OPEN_FILES];
161
162 static void pl_FreeReadBuffer( int fd );
163 static void pl_Unread( int fd, char *buffer, int numBytes, int copy );
164 static int pl_Read( int fd, char *buffer, int numReq );
165
166 int pl_PacketReceive( Tcl_Interp * interp, PLiodev *iodev, PDFstrm *pdfs );
167 int pl_PacketSend( Tcl_Interp * interp, PLiodev *iodev, PDFstrm *pdfs );
168
169 //
170 //--------------------------------------------------------------------------
171 //
172 // pl_FreeReadBuffer --
173 //
174 // This function is called to free up all the memory associated
175 // with a file once the file is closed.
176 //
177 // Results:
178 // None.
179 //
180 // Side effects:
181 // Any data buffered locally will be lost.
182 //
183 //--------------------------------------------------------------------------
184 //
185
186 static void
187 pl_FreeReadBuffer( int fd )
188 {
189 PartialRead *readList;
190
191 while ( partial[fd] != NULL )
192 {
193 readList = partial[fd];
194 partial[fd] = readList->next;
195 free( readList->buffer );
196 free( readList );
197 }
198 }
199
200 //
201 //--------------------------------------------------------------------------
202 //
203 // pl_Unread --
204 //
205 // This function puts data back into the read chain on a
206 // file descriptor. It's basically an extended "ungetc".
207 //
208 // Results:
209 // None.
210 //
211 // Side effects:
212 // Subsequent calls to pl_Read on the fd will get this data.
213 //
214 //--------------------------------------------------------------------------
215 //
216
217 static void
218 pl_Unread( int fd, char *buffer, int numBytes, int copy )
219 //int fd; // File descriptor
220 //char *buffer; // Data to unget
221 //int numBytes; // Number of bytes to unget
222 //int copy; // Should we copy the data, or use this
223 // buffer?
224 {
225 PartialRead *new;
226
227 new = (PartialRead *) malloc( sizeof ( PartialRead ) );
228 if ( copy )
229 {
230 new->buffer = (char *) malloc( (size_t) numBytes );
231 memcpy( new->buffer, buffer, (size_t) numBytes );
232 }
233 else
234 {
235 new->buffer = buffer;
236 }
237 new->bufSize = numBytes;
238 new->offset = 0;
239 new->next = partial[fd];
240 partial[fd] = new;
241 }
242
243 //
244 //--------------------------------------------------------------------------
245 //
246 // pl_Read --
247 //
248 // This function implements a "read"-like command, but
249 // buffers partial reads. The semantics are the same as
250 // with read.
251 //
252 // Results:
253 // Number of bytes read, or -1 on error (with errno set).
254 //
255 // Side effects:
256 // All available data is read from the file descriptor.
257 //
258 //--------------------------------------------------------------------------
259 //
260
261 static int
262 pl_Read( int fd, char *buffer, int numReq )
263 //int fd; // File descriptor to read from
264 //char *buffer; // Place to put the data
265 //int numReq; // Number of bytes to get
266 {
267 PartialRead *readList;
268 PartialRead *tmp;
269 int numRead;
270 int numToCopy;
271
272 readList = partial[fd];
273
274 //
275 // If there's no data left over from a previous read, then just do a read
276 // This is the common case.
277 //
278 if ( readList == NULL )
279 {
280 numRead = (int) read( fd, buffer, (size_t) numReq );
281 #ifdef DEBUG
282 {
283 int j;
284 fprintf( stderr, "received %d bytes starting with:", numRead );
285 for ( j = 0; j < MIN( 8, numRead ); j++ )
286 fprintf( stderr, " %x", 0x000000FF & (unsigned long) buffer[j] );
287 fprintf( stderr, "\n" );
288 }
289 #endif
290 return numRead;
291 }
292
293 //
294 // There's data left over from a previous read. Yank it in and
295 // only call read() if we didn't get enough data (this keeps the fd
296 // readable if they only request as much data as is in the buffers).
297 //
298 numRead = 0;
299 while ( ( readList != NULL ) && ( numRead < numReq ) )
300 {
301 numToCopy = readList->bufSize - readList->offset;
302 if ( numToCopy + numRead > numReq )
303 {
304 numToCopy = numReq - numRead;
305 }
306 memcpy( buffer + numRead, readList->buffer + readList->offset, (size_t) numToCopy );
307
308 //
309 // Consume the data
310 //
311 tmp = readList;
312 readList = readList->next;
313 tmp->offset += numToCopy;
314 if ( tmp->offset == tmp->bufSize )
315 {
316 free( tmp->buffer );
317 free( tmp );
318 partial[fd] = readList;
319 }
320 numRead += numToCopy;
321 }
322
323 //
324 // Only call read if at the end of a previously incomplete packet.
325 //
326 if ( ( numRead < numReq ) )
327 {
328 numToCopy = numReq - numRead;
329 numRead += (int) read( fd, buffer + numRead, (size_t) numToCopy );
330 }
331
332 return numRead;
333 }
334
335 //--------------------------------------------------------------------------
336 // This part for Tcl-DP only
337 //--------------------------------------------------------------------------
338
339 #ifdef PLD_dp
340
341 #include <dp.h>
342
343 #include <arpa/inet.h>
344 #include <netdb.h>
345 #include <netinet/in.h>
346 #include <sys/socket.h>
347
348 //--------------------------------------------------------------------------
349 // plHost_ID
350 //
351 // Tcl command -- return the IP address for the current host.
352 //
353 // Derived from source code in "UNIX Network Programming" by W. Richard
354 // Stevens, Prentice Hall, 1990.
355 //--------------------------------------------------------------------------
356
357 static char *
358 get_inet( char ** listptr, int length )
359 {
360 struct in_addr *ptr;
361
362 while ( ( ptr = (struct in_addr *) *listptr++ ) == NULL )
363 continue;
364
365 return inet_ntoa( *ptr );
366 }
367
368 int
369 plHost_ID( ClientData clientData, Tcl_Interp *interp, int argc, char **argv )
370 {
371 register struct hostent *hostptr;
372 char hostname[100];
373
374 if ( gethostname( hostname, 100 ) )
375 {
376 Tcl_AppendResult( interp, "Error -- cannot get host name",
377 (char *) NULL );
378 return TCL_ERROR;
379 }
380
381 if ( ( hostptr = gethostbyname( hostname ) ) == NULL )
382 {
383 Tcl_AppendResult( interp, "Error -- cannot get host info for node ",
384 hostname, (char *) NULL );
385 return TCL_ERROR;
386 }
387
388 Tcl_SetResult( interp,
389 get_inet( hostptr->h_addr_list, hostptr->h_length ),
390 TCL_VOLATILE );
391
392 return TCL_OK;
393 }
394
395 #endif // PLD_dp
396
397 //
398 //--------------------------------------------------------------------------
399 //
400 // pl_PacketReceive --
401 //
402 // This procedure is a modified version of Tdp_PacketReceive,
403 // from the Tcl-DP distribution. It reads the socket,
404 // returning a complete packet. If the entire packet cannot
405 // be read, the partial packet is buffered until the rest is
406 // available. Some capabilities have been removed from the
407 // original, such as the check for a non-server TCP socket,
408 // since there's no access to the optFlags array from here,
409 // and the peek capability, since I don't need it.
410 //
411 // Results:
412 // Packet contents stored in pdfs->buffer and pdfs->bp set
413 // to the number of bytes read (zero if incomplete).
414 //
415 // Side effects:
416 // The file descriptor passed in is read.
417 //
418 //--------------------------------------------------------------------------
419 //
420 int
421 pl_PacketReceive( Tcl_Interp *interp, PLiodev *iodev, PDFstrm *pdfs )
422 {
423 int j, numRead;
424 unsigned int packetLen, header[2];
425 int headerSize;
426 unsigned char hbuf[8];
427 const char *errMsg;
428
429 pdfs->bp = 0;
430
431 //
432 // Read in the header (8 bytes)
433 //
434 headerSize = 8;
435 numRead = pl_Read( iodev->fd, (char *) hbuf, headerSize );
436
437 if ( numRead <= 0 )
438 {
439 #ifdef DEBUG
440 fprintf( stderr, "Incorrect header read, numRead = %d\n", numRead );
441 #endif
442 goto readError;
443 }
444
445 //
446 // Check for incomplete read. If so, put it back and return.
447 //
448 if ( numRead < headerSize )
449 {
450 #ifdef DEBUG
451 fprintf( stderr, "Incomplete header read, numRead = %d\n", numRead );
452 #endif
453 pl_Unread( iodev->fd, (char *) hbuf, numRead, 1 );
454 Tcl_ResetResult( interp );
455 return TCL_OK;
456 }
457
458 //
459 // Convert header character stream into ints. This works when the
460 // connecting machine has a different size int and takes care of the
461 // endian problem to boot. It is also mostly backward compatible since
462 // network byte ordering (big endian) is used.
463 //
464
465 j = 0;
466
467 header[0] = 0;
468 header[0] |= (unsigned int) ( hbuf[j++] << 24 );
469 header[0] |= (unsigned int) ( hbuf[j++] << 16 );
470 header[0] |= (unsigned int) ( hbuf[j++] << 8 );
471 header[0] |= hbuf[j++];
472
473 header[1] = 0;
474 header[1] |= (unsigned int) ( hbuf[j++] << 24 );
475 header[1] |= (unsigned int) ( hbuf[j++] << 16 );
476 header[1] |= (unsigned int) ( hbuf[j++] << 8 );
477 header[1] |= hbuf[j++];
478
479 //
480 // Format of each packet:
481 //
482 // First 4 bytes are PACKET_MAGIC.
483 // Next 4 bytes are packetLen.
484 // Next packetLen-headerSize is zero terminated string
485 //
486 if ( header[0] != PACKET_MAGIC )
487 {
488 fprintf( stderr, "Badly formatted packet, numRead = %d\n", numRead );
489 Tcl_AppendResult( interp, "Error reading from ", iodev->typeName,
490 ": badly formatted packet", (char *) NULL );
491 return TCL_ERROR;
492 }
493 packetLen = header[1] - (unsigned int) headerSize;
494
495 //
496 // Expand the size of the buffer, as needed.
497 //
498
499 if ( header[1] > (unsigned) pdfs->bufmax )
500 {
501 free( (void *) pdfs->buffer );
502 pdfs->bufmax = header[1] + 32;
503 pdfs->buffer = (unsigned char *) malloc( pdfs->bufmax );
504 }
505
506 //
507 // Read in the packet, and if it's not all there, put it back.
508 //
509 // We have to be careful here, because we could block if just the
510 // header came in (making the file readable at the beginning of this
511 // function) but the rest of the packet is still out on the network.
512 //
513
514 if ( iodev->type == 0 )
515 {
516 numRead = pl_Read( iodev->fd, (char *) pdfs->buffer, (int) packetLen );
517 }
518 else
519 {
520 #ifdef PLD_dp
521 if ( Tdp_FDIsReady( iodev->fd ) & TCL_FILE_READABLE )
522 {
523 numRead = pl_Read( iodev->fd, (char *) pdfs->buffer, packetLen );
524 }
525 else
526 {
527 #ifdef DEBUG
528 fprintf( stderr, "Packet not ready, putting back header\n" );
529 #endif
530 pl_Unread( iodev->fd, (char *) hbuf, headerSize, 1 );
531 Tcl_ResetResult( interp );
532 return TCL_OK;
533 }
534 #endif
535 }
536
537 if ( numRead <= 0 )
538 {
539 goto readError;
540 }
541
542 if ( (unsigned) numRead != packetLen )
543 {
544 #ifdef DEBUG
545 fprintf( stderr, "Incomplete packet read, numRead = %d\n", numRead );
546 #endif
547 pl_Unread( iodev->fd, (char *) pdfs->buffer, numRead, 1 );
548 pl_Unread( iodev->fd, (char *) hbuf, headerSize, 1 );
549 return TCL_OK;
550 }
551
552 pdfs->bp = (size_t) numRead;
553 #ifdef DEBUG
554 fprintf( stderr, "received %d byte packet starting with:", numRead );
555 for ( j = 0; j < 4; j++ )
556 {
557 fprintf( stderr, " %x", 0x000000FF & (unsigned long) pdfs->buffer[j] );
558 }
559 fprintf( stderr, "\n" );
560 #endif
561
562 return TCL_OK;
563
564 readError:
565 //
566 //
567 // If we're in non-blocking mode, and this would block, return.
568 // If the connection is closed (numRead == 0), don't return an
569 // error message. Otherwise, return one.
570 //
571 // In either case, we close the file, delete the file handler, and
572 // return a null string.
573 //
574
575 if ( errno == PLPLOT_EWOULDBLOCK || errno == EAGAIN )
576 {
577 Tcl_ResetResult( interp );
578 return TCL_OK;
579 }
580
581 // Record the error before closing the file
582 if ( numRead != 0 )
583 {
584 errMsg = Tcl_PosixError( interp );
585 }
586 else
587 {
588 errMsg = NULL; // Suppresses spurious compiler warning
589 }
590
591 //
592 // Remove the file handler and close the file.
593 //
594 if ( iodev->type == 0 )
595 {
596 // Exclude UNIX-only feature
597 #if !defined ( MAC_TCL ) && !defined ( _WIN32 ) && !defined ( __CYGWIN__ )
598 Tk_DeleteFileHandler( iodev->fd );
599 #endif
600 close( iodev->fd );
601 }
602 pl_FreeReadBuffer( iodev->fd );
603
604 Tcl_ResetResult( interp );
605 if ( numRead == 0 )
606 {
607 return TCL_OK;
608 }
609 else
610 {
611 Tcl_AppendResult( interp, "pl_PacketReceive -- error reading from ",
612 iodev->typeName, ": ", errMsg, (char *) NULL );
613 return TCL_ERROR;
614 }
615 }
616
617 //
618 //--------------------------------------------------------------------------
619 //
620 // pl_PacketSend --
621 //
622 // This procedure is a modified version of Tdp_PacketSend,
623 // from the Tcl-DP distribution. It writes a complete packet
624 // to a socket or file-oriented device.
625 //
626 // Results:
627 // A standard tcl result.
628 //
629 // Side effects:
630 // The specified buffer is written to the file descriptor passed
631 // in.
632 //
633 //--------------------------------------------------------------------------
634 //
635
636 int
637 pl_PacketSend( Tcl_Interp * interp, PLiodev *iodev, PDFstrm *pdfs )
638 {
639 int j, numSent;
640 unsigned char hbuf[8];
641 unsigned int packetLen, header[2];
642 size_t len;
643 char *buffer, tmp[256];
644
645 //
646 // Format up the packet:
647 // First 4 bytes are PACKET_MAGIC.
648 // Next 4 bytes are packetLen.
649 // Next packetLen-8 bytes are buffer contents.
650 //
651
652 packetLen = (unsigned int) pdfs->bp + 8;
653
654 header[0] = PACKET_MAGIC;
655 header[1] = packetLen;
656
657 //
658 // Convert header ints to character stream.
659 // Network byte ordering (big endian) is used.
660 //
661
662 j = 0;
663
664 hbuf[j++] = (unsigned char) ( ( header[0] & (unsigned long) 0xFF000000 ) >> 24 );
665 hbuf[j++] = (unsigned char) ( ( header[0] & (unsigned long) 0x00FF0000 ) >> 16 );
666 hbuf[j++] = (unsigned char) ( ( header[0] & (unsigned long) 0x0000FF00 ) >> 8 );
667 hbuf[j++] = (unsigned char) ( header[0] & (unsigned long) 0x000000FF );
668
669 hbuf[j++] = (unsigned char) ( ( header[1] & (unsigned long) 0xFF000000 ) >> 24 );
670 hbuf[j++] = (unsigned char) ( ( header[1] & (unsigned long) 0x00FF0000 ) >> 16 );
671 hbuf[j++] = (unsigned char) ( ( header[1] & (unsigned long) 0x0000FF00 ) >> 8 );
672 hbuf[j++] = (unsigned char) ( header[1] & (unsigned long) 0x000000FF );
673
674 //
675 // Send it off, with error checking.
676 // Simulate writev using memcpy to put together
677 // the msg so it can go out in a single write() call.
678 //
679
680 len = pdfs->bp + 8;
681 buffer = (char *) malloc( len );
682
683 memcpy( buffer, (char *) hbuf, 8 );
684 memcpy( buffer + 8, (char *) pdfs->buffer, pdfs->bp );
685
686 #ifdef DEBUG
687 fprintf( stderr, "sending %z byte packet starting with:", len );
688 for ( j = 0; j < 12; j++ )
689 {
690 fprintf( stderr, " %x", 0x000000FF & (unsigned long) buffer[j] );
691 }
692 fprintf( stderr, "\n" );
693 #endif
694 numSent = (int) write( iodev->fd, buffer, len );
695
696 free( buffer );
697
698 if ( (unsigned) numSent != packetLen )
699 {
700 if ( ( errno == 0 ) || ( errno == PLPLOT_EWOULDBLOCK || errno == EAGAIN ) )
701 {
702 //
703 // Non-blocking I/O: return number of bytes actually sent.
704 //
705 Tcl_ResetResult( interp );
706 sprintf( tmp, "%d", numSent - 8 );
707 Tcl_SetResult( interp, tmp, TCL_VOLATILE );
708 return TCL_OK;
709 }
710 else if ( errno == EPIPE )
711 {
712 //
713 // Got a broken pipe signal, which means the far end closed
714 // the connection. Close the file and return 0 bytes sent.
715 //
716 if ( iodev->type == 0 )
717 {
718 close( iodev->fd );
719 }
720 sprintf( tmp, "0" );
721 Tcl_SetResult( interp, tmp, TCL_VOLATILE );
722 return TCL_OK;
723 }
724 else
725 {
726 Tcl_AppendResult( interp, "pl_PacketSend -- error writing to ",
727 iodev->typeName, ": ",
728 Tcl_PosixError( interp ), (char *) NULL );
729 }
730
731 return TCL_ERROR;
732 }
733
734 //
735 // Return the number of bytes sent (minus the header).
736 //
737 sprintf( tmp, "%d", numSent - 8 );
738 Tcl_SetResult( interp, tmp, TCL_VOLATILE );
739 return TCL_OK;
740 }
741
742 #else
743 int
744 pldummy_tcpip()
745 {
746 return 0;
747 }
748
749 #endif // defined(PLD_tk) || defined (ENABLE_tkX)
plConfig.h
PLiodev
Definition: pdf.h:61
header
const char header[]
Definition: deltaT-gen.c:41
argv
static char ** argv
Definition: qt.cpp:49
tcpip.h
PLiodev::typeName
const char * typeName
Definition: pdf.h:68
PDFstrm
Definition: pdf.h:49
PLiodev::fd
int fd
Definition: pdf.h:63
argc
static int argc
Definition: qt.cpp:48
pldummy_tcpip
int pldummy_tcpip()
Definition: tcpip.c:744
MIN
#define MIN(a, b)
Definition: dsplint.c:29
PDFstrm::bufmax
size_t bufmax
Definition: pdf.h:56
buffer
static PLINT * buffer
Definition: plfill.c:74
plDevs.h
pl_PacketReceive
PLDLLIMPEXP_TCLTK int pl_PacketReceive(Tcl_Interp *interp, PLiodev *iodev, PDFstrm *pdfs)
plHost_ID
int plHost_ID(ClientData clientData, Tcl_Interp *interp, int argc, const char **argv)
PLiodev::type
int type
Definition: pdf.h:67
interp
static Tcl_Interp * interp
Definition: tkMain.c:120
PDFstrm::bp
size_t bp
Definition: pdf.h:56
plplot.h
pl_PacketSend
PLDLLIMPEXP_TCLTK int pl_PacketSend(Tcl_Interp *interp, PLiodev *iodev, PDFstrm *pdfs)
PDFstrm::buffer
unsigned char * buffer
Definition: pdf.h:52