PLplot: psttf.cc Source File

PLplot 5.10.0

- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
psttf.cc
Go to the documentation of this file.
1 // $Id: psttf.cc 12874 2013-12-17 05:32:16Z airwin $
2 //
3 // PLplot PostScript device driver using LASi to provide fonts
4 // based on original ps.c PostScript driver
5 //
6 // Copyright (C) 1992, 2001 Geoffrey Furnish
7 // Copyright (C) 1992, 1993, 1994, 1995, 2001 Maurice LeBrun
8 // Copyright (C) 2000-2011 Alan W. Irwin
9 // Copyright (C) 2001, 2002 Joao Cardoso
10 // Copyright (C) 2001, 2003, 2004 Rafael Laboissiere
11 // Copyright (C) 2004, 2005 Thomas J. Duck
12 // Copyright (C) 2005, 2006 Andrew Ross
13 //
14 // This file is part of PLplot.
15 //
16 // PLplot is free software; you can redistribute it and/or modify
17 // it under the terms of the GNU Library General Public License as published
18 // by the Free Software Foundation; either version 2 of the License, or
19 // (at your option) any later version.
20 //
21 // PLplot is distributed in the hope that it will be useful,
22 // but WITHOUT ANY WARRANTY; without even the implied warranty of
23 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 // GNU Library General Public License for more details.
25 //
26 // You should have received a copy of the GNU Library General Public License
27 // along with PLplot; if not, write to the Free Software
28 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 //
30 //
31
32 #include "plDevs.h"
33
34 #if defined ( PLD_psttf )
35
36 //#define NEED_PLDEBUG
37 #include "plplotP.h"
38 #include "drivers.h"
39 #include "ps.h"
40
41 #include <string.h>
42 #include <time.h>
43 #include "plfreetype.h"
44 #include <iostream>
45 #include <fstream>
46 #include <LASi.h>
47
48 // Define macro to truncate small values to zero - prevents
49 // * printf printing -0.000
50 #define TRMFLT( a ) ( ( fabs( a ) < 5.0e-4 ) ? 0.0 : ( a ) )
51
52 using namespace LASi;
53 using namespace std;
54
55 // Device info
56
57 PLDLLIMPEXP_DRIVER const char* plD_DEVICE_INFO_psttf =
58 "psttf:PostScript File (monochrome):0:psttf:55:psttfm\n"
59 "psttfc:PostScript File (color):0:psttf:56:psttfc\n";
60
61
62 // Prototypes for functions in this file.
63
64 void plD_dispatch_init_psttfm( PLDispatchTable *pdt );
65 void plD_dispatch_init_psttfc( PLDispatchTable *pdt );
66
67 static char *ps_getdate( void );
68 static void ps_init( PLStream * );
69 static void fill_polygon( PLStream *pls );
70 static void proc_str( PLStream *, EscText * );
71 //static void esc_purge( char *, char * );
72
73 #define OUTBUF_LEN 128
74 static char outbuf[OUTBUF_LEN];
75 static int text = 1;
76 static int color;
77 static int hrshsym = 0;
78
79 // Font style and weight lookup tables
80
81 #define N_Pango_Lookup 5
82
83 const char * DefaultFamilyLookup[N_Pango_Lookup] = {
84 "sans",
85 "serif",
86 "monospace",
87 "sans,serif",
88 "sans,serif"
89 };
90
91 const char * EnvFamilyLookup[N_Pango_Lookup] = {
92 "PLPLOT_FREETYPE_SANS_FAMILY",
93 "PLPLOT_FREETYPE_SERIF_FAMILY",
94 "PLPLOT_FREETYPE_MONO_FAMILY",
95 "PLPLOT_FREETYPE_SCRIPT_FAMILY",
96 "PLPLOT_FREETYPE_SYMBOL_FAMILY"
97 };
98
99 #define FAMILY_LOOKUP_LEN 1024
100 char FamilyLookup[N_Pango_Lookup][FAMILY_LOOKUP_LEN];
101
102 const FontWeight WeightLookup[2] = {
103 NORMAL_WEIGHT,
104 BOLD
105 };
106
107 const FontStyle StyleLookup[3] = {
108 NORMAL_STYLE,
109 ITALIC,
110 OBLIQUE
111 };
112
113 static DrvOpt ps_options[] = { { "text", DRV_INT, &text, "Use Postscript text (text=0|1)" },
114 { "color", DRV_INT, &color, "Use color (color=0|1)" },
115 { "hrshsym", DRV_INT, &hrshsym, "Use Hershey symbol set (hrshsym=0|1)" },
116 { NULL, DRV_INT, NULL, NULL } };
117
118 // text > 0 uses some postscript tricks, namely a transformation matrix
119 // that scales, rotates (with slanting) and offsets text strings.
120 // It has yet some bugs for 3d plots.
121
122
123 static void psttf_dispatch_init_helper( PLDispatchTable *pdt,
124 const char *menustr, const char *devnam,
125 int type, int seq, plD_init_fp init )
126 {
127 #ifndef ENABLE_DYNDRIVERS
128 pdt->pl_MenuStr = (char *) menustr;
129 pdt->pl_DevName = (char *) devnam;
130 #else
131 (void) menustr; // Cast to void to silence compiler warnings about unused parameters
132 (void) devnam;
133 #endif
134 pdt->pl_type = type;
135 pdt->pl_seq = seq;
136 pdt->pl_init = init;
137 pdt->pl_line = (plD_line_fp) plD_line_psttf;
138 pdt->pl_polyline = (plD_polyline_fp) plD_polyline_psttf;
139 pdt->pl_eop = (plD_eop_fp) plD_eop_psttf;
140 pdt->pl_bop = (plD_bop_fp) plD_bop_psttf;
141 pdt->pl_tidy = (plD_tidy_fp) plD_tidy_psttf;
142 pdt->pl_state = (plD_state_fp) plD_state_psttf;
143 pdt->pl_esc = (plD_esc_fp) plD_esc_psttf;
144 }
145
146 void plD_dispatch_init_psttfm( PLDispatchTable *pdt )
147 {
148 psttf_dispatch_init_helper( pdt,
149 "PostScript File (monochrome)", "psttf",
150 plDevType_FileOriented, 55,
151 (plD_init_fp) plD_init_psttfm );
152 }
153
154 void plD_dispatch_init_psttfc( PLDispatchTable *pdt )
155 {
156 psttf_dispatch_init_helper( pdt,
157 "PostScript File (color)", "psttfc",
158 plDevType_FileOriented, 56,
159 (plD_init_fp) plD_init_psttfc );
160 }
161
162 //--------------------------------------------------------------------------
163 // plD_init_psttf()
164 //
165 // Initialize device.
166 //--------------------------------------------------------------------------
167
168 void
169 plD_init_psttfm( PLStream *pls )
170 {
171 color = 0;
172 pls->color = 0; // Not a color device
173
174 plParseDrvOpts( ps_options );
175 if ( color )
176 pls->color = 1; // But user wants color
177 ps_init( pls );
178 }
179
180 void
181 plD_init_psttfc( PLStream *pls )
182 {
183 color = 1;
184 pls->color = 1; // Is a color device
185 plParseDrvOpts( ps_options );
186
187 if ( !color )
188 pls->color = 0; // But user does not want color
189 ps_init( pls );
190 }
191
192 #define MAX_NUM_TRIES 10
193 static void
194 ps_init( PLStream *pls )
195 {
196 int i;
197 char *a;
198 PSDev *dev;
199 PostscriptDocument *doc;
200 PLFLT pxlx, pxly;
201
202 // Set default values - 7.5 x 10 [inches] (72 points = 1 inch)
203 if ( pls->xlength <= 0 || pls->ylength <= 0 )
204 {
205 pls->xlength = 540;
206 pls->ylength = 720;
207 }
208 if ( pls->xdpi <= 0 )
209 pls->xdpi = 72.;
210 if ( pls->ydpi <= 0 )
211 pls->ydpi = 72.;
212
213
214 pxlx = YPSSIZE / LPAGE_X;
215 pxly = XPSSIZE / LPAGE_Y;
216
217 if ( text )
218 {
219 pls->dev_text = 1; // want to draw text
220 pls->dev_unicode = 1; // want unicode
221 if ( hrshsym )
222 pls->dev_hrshsym = 1; // want Hershey symbols
223 }
224
225 pls->dev_fill0 = 1; // Can do solid fills
226
227 // Initialize family file info
228
229 plFamInit( pls );
230
231 // Prompt for a file name if not already set
232
233 plOpenFile( pls );
234
235 // Create postscript document object
236 if ( pls->psdoc != NULL )
237 delete (PostscriptDocument *) pls->psdoc;
238
239 pls->psdoc = new PostscriptDocument();
240 doc = (PostscriptDocument *) ( pls->psdoc );
241 doc->osBody() << fixed;
242 doc->osBody().precision( 3 );
243
244 // Allocate and initialize device-specific data
245
246 if ( pls->dev != NULL )
247 free( (void *) pls->dev );
248
249 pls->dev = calloc( 1, (size_t) sizeof ( PSDev ) );
250 if ( pls->dev == NULL )
251 plexit( "ps_init: Out of memory." );
252
253 dev = (PSDev *) pls->dev;
254
255 dev->xold = PL_UNDEFINED;
256 dev->yold = PL_UNDEFINED;
257
258 plP_setpxl( pxlx, pxly );
259
260 dev->llx = XPSSIZE;
261 dev->lly = YPSSIZE;
262 dev->urx = 0;
263 dev->ury = 0;
264 dev->ptcnt = 0;
265
266 // Rotate by 90 degrees since portrait mode addressing is used
267
268 dev->xmin = 0;
269 dev->ymin = 0;
270 dev->xmax = PSY;
271 dev->ymax = PSX;
272 dev->xlen = dev->xmax - dev->xmin;
273 dev->ylen = dev->ymax - dev->ymin;
274
275 plP_setphy( dev->xmin, dev->xmax, dev->ymin, dev->ymax );
276
277 // If portrait mode is specified, then set up an additional rotation
278 // transformation with aspect ratio allowed to adjust via freeaspect.
279 // Default orientation is landscape (ORIENTATION == 3 or 90 deg rotation
280 // counter-clockwise from portrait). (Legacy PLplot used seascape
281 // which was equivalent to ORIENTATION == 1 or 90 deg clockwise rotation
282 // from portrait.)
283
284 if ( pls->portrait )
285 {
286 plsdiori( (PLFLT) ( 4 - ORIENTATION ) );
287 pls->freeaspect = 1;
288 }
289
290 // File table for font families using either environment variables
291 // or defaults.
292 for ( i = 0; i < N_Pango_Lookup; i++ )
293 {
294 if ( ( a = getenv( EnvFamilyLookup[i] ) ) != NULL )
295 {
296 strncpy( FamilyLookup[i], a, FAMILY_LOOKUP_LEN - 1 );
297 FamilyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
298 }
299 else
300 {
301 strncpy( FamilyLookup[i], DefaultFamilyLookup[i], FAMILY_LOOKUP_LEN );
302 FamilyLookup[i][FAMILY_LOOKUP_LEN - 1] = '\0';
303 }
304 }
305 }
306
307
308 //--------------------------------------------------------------------------
309 // writeHeader()
310 //
311 // Write plplot postscript commands into the header
312 //--------------------------------------------------------------------------
313
314 void
315 writeHeader( PLStream *pls )
316 {
317 PostscriptDocument *doc = (PostscriptDocument *) ( pls->psdoc );
318
319 doc->osHeader() << "%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
320
321 doc->osHeader() << "%%Title: PLplot Graph\n";
322 doc->osHeader() << "%%Creator: PLplot Version " << PLPLOT_VERSION << "\n";
323 doc->osHeader() << "%%CreationDate: " << ps_getdate() << "\n";
324 doc->osHeader() << "%%Pages: (atend)\n";
325 doc->osHeader() << "%%EndComments\n\n";
326
327 // Definitions
328 // Save VM state
329
330 doc->osHeader() << "/PSSave save def\n";
331
332 // Define a dictionary and start using it
333
334 doc->osHeader() << "/PSDict 200 dict def\n";
335 doc->osHeader() << "PSDict begin\n";
336
337 doc->osHeader() << "/@restore /restore load def\n";
338 doc->osHeader() << "/restore\n";
339 doc->osHeader() << " {vmstatus pop\n";
340 doc->osHeader() << " dup @VMused lt {pop @VMused} if\n";
341 doc->osHeader() << " exch pop exch @restore /@VMused exch def\n";
342 doc->osHeader() << " } def\n";
343 doc->osHeader() << "/@pri\n";
344 doc->osHeader() << " {\n";
345 doc->osHeader() << " ( ) print\n";
346 doc->osHeader() << " ( ) cvs print\n";
347 doc->osHeader() << " } def\n";
348
349 // n @copies -
350
351 doc->osHeader() << "/@copies\n";
352 doc->osHeader() << " {\n";
353 doc->osHeader() << " /#copies exch def\n";
354 doc->osHeader() << " } def\n";
355
356 // - @start - -- start everything
357
358 doc->osHeader() << "/@start\n";
359 doc->osHeader() << " {\n";
360 doc->osHeader() << " vmstatus pop /@VMused exch def pop\n";
361 doc->osHeader() << " } def\n";
362
363 // - @end - -- finished
364
365 doc->osHeader() << "/@end\n";
366 doc->osHeader() << " {flush\n";
367 doc->osHeader() << " end\n";
368 doc->osHeader() << " PSSave restore\n";
369 doc->osHeader() << " } def\n";
370
371 // bop - -- begin a new page
372 // Only fill background if we are using color and if the bg isn't white
373
374 doc->osHeader() << "/bop\n";
375 doc->osHeader() << " {\n";
376 doc->osHeader() << " /SaveImage save def\n";
377 doc->osHeader() << " } def\n";
378
379 // - eop - -- end a page
380
381 doc->osHeader() << "/eop\n";
382 doc->osHeader() << " {\n";
383 doc->osHeader() << " showpage\n";
384 doc->osHeader() << " SaveImage restore\n";
385 doc->osHeader() << " } def\n";
386
387 // Set line parameters
388
389 doc->osHeader() << "/@line\n";
390 doc->osHeader() << " {0 setlinecap\n";
391 doc->osHeader() << " 0 setlinejoin\n";
392 doc->osHeader() << " 1 setmiterlimit\n";
393 doc->osHeader() << " } def\n";
394
395 // d @hsize - horizontal clipping dimension
396
397 doc->osHeader() << "/@hsize {/hs exch def} def\n";
398 doc->osHeader() << "/@vsize {/vs exch def} def\n";
399
400 // d @hoffset - shift for the plots
401
402 doc->osHeader() << "/@hoffset {/ho exch def} def\n";
403 doc->osHeader() << "/@voffset {/vo exch def} def\n";
404
405 // Set line width
406
407 doc->osHeader() << "/lw " << (int) (
408 ( pls->width < MIN_WIDTH ) ? DEF_WIDTH :
409 ( pls->width > MAX_WIDTH ) ? MAX_WIDTH : pls->width ) << " def\n";
410
411 // Setup user specified offsets, scales, sizes for clipping
412
413 doc->osHeader() << "/@SetPlot\n";
414 doc->osHeader() << " {\n";
415 doc->osHeader() << " ho vo translate\n";
416 doc->osHeader() << " XScale YScale scale\n";
417 doc->osHeader() << " lw setlinewidth\n";
418 doc->osHeader() << " } def\n";
419
420 // Setup x & y scales
421
422 doc->osHeader() << "/XScale\n";
423 doc->osHeader() << " {hs " << YPSSIZE << " div} def\n";
424 doc->osHeader() << "/YScale\n";
425 doc->osHeader() << " {vs " << XPSSIZE << " div} def\n";
426
427 // Macro definitions of common instructions, to keep output small
428
429 doc->osHeader() << "/M {moveto} def\n";
430 doc->osHeader() << "/D {lineto} def\n";
431 doc->osHeader() << "/A {0.5 0 360 arc} def\n";
432 doc->osHeader() << "/S {stroke} def\n";
433 doc->osHeader() << "/Z {stroke newpath} def\n";
434 if ( pls->dev_eofill )
435 doc->osHeader() << "/F {closepath gsave eofill grestore stroke} def\n";
436 else
437 doc->osHeader() << "/F {closepath gsave fill grestore stroke} def\n";
438 doc->osHeader() << "/N {newpath} def\n";
439 doc->osHeader() << "/C {setrgbcolor} def\n";
440 doc->osHeader() << "/G {setgray} def\n";
441 doc->osHeader() << "/W {setlinewidth} def\n";
442 doc->osHeader() << "/R {rotate} def\n";
443 doc->osHeader() << "/B {Z " << XMIN << " " << YMIN << " M " << XMIN << " " << YMAX << " D " << XMAX << " " << YMAX << " D " << XMAX << " " << YMIN << " D " << XMIN << " " << YMIN << " closepath} def\n";
444 doc->osHeader() << "/CL {newpath M D D D closepath clip} def\n";
445
446 // End of dictionary definition
447
448 doc->osHeader() << "end\n\n";
449
450 // Set up the plots
451
452 doc->osHeader() << "PSDict begin\n";
453 doc->osHeader() << "@start\n";
454 doc->osHeader() << COPIES << " @copies\n";
455 doc->osHeader() << "@line\n";
456 doc->osHeader() << YSIZE << " @hsize\n";
457 doc->osHeader() << XSIZE << " @vsize\n";
458 doc->osHeader() << YOFFSET << " @hoffset\n";
459 doc->osHeader() << XOFFSET << " @voffset\n";
460
461 doc->osHeader() << "@SetPlot\n" << endl;
462 }
463
464 //--------------------------------------------------------------------------
465 // plD_line_psttf()
466 //
467 // Draw a line in the current color from (x1,y1) to (x2,y2).
468 //--------------------------------------------------------------------------
469
470 void
471 plD_line_psttf( PLStream *pls, short x1a, short y1a, short x2a, short y2a )
472 {
473 PSDev *dev = (PSDev *) pls->dev;
474 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
475 PLINT x1 = x1a, y1 = y1a, x2 = x2a, y2 = y2a;
476
477 // Rotate by 90 degrees
478
479 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x1, &y1 );
480 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x2, &y2 );
481
482 if ( x1 == dev->xold && y1 == dev->yold && dev->ptcnt < 40 )
483 {
484 if ( pls->linepos + 12 > LINELENGTH )
485 {
486 doc->osBody() << '\n';
487 pls->linepos = 0;
488 }
489 else
490 doc->osBody() << ' ';
491
492 snprintf( outbuf, OUTBUF_LEN, "%d %d D", x2, y2 );
493 dev->ptcnt++;
494 pls->linepos += 12;
495 }
496 else
497 {
498 doc->osBody() << " Z\n";
499 pls->linepos = 0;
500
501 if ( x1 == x2 && y1 == y2 ) // must be a single dot, draw a circle
502 snprintf( outbuf, OUTBUF_LEN, "%d %d A", x1, y1 );
503 else
504 snprintf( outbuf, OUTBUF_LEN, "%d %d M %d %d D", x1, y1, x2, y2 );
505 dev->llx = MIN( dev->llx, x1 );
506 dev->lly = MIN( dev->lly, y1 );
507 dev->urx = MAX( dev->urx, x1 );
508 dev->ury = MAX( dev->ury, y1 );
509 dev->ptcnt = 1;
510 pls->linepos += 24;
511 }
512 dev->llx = MIN( dev->llx, x2 );
513 dev->lly = MIN( dev->lly, y2 );
514 dev->urx = MAX( dev->urx, x2 );
515 dev->ury = MAX( dev->ury, y2 );
516
517 doc->osBody() << outbuf;
518 pls->bytecnt += 1 + strlen( outbuf );
519 dev->xold = x2;
520 dev->yold = y2;
521 }
522
523 //--------------------------------------------------------------------------
524 // plD_polyline_psttf()
525 //
526 // Draw a polyline in the current color.
527 //--------------------------------------------------------------------------
528
529 void
530 plD_polyline_psttf( PLStream *pls, short *xa, short *ya, PLINT npts )
531 {
532 PLINT i;
533
534 for ( i = 0; i < npts - 1; i++ )
535 plD_line_psttf( pls, xa[i], ya[i], xa[i + 1], ya[i + 1] );
536 }
537
538 //--------------------------------------------------------------------------
539 // plD_eop_psttf()
540 //
541 // End of page.
542 //--------------------------------------------------------------------------
543
544 void
545 plD_eop_psttf( PLStream *pls )
546 {
547 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
548 doc->osBody() << " S\neop\n";
549 }
550
551 //--------------------------------------------------------------------------
552 // plD_bop_psttf()
553 //
554 // Set up for the next page.
555 // Advance to next family file if necessary (file output).
556 //--------------------------------------------------------------------------
557
558 void
559 plD_bop_psttf( PLStream *pls )
560 {
561 PSDev *dev = (PSDev *) pls->dev;
562 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
563
564 dev->xold = PL_UNDEFINED;
565 dev->yold = PL_UNDEFINED;
566
567 if ( !pls->termin )
568 plGetFam( pls );
569
570 pls->page++;
571
572 if ( pls->family )
573 doc->osBody() << "%%Page: " << (int) pls->page << " 1\n";
574 else
575 doc->osBody() << "%%Page: " << (int) pls->page << " " << (int) pls->page << "\n";
576
577 doc->osBody() << "bop\n";
578 if ( pls->color )
579 {
580 PLFLT r, g, b;
581 if ( pls->cmap0[0].r != 0xFF ||
582 pls->cmap0[0].g != 0xFF ||
583 pls->cmap0[0].b != 0xFF )
584 {
585 r = ( (PLFLT) pls->cmap0[0].r ) / 255.;
586 g = ( (PLFLT) pls->cmap0[0].g ) / 255.;
587 b = ( (PLFLT) pls->cmap0[0].b ) / 255.;
588
589 doc->osBody() << "B " << r << " " << g << " " << b << " C F\n";
590 }
591 }
592 pls->linepos = 0;
593
594 // This ensures the color and line width are set correctly at the beginning of
595 // each page
596
597 plD_state_psttf( pls, PLSTATE_COLOR0 );
598 plD_state_psttf( pls, PLSTATE_WIDTH );
599 }
600
601 //--------------------------------------------------------------------------
602 // plD_tidy_psttf()
603 //
604 // Close graphics file or otherwise clean up.
605 //--------------------------------------------------------------------------
606
607 void
608 plD_tidy_psttf( PLStream *pls )
609 {
610 PSDev *dev = (PSDev *) pls->dev;
611 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
612
613 dev->llx /= ENLARGE;
614 dev->lly /= ENLARGE;
615 dev->urx /= ENLARGE;
616 dev->ury /= ENLARGE;
617 dev->llx += XOFFSET;
618 dev->lly += YOFFSET;
619 dev->urx += XOFFSET;
620 dev->ury += YOFFSET;
621
622 // changed for correct Bounding boundaries Jan Thorbecke okt 1993
623 // occurs from the integer truncation -- postscript uses fp arithmetic
624
625 dev->urx += 1;
626 dev->ury += 1;
627
628 if ( pls->family )
629 doc->osFooter() << "%%Pages: 1\n";
630 else
631 doc->osFooter() << "%%Pages: " << (int) pls->page << "\n";
632
633 doc->osFooter() << "@end" << endl;
634
635 // Now write the rest of the header
636 writeHeader( pls );
637
638 // Write out postscript document to file and close
639 // For C++ stream we first need to close the file using
640 // the C FILE * handle, then reopen as a ofstream. Yuck!
641 if ( !strcmp( pls->FileName, "-" ) )
642 {
643 doc->write( cout, dev->llx, dev->lly, dev->urx, dev->ury );
644 }
645 else
646 {
647 plCloseFile( pls );
648 ofstream out;
649 out.open( pls->FileName );
650 doc->write( out, dev->llx, dev->lly, dev->urx, dev->ury );
651 out.close();
652 }
653
654 delete doc;
655 pls->psdoc = NULL;
656 }
657
658 //--------------------------------------------------------------------------
659 // plD_state_psttf()
660 //
661 // Handle change in PLStream state (color, pen width, fill attribute, etc).
662 //--------------------------------------------------------------------------
663
664 void
665 plD_state_psttf( PLStream *pls, PLINT op )
666 {
667 PSDev *dev = (PSDev *) pls->dev;
668 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
669
670 switch ( op )
671 {
672 case PLSTATE_WIDTH: {
673 int width = (int) (
674 ( pls->width < MIN_WIDTH ) ? DEF_WIDTH :
675 ( pls->width > MAX_WIDTH ) ? MAX_WIDTH : pls->width );
676
677 doc->osBody() << " S\n" << width << " W";
678
679 dev->xold = PL_UNDEFINED;
680 dev->yold = PL_UNDEFINED;
681 break;
682 }
683 case PLSTATE_COLOR0:
684 if ( !pls->color )
685 {
686 doc->osBody() << " S\n" << ( pls->icol0 ? 0.0 : 1.0 ) << " G";
687 break;
688 }
689 // else fallthrough
690 case PLSTATE_COLOR1:
691 if ( pls->color )
692 {
693 PLFLT r = ( (PLFLT) pls->curcolor.r ) / 255.0;
694 PLFLT g = ( (PLFLT) pls->curcolor.g ) / 255.0;
695 PLFLT b = ( (PLFLT) pls->curcolor.b ) / 255.0;
696
697 doc->osBody() << " S\n" << r << " " << g << " " << b << " C";
698 }
699 else
700 {
701 PLFLT r = ( (PLFLT) pls->curcolor.r ) / 255.0;
702 doc->osBody() << " S\n" << 1.0 - r << " G";
703 }
704 break;
705 }
706
707 // Reinitialize current point location.
708
709 if ( dev->xold != PL_UNDEFINED && dev->yold != PL_UNDEFINED )
710 {
711 doc->osBody() << " " << (int) dev->xold << " " << (int) dev->yold << " M \n";
712 }
713 }
714
715 //--------------------------------------------------------------------------
716 // plD_esc_psttf()
717 //
718 // Escape function.
719 //--------------------------------------------------------------------------
720
721 void
722 plD_esc_psttf( PLStream *pls, PLINT op, void *ptr )
723 {
724 switch ( op )
725 {
726 case PLESC_FILL:
727 fill_polygon( pls );
728 break;
729 case PLESC_HAS_TEXT:
730 proc_str( pls, (EscText *) ptr );
731 break;
732 }
733 }
734
735 //--------------------------------------------------------------------------
736 // fill_polygon()
737 //
738 // Fill polygon described in points pls->dev_x[] and pls->dev_y[].
739 // Only solid color fill supported.
740 //--------------------------------------------------------------------------
741
742 static void
743 fill_polygon( PLStream *pls )
744 {
745 PSDev *dev = (PSDev *) pls->dev;
746 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
747 PLINT n, ix = 0, iy = 0;
748 PLINT x, y;
749
750 doc->osBody() << " Z\n";
751
752 for ( n = 0; n < pls->dev_npts; n++ )
753 {
754 x = pls->dev_x[ix++];
755 y = pls->dev_y[iy++];
756
757 // Rotate by 90 degrees
758
759 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax, &x, &y );
760
761 // First time through start with a x y moveto
762
763 if ( n == 0 )
764 {
765 snprintf( outbuf, OUTBUF_LEN, "N %d %d M", x, y );
766 dev->llx = MIN( dev->llx, x );
767 dev->lly = MIN( dev->lly, y );
768 dev->urx = MAX( dev->urx, x );
769 dev->ury = MAX( dev->ury, y );
770 doc->osBody() << outbuf;
771 pls->bytecnt += strlen( outbuf );
772 continue;
773 }
774
775 if ( pls->linepos + 21 > LINELENGTH )
776 {
777 doc->osBody() << '\n';
778 pls->linepos = 0;
779 }
780 else
781 doc->osBody() << ' ';
782
783 pls->bytecnt++;
784
785 snprintf( outbuf, OUTBUF_LEN, "%d %d D", x, y );
786 dev->llx = MIN( dev->llx, x );
787 dev->lly = MIN( dev->lly, y );
788 dev->urx = MAX( dev->urx, x );
789 dev->ury = MAX( dev->ury, y );
790
791 doc->osBody() << outbuf;
792 pls->bytecnt += strlen( outbuf );
793 pls->linepos += 21;
794 }
795 dev->xold = PL_UNDEFINED;
796 dev->yold = PL_UNDEFINED;
797 doc->osBody() << " F ";
798 }
799
800 //--------------------------------------------------------------------------
801 // ps_getdate()
802 //
803 // Get the date and time
804 //--------------------------------------------------------------------------
805
806 static char *
807 ps_getdate( void )
808 {
809 int len;
810 time_t t;
811 char *p;
812
813 t = time( (time_t *) 0 );
814 p = ctime( &t );
815 len = strlen( p );
816 *( p + len - 1 ) = '\0'; // zap the newline character
817 return p;
818 }
819
820 // 0.8 should mimic the offset of first superscript/subscript level
821 // implemented in plstr (plsym.c) for Hershey fonts. However, when
822 // comparing with -dev xwin and -dev xcairo results changing this
823 // factor to 0.6 appears to offset the centers of the letters
824 // appropriately while 0.8 gives much poorer agreement with the
825 // other devices.
826 # define RISE_FACTOR 0.6
827
828 //--------------------------------------------------------------------------
829 // proc_str()
830 //
831 // Prints postscript strings.
832 // N.B. Now unicode only, no string access!
833 //
834 //--------------------------------------------------------------------------
835
836 void
837 proc_str( PLStream *pls, EscText *args )
838 {
839 PLFLT *t = args->xform, tt[4]; // Transform matrices
840 PLFLT theta, shear, stride; // Rotation angle and shear from the matrix
841 PLFLT ft_ht, offset; // Font height and offset
842 PLFLT cs, sn;
843 PSDev *dev = (PSDev *) pls->dev;
844 PostscriptDocument *doc = (PostscriptDocument *) pls->psdoc;
845 char *font, esc;
846 FontStyle style;
847 FontWeight weight;
848 // Be generous. Used to store lots of font changes which take
849 // 3 characters per change.
850 #define PROC_STR_STRING_LENGTH 1000
851 char *strp, str[PROC_STR_STRING_LENGTH], *cur_strp,
852 cur_str[PROC_STR_STRING_LENGTH];
853 float font_factor = 1.4;
854 PLINT clxmin, clxmax, clymin, clymax; // Clip limits
855 PLINT clipx[4], clipy[4]; // Current clip limits
856
857 PLFLT scale = 1., up = 0.; // Font scaling and shifting parameters
858
859 double lineSpacing, xAdvance, ymintmp, ymaxtmp, ymin, ymax, xmin, xmax;
860 PLINT xx[4], yy[4];
861
862 // unicode only! so test for it.
863 if ( args->unicode_array_len > 0 )
864 {
865 int j, s, f;
866 char *fonts[PROC_STR_STRING_LENGTH];
867 FontStyle styles[PROC_STR_STRING_LENGTH];
868 FontWeight weights[PROC_STR_STRING_LENGTH];
869 const PLUNICODE *cur_text;
870 PLUNICODE fci;
871 unsigned char fontfamily, fontstyle, fontweight;
872 PLFLT old_sscale, sscale, old_soffset, soffset, dup;
873 PLINT level = 0;
874
875 // translate from unicode into type 1 font index.
876 //
877 // Choose the font family, style, variant, and weight using
878 // the FCI (font characterization integer).
879 //
880
881 plgesc( &esc );
882 plgfci( &fci );
883 plP_fci2hex( fci, &fontfamily, PL_FCI_FAMILY );
884 plP_fci2hex( fci, &fontstyle, PL_FCI_STYLE );
885 plP_fci2hex( fci, &fontweight, PL_FCI_WEIGHT );
886 font = (char *) FamilyLookup[fontfamily];
887 weight = WeightLookup[fontweight];
888 style = StyleLookup[fontstyle];
889 // Need to add some error checking here
890 if ( false )
891 {
892 fprintf( stderr, "fci = 0x%x, font name pointer = NULL \n", fci );
893 plabort( "proc_str: FCI inconsistent with TrueTypeLookup; "
894 "internal PLplot error" );
895 return;
896 }
897 //pldebug("proc_str", "fci = 0x%x, font name = %s\n", fci, font);
898 cur_text = args->unicode_array;
899 for ( f = s = j = 0; j < args->unicode_array_len; j++ )
900 {
901 if ( cur_text[j] & PL_FCI_MARK )
902 {
903 // process an FCI by saving it and escaping cur_str
904 // with an escff to make it a 2-character escape
905 // that is not used in legacy Hershey code
906 //
907 if ( ( f < PROC_STR_STRING_LENGTH ) && ( s + 3 < PROC_STR_STRING_LENGTH ) )
908 {
909 plP_fci2hex( cur_text[j], &fontfamily, PL_FCI_FAMILY );
910 plP_fci2hex( cur_text[j], &fontstyle, PL_FCI_STYLE );
911 plP_fci2hex( cur_text[j], &fontweight, PL_FCI_WEIGHT );
912 fonts[f] = (char *) FamilyLookup[fontfamily];
913 weights[f] = WeightLookup[fontweight];
914 styles[f] = StyleLookup[fontstyle];
915 if ( fonts[f] == NULL )
916 {
917 fprintf( stderr, "string-supplied FCI = 0x%x, font name pointer = NULL \n", cur_text[j] );
918 plabort( "proc_str: string-supplied FCI inconsistent with font lookup;" );
919 return;
920 }
921 //pldebug("proc_str", "string-supplied FCI = 0x%x, font name = %s\n", cur_text[j], fonts[f]);
922 cur_str[s++] = esc;
923 cur_str[s++] = 'f';
924 cur_str[s++] = 'f';
925 f++;
926 }
927 }
928 else if ( s + 1 < PROC_STR_STRING_LENGTH )
929 {
930 s += ucs4_to_utf8( cur_text[j], &cur_str[s] );
931 //pldebug("proc_str", "unicode = 0x%x, type 1 code = %d\n",
932 // cur_text[j], cur_str[j]);
933 }
934 }
935 cur_str[s] = '\0';
936
937 // finish previous polyline
938
939 dev->xold = PL_UNDEFINED;
940 dev->yold = PL_UNDEFINED;
941
942 // Determine the font height
943 ft_ht = pls->chrht * 72.0 / 25.4; // ft_ht in points, ht is in mm
944
945
946 // The transform matrix has only rotations and shears; extract them
947 plRotationShear( t, &theta, &shear, &stride );
948 cs = cos( theta );
949 sn = sin( theta );
950 tt[0] = t[0] * cs + t[2] * sn;
951 tt[1] = t[1] * cs + t[3] * sn;
952 tt[2] = -t[0] * sn + t[2] * cs;
953 tt[3] = -t[1] * sn + t[3] * cs;
954
955 //
956 // Reference point conventions:
957 // If base = 0, it is aligned with the center of the text box
958 // If base = 1, it is aligned with the baseline of the text box
959 // If base = 2, it is aligned with the top of the text box
960 //
961 // Currently plplot only uses base=0
962 // Postscript uses base=1
963 //
964 // We must calculate the difference between the two and apply the offset.
965 //
966
967 if ( args->base == 2 ) // not supported by plplot
968 offset = ENLARGE * ft_ht / 2.; // half font height
969 else if ( args->base == 1 )
970 offset = 0.;
971 else
972 offset = -ENLARGE * ft_ht / 2.;
973
974 // Determine the adjustment for page orientation
975 theta -= PI / 2. * pls->diorot;
976 args->y += (int) ( offset * cos( theta ) );
977 args->x -= (int) ( offset * sin( theta ) );
978
979 // ps driver is rotated by default
980 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
981 &( args->x ), &( args->y ) );
982
983 // Correct for the fact ps driver uses landscape by default
984 theta += PI / 2.;
985
986 // Output
987 // Set clipping
988 clipx[0] = pls->clpxmi;
989 clipx[2] = pls->clpxma;
990 clipy[0] = pls->clpymi;
991 clipy[2] = pls->clpyma;
992 clipx[1] = clipx[2];
993 clipy[1] = clipy[0];
994 clipx[3] = clipx[0];
995 clipy[3] = clipy[2];
996 difilt( clipx, clipy, 4, &clxmin, &clxmax, &clymin, &clymax );
997 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
998 &clipx[0], &clipy[0] );
999 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
1000 &clipx[1], &clipy[1] );
1001 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
1002 &clipx[2], &clipy[2] );
1003 plRotPhy( ORIENTATION, dev->xmin, dev->ymin, dev->xmax, dev->ymax,
1004 &clipx[3], &clipy[3] );
1005 doc->osBody() << " gsave " << clipx[0] << " " << clipy[0] << " " <<
1006 clipx[1] << " " << clipy[1] << " " << clipx[2] << " " <<
1007 clipy[2] << " " << clipx[3] << " " << clipy[3] << " CL\n";
1008
1009 // move to string reference point
1010 doc->osBody() << " " << args->x << " " << args->y << " M\n";
1011
1012 // Save the current position and set the string rotation
1013 doc->osBody() << "gsave " << TRMFLT( theta * 180. / PI ) << " R\n";
1014
1015 doc->osBody() << "[" << TRMFLT( tt[0] ) << " " << TRMFLT( tt[2] ) << " " << TRMFLT( tt[1] )
1016 << " " << TRMFLT( tt[3] ) << " 0 0] concat\n";
1017
1018 xmax = 0;
1019 // Dummy run through the string first to work out the
1020 // length, including any font changes
1021 cur_strp = cur_str;
1022 f = 0;
1023 do
1024 {
1025 strp = str;
1026
1027 if ( *cur_strp == esc )
1028 {
1029 cur_strp++;
1030
1031 if ( *cur_strp == esc ) // <esc><esc>
1032 {
1033 *strp++ = *cur_strp++;
1034 }
1035 else if ( *cur_strp == 'f' )
1036 {
1037 cur_strp++;
1038 if ( *cur_strp++ != 'f' )
1039 {
1040 // escff occurs because of logic above. But any suffix
1041 // other than "f" should never happen.
1042 plabort( "proc_str, internal PLplot logic error;"
1043 "wrong escf escape sequence" );
1044 return;
1045 }
1046 font = fonts[f];
1047 style = styles[f];
1048 weight = weights[f];
1049 f++;
1050 continue;
1051 }
1052 else
1053 switch ( *cur_strp++ )
1054 {
1055 case 'd': //subscript
1056 case 'D':
1057 plP_script_scale( FALSE, &level,
1058 &old_sscale, &sscale, &old_soffset, &soffset );
1059 scale = sscale;
1060 // The correction for the difference in magnitude
1061 // between the baseline and middle coordinate systems
1062 // for subscripts should be
1063 // -0.5*(base font size - superscript/subscript font size).
1064 dup = -0.5 * ( 1.0 - sscale );
1065 up = -font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + dup );
1066 break;
1067
1068 case 'u': //superscript
1069 case 'U':
1070 plP_script_scale( TRUE, &level,
1071 &old_sscale, &sscale, &old_soffset, &soffset );
1072 scale = sscale;
1073 // The correction for the difference in magnitude
1074 // between the baseline and middle coordinate systems
1075 // for superscripts should be
1076 // 0.5*(base font size - superscript/subscript font size).
1077 dup = 0.5 * ( 1.0 - sscale );
1078 up = font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + dup );
1079 break;
1080
1081 // ignore the next sequences
1082
1083 case '+':
1084 case '-':
1085 case 'b':
1086 case 'B':
1087 plwarn( "'+', '-', and 'b/B' text escape sequences not processed." );
1088 break;
1089 }
1090 }
1091
1092 // copy from current to next token, adding a postscript escape
1093 // char '\' if necessary
1094 //
1095 while ( *cur_strp && *cur_strp != esc )
1096 {
1097 *strp++ = *cur_strp++;
1098 }
1099 *strp = '\0';
1100
1101 // if(fabs(up)<0.001) up = 0.; /* Watch out for small differences */
1102
1103 // Set the font size
1104 doc->setFont( font, style, weight );
1105 doc->setFontSize( font_factor * ENLARGE * ft_ht * scale );
1106 doc->get_dimensions( (const char *) str, &lineSpacing, &xAdvance, &ymintmp, &ymaxtmp );
1107 xmax += xAdvance;
1108 } while ( *cur_strp );
1109
1110 // Use the length of the string to calculate offset
1111 // Also used later for bounding box
1112 xmin = -xmax * args->just;
1113 xmax = xmin;
1114 ymin = 0;
1115 ymax = 0;
1116
1117 // Reset parameters
1118 level = 0;
1119 scale = 1.0;
1120 up = 0.0;
1121
1122 // Move relative to position to account for justification
1123 doc->osBody() << " gsave " << TRMFLT( xmin * tt[0] ) << " " <<
1124 TRMFLT( xmin * tt[2] ) << " rmoveto\n";
1125
1126 // Parse string for PLplot escape sequences and print everything out
1127
1128 cur_strp = cur_str;
1129 f = 0;
1130 do
1131 {
1132 strp = str;
1133
1134 if ( *cur_strp == esc )
1135 {
1136 cur_strp++;
1137
1138 if ( *cur_strp == esc ) // <esc><esc>
1139 {
1140 *strp++ = *cur_strp++;
1141 }
1142 else if ( *cur_strp == 'f' )
1143 {
1144 cur_strp++;
1145 if ( *cur_strp++ != 'f' )
1146 {
1147 // escff occurs because of logic above. But any suffix
1148 // other than "f" should never happen.
1149 plabort( "proc_str, internal PLplot logic error;"
1150 "wrong escf escape sequence" );
1151 return;
1152 }
1153 font = fonts[f];
1154 style = styles[f];
1155 weight = weights[f];
1156 f++;
1157 //pldebug("proc_str", "string-specified fci = 0x%x, font name = %s\n", fci, font);
1158 continue;
1159 }
1160 else
1161 switch ( *cur_strp++ )
1162 {
1163 case 'd': //subscript
1164 case 'D':
1165 plP_script_scale( FALSE, &level,
1166 &old_sscale, &sscale, &old_soffset, &soffset );
1167 scale = sscale;
1168 // The correction for the difference in magnitude
1169 // between the baseline and middle coordinate systems
1170 // for subscripts should be
1171 // -0.5*(base font size - superscript/subscript font size).
1172 dup = -0.5 * ( 1.0 - sscale );
1173 up = -font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + dup );
1174 break;
1175
1176 case 'u': //superscript
1177 case 'U':
1178 plP_script_scale( TRUE, &level,
1179 &old_sscale, &sscale, &old_soffset, &soffset );
1180 scale = sscale;
1181 // The correction for the difference in magnitude
1182 // between the baseline and middle coordinate systems
1183 // for superscripts should be
1184 // 0.5*(base font size - superscript/subscript font size).
1185 dup = 0.5 * ( 1.0 - sscale );
1186 up = font_factor * ENLARGE * ft_ht * ( RISE_FACTOR * soffset + dup );
1187 break;
1188
1189 // ignore the next sequences
1190
1191 case '+':
1192 case '-':
1193 case 'b':
1194 case 'B':
1195 plwarn( "'+', '-', and 'b/B' text escape sequences not processed." );
1196 break;
1197 }
1198 }
1199
1200 // copy from current to next token, adding a postscript escape
1201 // char '\' if necessary
1202 //
1203 while ( *cur_strp && *cur_strp != esc )
1204 {
1205 *strp++ = *cur_strp++;
1206 }
1207 *strp = '\0';
1208
1209 // if(fabs(up)<0.001) up = 0.; /* Watch out for small differences */
1210
1211 // Set the font size
1212 doc->setFont( font, style, weight );
1213 doc->setFontSize( font_factor * ENLARGE * ft_ht * scale );
1214 doc->get_dimensions( (const char *) str, &lineSpacing, &xAdvance, &ymintmp, &ymaxtmp );
1215 ymin = MIN( ymintmp + up, ymin );
1216 ymax = MAX( ymaxtmp + up, ymax );
1217 xmax += xAdvance;
1218
1219 // if up/down escape sequences, save current point and adjust baseline;
1220 // take the shear into account
1221 if ( up != 0. )
1222 doc->osBody() << "gsave " << TRMFLT( up * tt[1] ) << " " << TRMFLT( up * tt[3] ) << " rmoveto\n";
1223
1224 // print the string
1225 doc->osBody() << show( (const char *) str );
1226
1227 // back to baseline
1228 if ( up != 0. )
1229 doc->osBody() << "grestore " << TRMFLT( xAdvance * tt[0] ) << " " << TRMFLT( xAdvance * tt[2] ) << " rmoveto\n";
1230 } while ( *cur_strp );
1231
1232 doc->osBody() << "grestore\n";
1233 doc->osBody() << "grestore\n";
1234 doc->osBody() << "grestore\n";
1235
1236 //
1237 // Estimate text bounding box from LASi get_dimensions function.
1238 // xmin, xmax are text left and right extents,
1239 // ymin, ymax are top and bottom extents.
1240 // These need to be rotated / transformed to get the correct values
1241 //
1242 xx[0] = (PLINT) ( t[0] * xmin + t[1] * ymin );
1243 yy[0] = (PLINT) ( t[2] * xmin + t[3] * ymin );
1244 xx[1] = (PLINT) ( t[0] * xmin + t[1] * ymax );
1245 yy[1] = (PLINT) ( t[2] * xmin + t[3] * ymax );
1246 xx[2] = (PLINT) ( t[0] * xmax + t[1] * ymin );
1247 yy[2] = (PLINT) ( t[2] * xmax + t[3] * ymin );
1248 xx[3] = (PLINT) ( t[0] * xmax + t[1] * ymax );
1249 yy[3] = (PLINT) ( t[2] * xmax + t[3] * ymax );
1250
1251 plRotPhy( ORIENTATION, 0, 0, 0, 0, &xx[0], &yy[0] );
1252 plRotPhy( ORIENTATION, 0, 0, 0, 0, &xx[1], &yy[1] );
1253 plRotPhy( ORIENTATION, 0, 0, 0, 0, &xx[2], &yy[2] );
1254 plRotPhy( ORIENTATION, 0, 0, 0, 0, &xx[3], &yy[3] );
1255
1256
1257 xmin = MIN( MIN( MIN( xx[0], xx[1] ), xx[2] ), xx[3] ) + args->x;
1258 xmax = MAX( MAX( MAX( xx[0], xx[1] ), xx[2] ), xx[3] ) + args->x;
1259 ymin = MIN( MIN( MIN( yy[0], yy[1] ), yy[2] ), yy[3] ) + args->y;
1260 ymax = MAX( MAX( MAX( yy[0], yy[1] ), yy[2] ), yy[3] ) + args->y;
1261
1262 dev->llx = (int) ( MIN( dev->llx, xmin ) );
1263 dev->lly = (int) ( MIN( dev->lly, ymin ) );
1264 dev->urx = (int) ( MAX( dev->urx, xmax ) );
1265 dev->ury = (int) ( MAX( dev->ury, ymax ) );
1266 // doc->osBody() << "Z " << xmin << " " << ymin << " M "
1267 // << xmin << " " << ymax << " D "
1268 // << xmax << " " << ymax << " D "
1269 // << xmax << " " << ymin << " D "
1270 // << xmin << " " << ymin << " closepath\n"
1271 // << "Z " << args->x << " " << args->y << " A closepath\n";
1272 }
1273 }
1274
1275 //static void
1276 //esc_purge( char *dstr, char *sstr )
1277 //{
1278 // char esc;
1279 //
1280 // plgesc( &esc );
1281 //
1282 // while ( *sstr )
1283 // {
1284 // if ( *sstr != esc )
1285 // {
1286 // *dstr++ = *sstr++;
1287 // continue;
1288 // }
1289 //
1290 // sstr++;
1291 // if ( *sstr == esc )
1292 // {
1293 // *dstr++ = *sstr++;
1294 // continue;
1295 // }
1296 //
1297 // else
1298 // {
1299 // switch ( *sstr++ )
1300 // {
1301 // case 'f':
1302 // sstr++;
1303 // break; // two chars sequence
1304 //
1305 // default:
1306 // break; // single char escape
1307 // }
1308 // }
1309 // }
1310 // *dstr = '\0';
1311 //}
1312
1313 #else
1314 int
1315 pldummy_psttf()
1316 {
1317 return 0;
1318 }
1319
1320 #endif // defined(PLD_psttf) || ....