PLplot  5.10.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
ntk.c
Go to the documentation of this file.
1 // $Id: ntk.c 12932 2014-01-12 02:18:40Z airwin $
2 //
3 // Experimental tk driver using a plain "wish"
4 //
5 // Copyright (C) 2001 Joao Cardoso
6 // Copyright (C) 2004 Rafael Laboissiere
7 //
8 // This file is part of PLplot.
9 //
10 // PLplot is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU Library General Public License as published
12 // by the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
14 //
15 // PLplot is distributed in the hope that it will be useful,
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU Library General Public License for more details.
19 //
20 // You should have received a copy of the GNU Library General Public License
21 // along with PLplot; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23 //
24 //
25 
26 #include "plDevs.h"
27 
28 #ifdef PLD_ntk
29 
30 #include "plplotP.h"
31 #include "drivers.h"
32 #include "plevent.h"
33 
34 #include <tk.h>
35 
36 // Device info
37 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_ntk = "ntk:New tk driver:1:ntk:43:ntk\n";
38 
39 
41 
42 void plD_init_ntk( PLStream * );
43 void plD_line_ntk( PLStream *, short, short, short, short );
44 void plD_polyline_ntk( PLStream *, short *, short *, PLINT );
45 void plD_eop_ntk( PLStream * );
46 void plD_bop_ntk( PLStream * );
47 void plD_tidy_ntk( PLStream * );
48 void plD_state_ntk( PLStream *, PLINT );
49 void plD_esc_ntk( PLStream *, PLINT, void * );
50 
52 {
53 #ifndef ENABLE_DYNDRIVERS
54  pdt->pl_MenuStr = "New Tk device";
55  pdt->pl_DevName = "ntk";
56 #endif
58  pdt->pl_seq = 43;
59  pdt->pl_init = (plD_init_fp) plD_init_ntk;
60  pdt->pl_line = (plD_line_fp) plD_line_ntk;
61  pdt->pl_polyline = (plD_polyline_fp) plD_polyline_ntk;
62  pdt->pl_eop = (plD_eop_fp) plD_eop_ntk;
63  pdt->pl_bop = (plD_bop_fp) plD_bop_ntk;
64  pdt->pl_tidy = (plD_tidy_fp) plD_tidy_ntk;
65  pdt->pl_state = (plD_state_fp) plD_state_ntk;
66  pdt->pl_esc = (plD_esc_fp) plD_esc_ntk;
67 }
68 
69 // hardwired window size
70 #define XPIXELS 600
71 #define YPIXELS 400
72 
73 static PLFLT scale = 10.0; // Tk canvas units are in pixels, giving corse curves, fool plplot, and scale down when sending to tk
74 static PLFLT ppm; // device pixels per mm
75 
76 static Tcl_Interp *interp = NULL; // tcl interpreter
77 static Tk_Window mainw; // tk main window
78 
79 static char curcolor[80]; // current color in #rrggbb notation
80 
81 // 12000 is large enough to satisfy example 27 needs without
82 // erroring out in plD_polyline_ntk. Quadruple that to be conservative.
83 #define PLPLOT_NTK_CMD_SIZE 48000
84 static char cmd[PLPLOT_NTK_CMD_SIZE]; // buffer to build command to interp
85 static int ccanv = 0; // current canvas number
86 static char base[80]; // name of frame that contains the canvas
87 static char dash[80]; // dash string, as <mark space>*
88 
89 // line buffering
90 #define NPTS 1000
91 static short xold = -1, yold = -1; // last point of last 2 points line
92 static short xb[NPTS], yb[NPTS]; // buffer
93 static int curpts = 0; // current number of points buffered
94 
95 static int local = 1; // "local" or "remote" interpreter
96 static char rem_interp[80]; // name of remote interp
97 
98 // physical devices coordinates
99 static PLINT xmin = 0;
100 static PLINT xmax = XPIXELS;
101 static PLINT ymin = 0;
102 static PLINT ymax = YPIXELS;
103 
104 // locator
105 static PLGraphicsIn gin;
106 
107 static void
108 tk_cmd( const char *gcmd )
109 {
110  static char scmd[PLPLOT_NTK_CMD_SIZE];
111 
112  if ( local )
113  Tcl_Eval( interp, gcmd );
114  else
115  {
116  // the -async option makes it block, some times! but is *much* faster!
117  // and was working OK till now :(
118  // sprintf(scmd, "send -async %s {%s}", rem_interp, cmd);
119  //
120  sprintf( scmd, "send %s {%s}", rem_interp, gcmd ); // mess! make it more efficient
121  if ( Tcl_Eval( interp, scmd ) != TCL_OK )
122  fprintf( stderr, "%s\n", Tcl_GetStringResult( interp ) );
123  }
124 }
125 
126 static void
127 create_canvas( PLStream *pls )
128 {
129  int columnbreak;
130 
131  ccanv++;
132  columnbreak = ( ccanv % 30 == 0 );
133 
134  // create new canvas
135  sprintf( cmd, "set ccanv %d; canvas $plf.f2.c$ccanv -width $xmax -height $ymax -background #%02x%02x%02x -xscrollcommand \"$hs set\" -yscrollcommand \"$vs set\" -scrollregion \"0 0 $xmax $ymax\"", ccanv, pls->cmap0[0].r, pls->cmap0[0].g, pls->cmap0[0].b );
136  tk_cmd( cmd );
137 
138  // add new canvas to option menu
139  sprintf( cmd, "$plf.f1.mb.menu add command -label \"Page $ccanv\" -columnbreak %d -command {\n"
140  "set w $plf.f2.c%d;\n"
141  "$hs configure -command \"$w xview\";\n"
142  "$vs configure -command \"$w yview\";\n"
143  "set dname \"Page %d\";\n"
144  "pack forget $ocanvas;\n"
145  "set ocanvas $plf.f2.c%d;\n"
146  "pack $ocanvas -fill both -expand 1;\n"
147  "scan [$w xview] \"%%f %%f\" i j;\n"
148  "$hs set $i $j;\n"
149  "scan [$w yview] \"%%f %%f\" i j;\n"
150  "$vs set $i $j;}",
151  columnbreak, ccanv, ccanv, ccanv );
152  tk_cmd( cmd );
153 
154  sprintf( cmd, "set item(%d) 0", ccanv );
155  tk_cmd( cmd );
156 
157  // Shif-B1, zooms in
158  // FIXME inform the core lib of the zoom, see plframe.c around line 2818
159 
160  sprintf( cmd, "bind $plf.f2.c$ccanv <Shift-Button-1> {\n"
161  "set cc %d;\n"
162  "incr item($cc); set tt $item($cc);\n"
163  "if {$tt == 1} {\n"
164  "incr scroll_use;\n"
165  "pack $hs -side bottom -fill x;\n"
166  "pack $vs -side right -fill y;\n"
167  "pack forget %%W; pack %%W -fill both -expand 1}\n"
168  "set zx($cc,$tt) %%x;\n"
169  "set zy($cc,$tt) %%y;\n"
170  "%%W scale all %%x %%y 1.6 1.6;\n"
171  "%%W configure -scrollregion [%%W bbox all];\n"
172  "}", ccanv );
173 
174  tk_cmd( cmd );
175 
176  // Shif-B3, zooms out
177  sprintf( cmd, "bind $plf.f2.c$ccanv <Shift-Button-3> {\n"
178  "set cc %d; set tt $item($cc);\n"
179  "if {$tt != 0} {\n"
180  "%%W scale all $zx($cc,$tt) $zy($cc,$tt) 0.625 0.625\n"
181  "%%W configure -scrollregion [%%W bbox all];\n"
182  "set item($cc) [expr $tt - 1]}\n"
183  "if { $item($cc) == 0} {\n"
184  "set scroll_use [expr $scroll_use - 1];\n"
185  "if {$scroll_use == 0} {\n"
186  "pack forget $plf.f2.hscroll $plf.f2.vscroll}\n"
187  "%%W configure -scrollregion \"0 0 $xmax $ymax\"}}", ccanv );
188  tk_cmd( cmd );
189 
190  // Shift-B2, resets
191  sprintf( cmd, "bind $plf.f2.c$ccanv <Shift-Button-2> {\n"
192  "set cc %d; set tt $item($cc); \n"
193  "while {$tt != 0} {\n"
194  "%%W scale all $zx($cc,$tt) $zy($cc,$tt) 0.625 0.625\n"
195  "set tt [expr $tt - 1]};\n"
196  "set item($cc) 0;\n"
197  "%%W configure -scrollregion \"0 0 $xmax $ymax\";\n"
198  "set scroll_use [expr $scroll_use - 1];\n"
199  "if {$scroll_use == 0} {\n"
200  "pack forget $plf.f2.hscroll $plf.f2.vscroll}}", ccanv );
201  tk_cmd( cmd );
202 
203  // Control-B1-Motion, pan
204  sprintf( cmd, "bind $plf.f2.c$ccanv <Control-Button-1> \"$plf.f2.c%d scan mark %%x %%y\"", ccanv );
205  tk_cmd( cmd );
206 
207  sprintf( cmd, "bind $plf.f2.c$ccanv <Control-Button1-Motion> \"$plf.f2.c%d scan dragto %%x %%y\"", ccanv );
208  tk_cmd( cmd );
209 
210  // Control-B2, identify and (in the far future) edit object
211  tk_cmd( "bind $plf.f2.c$ccanv <Control-Button-2> {\n"
212  "set xx [ expr [winfo pointerx .] - [winfo rootx %W]];\n"
213  "set yy [ expr [winfo pointery .] - [winfo rooty %W]];\n"
214  "set near [%W find closest $xx $yy];\n"
215  "%W move $near 20 20;\n"
216  "after 500 \"%W move $near -20 -20\"}" );
217 
218  // change view to the new canvas by invoking the menu buttom
219  sprintf( cmd, "$plf.f1.mb.menu invoke %d", ccanv - 1 );
220  tk_cmd( cmd );
221 }
222 
223 //--------------------------------------------------------------------------
224 // plD_init_ntk()
225 //
226 // Initialize device (terminal).
227 //--------------------------------------------------------------------------
228 
229 void
230 plD_init_ntk( PLStream *pls )
231 {
232  pls->dev_fill0 = 1; // Handle solid fills
233  pls->dev_fill1 = 1; // Driver handles pattern fills
234  pls->color = 1; // Is a color device
235  pls->dev_dash = 1; // Handle dashed lines
236  pls->plbuf_write = 1; // Use plot buffer
237 
238  strcpy( curcolor, "black" ); // default color by name, not #rrggbb
239 
240  if ( pls->server_name != NULL )
241  {
242  local = 0;
243  strcpy( rem_interp, pls->server_name );
244  }
245 
246  if ( pls->geometry != NULL )
247  sscanf( pls->geometry, "%dx%d", &xmax, &ymax );
248 
249 // if ( pls->plwindow != NULL )
250 // strcpy( base, pls->plwindow );
251 // else
252  strcpy( base, ".plf" ); // default frame containing the canvas
253 
254  interp = Tcl_CreateInterp();
255 
256  if ( Tcl_Init( interp ) != TCL_OK )
257  plexit( "Unable to initialize Tcl." );
258 
259  if ( Tk_Init( interp ) )
260  plexit( "Unable to initialize Tk." );
261 
262  mainw = Tk_MainWindow( interp );
263  Tcl_Eval( interp, "rename exec {}" );
264 
265  Tcl_Eval( interp, "tk appname PLplot_ntk" ); // give interpreter a name
266 
267  if ( !local )
268  {
269  Tcl_Eval( interp, "wm withdraw ." );
270 
271  sprintf( cmd, "send %s \"set client [tk appname]; wm deiconify .\"", rem_interp );
272  if ( Tcl_Eval( interp, cmd ) != TCL_OK )
273  {
274  fprintf( stderr, "%s\n", Tcl_GetStringResult( interp ) );
275  plexit( "No such tk server." );
276  }
277  }
278 
279  sprintf( cmd, "set scroll_use 0; set plf %s; set vs $plf.f2.vscroll; set hs $plf.f2.hscroll; set xmax %d; set ymax %d; set ocanvas .;", base, xmax, ymax );
280  tk_cmd( cmd );
281 
282  tk_cmd( "catch \"frame $plf\"; pack $plf -fill both -expand 1" );
283 
284  sprintf( cmd, "frame $plf.f1;\n"
285  "frame $plf.f2 -width %d -height %d;\n"
286  "pack $plf.f1 -fill x;\n"
287  "pack $plf.f2 -fill both -expand 1", xmax, ymax );
288  tk_cmd( cmd );
289 
290  tk_cmd( "scrollbar $plf.f2.hscroll -orient horiz;\n"
291  "scrollbar $plf.f2.vscroll" );
292 
293  tk_cmd( "menubutton $plf.f1.mb -text \"Page 1\" -textvariable dname -relief raised -indicatoron 1 -menu $plf.f1.mb.menu;\n"
294  "menu $plf.f1.mb.menu -tearoff 0;\n"
295  "pack $plf.f1.mb -side left" );
296 
297  if ( local )
298  tk_cmd( "button $plf.f1.quit -text Quit -command exit;\n"
299  "pack $plf.f1.quit -side right" );
300  else
301  tk_cmd( "button $plf.f1.quit -text Quit -command {send -async $client exit;\n"
302  "destroy $plf;\n"
303  "wm withdraw .};\n"
304  "pack $plf.f1.quit -side right" );
305 
306  // FIXME: I just discovered that Tcl_Eval is slower than Tcl_EvalObj. Fix it global-wide, `man Tcl_Eval'
307 
308  // Set up device parameters
309 
310  Tcl_Eval( interp, "tk scaling" ); // pixels per mm
311  ppm = (PLFLT) atof( Tcl_GetStringResult( interp ) ) / ( 25.4 / 72. );
312  plP_setpxl( ppm, ppm );
313  plP_setphy( xmin, (PLINT) ( xmax * scale ), ymin, (PLINT) ( ymax * scale ) );
314 
315  tk_cmd( "update" );
316 }
317 
318 static void
319 flushbuffer( PLStream *pls )
320 {
321  if ( curpts )
322  {
323  plD_polyline_ntk( pls, xb, yb, curpts );
324 // if (curpts != 2) fprintf(stderr,"%d ", curpts);
325  xold = yold = -1; curpts = 0;
326  }
327 }
328 
329 void
330 plD_line_ntk( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
331 {
332  if ( xold == x1a && yold == y1a )
333  {
334  xold = xb[curpts] = x2a; yold = yb[curpts] = y2a; curpts++;
335  }
336  else
337  {
338  flushbuffer( pls );
339  xb[curpts] = x1a; yb[curpts] = y1a; curpts++;
340  xold = xb[curpts] = x2a; yold = yb[curpts] = y2a; curpts++;
341  }
342 
343  if ( curpts == NPTS )
344  {
345  //fprintf( stderr, "\nflush: %d ", curpts );
346  flushbuffer( pls );
347  }
348 }
349 
350 void
351 plD_polyline_ntk( PLStream * PL_UNUSED( pls ), short *xa, short *ya, PLINT npts )
352 {
353  PLINT i, j;
354 
355  // there must exist a way to code this using the tk C API
356  j = sprintf( cmd, "$plf.f2.c%d create line ", ccanv );
357  for ( i = 0; i < npts; i++ )
358  {
359  // To be completely safe, assume 5 characters to the left of the
360  // decimal point ==> 2*(5+3) characters written per sprintf
361  // call.
362  if ( ( j + 16 ) > PLPLOT_NTK_CMD_SIZE )
363  plexit( "plD_polyline_ntk: too many x, y values to hold in static cmd array" );
364  j += sprintf( &cmd[j], "%.1f %.1f ", xa[i] / scale, ymax - ya[i] / scale );
365  }
366  j += sprintf( &cmd[j], " -fill %s", curcolor );
367  if ( dash[0] == '-' )
368  j += sprintf( &cmd[j], " %s", dash );
369 
370  tk_cmd( cmd );
371 }
372 
373 // an event loop has to be designed, getcursor() and waitforpage() are just experimental
374 
375 static void
376 waitforpage( PLStream * PL_UNUSED( pls ) )
377 {
378  int key = 0, st = 0;
379  // why can't I bind to the canvas? or even any frame?
380 //tk_cmd("bind . <KeyPress> {set keypress %N; puts \"\n%k-%A-%K-%N\"}");
381  tk_cmd( "bind . <KeyPress> {set keypress %N}" );
382 
383  while ( ( key & 0xff ) != PLK_Return && ( key & 0xff ) != PLK_Linefeed && key != PLK_Next && key != 'Q' )
384  {
385  while ( st != 1 )
386  {
387  tk_cmd( "update" );
388  tk_cmd( "info exists keypress" );
389  sscanf( Tcl_GetStringResult( interp ), "%d", &st );
390  }
391 
392  tk_cmd( "set keypress" );
393  sscanf( Tcl_GetStringResult( interp ), "%d", &key );
394 //fprintf(stderr,"\n%d\n", key);fflush(stderr);
395  tk_cmd( "unset keypress" );
396  st = 0;
397  }
398 
399  tk_cmd( "bind . <Key> {};" );
400 }
401 
402 void
403 plD_eop_ntk( PLStream *pls )
404 {
405  flushbuffer( pls );
406  tk_cmd( "update" );
407 }
408 
409 void
410 plD_bop_ntk( PLStream *pls )
411 {
412  create_canvas( pls );
413 }
414 
415 void
416 plD_tidy_ntk( PLStream *pls )
417 {
418  if ( !pls->nopause )
419  waitforpage( pls );
420 
421  tk_cmd( "destroy $plf; wm withdraw ." );
422 }
423 
424 void
425 plD_state_ntk( PLStream *pls, PLINT op )
426 {
427  switch ( op )
428  {
429  case PLSTATE_COLOR0:
430  case PLSTATE_COLOR1:
431  flushbuffer( pls );
432  sprintf( curcolor, "#%02x%02x%02x",
433  pls->curcolor.r, pls->curcolor.g, pls->curcolor.b );
434  break;
435  }
436 }
437 
438 static void
439 getcursor( PLStream * PL_UNUSED( pls ), PLGraphicsIn *ptr )
440 {
441  int st = 0;
442 
443  plGinInit( &gin );
444 
445  if ( 0 )
446  {
447  while ( st != 1 )
448  {
449  tk_cmd( "update" );
450  tk_cmd( "winfo exists $plf.f2.c$ccanv" );
451  sscanf( Tcl_GetStringResult( interp ), "%d", &st );
452  }
453  st = 0;
454  // this give a "Segmentation fault", even after checking for the canvas!
455  tk_cmd( "set ocursor [lindex [$plf.f2.c$ccanv configure -cursor] 4]" );
456  }
457 
458  tk_cmd( "$plf.f2.c$ccanv configure -cursor cross;\n"
459  "bind $plf.f2.c$ccanv <Button> {set xloc %x; set yloc %y; set bloc %b; set sloc %s};\n"
460  "bind $plf.f2.c$ccanv <B1-Motion> {set xloc %x; set yloc %y; set bloc %b; set sloc %s};\n"
461  "bind $plf.f2.c$ccanv <B2-Motion> {set xloc %x; set yloc %y; set bloc %b; set sloc %s};\n"
462  "bind $plf.f2.c$ccanv <B3-Motion> {set xloc %x; set yloc %y; set bloc %b; set sloc %s};" );
463 
464  while ( st != 1 )
465  {
466  tk_cmd( "update" );
467  tk_cmd( "info exists xloc" );
468  sscanf( Tcl_GetStringResult( interp ), "%d", &st );
469  }
470  tk_cmd( "set xloc" );
471  sscanf( Tcl_GetStringResult( interp ), "%d", &gin.pX );
472  tk_cmd( "set yloc" );
473  sscanf( Tcl_GetStringResult( interp ), "%d", &gin.pY );
474  tk_cmd( "set bloc" );
475  sscanf( Tcl_GetStringResult( interp ), "%ud", &gin.button );
476  tk_cmd( "set sloc" );
477  sscanf( Tcl_GetStringResult( interp ), "%ud", &gin.state );
478 
479  gin.dX = (PLFLT) gin.pX / xmax;
480  gin.dY = 1. - (PLFLT) gin.pY / ymax;
481 
482  tk_cmd( "bind $plf.f2.c$ccanv <ButtonPress> {};\n"
483  "bind $plf.f2.c$ccanv <ButtonMotion> {};\n"
484  "bind $plf.f2.c$ccanv <B2-Motion> {};\n"
485  "bind $plf.f2.c$ccanv <B3-Motion> {};\n"
486  "unset xloc" );
487 
488  // seg fault, see above. tk_cmd("$plf.f2.c$ccanv configure -cursor $ocursor");
489  tk_cmd( "$plf.f2.c$ccanv configure -cursor {}" );
490 
491  *ptr = gin;
492 }
493 
494 void
495 plD_esc_ntk( PLStream *pls, PLINT op, void *ptr )
496 {
497  PLINT i, j;
498  short *xa, *ya;
499  //Pixmap bitmap;
500  static const unsigned char bit_pat[] = {
501  0x24, 0x01, 0x92, 0x00, 0x49, 0x00, 0x24, 0x00, 0x12, 0x00, 0x09, 0x00,
502  0x04, 0x00, 0x02, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
503  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff
504  };
505 
506  switch ( op )
507  {
508  case PLESC_DASH:
509  xa = (short *) malloc( sizeof ( short ) * (size_t) pls->dev_npts );
510  ya = (short *) malloc( sizeof ( short ) * (size_t) pls->dev_npts );
511  for ( i = 0; i < pls->dev_npts; i++ )
512  {
513  xa[i] = pls->dev_x[i];
514  ya[i] = pls->dev_y[i];
515  }
516 
517  j = sprintf( dash, "-dash {" );
518  for ( i = 0; i < pls->nms; i++ )
519  j += sprintf( &dash[j], " %d %d",
520  (int) ceil( pls->mark[i] / 1e3 * ppm ),
521  (int) ceil( pls->space[i] / 1e3 * ppm ) );
522  sprintf( &dash[j], "}" );
523  plD_polyline_ntk( pls, xa, ya, pls->dev_npts );
524  free( xa ); free( ya );
525  dash[0] = 0;
526  break;
527 
528  case PLESC_FLUSH:
529  tk_cmd( "update" );
530  break;
531 
532  case PLESC_GETC:
533  getcursor( pls, (PLGraphicsIn *) ptr );
534  break;
535 
536  case PLESC_FILL:
537  if ( pls->patt != 0 )
538  {
539  // this is a hack! The real solution is in the if(0) below
540  pls->xpmm *= scale;
541  pls->ypmm *= scale;
542  plfill_soft( pls->dev_x, pls->dev_y, pls->dev_npts );
543  pls->xpmm /= scale;
544  pls->ypmm /= scale;
545  }
546  else
547  {
548  j = sprintf( cmd, "$plf.f2.c%d create polygon ", ccanv );
549  for ( i = 0; i < pls->dev_npts; i++ )
550  j += sprintf( &cmd[j], "%.1f %.1f ", pls->dev_x[i] / scale,
551  ymax - pls->dev_y[i] / scale );
552  j += sprintf( &cmd[j], " -fill %s", curcolor );
553  tk_cmd( cmd );
554  }
555 
556  if ( 0 )
557  {
558  if ( pls->patt != 0 )
559  {
560  Tk_DefineBitmap( interp, Tk_GetUid( "foo" ), (const char *) bit_pat, 16, 16 );
561  //bitmap = Tk_GetBitmap( interp, mainw, Tk_GetUid( "patt" ) );
562  }
563  j = sprintf( cmd, "$plf.f2.c%d create polygon ", ccanv );
564  for ( i = 0; i < pls->dev_npts; i++ )
565  j += sprintf( &cmd[j], "%.1f %.1f ", pls->dev_x[i] / scale,
566  ymax - pls->dev_y[i] / scale );
567  j += sprintf( &cmd[j], " -fill %s", curcolor );
568  if ( pls->patt != 0 )
569  sprintf( &cmd[j], " -stipple patt -outline black" );
570 
571  tk_cmd( cmd );
572  //Tk_FreeBitmap(display, bitmap)
573  }
574  break;
575  }
576 }
577 
578 #else
579 int
581 {
582  return 0;
583 }
584 
585 #endif // PLD_ntkdev