PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
tek.c
Go to the documentation of this file.
1 // PLplot tektronix device & emulators driver.
2 //
3 #include "plDevs.h"
4 
5 #if defined ( PLD_xterm ) || /* xterm */ \
6  defined ( PLD_tek4010 ) || /* TEK 4010 */ \
7  defined ( PLD_tek4010f ) || /* ditto, file */ \
8  defined ( PLD_tek4107 ) || /* TEK 4107 */ \
9  defined ( PLD_tek4107f ) || /* ditto, file */ \
10  defined ( PLD_mskermit ) || /* MS-kermit emulator */ \
11  defined ( PLD_versaterm ) || /* Versaterm emulator */ \
12  defined ( PLD_vlt ) || /* VLT emulator */ \
13  defined ( PLD_conex ) // conex emulator 4010/4014/4105
14 
15 #define NEED_PLDEBUG
16 #include "plplotP.h"
17 #include "drivers.h"
18 #include "plevent.h"
19 
20 #include <ctype.h>
21 
22 // Device info
23 
24 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_tek =
25 #if defined ( PLD_conex )
26  "conex:Conex vt320/tek emulator:1:tek:24:conex\n"
27 #endif
28 #if defined ( PLD_mskermit )
29  "mskermit:MS-Kermit emulator:1:tek:21:mskermit\n"
30 #endif
31 #if defined ( PLD_tek4107t )
32  "tek4107t:Tektronix Terminal (4105/4107):1:tek:20:tek4107t\n"
33 #endif
34 #if defined ( PLD_tek4107f )
35  "tek4107f:Tektronix File (4105/4107):0:tek:28:tek4107f\n"
36 #endif
37 #if defined ( PLD_tekt )
38  "tekt:Tektronix Terminal (4010):1:tek:19:tekt\n"
39 #endif
40 #if defined ( PLD_tekf )
41  "tekf:Tektronix File (4010):0:tek:27:tekf\n"
42 #endif
43 #if defined ( PLD_versaterm )
44  "versaterm:Versaterm vt100/tek emulator:1:tek:22:versaterm\n"
45 #endif
46 #if defined ( PLD_vlt )
47  "vlt:VLT vt100/tek emulator:1:tek:23:vlt\n"
48 #endif
49 #if defined ( PLD_xterm )
50  "xterm:Xterm Window:1:tek:18:xterm\n"
51 #endif
52 ;
53 
54 // Prototype the driver entry points that will be used to initialize the
55 // dispatch table entries.
56 
57 void plD_init_xterm( PLStream * );
58 void plD_init_tekt( PLStream * );
59 void plD_init_tekf( PLStream * );
60 void plD_init_tek4107t( PLStream * );
61 void plD_init_tek4107f( PLStream * );
62 void plD_init_mskermit( PLStream * );
63 void plD_init_versaterm( PLStream * );
64 void plD_init_vlt( PLStream * );
65 void plD_init_conex( PLStream * );
66 
67 // External generic entry points
68 
69 void plD_line_tek( PLStream *, short, short, short, short );
70 void plD_polyline_tek( PLStream *, short *, short *, PLINT );
71 void plD_eop_tek( PLStream * );
72 void plD_bop_tek( PLStream * );
73 void plD_tidy_tek( PLStream * );
74 void plD_state_tek( PLStream *, PLINT );
75 void plD_esc_tek( PLStream *, PLINT, void * );
76 
77 // Static function prototypes
78 
79 static void WaitForPage( PLStream *pls );
80 static void tek_init( PLStream *pls );
81 static void tek_text( PLStream *pls );
82 static void tek_graph( PLStream *pls );
83 static void fill_polygon( PLStream *pls );
84 static void GetCursor( PLStream *pls, PLGraphicsIn *ptr );
85 static void encode_int( char *c, int i );
86 static void encode_vector( char *c, int x, int y );
87 static void decode_gin( char *c, PLGraphicsIn *gin );
88 static void tek_vector( PLStream *pls, int x, int y );
89 static void scolor( PLStream *pls, int icol, int r, int g, int b );
90 static void setcmap( PLStream *pls );
91 
92 static void LookupEvent( PLStream *pls );
93 static void InputEH( PLStream *pls );
94 static void LocateEH( PLStream *pls );
95 
96 // Stuff for handling tty cbreak mode
97 
98 #ifdef HAVE_TERMIOS_H
99 #include <termios.h>
100 #include <unistd.h>
101 static struct termios termios_cbreak, termios_reset;
102 static enum { RESET, CBREAK } ttystate = RESET;
103 static void tty_setup( void );
104 static int tty_cbreak( void );
105 static int tty_reset( void );
106 static void tty_atexit( void );
107 #else
108 static void tty_setup( void )
109 {
110 }
111 static int tty_cbreak( void )
112 {
113  return 0;
114 }
115 static int tty_reset( void )
116 {
117  return 0;
118 }
119 static void tty_atexit( void )
120 {
121 }
122 #endif
123 
124 // Pixel settings
125 
126 #define TEKX 1023
127 #define TEKY 779
128 
129 // Graphics control characters.
130 
131 #define RING_BELL "\007" // ^G = 7
132 #define CLEAR_VIEW "\033\f" // clear the view = ESC FF
133 
134 #define ALPHA_MODE "\037" // Enter Alpha mode: US
135 #define VECTOR_MODE "\035" // Enter Vector mode: GS
136 #define GIN_MODE "\033\032" // Enter GIN mode: ESC SUB
137 #define BYPASS_MODE "\033\030" // Enter Bypass mode: ESC CAN
138 #define XTERM_VTMODE "\033\003" // End xterm-Tek mode: ESC ETX
139 #define CANCEL "\033KC" // Cancel
140 
141 // Static vars
142 
143 enum { tek4010, tek4105, tek4107, xterm, mskermit, vlt, versaterm };
144 
145 // One of these holds the tek driver state information
146 
147 typedef struct
148 {
149  PLINT xold, yold; // Coordinates of last point plotted
150  int exit_eventloop; // Break out of event loop
151  int locate_mode; // Set while in locate (pick) mode
152  int curcolor; // Current color index
153  PLGraphicsIn gin; // Graphics input structure
154 } TekDev;
155 
156 // color for MS-DOS Kermit v2.31 (and up) tektronix emulator
157 // 0 = normal, 1 = bright
158 // foreground color (30-37) = 30 + colors
159 // where colors are 1=red, 2=green, 4=blue
160 //
161 #ifdef PLD_mskermit
162 static char *kermit_color[15] = {
163  "0;30", "0;37",
164  "0;32", "0;36","0;31", "0;35",
165  "1;34", "1;33","1;31", "1;37",
166  "1;35", "1;32","1;36", "0;34",
167  "0;33"
168 };
169 #endif
170 
171 static void tek_dispatch_init_helper( PLDispatchTable *pdt,
172  char *menustr, char *devnam,
173  int type, int seq, plD_init_fp init )
174 {
175 #ifndef ENABLE_DYNDRIVERS
176  pdt->pl_MenuStr = menustr;
177  pdt->pl_DevName = devnam;
178 #endif
179  pdt->pl_type = type;
180  pdt->pl_seq = seq;
181  pdt->pl_init = init;
182  pdt->pl_line = (plD_line_fp) plD_line_tek;
183  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_tek;
184  pdt->pl_eop = (plD_eop_fp) plD_eop_tek;
185  pdt->pl_bop = (plD_bop_fp) plD_bop_tek;
186  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_tek;
187  pdt->pl_state = (plD_state_fp) plD_state_tek;
188  pdt->pl_esc = (plD_esc_fp) plD_esc_tek;
189 }
190 
192 {
193  tek_dispatch_init_helper( pdt,
194  "Xterm Window", "xterm",
196  (plD_init_fp) plD_init_xterm );
197 }
198 
200 {
201  tek_dispatch_init_helper( pdt,
202  "Tektronix Terminal (4010)", "tekt",
204  (plD_init_fp) plD_init_tekt );
205 }
206 
208 {
209  tek_dispatch_init_helper( pdt,
210  "Tektronix Terminal (4105/4107)", "tek4107t",
212  (plD_init_fp) plD_init_tek4107t );
213 }
214 
216 {
217  tek_dispatch_init_helper( pdt,
218  "MS-Kermit emulator", "mskermit",
220  (plD_init_fp) plD_init_mskermit );
221 }
222 
224 {
225  tek_dispatch_init_helper( pdt,
226  "Versaterm vt100/tek emulator", "versaterm",
228  (plD_init_fp) plD_init_versaterm );
229 }
230 
232 {
233  tek_dispatch_init_helper( pdt,
234  "VLT vt100/tek emulator", "vlt",
236  (plD_init_fp) plD_init_vlt );
237 }
238 
240 {
241  tek_dispatch_init_helper( pdt,
242  "Conex vt320/tek emulator", "conex",
244  (plD_init_fp) plD_init_conex );
245 }
246 
248 {
249  tek_dispatch_init_helper( pdt,
250  "Tektronix File (4010)", "tekf",
252  (plD_init_fp) plD_init_tekf );
253 }
254 
256 {
257  tek_dispatch_init_helper( pdt,
258  "Tektronix File (4105/4107)", "tek4107f",
260  (plD_init_fp) plD_init_tek4107f );
261 }
262 
263 //--------------------------------------------------------------------------
264 // plD_init_xterm() xterm
265 // plD_init_tekt() Tek 4010 terminal
266 // plD_init_tekf() Tek 4010 file
267 // plD_init_tek4107t() Tek 4105/4107 terminal
268 // plD_init_tek4107f() Tek 4105/4107 file
269 // plD_init_mskermit() MS-Kermit emulator (DOS)
270 // plD_init_vlt() VLT emulator (Amiga)
271 // plD_init_versaterm() VersaTerm emulator (Mac)
272 // plD_init_conex() Conex vt320/Tek 4105 emulator (DOS)
273 //
274 // These just set attributes for the particular tektronix device, then call
275 // tek_init(). The following attributes can be set:
276 //
277 // pls->termin if a terminal device
278 // pls->color if color (1), if only fixed colors (2)
279 // pls->dev_fill0 if can handle solid area fill
280 // pls->dev_fill1 if can handle pattern area fill
281 //--------------------------------------------------------------------------
282 
283 void
284 plD_init_xterm( PLStream *pls )
285 {
286  pls->dev_minor = xterm;
287  pls->termin = 1;
288  tek_init( pls );
289 }
290 
291 void
292 plD_init_tekt( PLStream *pls )
293 {
294  pls->termin = 1;
295  plD_init_tekf( pls );
296 }
297 
298 void
299 plD_init_tekf( PLStream *pls )
300 {
301  pls->dev_minor = tek4010;
302  tek_init( pls );
303 }
304 
305 void
306 plD_init_tek4107t( PLStream *pls )
307 {
308  pls->termin = 1;
309  plD_init_tek4107f( pls );
310 }
311 
312 void
313 plD_init_tek4107f( PLStream *pls )
314 {
315  pls->dev_minor = tek4107;
316  pls->color = 1;
317  pls->dev_fill0 = 1;
318  tek_init( pls );
319 }
320 
321 void
322 plD_init_mskermit( PLStream *pls )
323 {
324  pls->dev_minor = mskermit;
325  pls->termin = 1;
326  pls->color = 1;
327  pls->dev_fill0 = 1;
328  tek_init( pls );
329 }
330 
331 void
332 plD_init_vlt( PLStream *pls )
333 {
334  pls->dev_minor = vlt;
335  pls->termin = 1;
336  pls->color = 1;
337  pls->dev_fill0 = 1;
338  tek_init( pls );
339 }
340 
341 void
342 plD_init_versaterm( PLStream *pls )
343 {
344  pls->dev_minor = versaterm;
345  pls->termin = 1;
346  pls->color = 1;
347  pls->dev_fill0 = 1;
348  tek_init( pls );
349 }
350 
351 void
352 plD_init_conex( PLStream *pls )
353 {
354  pls->dev_minor = xterm; // responds to xterm escape codes
355  pls->termin = 1;
356  pls->color = 2; // only fixed colours
357  tek_init( pls );
358 }
359 
360 //--------------------------------------------------------------------------
361 // tek_init()
362 //
363 // Generic tektronix device initialization.
364 //--------------------------------------------------------------------------
365 
366 static void
367 tek_init( PLStream *pls )
368 {
369  TekDev *dev;
370  int xmin = 0;
371  int xmax = TEKX;
372  int ymin = 0;
373  int ymax = TEKY;
374 
375  PLFLT pxlx = 4.771;
376  PLFLT pxly = 4.653;
377 
378  pls->graphx = TEXT_MODE;
379 
380 // Allocate and initialize device-specific data
381 
382  pls->dev = calloc( 1, (size_t) sizeof ( TekDev ) );
383  if ( pls->dev == NULL )
384  plexit( "tek_init: Out of memory." );
385 
386  dev = (TekDev *) pls->dev;
387 
388  dev->curcolor = 1;
389  dev->xold = PL_UNDEFINED;
390  dev->yold = PL_UNDEFINED;
391 
392  plP_setpxl( pxlx, pxly );
393  plP_setphy( xmin, xmax, ymin, ymax );
394 
395 // Terminal/file initialization
396 
397  if ( pls->termin )
398  {
399  pls->OutFile = stdout;
400  tty_setup();
401  }
402  else
403  {
404  plFamInit( pls );
405  plOpenFile( pls );
406  }
407 
408  switch ( pls->dev_minor )
409  {
410 #ifdef PLD_tek4107
411  case tek4107:
412  pls->graphx = GRAPHICS_MODE;
413  fprintf( pls->OutFile, "\033%%!0" ); // set tek mode
414  fprintf( pls->OutFile, "\033KN1" ); // clear the view
415  fprintf( pls->OutFile, "\033LZ" ); // clear dialog buffer
416  fprintf( pls->OutFile, "\033ML1" ); // set default color
417  break;
418 #endif // PLD_tek4107
419 
420 // A sneaky hack: VLT sometimes has leftover panel information, causing
421 // garbage at the beginning of a sequence of color fills. Since
422 // there is no clear panel command, instead I set the fill color to the
423 // same as background and issue an end panel command.
424 //
425 #ifdef PLD_vlt
426  case vlt: {
427  char fillcol[4];
428  tek_graph( pls );
429  encode_int( fillcol, 0 );
430  fprintf( pls->OutFile, "\033MP%s\033LE", fillcol );
431  break;
432  }
433 #endif // PLD_vlt
434 
435  default:
436  tek_graph( pls );
437  }
438 
439 // Initialize palette
440 
441  if ( pls->color & 0x01 )
442  {
443  printf( "\033TM111" ); // Switch to RGB colors
444  setcmap( pls );
445  }
446 
447 // Finish initialization
448 
449  fprintf( pls->OutFile, VECTOR_MODE ); // Enter vector mode
450  if ( pls->termin )
451  fprintf( pls->OutFile, CLEAR_VIEW ); // erase and home
452 
453  fflush( pls->OutFile );
454 }
455 
456 //--------------------------------------------------------------------------
457 // plD_line_tek()
458 //
459 // Draw a line from (x1,y1) to (x2,y2).
460 //--------------------------------------------------------------------------
461 
462 void
463 plD_line_tek( PLStream *pls, short x1, short y1, short x2, short y2 )
464 {
465  TekDev *dev = (TekDev *) pls->dev;
466 
467  tek_graph( pls );
468 
469 // If not continuation of previous line, begin a new one
470 
471  if ( x1 != dev->xold || y1 != dev->yold )
472  {
473  pls->bytecnt += fprintf( pls->OutFile, VECTOR_MODE );
474  tek_vector( pls, x1, y1 );
475  }
476 
477 // Now send following point to complete line draw
478 
479  tek_vector( pls, x2, y2 );
480 
481  dev->xold = x2;
482  dev->yold = y2;
483 }
484 
485 //--------------------------------------------------------------------------
486 // plD_polyline_tek()
487 //
488 // Draw a polyline in the current color.
489 //--------------------------------------------------------------------------
490 
491 void
492 plD_polyline_tek( PLStream *pls, short *xa, short *ya, PLINT npts )
493 {
494  PLINT i;
495  TekDev *dev = (TekDev *) pls->dev;
496  short x = xa[0], y = ya[0];
497 
498  tek_graph( pls );
499 
500 // If not continuation of previous line, begin a new one
501 
502  if ( x != dev->xold || y != dev->yold )
503  {
504  pls->bytecnt += fprintf( pls->OutFile, VECTOR_MODE );
505  tek_vector( pls, x, y );
506  }
507 
508 // Now send following points to complete polyline draw
509 
510  for ( i = 1; i < npts; i++ )
511  tek_vector( pls, xa[i], ya[i] );
512 
513  dev->xold = xa[npts - 1];
514  dev->yold = ya[npts - 1];
515 }
516 
517 //--------------------------------------------------------------------------
518 // plD_eop_tek()
519 //
520 // End of page. User must hit a <CR> to continue (terminal output).
521 //--------------------------------------------------------------------------
522 
523 void
524 plD_eop_tek( PLStream *pls )
525 {
526  tek_graph( pls );
527 
528  if ( pls->termin )
529  {
530  if ( !pls->nopause )
531  WaitForPage( pls );
532  }
533  fprintf( pls->OutFile, CLEAR_VIEW ); // erase and home
534 }
535 
536 //--------------------------------------------------------------------------
537 // plD_bop_tek()
538 //
539 // Set up for the next page. Advance to next family file if necessary
540 // (file output). Devices that share graphics/alpha screens need a page
541 // clear.
542 //--------------------------------------------------------------------------
543 
544 void
545 plD_bop_tek( PLStream *pls )
546 {
547  TekDev *dev = (TekDev *) pls->dev;
548 
549  dev->xold = PL_UNDEFINED;
550  dev->yold = PL_UNDEFINED;
551 
552  if ( pls->termin )
553  {
554  switch ( pls->dev_minor )
555  {
556  case mskermit:
557  fprintf( pls->OutFile, CLEAR_VIEW ); // erase and home
558  break;
559  }
560  }
561  else
562  {
563  plGetFam( pls );
564  }
565  pls->page++;
566 
567 // Initialize palette
568 
569  if ( pls->color & 0x01 )
570  setcmap( pls );
571 }
572 
573 //--------------------------------------------------------------------------
574 // plD_tidy_tek()
575 //
576 // Close graphics file or otherwise clean up.
577 //--------------------------------------------------------------------------
578 
579 void
580 plD_tidy_tek( PLStream *pls )
581 {
582  if ( !pls->termin )
583  {
584  plCloseFile( pls );
585  }
586  else
587  {
588  tek_text( pls );
589  fflush( pls->OutFile );
590  }
591 }
592 
593 //--------------------------------------------------------------------------
594 // tek_color()
595 //
596 // Change to specified color index.
597 //--------------------------------------------------------------------------
598 
599 static void
600 tek_color( PLStream *pls, int icol )
601 {
602  switch ( pls->dev_minor )
603  {
604 #ifdef PLD_mskermit // Is this really necessary?
605  case mskermit:
606  printf( "\033[%sm", kermit_color[icol % 14] );
607  break;
608 #endif
609  default:
610  pls->bytecnt += fprintf( pls->OutFile, "\033ML%c", icol + '0' );
611  }
612 }
613 
614 //--------------------------------------------------------------------------
615 // plD_state_tek()
616 //
617 // Handle change in PLStream state (color, pen width, fill attribute,
618 // etc).
619 //--------------------------------------------------------------------------
620 
621 void
622 plD_state_tek( PLStream *pls, PLINT op )
623 {
624  TekDev *dev = (TekDev *) pls->dev;
625 
626  switch ( op )
627  {
628  case PLSTATE_WIDTH:
629  break;
630 
631  case PLSTATE_COLOR0:
632  if ( pls->color )
633  {
634  int icol0 = pls->icol0;
635  tek_graph( pls );
636  if ( icol0 != PL_RGB_COLOR )
637  {
638  dev->curcolor = icol0;
639  tek_color( pls, icol0 );
640  }
641  }
642  break;
643 
644  case PLSTATE_COLOR1:
645  if ( pls->color )
646  {
647  int icol1, ncol1;
648  tek_graph( pls );
649  if ( ( ncol1 = MIN( 16 - pls->ncol0, pls->ncol1 ) ) < 1 )
650  break;
651 
652  icol1 = pls->ncol0 + ( pls->icol1 * ( ncol1 - 1 ) ) / ( pls->ncol1 - 1 );
653  dev->curcolor = icol1;
654  tek_color( pls, icol1 );
655  }
656  break;
657 
658  case PLSTATE_CMAP0:
659  case PLSTATE_CMAP1:
660  if ( pls->color & 0x01 )
661  setcmap( pls );
662 
663  break;
664  }
665 }
666 
667 //--------------------------------------------------------------------------
668 // plD_esc_tek()
669 //
670 // Escape function.
671 //--------------------------------------------------------------------------
672 
673 void
674 plD_esc_tek( PLStream *pls, PLINT op, void *ptr )
675 {
676  switch ( op )
677  {
678  case PLESC_TEXT:
679  tek_text( pls );
680  break;
681 
682  case PLESC_GRAPH:
683  tek_graph( pls );
684  break;
685 
686  case PLESC_FILL:
687  fill_polygon( pls );
688  break;
689 
690  case PLESC_GETC:
691  GetCursor( pls, (PLGraphicsIn *) ptr );
692  break;
693  }
694 }
695 
696 //--------------------------------------------------------------------------
697 // GetCursor()
698 //
699 // Waits for a left button mouse event and returns coordinates.
700 // xterm doesn't handle GIN. I think all the rest do.
701 //--------------------------------------------------------------------------
702 
703 static void
704 GetCursor( PLStream *pls, PLGraphicsIn *ptr )
705 {
706 #define MAX_GIN 10
707  char input_string[MAX_GIN];
708  int i = 0;
709 
710  plGinInit( ptr );
711 
712  if ( pls->termin && pls->dev_minor != xterm )
713  {
714  tek_graph( pls );
715 
716  // Enter GIN mode
717 
718  printf( GIN_MODE );
719  fflush( stdout );
720 
721  // Read & decode report
722 
723  while ( ++i < MAX_GIN && ( input_string[i - 1] = getchar() ) != '\n' )
724  ;
725 
726  input_string[i - 1] = '\0';
727  ptr->keysym = input_string[0];
728  decode_gin( &input_string[1], ptr );
729 
730  // Switch out of GIN mode
731 
732  printf( VECTOR_MODE );
733  }
734 }
735 
736 //--------------------------------------------------------------------------
737 // fill_polygon()
738 //
739 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
740 //--------------------------------------------------------------------------
741 
742 static void
743 fill_polygon( PLStream *pls )
744 {
745  TekDev *dev = (TekDev *) pls->dev;
746  int i;
747  char fillcol[4], firstpoint[5];
748 
749  if ( pls->dev_npts < 1 )
750  return;
751 
752  tek_graph( pls );
753 
754  encode_int( fillcol, -dev->curcolor );
755  encode_vector( firstpoint, pls->dev_x[0], pls->dev_y[0] );
756 
757 // Select the fill pattern
758 
759  pls->bytecnt += fprintf( pls->OutFile, "\033MP%s", fillcol );
760 
761 // Begin panel boundary
762 // Set pls->debug to see the boundary of each fill box -- cool!
763 
764  if ( pls->debug )
765  pls->bytecnt += fprintf( pls->OutFile, "\033LP%s1", firstpoint );
766  else
767  pls->bytecnt += fprintf( pls->OutFile, "\033LP%s0", firstpoint );
768 
769 // Specify boundary (in vector mode)
770 
771  pls->bytecnt += fprintf( pls->OutFile, VECTOR_MODE );
772  for ( i = 1; i < pls->dev_npts; i++ )
773  tek_vector( pls, pls->dev_x[i], pls->dev_y[i] );
774 
775 // End panel
776 
777  pls->bytecnt += fprintf( pls->OutFile, "\033LE" );
778 }
779 
780 //--------------------------------------------------------------------------
781 // tek_text()
782 //
783 // Switch to text screen (or alpha mode, for vanilla tek's). Restore
784 // terminal to its original state, to better handle user input if
785 // necessary.
786 //
787 // Note: xterm behaves strangely in the following circumstance: switch to
788 // the text screen, print a string, and switch to the graphics screen, all
789 // done in quick succession. The first character of the printed string
790 // usually comes out blank -- but only apparently so, because if you force
791 // a refresh of the screen in this area it will reappear. This is a
792 // reproducible bug on the HP 720 under X11R5. If you insert a sleep(1)
793 // after the switch to text screen or before the switch to graphics
794 // screen, the string is printed correctly. I've been unable to find a
795 // workaround for this problem (and I've tried, you can believe eet man).
796 //--------------------------------------------------------------------------
797 
798 static void
799 tek_text( PLStream *pls )
800 {
801  if ( pls->termin && ( pls->graphx == GRAPHICS_MODE ) )
802  {
803  tty_reset();
804  pls->graphx = TEXT_MODE;
805  switch ( pls->dev_minor )
806  {
807  case xterm:
808  printf( "\033\003" ); // vt100 mode (xterm) = ESC ETX
809  break;
810 
811  case mskermit:
812  case vlt:
813  printf( "\033[?38l" ); // vt100 screen
814  break;
815 
816  case versaterm:
817  printf( "\033%%!2" ); // vt100 screen
818  break;
819 
820  case tek4107:
821  printf( "\033LV1" ); // set dialog visible
822  printf( "\033%%!1" ); // set ansi mode
823  break;
824 
825  default:
826  printf( ALPHA_MODE ); // enter alpha mode
827  }
828  fflush( stdout );
829  }
830 }
831 
832 //--------------------------------------------------------------------------
833 // tek_graph()
834 //
835 // Switch to graphics screen. Also switch terminal to cbreak mode, to allow
836 // single keystrokes to govern actions at end of page.
837 //--------------------------------------------------------------------------
838 
839 static void
840 tek_graph( PLStream *pls )
841 {
842  if ( pls->termin && ( pls->graphx == TEXT_MODE ) )
843  {
844  tty_cbreak();
845  pls->graphx = GRAPHICS_MODE;
846  switch ( pls->dev_minor )
847  {
848  case xterm:
849  case mskermit:
850  case vlt:
851  printf( "\033[?38h" ); // switch to tek screen
852  break;
853 
854  case versaterm:
855  printf( "\033%%!0" ); // switch to tek4107 screen
856  break;
857 
858  case tek4107:
859  printf( "\033%%!0" ); // set tek mode
860  printf( CLEAR_VIEW ); // clear screen
861  printf( "\033LV0" ); // set dialog invisible
862  break;
863  }
864  }
865 }
866 
867 //--------------------------------------------------------------------------
868 // encode_int()
869 //
870 // Encodes a single int into standard tek integer format, storing into a
871 // NULL-terminated character string (must be length 4 or greater). This
872 // scheme does not work for negative integers less than 15.
873 //--------------------------------------------------------------------------
874 
875 static void
876 encode_int( char *c, int i )
877 {
878  int negative = 0;
879 
880  if ( i > 0 )
881  {
882  if ( i & 0x7C00 ) // are any of bits 10-14 set?
883  *c++ = ( ( i >> 10 ) & 0x1F ) | 0x40;
884  if ( i & 0x03F0 ) // are any of bits 4-9 set?
885  *c++ = ( ( i >> 4 ) & 0x3F ) | 0x40;
886  }
887  else
888  {
889  i = -i;
890  negative = 1;
891  }
892 
893  if ( i & 0x000F ) // are any of bits 0-3 set?
894  *c = ( i & 0x0F ) | 0x20;
895  else // if not, put in a space
896  *c = 0x20;
897 
898  if ( !negative ) // if positive, set sign bit
899  *c |= 0x10;
900 
901  c++; *c = '\0'; // NULL-terminate
902  return;
903 }
904 
905 //--------------------------------------------------------------------------
906 // decode_gin()
907 //
908 // Decodes a GIN tek vector string into an xy pair of relative device
909 // coordinates. It's best to not use absolute device coordinates since the
910 // coordinate bounds are different depending on the report encoding used.
911 //
912 // Standard: <HiX><LoX><HiY><LoY>
913 // Extended: <HiY><Extra><LoY><HiX><LoX>
914 //
915 // where <Extra> holds the two low order bits for each coordinate.
916 //--------------------------------------------------------------------------
917 
918 static void
919 decode_gin( char *c, PLGraphicsIn *gin )
920 {
921  int x, y, lc = strlen( c );
922 
923  if ( lc == 4 )
924  {
925  x = ( ( c[0] & 0x1f ) << 5 ) +
926  ( ( c[1] & 0x1f ) );
927 
928  y = ( ( c[2] & 0x1f ) << 5 ) +
929  ( ( c[3] & 0x1f ) );
930 
931  gin->pX = x;
932  gin->pY = y;
933  gin->dX = x / (double) TEKX;
934  gin->dY = y / (double) TEKY;
935  }
936  else if ( lc == 5 )
937  {
938  y = ( ( c[0] & 0x1f ) << 7 ) +
939  ( ( c[2] & 0x1f ) << 2 ) +
940  ( ( c[1] & 0x06 ) >> 2 );
941 
942  x = ( ( c[3] & 0x1f ) << 7 ) +
943  ( ( c[4] & 0x1f ) << 2 ) +
944  ( ( c[1] & 0x03 ) );
945 
946  gin->pX = x;
947  gin->pY = y;
948  gin->dX = x / (double) ( TEKX << 2 );
949  gin->dY = y / (double) ( TEKY << 2 );
950  }
951  else // Illegal encoding
952  {
953  gin->pX = 0;
954  gin->pY = 0;
955  gin->dY = 0;
956  gin->dX = 0;
957  }
958 }
959 
960 //--------------------------------------------------------------------------
961 // encode_vector()
962 //
963 // Encodes an xy vector (2 ints) into standard tek vector format, storing
964 // into a NULL-terminated character string of length 5. Note that the y
965 // coordinate always comes first.
966 //--------------------------------------------------------------------------
967 
968 static void
969 encode_vector( char *c, int x, int y )
970 {
971  c[0] = ( y >> 5 ) + 0x20; // hy
972  c[1] = ( y & 0x1f ) + 0x60; // ly
973  c[2] = ( x >> 5 ) + 0x20; // hx
974  c[3] = ( x & 0x1f ) + 0x40; // lx
975  c[4] = '\0'; // NULL
976 }
977 
978 //--------------------------------------------------------------------------
979 // tek_vector()
980 //
981 // Issues a vector draw command, assuming we are in vector plot mode. XY
982 // coordinates are encoded according to the standard xy encoding scheme.
983 //--------------------------------------------------------------------------
984 
985 static void
986 tek_vector( PLStream *pls, int x, int y )
987 {
988  char c[5];
989 
990  encode_vector( c, x, y );
991  pls->bytecnt += fprintf( pls->OutFile, "%s", c );
992 }
993 
994 //--------------------------------------------------------------------------
995 // scolor()
996 //
997 // Sets a color by tek-encoded RGB values. Need to convert PLplot RGB
998 // color range (0 to 255) to Tek RGB color range (0 to 100).
999 //--------------------------------------------------------------------------
1000 
1001 static void
1002 scolor( PLStream *pls, int icol, int r, int g, int b )
1003 {
1004  char tek_col[4], tek_r[4], tek_g[4], tek_b[4];
1005 
1006  encode_int( tek_col, icol );
1007  encode_int( tek_r, ( 100 * r ) / 255 );
1008  encode_int( tek_g, ( 100 * g ) / 255 );
1009  encode_int( tek_b, ( 100 * b ) / 255 );
1010 
1011  pls->bytecnt += fprintf( pls->OutFile, "\033TG14%s%s%s%s",
1012  tek_col, tek_r, tek_g, tek_b );
1013 }
1014 
1015 //--------------------------------------------------------------------------
1016 // setcmap()
1017 //
1018 // Sets up color palette.
1019 //--------------------------------------------------------------------------
1020 
1021 static void
1022 setcmap( PLStream *pls )
1023 {
1024  int i, ncol1 = MIN( 16 - pls->ncol0, pls->ncol1 );
1025  PLColor cmap1col;
1026 
1027  tek_graph( pls );
1028 
1029 // Initialize cmap 0 colors
1030 
1031  for ( i = 0; i < pls->ncol0; i++ )
1032  scolor( pls, i, pls->cmap0[i].r, pls->cmap0[i].g, pls->cmap0[i].b );
1033 
1034 // Initialize any remaining slots for cmap1
1035 
1036  for ( i = 0; i < ncol1; i++ )
1037  {
1038  plcol_interp( pls, &cmap1col, i, ncol1 );
1039  scolor( pls, i + pls->ncol0, cmap1col.r, cmap1col.g, cmap1col.b );
1040  }
1041 }
1042 
1043 //--------------------------------------------------------------------------
1044 // WaitForPage()
1045 //
1046 // This routine waits for the user to advance the plot, while handling
1047 // all other events.
1048 //--------------------------------------------------------------------------
1049 
1050 static void
1051 WaitForPage( PLStream *pls )
1052 {
1053  TekDev *dev = (TekDev *) pls->dev;
1054 
1055  printf( ALPHA_MODE ); // Switch to alpha mode (necessary)
1056  printf( RING_BELL ); // and ring bell
1057  printf( VECTOR_MODE ); // Switch out of alpha mode
1058  fflush( stdout );
1059 
1060  while ( !dev->exit_eventloop )
1061  {
1062  LookupEvent( pls );
1063  if ( dev->locate_mode )
1064  LocateEH( pls );
1065  else
1066  InputEH( pls );
1067  }
1068  dev->exit_eventloop = FALSE;
1069 }
1070 
1071 //--------------------------------------------------------------------------
1072 // LookupEvent()
1073 //
1074 // Fills in the PLGraphicsIn from an input event.
1075 //--------------------------------------------------------------------------
1076 
1077 static void
1078 LookupEvent( PLStream *pls )
1079 {
1080  TekDev *dev = (TekDev *) pls->dev;
1081  PLGraphicsIn *gin = &( dev->gin );
1082 
1083  if ( dev->locate_mode )
1084  {
1085  GetCursor( pls, gin );
1086  }
1087  else
1088  {
1089  plGinInit( gin );
1090  gin->keysym = getchar();
1091  }
1092 
1093  if ( isprint( gin->keysym ) )
1094  {
1095  gin->string[0] = gin->keysym;
1096  gin->string[1] = '\0';
1097  }
1098  else
1099  {
1100  gin->string[0] = '\0';
1101  }
1102 
1103  pldebug( "LookupEvent",
1104  "Keycode %x, string: %s\n", gin->keysym, gin->string );
1105 }
1106 
1107 //--------------------------------------------------------------------------
1108 // LocateEH()
1109 //
1110 // Handles locate mode events.
1111 //
1112 // In locate mode: move cursor to desired location and select by pressing a
1113 // key or by clicking on the mouse (if available). Typically the world
1114 // coordinates of the selected point are reported.
1115 //
1116 // There are two ways to enter Locate mode -- via the API, or via a driver
1117 // command. The API entry point is the call plGetCursor(), which initiates
1118 // locate mode and does not return until input has been obtained. The
1119 // driver entry point is by entering a 'L' while the driver is waiting for
1120 // events.
1121 //
1122 // Locate mode input is reported in one of three ways:
1123 // 1. Through a returned PLGraphicsIn structure, when user has specified a
1124 // locate handler via (*pls->LocateEH).
1125 // 2. Through a returned PLGraphicsIn structure, when locate mode is invoked
1126 // by a plGetCursor() call.
1127 // 3. Through writes to stdout, when locate mode is invoked by a driver
1128 // command and the user has not supplied a locate handler.
1129 //
1130 // Hitting <Escape> will at all times end locate mode. Other keys will
1131 // typically be interpreted as locator input. Selecting a point out of
1132 // bounds will end locate mode unless the user overrides with a supplied
1133 // Locate handler.
1134 //--------------------------------------------------------------------------
1135 
1136 static void
1137 LocateEH( PLStream *pls )
1138 {
1139  TekDev *dev = (TekDev *) pls->dev;
1140  PLGraphicsIn *gin = &( dev->gin );
1141 
1142 // End locate mode on <Escape>
1143 
1144  if ( gin->keysym == PLK_Escape )
1145  {
1146  dev->locate_mode = 0;
1147  return;
1148  }
1149 
1150 // Call user locate mode handler if provided
1151 
1152  if ( pls->LocateEH != NULL )
1153  ( *pls->LocateEH )( gin, pls->LocateEH_data, &dev->locate_mode );
1154 
1155 // Use default procedure
1156 
1157  else
1158  {
1159  // Try to locate cursor
1160 
1161  if ( plTranslateCursor( gin ) )
1162  {
1163  // Successful, so send report to stdout
1164 
1165  pltext();
1166  if ( isprint( gin->keysym ) )
1167  printf( "%f %f %c\n", gin->wX, gin->wY, gin->keysym );
1168  else
1169  printf( "%f %f\n", gin->wX, gin->wY );
1170 
1171  plgra();
1172  }
1173  else
1174  {
1175  // Selected point is out of bounds, so end locate mode
1176 
1177  dev->locate_mode = 0;
1178  }
1179  }
1180 }
1181 
1182 //--------------------------------------------------------------------------
1183 // InputEH()
1184 //
1185 // Event handler routine for xterm. Just reacts to keyboard input.
1186 //
1187 // In locate mode: move cursor to desired location and select by pressing a
1188 // key or by clicking on the mouse (if available). The world coordinates of
1189 // the selected point are output on the text screen. Terminate by picking a
1190 // point out of bounds, hitting page advance, or the escape key. If you
1191 // want to customize this, write an event handler to do it.
1192 //--------------------------------------------------------------------------
1193 
1194 static void
1195 InputEH( PLStream *pls )
1196 {
1197  TekDev *dev = (TekDev *) pls->dev;
1198  PLGraphicsIn *gin = &( dev->gin );
1199 
1200 // Call user event handler.
1201 // Since this is called first, the user can disable all PLplot internal
1202 // event handling by setting gin->keysym to 0 and gin->string to '\0'.
1203 //
1204  if ( pls->KeyEH != NULL )
1205  ( *pls->KeyEH )( gin, pls->KeyEH_data, &dev->exit_eventloop );
1206 
1207 // Remaining internal event handling
1208 
1209  switch ( gin->keysym )
1210  {
1211  case PLK_Linefeed:
1212  // Advance to next page (i.e. terminate event loop) on a <eol>
1213  dev->exit_eventloop = TRUE;
1214  break;
1215 
1216  case 'Q':
1217  // Terminate on a 'Q' (not 'q', since it's too easy to hit by mistake)
1218  pls->nopause = TRUE;
1219  plexit( "" );
1220  break;
1221 
1222  case 'L':
1223  // Begin locate mode
1224  dev->locate_mode = 1;
1225  break;
1226  }
1227 }
1228 
1229 //--------------------------------------------------------------------------
1230 // tty cbreak-mode handlers
1231 //
1232 // Taken from "Advanced Programming in the UNIX(R) Environment",
1233 // by W. Richard Stevens.
1234 //--------------------------------------------------------------------------
1235 
1236 #ifdef HAVE_TERMIOS_H
1237 
1238 static void
1239 tty_setup( void ) // setup for terminal operations
1240 {
1241  if ( tcgetattr( STDIN_FILENO, &termios_reset ) < 0 )
1242  {
1243  fprintf( stderr, "Unable to set up cbreak mode.\n" );
1244  return;
1245  }
1246 
1247  termios_cbreak = termios_reset; // structure copy
1248 
1249  termios_cbreak.c_lflag &= ~( ICANON ); // canonical mode off
1250  termios_cbreak.c_cc[VMIN] = 1; // 1 byte at a time
1251  termios_cbreak.c_cc[VTIME] = 0; // no timer
1252 
1253 #ifdef STDC_HEADERS
1254  if ( atexit( tty_atexit ) )
1255  fprintf( stderr, "Unable to set up atexit handler.\n" );
1256 #endif
1257  return;
1258 }
1259 
1260 static int
1261 tty_cbreak( void ) // put terminal into a cbreak mode
1262 {
1263  if ( ttystate != CBREAK )
1264  {
1265  if ( tcsetattr( STDIN_FILENO, TCSAFLUSH, &termios_cbreak ) < 0 )
1266  return -1;
1267 
1268  ttystate = CBREAK;
1269  }
1270  return 0;
1271 }
1272 
1273 static int
1274 tty_reset( void ) // restore terminal's mode
1275 {
1276  if ( ttystate != RESET )
1277  {
1278  if ( tcsetattr( STDIN_FILENO, TCSAFLUSH, &termios_reset ) < 0 )
1279  return -1;
1280 
1281  ttystate = RESET;
1282  }
1283  return 0;
1284 }
1285 
1286 static void
1287 tty_atexit( void ) // exit handler
1288 {
1289  tty_reset();
1290 }
1291 
1292 #endif // HAVE_TERMIOS_H
1293 
1294 #else
1296 {
1297  return 0;
1298 }
1299 
1300 #endif // defined(PLD_xterm) || ...