1 /* Copyright (c) 1991 - 1994 Heinz W. Werntges.  All rights reserved.
2    Parts Copyright (c) 1999 - 2001 Martin Kroeker All rights reserved.
3 
4    Distributed by Free Software Foundation, Inc.
5 
6    This file is part of HP2xx.
7 
8    HP2xx is distributed in the hope that it will be useful, but
9    WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
10    to anyone for the consequences of using it or for whether it serves any
11    particular purpose or works at all, unless he says so in writing.  Refer
12    to the GNU General Public License, Version 2 or later, for full details.
13 
14    Everyone is granted permission to copy, modify and redistribute
15    HP2xx, but only under the conditions described in the GNU General Public
16    License.  A copy of this license is supposed to have been
17    given to you along with HP2xx so you can know your rights and
18    responsibilities.  It should be in a file named COPYING.  Among other
19    things, the copyright notice and this notice must be preserved on all
20    copies.
21 
22    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
23  */
24 
25 /** HPGL.c: HPGL parser & i/o part of HP2xx (based on D. Donath's "HPtoGF.c")
26  **
27  ** 91/01/13  V 1.00  HWW  Originating
28  ** 91/01/19  V 1.01  HWW  reorganized
29  ** 91/01/24  V 1.02  HWW  ESC.-Sequences acknowledged (preliminary!!)
30  ** 91/01/29  V 1.03  HWW  Incl. SUN portation
31  ** 91/01/31  V 1.04  HWW  Parser: ESC sequences should be skipped now
32  ** 91/02/10  V 1.05  HWW  Parser renewed
33  ** 91/02/15  V 1.06  HWW  stdlib.h supported
34  ** 91/02/19  V 1.07a HWW  parser refined, bugs fixed
35  ** 91/06/09  V 1.08  HWW  New options added; some restructuring
36  ** 91/06/16  V 1.09  HWW  VGA mode added; some renaming; silent_mode!
37  ** 91/06/20  V 1.10  HWW  Rotation added
38  ** 91/10/15  V 1.11  HWW  ANSI_C; header files reorganized
39  ** 91/10/20  V 1.11a HWW  VAX_C support
40  ** 91/10/25  V 1.11b HWW  Support of LT; and LT0; (line type, partial)
41  ** 91/11/20  V 1.12  HWW  SPn; support: many changes!
42  ** 91/11/21  V 1.12b HWW  First comma in "PA,xxxx,yyyy..." accepted
43  ** 91/12/22  V 1.13  HWW  Multiple MOVE compression; "plot_rel", "old_pen"
44  ** 92/01/13  V 1.13c HWW  VAX problem with ungetc()/fscanf() fixed; bug fixed
45  ** 92/01/15  V 1.13d HWW  "vga" --> "pre"
46  ** 92/01/30  V 1.14c HWW  Parser: no need of ';', better portable
47  ** 92/02/06  V 1.15a HWW  Parser: AR, AA, CI, read_float() added;
48  **			   toupper() removed (MACH problems)
49  ** 92/02/19  V 1.16c HWW  LB etc. supported
50  ** 92/02/23  V 1.17b HWW  LB etc. improved, PG supported
51  ** 92/02/25  V 1.17c HWW  Parser improved: SP, LT, multi-mv suppression
52  ** 92/03/01  V 1.17d HWW  Char sizes: debugged
53  ** 92/03/03  V 1.17e HWW  LB_Mode introduced
54  ** 92/04/15  V 1.17f HWW  Width x Height limit assumed
55  ** 92/05/21  V 1.18a HWW  Multiple-file usage
56  ** 92/05/28  V 1.19a HWW  XT, YT, TL, SM added
57  ** 92/10/20  V 1.20c HWW  More line types added (debugged)
58  ** 92/11/08  V 1.20d HWW  Interval of active pages
59  ** 92/12/13  V 1.20e HWW  truesize option added
60  ** 93/02/10  V 1.21a HWW  Arcs & circles now properly closed;
61  **			   Bug fixed: SC does not interfere with last move
62  ** 93/03/10  V 1.21b HWW  Bug fixed in LT scanner part
63  ** 93/03/22, V 1.21c HWW  HYPOT() workaround for a weird BCC behavior;
64  ** 93/04/02		   Line_Generator(): Case *pb==*pa caught
65  ** 93/04/13  V 1.22a HWW  UC supported (code by Alois Treindl)
66  ** 93/04/25  V 1.22b HWW  LB/PR bug fix by E. Norum included
67  ** 93/05/20  V 1.22c HWW  LT1 pattern adjustment (report by E. Frambach)
68  ** 93/09/02  V 1.22d HWW  EA (rect) added (by Th. Hiller)
69  ** 94/01/01  V 1.22e HWW  Misc. additions suggested by L. Lowe:
70  **			    1) PlotCmd_from_tmpfile(): int --> PlotCmd
71  **                         2) ES: 2nd parameter now optional
72  **                         3) evaluate_HPGL(): center_mode introduced
73  ** 94/02/14  V 1.30a HWW  Re-organized; many changes; min/max bug fixed
74  ** 99/02/28          MK   IW,CA,CS,SA,SS commands added
75  ** 99/04/24          MK   PC,PW commands added
76  ** 99/05/10          MK   RO command added (code by rs@daveg.com)
77  ** 99/05/18          MK   partial PE support (by Eugene Doudine)
78  ** 99/06/05          MK   PC improvements and fixes
79  ** 99/11/30          MK   support for fractional PE; PS/RO fixes
80  ** 00/02/06          MK   allow commandline overrides for PC/PW
81  ** 00/02/13          MK   DV support (backport from delayed 3.4.prealpha)
82  ** 00/02/26          MK   ER,EP,FP,FT,PM,PT,RA,RR,WG commands added
83  ** 00/02/27          MK   WU command added
84  ** 00/03/02          MK   SC types 1 and 2, more robust handling of PE,
85  **                        removed PE_line(), split lines() into file reader
86  **                        and common linedrawing backend for PD/PA and PE
87  **                        added PJL parser and RTL escape sequences
88  **                        (all these patches provided by Eugene Doudine)
89  ** 00/03/03          MK   convert IW parameters if scaling is in effect
90  ** 00/03/05          MK   AT/RT (arc through three points) added
91  ** 01/01/01	      MK   UL added and PW rewritten (Andrew J.Bird)
92  ** 		           empty PUPD sequence now draws a small dot
93  **			   linedrawing fixed (added two moves when IW was
94  **	 		   in effect, ever since IW support was added)
95  ** 01/04/01	      MK   BR/BZ added
96  ** 01/04/22	      MK   reset PW and RO flags/values on reinitialization
97  **			   (Yuri Strelenko)
98  ** 01/12/04	      MK   moved reinitialization of n_unknown and n_unexpected
99  **			   from reset_HPGL to init_HPGL so that they are not overwritten
100  **			   when a single drawing contains several IN statements
101  ** 02/06/02	      AJB  Moved HYPOT macro to hpgl.h - so we can use it in murphy.c
102  **/
103 
104 #include <stdio.h>
105 #include <stdlib.h>
106 
107 #ifndef _NO_VCL
108 #include <unistd.h>
109 #endif
110 
111 #include <string.h>
112 #include <ctype.h>
113 #include <math.h>
114 #include "bresnham.h"
115 #include "hp2xx.h"
116 #include "chardraw.h"
117 #include "clip.h"
118 #include "pendef.h"
119 #include "lindef.h"
120 #include "hpgl.h"
121 
122 #define	ETX		'\003'
123 
124 /*
125 #define P1X_default	603.0
126 #define P1Y_default	521.0
127 #define P2X_default	10603.0
128 #define P2Y_default	7721.0
129 */
130 #define P1X_default	0.0	/* drop margins       */
131 #define P1Y_default	0.0
132 /*
133 #define P2X_default   11880.
134 #define P2Y_default   16800.
135 */
136 #define P2X_default   33600.	/* A0 media */
137 #define P2Y_default   47520.
138 
139 
140 #ifdef NORINT
141 #define rint(a) (long)(a+0.5)
142 #endif
143 
144 /**
145  ** Globals needed in other source files:
146  **/
147 LineType CurrentLineType = LT_solid;
148 short scale_flag = FALSE;
149 short record_off = FALSE;
150 long vec_cntr_w = 0L;
151 long n_commands = 0L;
152 short silent_mode = FALSE;
153 FILE *td;
154 
155 HPGL_Pt HP_pos = { 0, 0 };	/* Actual plotter pen position  */
156 HPGL_Pt P1 = { P1X_default, P1Y_default };	/* Scaling points */
157 HPGL_Pt P2 = { P2X_default, P2Y_default };
158 int iwflag = 0;			/*MK */
159 int mode_vert = 0;
160 HPGL_Pt C1 = { P1X_default, P1Y_default };	/* Clipping points        */
161 HPGL_Pt C2 = { P2X_default, P2Y_default };
162 HPGL_Pt S1 = { P1X_default, P1Y_default };	/* Scaled       */
163 HPGL_Pt S2 = { P2X_default, P2Y_default };	/* points       */
164 HPGL_Pt Q = { 1., 1. };		/* Delta-P/Delta-S: Initialized with first SC   */
165 HPGL_Pt M;			/* maximum coordinates set by PS instruction */
166 /**
167  ** Global from chardraw.c:
168  **/
169 extern TextPar tp;
170 
171 /**
172  ** "Local" globals (I know this is messy...) :
173  **/
174 static float xmin, xmax, ymin, ymax, neg_ticklen, pos_ticklen;
175 static double Diag_P1_P2, pat_pos;
176 static HPGL_Pt p_last = { M_PI, M_PI };	/* Init. to "impossible" values */
177 
178 static HPGL_Pt polygons[MAXPOLY];
179 static int vertices = -1;
180 static short polygon_mode = FALSE;
181 static int filltype = 1;
182 static float hatchspace = 0.;
183 static float hatchangle = 0.;
184 static float saved_hatchspace[2] = { 0., 0. };
185 static float saved_hatchangle[2] = { 0., 0. };
186 static float thickness = 0.;
187 static short polygon_penup = FALSE;
188 static HPGL_Pt anchor = { 100000.0, 100000.0 };
189 static HPGL_Pt polystart = { 0.0, 0.0 };
190 static float rot_cos, rot_sin;
191 
192 static short rotate_flag = FALSE;	/* Flags tec external to HP-GL  */
193 static short ps_flag = FALSE;
194 static short ac_flag = FALSE;
195 static double rot_ang = 0.;
196 static double rot_tmp = 0.;	/* saved RO value for resetting after drawing */
197 static short mv_flag = FALSE;
198 static short pg_flag = FALSE;
199 static short ct_dist = FALSE;
200 static short fixedcolor = FALSE;
201 static short fixedwidth = FALSE;
202 static int first_page = 0;
203 static int last_page = 0;
204 static int n_unexpected = 0;
205 static int n_unknown = 0;
206 static int page_number = 1;
207 static long vec_cntr_r = 0L;
208 static short pen = -1;
209 static short pens_in_use[NUMPENS];
210 static short pen_down = FALSE;	/* Internal HP-GL book-keeping: */
211 static short plot_rel = FALSE;
212 static short saved_penstate = FALSE;	/* to track penstate over polygon mode */
213 static short wu_relative = FALSE;
214 static int again = FALSE;
215 static char StrTerm = ETX;	/* String terminator char       */
216 static short StrTermSilent = 1;	/* only terminates, or prints too */
217 static char *strbuf = NULL;
218 static unsigned int strbufsize = MAX_LB_LEN + 1;
219 static char symbol_char = '\0';	/* Char in Symbol Mode (0=off)  */
220 static unsigned char r_base = 0;
221 static unsigned char g_base = 0;
222 static unsigned char b_base = 0;
223 static unsigned char r_max = 255;
224 static unsigned char g_max = 255;
225 static unsigned char b_max = 255;
226 
227 /* Known HPGL commands, ASCII-coded as High-byte/low-byte int's */
228 
229 #define AA	0x4141
230 #define AC	0x4143
231 #define AD      0x4144
232 #define AF	0x4146
233 #define AH	0x4148
234 #define AR	0x4152
235 #define AT      0x4154
236 #define BL	0x424C
237 #define BP      0x4250
238 #define BR      0x4252
239 #define BZ      0x425A
240 #define CA      0x4341		/*MK */
241 #define CI	0x4349
242 #define CO	0x434F /*AJB*/
243 #define CP	0x4350
244 #define CR	0x4352
245 #define CS      0x4353		/*MK */
246 #define CT	0x4354
247 #define DF	0x4446
248 #define DI	0x4449
249 #define DR	0x4452
250 #define DT	0x4454
251 #define DV      0x4456
252 #define EA	0x4541
253 #define EC	0x4543 /*AJB*/
254 #define EP      0x4550
255 #define ER      0x4552
256 #define ES	0x4553
257 #define EW      0x4557		/*MK */
258 #define FP      0x4650
259 #define FT      0x4654
260 #define IN	0x494E
261 #define IP	0x4950
262 #define IR	0x4952
263 #define IW      0x4957		/*MK */
264 #define LA	0x4C41 /*AJB*/
265 #define LB	0x4C42
266 #define LO	0x4C4F
267 #define LT	0x4C54
268 #define MG      0x4D47
269 #define NP      0x4E50
270 #define NR      0x4E52
271 #define OP	0x4F50
272 #define OW	0x4F57
273 #define PA	0x5041
274 #define PB	0x5042
275 #define PC      0x5043		/*MK */
276 #define PD	0x5044
277 #define PE      0x5045
278 #define PG	0x5047
279 #define PM      0x504D
280 #define PR	0x5052
281 #define PS      0x5053
282 #define PT      0x5054
283 #define PU	0x5055
284 #define PW	0x5057		/*MK */
285 #define RA      0x5241
286 #define RO	0x524F		/*RS */
287 #define RR      0x5252
288 #define RT      0x5254
289 #define SA      0x5341		/*MK */
290 #define SC	0x5343
291 #define SD      0x5344
292 #define SI	0x5349
293 #define SL	0x534C
294 #define SM	0x534D
295 #define SP	0x5350
296 #define SR	0x5352
297 #define SS      0x5353		/*MK */
298 #define TL	0x544C
299 #define UC	0x5543
300 #define UL	0x554C /*AJB*/
301 #define VS	0x5653
302 #define WD	0x5744
303 #define WG      0x5747
304 #define WU      0x5755
305 #define XT	0x5854
306 #define YT	0x5954
par_err_exit(int code,int cmd,FILE * hd)307 static void par_err_exit(int code, int cmd, FILE * hd)
308 {
309 
310 	const char *msg;
311 	char tmpstr[21];
312 
313 	switch (code) {
314 	case 0:
315 		msg = "Illegal parameters";
316 		break;
317 	case 1:
318 		msg = "Error in first parameter";
319 		break;
320 	case 2:
321 		msg = "No second parameter";
322 		break;
323 	case 3:
324 		msg = "No third parameter";
325 		break;
326 	case 4:
327 		msg = "No fourth parameter";
328 		break;
329 	case 98:
330 		msg = "sscanf error: corrupted file?";
331 		break;
332 	case 99:
333 	default:
334 		msg = "Internal error";
335 		break;
336 	}
337 	Eprintf("\nError in command %c%c: %s\n", cmd >> 8, cmd & 0xFF,
338 		msg);
339 	Eprintf(" @ Cmd %ld\n", vec_cntr_w);
340 	fseek(hd, -10L, SEEK_CUR);
341 	read_string(tmpstr, hd);
342 	tmpstr[20] = '\0';
343 	Eprintf(" lately read: %s\n", tmpstr);
344 	exit(ERROR);
345 }
346 
347 
348 
349 
reset_HPGL(void)350 static void reset_HPGL(void)
351 {
352 	int i;
353 
354 	p_last.x = p_last.y = M_PI;
355 	pen_down = FALSE;
356 	plot_rel = FALSE;
357 	pen = -1;
358 /*  n_unexpected = 0;
359   n_unknown = 0;*/
360 	mv_flag = FALSE;
361 	wu_relative = FALSE;
362 	pg_flag = FALSE;
363 	iwflag = FALSE;
364 	ps_flag = FALSE;
365 	ac_flag = FALSE;
366 	filltype = 1;
367 	saved_hatchangle[0] = saved_hatchangle[1] = 0.;
368 	saved_hatchspace[0] = saved_hatchspace[1] = 0.;
369 	ct_dist = FALSE;
370 	CurrentLineType = LT_solid;
371 
372 	set_line_style_defaults();
373 /*  set_line_attr_defaults();*/
374 	CurrentLineAttr.Join = LAJ_plain_miter;
375 	CurrentLineAttr.End = LAE_butt;
376 	CurrentLineAttr.Limit = 5;
377 	tp->sstrokewidth = tp->astrokewidth = tp->strokewidth = 0.11;
378 	StrTerm = ETX;
379 	StrTermSilent = 1;
380 	if (strbuf == NULL) {
381 		strbuf = malloc(strbufsize);
382 		if (strbuf == NULL) {
383 			fprintf(stderr, "\nNo memory !\n");
384 			exit(ERROR);
385 		}
386 	}
387 	strbuf[0] = '\0';
388 
389 	P1.x = P1X_default;
390 	P1.y = P1Y_default;
391 
392 	Diag_P1_P2 = /*@-unrecog@ */ HYPOT(P2.x - P1.x, P2.y - P1.y);
393 	CurrentLinePatLen = 0.04 * Diag_P1_P2;
394 	pat_pos = 0.0;
395 	scale_flag = FALSE;
396 	S1 = P1;
397 	S2 = P2;
398 	Q.x = Q.y = 1.0;
399 	HP_pos.x = HP_pos.y = 0.0;
400 	neg_ticklen = 0.005;	/* 0.5 %        */
401 	pos_ticklen = 0.005;
402 	symbol_char = '\0';
403 	rot_ang -= rot_tmp;
404 	rot_tmp = 0.;
405 	if (rot_ang == 0.)
406 		rotate_flag = FALSE;
407 	if (rotate_flag) {
408 		rot_cos = cos(M_PI * rot_ang / 180.0);
409 		rot_sin = sin(M_PI * rot_ang / 180.0);
410 	}
411 	init_text_par();
412 	if (fixedcolor == FALSE) {
413 		set_color_rgb(xxBackground, 255, 255, 255);
414 		set_color_rgb(xxForeground, 0, 0, 0);
415 		set_color_rgb(xxRed, 255, 0, 0);
416 		set_color_rgb(xxGreen, 0, 255, 0);
417 		set_color_rgb(xxBlue, 0, 0, 255);
418 		set_color_rgb(xxCyan, 0, 255, 255);
419 		set_color_rgb(xxMagenta, 255, 0, 255);
420 		set_color_rgb(xxYellow, 255, 255, 0);
421 		pt.color[0] = xxBackground;
422 		pt.color[1] = xxForeground;
423 		pt.color[2] = xxRed;
424 		pt.color[3] = xxGreen;
425 		pt.color[4] = xxBlue;
426 		pt.color[5] = xxCyan;
427 		pt.color[6] = xxMagenta;
428 		pt.color[7] = xxYellow;
429 	}
430 	if (fixedwidth == FALSE)
431 		for (i = 0; i < 8; i++)
432 			pt.width[i] = 0.1;
433 	record_off = (first_page > page_number)
434 	    || ((last_page < page_number) && (last_page > 0));
435 }
436 
init_HPGL(GEN_PAR * pg,const IN_PAR * pi)437 static void init_HPGL(GEN_PAR * pg, const IN_PAR * pi)
438 {
439 /**
440  ** Re-init. global var's for multiple-file applications
441  **/
442 /*fprintf(stderr,"init_HPGL\n");*/
443 	td = pg->td;
444 	silent_mode = (short) pg->quiet;
445 	xmin = pi->x0;
446 	ymin = pi->y0;
447 	xmax = pi->x1;
448 	ymax = pi->y1;
449 	fixedcolor = (short) pi->hwcolor;
450 	fixedwidth = (short) pi->hwsize;
451 	r_base = g_base = b_base = 0;
452 	r_max = g_max = b_max = 255;
453 
454 /*  pens_in_use = 0; */
455 	pg->maxpens = 8;
456 	pg->maxcolor = 1;
457 	memset(pens_in_use, 0, NUMPENS * sizeof(short));
458   /**
459    ** Record ON if no page selected (pg->page == 0)!
460    **/
461 	first_page = pi->first_page;	/* May be 0     */
462 	last_page = pi->last_page;	/* May be 0     */
463 	record_off = (first_page > page_number)
464 	    || ((last_page < page_number) && (last_page > 0));
465 
466 	rot_ang = pi->rotation;
467 	rotate_flag = (rot_ang != 0.0) ? TRUE : FALSE;
468 	if (rotate_flag) {
469 		rot_cos = cos(M_PI * rot_ang / 180.0);
470 		rot_sin = sin(M_PI * rot_ang / 180.0);
471 	}
472 	vec_cntr_r = 0L;
473 	vec_cntr_w = 0L;
474 	n_unexpected = 0;
475 	n_commands = 0;
476 	n_unknown = 0;
477 
478 	if (pi->hwlimit.x > 0.)
479 		P2.x = S2.x = pi->hwlimit.x;
480 	if (pi->hwlimit.y > 0.)
481 		P2.y = S2.y = pi->hwlimit.y;
482 
483 	reset_HPGL();
484 }
485 
486 
487 
User_to_Plotter_coord(const HPGL_Pt * p_usr,HPGL_Pt * p_plot)488 static void User_to_Plotter_coord(const HPGL_Pt * p_usr, HPGL_Pt * p_plot)
489 /**
490  ** 	Utility: Transformation from (scaled) user coordinates
491  **	to plotter coordinates
492  **/
493 {
494 	p_plot->x = P1.x + (p_usr->x - S1.x) * Q.x;
495 	p_plot->y = P1.y + (p_usr->y - S1.y) * Q.y;
496 }
497 
498 
499 
Plotter_to_User_coord(const HPGL_Pt * p_plot,HPGL_Pt * p_usr)500 static void Plotter_to_User_coord(const HPGL_Pt * p_plot, HPGL_Pt * p_usr)
501 /**
502  ** 	Utility: Transformation from plotter coordinates
503  **	to (scaled) user coordinates
504  **/
505 {
506 	p_usr->x = S1.x + (p_plot->x - P1.x) / Q.x;
507 	p_usr->y = S1.y + (p_plot->y - P1.y) / Q.y;
508 }
509 
510 
511 
PlotCmd_to_tmpfile(PlotCmd cmd)512 void PlotCmd_to_tmpfile(PlotCmd cmd)
513 {
514 	if (record_off)		/* Wrong page!  */
515 		return;
516 
517 	if (!silent_mode)
518 		switch (vec_cntr_w++) {
519 		case 0:
520 			Eprintf("Writing Cmd: ");
521 			break;
522 		case 1:
523 			Eprintf("1 ");
524 			break;
525 		case 2:
526 			Eprintf("2 ");
527 			break;
528 		case 5:
529 			Eprintf("5 ");
530 			break;
531 		case 10:
532 			Eprintf("10 ");
533 			break;
534 		case 20:
535 			Eprintf("20 ");
536 			break;
537 		case 50:
538 			Eprintf("50 ");
539 			break;
540 		case 100:
541 			Eprintf("100 ");
542 			break;
543 		case 200:
544 			Eprintf("200 ");
545 			break;
546 		case 500:
547 			Eprintf("500 ");
548 			break;
549 		case 1000:
550 			Eprintf("1k ");
551 			break;
552 		case 2000:
553 			Eprintf("2k ");
554 			break;
555 		case 5000:
556 			Eprintf("5k ");
557 			break;
558 		case 10000:
559 			Eprintf("10k ");
560 			break;
561 		case 20000:
562 			Eprintf("20k ");
563 			break;
564 		case 50000L:
565 			Eprintf("50k ");
566 			break;
567 		case 100000L:
568 			Eprintf("100k ");
569 			break;
570 		case 200000L:
571 			Eprintf("200k ");
572 			break;
573 		case 500000L:
574 			Eprintf("500k ");
575 			break;
576 		case 1000000L:
577 			Eprintf("1000k ");
578 			break;
579 		case 2000000L:
580 			Eprintf("2000k ");
581 			break;
582 		case 3000000L:
583 			Eprintf("3000k ");
584 			break;
585 		case 4000000L:
586 			Eprintf("4000k ");
587 			break;
588 		case 5000000L:
589 			Eprintf("5000k... ");
590 			break;
591 		case 10000000L:
592 			Eprintf("10000k ");
593 			break;
594 		}
595 
596 	if (fputc((int) cmd, td) == EOF) {
597 		PError("PlotCmd_to_tmpfile");
598 		Eprintf("Error @ Cmd %ld\n", vec_cntr_w);
599 		exit(ERROR);
600 	}
601 }
602 
603 
604 
605 
HPGL_Pt_to_tmpfile(const HPGL_Pt * pf)606 void HPGL_Pt_to_tmpfile(const HPGL_Pt * pf)
607 {
608 	if (record_off)		/* Wrong page!  */
609 		return;
610 
611 	if (fwrite((VOID *) pf, sizeof(*pf), 1, td) != 1) {
612 		PError("HPGL_Pt_to_tmpfile");
613 		Eprintf("Error @ Cmd %ld\n", vec_cntr_w);
614 		exit(ERROR);
615 	}
616 	xmin = MIN(pf->x, xmin);
617 	ymin = MIN(pf->y, ymin);
618 	xmax = MAX(pf->x, xmax);
619 	ymax = MAX(pf->y, ymax);
620 }
621 
622 
HPGL_Pt_to_polygon(HPGL_Pt pf)623 void HPGL_Pt_to_polygon(HPGL_Pt pf)
624 {
625 	if (record_off)		/* Wrong page!  */
626 		return;
627 
628 	polygons[++vertices] = pf;
629 	if (rotate_flag) {
630 		double tmp = rot_cos * pf.x - rot_sin * pf.y;
631 		pf.y = rot_sin * pf.x + rot_cos * pf.y;
632 		pf.x = tmp;
633 	}
634 	xmin = MIN(pf.x, xmin);
635 	ymin = MIN(pf.y, ymin);
636 	xmax = MAX(pf.x, xmax);
637 	ymax = MAX(pf.y, ymax);
638 }
639 
640 
641 
642 
643 /**
644  **	Low-level vector generation & file I/O
645  **/
646 
647 static void
LPattern_Generator(HPGL_Pt * pa,double dx,double dy,double start_of_pat,double end_of_pat)648 LPattern_Generator(HPGL_Pt * pa,
649 		   double dx, double dy,
650 		   double start_of_pat, double end_of_pat)
651 /**
652  **	Generator of Line type patterns:
653  **
654  **	pa:		Start point (ptr) of current line segment
655  **	dx, dy:		Components of c * (*pb - *pa), c holding
656  **				dx^2 + dy^2 = pattern_length^2
657  **	start_of_pat:	Fraction of start point within pattern
658  **	end_of_pat:	Fraction of end   point within pattern
659  **			Valid: 0 <= start_of_pat <= end_of_pat <= 1
660  **
661  **	A pattern consists of alternating "line"/"point" and "gap" elements,
662  **	always starting with a line/point. A point is a line of zero length.
663  **	The table below contains the relative lengths of the elements
664  **	of all line types except LT0; and LT; (7), which are treated separately.
665  **	These lengths always add up to 1. A negative value terminates a pattern.
666  **/
667 {
668 	double length_of_ele, start_of_action, end_of_action;
669 	static double *p_cur_pat;
670 
671 	p_cur_pat = lt[(LT_MIN * -1) + (int) CurrentLinePattern];	/* was CurrentLineType */
672 
673 	if (CurrentLineType == LT_adaptive)
674 		for (;;) {
675 			length_of_ele = (double) *p_cur_pat++ / 100;	/* Line or point        */
676 			if (length_of_ele < 0.)
677 				return;
678 			if (length_of_ele < 1.e-5)
679 				PlotCmd_to_tmpfile(PLOT_AT);
680 			else
681 				PlotCmd_to_tmpfile(DRAW_TO);
682 
683 			pa->x += dx * length_of_ele;
684 			pa->y += dy * length_of_ele;
685 			HPGL_Pt_to_tmpfile(pa);
686 
687 			length_of_ele = (double) *p_cur_pat++ / 100;	/* Gap        */
688 			if (length_of_ele < 0.)
689 				return;
690 			pa->x += dx * length_of_ele;
691 			pa->y += dy * length_of_ele;
692 			PlotCmd_to_tmpfile(MOVE_TO);
693 			HPGL_Pt_to_tmpfile(pa);
694 	} else			/* LT_fixed */
695 		for (end_of_action = 0.0;;) {
696 	    /**
697 	     ** Line or point:
698 	     **/
699 			start_of_action = end_of_action;
700 			length_of_ele = (double) *p_cur_pat++ / 100;
701 			if (length_of_ele < 0.)
702 				return;
703 
704 			if (length_of_ele < 1.e-5) {	/* Dot Only */
705 				PlotCmd_to_tmpfile(PLOT_AT);
706 				HPGL_Pt_to_tmpfile(pa);
707 			} else {	/* Line Segment */
708 				end_of_action += length_of_ele;
709 
710 				if (end_of_action > start_of_pat) {	/* If anything to do:   */
711 					if (start_of_pat <= start_of_action) {	/* If start is valid    */
712 						if (end_of_action <= end_of_pat) {	/* Draw full element    */
713 							pa->x +=
714 							    dx *
715 							    length_of_ele;
716 							pa->y +=
717 							    dy *
718 							    length_of_ele;
719 							PlotCmd_to_tmpfile
720 							    (DRAW_TO);
721 							HPGL_Pt_to_tmpfile
722 							    (pa);
723 						} else
724 							/* End_of_action beyond End_of_pattern:   */
725 						{	/* --> Draw only first part of element: */
726 							pa->x +=
727 							    dx *
728 							    (end_of_pat -
729 							     start_of_action);
730 							pa->y +=
731 							    dy *
732 							    (end_of_pat -
733 							     start_of_action);
734 							PlotCmd_to_tmpfile
735 							    (DRAW_TO);
736 							HPGL_Pt_to_tmpfile
737 							    (pa);
738 							return;
739 						}
740 					} else
741 						/* Start_of_action before Start_of_pattern:       */
742 					{
743 						if (end_of_action <= end_of_pat) {	/* Draw remainder of element            */
744 							pa->x +=
745 							    dx *
746 							    (end_of_action
747 							     -
748 							     start_of_pat);
749 							pa->y +=
750 							    dy *
751 							    (end_of_action
752 							     -
753 							     start_of_pat);
754 							PlotCmd_to_tmpfile
755 							    (DRAW_TO);
756 							HPGL_Pt_to_tmpfile
757 							    (pa);
758 						} else
759 							/* End_of_action beyond End_of_pattern:   */
760 							/* Draw central part of element & leave   */
761 						{
762 							if (end_of_pat ==
763 							    start_of_pat)
764 								PlotCmd_to_tmpfile
765 								    (PLOT_AT);
766 							else
767 								PlotCmd_to_tmpfile
768 								    (DRAW_TO);
769 							pa->x +=
770 							    dx *
771 							    (end_of_pat -
772 							     start_of_pat);
773 							pa->y +=
774 							    dy *
775 							    (end_of_pat -
776 							     start_of_pat);
777 
778 							HPGL_Pt_to_tmpfile
779 							    (pa);
780 							return;
781 						}
782 					}
783 				}
784 			}
785 	    /**
786 	     ** Gap (analogous to line/point):
787 	     **/
788 			start_of_action = end_of_action;
789 			length_of_ele = (double) *p_cur_pat++ / 100;
790 			if (length_of_ele < 0)
791 				return;
792 			end_of_action += length_of_ele;
793 			if (end_of_action > start_of_pat) {	/* If anything to do:   */
794 				if (start_of_pat <= start_of_action) {	/* If start is valid    */
795 					if (end_of_action <= end_of_pat) {	/* Full gap             */
796 						pa->x +=
797 						    dx * length_of_ele;
798 						pa->y +=
799 						    dy * length_of_ele;
800 						PlotCmd_to_tmpfile
801 						    (MOVE_TO);
802 						HPGL_Pt_to_tmpfile(pa);
803 					} else
804 						/* End_of_action beyond End_of_pattern:   */
805 					{	/* --> Apply only first part of gap:    */
806 						pa->x +=
807 						    dx * (end_of_pat -
808 							  start_of_action);
809 						pa->y +=
810 						    dy * (end_of_pat -
811 							  start_of_action);
812 						PlotCmd_to_tmpfile
813 						    (MOVE_TO);
814 						HPGL_Pt_to_tmpfile(pa);
815 						return;
816 					}
817 				} else
818 					/* Start_of_action before Start_of_pattern:       */
819 				{
820 					if (end_of_action <= end_of_pat) {	/* Apply remainder of gap               */
821 						pa->x +=
822 						    dx * (end_of_action -
823 							  start_of_pat);
824 						pa->y +=
825 						    dy * (end_of_action -
826 							  start_of_pat);
827 						PlotCmd_to_tmpfile
828 						    (MOVE_TO);
829 						HPGL_Pt_to_tmpfile(pa);
830 					} else
831 						/* End_of_action beyond End_of_pattern:   */
832 						/* Apply central part of gap & leave      */
833 					{
834 						if (end_of_pat ==
835 						    start_of_pat)
836 							return;	/* A null move  */
837 						pa->x +=
838 						    dx * (end_of_pat -
839 							  start_of_pat);
840 						pa->y +=
841 						    dy * (end_of_pat -
842 							  start_of_pat);
843 						PlotCmd_to_tmpfile
844 						    (MOVE_TO);
845 						HPGL_Pt_to_tmpfile(pa);
846 						return;
847 					}
848 				}
849 			}
850 		}
851 }
852 
853 /**
854  ** Rectangles --  by Th. Hiller (hiller@tu-harburg.d400.de)
855  **/
856 
rect(int relative,int filled,float cur_pensize,HPGL_Pt p)857 static void rect(int relative, int filled, float cur_pensize, HPGL_Pt p)
858 {
859 	HPGL_Pt p1;
860 
861 	if (relative) {		/* Process coordinates */
862 		p.x += p_last.x;
863 		p.y += p_last.y;
864 	}
865 	if (!filled) {
866 		p1.x = p_last.x;
867 		p1.y = p.y;
868 		Pen_action_to_tmpfile(DRAW_TO, &p1, scale_flag);
869 		p1.x = p.x;
870 		p1.y = p.y;
871 		Pen_action_to_tmpfile(DRAW_TO, &p1, scale_flag);
872 		p1.x = p.x;
873 		p1.y = p_last.y;
874 		Pen_action_to_tmpfile(DRAW_TO, &p1, scale_flag);
875 		p1.x = p_last.x;
876 		p1.y = p_last.y;
877 		Pen_action_to_tmpfile(DRAW_TO, &p1, scale_flag);
878 	} else {
879 		vertices = -1;
880 		HPGL_Pt_to_polygon(p_last);
881 		p1.x = p_last.x;
882 		p1.y = p.y;
883 		HPGL_Pt_to_polygon(p1);
884 		HPGL_Pt_to_polygon(p1);
885 		HPGL_Pt_to_polygon(p);
886 		HPGL_Pt_to_polygon(p);
887 		p1.x = p.x;
888 		p1.y = p_last.y;
889 		HPGL_Pt_to_polygon(p1);
890 		HPGL_Pt_to_polygon(p1);
891 		HPGL_Pt_to_polygon(p_last);
892 		if (hatchspace == 0.)
893 			hatchspace = cur_pensize;
894 		if (filltype < 3 && thickness > 0.)
895 			hatchspace = thickness;
896 		if (ac_flag == 0) {	/* not yet initialized */
897 			anchor.x = P1.x;
898 			anchor.y = P1.y;
899 /*	fprintf(stderr,"anchor init to P1\n");*/
900 
901 			/*      anchor.y=MIN(P1.y,ymin); */
902 		}
903 		fill(polygons, vertices, anchor, P2, scale_flag,
904 		     filltype, hatchspace, hatchangle);
905 	}
906 	Pen_action_to_tmpfile(MOVE_TO, &p_last, scale_flag);
907 }
908 
rects(int relative,int filled,float cur_pensize,FILE * hd)909 static void rects(int relative, int filled, float cur_pensize, FILE * hd)
910 {
911 	HPGL_Pt p;
912 	for (;;) {
913 		if (read_float(&p.x, hd))	/* No number found */
914 			return;
915 
916 		if (read_float(&p.y, hd))	/* x without y invalid! */
917 			par_err_exit(2, EA, hd);
918 		rect(relative, filled, cur_pensize, p);
919 	}
920 }
921 
922 
923 /*
924    struct PE_flags{
925    int abs;
926    int up;
927    int sbmode;
928    int fract;
929    int pen;
930    } ;
931  */
read_PE_flags(GEN_PAR * pg,int c,FILE * hd,PE_flags * fl)932 int read_PE_flags(GEN_PAR * pg, int c, FILE * hd, PE_flags * fl)
933 {
934 	short old_pen;
935 	float ftmp;
936 	int ctmp;
937 	switch (c) {
938 	case 183:
939 	case '7':
940 		/* seven bit mode */
941 		fl->sbmode = 1;
942 		break;
943 
944 	case 185:
945 	case '9':
946 		/* rectangle mode */
947 		fl->rect = 1;
948 		fl->up = 1;
949 		break;
950 
951 	case 186:
952 	case ':':
953 		/* select pen */
954 		if (EOF == (fl->pen = getc(hd))) {
955 			par_err_exit(98, PE, hd);
956 		}
957 		old_pen = pen;
958 		read_PE_coord(fl->pen, hd, fl, &ftmp);
959 		pen = (short) ftmp;
960 		if (pen < 0 || (int) pen > pg->maxpens) {
961 			Eprintf
962 			    ("\nIllegal pen number %d: replaced by %d\n",
963 			     pen, pen % pg->maxpens);
964 			n_unexpected++;
965 			pen = pen % pg->maxpens;
966 		}
967 		if (pen == 0 && pg->mapzero > -1)
968 			pen = pg->mapzero;
969 		if (old_pen != pen) {
970 			if ((fputc(SET_PEN, td) == EOF)
971 			    || (fputc(pen, td) == EOF)) {
972 				PError("Writing to temporary file:");
973 				Eprintf("Error @ Cmd %ld\n", vec_cntr_w);
974 				exit(ERROR);
975 			}
976 		}
977 		if (pen)
978 			pens_in_use[pen] = 1;
979 		pg->maxcolor = MAX(pg->maxcolor, (int) pen);
980 /*MK */
981 		break;
982 
983 	case 190:
984 	case '>':
985 		/* fractional data */
986 
987 		if (EOF == (ctmp = getc(hd))) {
988 			par_err_exit(98, PE, hd);
989 		}
990 		fl->fract = decode_PE_char(ctmp, fl);
991 		fl->fract =
992 		    ((fl->fract >> 1) * ((fl->fract & 0x01) ? -1 : 1));
993 /*      fprintf(stderr,"PE > flag, fract =%d (%d decimals) ",fl->fract, fl->fract/3); */
994 		break;
995 
996 	case 188:
997 	case '<':
998 		/* pen up */
999 		fl->up = 1;
1000 		fl->rect = 0;
1001 		break;
1002 
1003 	case 189:
1004 	case '=':
1005 		/* abs plotting */
1006 
1007 		fl->abs = 1;
1008 		break;
1009 
1010 	default:
1011 		return (0);
1012 	}
1013 	return (1);
1014 }
1015 
isPEterm(int c,PE_flags * fl)1016 int isPEterm(int c, PE_flags * fl)
1017 {
1018 	if ((fl->sbmode) && ((c > 94) || (c < 63)))
1019 		return 1;
1020 	if ((!fl->sbmode) && ((c > 190) || (c < 63)))
1021 		return 1;
1022 	return (0);
1023 }
1024 
1025 
decode_PE_char(int c,PE_flags * fl)1026 int decode_PE_char(int c, PE_flags * fl)
1027 {
1028 	if (fl->sbmode) {
1029 		c &= 0x7f;
1030 		return ((c > 94) ? (c - 95) : (c - 63));
1031 	} else {
1032 		return ((c > 190) ? (c - 191) : (c - 63));
1033 	}
1034 }
1035 
read_PE_coord(int c,FILE * hd,PE_flags * fl,float * fv)1036 int read_PE_coord(int c, FILE * hd, PE_flags * fl, float *fv)
1037 {
1038 	long lv = 0;
1039 	int i = 0;
1040 	int shft = (fl->sbmode) ? 5 : 6;
1041 
1042 	for (;;) {
1043 		if (c < 63) {
1044 			if (!i) {	/* avoid endless getc/ungetc loop with broken files */
1045 				Eprintf("error in PE data!\n");
1046 				return 0;
1047 			}
1048 			ungetc(c, hd);
1049 			break;
1050 		}
1051 		lv |= ((long) decode_PE_char(c, fl)) << (i * shft);
1052 		i++;
1053 		if (isPEterm(c, fl)) {
1054 			break;
1055 		}
1056 		if (EOF == (c = getc(hd))) {
1057 			par_err_exit(98, PE, hd);
1058 		}
1059 	}
1060 	*fv = (float) (((lv >> 1) * ((lv & 0x01) ? -1 : 1)) << fl->fract);
1061 	return (1);
1062 }
1063 
1064 
read_PE_pair(int c,FILE * hd,PE_flags * fl,HPGL_Pt * p)1065 int read_PE_pair(int c, FILE * hd, PE_flags * fl, HPGL_Pt * p)
1066 {
1067 	if (!read_PE_coord(c, hd, fl, &(p->x)))
1068 		return 0;
1069 	if (EOF == (c = getc(hd))) {
1070 		par_err_exit(98, PE, hd);
1071 	}
1072 	if (!read_PE_coord(c, hd, fl, &(p->y)))
1073 		return 0;
1074 	return (1);
1075 }
1076 
1077 
1078 
1079 
read_PE(GEN_PAR * pg,FILE * hd)1080 void read_PE(GEN_PAR * pg, FILE * hd)
1081 {
1082 	int c;
1083 
1084 	HPGL_Pt p;
1085 	PE_flags fl;
1086 
1087 	fl.fract = 0;
1088 	fl.sbmode = 0;
1089 	fl.abs = 0;
1090 	fl.up = 0;
1091 	fl.pen = 0;
1092 
1093 	for (c = getc(hd); (c != EOF) && (c != ';'); c = getc(hd)) {
1094 		if (!read_PE_flags(pg, c, hd, &fl)) {
1095 			if (!read_PE_pair(c, hd, &fl, &p))
1096 				continue;
1097 			switch (fl.rect) {
1098 			case 1:
1099 				pen_down = 0;
1100 				line(!fl.abs, p);
1101 				fl.rect = 2;
1102 				break;
1103 			case 2:
1104 				pen_down = 1;
1105 				rect(1, pg->nofill ? 0 : 1, pt.width[pen],
1106 				     p);
1107 				fl.rect = 1;
1108 				/* should be up when PE ends while */
1109 				/* in PE mode */
1110 				pen_down = 0;
1111 				break;
1112 			default:
1113 				pen_down = (fl.up) ? FALSE : TRUE;
1114 				line(!fl.abs, p);
1115 				fl.up = 0;
1116 				break;
1117 			}
1118 			fl.abs = 0;
1119 			tp->CR_point = HP_pos;
1120 		}
1121 	}
1122 }
1123 
1124 
ceil_with_tolerance(double x,double tol)1125 double ceil_with_tolerance(double x, double tol)
1126 {
1127 	double rounded;
1128 
1129 /*    rounded=rint(x);*/
1130 	rounded = (double) (x + 0.5);
1131 
1132 	if (fabs(rounded - x) <= tol)
1133 		return (rounded);
1134 	else
1135 		return (ceil(x));
1136 }
1137 
Line_Generator(HPGL_Pt * pa,const HPGL_Pt * pb,int mv_flag)1138 static void Line_Generator(HPGL_Pt * pa, const HPGL_Pt * pb, int mv_flag)
1139 {
1140 	double seg_len, dx, dy, quot;
1141 	int n_pat, i;
1142 
1143 	dx = pb->x - pa->x;
1144 	dy = pb->y - pa->y;
1145 	seg_len = HYPOT(dx, dy);
1146 
1147 	switch (CurrentLineType) {
1148 
1149 	case LT_solid:
1150 		if (seg_len < 1.e-8) {
1151 			if (!silent_mode)
1152 				Eprintf
1153 				    ("Warning: Zero line segment length -- skipped\n");
1154 			return;	/* No line to draw ??           */
1155 		}
1156 		PlotCmd_to_tmpfile(DRAW_TO);
1157 		HPGL_Pt_to_tmpfile(pb);
1158 		return;
1159 
1160 	case LT_adaptive:
1161 		if (seg_len < 1.e-8) {
1162 			if (!silent_mode)
1163 				Eprintf
1164 				    ("Warning: Zero line segment length -- skipped\n");
1165 			return;	/* No line to draw ??           */
1166 		}
1167 		pat_pos = 0.0;	/* Reset to start-of-pattern    */
1168 		n_pat =
1169 		    (int) ceil_with_tolerance(seg_len / CurrentLinePatLen,
1170 					      CurrentLinePatLen *
1171 					      LT_PATTERN_TOL);
1172 		if (n_pat == 0) {	/* sanity check for segment << pattern length */
1173 			n_pat = 1;
1174 			if (!silent_mode)
1175 				fprintf(stderr,
1176 					"very short pattern run encountered\n");
1177 		}
1178 		dx /= n_pat;
1179 		dy /= n_pat;
1180 		/* Now draw n_pat complete line patterns */
1181 		for (i = 0; i < n_pat; i++)
1182 			LPattern_Generator(pa, dx, dy, 0.0, 1.0);
1183 		return;
1184 
1185 	case LT_plot_at:
1186 		PlotCmd_to_tmpfile(PLOT_AT);
1187 		HPGL_Pt_to_tmpfile(pb);
1188 		return;
1189 
1190 	case LT_fixed:
1191 		if (seg_len < 1.e-8) {
1192 			if (!silent_mode)
1193 				Eprintf
1194 				    ("Warning: Zero line segment length -- skipped\n");
1195 			return;	/* No line to draw ??           */
1196 		}
1197 		if (mv_flag)	/* Last move ends old line pattern      */
1198 			pat_pos = 0.0;
1199 		quot = seg_len / CurrentLinePatLen;
1200 		dx /= quot;
1201 		dy /= quot;
1202 		while (quot >= 1.0) {
1203 			LPattern_Generator(pa, dx, dy, pat_pos, 1.0);
1204 			quot -= (1.0 - pat_pos);
1205 			pat_pos = 0.0;
1206 		}
1207 		quot += pat_pos;
1208 		if (quot >= 1.0) {
1209 			LPattern_Generator(pa, dx, dy, pat_pos, 1.0);
1210 			quot -= 1.0;
1211 			pat_pos = 0.0;
1212 		}
1213 		if (quot > LT_PATTERN_TOL) {
1214 			LPattern_Generator(pa, dx, dy, pat_pos, quot);
1215 			pat_pos = quot;
1216 		} else {
1217 			PlotCmd_to_tmpfile(MOVE_TO);
1218 			HPGL_Pt_to_tmpfile(pb);
1219 		}
1220 		return;
1221 
1222 	default:
1223 		break;
1224 	}
1225 
1226 }
1227 
1228 
1229 
1230 
Pen_action_to_tmpfile(PlotCmd cmd,const HPGL_Pt * p,int scaled)1231 void Pen_action_to_tmpfile(PlotCmd cmd, const HPGL_Pt * p, int scaled)
1232 {
1233 	static HPGL_Pt P_last;
1234 	HPGL_Pt P;
1235 	double tmp;
1236 
1237 	if (record_off)		/* Wrong page!  */
1238 		return;
1239 
1240 	if (scaled)		/* Rescaling    */
1241 		User_to_Plotter_coord(p, &P);
1242 	else
1243 		P = *p;		/* Local copy   */
1244 
1245 
1246 	HP_pos = P;		/* Actual plotter pos. in plotter coord */
1247 	if (rotate_flag) {	/* hp2xx-specific global rotation       */
1248 		tmp = rot_cos * P.x - rot_sin * P.y;
1249 		P.y = rot_sin * P.x + rot_cos * P.y;
1250 		P.x = tmp;
1251 	}
1252 
1253 	/* Extreme values needed for later scaling:    */
1254 
1255 	switch (cmd) {
1256 	case MOVE_TO:
1257 		mv_flag = TRUE;
1258 		break;
1259 
1260   /**
1261    ** Multiple-move suppression. In addition,
1262    ** a move only precedes a draw -- nothing else!
1263    **/
1264 
1265 	case DRAW_TO:
1266 		if (mv_flag) {
1267 			PlotCmd_to_tmpfile(MOVE_TO);
1268 			HPGL_Pt_to_tmpfile(&P_last);
1269 		}
1270 		/* drop through */
1271 	case PLOT_AT:
1272 		Line_Generator(&P_last, &P, mv_flag);
1273 		mv_flag = FALSE;
1274 		break;
1275 
1276 	default:
1277 		Eprintf("Illegal Pen Action: %d\n", cmd);
1278 		Eprintf("Error @ Cmd %ld\n", vec_cntr_w);
1279 		exit(ERROR);
1280 	}
1281 	P_last = P;
1282 }
1283 
1284 
1285 
1286 
1287 
read_float(float * pnum,FILE * hd)1288 int read_float(float *pnum, FILE * hd)
1289 /**
1290  ** Main work-horse for parameter input:
1291  **
1292  ** Search for next number, skipping white space but return if mnemonic met.
1293  ** If found, read in number
1294  **	returns	0 if valid number
1295  **		1 if command ended
1296  **		2 if scanf failed (possibly corrupted file)
1297  **	      EOF if EOF met
1298  **/
1299 {
1300 	int c;
1301 	char *ptr, numbuf[80];
1302 
1303 	for (c = getc(hd);
1304 	     (c != '.') && (c != '+') && (c != '-') && ((c < '0')
1305 							|| (c > '9'));
1306 	     c = getc(hd)) {
1307 		if (c == EOF)	/* Wait for number      */
1308 			return EOF;	/* Should not happen    */
1309 		if (c == ';')
1310 			return 1;	/* Terminator reached   */
1311 		if (((c >= 'A') && (c <= 'Z')) ||
1312 		    ((c >= 'a') && (c <= 'a')) || (c == ESC)) {
1313 			ungetc(c, hd);
1314 			return 1;	/* Next Mnemonic reached */
1315 		}
1316 	}
1317 	/* Number found: Get it */
1318 	ptr = numbuf;
1319 	for (*ptr++ = c, c = getc(hd);
1320 	     ((c >= '0') && (c <= '9')) || (c == '.'); c = getc(hd))
1321 		*ptr++ = c;	/* Read number          */
1322 	*ptr = '\0';
1323 	if (c != EOF)
1324 		ungetc(c, hd);
1325 
1326 	if (sscanf(numbuf, "%f", pnum) != 1)
1327 		return 11;	/* Should never happen  */
1328 	return 0;
1329 }
1330 
1331 
1332 
1333 
read_string(char * buf,FILE * hd)1334 void read_string(char *buf, FILE * hd)
1335 {
1336 	int c;
1337 	unsigned int n;
1338 
1339 	for (n = 0, c = getc(hd); (c != EOF) && (c != StrTerm);
1340 	     c = getc(hd)) {
1341 		if (n > strbufsize / 2) {
1342 			strbufsize *= 2;
1343 			strbuf = realloc(strbuf, strbufsize);
1344 			if (strbuf == NULL) {
1345 				fprintf(stderr, "\nNo memory !\n");
1346 				exit(ERROR);
1347 			}
1348 			buf = strbuf + n;
1349 		}
1350 		if (c == '\0')
1351 			continue;	/* ignore \0 */
1352 		if (n++ < strbufsize)
1353 			*buf++ = c;
1354 	}
1355 	if (c != StrTerm || StrTermSilent == 0)
1356 		*buf++ = c;
1357 	*buf = '\0';
1358 }
1359 
1360 
1361 
1362 
read_symbol_char(FILE * hd)1363 static void read_symbol_char(FILE * hd)
1364 {
1365 	int c;
1366 
1367 	for (c = getc(hd); /* ended by switch{} */ ; c = getc(hd))
1368 		switch (c) {
1369 		case ' ':
1370 		case _HT:
1371 		case _LF:
1372 			break;	/* Skip white space             */
1373 		case _CR:
1374 		case EOF:
1375 		case ';':	/* CR or "term" end symbol mode */
1376 			symbol_char = '\0';
1377 			return;
1378 		default:
1379 			if (c < ' ' || c > '~')
1380 				break;	/* Ignore unprintable chars     */
1381 			else {
1382 				symbol_char = c;
1383 				return;
1384 			}
1385 		}
1386 }
1387 
1388 
1389 
1390 
read_ESC_HP7550A(FILE * hd)1391 static void read_ESC_HP7550A(FILE * hd)
1392 /*
1393  * Read & skip HP 7550A control commands (ESC.-Commands)
1394  */
1395 {
1396 	int c;
1397 
1398 	switch (getc(hd)) {
1399 	case EOF:
1400 		n_unexpected++;
1401 		Eprintf("\nUnexpected EOF!\n");
1402 		return;
1403 		break;
1404 	case 'A':
1405 	case 'B':
1406 	case 'E':
1407 	case 'J':
1408 	case 'K':
1409 	case 'L':
1410 	case 'O':
1411 	case 'U':
1412 	case 'Y':
1413 	case '(':
1414 	case ')':
1415 		return;		/* Commands without parameters  */
1416 	case '@':
1417 	case 'H':
1418 	case 'I':
1419 	case 'M':
1420 	case 'N':
1421 	case 'P':
1422 	case 'Q':
1423 	case 'S':
1424 	case 'T':
1425 		do {		/* Search for terminator ':'    */
1426 			c = getc(hd);
1427 		}
1428 		while ((c != ':') && (c != EOF));
1429 		if (c == EOF) {
1430 			n_unexpected++;
1431 			Eprintf("\nUnexpected EOF!\n");
1432 		}
1433 		return;
1434 	default:
1435 		n_unknown++;
1436 		return;
1437 	}
1438 }
1439 
1440 
read_PJL(FILE * hd)1441 static int read_PJL(FILE * hd)
1442 /*
1443  * a simple PJL parser
1444  * just reads PJL header and
1445  * return
1446  *   TRUE if PJL enters HPGL context,
1447  *   FALSE  if not
1448  *  *
1449  * PJL lines are like this:
1450  * @PJL[ command][ args][\r]\n
1451  * (however I've seen some wrong PJL files with \n\r )
1452  * @PJL must be uppercase, ther rest of string is not
1453  * case sensitive
1454  * The last line of a PJL header is like these:
1455  * @PJL ENTER LANGUAGE = HPGL2
1456  * @PJL EOJ [NAME = "something"]
1457  */
1458 {
1459 #define PJLBS 257
1460 
1461 	char strbuf[PJLBS];
1462 	int i, j, ov, ctmp, qt, el = 0, nw = 0, rc = -2, nl = 0;
1463 	for (;;) {
1464 		/* read word */
1465 		for (i = ov = qt = 0;; i++) {
1466 			ctmp = getc(hd);
1467 			if (ctmp == ESC) {
1468 				while (ctmp != 'X')
1469 					ctmp = getc(hd);
1470 				ctmp = getc(hd);
1471 			}
1472 			if (PJLBS - 1 == i) {
1473 				if (!silent_mode)
1474 					Eprintf
1475 					    ("PJL buffer overflow, rest of token dropped\n");
1476 				ov = 1;
1477 				strbuf[i] = '\0';
1478 			}
1479 			if (!ov)
1480 				strbuf[i] = (0 == nw
1481 					     || qt) ? ctmp : toupper(ctmp);
1482 			if (EOF == ctmp) {
1483 				if (!ov)
1484 					strbuf[i] = 0;
1485 				break;
1486 			} else if ('=' == ctmp && 0 == i) {
1487 				strbuf[i] = '=';
1488 				strbuf[++i] = '\0';
1489 				ctmp = ' ';
1490 				break;
1491 			} else if (strchr(" \t=", ctmp)) {
1492 				if (!qt) {
1493 					if (!ov)
1494 						strbuf[i] = 0;
1495 					break;
1496 				}
1497 			} else if ('\n' == ctmp || '\r' == ctmp) {
1498 				if (!ov)
1499 					strbuf[i] = 0;
1500 				nl = 1;
1501 				break;
1502 			} else if ('"' == ctmp) {
1503 				qt = !qt;
1504 			}
1505 		}
1506 		/* handle word */
1507 		if (i) {
1508 #ifdef DEBUG_ESC
1509 			Eprintf("word %d: read %d bytes: '%s'\n", nw, i,
1510 				strbuf);
1511 #endif
1512 			if (0 == nw && strcmp(strbuf, "@PJL")) {
1513 				Eprintf
1514 				    ("unexpected end of a PJL header!\n");
1515 				return (TRUE);
1516 			} else if (1 == nw && !strcmp(strbuf, "EOJ")) {
1517 				if (!silent_mode)
1518 					Eprintf("end of a PJL job\n");
1519 				rc = TRUE;
1520 			} else if (1 == nw && !strcmp(strbuf, "ENTER")) {
1521 				el++;
1522 			} else if (2 == nw && 1 == el
1523 				   && !strcmp(strbuf, "LANGUAGE")) {
1524 				el++;
1525 			} else if (3 == nw && 2 == el
1526 				   && !strcmp(strbuf, "=")) {
1527 				el++;
1528 			} else if (4 == nw && 3 == el) {
1529 				if (!silent_mode)
1530 					Eprintf("Entering %s context\n",
1531 						strbuf);
1532 				rc = strncmp(strbuf, "HPGL",
1533 					     4) ? FALSE : TRUE;
1534 			}
1535 			nw++;
1536 		}
1537 		/* read separator */
1538 		for (j = 0; EOF != ctmp; j++) {
1539 			if (!strchr(" \t\n\r", ctmp)) {
1540 				ungetc(ctmp, hd);
1541 				break;
1542 			}
1543 			ctmp = getc(hd);
1544 			if ('\n' == ctmp) {
1545 				nl = 1;
1546 			}
1547 		}
1548 #ifdef DEBUG_ESC
1549 		if (j)
1550 			Eprintf("separator: read %d bytes\n", j);
1551 #endif
1552 
1553 		if (nl) {
1554 			nw = el = nl = 0;
1555 			if (-2 != rc)
1556 				return rc;
1557 		}
1558 		if (EOF == ctmp) {
1559 			if (!silent_mode)
1560 				Eprintf("EOF in PJL context\n");
1561 			return (FALSE);
1562 		}
1563 	}
1564 }
1565 
read_ESC_RTL(FILE * hd,int c1,int hp)1566 static void read_ESC_RTL(FILE * hd, int c1, int hp)
1567 /*
1568  *read and skip ESC% control commands
1569  */
1570 {
1571 	/*
1572 	 * known escapes:
1573 	 * ESC%-12345X    UEL (Universal Escape Language)
1574 	 *                followed by @PJL..
1575 	 *
1576 	 * ESC%-1B        Enter HPGL/2 context
1577 	 * ESC%0B         -
1578 	 * ESC%1B         -
1579 	 *
1580 	 * ESC%1A         Exit HPGL/2 context
1581 	 * ESC%0A         -
1582 	 * ESC%-1A        -
1583 
1584 	 * how a PCL escape looks like:
1585 	 * ESC, lowercase letters and digits, an Upper case letter
1586 
1587 	 */
1588 	int c0, c2, ctmp = 0, nf;
1589 
1590 	for (c0 = ESC, c2 = getc(hd), nf = 0;
1591 	     EOF != c2; c0 = c1, c1 = c2, c2 = getc(hd)) {
1592 
1593 		if ((ESC == c0) && (c1 == '%')) {
1594 			if ('-' == c2) {
1595 				c2 = getc(hd);
1596 				nf = 1;
1597 			}
1598 			switch (c2) {
1599 			case EOF:
1600 				n_unexpected++;
1601 				Eprintf("\nUnexpected EOF!\n");
1602 				return;
1603 				break;
1604 			case '1':
1605 			case '0':
1606 				switch (ctmp = getc(hd)) {
1607 				case 'A':
1608 
1609 					if (hp && !silent_mode) {
1610 #ifdef DEBUG_ESC
1611 						Eprintf
1612 						    ("leaving HPGL context\n");
1613 #endif
1614 						hp = FALSE;
1615 					}
1616 					continue;
1617 				case 'B':
1618 #ifdef DEBUG_ESC
1619 					if (!silent_mode && !hp)
1620 						Eprintf
1621 						    ("entering HPGL context\n");
1622 #endif
1623 					return;
1624 				case '2':
1625 					/* check for UEL */
1626 					if (nf && '1' == c2 &&
1627 					    '3' == (c2 = getc(hd)) &&
1628 					    '4' == (c2 = getc(hd)) &&
1629 					    '5' == (c2 = getc(hd))
1630 					    && 'X' == (c2 = getc(hd))) {
1631 #ifdef DEBUG_ESC
1632 						if (!silent_mode)
1633 							Eprintf
1634 							    ("UEL found\n");
1635 #endif
1636 						if (read_PJL(hd)) {
1637 							return;
1638 						} else {
1639 							hp = 0;
1640 							continue;
1641 						}
1642 					} else {
1643 						ungetc(ctmp, hd);
1644 						if (hp)
1645 							return;
1646 					}
1647 					break;
1648 				default:
1649 					if (!silent_mode)
1650 						Eprintf
1651 						    ("unknown escape: ESC%%%s%c%c\n",
1652 						     nf ? "-" : "", c2,
1653 						     ctmp);
1654 					ungetc(ctmp, hd);
1655 					if (hp)
1656 						return;
1657 				}
1658 				break;
1659 			default:
1660 				if (!silent_mode)
1661 					Eprintf
1662 					    ("unknown escape: ESC%%%s%c",
1663 					     nf ? "-" : "", c2);
1664 				ungetc(ctmp, hd);
1665 				if (hp)
1666 					return;
1667 				break;
1668 			}
1669 		}
1670 		if (hp == TRUE && !nf && c1 != '%' && c1 != 'E') {
1671 			ungetc(ctmp, hd);
1672 			if (!silent_mode)
1673 				Eprintf("invalid escape ESC%c%c\n", c1,
1674 					c2);
1675 			return;
1676 		}
1677 	}
1678 }
1679 
read_ESC_cmd(FILE * hd,int hp)1680 static void read_ESC_cmd(FILE * hd, int hp)
1681 /*
1682  * Read & skip device control commands (ESC.-Commands)
1683 
1684  */
1685 {
1686 	int ctmp;
1687 	switch (ctmp = getc(hd)) {
1688 	case '.':
1689 		read_ESC_HP7550A(hd);
1690 		break;
1691 	case EOF:
1692 		n_unexpected++;
1693 		Eprintf("\nUnexpected EOF!\n");
1694 		return;
1695 	default:
1696 		read_ESC_RTL(hd, ctmp, hp);
1697 		break;
1698 	}
1699 }
1700 
1701 
1702 
1703 /****************************************************************************/
1704 
1705 
1706 
1707 /**
1708  **	lines:	Process PA-, PR-, PU-, and  PD- commands
1709  **/
lines(int relative,FILE * hd)1710 static void lines(int relative, FILE * hd)
1711 /**
1712  ** Examples of anticipated commands:
1713  **
1714  **	PA PD0,0,80,50,90,20PU140,30PD150,80;
1715  **	PU0,0;PD20.53,40.32,30.08,60.2,40,90,;PU100,300;PD120,340...
1716  **/
1717 {
1718 	HPGL_Pt p;
1719 	int numcmds = 0;
1720 	int outside = 0;
1721 	double p1x, p1y, p2x, p2y;
1722 
1723 	for (;;) {
1724 		if (read_float(&p.x, hd)) {	/* No number found      */
1725 			if (numcmds > 0)
1726 				return;
1727 			if (pen_down && mv_flag && pen > 0 && pt.width[pen] < 0.35) {	/*simulate dot created by 'real' pen on PD;PU; */
1728 				/*but not on PDPA */
1729 				p.x = p_last.x + 0.01;
1730 				p.y = p_last.y + 0.01;
1731 				outside = 0;
1732 				if (iwflag) {
1733 					p1x =
1734 					    P1.x + (p_last.x - S1.x) * Q.x;
1735 					p1y =
1736 					    P1.y + (p_last.y - S1.y) * Q.y;
1737 					p2x = P1.x + (p.x - S1.x) * Q.x;
1738 					p2y = P1.y + (p.y - S1.y) * Q.y;
1739 
1740 					outside =
1741 					    (DtClipLine
1742 					     (C1.x, C1.y, C2.x, C2.y, &p1x,
1743 					      &p1y, &p2x,
1744 					      &p2y) == CLIP_NODRAW);
1745 				}
1746 				if (!outside) {
1747 					Pen_action_to_tmpfile(MOVE_TO, &p,
1748 							      scale_flag);
1749 					Pen_action_to_tmpfile(DRAW_TO,
1750 							      &p_last,
1751 							      scale_flag);
1752 				}
1753 			}
1754 			return;
1755 		}
1756 
1757 		if (read_float(&p.y, hd))	/* x without y invalid! */
1758 			par_err_exit(2, PA, hd);
1759 		line(relative, p);
1760 		numcmds++;
1761 	}
1762 }
1763 
1764 
1765 /*
1766  * line : process a pair of coordinates
1767  */
line(int relative,HPGL_Pt p)1768 void line(int relative, HPGL_Pt p)
1769 {
1770 	HPGL_Pt pl, porig;
1771 	int outside = 0;
1772 	double x1, y1, x2, y2;
1773 
1774 	if (relative) {
1775 		p.x += p_last.x;
1776 		p.y += p_last.y;
1777 	}
1778 
1779 	porig.x = p.x;
1780 	porig.y = p.y;
1781 
1782 	if (iwflag) {
1783 		x1 = P1.x + (p_last.x - S1.x) * Q.x;
1784 		y1 = P1.y + (p_last.y - S1.y) * Q.y;
1785 		x2 = P1.x + (p.x - S1.x) * Q.x;
1786 		y2 = P1.y + (p.y - S1.y) * Q.y;
1787 
1788 		outside =
1789 		    (DtClipLine(C1.x, C1.y, C2.x, C2.y, &x1, &y1, &x2, &y2)
1790 		     == CLIP_NODRAW);
1791 
1792 		if (!outside) {
1793 			p.x = (x2 - P1.x) / Q.x + S1.x;
1794 			p.y = (y2 - P1.y) / Q.y + S1.y;
1795 			pl.x = (x1 - P1.x) / Q.x + S1.x;
1796 			pl.y = (y1 - P1.y) / Q.y + S1.y;
1797 			if (pl.x != p_last.x || pl.y != p_last.y)
1798 				Pen_action_to_tmpfile(MOVE_TO, &pl,
1799 						      scale_flag);
1800 
1801 		}
1802 
1803 	} else
1804 		pl = p_last;
1805 
1806 	if (polygon_mode && polygon_penup)
1807 		pen_down = FALSE;
1808 
1809 	if (pen_down && !outside) {
1810 		if (polygon_mode) {
1811 			HPGL_Pt_to_polygon(pl);
1812 			HPGL_Pt_to_polygon(p);
1813 /*	      fprintf(stderr,"polygon line1: %f %f - %f %f\n",p_last.x,p_last.y,p.x,p.y);*/
1814 		} else {
1815 			Pen_action_to_tmpfile(DRAW_TO, &p, scale_flag);
1816 /*	      fprintf(stderr,"std line1: %f %f - %f %f\n",p_last.x,p_last.y,p.x,p.y); */
1817 		}
1818 	} else {
1819 		if (iwflag) {
1820 			Pen_action_to_tmpfile(MOVE_TO, &porig, scale_flag);
1821 		} else {
1822 			Pen_action_to_tmpfile(MOVE_TO, &p, scale_flag);
1823 		}
1824 	}
1825 
1826 	if (polygon_mode && polygon_penup) {
1827 		polygon_penup = FALSE;
1828 		polystart = p;
1829 		pen_down = TRUE;
1830 	}
1831 
1832 
1833 	if (symbol_char) {
1834 		plot_symbol_char(symbol_char);
1835 		Pen_action_to_tmpfile(MOVE_TO, &p, scale_flag);
1836 	}
1837 	outside = 0;
1838 	p_last = porig;
1839 
1840 }
1841 
1842 
1843 /**
1844  **	Arcs, circles and alike
1845  **/
1846 
1847 
arc_increment(HPGL_Pt * pcenter,double r,double phi)1848 static void arc_increment(HPGL_Pt * pcenter, double r, double phi)
1849 {
1850 	HPGL_Pt p;
1851 	int outside = 0;
1852 	p.x = pcenter->x + r * cos(phi);
1853 	p.y = pcenter->y + r * sin(phi);
1854 
1855 	if (iwflag) {
1856 		if (P1.x + (p.x - S1.x) * Q.x > C2.x
1857 		    || P1.y + (p.y - S1.y) * Q.y > C2.y) {
1858 /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
1859 			outside = 1;
1860 		}
1861 		if (P1.x + (p.x - S1.x) * Q.x < C1.x
1862 		    || P1.y + (p.y - S1.y) * Q.y < C1.y) {
1863 /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
1864 			outside = 1;
1865 		}
1866 	}
1867 
1868 	if (polygon_mode) {
1869 		if (polygon_penup)
1870 			polygon_penup = FALSE;
1871 		else if (pen_down && !outside) {
1872 			HPGL_Pt_to_polygon(p_last);
1873 			HPGL_Pt_to_polygon(p);
1874 /*fprintf(stderr,"arcpoint %f %f\n",p.x,p.y);*/
1875 
1876 		} else if ((p.x != p_last.x) || (p.y != p_last.y)) {
1877 			/*polygon_penup=TRUE; */
1878 			HPGL_Pt_to_polygon(p_last);
1879 			HPGL_Pt_to_polygon(p);
1880 /*fprintf(stderr,"final arcpoint %f %f\n",p.x,p.y);*/
1881 		}
1882 	} else {
1883 		if (pen_down && !outside)
1884 			Pen_action_to_tmpfile(DRAW_TO, &p, scale_flag);
1885 		else if (!outside
1886 			 && ((p.x != p_last.x) || (p.y != p_last.y)))
1887 			Pen_action_to_tmpfile(MOVE_TO, &p, scale_flag);
1888 	}
1889 	p_last = p;
1890 }
1891 
bezier(int relative,FILE * hd)1892 static void bezier(int relative, FILE * hd)
1893 {
1894 	HPGL_Pt p, p1, p2, p3, polyp;
1895 	int i, outside;
1896 	float t;
1897 /*  double SafeLinePatLen = CurrentLinePatLen;*/
1898 
1899 	for (;;) {		/* parameter set may contain several bezier curves */
1900 		if (read_float(&p1.x, hd))	/* No number found      */
1901 			return;
1902 
1903 		if (read_float(&p1.y, hd))	/* x without y invalid! */
1904 			par_err_exit(2, BZ, hd);
1905 
1906 		if (read_float(&p2.x, hd))	/* No number found      */
1907 			return;
1908 
1909 		if (read_float(&p2.y, hd))	/* x without y invalid! */
1910 			par_err_exit(2, BZ, hd);
1911 
1912 		if (read_float(&p3.x, hd))	/* No endpoint */
1913 			par_err_exit(3, BZ, hd);
1914 
1915 		if (read_float(&p3.y, hd))	/* No endpoint */
1916 			par_err_exit(3, BZ, hd);
1917 
1918 		if (relative) {	/* Transform coordinates  */
1919 			p1.x = p1.x + p_last.x;
1920 			p1.y = p1.y + p_last.y;
1921 			p2.x = p2.x + p_last.x;
1922 			p2.y = p2.y + p_last.y;
1923 			p3.x = p3.x + p_last.x;
1924 			p3.y = p3.y + p_last.y;
1925 		}
1926 
1927 /*
1928 p(t) = t^3*P3 + 3*t^2*(1-t)*P2 + 3*t*(1-t)^2* P1 + (1-t)^3 * P0
1929 */
1930 
1931 		polyp = p_last;
1932 		outside = 0;
1933 
1934 		for (i = 0; i < 51; i++) {
1935 			t = (float) i / 50.;
1936 			p.x =
1937 			    t * t * t * p3.x + 3 * t * t * (1. -
1938 							    t) * p2.x +
1939 			    3 * t * (1. - t) * (1. - t) * p1.x + (1. -
1940 								  t) *
1941 			    (1. - t) * (1. - t) * p_last.x;
1942 			p.y =
1943 			    t * t * t * p3.y + 3 * t * t * (1. -
1944 							    t) * p2.y +
1945 			    3 * t * (1. - t) * (1. - t) * p1.y + (1. -
1946 								  t) *
1947 			    (1. - t) * (1. - t) * p_last.y;
1948 
1949 /*fprintf(stderr,"bezier point %f %f\n",p.x,p.y);*/
1950 			if (iwflag) {
1951 				if (P1.x + (p.x - S1.x) * Q.x > C2.x
1952 				    || P1.y + (p.y - S1.y) * Q.y > C2.y) {
1953 /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
1954 					outside = 1;
1955 				}
1956 				if (P1.x + (p.x - S1.x) * Q.x < C1.x
1957 				    || P1.y + (p.y - S1.y) * Q.y < C1.y) {
1958 /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
1959 					outside = 1;
1960 				}
1961 			}
1962 
1963 			if (!outside) {
1964 				if (polygon_mode) {
1965 					HPGL_Pt_to_polygon(polyp);
1966 					HPGL_Pt_to_polygon(p);
1967 					polyp.x = p.x;
1968 					polyp.y = p.y;
1969 				} else {
1970 					Pen_action_to_tmpfile(DRAW_TO, &p,
1971 							      scale_flag);
1972 				}
1973 			} else
1974 				Pen_action_to_tmpfile(MOVE_TO, &p,
1975 						      scale_flag);
1976 			outside = 0;
1977 		}
1978 
1979 		p_last.x = p3.x;
1980 		p_last.y = p3.y;
1981 
1982 	}
1983 }
1984 
tarcs(int relative,FILE * hd)1985 static void tarcs(int relative, FILE * hd)
1986 {
1987 	HPGL_Pt p, p2, p3, center, d;
1988 	float alpha, eps;
1989 	double phi, phi0, r;
1990 	double SafeLinePatLen = CurrentLinePatLen;
1991 
1992 	if (read_float(&p2.x, hd))	/* No number found      */
1993 		return;
1994 
1995 	if (read_float(&p2.y, hd))	/* x without y invalid! */
1996 		par_err_exit(2, AT, hd);
1997 
1998 	if (read_float(&p3.x, hd))	/* No endpoint */
1999 		par_err_exit(3, AT, hd);
2000 
2001 	if (read_float(&p3.y, hd))	/* No endpoint */
2002 		par_err_exit(3, AT, hd);
2003 
2004 	switch (read_float(&eps, hd)) {	/* chord angle is optional */
2005 	case 0:
2006 		if (eps < 0.5)
2007 			eps = 0.5;
2008 		break;
2009 	case 1:		/* No resolution option */
2010 		eps = 5.0;	/*    so use default!   */
2011 		break;
2012 	case 2:		/* Illegal state        */
2013 		par_err_exit(98, AT, hd);
2014 	case EOF:
2015 		return;
2016 	default:		/* Illegal state        */
2017 		par_err_exit(99, AT, hd);
2018 	}
2019 	if (ct_dist == FALSE)
2020 		eps *= M_PI / 180.0;	/* Deg-to-Rad           */
2021 
2022 	d = p_last;
2023 
2024 	if (!relative) {	/* Transform coordinates  */
2025 		p2.x = p2.x - p_last.x;
2026 		p2.y = p2.y - p_last.y;
2027 		p3.x = p3.x - p_last.x;
2028 		p3.y = p3.y - p_last.y;
2029 	}
2030 
2031 /*
2032     2*p2.x*h+2*p2.y*k = p2.x^2 + p2.y^2
2033 
2034     k= (p2.x^2 + p2.y^2 - 2*p2.x*h) /2*p2.y
2035 
2036     2*p3.x*h+2*p3.y*k = p3.x^2 + p3.y^2
2037 
2038 
2039 2* p3.x*h +2*p3.y * (p2.x^2 + p2.y^2 -2*p2.x*h) / 2*p2.y = (p3.x^2 + p3.y^2)
2040 2* p3.x*h +2*p3.y * (p2.x^2 + p2.y^2 -2*p2.x*h)  = (p3.x^2 + p3.y^2) *2*p2.y
2041 
2042 2*p3.x*h + 2*p3.y*p2.x^2 + 2*p3.y*p2.y^2 - 4*p2.x*p3.y*h =...
2043 (2*p3.x-4*p2.y*p3.y)*h  + 2*p3.y*p2.x^2 + 2*p3.y*p2.y^2 = ...
2044 h = ( 2*p2.y*(p2.x^2 + p2.y^2) -2*p3.y*p2.x^2 - 2*p3.y*p2.y^2 )  / 2*p3.x-4*p2.x*p3.y
2045 */
2046 	center.x =
2047 	    (2. * p2.y * (p3.x * p3.x + p3.y * p3.y) -
2048 	     2. * p3.y * p2.x * p2.x -
2049 	     2. * p3.y * p2.y * p2.y) / (2. * p3.x - 4. * p2.x * p3.y);
2050 	center.y =
2051 	    (p2.x * p2.x + p2.y * p2.y -
2052 	     2. * p2.x * center.x) / (2. * p2.y);
2053 
2054 	r = sqrt(center.x * center.x + center.y * center.y);
2055 
2056 	if (ct_dist == TRUE)
2057 		eps = 2. * acos((r - eps) / r);
2058 	center.x = center.x + p_last.x;
2059 	center.y = center.y + p_last.y;
2060 
2061 
2062 	d.x = p_last.x - center.x;
2063 	d.y = p_last.y - center.y;
2064 
2065 	phi0 = atan2(d.y, d.x);
2066 
2067 	d.x = p3.x + p_last.x - center.x;
2068 	d.y = p3.y + p_last.y - center.y;
2069 
2070 	alpha = 2. * atan2(d.y, d.x);
2071 /*
2072 fprintf(stderr,"AT: P1 at %f %f , P2 %f %f, P3 %f %f, center %f %f radius %f\n",
2073 p_last.x,p_last.y,p2.x+p_last.x,p2.y+p_last.y,p3.x+p_last.x,p3.y+p_last.y,
2074 center.x,center.y,r);
2075 */
2076 	if (CurrentLineType == LT_adaptive) {	/* Adaptive patterns:   */
2077 		p.x = r * cos(eps);	/* A chord segment      */
2078 		p.y = r * sin(eps);
2079 		if (scale_flag)
2080 			User_to_Plotter_coord(&p, &p);
2081 
2082 		/*      Pattern length = chord length           */
2083 		CurrentLinePatLen = HYPOT(p.x, p.y);
2084 	}
2085 
2086 	if (alpha > 0.0) {
2087 		for (phi = phi0 + MIN(eps, alpha); phi < phi0 + alpha;
2088 		     phi += eps)
2089 			arc_increment(&center, r, phi);
2090 		arc_increment(&center, r, phi0 + alpha);	/* to endpoint */
2091 	} else {
2092 		for (phi = phi0 - MIN(eps, -alpha); phi > phi0 + alpha;
2093 		     phi -= eps)
2094 			arc_increment(&center, r, phi);
2095 		arc_increment(&center, r, phi0 + alpha);	/* to endpoint */
2096 	}
2097 
2098 	CurrentLinePatLen = SafeLinePatLen;	/* Restore */
2099 
2100 	p_last.x = p_last.x + p3.x;
2101 	p_last.y = p_last.y + p3.y;
2102 
2103 }
2104 
arcs(int relative,FILE * hd)2105 static void arcs(int relative, FILE * hd)
2106 {
2107 	HPGL_Pt p, d, center;
2108 	float alpha, eps;
2109 	double phi, phi0, r;
2110 	double SafeLinePatLen = CurrentLinePatLen;
2111 
2112 	if (read_float(&p.x, hd))	/* No number found      */
2113 		return;
2114 
2115 	if (read_float(&p.y, hd))	/* x without y invalid! */
2116 		par_err_exit(2, AA, hd);
2117 
2118 	if (read_float(&alpha, hd))	/* Invalid without angle */
2119 		par_err_exit(3, AA, hd);
2120 	else
2121 		alpha *= M_PI / 180.0;	/* Deg-to-Rad           */
2122 
2123 	switch (read_float(&eps, hd)) {
2124 	case 0:
2125 		if (eps < 0.5)
2126 			eps = 0.5;
2127 		break;
2128 	case 1:		/* No resolution option */
2129 		eps = 5.0;	/*    so use default!   */
2130 		break;
2131 	case 2:		/* Illegal state        */
2132 		par_err_exit(98, AA, hd);
2133 	case EOF:
2134 		return;
2135 	default:		/* Illegal state        */
2136 		par_err_exit(99, AA, hd);
2137 	}
2138 
2139 	if (ct_dist == FALSE)
2140 		eps *= M_PI / 180.0;	/* Deg-to-Rad           */
2141 
2142 	if (relative) {		/* Process coordinates  */
2143 		d = p;		/* Difference vector    */
2144 		center.x = d.x + p_last.x;
2145 		center.y = d.y + p_last.y;
2146 	} else {
2147 		d.x = p.x - p_last.x;
2148 		d.y = p.y - p_last.y;
2149 		center.x = p.x;
2150 		center.y = p.y;
2151 	}
2152 
2153 	if (((r = sqrt(d.x * d.x + d.y * d.y)) == 0.0) || (alpha == 0.0))
2154 		return;		/* Zero radius or zero arc angle given  */
2155 
2156 	if (ct_dist == TRUE)
2157 		eps = 2. * acos((r - eps) / r);
2158 
2159 	phi0 = atan2(-d.y, -d.x);
2160 
2161 	if (CurrentLineType == LT_adaptive) {	/* Adaptive patterns:   */
2162 		p.x = r * cos(eps);	/* A chord segment      */
2163 		p.y = r * sin(eps);
2164 		if (scale_flag)
2165 			User_to_Plotter_coord(&p, &p);
2166 
2167 		/*      Pattern length = chord length           */
2168 		CurrentLinePatLen = HYPOT(p.x, p.y);
2169 	}
2170 
2171 	if (alpha > 0.0) {
2172 		for (phi = phi0 + MIN(eps, alpha); phi < phi0 + alpha;
2173 		     phi += eps)
2174 			arc_increment(&center, r, phi);
2175 		arc_increment(&center, r, phi0 + alpha);	/* to endpoint */
2176 	} else {
2177 		for (phi = phi0 - MIN(eps, -alpha); phi > phi0 + alpha;
2178 		     phi -= eps)
2179 			arc_increment(&center, r, phi);
2180 		arc_increment(&center, r, phi0 + alpha);	/* to endpoint */
2181 	}
2182 	CurrentLinePatLen = SafeLinePatLen;	/* Restore */
2183 }
2184 
fwedges(FILE * hd,float cur_pensize)2185 static void fwedges(FILE * hd, float cur_pensize)
2186 {				/*derived from circles */
2187 	HPGL_Pt p, oldp, center;
2188 	float eps, r, start, sweep;
2189 	double phi;
2190 	double SafeLinePatLen = CurrentLinePatLen;
2191 	int outside = 0;
2192 	int i;
2193 
2194 	if (read_float(&r, hd))	/* No radius found      */
2195 		return;
2196 	if (read_float(&start, hd))	/* No start angle found */
2197 		return;
2198 
2199 	if (read_float(&sweep, hd))	/* No sweep angle found */
2200 		return;
2201 
2202 	switch (read_float(&eps, hd)) {	/* chord angle */
2203 	case 0:
2204 		if (eps < 0.5)
2205 			eps = 0.5;
2206 		break;
2207 	case 1:		/* No resolution option */
2208 		eps = 5.0;	/*    so use default!   */
2209 		break;
2210 	case 2:		/* Illegal state        */
2211 		par_err_exit(98, EW, hd);
2212 	case EOF:
2213 		return;
2214 	default:		/* Illegal state        */
2215 		par_err_exit(99, EW, hd);
2216 	}
2217 
2218 	if (ct_dist == TRUE)
2219 		eps = 2. * acos((r - eps) / r);
2220 	else
2221 		eps *= M_PI / 180.0;	/* Deg-to-Rad           */
2222 	start *= M_PI / 180.0;	/* Deg-to-Rad           */
2223 	sweep *= M_PI / 180.0;	/* Deg-to-Rad           */
2224 
2225 
2226 	center = p_last;	/* reference point is last position */
2227 	vertices = -1;		/* clear the polygon buffer */
2228 	if (r == 0.0)		/* Zero radius given    */
2229 		return;
2230 
2231 	HPGL_Pt_to_polygon(p_last);
2232 	p.x = center.x + r * cos(start);
2233 	p.y = center.y + r * sin(start);
2234 	HPGL_Pt_to_polygon(p);
2235 
2236 
2237 	if (CurrentLineType == LT_adaptive) {	/* Adaptive patterns    */
2238 		p.x = r * cos(eps);	/* A chord segment      */
2239 		p.y = r * sin(eps);
2240 		if (scale_flag)
2241 			User_to_Plotter_coord(&p, &p);
2242 
2243 		/*      Pattern length = chord length           */
2244 		CurrentLinePatLen = HYPOT(p.x, p.y);
2245 	}
2246 	i = 1;
2247 	for (phi = eps; phi <= sweep; phi += eps) {
2248 		oldp = p;
2249 		p.x = center.x + r * cos(start + phi);
2250 		p.y = center.y + r * sin(start + phi);
2251 		if (iwflag) {
2252 			if (P1.x + (p.x - S1.x) * Q.x > C2.x
2253 			    || P1.y + (p.y - S1.y) * Q.y > C2.y) {
2254 /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
2255 				outside = 1;
2256 			}
2257 			if (P1.x + (p.x - S1.x) * Q.x < C1.x
2258 			    || P1.y + (p.y - S1.y) * Q.y < C1.y) {
2259 /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
2260 				outside = 1;
2261 			}
2262 		}
2263 		if (!outside) {
2264 			HPGL_Pt_to_polygon(oldp);
2265 			HPGL_Pt_to_polygon(p);
2266 		}
2267 		outside = 0;
2268 	}
2269 	HPGL_Pt_to_polygon(p);
2270 	HPGL_Pt_to_polygon(center);
2271 	if (hatchspace == 0.)
2272 		hatchspace = cur_pensize;
2273 	if (filltype < 3 && thickness > 0.)
2274 		hatchspace = thickness;
2275 	if (!ac_flag) {		/* not yet initialized */
2276 		anchor.x = P1.x;
2277 		anchor.y = P1.y;
2278 	}
2279 	fill(polygons, vertices, anchor, P2, scale_flag, filltype,
2280 	     hatchspace, hatchangle);
2281 
2282 
2283 	CurrentLinePatLen = SafeLinePatLen;	/* Restore */
2284 
2285 }
2286 
2287 
2288 
circles(FILE * hd)2289 static void circles(FILE * hd)
2290 {
2291 	HPGL_Pt p, center, polyp;
2292 	float eps, r;
2293 	double phi;
2294 	double SafeLinePatLen = CurrentLinePatLen;
2295 	int outside = 0;
2296 
2297 	if (read_float(&r, hd))	/* No radius found      */
2298 		return;
2299 
2300 	switch (read_float(&eps, hd)) {
2301 	case 0:
2302 		if (eps < 0.5)
2303 			eps = 0.5;
2304 		break;
2305 	case 1:		/* No resolution option */
2306 		eps = 5.0;	/*    so use default!   */
2307 		break;
2308 	case 2:		/* Illegal state        */
2309 		par_err_exit(98, CI, hd);
2310 	case EOF:
2311 		return;
2312 	default:		/* Illegal state        */
2313 		par_err_exit(99, CI, hd);
2314 	}
2315 
2316 	if (ct_dist == TRUE)
2317 		eps = 2. * acos((r - eps) / r);
2318 	else
2319 		eps *= M_PI / 180.0;	/* Deg-to-Rad           */
2320 
2321 
2322 	center = p_last;
2323 
2324 	if (r == 0.0)		/* Zero radius given    */
2325 		return;
2326 
2327 	p.x = center.x + r;
2328 	p.y = center.y;
2329 	Pen_action_to_tmpfile(MOVE_TO, &p, scale_flag);
2330 	if (polygon_mode) {
2331 		polyp.x = p.x;
2332 		polyp.y = p.y;
2333 	}
2334 	if (CurrentLineType == LT_adaptive) {	/* Adaptive patterns    */
2335 		p.x = r * cos(eps);	/* A chord segment      */
2336 		p.y = r * sin(eps);
2337 		if (scale_flag)
2338 			User_to_Plotter_coord(&p, &p);
2339 
2340 		/*      Pattern length = chord length           */
2341 		CurrentLinePatLen = HYPOT(p.x, p.y);
2342 	}
2343 
2344 	for (phi = eps; phi < 2.0 * M_PI; phi += eps) {
2345 		p.x = center.x + r * cos(phi);
2346 		p.y = center.y + r * sin(phi);
2347 		if (iwflag) {
2348 			if (P1.x + (p.x - S1.x) * Q.x > C2.x
2349 			    || P1.y + (p.y - S1.y) * Q.y > C2.y) {
2350 /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
2351 				outside = 1;
2352 			}
2353 			if (P1.x + (p.x - S1.x) * Q.x < C1.x
2354 			    || P1.y + (p.y - S1.y) * Q.y < C1.y) {
2355 /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
2356 				outside = 1;
2357 			}
2358 		}
2359 
2360 		if (!outside) {
2361 			if (polygon_mode) {
2362 				HPGL_Pt_to_polygon(polyp);
2363 				HPGL_Pt_to_polygon(p);
2364 				polyp.x = p.x;
2365 				polyp.y = p.y;
2366 			} else {
2367 				Pen_action_to_tmpfile(DRAW_TO, &p,
2368 						      scale_flag);
2369 			}
2370 		} else
2371 			Pen_action_to_tmpfile(MOVE_TO, &p, scale_flag);
2372 		outside = 0;
2373 	}
2374 	p.x = center.x + r;	/* Close circle at r * (1, 0)   */
2375 	p.y = center.y;
2376 	if (polygon_mode) {
2377 		HPGL_Pt_to_polygon(polyp);
2378 		HPGL_Pt_to_polygon(p);
2379 	} else
2380 		Pen_action_to_tmpfile(DRAW_TO, &p, scale_flag);
2381 
2382 	if (!polygon_mode) {
2383 		/* draw one overlapping segment to avoid leaving gap with wide pens */
2384 		p.x = center.x + r * cos(eps);
2385 		p.y = center.y + r * sin(eps);
2386 		if (iwflag) {
2387 			if (P1.x + (p.x - S1.x) * Q.x > C2.x
2388 			    || P1.y + (p.y - S1.y) * Q.y > C2.y) {
2389 /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
2390 				outside = 1;
2391 			}
2392 			if (P1.x + (p.x - S1.x) * Q.x < C1.x
2393 			    || P1.y + (p.y - S1.y) * Q.y < C1.y) {
2394 /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
2395 				outside = 1;
2396 			}
2397 		}
2398 
2399 		if (!outside) {
2400 			if (polygon_mode) {
2401 				HPGL_Pt_to_polygon(polyp);
2402 				HPGL_Pt_to_polygon(p);
2403 				polyp.x = p.x;
2404 				polyp.y = p.y;
2405 			} else {
2406 				Pen_action_to_tmpfile(DRAW_TO, &p,
2407 						      scale_flag);
2408 			}
2409 		}
2410 	}
2411 	Pen_action_to_tmpfile(MOVE_TO, &center, scale_flag);
2412 
2413 	CurrentLinePatLen = SafeLinePatLen;	/* Restore */
2414 }
2415 
wedges(FILE * hd)2416 static void wedges(FILE * hd)
2417 {				/*derived from circles */
2418 	HPGL_Pt p, center;
2419 	float eps, r, start, sweep;
2420 	double phi;
2421 	double SafeLinePatLen = CurrentLinePatLen;
2422 	int outside = 0;
2423 
2424 	if (read_float(&r, hd))	/* No radius found      */
2425 		return;
2426 
2427 	if (read_float(&start, hd))	/* No start angle found */
2428 		return;
2429 
2430 	if (read_float(&sweep, hd))	/* No sweep angle found */
2431 		return;
2432 
2433 	switch (read_float(&eps, hd)) {	/* chord angle */
2434 	case 0:
2435 		if (eps < 0.5)
2436 			eps = 0.5;
2437 		break;
2438 	case 1:		/* No resolution option */
2439 		eps = 5.0;	/*    so use default!   */
2440 		break;
2441 	case 2:		/* Illegal state        */
2442 		par_err_exit(98, EW, hd);
2443 	case EOF:
2444 		return;
2445 	default:		/* Illegal state        */
2446 		par_err_exit(99, EW, hd);
2447 	}
2448 
2449 	if (ct_dist == TRUE)
2450 		eps = 2. * acos((r - eps) / r);
2451 	else
2452 		eps *= M_PI / 180.0;	/* Deg-to-Rad           */
2453 	start *= M_PI / 180.0;	/* Deg-to-Rad           */
2454 	sweep *= M_PI / 180.0;	/* Deg-to-Rad           */
2455 
2456 
2457 	center = p_last;	/* reference point is last position */
2458 
2459 	if (r == 0.0)		/* Zero radius given    */
2460 		return;
2461 
2462 	p.x = center.x + r * cos(start);
2463 	p.y = center.y + r * sin(start);
2464 	Pen_action_to_tmpfile(DRAW_TO, &p, scale_flag);
2465 
2466 	if (CurrentLineType == LT_adaptive) {	/* Adaptive patterns    */
2467 		p.x = r * cos(eps);	/* A chord segment      */
2468 		p.y = r * sin(eps);
2469 		if (scale_flag)
2470 			User_to_Plotter_coord(&p, &p);
2471 
2472 		/*      Pattern length = chord length           */
2473 		CurrentLinePatLen = HYPOT(p.x, p.y);
2474 	}
2475 
2476 	for (phi = eps; phi <= sweep; phi += eps) {
2477 		p.x = center.x + r * cos(start + phi);
2478 		p.y = center.y + r * sin(start + phi);
2479 		if (iwflag) {
2480 			if (P1.x + (p.x - S1.x) * Q.x > C2.x
2481 			    || P1.y + (p.y - S1.y) * Q.y > C2.y) {
2482 /*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
2483 				outside = 1;
2484 			}
2485 			if (P1.x + (p.x - S1.x) * Q.x < C1.x
2486 			    || P1.y + (p.y - S1.y) * Q.y < C1.y) {
2487 /*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
2488 				outside = 1;
2489 			}
2490 		}
2491 		if (!outside)
2492 			Pen_action_to_tmpfile(DRAW_TO, &p, scale_flag);
2493 		else
2494 			Pen_action_to_tmpfile(MOVE_TO, &p, scale_flag);
2495 		outside = 0;
2496 	}
2497 
2498 	Pen_action_to_tmpfile(DRAW_TO, &center, scale_flag);
2499 
2500 	CurrentLinePatLen = SafeLinePatLen;	/* Restore */
2501 }
2502 
2503 
2504 
ax_ticks(int mode)2505 static void ax_ticks(int mode)
2506 {
2507 	HPGL_Pt p0, p1, p2;
2508 	LineType SafeLineType = CurrentLineType;
2509 
2510 	p0 = p1 = p2 = p_last;
2511 /**
2512  ** According to the HP-GL manual,
2513  ** XT & YT are not affected by LT
2514  **/
2515 	CurrentLineType = LT_solid;
2516 
2517 	if (mode == 0) {	/* X tick       */
2518 		if (scale_flag) {
2519 			p1.y -= neg_ticklen * (P2.y - P1.y) / Q.y;
2520 			p2.y += pos_ticklen * (P2.y - P1.y) / Q.y;
2521 		} else {
2522 			p1.y -= neg_ticklen * (P2.y - P1.y);
2523 			p2.y += pos_ticklen * (P2.y - P1.y);
2524 		}
2525 	} else
2526 		/* Y tick */
2527 	{
2528 		if (scale_flag) {
2529 			p1.x -= neg_ticklen * (P2.x - P1.x) / Q.x;
2530 			p2.x += pos_ticklen * (P2.x - P1.x) / Q.x;
2531 		} else {
2532 			p1.x -= neg_ticklen * (P2.x - P1.x);
2533 			p2.x += pos_ticklen * (P2.x - P1.x);
2534 		}
2535 	}
2536 
2537 	Pen_action_to_tmpfile(MOVE_TO, &p1, scale_flag);
2538 	Pen_action_to_tmpfile(DRAW_TO, &p2, scale_flag);
2539 	Pen_action_to_tmpfile(MOVE_TO, &p0, scale_flag);
2540 
2541 	CurrentLineType = SafeLineType;
2542 }
2543 
2544 
2545 
2546 /**
2547  **	Process a single HPGL command
2548  **/
2549 
read_HPGL_cmd(GEN_PAR * pg,int cmd,FILE * hd)2550 static void read_HPGL_cmd(GEN_PAR * pg, int cmd, FILE * hd)
2551 {
2552 	short old_pen;
2553 	HPGL_Pt p1 = { 0., 0. }, p2 = {
2554 	0., 0.};
2555 	float ftmp;
2556 	float csfont;
2557 	int mypen, myred, mygreen, myblue, i;
2558 	float mywidth, myheight;
2559 	char tmpstr[1024];
2560 	char SafeTerm;
2561 	static int FoundUserFill = 0;
2562 /**
2563  ** Each command consists of 2 characters. We unite them here to a single int
2564  ** to allow for easy processing within a big switch statement:
2565  **/
2566 
2567 	switch (cmd & 0xDFDF) {	/* & forces to upper case       */
2568   /**
2569    ** Commands appear in alphabetical order within each topic group
2570    ** except for command synonyms.
2571    **/
2572 	case AA:		/* Arc Absolute                 */
2573 		arcs(FALSE, hd);
2574 		tp->CR_point = HP_pos;
2575 		break;
2576 	case AR:		/* Arc Relative                 */
2577 		arcs(TRUE, hd);
2578 		tp->CR_point = HP_pos;
2579 		break;
2580 	case AT:		/* Arc Absolute, through Three points */
2581 		tarcs(FALSE, hd);
2582 		break;
2583 	case BR:		/* cubic bezier curve, relative control points */
2584 		bezier(TRUE, hd);
2585 		break;
2586 	case BZ:		/* cubic bezier curve, absolute control points */
2587 		bezier(FALSE, hd);
2588 		break;
2589 	case AC:		/* anchor corner of fill patterns */
2590 		if (read_float(&ftmp, hd)) {	/* just AC - default hard-clip limit */
2591 			anchor.x = P1.x;
2592 			anchor.y = P1.y;
2593 			if (scale_flag)
2594 				User_to_Plotter_coord(&anchor, &anchor);
2595 			break;
2596 		} else {
2597 			ac_flag = 1;
2598 			anchor.x = ftmp;
2599 		}
2600 		if (read_float(&ftmp, hd))
2601 			anchor.y = 0.;
2602 		else
2603 			anchor.y = ftmp;
2604 		if (scale_flag)
2605 			User_to_Plotter_coord(&anchor, &anchor);
2606 		break;
2607 	case AD:
2608 		if (read_float(&ftmp, hd))	/* just AD - defaults */
2609 			tp->altfont = 0;
2610 		else {
2611 			switch ((int) ftmp) {
2612 			case 1:	/* charset */
2613 				if (read_float(&csfont, hd))
2614 					par_err_exit(2, cmd, hd);
2615 				else
2616 					tp->altfont = (int) csfont;
2617 				break;
2618 			case 2:	/* fixed or variable spacing */
2619 				if (read_float(&csfont, hd))
2620 					par_err_exit(2, cmd, hd);
2621 				else if ((int) csfont == 1 && !silent_mode)
2622 					fprintf(stderr,
2623 						"only fixed fonts available\n");
2624 				break;
2625 			case 3:	/* font pitch */
2626 			case 4:	/* font height */
2627 			case 5:	/* posture */
2628 			case 6:	/* stroke weight */
2629 				if (read_float(&ftmp, hd))
2630 					par_err_exit(2, cmd, hd);
2631 				if (ftmp == 9999)
2632 					tp->astrokewidth = ftmp;
2633 				else {
2634 					if (ftmp < -7. || ftmp > 7.)
2635 						ftmp = 0.;
2636 					tp->astrokewidth = 0.11 + ftmp / 70.;	/* 0.01 ... 0.21 mm */
2637 				}
2638 				break;
2639 			case 7:	/* typeface */
2640 				if (read_float(&csfont, hd))
2641 					par_err_exit(2, cmd, hd);
2642 				else if (!silent_mode)
2643 					fprintf(stderr,
2644 						"pitch/height/posture/typeface unsupported\n");
2645 				break;
2646 			default:
2647 				par_err_exit(1, cmd, hd);
2648 			}
2649 		}
2650 		break;
2651 	case CA:		/* Alternate character set      */
2652 		if (read_float(&csfont, hd))	/* just CA;    */
2653 			tp->altfont = 0;
2654 		else
2655 			tp->altfont = (int) csfont;
2656 		break;
2657 	case CI:		/* Circle                       */
2658 		circles(hd);
2659 		break;
2660 	case CO:		/* Comment                      */
2661 		SafeTerm = StrTerm;
2662 		StrTerm = ';';
2663 		read_string(tmpstr, hd);
2664 		StrTerm = SafeTerm;
2665 		if (strlen(tmpstr) > 0)
2666 			tmpstr[strlen(tmpstr) - 1] = '\0';
2667 		if (!silent_mode)
2668 			printf("\n%s\n", tmpstr);
2669 		break;
2670 	case CR:		/* color range */
2671 		if (read_float(&ftmp, hd)) {
2672 			r_base = g_base = b_base = 0;
2673 			r_max = g_max = b_max = 255;
2674 			break;
2675 		} else {
2676 			r_base = (unsigned char) ftmp;
2677 		}
2678 		if (read_float(&ftmp, hd)) {
2679 			r_max = 255;
2680 			break;
2681 
2682 		} else {
2683 			r_max = (unsigned char) ftmp;
2684 		}
2685 		if (read_float(&ftmp, hd)) {
2686 			break;
2687 
2688 		} else {
2689 			g_base = (unsigned char) ftmp;
2690 		}
2691 		if (read_float(&ftmp, hd)) {
2692 			g_max = 255;
2693 			break;
2694 		} else {
2695 			g_max = (unsigned char) ftmp;
2696 		}
2697 		if (read_float(&ftmp, hd)) {
2698 			break;
2699 		} else {
2700 			b_base = (unsigned char) ftmp;
2701 		}
2702 		if (read_float(&ftmp, hd)) {
2703 			b_max = 255;
2704 			break;
2705 		} else {
2706 			b_max = (unsigned char) ftmp;
2707 			break;
2708 		}
2709 	case CS:		/*character set selection       */
2710 		if (read_float(&csfont, hd))	/* just CS;     */
2711 			tp->font = 0;
2712 		else
2713 			tp->font = (int) csfont;
2714 		tp->stdfont = tp->font;
2715 		break;
2716 	case CT:		/* chord tolerance */
2717 		if (read_float(&ftmp, hd) || ftmp != 1.)
2718 			ct_dist = FALSE;
2719 		else
2720 			ct_dist = TRUE;
2721 		break;
2722 	case EP:		/* edge polygon */
2723 		if (polygon_penup == TRUE)
2724 			if (p_last.x != polystart.x
2725 			    || p_last.y != polystart.y)
2726 				vertices -= 2;
2727 
2728 		for (i = 0; i < vertices; i = i + 2) {	/*for all polygon edges */
2729 			p1.x = polygons[i].x;
2730 			p1.y = polygons[i].y;
2731 			Pen_action_to_tmpfile(MOVE_TO, &p1, scale_flag);
2732 			p1.x = polygons[i + 1].x;
2733 			p1.y = polygons[i + 1].y;
2734 			Pen_action_to_tmpfile(DRAW_TO, &p1, scale_flag);
2735 		}
2736 		Pen_action_to_tmpfile(MOVE_TO, &p_last, scale_flag);
2737 		break;
2738 
2739 	case EW:		/* Edge Wedge                   */
2740 		wedges(hd);
2741 		break;
2742 
2743 	case EC:
2744 		/*  printf("cut paper\n"); */
2745 		break;
2746 
2747 	case FP:		/* fill polygon */
2748 		if (pg->nofill) {	/* treat like EP */
2749 			if (!silent_mode)
2750 				fprintf(stderr, "FP : suppressed\n");
2751 			for (i = 0; i < vertices; i = i + 2) {	/*for all polygon edges */
2752 				p1.x = polygons[i].x;
2753 				p1.y = polygons[i].y;
2754 				Pen_action_to_tmpfile(MOVE_TO, &p1,
2755 						      scale_flag);
2756 				p1.x = polygons[i + 1].x;
2757 				p1.y = polygons[i + 1].y;
2758 				Pen_action_to_tmpfile(DRAW_TO, &p1,
2759 						      scale_flag);
2760 			}
2761 			Pen_action_to_tmpfile(MOVE_TO, &p_last,
2762 					      scale_flag);
2763 			break;
2764 		}
2765 		if (hatchspace == 0.)
2766 			hatchspace = pt.width[pen];
2767 		if (filltype < 3 && thickness > 0.)
2768 			hatchspace = thickness;
2769 		if (!ac_flag) {	/* not yet initialized */
2770 			anchor.x = P1.x;
2771 			anchor.y = P1.y;
2772 		}
2773 		fill(polygons, vertices, anchor, P2, scale_flag, filltype,
2774 		     hatchspace, hatchangle);
2775 		Pen_action_to_tmpfile(MOVE_TO, &p_last, scale_flag);
2776 		break;
2777 	case FT:		/* Fill Type */
2778 		if (read_float(&ftmp, hd)) {	/* just FT -> FT=1 */
2779 			filltype = 1;
2780 			break;
2781 		} else {
2782 			filltype = (int) ftmp;
2783 		}
2784 		if (filltype < 3)
2785 			break;
2786 
2787 		if (filltype > 4) {
2788 			if (FoundUserFill == 0) {
2789 				FoundUserFill = 1;
2790 				if (!silent_mode)
2791 					fprintf(stderr,
2792 						"\nNo support for user-defined fill types, using type 1 instead\n");
2793 			}
2794 			filltype = 1;
2795 			break;
2796 		}
2797 
2798 		if (read_float(&ftmp, hd)) {
2799 			hatchspace = saved_hatchspace[filltype - 3];
2800 			if (hatchspace == 0.)
2801 				hatchspace = 0.01 * Diag_P1_P2;
2802 			hatchangle = saved_hatchangle[filltype - 3];
2803 			break;
2804 		} else {
2805 			if (ftmp <= 0.)
2806 				ftmp = 0.01 * Diag_P1_P2;
2807 			hatchspace = ftmp;
2808 			saved_hatchspace[filltype - 3] = hatchspace;
2809 		}
2810 		if (read_float(&ftmp, hd)) {
2811 			hatchangle = saved_hatchangle[filltype - 3];
2812 			break;
2813 		} else {
2814 			hatchangle = ftmp;
2815 			saved_hatchangle[filltype - 3] = hatchangle;
2816 		}
2817 		break;
2818 	case NP:		/* Number of Pens                    */
2819 		if (read_float(&ftmp, hd) || ftmp > NUMPENS)	/* invalid or missing */
2820 			break;
2821 		else {
2822 			pg->maxpens = (int) ftmp;
2823 			if (!silent_mode)
2824 				fprintf(stderr, "NP: %d pens requested\n",
2825 					pg->maxpens);
2826 		}
2827 		break;
2828 	case NR:		/*Not ready - pause plotter (noop) */
2829 		if (read_float(&ftmp, hd))
2830 			break;
2831 		break;
2832 	case PA:		/* Plot Absolute                */
2833 		lines(plot_rel = FALSE, hd);
2834 		tp->CR_point = HP_pos;
2835 		break;
2836 	case PC:		/* Pen Color                    */
2837 		if (read_float(&ftmp, hd) || fixedcolor || (int) ftmp > pg->maxpens) {	/* invalid or missing */
2838 			break;
2839 		} else {
2840 			mypen = (int) ftmp;
2841 			if (pg->mapzero == mypen)
2842 				break;
2843 			/* this color is remapped for pen 0, ignore original definition */
2844 			if (read_float(&ftmp, hd))	/* no red component  */
2845 				myred = 0;
2846 			else
2847 				myred = 255 * (ftmp - r_base) / r_max;
2848 			if (read_float(&ftmp, hd))	/* no green component  */
2849 				mygreen = 0;
2850 			else
2851 				mygreen = 255 * (ftmp - g_base) / g_max;
2852 			if (read_float(&ftmp, hd))	/* no blue component  */
2853 				myblue = 0;
2854 			else
2855 				myblue = 255 * (ftmp - b_base) / b_max;
2856 			pg->is_color = TRUE;
2857 			PlotCmd_to_tmpfile(DEF_PC);
2858 			if (mypen == 0 && pg->mapzero > -1)
2859 				mypen = pg->mapzero;
2860 			Pen_Color_to_tmpfile(mypen, myred, mygreen,
2861 					     myblue);
2862 			break;
2863 		}
2864 	case PD:		/* Pen  Down                    */
2865 		pen_down = TRUE;
2866 		lines(plot_rel, hd);
2867 		tp->CR_point = HP_pos;
2868 		break;
2869 	case PE:
2870 		read_PE(pg, hd);
2871 		tp->CR_point = HP_pos;
2872 		break;
2873 	case PM:
2874 		if (read_float(&ftmp, hd) || ftmp == 0) {	/* no parameters or PM0 */
2875 			polygon_mode = TRUE;
2876 			polygon_penup = FALSE;
2877 			saved_penstate = pen_down;
2878 			vertices = -1;
2879 			polystart = p_last;
2880 			break;
2881 		}
2882 		if (ftmp == 1) {
2883 			if (vertices > 0)
2884 				polygon_penup = TRUE;
2885 			pen_down = FALSE;
2886 			break;
2887 		}
2888 		if (ftmp == 2) {
2889 			polygon_mode = FALSE;
2890 			pen_down = saved_penstate;
2891 			if (p_last.x != polystart.x
2892 			    || p_last.y != polystart.y) {
2893 				int outside = 0;
2894 				double x1, y1, x2, y2;
2895 				if (iwflag) {
2896 					x1 = P1.x + (p_last.x -
2897 						     S1.x) * Q.x;
2898 					y1 = P1.y + (p_last.y -
2899 						     S1.y) * Q.y;
2900 					x2 = P1.x + (polystart.x -
2901 						     S1.x) * Q.x;
2902 					y2 = P1.y + (polystart.y -
2903 						     S1.y) * Q.y;
2904 
2905 					outside =
2906 					    (DtClipLine
2907 					     (C1.x, C1.y, C2.x, C2.y, &x1,
2908 					      &y1, &x2,
2909 					      &y2) == CLIP_NODRAW);
2910 
2911 					if (!outside) {
2912 						p_last.x =
2913 						    (x2 - P1.x) / Q.x +
2914 						    S1.x;
2915 						p_last.y =
2916 						    (y2 - P1.y) / Q.y +
2917 						    S1.y;
2918 						polystart.x =
2919 						    (x1 - P1.x) / Q.x +
2920 						    S1.x;
2921 						polystart.y =
2922 						    (y1 - P1.y) / Q.y +
2923 						    S1.y;
2924 					}
2925 				}
2926 				if (!outside) {
2927 					HPGL_Pt_to_polygon(p_last);
2928 					HPGL_Pt_to_polygon(polystart);	/* force closing of open polygon */
2929 				}
2930 			}
2931 		}
2932 		break;
2933 	case PR:		/* Plot Relative                */
2934 		lines(plot_rel = TRUE, hd);
2935 		tp->CR_point = HP_pos;
2936 		break;
2937 	case PS:
2938 		if (read_float(&ftmp, hd) || ftmp == 0.) {	/* no parameters or PS0; */
2939 			break;
2940 		} else {
2941 			myheight = ftmp;
2942 		}
2943 		if (read_float(&ftmp, hd)) {	/* no parameters */
2944 			mywidth = P2.y;
2945 		} else {
2946 			mywidth = ftmp;
2947 			if (mywidth > myheight) {
2948 				mywidth = myheight;
2949 				myheight = ftmp;
2950 			}
2951 		}
2952 		if (pg->no_ps == TRUE) {
2953 			if (!silent_mode)
2954 				Eprintf("PS: suppressed\n");
2955 			break;
2956 		}
2957 		ps_flag = 1;
2958 /*      fprintf(stderr,"min,max vor PS: %f %f %f %f\n",xmin,ymin,xmax,ymax);*/
2959 		M.x = myheight;
2960 		M.y = mywidth;
2961 		p1.x = 0;
2962 		p1.y = 0;
2963 
2964 		if (scale_flag)	/* Rescaling    */
2965 			User_to_Plotter_coord(&p1, &p2);
2966 		else
2967 			p2 = p1;	/* Local copy   */
2968 		if (rotate_flag) {	/* hp2xx-specific global rotation       */
2969 			ftmp = rot_cos * p2.x - rot_sin * p2.y;
2970 			p2.y = rot_sin * p2.x + rot_cos * p2.y;
2971 			p2.x = ftmp;
2972 		}
2973 		xmin = MIN(p2.x, xmin);
2974 		ymin = MIN(p2.y, ymin);
2975 		xmax = MAX(p2.x, xmax);
2976 		ymax = MAX(p2.y, ymax);
2977 
2978 		p1.x = myheight;
2979 		p1.y = mywidth;
2980 		if (scale_flag)	/* Rescaling    */
2981 			User_to_Plotter_coord(&p1, &p2);
2982 		else
2983 			p2 = p1;	/* Local copy   */
2984 		if (rotate_flag) {	/* hp2xx-specific global rotation       */
2985 			ftmp = rot_cos * p2.x - rot_sin * p2.y;
2986 			p2.y = rot_sin * p2.x + rot_cos * p2.y;
2987 			p2.x = ftmp;
2988 		}
2989 		xmin = MIN(p2.x, xmin);
2990 		ymin = MIN(p2.y, ymin);
2991 		xmax = MAX(p2.x, xmax);
2992 		ymax = MAX(p2.y, ymax);
2993 /*      fprintf(stderr,"min,max vor PS: %f %f %f %f\n",xmin,ymin,xmax,ymax);*/
2994 
2995 /* add the following - to get the correct linetype scale etc */
2996 		P1.x = 0.;
2997 		P1.y = 0.;
2998 		P2.x = myheight;
2999 		P2.y = mywidth;
3000 		if (rotate_flag) {
3001 			P2.x = mywidth;
3002 			P2.y = myheight;
3003 		}
3004 		Diag_P1_P2 = HYPOT(P2.x - P1.x, P2.y - P1.y);
3005 		CurrentLinePatLen = 0.04 * Diag_P1_P2;
3006 		S1 = P1;
3007 		S2 = P2;
3008 /* ajb */
3009 		break;
3010 	case PT:		/* Pen thickness (for solid fills - current pen only */
3011 		if (read_float(&ftmp, hd)) {	/* no parameters */
3012 			thickness = 0.3;
3013 			break;
3014 		} else {
3015 			if (ftmp >= 0.1 && ftmp <= 5.)
3016 				thickness = ftmp;
3017 		}
3018 	case PU:		/* Pen  Up                      */
3019 		pen_down = FALSE;
3020 		if (polygon_mode)
3021 			polygon_penup = TRUE;
3022 		lines(plot_rel, hd);
3023 		tp->CR_point = HP_pos;
3024 		break;
3025 	case PW:		/* Pen Width                    */
3026 		if (fixedwidth) {
3027 			if (!silent_mode)
3028 				fprintf(stderr,
3029 					"PW: ignored (hardware mode)\n");
3030 			break;
3031 		}
3032 		if (read_float(&ftmp, hd)) {	/* no parameters -> set defaults */
3033 			mywidth = 0.35;
3034 /* FIXME - scaling here ! */
3035 			if (wu_relative)
3036 				mywidth = Diag_P1_P2 / 1000.;
3037 			if (mywidth < 0.1)
3038 				mywidth = 0.1;
3039 			PlotCmd_to_tmpfile(DEF_PW);
3040 			Pen_Width_to_tmpfile(0, mywidth);
3041 /*
3042           fprintf(stderr,"PW: defaulting to 0.35 for all pens\n");
3043 */
3044 			break;
3045 		} else {
3046 			mywidth = ftmp;	/* first or only parameter is width */
3047 			if (wu_relative)
3048 				mywidth = Diag_P1_P2 * ftmp / 1000.;
3049 			if (mywidth < 0.1)
3050 				mywidth = 0.1;
3051 		}
3052 
3053 		if (read_float(&ftmp, hd)) {	/* width only, applies to all pens */
3054 			PlotCmd_to_tmpfile(DEF_PW);
3055 			Pen_Width_to_tmpfile(0, mywidth);
3056 			if (pg->maxpensize < mywidth)
3057 				pg->maxpensize = mywidth;
3058 /*
3059           fprintf(stderr,"PW: defaulting to %f for all pens\n",mywidth);
3060 */
3061 		} else {	/* second parameter is pen */
3062 			PlotCmd_to_tmpfile(DEF_PW);
3063 			Pen_Width_to_tmpfile((int) ftmp, mywidth);
3064 			if ((int) ftmp <= pg->maxpens) {
3065 				if (pg->maxpensize < mywidth)
3066 					pg->maxpensize = mywidth;
3067 			}
3068 /*
3069          fprintf(stderr,"pen%d, size now %f\n",(int) ftmp,mywidth);
3070 */
3071 		}
3072 		break;
3073 	case TL:		/* Tick Length                  */
3074 		if (read_float(&ftmp, hd)) {	/* No number found  */
3075 			neg_ticklen = pos_ticklen = 0.005;
3076 			return;
3077 		} else
3078 			pos_ticklen = ftmp / 100.0;
3079 
3080 		if (read_float(&ftmp, hd)) {	/* pos, but not neg */
3081 			neg_ticklen = 0.0;
3082 			return;
3083 		} else
3084 			neg_ticklen = ftmp / 100.0;
3085 		break;
3086 	case WG:		/* Filled Wedge                 */
3087 		fwedges(hd, pt.width[pen]);
3088 		break;
3089 	case WU:		/* pen Width Unit is relative  */
3090 		if (read_float(&ftmp, hd) || ftmp == 0.)	/* Zero or no number  */
3091 			wu_relative = FALSE;
3092 		else
3093 			wu_relative = TRUE;
3094 		break;
3095 	case XT:		/* X Tick                       */
3096 		ax_ticks(0);
3097 		break;
3098 	case YT:		/* Y Tick                       */
3099 		ax_ticks(1);
3100 		break;
3101 
3102 
3103 	case IP:		/* Input reference Points P1,P2 */
3104 		tp->width /= (P2.x - P1.x);
3105 		tp->height /= (P2.y - P1.y);
3106 		if (read_float(&p1.x, hd)) {	/* No number found  */
3107 			P1.x = P1X_default;
3108 			P1.y = P1Y_default;
3109 			P2.x = P2X_default;
3110 			P2.y = P2Y_default;
3111 			goto IP_Exit;
3112 		}
3113 		if (read_float(&p1.y, hd))	/* x without y! */
3114 			par_err_exit(2, cmd, hd);
3115 
3116 		if (read_float(&p2.x, hd)) {	/* No number found  */
3117 			P2.x += p1.x - P1.x;
3118 			P2.y += p1.y - P1.y;
3119 			P1 = p1;
3120 			goto IP_Exit;
3121 		}
3122 		if (read_float(&p2.y, hd))	/* x without y! */
3123 			par_err_exit(4, cmd, hd);
3124 
3125 		P1 = p1;
3126 		P2 = p2;
3127 
3128 	      IP_Exit:
3129 		S1 = P1;
3130 		S2 = P2;
3131 		Q.x = (P2.x - P1.x) / (S2.x - S1.x);
3132 		Q.y = (P2.y - P1.y) / (S2.y - S1.y);
3133 		Diag_P1_P2 = HYPOT(P2.x - P1.x, P2.y - P1.y);
3134 		CurrentLinePatLen = 0.04 * Diag_P1_P2;
3135 		tp->width *= (P2.x - P1.x);
3136 		tp->height *= (P2.y - P1.y);
3137 		adjust_text_par();
3138 		return;
3139 
3140 	case IR:		/* input reference points P1,P2 as percentages of defaults */
3141 		if (read_float(&p1.x, hd))	/* No number found  */
3142 			return;	/* keep defaults */
3143 		if (read_float(&p1.y, hd))	/* x without y! */
3144 			par_err_exit(2, cmd, hd);
3145 
3146 /*fprintf(stderr,"P1,P2 vor IR: %f %f, %f %f\n",P1.x,P1.y,P2.x,P2.y);*/
3147 
3148 		mywidth = P2.x - P1.x;
3149 		myheight = P2.y - P1.y;
3150 		ftmp = p1.x;
3151 		p1.x = P1.x;	/* need old value for computation of new P2 */
3152 		P1.x = p1.x + ftmp / 100. * mywidth;
3153 		ftmp = p1.y;
3154 		p1.y = P1.y;
3155 		P1.y = p1.y + ftmp / 100. * myheight;
3156 
3157 		if (read_float(&p2.x, hd)) {	/* No number found  */
3158 			P2.x = P1.x + mywidth;	/* P2 tracks new P1 too keep constant size */
3159 			P2.y = P1.y + myheight;
3160 /*fprintf(stderr,"P1,P2 nach IR: %f %f, %f %f\n",P1.x,P1.y,P2.x,P2.y);*/
3161 			return;
3162 		}
3163 		if (read_float(&p2.y, hd))	/* x without y! */
3164 			par_err_exit(4, cmd, hd);
3165 
3166 		P2.x = p1.x + p2.x / 100. * mywidth;
3167 		P2.y = p1.y + p2.y / 100. * myheight;
3168 		if (P1.x == P2.x)
3169 			P2.x = P2.x + 1.;
3170 		if (P1.y == P2.y)
3171 			P2.y = P2.y + 1.;
3172 		fprintf(stderr, "P1,P2 nach IR: %f %f, %f %f\n", P1.x,
3173 			P1.y, P2.x, P2.y);
3174 		Q.x = (P2.x - P1.x) / (S2.x - S1.x);
3175 		Q.y = (P2.y - P1.y) / (S2.y - S1.y);
3176 		Diag_P1_P2 = HYPOT(P2.x - P1.x, P2.y - P1.y);
3177 		CurrentLinePatLen = 0.04 * Diag_P1_P2;
3178 		tp->width *= (P2.x - P1.x);
3179 		tp->height *= (P2.y - P1.y);
3180 		adjust_text_par();
3181 		return;
3182 
3183 	case IW:
3184 		iwflag = 1;
3185 		if (read_float(&C1.x, hd)) {	/* No number found  */
3186 			if (P1.x == P1X_default && P1.y == P1Y_default
3187 			    && P2.x == P2X_default
3188 			    && P2.y == P2Y_default) {
3189 				iwflag = 0;
3190 				break;
3191 			}
3192 			C1 = P1;
3193 			C2 = P2;
3194 			if (scale_flag) {
3195 				C1 = S1;
3196 				C2 = S2;
3197 			}
3198 			if (rotate_flag && !ps_flag) {
3199 				switch ((int) fabs(rot_tmp)) {
3200 				case 90:
3201 				case 270:
3202 					ftmp = C1.x;
3203 					C1.x = C1.y;
3204 					C1.y = ftmp;
3205 					ftmp = C2.x;
3206 					C2.x = C2.y;
3207 					C2.y = ftmp;
3208 					break;
3209 				default:
3210 					break;
3211 				}
3212 			}
3213 		} else {
3214 			if (read_float(&C1.y, hd))	/* x without y! */
3215 				par_err_exit(2, cmd, hd);
3216 			if (read_float(&C2.x, hd))	/* No number found  */
3217 				par_err_exit(3, cmd, hd);
3218 			if (read_float(&C2.y, hd))	/* x without y! */
3219 				par_err_exit(4, cmd, hd);
3220 		}
3221 /*fprintf (stderr," clip limits (%f,%f)(%f,%f)\n",C1.x,C1.y,C2.x,C2.y);*/
3222 
3223 		if (scale_flag) {
3224 			User_to_Plotter_coord(&C1, &C1);
3225 			User_to_Plotter_coord(&C2, &C2);
3226 		}
3227 
3228 
3229 		if (C2.x < C1.x) {
3230 			ftmp = C2.x;
3231 			C2.x = C1.x;
3232 			C1.x = ftmp;
3233 		}
3234 		if (C2.y < C1.y) {
3235 			ftmp = C2.y;
3236 			C2.y = C1.y;
3237 			C1.y = ftmp;
3238 		}
3239 
3240 		C1.x -= pg->extraclip;
3241 		C1.y -= pg->extraclip;
3242 		C2.x += pg->extraclip;
3243 		C2.y += pg->extraclip;
3244 
3245 		break;
3246 
3247 	case OP:		/* Output reference Points P1,P2 */
3248 		if (!silent_mode) {
3249 			Eprintf("\nP1 = (%g, %g)\n", P1.x, P1.y);
3250 			Eprintf("P2 = (%g, %g)\n", P2.x, P2.y);
3251 		}
3252 		break;
3253 	case OW:		/* Output clip box  */
3254 		if (!silent_mode) {
3255 			Eprintf("\nC1 = (%g, %g)\n", C1.x, C1.y);
3256 			Eprintf("C2 = (%g, %g)\n", C2.x, C2.y);
3257 		}
3258 		break;
3259 
3260 	case AF:
3261 	case AH:
3262 	case PG:		/* new PaGe                     */
3263 		/* record ON happens only once! */
3264 		page_number++;
3265 /*		fprintf(stderr, "PG: page_number now %d\n", page_number);*/
3266 		record_off = (first_page > page_number)
3267 		    || ((last_page < page_number) && (last_page > 0));
3268 		pg_flag = TRUE;
3269 		return;
3270 		break;
3271 
3272 	case EA:		/* Edge Rectangle absolute */
3273 		rects(plot_rel = FALSE, 0, pt.width[pen], hd);
3274 		tp->CR_point = HP_pos;
3275 		break;
3276 
3277 	case ER:		/* Edge Rectangle relative */
3278 		rects(TRUE, 0, 0., hd);
3279 		tp->CR_point = HP_pos;
3280 		break;
3281 
3282 	case RA:		/* Fill Rectangle absolute */
3283 		rects(plot_rel = FALSE, 1, pt.width[pen], hd);
3284 		tp->CR_point = HP_pos;
3285 		break;
3286 
3287 	case RR:		/* Fill Rectangle relative */
3288 		rects(plot_rel = TRUE, 1, pt.width[pen], hd);
3289 		tp->CR_point = HP_pos;
3290 		break;
3291 
3292 	case RT:		/* Relative arc, through Three points */
3293 		tarcs(TRUE, hd);
3294 		break;
3295 
3296 	case LT:		/* Line Type:                   */
3297 		if (read_float(&p1.x, hd))	/* just LT;     */
3298 			CurrentLineType = LT_solid;
3299 		else {
3300 			if ((((int) p1.x) >= LT_MIN)
3301 			    && (((int) p1.x) < LT_ZERO))
3302 				CurrentLineType = LT_adaptive;
3303 			else if (((int) p1.x) == LT_ZERO)
3304 				CurrentLineType = LT_plot_at;
3305 			else if ((((int) p1.x) > LT_ZERO)
3306 				 && (((int) p1.x) <= LT_MAX))
3307 				CurrentLineType = LT_fixed;
3308 			else {
3309 				Eprintf("Illegal line type:\t%d\n",
3310 					(int) p1.x);
3311 				CurrentLineType = LT_solid;	/* set to something sane */
3312 			}
3313 			CurrentLinePattern = (int) p1.x;
3314 
3315 			if (!read_float(&p1.y, hd)) {	/* optional pattern length?     */
3316 				if (p1.y <= 0.0)
3317 					Eprintf
3318 					    ("Illegal pattern length:\t%g\n",
3319 					     p1.y);
3320 				else {
3321 					Diag_P1_P2 =
3322 					    HYPOT(P2.x - P1.x,
3323 						  P2.y - P1.y);
3324 
3325 					if (!read_float(&ftmp, hd)) {
3326 						if (ftmp == 1.0) {
3327 							CurrentLinePatLen = p1.y * 40;	/* absolute */
3328 						} else {
3329 							CurrentLinePatLen = Diag_P1_P2 * p1.y / 100.0;	/* relative */
3330 						}
3331 					} else {
3332 						CurrentLinePatLen = Diag_P1_P2 * p1.y / 100.0;	/* relative */
3333 					}
3334 				}
3335 			}
3336 		}
3337 
3338 		break;
3339 
3340 	case SC:		/* Input Scale Points S1,S2     */
3341 		User_to_Plotter_coord(&p_last, &p_last);
3342 		if (read_float(&p1.x, hd)) {	/* No number found  */
3343 			S1.x = P1X_default;
3344 			S1.y = P1Y_default;
3345 			S2.x = P2X_default;
3346 			S2.y = P2Y_default;
3347 			scale_flag = FALSE;
3348 			Q.x = Q.y = 1.0;
3349 			break;
3350 		}
3351 		if (read_float(&p2.x, hd))	/* x without y! */
3352 			par_err_exit(2, cmd, hd);
3353 		if (read_float(&p1.y, hd))	/* No number found  */
3354 			par_err_exit(3, cmd, hd);
3355 		if (read_float(&p2.y, hd))	/* x without y! */
3356 			par_err_exit(4, cmd, hd);
3357 
3358 		if (p1.x == p2.x || p1.y == p2.y) {	/* min must differ from max */
3359 			if (!silent_mode)
3360 				Eprintf
3361 				    ("Warning: Invalid SC command parameters -- ignored\n");
3362 			Q.x = Q.y = 1.0;
3363 			break;
3364 		}
3365 		S1.x = p1.x;
3366 		S1.y = p1.y;
3367 		S2.x = p2.x;
3368 		S2.y = p2.y;
3369 		if (read_float(&ftmp, hd))
3370 			ftmp = 0;	/*scaling defaults to type 0 */
3371 		switch ((int) ftmp) {
3372 		case 0:	/* anisotropic scaling */
3373 			Q.x = (P2.x - P1.x) / (S2.x - S1.x);
3374 			Q.y = (P2.y - P1.y) / (S2.y - S1.y);
3375 			break;
3376 
3377 		case 1:	/* isotropic scaling */
3378 			if (read_float(&ftmp, hd))	/* percentage of unused space on the left */
3379 				ftmp = 50.0;	/* of the isotropic area defaults to 50%  */
3380 			Q.x = (P2.x - P1.x) / (S2.x - S1.x);
3381 			Q.y = (P2.y - P1.y) / (S2.y - S1.y);
3382 			if (Q.x < Q.y) {
3383 				if (read_float(&ftmp, hd))
3384 					ftmp = 50.0;	/* percentage of unused space below the plot */
3385 				S1.y +=
3386 				    ftmp * ((P2.y - P1.y) / Q.y -
3387 					    (P2.y - P1.y) / Q.x) / 100.0;
3388 				Q.y = Q.x;
3389 				S2.y = S1.y + (P2.y - P1.y) / Q.y;
3390 			} else {
3391 				S1.x +=
3392 				    ftmp * ((P2.x - P1.x) / Q.x -
3393 					    (P2.x - P1.x) / Q.y) / 100.0;
3394 				read_float(&ftmp, hd);	/* mandatory 'bottom' value is unused */
3395 				Q.x = Q.y;
3396 				S2.x = S1.x + (P2.x - P1.x) / Q.x;
3397 			}
3398 			break;
3399 		case 2:	/* point factor scaling */
3400 			Q.x = S2.x;
3401 			Q.y = S2.y;
3402 			S2.x = S1.x + (P2.x - P1.x) / Q.x;
3403 			S2.y = S1.y + (P2.y - P1.y) / Q.y;
3404 			break;
3405 		default:
3406 			par_err_exit(0, cmd, hd);
3407 		}
3408 		scale_flag = TRUE;
3409 		Plotter_to_User_coord(&p_last, &p_last);
3410 		break;
3411 
3412 	case SP:		/* Select pen: none/0, or number */
3413 		old_pen = pen;
3414 		thickness = 0.;	/* clear any PT setting (should we default to 0.3 here ??) */
3415 		if (read_float(&p1.x, hd))	/* just SP;     */
3416 			pen = 0;
3417 		else {
3418 			pen = (short) p1.x;
3419 			if (pen == 0 && pg->mapzero > -1)
3420 				pen = pg->mapzero;
3421 		}
3422 		if (pen < 0 || (int) pen > pg->maxpens) {
3423 			Eprintf
3424 			    ("\nIllegal pen number %d: replaced by %d\n",
3425 			     pen, pen % pg->maxpens);
3426 			n_unexpected++;
3427 			pen = pen % pg->maxpens;
3428 		}
3429 		if (old_pen != pen) {
3430 			if ((fputc(SET_PEN, td) == EOF)
3431 			    || (fputc(pen, td) == EOF)) {
3432 				PError("Writing to temporary file:");
3433 				Eprintf("Error @ Cmd %ld\n", vec_cntr_w);
3434 				exit(ERROR);
3435 			}
3436 		}
3437 		if (pen)
3438 			pens_in_use[pen] = 1;
3439 		pg->maxcolor = MAX(pg->maxcolor, (int) pen);
3440 /*              pens_in_use |= (1 << (pen-1)); */
3441 		break;
3442 
3443 	case BP:		/* Begin Plot */
3444 		for (;;) {
3445 			if (read_float(&ftmp, hd)) {	/* No number found */
3446 				break;
3447 			} else {
3448 				switch ((int) ftmp) {
3449 				case 1:	/* picture name follows */
3450 					tmpstr[0] = fgetc(hd);	/* skip comma */
3451 					tmpstr[0] = fgetc(hd);
3452 					if (!silent_mode)
3453 						fprintf(stderr,
3454 							"HPGL picture name: %c",
3455 							tmpstr[0]);
3456 					if (tmpstr[0] == '"') {
3457 						tmpstr[0] = ' ';
3458 						do {
3459 							tmpstr[0] =
3460 							    fgetc(hd);
3461 							if (!silent_mode)
3462 								fputc
3463 								    (tmpstr
3464 								     [0],
3465 								     stderr);
3466 						}
3467 						while (tmpstr[0] != '"');
3468 					}
3469 					if (!silent_mode)
3470 						fprintf(stderr, "\n");
3471 					break;
3472 				case 2:	/* number of copies */
3473 				case 3:	/* disposition code */
3474 				case 4:	/* render unfinished */
3475 				case 5:	/* autorotation */
3476 					if (read_float(&ftmp, hd))
3477 						break;
3478 					break;
3479 				default:
3480 					break;
3481 				}
3482 			}
3483 		}
3484 		/* fall through to initialization code now */
3485 	case DF:		/* Set to default               */
3486 	case IN:		/* Initialize */
3487 		reset_HPGL();
3488 		tp->CR_point = HP_pos;
3489 		break;
3490 	case RO:
3491 		if (read_float(&ftmp, hd)) {	/* No number found  */
3492 			break;
3493 		} else {
3494 			/*if (!silent_mode)
3495 			   fprintf (stderr, "RO encountered, rotating P1,P2 by %f\n", ftmp);
3496 			 */
3497 			rotate_flag = 1;
3498 			rot_ang += ftmp;
3499 			rot_tmp = ftmp;
3500 			switch ((int) ftmp) {
3501 			case 90:
3502 			case 270:
3503 				ftmp = M.x;
3504 				M.x = M.y;
3505 				M.y = ftmp;
3506 				break;
3507 			case 0:
3508 			case 180:
3509 				break;
3510 			default:
3511 				rotate_flag = 0;
3512 				break;
3513 			}
3514 
3515 			/* if (!silent_mode)
3516 			   fprintf (stderr, "cumulative rot_ang now %f\n", rot_ang); */
3517 			rot_cos = cos(M_PI * rot_ang / 180.0);
3518 			rot_sin = sin(M_PI * rot_ang / 180.0);
3519 
3520 			if (ps_flag) {	/* transform extents from previous PS statement */
3521 
3522 				xmin = 1e10;
3523 				ymin = 1e10;
3524 				xmax = 1e-10;
3525 				ymax = 1e-10;
3526 
3527 				p1.x = 0;
3528 				p1.y = 0;
3529 				if (scale_flag)	/* Rescaling    */
3530 					User_to_Plotter_coord(&p1, &p2);
3531 				else
3532 					p2 = p1;	/* Local copy   */
3533 				HP_pos = p2;	/* Actual plotter pos. in plotter coord */
3534 				ftmp = rot_cos * p2.x - rot_sin * p2.y;
3535 				p2.y = rot_sin * p2.x + rot_cos * p2.y;
3536 				p2.x = ftmp;
3537 				xmin = MIN(p2.x, xmin);
3538 				ymin = MIN(p2.y, ymin);
3539 				xmax = MAX(p2.x, xmax);
3540 				ymax = MAX(p2.y, ymax);
3541 				p1.x = M.x;
3542 				p1.y = M.y;
3543 				if (scale_flag)	/* Rescaling    */
3544 					User_to_Plotter_coord(&p1, &p2);
3545 				else
3546 					p2 = p1;	/* Local copy   */
3547 				HP_pos = p2;	/* Actual plotter pos. in plotter coord */
3548 				ftmp = rot_cos * p2.x - rot_sin * p2.y;
3549 				p2.y = rot_sin * p2.x + rot_cos * p2.y;
3550 				p2.x = ftmp;
3551 				xmin = MIN(p2.x, xmin);
3552 				ymin = MIN(p2.y, ymin);
3553 				xmax = MAX(p2.x, xmax);
3554 				ymax = MAX(p2.y, ymax);
3555 			}
3556 		}
3557 		break;
3558 	case BL:		/* Buffer label string          */
3559 		read_string(strbuf, hd);
3560 		break;
3561 	case CP:		/* Char Plot (rather: move)     */
3562 		if (read_float(&p1.x, hd)) {	/* No number found  */
3563 			plot_string("\n\r", LB_direct, pen);
3564 			return;
3565 		} else if (read_float(&p1.y, hd))
3566 			par_err_exit(2, cmd, hd);
3567 
3568 		p2.x =
3569 		    p1.x * tp->chardiff.x - p1.y * tp->linediff.x +
3570 		    HP_pos.x;
3571 		p2.y =
3572 		    p1.x * tp->chardiff.y - p1.y * tp->linediff.y +
3573 		    HP_pos.y;
3574 		Pen_action_to_tmpfile(MOVE_TO, &p2, FALSE);
3575 		break;
3576 	case DI:		/* Char plot Dir (absolute)     */
3577 		if (read_float(&p1.x, hd)) {	/* No number found  */
3578 			tp->dir = 0.0;
3579 			tp->CR_point = HP_pos;
3580 			adjust_text_par();
3581 			break;
3582 		}
3583 		if (read_float(&p1.y, hd))	/* x, but not y */
3584 			par_err_exit(2, cmd, hd);
3585 		if ((p1.x == 0.0) && (p1.y == 0.0))
3586 			par_err_exit(0, cmd, hd);
3587 		tp->dir = atan2(p1.y, p1.x);
3588 		tp->CR_point = HP_pos;
3589 		adjust_text_par();
3590 		break;
3591 	case DR:		/* Char plot Dir (rel P1,P2)    */
3592 		if (read_float(&p1.x, hd)) {	/* No number found  */
3593 			tp->dir = 0.0;
3594 			tp->CR_point = HP_pos;
3595 			adjust_text_par();
3596 			break;
3597 		}
3598 		if (read_float(&p1.y, hd))
3599 			par_err_exit(2, cmd, hd);	/* x, but not y */
3600 		if ((p1.x == 0.0) && (p1.y == 0.0))
3601 			par_err_exit(0, cmd, hd);
3602 		tp->dir =
3603 		    atan2(p1.y * (P2.y - P1.y), p1.x * (P2.x - P1.x));
3604 		tp->CR_point = HP_pos;
3605 		adjust_text_par();
3606 		break;
3607 	case DT:		/* Define string terminator     */
3608 		StrTerm = getc(hd);
3609 		if (StrTerm == ';') {	/*just DT */
3610 			StrTerm = ETX;
3611 			StrTermSilent = 1;
3612 			break;
3613 		}
3614 		if (read_float(&ftmp, hd)) {
3615 			StrTermSilent = 1;
3616 		} else
3617 			StrTermSilent = (short) ftmp;
3618 		break;
3619 	case DV:		/* Text direction vertical      */
3620 		if (read_float(&ftmp, hd) || ftmp == 0)
3621 			mode_vert = 0;
3622 		else
3623 			mode_vert = 1;
3624 		break;
3625 	case ES:		/* Extra Space                  */
3626 		if (read_float(&tp->espace, hd)) {	/* No number found */
3627 			tp->espace = 0.0;
3628 			tp->eline = 0.0;
3629 		} else if (read_float(&tp->eline, hd))
3630 			tp->eline = 0.0;	/* Supply default       */
3631 		adjust_text_par();
3632 		break;
3633 	case LA:		/* Line Attributes */
3634 		set_line_attr(hd);
3635 		break;
3636 	case LB:		/* Label string                 */
3637 		read_string(strbuf, hd);
3638 		plot_string(strbuf, LB_direct, pen);
3639 		/*
3640 		 * Bug fix by W. Eric Norum:
3641 		 * Update the position so that subsequent `PR's will work.
3642 		 */
3643 		if (scale_flag)
3644 			Plotter_to_User_coord(&HP_pos, &p_last);
3645 		else
3646 			p_last = HP_pos;
3647 		break;
3648 	case LO:		/* Label Origin                 */
3649 		if (read_float(&p1.x, hd))	/* No number found */
3650 			tp->orig = 1;
3651 		else {
3652 			tp->orig = (int) p1.x;
3653 			if (tp->orig < 1 || tp->orig == 10
3654 			    || tp->orig > 19)
3655 				tp->orig = 1;	/* Error        */
3656 		}
3657 		adjust_text_par();
3658 		break;
3659 	case PB:		/* Plot Buffered label string   */
3660 		plot_string(strbuf, LB_buffered, pen);
3661 		break;
3662 	case SI:		/* Char cell Sizes (absolute)   */
3663 		if (read_float(&tp->width, hd)) {	/* No number found */
3664 			tp->width = 0.187;	/* [cm], A4     */
3665 			tp->height = 0.269;	/* [cm], A4     */
3666 		} else {
3667 			if (read_float(&tp->height, hd))
3668 				par_err_exit(2, cmd, hd);
3669 			if ((tp->width == 0.0) || (tp->height == 0.0))
3670 				par_err_exit(0, cmd, hd);
3671 		}
3672 		tp->width *= 400.0;	/* [cm] --> [plotter units]        */
3673 		tp->height *= 400.0;	/* [cm] --> [plotter units]        */
3674 		adjust_text_par();
3675 		break;
3676 	case SL:		/* Char Slant                   */
3677 		if (read_float(&tp->slant, hd))	/* No number found     */
3678 			tp->slant = 0.0;
3679 		adjust_text_par();
3680 		break;
3681 	case SM:		/* Symbol Mode                  */
3682 		read_symbol_char(hd);
3683 		break;
3684 	case SR:		/* Character  sizes (Rel P1,P2) */
3685 		if (read_float(&tp->width, hd)) {	/* No number found */
3686 			tp->width = 0.75;	/* % of (P2-P1)_x    */
3687 			tp->height = 1.5;	/* % of (P2-P1)_y    */
3688 		} else {
3689 			if (read_float(&tp->height, hd))
3690 				par_err_exit(2, (short) cmd, hd);
3691 			if ((tp->width == 0.0) || (tp->height == 0.0))
3692 				par_err_exit(0, (short) cmd, hd);
3693 		}
3694 		tp->width *= (P2.x - P1.x) / 100.0;	/* --> [pl. units]     */
3695 		tp->height *= (P2.y - P1.y) / 100.0;
3696 		adjust_text_par();
3697 		break;
3698 	case SA:		/* Select designated alternate charset */
3699 		if (tp->altfont)
3700 			tp->font = tp->altfont;
3701 		else		/* Was never designated, default to 0 */
3702 			tp->font = 0;
3703 		tp->strokewidth = tp->astrokewidth;
3704 		break;
3705 	case SD:
3706 		if (read_float(&ftmp, hd))	/* just SD - defaults */
3707 			tp->stdfont = 0;
3708 		else {
3709 			switch ((int) ftmp) {
3710 			case 1:	/* charset */
3711 				if (read_float(&csfont, hd))
3712 					par_err_exit(2, cmd, hd);
3713 				else
3714 					tp->stdfont = (int) csfont;
3715 				break;
3716 			case 2:	/* fixed or variable spacing */
3717 				if (read_float(&csfont, hd))
3718 					par_err_exit(2, cmd, hd);
3719 				else if ((int) csfont == 1 && !silent_mode)
3720 					fprintf(stderr,
3721 						"only fixed fonts available\n");
3722 				break;
3723 			case 3:	/* font pitch */
3724 			case 4:	/* font height */
3725 			case 5:	/* posture */
3726 			case 6:	/* stroke weight */
3727 				if (read_float(&ftmp, hd))
3728 					par_err_exit(2, cmd, hd);
3729 				if (ftmp == 9999)
3730 					tp->sstrokewidth = ftmp;
3731 				else {
3732 					if (ftmp < -7. || ftmp > 7.)
3733 						ftmp = 0.;
3734 					tp->sstrokewidth = 0.11 + ftmp / 70.;	/* 0.01 ... 0.21 mm */
3735 				}
3736 				break;
3737 			case 7:	/* typeface */
3738 				if (read_float(&csfont, hd))
3739 					par_err_exit(2, cmd, hd);
3740 				else if (!silent_mode)
3741 					fprintf(stderr,
3742 						"pitch/height/posture/typeface unsupported\n");
3743 				break;
3744 			default:
3745 				par_err_exit(1, cmd, hd);
3746 			}
3747 		}
3748 		break;
3749 	case SS:		/* Select designated standard character set */
3750 		if (tp->stdfont)
3751 			tp->font = tp->stdfont;
3752 		else		/* Was never designated, default to 0 */
3753 			tp->font = 0;
3754 		tp->strokewidth = tp->sstrokewidth;
3755 		break;
3756 	case UC:		/* User defined character       */
3757 		plot_user_char(hd, pen);
3758 		break;
3759 	case UL:		/* User defined line style      */
3760 		set_line_style_by_UL(hd);
3761 		break;
3762 	case MG:
3763 	case WD:		/* Write string to display      */
3764 		read_string(strbuf, hd);
3765 		if (!silent_mode)
3766 			Eprintf("\nLABEL: %s\n", strbuf);
3767 		break;
3768 	case VS:
3769 		if (read_float(&ftmp, hd))	/* Just VS */
3770 			break;
3771 		if (read_float(&ftmp, hd))	/* uniform speed */
3772 			break;
3773 		if (read_float(&ftmp, hd))	/* speed for given pen */
3774 			break;
3775 	default:		/* Skip unknown HPGL command: */
3776 		n_unknown++;
3777 		if (!silent_mode)
3778 			Eprintf("  %c%c: ignored  ", cmd >> 8, cmd & 0xFF);
3779 		if (cmd == EOF) {
3780 			n_unexpected++;
3781 			if (!silent_mode)
3782 				Eprintf("\nUnexpected EOF!\t");
3783 		}
3784 		break;
3785 	}
3786 }
3787 
3788 
read_HPGL(GEN_PAR * pg,const IN_PAR * pi)3789 void read_HPGL(GEN_PAR * pg, const IN_PAR * pi)
3790 /**
3791  ** This routine is the high-level entry for HP-GL processing.
3792  ** It reads the input stream character-by-character, identifies
3793  ** ESC. commands (device controls) and HP-GL mnemonics, reads
3794  ** parameters (if expected), and initiates processing of these
3795  ** commands. It finally reports on this parsing process.
3796  **/
3797 {
3798 	int c;
3799 	int cmd;
3800 
3801 	vec_cntr_r = 0L;
3802 	vec_cntr_w = 0L;
3803 	n_unexpected = 0;
3804 	n_commands = 0;
3805 	n_unknown = 0;
3806 
3807 	if ((c = getc(pi->hd)) == EOF)
3808 		return;
3809 	else
3810 		ungetc(c, pi->hd);
3811 
3812 	if (!pg_flag)
3813 		init_HPGL(pg, pi);
3814 
3815 	if (!pg->quiet)
3816 		Eprintf("\nReading HPGL file\n");
3817 
3818   /**
3819    ** MAIN parser LOOP!!
3820    **/
3821 	while ((c = getc(pi->hd)) != EOF) {
3822 		switch (c) {
3823 #ifdef MUTOH_KLUGE
3824 		case '\a':
3825 			Eprintf("Mutoh header found\n");
3826 			read_ESC_cmd(pi->hd, FALSE);	/* ESC sequence */
3827 			break;
3828 #endif
3829 		case ESC:
3830 			read_ESC_cmd(pi->hd, TRUE);	/* ESC sequence */
3831 			break;
3832 		default:
3833 			if ((c < 'A') || (c > 'z')
3834 			    || ((c > 'Z') && (c < 'a')))
3835 				break;
3836 			if (c == 'P') {
3837 				if ((cmd = getc(pi->hd)) == 'G') {
3838 					page_number++;
3839 /*		fprintf(stderr, "stream-reading PG: page_number now %d\n", page_number);*/
3840 					record_off =
3841 					    (first_page > page_number)
3842 					    || ((last_page < page_number)
3843 						&& (last_page > 0));
3844 					goto END;
3845 				} else {
3846 					if (cmd == EOF)
3847 						return;
3848 					ungetc(cmd, pi->hd);
3849 				}
3850 			}
3851 			if (c == 'N') {
3852 				if ((cmd = getc(pi->hd)) == 'R') {
3853 /*	  fprintf(stderr,"***NR***\n");'*/
3854 					page_number++;
3855 /*		fprintf(stderr, "stream-reading NR: page_number now %d\n", page_number);*/
3856 					record_off =
3857 					    (first_page > page_number)
3858 					    || ((last_page < page_number)
3859 						&& (last_page > 0));
3860 					goto END;
3861 				} else {
3862 					if (cmd == EOF)
3863 						return;
3864 					ungetc(cmd, pi->hd);
3865 				}
3866 			}
3867 			if (c == 'A') {
3868 				cmd = getc(pi->hd);
3869 				if (cmd == 'F' || cmd == 'H') {
3870 /*	  fprintf(stderr,"***AF/AH***\n");*/
3871 					page_number++;
3872 /*		fprintf(stderr, "stream-reading AF/AH: page_number now %d\n", page_number);*/
3873 					record_off =
3874 					    (first_page > page_number)
3875 					    || ((last_page < page_number)
3876 						&& (last_page > 0));
3877 					goto END;
3878 				} else {
3879 					if (cmd == EOF)
3880 						return;
3881 					ungetc(cmd, pi->hd);
3882 				}
3883 			}
3884 			cmd = c << 8;
3885 			if ((c = getc(pi->hd)) == EOF)
3886 				return;
3887 			if ((c < 'A') || (c > 'z')
3888 			    || ((c > 'Z') && (c < 'a'))) {
3889 				ungetc(c, pi->hd);
3890 				break;
3891 			}
3892 			cmd |= (c & 0xFF);
3893 			n_commands++;
3894 			read_HPGL_cmd(pg, cmd, pi->hd);
3895 		}
3896 	}
3897 	if (c == EOF) {
3898 		page_number++;
3899 /*			fprintf(stderr, "EOF : page_number now %d\n", page_number);*/
3900 	}
3901       END:
3902 	if (!pg->quiet && n_commands > 0) {
3903 		Eprintf("Page number %d of range %d - %d\n",
3904 			page_number - 1, pi->first_page, pi->last_page);
3905 		Eprintf("\nHPGL commands read: %d\n", n_commands);
3906 		Eprintf("HPGL command(s) ignored: %d\n", n_unknown);
3907 		Eprintf("Unexpected event(s):  %d\n", n_unexpected);
3908 		Eprintf("Internal command(s):  %ld\n", vec_cntr_w);
3909 		if ((pi->first_page > page_number - 1)
3910 		    || ((pi->last_page < page_number - 1)
3911 			&& (pi->last_page > 0))) {
3912 			n_commands = -1;
3913 			Eprintf
3914 			    ("Page %d not drawn (outside selected range %d-%d)\n",
3915 			     page_number - 1, pi->first_page,
3916 			     pi->last_page);
3917 		}
3918 		Eprintf("Pens used: ");
3919 /*      for (c=0; c < NUMPENS; c++, pens_in_use >>= 1)
3920    if (pens_in_use & 1)
3921  */
3922 		for (c = 0; c < NUMPENS; c++)
3923 			if (pens_in_use[c] == 1)
3924 				Eprintf("%d ", c);
3925 /*                      Eprintf ("%d ", c+1); */
3926 		Eprintf("\nMax. number of pages: %d\n", page_number - 1);
3927 	}
3928 }
3929 
3930 
3931 
3932 
3933 void
adjust_input_transform(const GEN_PAR * pg,const IN_PAR * pi,OUT_PAR * po)3934 adjust_input_transform(const GEN_PAR * pg, const IN_PAR * pi, OUT_PAR * po)
3935 {
3936 /**
3937  ** The temporary input data of the temp. file may be re-used multiple
3938  ** times by calling this function with varying parameters,
3939  ** mainly in pi.
3940  **
3941  ** Some conversion factors for transformation from HP-GL coordinates
3942  ** (as given in the temp. file) into mm or pel numbers are set here.
3943  ** There are both global parameters and elemts of po set here.
3944  ** DPI-related factors only apply if the current mode is a raster mode.
3945  **
3946  ** # points (dots) in any direction = range [mm] * 1in/25.4mm * #dots/in
3947  **/
3948 
3949 	double dot_ratio, Dx, Dy, tmp_w, tmp_h;
3950 	char *dir_str;
3951 
3952 	Dx = xmax - xmin;
3953 	Dy = ymax - ymin;
3954 	dot_ratio = (double) po->dpi_y / (double) po->dpi_x;
3955 	po->width = pi->width;
3956 	po->height = pi->height;
3957 	po->xoff = pi->xoff;
3958 	po->yoff = pi->yoff;
3959 
3960 	/* Width  assuming given height:      */
3961 	tmp_w = pi->height * Dx / Dy * pi->aspectfactor;
3962 /*  tmp_w     = pi->height * Dx / Dx / pi->aspectfactor; */
3963 	/* Height assuming given width:       */
3964 	tmp_h = pi->width * Dy / Dx / pi->aspectfactor;
3965 
3966   /**
3967    ** EITHER width OR height MUST be the correct limit. The other will
3968    ** be adapted. Adaptation of both is inconsistent, except in truesize mode.
3969    **/
3970 
3971 	if (pi->truesize) {
3972 		po->width = Dx / 40.0;	/* Ignore -w, take natural HP-GL range  */
3973 		po->height = Dy / 40.0;	/* Ignore -h, take natural HP-GL range  */
3974 		po->HP_to_xdots = (float) (po->dpi_x / 1016.0);	/* dots per HP unit */
3975 		po->HP_to_ydots = (float) (po->dpi_y / 1016.0);	/*  (1/40 mm)       */
3976 		dir_str = "true sizes";
3977 		if (pi->center_mode) {
3978 			if (!pg->quiet) {
3979 				fprintf(stderr,
3980 					"trying to center image\n");
3981 				fprintf(stderr,
3982 					"po->width ?<? tmp_w: %f %f\n",
3983 					po->width, tmp_w);
3984 				fprintf(stderr,
3985 					"po->height ?<? tmp_h: %f %f\n",
3986 					po->height, tmp_h);
3987 			}
3988 			if (po->width < tmp_w)
3989 				po->xoff += (tmp_w - po->width) / 2.0;
3990 			if (po->height < tmp_h)
3991 				po->yoff += (tmp_h - po->height) / 2.0;
3992 		}
3993 
3994 	} else {
3995 /*    if (po->width > tmp_w) */
3996 		if (Dy > Dx) {
3997 			po->HP_to_ydots =
3998 			    (float) (po->dpi_y * po->height) / Dy / 25.4;
3999 			po->HP_to_xdots =
4000 			    po->HP_to_ydots * pi->aspectfactor / dot_ratio;
4001 			if (pi->center_mode)
4002 				po->xoff += (po->width - tmp_w) / 2.0;	/* by L. Lowe   */
4003 			po->width = tmp_w;
4004 			dir_str = "width adapted";	/* Height fits, adjust width    */
4005 		} else {
4006 			po->HP_to_xdots =
4007 			    (float) (po->dpi_x * po->width) / Dx / 25.4;
4008 			po->HP_to_ydots =
4009 			    po->HP_to_xdots * dot_ratio / pi->aspectfactor;
4010 			if (pi->center_mode)
4011 				po->yoff += (po->height - tmp_h) / 2.0;	/* by L. Lowe   */
4012 			po->height = tmp_h;
4013 			dir_str = "height adapted";	/* Width  fits, adjust height   */
4014 		}
4015 	}
4016 
4017 	if (!pg->quiet) {
4018 		Eprintf("\nWidth  x  height: %5.2f x %5.2f mm, %s\n",
4019 			po->width, po->height, dir_str);
4020 		Eprintf("Coordinate range: (%g, %g) ... (%g, %g)\n",
4021 			xmin, ymin, xmax, ymax);
4022 	}
4023 
4024 	po->xmin = xmin;
4025 	po->xmax = xmax;
4026 	po->ymin = ymin;
4027 	po->ymax = ymax;
4028 }
4029 
4030 #ifdef EMF
reset_tmpfile(void)4031 void reset_tmpfile(void)
4032 {
4033 	(void) lseek(fileno(td), 0L, SEEK_SET);
4034 	if (vec_cntr_r)
4035 		again = TRUE;
4036 	vec_cntr_r = 0;
4037 }
4038 #endif
4039 
PlotCmd_from_tmpfile(void)4040 PlotCmd PlotCmd_from_tmpfile(void)
4041 {
4042 	PlotCmd cmd;
4043 
4044 	if (!silent_mode && !again)
4045 		switch (vec_cntr_r++) {
4046 		case 0:
4047 			Eprintf("\nProcessing Cmd: ");
4048 			break;
4049 		case 1:
4050 			Eprintf("1 ");
4051 			break;
4052 		case 2:
4053 			Eprintf("2 ");
4054 			break;
4055 		case 5:
4056 			Eprintf("5 ");
4057 			break;
4058 		case 10:
4059 			Eprintf("10 ");
4060 			break;
4061 		case 20:
4062 			Eprintf("20 ");
4063 			break;
4064 		case 50:
4065 			Eprintf("50 ");
4066 			break;
4067 		case 100:
4068 			Eprintf("100 ");
4069 			break;
4070 		case 200:
4071 			Eprintf("200 ");
4072 			break;
4073 		case 500:
4074 			Eprintf("500 ");
4075 			break;
4076 		case 1000:
4077 			Eprintf("1k ");
4078 			break;
4079 		case 2000:
4080 			Eprintf("2k ");
4081 			break;
4082 		case 5000:
4083 			Eprintf("5k ");
4084 			break;
4085 		case 10000:
4086 			Eprintf("10k ");
4087 			break;
4088 		case 20000:
4089 			Eprintf("20k ");
4090 			break;
4091 		case 50000L:
4092 			Eprintf("50k ");
4093 			break;
4094 		case 100000L:
4095 			Eprintf("100k ");
4096 			break;
4097 		case 200000L:
4098 			Eprintf("200k ");
4099 			break;
4100 		case 500000L:
4101 			Eprintf("500k ");
4102 			break;
4103 		}
4104 
4105 	switch (cmd = fgetc(td)) {
4106 	case NOP:
4107 	case MOVE_TO:
4108 	case DRAW_TO:
4109 	case PLOT_AT:
4110 	case SET_PEN:
4111 	case DEF_PW:
4112 	case DEF_PC:
4113 	case DEF_LA:
4114 		return cmd;
4115 	case (unsigned int) EOF:
4116 	default:
4117 		return CMD_EOF;
4118 	}
4119 }
4120 
4121 
4122 
HPGL_Pt_from_tmpfile(HPGL_Pt * pf)4123 void HPGL_Pt_from_tmpfile(HPGL_Pt * pf)
4124 {
4125 	if (fread((VOID *) pf, sizeof(*pf), 1, td) != 1) {
4126 		PError("HPGL_Pt_from_tmpfile");
4127 		Eprintf("Error @ Cmd %ld\n", vec_cntr_r);
4128 		exit(ERROR);
4129 	}
4130 	if (pf->x < xmin || pf->x > xmax)
4131 		Eprintf
4132 		    ("HPGL_Pt_from_tmpfile: x out of range (%g not in [%g, %g])\n",
4133 		     pf->x, xmin, xmax);
4134 	if (pf->y < ymin || pf->y > ymax)
4135 		Eprintf
4136 		    ("HPGL_Pt_from_tmpfile: y out of range (%g not in [%g, %g])\n",
4137 		     pf->y, ymin, ymax);
4138 }
4139