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