Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtinfo / dtinfo / src / cgm / cgmcmds.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: cgmcmds.c /main/12 1996/11/11 11:32:39 cde-hal $ */
24 /* module to process the CGM binary format commands */
25 /* optimised for calling XLib commands */
26 #include "cgm.h"                /* our defs */
27 #include <math.h>       /* math functions */
28 #include <stdio.h>      /* math functions */
29 /* everything is in C rather than C++ for portability */
30 /* means we must use some file-scope globals */
31 #define MAXCOLRS 1024 /* allow only this many colours for mapped devices */
32 static Display *display;
33 static Window win;
34 static int depth;
35 static Colormap cmap;
36 static Visual *vis;
37 static int visualClass, visualID, colormap_size, bits_per_rgb;
38 static unsigned long redMask, greenMask, blueMask;
39 static unsigned int visualDepth;
40 /* in case we need this for error messages */
41 static char *visualNames[6] = {"StaticGrey", "GrayScale", "StaticColor",
42                                "PseudoColor", "TrueColor", "DirectColor"};
43 static Dimension *ret_width;
44 static Dimension *ret_height;
45 static XColor my_colrs[MAXCOLRS];
46 static Pixel **ret_colrs;
47 static int *ret_number;
48 static float xScale;
49 static int max_size = 512, max_y, max_x;
50 static Pixmap P;
51 static Pixmap *retPixmap;
52 /* Graphics Contexts, and ancillaries */
53 static GC fillGC, edgeGC, textGC, markGC, lineGC, cellGC;
54 static XGCValues myStruct; /* for convenience */
55 static unsigned long mask;
56 static Pixel blackPixel, whitePixel;
57 static float xPxlMM, yPxlMM; /* pixels per mm */
58 static double pi;
59 static int setBackColr = 0; /* has the background colour been set ? */
60 /* index into this for dashed line specs */
61 static char lineArray[6] = {9, 9, 3, 3, 3, 3};
62 /* deal with Colour map */
63 #define COLCONV 65535.0 /* for conversion to XColors */
64 static Pixel coltabPixels[MAXCOLRS];
65 /* for clipping */
66 static Region clipRegion, extRegion;
67 /* for text */
68 static partialText *textPtr;
69 static int textW, textH, textX, textY;
70
71 /* EAM */
72 static float ScaleFactor;
73 /* now the Binary format specific routines that read the various data types */
74 /* all of these routines take the address of a pointer and step the pointer */
75 /* forward before they return */
76 /* the general Binary format string */
77 static b_str(unsigned char **in_ptr, char **out_ptr)
78 {
79   int p_len, data_left, i;
80   unsigned char *my_ptr;
81   
82   p_len = (int) *(*in_ptr)++;
83   if (p_len == 255) {   /* more to come */
84     data_left = (**in_ptr >> 7) && 1;
85     p_len = ((**in_ptr & 127) << 8) + (int) *(*in_ptr + 1);
86     *in_ptr += 2;       /* skip over this bit */
87     if (data_left) {            /* fix later */
88       burp(stderr, "truncating string at %d bytes\n", p_len);
89       return(CGM_WARN);
90     }
91   }
92   if (!(my_ptr = (unsigned char *) malloc(p_len + 1))) {
93     burp(stderr, "couldn't grab %d bytes in b_str\n", p_len + 1);
94     return(0);
95   }
96   *out_ptr = (char *) my_ptr;
97   for (i=0; i<p_len; ++i) *my_ptr++ = *(*in_ptr)++;
98   *my_ptr = (unsigned char) 0;
99   
100   return(1);
101 }
102 /* now the integers */
103 /* unsigned CGM integer at arbitrary legal precision */
104 static unsigned int b_guint(in_ptr, bits_p)
105      unsigned char **in_ptr;            /* pointer to the input data pointer */
106      int bits_p;                        /* no. of bits precision */
107 {
108   int i;
109   unsigned int val;
110   
111   val = *(*in_ptr)++;
112   for (i=1; i<(bits_p / 8); ++i)
113     val = (val << 8) | *(*in_ptr)++;
114   
115   return(val);
116 }
117 /* signed CGM integer at arbitrary legal precision */
118 static int b_gsint(in_ptr, bits_p)
119      unsigned char **in_ptr;            /* pointer to the input data pointer */
120      int bits_p;                        /* no. of bits precision */
121 {
122   int i, val;
123   /* have to worry about sign extension, may not have signed char */
124   if (**in_ptr & (1 << 7)) val = (-1 ^ 255) | *(*in_ptr)++;
125   else val = *(*in_ptr)++;
126   for (i=1; i<(bits_p / 8); ++i)
127     val = (val << 8) | *(*in_ptr)++;
128   
129   return(val);
130 }
131 /* now the reals */
132 /* the fixed point real */
133 static double b_fixed(dat_ptr, prec)
134      unsigned char **dat_ptr;
135      rp_type *prec;
136 {
137   double ret;
138   /* do it in two parts; the big (first) part and fractional (second) part */
139   
140   ret = (double) b_gsint(dat_ptr, prec->exp);   /* first part */
141   ret += (double) b_guint(dat_ptr, prec->fract) / (1 << prec->fract);
142   
143   return(ret);
144 }
145 /* the IEEE floating point */
146 static double b_ieee(dat_ptr, prec)
147      unsigned char **dat_ptr;
148      rp_type *prec;
149 {
150 #define TABLESIZE 128
151   static double shift_table[TABLESIZE];
152   double ret, dsp;
153   int is_neg, i;        /* is it a negative number ? */
154   unsigned long big_part, small_part;
155   /* use table for both speed and safety */
156   if (shift_table[0] == 0) {
157     for (i=0; i<TABLESIZE; ++i) shift_table[i] = 1.0 / (1 << i);
158   }
159
160   /* this is basically copied from the IEEE spec */
161   
162   is_neg = (**dat_ptr >> 7) & 1;
163   
164   if ((prec->exp + prec->fract) == 32) {        /* 32-bit precision */
165     big_part = (((*dat_ptr)[0] & 127) << 1) + (((*dat_ptr)[1] >> 7) & 1);
166     small_part = (((*dat_ptr)[1] & 127) << 16) +
167       ((*dat_ptr)[2] << 8) + (*dat_ptr)[3];
168     *dat_ptr += 4;      /* skip forward */
169     /* now check for special cases */
170     if (big_part == 255) {
171       if (small_part == 0) {
172         /* ret = (double) HUGE_VAL;      biggest possible */
173         ret = (double) 1000000;         /* biggest possible */
174       } else {
175         burp(stderr, "IEEE undefined real, small part = %ld, != 0\n",
176              small_part);
177         return(0.0);
178       }
179     } else if (big_part == 0) {
180       if (small_part == 0) {
181         ret = 0.0;
182       } else {
183         ret = small_part * pow(2.0, -149.0);
184       }
185     }
186     else {      /* normal case */
187       /* ret = 1.0 + small_part * pow(2.0, -23.0); */
188       ret = 1.0 + small_part * shift_table[23];
189       /* ret *= pow(2.0, (double) big_part - 127.0); */
190       if (big_part < TABLESIZE) 
191         ret *= shift_table[TABLESIZE - 1 - big_part];
192       else ret *= pow(2.0, (double) big_part - 127.0);
193       /* avoid use of pow, gives trouble on some compilers */
194     }
195   } else        if ((prec->exp + prec->fract) == 64) {  /* 64-bit precision */
196     big_part = ((**dat_ptr & 127) << 4) + 
197       ((*(*dat_ptr + 1) >> 4) & 15);
198     dsp = (double) (*(*dat_ptr + 1) & 15);
199     for (i=2; i<8; ++i) {
200       dsp *= 256;
201       dsp += (double) *(*dat_ptr + i);
202     }
203     *dat_ptr += 8;              /* skip forward */
204     if (big_part == 2047) {
205       if (dsp == 0.0) {
206         /* ret = (double) HUGE_VAL;      biggest possible */
207         ret = (double) 1000000;         /* biggest possible */
208       } else {
209         burp(stderr, "IEEE undefined real, dsp = %f, != 0.0\n", dsp);
210         return(0.0);
211       }
212     } else if (big_part == 0) {         
213       if (dsp == 0.0) ret = 0.0;
214       else ret = dsp * pow(2.0, -1074.0);
215     } else {
216       ret = 1.0 + dsp * pow(2.0, -52.0);
217       ret *= pow(2.0, (double) big_part - 1023.0);
218     }
219   } else {
220     burp(stderr, "illegal precision in IEEE\n");
221     return(0.0);
222   }
223   if (is_neg) ret = -ret;
224   return(ret);
225 #undef TABLESIZE
226 }
227 /* the general real */
228 static double b_real(dat_ptr, rprec)
229      unsigned char **dat_ptr;
230      rp_type *rprec;
231 {
232   if (rprec->fixed == 0) {      /* floating point */
233     return(b_ieee(dat_ptr, rprec));
234   } else if (rprec->fixed == 1) {       /* fixed */
235     return(b_fixed(dat_ptr, rprec));
236   } else {
237     burp(stderr, "illegal real precision %d\n", rprec->fixed);
238     return(0.0);
239   }
240 }
241 /* XLib specific functions */
242 /* the setup routine */
243 xl_setup(Screen *screen, Display *inDisplay, Window inWin, int inDepth,
244          Colormap inCmap, Visual *inVis, GC inGC, Dimension *in_width,
245          Dimension *in_height, Pixel **in_colrs, int *in_number,
246          Pixmap *inPixmap, unsigned short sf)
247 {
248   XVisualInfo myTemp, *myInfo;
249   int tmp;
250   ScaleFactor = (float)sf;
251   ScaleFactor /= 100.0;
252   /* store the info */
253   display = inDisplay;
254   win = inWin;
255   depth = inDepth;
256   cmap = inCmap;
257   vis = inVis;
258   ret_width = in_width;
259   ret_height = in_height;
260   ret_colrs = in_colrs;
261   /* figure out our visual class */
262   visualID = XVisualIDFromVisual(inVis);
263   myTemp.visualid = visualID;
264   /* get the visual info */
265   myInfo = XGetVisualInfo(display, VisualIDMask, &myTemp, &tmp);
266   visualClass = myInfo->class; /* crazy for XLib to use this word ! */
267   visualDepth = myInfo->depth;
268   redMask = myInfo->red_mask;
269   greenMask = myInfo->green_mask;
270   blueMask = myInfo->blue_mask;
271   colormap_size = myInfo->colormap_size;
272   bits_per_rgb = myInfo->bits_per_rgb;
273 #ifdef DEBUG_VISUAL
274   fprintf(stderr, "visual class is %s\n", visualNames[visualClass]);
275   fprintf(stderr, "depth = %d, mask = (%ld, %ld, %ld), cmap_size = %d, bits = %d\n",
276           visualDepth, redMask, greenMask, blueMask, colormap_size,
277           bits_per_rgb);
278 #endif
279   XFree(myInfo);
280   /* get the memory now for in_colrs in case we get a malformed cgm file */
281   *ret_colrs = (Pixel *) malloc(MAXCOLRS * sizeof(Pixel));
282   ret_number = in_number;
283   *ret_number = 0;
284   retPixmap = inPixmap; /* so we can change *inPixmap later */
285   /* make the GCs */
286   myStruct.line_width = 0; /* default to 0 for speed */
287   myStruct.line_style = LineSolid;
288   myStruct.fill_style = FillSolid;
289   myStruct.cap_style = CapButt;
290   myStruct.join_style = JoinBevel; /* screws up with Miter */
291   mask =
292     GCLineWidth |
293       GCLineStyle |
294         GCFillStyle |
295           GCCapStyle |
296             GCJoinStyle;
297   fillGC = XCreateGC(display, win, mask, &myStruct);
298   edgeGC = XCreateGC(display, win, mask, &myStruct);
299   textGC = XCreateGC(display, win, mask, &myStruct);  
300   markGC = XCreateGC(display, win, mask, &myStruct);
301   lineGC = XCreateGC(display, win, mask, &myStruct);
302   cellGC = XCreateGC(display, win, mask, &myStruct);
303   /* take the foreground and background colours from the input GC */
304   mask =
305     GCBackground |
306       GCForeground;
307   XCopyGC(display, inGC, mask, fillGC);
308   XCopyGC(display, inGC, mask, edgeGC);
309   XCopyGC(display, inGC, mask, textGC);
310   XCopyGC(display, inGC, mask, textGC);
311   XCopyGC(display, inGC, mask, lineGC);
312   pi = 4 * atan(1.0);
313   /* get our black and white pixels */
314   blackPixel = BlackPixelOfScreen(screen);
315   whitePixel = WhitePixelOfScreen(screen);
316   xPxlMM = ((float) WidthOfScreen(screen)) / WidthMMOfScreen(screen);
317   yPxlMM = ((float) HeightOfScreen(screen)) / HeightMMOfScreen(screen);
318   return 1;
319 }
320 /* how we get a X coordinate, use float, probably truncate later */
321 static float getX(unsigned char **dat_ptr, cgm_s_type *cgm_s)
322 {
323   switch (cgm_s->vdctype) {
324   case VDC_INT: return xScale *
325     (b_gsint(dat_ptr, cgm_s->vdcintprec)  - cgm_s->vdcextent[0].i);
326   case VDC_REAL: return xScale *
327       (b_real(dat_ptr, &(cgm_s->vdcrprec)) - cgm_s->vdcextent[0].r);
328   default: return 0; /* where did this come from ? */
329   }
330 }
331 /* how we get a Y coordinate, use float, probably truncate later */
332 static float getY(unsigned char **dat_ptr, cgm_s_type *cgm_s)
333 {
334   switch (cgm_s->vdctype) {
335   case VDC_INT: return xScale *
336     (b_gsint(dat_ptr, cgm_s->vdcintprec)  - cgm_s->vdcextent[1].i);
337   case VDC_REAL: return xScale *
338       (b_real(dat_ptr, &(cgm_s->vdcrprec)) - cgm_s->vdcextent[1].r);
339   default: return 0; /* where did this come from ? */
340   }
341 }
342 /* how we get a VDC, use float, probably truncate later, no offset needed */
343 static float getVDC(unsigned char **dat_ptr, cgm_s_type *cgm_s)
344 {
345   switch (cgm_s->vdctype) {
346   case VDC_INT: return xScale * b_gsint(dat_ptr, cgm_s->vdcintprec);
347   case VDC_REAL: return xScale * b_real(dat_ptr, &(cgm_s->vdcrprec));
348   default: return 0; /* where did this come from ? */
349   }
350 }
351 /* quick macro for colour difference */
352 #define XCOLRDIF(colr1, colr2) \
353 (abs(colr1.red - colr2.red) + \
354  abs(colr1.green - colr2.green) + \
355  abs(colr1.blue - colr2.blue))
356 /* this is where all colours are sorted out, even indexed colours */
357 static Pixel getPixel(cgm_s_type *cgm_s, int iColrs[3])
358 {
359   Status ret;
360   XColor inColr;
361   Pixel bestPixel = 0;
362   float dColrs[3];
363   float fDiv;
364   unsigned short r, g, b;
365   int i, bestI;
366   unsigned int bestDif, tempDif;
367   /* normalize colours for X routines */
368   for (i=0; i<3; ++i) {
369     fDiv = cgm_s->cvextent[i+3] - cgm_s->cvextent[i]; /* for safety */
370     dColrs[i] = (iColrs[i] - cgm_s->cvextent[i]) / fDiv;
371   }
372   /* we split up by visual class */
373   switch (visualClass) {
374   case 5: /* DirectColor */
375   case 2: /* StaticColor */
376   case 4: /* TrueColor */
377     /* can get the pixel directly for these classes */
378     /* assume it's better to do that than work with the colour map */
379     bestPixel = (redMask & (int) (redMask * dColrs[0])) |
380       (greenMask & (int) (greenMask * dColrs[1])) |
381       (blueMask & (int) (blueMask * dColrs[2]));
382     return bestPixel;
383     /* now the visuals for which XAllocColor makes sense */
384   default: /* just in case */
385   case 1: /* GreyScale */
386   case 0 : /* Static Grey */
387     if (visualDepth == 2) { /* monochrome, a common display */
388       return ((dColrs[0] + dColrs[1] + dColrs[2]) > 0.9) ? blackPixel :
389         whitePixel;
390     }
391     /* else fall thru to the pseudo colour visual for XAllocColor */
392   case 3: /* PseudoColor */
393     /* just ask for closest colour */
394     inColr.red = (unsigned short) (dColrs[0] * COLCONV + 0.4999);
395     inColr.green = (unsigned short) (dColrs[1] * COLCONV + 0.4999);
396     inColr.blue = (unsigned short) (dColrs[2] * COLCONV + 0.4999);
397     ret = XAllocColor(display, cmap, &inColr);
398     if (ret) {
399       /* lets see if it's a new one or not */
400       for (i=0; i<*ret_number; ++i) {
401         if (my_colrs[i].pixel == inColr.pixel)
402         {
403           XFreeColors(display, cmap, &inColr.pixel,1, 0);
404           return inColr.pixel;
405         }
406       }
407       /* must be a new one */
408       my_colrs[*ret_number].red = inColr.red;
409       my_colrs[*ret_number].green = inColr.green;
410       my_colrs[*ret_number].blue = inColr.blue;
411       my_colrs[*ret_number].pixel = inColr.pixel;
412       if (*ret_number < (MAXCOLRS - 1))
413       {
414          ++*ret_number;
415       }
416       return inColr.pixel;
417     } else {
418       /* look for best so far */
419       /* if nothing, fall back on black/white */
420       if (!*ret_number) return ((dColrs[0] + dColrs[1] + dColrs[2]) > 0.9)
421         ? blackPixel : whitePixel;
422       /* at least have some to work with */
423       bestI = 0;
424       bestPixel = my_colrs[bestI].pixel;
425       bestDif = XCOLRDIF(my_colrs[bestI], inColr);
426       for (i=1; i<*ret_number; ++i) { /* real ugly, but do for now */
427         tempDif = XCOLRDIF(my_colrs[i], inColr);
428         if (tempDif < bestDif) {
429           bestPixel = my_colrs[i].pixel;
430           bestDif = tempDif;
431           bestI = i;
432         }
433       }
434     }
435     return bestPixel;
436   } /* end of switch */
437 }
438 /* a direct colour */
439 static void setRGB(cgm_s_type *cgm_s, int iColrs[3], GC inGC)
440 {
441   Pixel usePixel;
442   usePixel = getPixel(cgm_s, iColrs);
443   XSetForeground(display, inGC, usePixel);
444 }
445 /* an indexed colour */
446 static Pixel getIPixel(int index)
447 {
448   if ((index >= 0) && (index < MAXCOLRS) && coltabPixels[index]) {
449     return coltabPixels[index];
450   } else return blackPixel;; 
451 }
452 static void setIndex(cgm_s_type *cgm_s, int index, GC inGC)
453 {
454   XSetForeground(display, inGC, getIPixel(index));    
455 }
456 /* now the functions that do the work */
457 /* Delimiters */
458 /* Begin Metafile */
459 static bmf(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
460            cgm_s_type *cgm_s)
461 {
462   /* nothing for now */
463   return 1;
464 }
465 /* End Metafile */
466 static emf(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
467            cgm_s_type *cgm_s)
468 {
469   /* nothing for now */
470   return 1;
471 }
472 /* Begin Picture */
473 static bpic(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
474             cgm_s_type *cgm_s)
475 {
476   /* nothing for now */
477   return 1;
478 }
479 /* Begin Picture Body */
480 static bpicbody(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
481                 cgm_s_type *cgm_s)
482 {
483   XPoint myClipRect[4];
484   GC clearGC;
485   /* look at VDC extent and figure out Pixmap size and scaling */
486   float x0, x1, y0, y1, w, h, maxWH;
487   int i;
488   if (cgm_s->vdctype) { /* real VDC's */
489     x0 = cgm_s->vdcextent[0].r;
490     y0 = cgm_s->vdcextent[1].r;
491     x1 = cgm_s->vdcextent[2].r;
492     y1 = cgm_s->vdcextent[3].r;
493   } else { /* integer VDC'c */
494     x0 = cgm_s->vdcextent[0].i;
495     y0 = cgm_s->vdcextent[1].i;
496     x1 = cgm_s->vdcextent[2].i;
497     y1 = cgm_s->vdcextent[3].i;
498   }
499   w = (x1 > x0) ? x1 - x0 : x0 - x1;
500   h = (y1 > y0) ? y1 - y0 : y0 - y1;
501   /* presently have max_size for size of the window */
502   /* need to override max_size if we have metric scaling set */
503   if (cgm_s->scalmode) { /* metric scaling */
504     /* there are supposed to be cgm_s->scalmode_f millimetres per vdc unit */
505     /* find the biggest direction */
506     maxWH = (w > h) ? w : h;
507     /* assuming square pixels, how many do we need ? */
508     max_size = (int) (xPxlMM * maxWH * cgm_s->scalmode_f);
509   }
510
511   if (h > w) { /* taller than wide */
512     xScale = max_size / h;
513     max_y = *ret_height = max_size;
514     max_x = *ret_width = max_size * w / h;
515   } else { /* wider than tall */
516     if (w == 0) w = 1; /* just in case */
517     xScale = max_size / w;
518     max_x = *ret_width = max_size;
519     max_y = *ret_height = max_size * h / w;
520   }
521   if (ScaleFactor > 0)
522   {
523     max_y =  *ret_height = ScaleFactor * max_y;
524     max_x =  *ret_width = ScaleFactor * max_x;
525     /*max_size *= ScaleFactor; */
526     xScale *= ScaleFactor;
527   }
528
529
530   /* set up for clipping */
531   myClipRect[0].x = myClipRect[0].y = myClipRect[3].x = myClipRect[1].y = 0;
532   myClipRect[1].x = myClipRect[2].x = max_x;
533   myClipRect[2].y = myClipRect[3].y = max_y;
534   clipRegion = XPolygonRegion(myClipRect, 4, EvenOddRule);
535   extRegion = XPolygonRegion(myClipRect, 4, EvenOddRule);
536   /* make the Pixmap */
537   *retPixmap = P = XCreatePixmap(display, win, *ret_width, *ret_height, depth);
538   /* fill it with the right background colour */
539   if (setBackColr) { /* set explicitly */
540     myStruct.foreground = getPixel(cgm_s, cgm_s->backcolr);
541   } else { /* use incoming GC */
542     mask = GCBackground | GCForeground;
543     XGetGCValues(display, lineGC, mask, &myStruct);
544     /* now put the background colr in the foreground and do the fill */
545     myStruct.foreground = myStruct.background;
546   }
547   myStruct.fill_style = FillSolid;
548   mask = GCFillStyle | GCForeground;
549   clearGC = XCreateGC(display, win, mask, &myStruct);
550   XFillRectangle(display, P, clearGC, 0, 0, *ret_width, *ret_height);
551   /* no text yet to set */
552   textPtr = NULL;
553   return(1);
554 }
555 /* End Picture */
556 static epic(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
557             cgm_s_type *cgm_s)
558 {
559   /* need to fill out the pixels array */
560   int i;
561   for (i=0; i < *ret_number; ++i) {
562     (*ret_colrs)[i] = my_colrs[i].pixel;
563   }
564   return 1;
565 }
566 /* Metafile Descriptors */
567 /* Metafile Version */
568 static mfversion(dat_ptr, cmd_ptr, cgm_s)
569      unsigned char *dat_ptr;
570      struct cmd_info_s *cmd_ptr;
571      cgm_s_type *cgm_s;
572 {
573   /* nothing for now */
574   return 1;
575 }
576 /* Metafile Descriptor */
577 static mfdescrip(dat_ptr, cmd_ptr, cgm_s)
578      unsigned char *dat_ptr;
579      struct cmd_info_s *cmd_ptr;
580      cgm_s_type *cgm_s;
581 {
582   /* nothing for now */
583   return 1;
584 }
585 /* VDC type */
586 static vdctype(dat_ptr, cmd_ptr, cgm_s)
587      unsigned char *dat_ptr;
588      struct cmd_info_s *cmd_ptr;
589      cgm_s_type *cgm_s;
590 {
591   /* 0=>integer, 1=>real */ 
592   
593   cgm_s->vdctype = b_gsint(&dat_ptr, 16);
594   
595   return 1;
596 }
597 /* Integer Precision */
598 static intprec(dat_ptr, cmd_ptr, cgm_s)
599      unsigned char *dat_ptr;
600      struct cmd_info_s *cmd_ptr;
601      cgm_s_type *cgm_s;
602 {
603   cgm_s->intprec = b_gsint(&dat_ptr, cgm_s->intprec);
604   return 1;
605 }
606 /* Real Precision */
607 static realprec(dat_ptr, cmd_ptr, cgm_s)
608      unsigned char *dat_ptr;
609      struct cmd_info_s *cmd_ptr;
610      cgm_s_type *cgm_s;
611 {
612   cgm_s->realprec.fixed = b_gsint(&dat_ptr, cgm_s->intprec);
613   cgm_s->realprec.exp = b_gsint(&dat_ptr, cgm_s->intprec);
614   cgm_s->realprec.fract = b_gsint(&dat_ptr, cgm_s->intprec);
615   
616   return 1;
617 }
618 /* Index Precision */
619 static indexprec(dat_ptr, cmd_ptr, cgm_s)
620      unsigned char *dat_ptr;
621      struct cmd_info_s *cmd_ptr;
622      cgm_s_type *cgm_s;
623 {
624   cgm_s->indexprec = b_gsint(&dat_ptr, cgm_s->intprec);
625   return 1;
626 }
627 /* Colour Precision */
628 static colprec(dat_ptr, cmd_ptr, cgm_s)
629      unsigned char *dat_ptr;
630      struct cmd_info_s *cmd_ptr;
631      cgm_s_type *cgm_s;
632 {
633   cgm_s->colprec = b_gsint(&dat_ptr, cgm_s->intprec);
634   return 1;
635 }
636 /* Colour Index Precision */
637 static cindprec(dat_ptr, cmd_ptr, cgm_s)
638      unsigned char *dat_ptr;
639      struct cmd_info_s *cmd_ptr;
640      cgm_s_type *cgm_s;
641 {
642   cgm_s->cindprec = b_gsint(&dat_ptr, cgm_s->intprec);
643   return 1;
644 }
645 /* Maximum Colour Index */
646 static maxcind(dat_ptr, cmd_ptr, cgm_s)
647      unsigned char *dat_ptr;
648      struct cmd_info_s *cmd_ptr;
649      cgm_s_type *cgm_s;
650 {
651   cgm_s->maxcind = b_guint(&dat_ptr, cgm_s->cindprec);
652   return 1;
653 }
654 /* Colour Value Extent */
655 static cvextent(dat_ptr, cmd_ptr, cgm_s)
656      unsigned char *dat_ptr;
657      struct cmd_info_s *cmd_ptr;
658      cgm_s_type *cgm_s;
659 {
660   int i;
661   for (i=0; i<6; ++i)
662     cgm_s->cvextent[i] = b_guint(&dat_ptr, cgm_s->colprec);
663   /* don't allow problems */
664   for (i=0; i<3; ++i) {
665     if (cgm_s->cvextent[i+3] == cgm_s->cvextent[i]) {
666       cgm_s->cvextent[i+3] = 0;
667       cgm_s->cvextent[i+3] = 255;
668     }
669   }
670   return 1;
671 }
672 /* Metafile Element List */
673 static mfellist(dat_ptr, cmd_ptr, cgm_s)
674      unsigned char *dat_ptr;
675      struct cmd_info_s *cmd_ptr;
676      cgm_s_type *cgm_s;
677 {
678   int i;
679   cgm_s->mfellist_s = b_gsint(&dat_ptr, cgm_s->intprec);
680   if (!(cgm_s->mfellist = (int *) malloc(sizeof(int) * 2 * 
681                                          cgm_s->mfellist_s))) {
682     burp(stderr, "couldn't get memory for MF ellement list\n");
683     return(0);
684   }
685   for (i=0; i<2 * cgm_s->mfellist_s; ++i) 
686     *(cgm_s->mfellist + i) = b_gsint(&dat_ptr, cgm_s->indexprec);
687   return 1;
688 }
689 /* Metafile Defaults Replacement, a complex element */
690 static mfdefrep(dat_ptr, cmd_ptr, cgm_s)
691      unsigned char *dat_ptr;
692      struct cmd_info_s *cmd_ptr;
693      cgm_s_type *cgm_s;
694 {
695   struct cmd_info_s new_cmd;    /* for the new commands */
696   int i, ret = 1, new_len, b_to_move, data_left;
697   unsigned char *out_ptr, *end_ptr, *new_ptr, *start_ptr;
698   
699   /* in this element, many other elements can be encoded in its             */
700   /* parameter list. So we take them one at a time and hand them over */
701   /* to do_b_cmd. Thus do_b_cmd is being called recursively.        */
702   if (!(out_ptr = (unsigned char *) malloc(cmd_ptr->p_len))) {
703     burp(stderr, 
704          "couldn't make memory for metafile defaults replacement\n");
705     return(0);
706   }     /* made some memory for decoded commands */
707   /* now put the decoded commands into the new memory */
708   /* setup pointers */
709   new_ptr = out_ptr;
710   end_ptr = dat_ptr + cmd_ptr->p_len;
711   /* initialise the new command pointer */
712   new_cmd.no = cmd_ptr->no;
713   new_cmd.sub_no = 1;
714   new_cmd.byte_no = 0;
715   while (dat_ptr < end_ptr) {   /* some input left */
716     start_ptr = dat_ptr;                /* mark place */
717     /* now decipher the command header (lots of magic numbers !)*/
718     new_cmd.Class = (int) ((dat_ptr[0] >> 4) & 15);
719     new_cmd.element = (int) (((dat_ptr[0] << 3) & 127) |
720                              ((dat_ptr[1] >> 5) & 7));
721     new_cmd.p_len = (int) (dat_ptr[1] & 31);
722     if ((new_cmd.Class != B_PDESCLASS) &&
723         (new_cmd.Class != B_CTRLCLASS) &&
724         (new_cmd.Class != B_ATTRCLASS)) {
725       burp(stderr, "illegal command in Metafile Defaults Replacement: ");
726       burp(stderr, "class = %d, element = %d\n", new_cmd.Class,
727            new_cmd.element);
728     }
729     dat_ptr += 2;               /* skip over header */
730     if (new_cmd.p_len < 31) {           /* short form */
731       b_to_move = (new_cmd.p_len % 2) ? new_cmd.p_len + 1 
732         : new_cmd.p_len;
733       for (i=0; i<b_to_move; ++i) *out_ptr++ = *dat_ptr++;
734     } else {                    /* long form */
735       data_left = 1;
736       new_cmd.p_len = 0;                        /* start fresh */
737       while (data_left) {               /* some data still to get */
738         /* how much to come ? */
739         new_len = (int) (((dat_ptr[0] & 127) << 8) | 
740                          dat_ptr[1]);
741         /* any more to come ? */
742         data_left = (dat_ptr[0] >> 7) & 1;
743         new_cmd.p_len += new_len;
744         dat_ptr += 2;
745         b_to_move = (new_len % 2) ? new_len + 1 : new_len;
746         for (i=0; i<b_to_move; ++i) *out_ptr++ = *dat_ptr++;
747       }
748     }
749     /* now make the call */
750     if (!do_b_cmd(&new_cmd, new_ptr, cgm_s)) {
751       burp(stderr, "error in do_b_cmd while replacing defaults\n");
752       return(0);
753     }       
754     ++new_cmd.sub_no;
755     new_cmd.byte_no += (dat_ptr - start_ptr);
756     out_ptr = new_ptr;  /* back to the beginning */
757   }
758   
759   /* now tell the devices that we are finished replacing defaults */
760   return 1;
761 }
762 /* Font List, store the data, but ignored for now */
763 static fontlist(dat_ptr, cmd_ptr, cgm_s)
764      unsigned char *dat_ptr;
765      struct cmd_info_s *cmd_ptr;
766      cgm_s_type *cgm_s;
767 {
768   int i;
769   unsigned char *my_ptr = NULL;
770   
771   my_ptr = dat_ptr;
772   for (i=0; (i<MAX_FONTS) && (my_ptr < (dat_ptr + cmd_ptr->p_len - 3));
773        ++i) {
774     if (!b_str(&my_ptr, cgm_s->fontlist + i)) {
775       burp(stderr, "couldn't get font name\n");
776       return(0);
777     }
778   }
779   /* zero out the rest of the fonts */
780   for (; i>MAX_FONTS; ++i) cgm_s->fontlist[i] = NULL;
781   
782   return 1;
783 }
784 /* Character Set List, stored but ignored */
785 static charlist(dat_ptr, cmd_ptr, cgm_s)
786      unsigned char *dat_ptr;
787      struct cmd_info_s *cmd_ptr;
788      cgm_s_type *cgm_s;
789 {
790   int i;
791   unsigned char *my_ptr = NULL;
792   
793   my_ptr = dat_ptr;
794   for (i=0; (i<MAX_FONTS) && (my_ptr < (dat_ptr + cmd_ptr->p_len - 3));
795        ++i) {
796     cgm_s->chartype[i] = b_gsint(&my_ptr, 16);
797     if (!b_str(&my_ptr, cgm_s->charlist + i)) {
798       burp(stderr, "couldn't get character set list\n");
799       return(0);
800     }
801   }
802   /* zero out the rest */
803   for (; i<MAX_FONTS; ++i) {
804     cgm_s->charlist[i] = NULL;
805     cgm_s->chartype[i] = 0;
806   }
807   return 1;
808 }
809 /* Character Announcer */
810 static charannounce(dat_ptr, cmd_ptr, cgm_s)
811      unsigned char *dat_ptr;
812      struct cmd_info_s *cmd_ptr;
813      cgm_s_type *cgm_s;
814 {
815   cgm_s->charannounce = b_gsint(&dat_ptr, 16);
816   return 1;
817 }
818 /* Picture Descriptors */
819 /* Scaling Mode */
820 static scalmode(dat_ptr, cmd_ptr, cgm_s)
821      unsigned char *dat_ptr;
822      struct cmd_info_s *cmd_ptr;
823      cgm_s_type *cgm_s;
824 {
825   
826   cgm_s->scalmode = b_gsint(&dat_ptr, 16);
827   if (cgm_s->scalmode) cgm_s->scalmode_f = 
828     b_ieee(&dat_ptr, &(cgm_s->realprec));       /* strange default */
829   
830   return 1;
831 }
832 /* Colour Selection Mode */
833 static colselmode(dat_ptr, cmd_ptr, cgm_s)
834      unsigned char *dat_ptr;
835      struct cmd_info_s *cmd_ptr;
836      cgm_s_type *cgm_s;
837 {
838   
839   cgm_s->colselmode = b_gsint(&dat_ptr, 16);
840   return 1;
841 }
842 /* Line Width Specification Mode */
843 static lwidspecmode(dat_ptr, cmd_ptr, cgm_s)
844      unsigned char *dat_ptr;
845      struct cmd_info_s *cmd_ptr;
846      cgm_s_type *cgm_s;
847 {
848   cgm_s->lwidspecmode = b_gsint(&dat_ptr, 16);
849   return 1;
850 }
851 /* Marker Size Specification Mode */
852 static marksizspecmode(dat_ptr, cmd_ptr, cgm_s)
853      unsigned char *dat_ptr;
854      struct cmd_info_s *cmd_ptr;
855      cgm_s_type *cgm_s;
856 {
857   cgm_s->marksizspecmode = b_gsint(&dat_ptr, 16);
858   return 1;
859 }
860 /* Edge Width Specification Mode */
861 static edwidspecmode(dat_ptr, cmd_ptr, cgm_s)
862      unsigned char *dat_ptr;
863      struct cmd_info_s *cmd_ptr;
864      cgm_s_type *cgm_s;
865 {
866   cgm_s->edwidspecmode = b_gsint(&dat_ptr, 16);
867   return 1;
868 }
869 /* VDC Extent */
870 static vdcextent(dat_ptr, cmd_ptr, cgm_s)
871      unsigned char *dat_ptr;
872      struct cmd_info_s *cmd_ptr;
873      cgm_s_type *cgm_s;
874 {
875   int i;
876   
877   switch (cgm_s->vdctype) {
878   case VDC_INT: for (i=0; i<4; ++i) cgm_s->vdcextent[i].i = 
879     b_gsint(&dat_ptr, cgm_s->vdcintprec);
880     break;
881   case VDC_REAL:        for (i=0; i<4; ++i) cgm_s->vdcextent[i].r = 
882     b_real(&dat_ptr, &(cgm_s->vdcrprec));
883     break;
884   }
885   return 1;
886 }
887 /* Background Colour */
888 static backcolr(dat_ptr, cmd_ptr, cgm_s)
889      unsigned char *dat_ptr;
890      struct cmd_info_s *cmd_ptr;
891      cgm_s_type *cgm_s;
892 {
893   int i;
894   for (i=0; i<3; ++i)
895     cgm_s->backcolr[i] = b_guint(&dat_ptr, cgm_s->colprec);
896   setBackColr = 0;
897   return 1;
898 }
899 /* Control Elements */
900 /* VDC Integer Precision */
901 static vdcintprec(dat_ptr, cmd_ptr, cgm_s)
902      unsigned char *dat_ptr;
903      struct cmd_info_s *cmd_ptr;
904      cgm_s_type *cgm_s;
905 {
906   cgm_s->vdcintprec = b_gsint(&dat_ptr, cgm_s->intprec);
907   return 1;
908 }
909 /* VDC Real Precision */
910 static vdcrprec(dat_ptr, cmd_ptr, cgm_s)
911      unsigned char *dat_ptr;
912      struct cmd_info_s *cmd_ptr;
913      cgm_s_type *cgm_s;
914 {
915   cgm_s->vdcrprec.fixed = b_gsint(&dat_ptr, cgm_s->intprec);
916   cgm_s->vdcrprec.exp = b_gsint(&dat_ptr, cgm_s->intprec);
917   cgm_s->vdcrprec.fract = b_gsint(&dat_ptr, cgm_s->intprec);
918   
919   return 1;
920 }
921 /* Auxiliary Colour */
922 static auxcolr(dat_ptr, cmd_ptr, cgm_s)
923      unsigned char *dat_ptr;
924      struct cmd_info_s *cmd_ptr;
925      cgm_s_type *cgm_s;
926 {
927   int i;
928   switch(cgm_s->colselmode) {
929   case I_C_M:   cgm_s->auxcolr[3] = b_guint(&dat_ptr, cgm_s->cindprec);
930     break;
931   case D_C_M:   for (i=0; i<3; ++i) 
932     cgm_s->auxcolr[i] = b_gsint(&dat_ptr, cgm_s->colprec);
933     break;
934   }
935   return 1;
936 }
937 /* Transparency */
938 static transp(dat_ptr, cmd_ptr, cgm_s)
939      unsigned char *dat_ptr;
940      struct cmd_info_s *cmd_ptr;
941      cgm_s_type *cgm_s;
942 {
943   cgm_s->transp = b_gsint(&dat_ptr, 16);
944   return 1;
945 }
946 /* return a set of XPoints, and their number */
947 unsigned int getXPoints(unsigned char *dat_ptr,
948                         struct cmd_info_s *cmd_ptr, cgm_s_type *cgm_s,
949                         XPoint **inPtr)
950 {
951   int i, noPts;
952   static XPoint *myPtr = NULL;
953   static int mySize = 0;
954   if (cgm_s->vdctype == VDC_INT) {
955     noPts = (8 * cmd_ptr->p_len) / (2 * cgm_s->vdcintprec);
956   } else if (cgm_s->vdctype == VDC_REAL) {
957     noPts = (8 * cmd_ptr->p_len) /
958       (2 * (cgm_s->vdcrprec.fract + cgm_s->vdcrprec.exp));
959   } else return 0;
960   if (noPts < 1) return 0;
961   if (noPts > mySize) { /* need more points memory */
962     if (myPtr) free(myPtr); /* eliminate old memory */
963     myPtr = (XPoint *) malloc(sizeof(XPoint) * noPts);
964     mySize = noPts;
965   }
966   /* fill it out */
967   for (i=0; i<noPts; ++i) {
968     myPtr[i].x = getX(&dat_ptr, cgm_s);
969     myPtr[i].y = max_y - getY(&dat_ptr, cgm_s);
970   }
971   /* fill out the return values */
972   *inPtr = myPtr;
973   return noPts;
974 }
975 /* Clipping Rectangle */
976 static cliprect(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
977                 cgm_s_type *cgm_s)
978 {
979   int noPts;
980   XPoint *myPtr = NULL, myClipRect[4];
981   noPts = getXPoints(dat_ptr, cmd_ptr, cgm_s, &myPtr);
982   if ((noPts < 2 ) || !myPtr) return 0;
983   /* have to get clipping rectangle set up correctly */
984   if (myPtr[0].x < myPtr[1].x) {
985     myClipRect[0].x = myClipRect[3].x = myPtr[0].x - 1;
986     myClipRect[1].x = myClipRect[2].x = myPtr[1].x - 1;
987   } else {
988     myClipRect[0].x = myClipRect[3].x = myPtr[1].x - 1;
989     myClipRect[1].x = myClipRect[2].x = myPtr[0].x - 1;
990   }
991   if (myPtr[0].y < myPtr[1].y) {
992     myClipRect[0].y = myClipRect[1].y = myPtr[0].y - 1;
993     myClipRect[2].y = myClipRect[3].y = myPtr[1].y - 1;
994   } else {
995     myClipRect[0].y = myClipRect[1].y = myPtr[1].y - 1;
996     myClipRect[2].y = myClipRect[3].y = myPtr[0].y - 1;
997   }
998   clipRegion = XPolygonRegion(myClipRect, 4, EvenOddRule);
999
1000   /* if clipping is on, set the clipping area */
1001   if (cgm_s->clipindic) {
1002     XSetRegion(display, lineGC, clipRegion);
1003     XSetRegion(display, textGC, clipRegion);
1004     XSetRegion(display, fillGC, clipRegion);
1005     XSetRegion(display, edgeGC, clipRegion);
1006     XSetRegion(display, cellGC, clipRegion);
1007     XSetRegion(display, markGC, clipRegion);
1008   }
1009   
1010   return 1;
1011 }
1012 /* Clipping Indicator */
1013 static clipindic(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
1014                  cgm_s_type *cgm_s)
1015 {
1016   Region r;
1017   cgm_s->clipindic = b_gsint(&dat_ptr, 16);
1018   if (cgm_s->clipindic) {
1019     XSetRegion(display, lineGC, clipRegion);
1020     XSetRegion(display, textGC, clipRegion);
1021     XSetRegion(display, fillGC, clipRegion);
1022     XSetRegion(display, edgeGC, clipRegion);
1023     XSetRegion(display, cellGC, clipRegion);
1024     XSetRegion(display, markGC, clipRegion);
1025   } else {
1026     XSetRegion(display, lineGC, extRegion);
1027     XSetRegion(display, textGC, extRegion);
1028     XSetRegion(display, fillGC, extRegion);
1029     XSetRegion(display, edgeGC, extRegion);
1030     XSetRegion(display, cellGC, extRegion);
1031     XSetRegion(display, markGC, extRegion);
1032   }
1033   return 1;
1034 }
1035 /* Graphical primitives */
1036 unsigned int getXSegments(unsigned char *dat_ptr,
1037                           struct cmd_info_s *cmd_ptr, cgm_s_type *cgm_s,
1038                           XSegment **inPtr)
1039 {
1040   int i, noSegments;
1041   XSegment *myPtr = NULL; 
1042   /* figure out how many segments we have */
1043   if (cgm_s->vdctype == VDC_INT) {
1044     noSegments = (8 * cmd_ptr->p_len)  / (4 * cgm_s->vdcintprec);
1045   } else if (cgm_s->vdctype == VDC_REAL) {
1046     noSegments = (8 * cmd_ptr->p_len) /
1047       (4 *(cgm_s->vdcrprec.fract + cgm_s->vdcrprec.exp));
1048   } else return 0;
1049   if (noSegments < 1) return 0;
1050   /* make memory for our segments */
1051   myPtr = (XSegment *) malloc(sizeof(XSegment) * noSegments);
1052   /* and fill it out */
1053   for (i=0; i<noSegments; ++i) {
1054     myPtr[i].x1 = getX(&dat_ptr, cgm_s);
1055     myPtr[i].y1 = max_y - getY(&dat_ptr, cgm_s);
1056     myPtr[i].x2 = getX(&dat_ptr, cgm_s);
1057     myPtr[i].y2 = max_y - getY(&dat_ptr, cgm_s);
1058   }
1059   /* return our values */
1060   *inPtr = myPtr;
1061   return noSegments;
1062 }
1063 /* Polyline */
1064 static polyline(dat_ptr, cmd_ptr, cgm_s)
1065      unsigned char *dat_ptr;
1066      struct cmd_info_s *cmd_ptr;
1067      cgm_s_type *cgm_s;
1068 {
1069   int noPts;
1070   XPoint *myPtr = NULL;
1071   noPts = getXPoints(dat_ptr, cmd_ptr, cgm_s, &myPtr);
1072   if ((noPts < 1) || !myPtr) return 0;
1073   XDrawLines(display, P, lineGC, myPtr, noPts, CoordModeOrigin);  
1074   return(1);
1075 }
1076 /* Disjoint Polyline, on/off segments */
1077 static dispoly(dat_ptr, cmd_ptr, cgm_s)
1078      unsigned char *dat_ptr;
1079      struct cmd_info_s *cmd_ptr;
1080      cgm_s_type *cgm_s;
1081 {
1082   int noSegments;
1083   XSegment *myPtr = NULL;
1084
1085   noSegments = getXSegments(dat_ptr, cmd_ptr, cgm_s, &myPtr);
1086   if ((noSegments < 1) || !myPtr) return 0;
1087   XDrawSegments(display, P, lineGC, myPtr, noSegments);  
1088   if (myPtr) free(myPtr);
1089   return(1);
1090 }
1091 /* Polymarker */
1092 static polymarker(dat_ptr, cmd_ptr, cgm_s)
1093      unsigned char *dat_ptr;
1094      struct cmd_info_s *cmd_ptr;
1095      cgm_s_type *cgm_s;
1096 {
1097   int noPts, i, x, y, size, asize;
1098   /* figure out the number of points */
1099   if (cgm_s->vdctype == VDC_INT) {
1100     noPts = (8 * cmd_ptr->p_len) / (2 * cgm_s->vdcintprec);
1101   } else if (cgm_s->vdctype == VDC_REAL) {
1102     noPts = (8 * cmd_ptr->p_len) /
1103       (2 * (cgm_s->vdcrprec.fract + cgm_s->vdcrprec.exp));
1104   } else return 0;
1105   if (noPts < 1) return 0;
1106
1107   /* go thru the points, drawing the markers */
1108   size = cgm_s->msize.i / 2;
1109   if (size < 1) size = 1; /* minimum size */
1110   asize = 0.7 * size; /* asterisk/cross size */
1111   if (asize < 1) asize = 1; /* minimum size */
1112
1113   for (i=0; i<noPts; ++i) {
1114     x = getX(&dat_ptr, cgm_s);
1115     y = max_y - getY(&dat_ptr, cgm_s);
1116     switch(cgm_s->mtype) { /* what type of marker */
1117     case 1: /* dot */
1118       XDrawPoint(display, P, markGC, x, y);
1119       break;
1120     case 2: /* plus */
1121       XDrawLine(display, P, markGC, x - size, y, x + size, y);
1122       XDrawLine(display, P, markGC, x, y - size, x, y + size);
1123       break;
1124     case 4: /* circle */
1125       XDrawArc(display, P, markGC, x - size, y - size,
1126                2 * size, 2 * size, 0, 360 * 64);
1127       break;
1128     case 3: /* asterisk, use fallthru */
1129       XDrawLine(display, P, markGC, x - size, y, x + size, y);
1130       XDrawLine(display, P, markGC, x, y - size, x, y + size);
1131     case 5: /* cross */
1132       XDrawLine(display, P, markGC, x - asize, y - asize, x + asize, y + asize);
1133       XDrawLine(display, P, markGC, x - asize, y + asize, x + asize, y - asize);
1134       break;
1135     default: /* do nothing */
1136       break;
1137     }
1138   }
1139   return(1);
1140 }
1141 /* in cgmtext.c */
1142 /* actually draw some text */
1143 void draw_cgm_text(Display*,  Drawable, GC, cgm_s_type*, int, int, int, int,
1144                    partialText*);
1145 /* got a final flag, so actually draw text */
1146 void doText(cgm_s_type *cgm_s)
1147 {
1148   partialText *myPtr, *tmpPtr;
1149   /* draw the text */
1150   draw_cgm_text(display, P, textGC, cgm_s, textX, textY, textW, textH,  textPtr);
1151   /* clean up memory */
1152   for (myPtr = textPtr; myPtr; myPtr = tmpPtr) {
1153     tmpPtr = myPtr->next;
1154     free(myPtr->text);
1155     free(myPtr);
1156   }
1157   textPtr = NULL;
1158   textX = textY = textW = textH = 0;
1159 }
1160 /* Regular Text */
1161 static text(dat_ptr, cmd_ptr, cgm_s)
1162      unsigned char *dat_ptr;
1163      struct cmd_info_s *cmd_ptr;
1164      cgm_s_type *cgm_s;
1165 {
1166   int final_flag;
1167   unsigned char *out_ptr;
1168   partialText *newPtr, *myPtr;
1169    /* clean up in case we didn't get a final flag (e.g., old NCAR) */
1170   if (textPtr) doText(cgm_s);
1171   
1172   /* first get the point for the string */
1173   textX = getX(&dat_ptr, cgm_s);
1174   textY = max_y - getY(&dat_ptr, cgm_s);
1175   /* make some memory */
1176   newPtr = (partialText *) malloc(sizeof(partialText));
1177   newPtr->text = NULL;
1178   newPtr->next = NULL;
1179   newPtr->tcolr = cgm_s->tPixel;
1180   newPtr->cexpfac = cgm_s->cexpfac;
1181   newPtr->cspace = cgm_s->cspace;
1182   newPtr->cheight = cgm_s->cheight.i;
1183   /* now the final/not final flag */
1184   final_flag = b_gsint(&dat_ptr, 16);
1185   
1186
1187   /* now the string */
1188   if (!b_str(&dat_ptr, &(newPtr->text))) {
1189     burp(stderr, "couldn't get text string\n");
1190     return(0);
1191   }
1192   /* append it to our pointer */
1193   if (textPtr) {
1194     for (myPtr = textPtr; myPtr->next; myPtr = myPtr->next);
1195     myPtr->next = newPtr;
1196   } else textPtr = newPtr;
1197   /* any more to come ? */
1198   if (final_flag) doText(cgm_s);
1199   return 1;
1200 }
1201 /* Restricted Text */
1202 static restext(dat_ptr, cmd_ptr, cgm_s)
1203      unsigned char *dat_ptr;
1204      struct cmd_info_s *cmd_ptr;
1205      cgm_s_type *cgm_s;
1206 {
1207   int final_flag;
1208   partialText *newPtr, *myPtr;
1209   
1210   /* first the width and height */
1211   textW = getVDC(&dat_ptr, cgm_s);
1212   textH = getVDC(&dat_ptr, cgm_s);
1213   /* now get the point for the string */
1214   textX = getX(&dat_ptr, cgm_s);
1215   textY = max_y - getY(&dat_ptr, cgm_s);
1216   /* now the final/not final flag */
1217   final_flag = b_gsint(&dat_ptr, 16);
1218   /* make some memory */
1219   newPtr = (partialText *) malloc(sizeof(partialText));
1220   newPtr->text = NULL;
1221   newPtr->next = NULL;
1222   newPtr->tcolr = cgm_s->tPixel;
1223   newPtr->cexpfac = cgm_s->cexpfac;
1224   newPtr->cspace = cgm_s->cspace;
1225   newPtr->cheight = cgm_s->cheight.i;
1226
1227   /* now the string */
1228   if (!b_str(&dat_ptr, &(newPtr->text))) {
1229     burp(stderr, "couldn't get text string\n");
1230     return(0);
1231   }
1232   /* append it to our pointer */
1233   if (textPtr) {
1234     for (myPtr = textPtr; myPtr->next; myPtr = myPtr->next);
1235     myPtr->next = newPtr;
1236   } else textPtr = newPtr;
1237   /* any more to come ? */
1238   if (final_flag) doText(cgm_s);
1239   return 1;
1240 }
1241 /* Appended Text */
1242 static apptext(dat_ptr, cmd_ptr, cgm_s)
1243      unsigned char *dat_ptr;
1244      struct cmd_info_s *cmd_ptr;
1245      cgm_s_type *cgm_s;
1246 {
1247   int i, ret, final_flag;
1248   partialText *newPtr, *myPtr;
1249   if (!textPtr) return; /* can't append if there's nothing started ! */
1250   
1251   /* first the final/not final flag */
1252   final_flag = b_gsint(&dat_ptr, 16);
1253   /* make some memory */
1254   newPtr = (partialText *) malloc(sizeof(partialText));
1255   newPtr->text = NULL;
1256   newPtr->next = NULL;
1257   newPtr->tcolr = cgm_s->tPixel;
1258   newPtr->cexpfac = cgm_s->cexpfac;
1259   newPtr->cspace = cgm_s->cspace;
1260   newPtr->cheight = cgm_s->cheight.i;
1261   
1262   /* now the string */
1263   if (!b_str(&dat_ptr, &(newPtr->text))) {
1264     burp(stderr, "couldn't get text string\n");
1265     return(0);
1266   }
1267   /* append it to our pointer */
1268   /* find last partial text */
1269   for (myPtr = textPtr; myPtr->next; myPtr = myPtr->next);
1270   myPtr->next = newPtr;
1271   return 1;
1272 }
1273 /* Polygon */
1274 static polygon(dat_ptr, cmd_ptr, cgm_s)
1275      unsigned char *dat_ptr;
1276      struct cmd_info_s *cmd_ptr;
1277      cgm_s_type *cgm_s;
1278 {
1279   int noPts;
1280   XPoint *myPtr = NULL;
1281   noPts = getXPoints(dat_ptr, cmd_ptr, cgm_s, &myPtr);
1282   if ((noPts < 2) || !myPtr) return 0;
1283   /* fill the polygon */
1284   XFillPolygon(display, P, fillGC, myPtr, noPts, Complex, CoordModeOrigin);
1285   /* draw the edge ? */
1286   if (cgm_s->evis) { /* not necessary, but here for optimization */
1287     XDrawLines(display, P, edgeGC, myPtr, noPts, CoordModeOrigin);  
1288     /* close the edge */
1289     XDrawLine(display, P, edgeGC, myPtr[0].x, myPtr[0].y,
1290               myPtr[noPts - 1].x, myPtr[noPts - 1].y);
1291   }
1292   return 1;
1293 }
1294 /* Polyset */
1295 static polyset(dat_ptr, cmd_ptr, cgm_s)
1296      unsigned char *dat_ptr;
1297      struct cmd_info_s *cmd_ptr;
1298      cgm_s_type *cgm_s;
1299 {
1300   int i, j, noPts, *vPtr, lastFill;
1301   XPoint *myPtr;
1302   
1303   /* get the number of pts */
1304   switch (cgm_s->vdctype) {
1305   case VDC_INT: noPts = (8 * cmd_ptr->p_len) / (2 * cgm_s->vdcintprec + 16);
1306     break;
1307   case VDC_REAL:        noPts = (8 * cmd_ptr->p_len) / 
1308     (2 * (cgm_s->vdcrprec.fract + cgm_s->vdcrprec.exp) + 16);
1309     break;
1310   default: return 0; /* shouldn't happen */
1311   }
1312   /* now make the memory */
1313   myPtr = (XPoint *) malloc(sizeof(XPoint) * noPts);
1314   vPtr = (int *) malloc(sizeof(int) * noPts);
1315   /* check we got it */
1316   if ((noPts < 2) || !myPtr || !vPtr) return 0;
1317   /* and fill it out */
1318   for (i=0; i<noPts; ++i) {
1319     myPtr[i].x = getX(&dat_ptr, cgm_s);
1320     myPtr[i].y = max_y - getY(&dat_ptr, cgm_s);
1321     vPtr[i] = b_gsint(&dat_ptr, 16);    /* the flag */
1322   }
1323   /* draw the polygon set */
1324   lastFill = 0; /* no closure pts yet */
1325   for (i=0; i<noPts; ++i) {
1326     /* check the edge out flag */
1327     switch (vPtr[i]) {
1328     case 0: /* invisible edge */
1329       break;
1330     case 1: /* visible edge */
1331       if (i < (noPts - 1))
1332         XDrawLine(display, P, edgeGC, myPtr[i].x, myPtr[i].y,
1333                   myPtr[i + 1].x, myPtr[i + 1].y);
1334       break;
1335     case 2: /* close, invisible edge */
1336       if (i > (lastFill + 2)) 
1337         XFillPolygon(display, P, fillGC, myPtr + lastFill, i - lastFill + 1,
1338                      Complex, CoordModeOrigin);
1339       lastFill = i + 1;
1340       break;
1341     case 3: /* close, visible edge */
1342       if (i > (lastFill + 2)) 
1343         XFillPolygon(display, P, fillGC, myPtr + lastFill, i - lastFill + 1,
1344                      Complex, CoordModeOrigin);
1345       if (i > lastFill)
1346         XDrawLine(display, P, edgeGC, myPtr[i].x, myPtr[i].y,
1347                   myPtr[lastFill].x, myPtr[lastFill].y);
1348       lastFill = i + 1;
1349       break;
1350     default: /* do nothing */
1351       break;
1352     }
1353   }
1354   /* free the memory */
1355   free(myPtr);
1356   free(vPtr); 
1357   return 1;
1358 }
1359 /* Cell Array */
1360 /* need specific functions to deal with cell array colours */
1361 /* macro to get an unsigned integer value from a cell array */
1362 static int temp;
1363 #define UINT unsigned int
1364 #define AINT(ptr, prec, out, done) switch(prec) {\
1365 case 32: out = (((UINT)ptr[0]) << 24) + (((UINT)ptr[1]) << 16)\
1366  + (((UINT)ptr[2]) << 8) + ptr[3]; ptr += 4; break;\
1367 case 24: out = (((UINT)ptr[0]) << 16)\
1368  + (((UINT)ptr[1]) << 8) + ptr[2]; ptr += 3; break;\
1369 case 16: out = (((UINT)ptr[0]) << 8) + ptr[1]; ptr += 2; break;\
1370 case 8: out = *ptr++; break;\
1371 case 4: if(!(temp=(((done + 1) * prec) % 8))) out = *ptr++ & 15; \
1372 else out = (*ptr >> temp) & 15; break;\
1373 case 2: if(!(temp=(((done + 1) * prec) % 8))) out = *ptr++ & 3; \
1374 else out = (*ptr >> (8 - temp)) & 3; break;\
1375 case 1: if(!(temp=(((done + 1) * prec) % 8))) out = *ptr++ & 1; \
1376 else out = (*ptr >> (8 - temp)) & 1; break;}
1377 /* get a packed list */
1378 static void getListPixels(unsigned char *datPtr, cgm_s_type *cgm_s,
1379                             int nx, int ny, int prec, Pixel *retPtr)
1380 {
1381   unsigned char *startPtr;
1382   int rowSize, i, j, k, maxCol, done, iCol, iColrs[3];
1383   /* may be in direct colour mode or indexed colour mode */
1384   switch (cgm_s->colselmode) {
1385   case D_C_M: /* direct colour */
1386     rowSize = (nx * 3 * prec + 7) / 8; /* no of bytes per row */
1387     if (rowSize % 2) ++rowSize; /* round up */
1388     for (i = 0; i < ny; ++i) {
1389       startPtr = datPtr;
1390       done = 0;
1391       for (j = 0; j < nx; ++j) {
1392         for (k=0; k<3; ++k) {
1393           AINT(startPtr, prec, iColrs[k], done);
1394           ++done;
1395         }
1396         *retPtr++ = getPixel(cgm_s, iColrs);
1397       }
1398       datPtr += rowSize;
1399     }
1400     break;
1401   case I_C_M:
1402     rowSize = (nx * prec + 7) / 8; /* no of bytes per row */
1403     if (rowSize % 2) ++rowSize; /* round up */
1404     for (i = 0; i < ny; ++i) {
1405       startPtr = datPtr;
1406       done = 0;
1407       for (j = 0; j < nx; ++j) {
1408         AINT(startPtr, prec, iCol, done);
1409         ++done;
1410         *retPtr++ = getIPixel(iCol);
1411       }
1412       datPtr += rowSize;
1413     }
1414     break;
1415   default: /* nothing */ break;
1416   }
1417 }
1418 /* get a run-length encoded list */
1419 static void getRLPixels(unsigned char *dat_ptr, cgm_s_type *cgm_s,
1420                             int nx, int ny, int prec, Pixel *retPtr)
1421 {
1422   static unsigned char bitMask[8] = {255, 127, 63, 31, 15, 7, 3, 1};
1423   unsigned char *rowPtr;
1424   Pixel myPixel;
1425   int i, j, k, done, iCol, iColrs[3], bitOffset,count;
1426   Pixel tP;
1427
1428   for (i=0; i<ny; ++i) { /* loop through the rows */
1429     done = j = bitOffset = 0;
1430     rowPtr = dat_ptr;
1431     while (j < nx) { /* still some left in this row */
1432       /* pick up the count of repeated colours, may span bytes */
1433       count = (bitOffset) ?
1434         (dat_ptr[0] & bitMask[bitOffset] << (bitOffset + 8)) +
1435         (dat_ptr[1] << bitOffset) +
1436         (dat_ptr[2] >> (8 - bitOffset)) :
1437         (dat_ptr[0] << 8) + dat_ptr[1];
1438       if ((j + count) > nx) return; /* too many pixels */
1439       dat_ptr += 2;
1440       done += 16 / prec;
1441       /* now get the next colour and replicate it count times */
1442       switch (cgm_s->colselmode) {
1443       case D_C_M: /* direct colour */
1444         /* get the r, g, b values */
1445         for (k=0; k<3; ++k) {
1446           AINT(dat_ptr, prec, iColrs[k], done);
1447           ++done;
1448         }
1449         myPixel = getPixel(cgm_s, iColrs);
1450         for (k=0; k<count; ++k) retPtr[i * nx + j + k] = myPixel;
1451         j += count;
1452         break;
1453       case I_C_M:
1454         /* get one pixel */
1455         AINT(dat_ptr, prec, iCol, done);
1456         tP = getIPixel(iCol);
1457         /* and replicate it */
1458         for (k=0; k<count; ++k) {
1459           retPtr[i * nx + j + k] = tP
1460 ;
1461         }
1462         ++done;
1463         j += count;
1464         break;
1465       default: /* nothing */ break;
1466       } /* end of switch */
1467       bitOffset = (done * prec) % 8;
1468     } /* end of row */
1469     /* may have to skip to end of row */
1470     if (bitOffset) ++dat_ptr; /* incomplete byte */
1471     if (((int) dat_ptr - (int) rowPtr) % 2) ++dat_ptr; /* need to round up */
1472   } /* end of cell array */
1473 }
1474
1475
1476 /* build a pixel array, (x, y) = (x + y * nx) storage */
1477 static Pixel *getPixels(unsigned char *dat_ptr, cgm_s_type *cgm_s,
1478                         int nx, int ny, int localPrec, int repMode)
1479 {
1480   int ix, iy;
1481   Pixel *retPtr;
1482   retPtr = (Pixel *) malloc(nx * ny * sizeof(Pixel));
1483   if (!retPtr) return NULL;
1484   /* get the local colour precision */
1485   if (!localPrec) localPrec =
1486                     (cgm_s->colselmode) ? cgm_s->colprec :cgm_s->cindprec;
1487
1488   /* get the pixels for each case */
1489   if (repMode) { /* packed list */
1490     getListPixels(dat_ptr, cgm_s, nx, ny, localPrec, retPtr);
1491   } else { /* run-length encoded */
1492     getRLPixels(dat_ptr, cgm_s, nx, ny, localPrec, retPtr);
1493   }
1494   return retPtr;
1495 }
1496 /* actually get the cellarray command */
1497 static cellarray(dat_ptr, cmd_ptr, cgm_s)
1498      unsigned char *dat_ptr;
1499      struct cmd_info_s *cmd_ptr;
1500      cgm_s_type *cgm_s;
1501 {
1502   int i, j, x[3], y[3], nx, ny, local_prec, rep_mode, xSize, ySize;
1503   int Qx, Qy, Rx, Ry, det, xMin, xMax, yMin, yMax, newX, newY, ix, iy,
1504   oldX, oldY;
1505   double ddet, axx, axy, ayx, ayy;
1506   XImage *myImage;
1507   Pixel *myPixels;
1508   
1509   /* first get the corner co-ordinates */
1510   for (i=0; i<3; ++i) {
1511     x[i] = getX(&dat_ptr, cgm_s);
1512     y[i] = getY(&dat_ptr, cgm_s);
1513   }
1514   /* now the bit array specifics */
1515   nx = b_gsint(&dat_ptr, cgm_s->intprec);
1516   ny = b_gsint(&dat_ptr, cgm_s->intprec);
1517   local_prec = b_gsint(&dat_ptr, cgm_s->intprec);
1518   rep_mode = b_gsint(&dat_ptr, 16);
1519   /* get the expanded cell array */
1520   if (!(myPixels = getPixels(dat_ptr, cgm_s, nx, ny, local_prec, rep_mode)))
1521     return 0;
1522   
1523   /* make sure we're not co-linear */
1524   Qx = x[1] - x[0];
1525   Qy = y[1] - y[0];
1526   Rx = x[2] - x[0];
1527   Ry = y[2] - y[0];
1528   /* figure out the determinant */
1529   if (!(det = Rx * Qy - Ry * Qx)) return 1; /* co-linear */
1530   ddet = (double) det; /* explicit cast for Ultrix bug */
1531   /* figure out the transformation matrix */
1532   /* need nx+1, ny+1, because o integer arithmetic expanding range */
1533   axx = (nx + 1) * (Qy - Ry) / ddet;
1534   axy = (nx + 1) * (Rx - Qx) / ddet;
1535   ayx = - (ny + 1) * Ry / ddet;
1536   ayy = (ny + 1)  * Rx / ddet;
1537   /* figure out the 4th pt and use it as beginning of bounding rectangle */
1538   xMin = xMax = x[0] + x[1] - x[2];
1539   yMin = yMax = y[0] + y[1] - y[2];
1540   for (i=0; i<3; ++i) {
1541     if (x[i] < xMin) xMin = x[i];
1542     if (x[i] > xMax) xMax = x[i];
1543     if (y[i] < yMin) yMin = y[i];
1544     if (y[i] > yMax) yMax = y[i];
1545   }
1546   /* make sure we're inside the pixmap */
1547   if (xMin < 0) xMin = 0;
1548   if (yMin < 0) yMin = 0;
1549   if (xMax > max_x) xMax = max_x;
1550   if (yMax > max_y) yMax = max_y;
1551   /* get the image */
1552   xSize = xMax - xMin;
1553   ySize = yMax - yMin;
1554   myImage = XGetImage(display, P, xMin, max_y - yMax, xSize, ySize,
1555                       ~0, ZPixmap);
1556   /* now go thru the screen pixels */
1557   for (iy=1; iy <= ySize; ++iy) {
1558     /* get the real Image y coord, relative to (x0, y0) */
1559     oldY = iy - (y[0] - yMin);
1560     for (ix=0; ix<xSize; ++ix) {
1561       /* get the real Image x coord, relative to (x0, y0) */
1562       oldX = ix - (x[0] - xMin);
1563       /* see if we have data for the transformed point */
1564       newX = (int) (axx * oldX + axy * oldY - 0.99);
1565       newY = (int) (ayx * oldX + ayy * oldY - 0.99);
1566       if ((newX >= 0) && (newX < nx) && (newY >= 0) && (newY < ny)) {
1567         XPutPixel(myImage, ix, ySize - iy, myPixels[newX + newY * nx]);
1568       }
1569     }
1570   }
1571   /* copy the XImage back */
1572
1573   XPutImage(display, P, cellGC, myImage, 0, 0, xMin, max_y - yMax,
1574             xSize, ySize);
1575   /* return the memory */
1576   XDestroyImage(myImage);
1577   free(myPixels);
1578   return 1;
1579 }
1580 /* Rectangle */
1581 static rectangle(dat_ptr, cmd_ptr, cgm_s)
1582      unsigned char *dat_ptr;
1583      struct cmd_info_s *cmd_ptr;
1584      cgm_s_type *cgm_s;
1585 {
1586   int i, xPts[2], yPts[2], x, y, old_style;
1587   unsigned int w, h;
1588   
1589   /* just 2 pts to grab */
1590   for (i=0; i<2; ++i) {
1591     xPts[i] = getX(&dat_ptr, cgm_s);
1592     yPts[i] = max_y - getY(&dat_ptr, cgm_s);
1593   }
1594   /* now arrange them to the satisfaction of XLib */
1595   if (xPts[0] < xPts[1]) {
1596     w = xPts[1] - xPts[0];
1597     x = xPts[0];
1598   } else {
1599     w = xPts[0] - xPts[1];
1600     x = xPts[1];
1601   }
1602   if (yPts[0] < yPts[1]) {
1603     h = yPts[1] - yPts[0];
1604     y = yPts[0];
1605   } else {
1606     h = yPts[0] - yPts[1];
1607     y = yPts[1];
1608   }
1609   /* and fill the rectangle */
1610   XFillRectangle(display, P, fillGC, x, y, w, h);
1611   /* and the edge, have to make sure corners look OK */
1612   /* store the old value of cap style */
1613   XGetGCValues(display, edgeGC, GCCapStyle, &myStruct);
1614   old_style = myStruct.cap_style;
1615   myStruct.cap_style = CapProjecting;
1616   XChangeGC(display, edgeGC, GCCapStyle, &myStruct);  
1617   /* draw the lines */
1618   XDrawLine(display, P, edgeGC, x, y, x + w, y);
1619   XDrawLine(display, P, edgeGC, x + w, y, x + w, y + h);
1620   XDrawLine(display, P, edgeGC, x + w, y + h, x, y + h);
1621   XDrawLine(display, P, edgeGC, x, y + h, x, y);
1622   /* restore the old value */
1623   myStruct.cap_style = old_style;
1624   XChangeGC(display, edgeGC, GCCapStyle, &myStruct);  
1625   return 1;
1626 }
1627 /* Circle */
1628 static circle(dat_ptr, cmd_ptr, cgm_s)
1629      unsigned char *dat_ptr;
1630      struct cmd_info_s *cmd_ptr;
1631      cgm_s_type *cgm_s;
1632 {
1633   int x, y, r;
1634   /* get the center position and radius */
1635   x = getX(&dat_ptr, cgm_s);
1636   y = max_y - getY(&dat_ptr, cgm_s);
1637   r = getVDC(&dat_ptr, cgm_s);
1638   if (r < 0) return 0;
1639   /* fill the circle */
1640   XSetArcMode(display, fillGC, ArcChord); /* for safety */
1641   XFillArc(display, P, fillGC, x - r, y - r, 2 * r, 2 * r, 0, 360 * 64);
1642   /* draw the edge */
1643   XDrawArc(display, P, edgeGC, x - r, y - r, 2 * r, 2 * r, 0, 360 * 64);
1644   return 1;
1645 }
1646 /* get radius, center and angles from 3 pts */
1647 static int getArc(float inX[3], float inY[3], int *outXC, int *outYC,
1648                   double *outTheta0, double *outDtheta)
1649 {
1650   int i, r, xc, yc;
1651   double theta[3], dtheta;
1652   float m1, m2, x[5], y[5];
1653   /* for convenience */
1654   for (i=0; i<3; ++i) {
1655     x[i] = inX[i];
1656     y[i] = inY[i];
1657   }
1658   /* get the midpoints between the pts */
1659   for (i=0; i<2; ++i) {
1660     x[i+3] = (x[i] + x[i+1]) / 2;
1661     y[i+3] = (y[i] + y[i+1]) / 2;
1662   }
1663   /*
1664     the perpendiculars to the 2 lines thru their midpts will meet at the center
1665     thus we have 4 eqns for 4 unknowns:
1666     xc = x3 + a * (y1 - y0)
1667     yc = y3 - a * (x1 - x0)
1668     xc = x4 + b * (y2 - y1)
1669     yc = y4 - b * (x2 - x1)
1670     we can eliminate a and b to find xc and yc
1671     (xc - x3) / (y1 - y0) = - (yc - y3) / (x1 - x0)
1672     (xc - x4) / (y2 - y1) = - (yc - y4) / (x2 - x1)
1673   */
1674   /* get xc first */
1675   if (y[1] == y[0]) xc = x[3];
1676   else if (y[2] == y[1]) xc = x[4];
1677   else { /* divisors are non-zero, get radii slopes */
1678     m1 = -(x[1] - x[0]) / (y[1] - y[0]);
1679     m2 = -(x[2] - x[1]) / (y[2] - y[1]);
1680     /* (xc - x3) * m1 + y3 = (xc - x4) * m2 + y4, i.e.,
1681        xc * (m1 - m2) = m1 * x3 - m2 * x4 + y4 - y3 */
1682     xc = (m1 * x[3] - m2 * x[4] + y[4] - y[3]) / (m1 - m2);
1683   }
1684   if (xc == x[3]) yc = y[3];
1685   else yc = y[3] + m1 * (xc - x[3]);
1686    /* have the center, now get the radius */
1687 #define SQ(x) ((double) ((x) * (x)))
1688    r = sqrt(SQ(x[0] - xc) + SQ(y[0] - yc));
1689
1690   /* now get the angles */
1691
1692   for (i=0; i<3; ++i) {
1693     theta[i] = atan2(y[i] - yc, x[i] - xc);
1694     if (theta[i] < 0) theta[i] += 2 * pi; /* for XLib coords */
1695   }
1696   /* figure out the delta theta angle */
1697   dtheta = theta[2] - theta[0];
1698   if (theta[1] > theta[0]) { /* need to go clockwise */
1699     if (dtheta < 0) dtheta += 2 * pi;
1700   } else { /* need to go anticlockwise */
1701     if (dtheta > 0) dtheta -= 2 * pi;
1702   }
1703   *outXC = xc;
1704   *outYC = yc;
1705   *outTheta0 = theta[0];
1706   *outDtheta = dtheta;
1707   return r;
1708 }
1709 /* Circular Arc, set by 3 points */
1710 static circ3(dat_ptr, cmd_ptr, cgm_s)
1711      unsigned char *dat_ptr;
1712      struct cmd_info_s *cmd_ptr;
1713      cgm_s_type *cgm_s;
1714 {
1715   int xc, yc, r, i;
1716   double theta0, dtheta;
1717   float det1, x[3], y[3];
1718
1719   /* just 3 pts to grab */
1720   for (i=0; i<3; ++i) {
1721     x[i] = getX(&dat_ptr, cgm_s);
1722     y[i] = getY(&dat_ptr, cgm_s);
1723   }
1724   /* get the determinant, find out if they're co-linear */
1725   det1 = (x[2] - x[0]) * (y[1] - y[0])
1726     - (x[1] - x[0]) * (y[2] - y[0]);
1727   if (det1 == 0) { /* co-linear, just connect points */
1728     XDrawLine(display, P, lineGC, x[0], max_y - y[0], x[1], max_y - y[1]);
1729     XDrawLine(display, P, lineGC, x[1], max_y - y[1], x[2], max_y - y[2]);
1730     return 1;
1731   }
1732   /* now need to figure out arc in appropriate coordinates */
1733   r = getArc(x, y, &xc, &yc, &theta0, &dtheta);
1734   /* convert to left handed XLib coords */
1735   yc = max_y - yc;
1736   if (r == 0) return 0;
1737   XDrawArc(display, P, lineGC, xc - r, yc - r, 2 * r, 2 * r,
1738            (int) ((theta0 / pi) * 180 * 64),
1739            (int) ((dtheta / pi) * 180 * 64));
1740   return 1;
1741 }
1742 /* Circular Arc, set by 3 points, close */
1743 static circ3close(dat_ptr, cmd_ptr, cgm_s)
1744      unsigned char *dat_ptr;
1745      struct cmd_info_s *cmd_ptr;
1746      cgm_s_type *cgm_s;
1747 {
1748   int xc, yc, r, i, close_type, x0, y0, x2, y2;
1749   float det1, x[3], y[3]; /* use floats since we must manipulate them */
1750   double theta0, dtheta;
1751   /* just 3 pts plus an eint to grab */
1752   for (i=0; i<3; ++i) {
1753     x[i] = getX(&dat_ptr, cgm_s);
1754     y[i] = getY(&dat_ptr, cgm_s);
1755   }
1756   close_type = b_gsint(&dat_ptr, 16); /* how do we close the arc ? */
1757   /* get the determinant, find out if they're co-linear */
1758   det1 = (x[2] - x[0]) * (y[1] - y[0])
1759     - (x[1] - x[0]) * (y[2] - y[0]);
1760   if (det1 == 0) { /* co-linear, just connect points */
1761     XDrawLine(display, P, lineGC, x[0], max_y - y[0], x[1], max_y - y[1]);
1762     XDrawLine(display, P, lineGC, x[1], max_y - y[1], x[2], max_y - y[2]);
1763     return 1;
1764   }
1765   /* now need to figure out arc in appropriate coordinates */
1766   r = getArc(x, y, &xc, &yc, &theta0, &dtheta);
1767   if (r == 0) return 0;
1768   /* convert to left handed XLib coords */
1769   yc = max_y - yc;
1770   /* need the ends, use angles so things match up */
1771   x0 = (int) (xc + r * cos(theta0));
1772   y0 = (int) (yc - r * sin(theta0));
1773   x2 = (int) (xc + r * cos(theta0 + dtheta));
1774   y2 = (int) (yc - r * sin(theta0 + dtheta));
1775   /* fill the arc, use the correct type of close */
1776   if (close_type) XSetArcMode(display, fillGC, ArcChord);
1777   else XSetArcMode(display, fillGC, ArcPieSlice);
1778   /* now the actual fill */
1779   XFillArc(display, P, fillGC, xc - r, yc - r, 2 * r, 2 * r,
1780            (int) ((theta0 / pi) * 180 * 64),
1781            (int) ((dtheta / pi) * 180 * 64));
1782   /* and draw the edge */
1783   XDrawArc(display, P, edgeGC, xc - r, yc - r, 2 * r, 2 * r,
1784            (int) ((theta0 / pi) * 180 * 64),
1785            (int) ((dtheta / pi) * 180 * 64));
1786   /* and close it */
1787   if (close_type) { /* chord closure */
1788     XDrawLine(display, P, edgeGC, x0, y0, x2, y2);
1789   } else { /* pie closure */
1790     XDrawLine(display, P, edgeGC, x0, y0, xc, yc);
1791     XDrawLine(display, P, edgeGC, xc, yc, x2, y2);
1792   }
1793   return 1;
1794 }
1795 /* return angles from directions in radians */
1796 static double getAngles(int xc, int yc, float dxy[4], double  *outTheta0)
1797 {
1798   int i;
1799   double theta[2], dtheta;
1800   for (i=0; i<2; ++i) {
1801     theta[i] = atan2(dxy[2 * i + 1], dxy[2 * i]);
1802     if (theta[i] < 0) theta[i] += 2 * pi; /* for XLib coords */
1803   }
1804   dtheta = theta[1] - theta[0];
1805   /* need to go in the positive direction */
1806   if (dtheta < 0) dtheta += 2 * pi;
1807   *outTheta0 = theta[0];
1808   return dtheta;
1809 }
1810 /* Circular Arc, set by center */
1811 static circcentre(dat_ptr, cmd_ptr, cgm_s)
1812      unsigned char *dat_ptr;
1813      struct cmd_info_s *cmd_ptr;
1814      cgm_s_type *cgm_s;
1815 {
1816   int i, xc, yc, r;
1817   double theta0, dtheta;
1818   float dxy[4];
1819   /* get the center */
1820   xc = getX(&dat_ptr, cgm_s);
1821   yc = getY(&dat_ptr, cgm_s);
1822   /* get the tangent vectors */
1823   for (i=0; i<4; ++i) dxy[i] = getVDC(&dat_ptr, cgm_s);
1824   /* get the radius */
1825   r = getVDC(&dat_ptr, cgm_s);
1826   if (r == 0) return 1;
1827   /* get the angles */
1828   dtheta = getAngles(xc, yc, dxy, &theta0);
1829   if (dtheta == 0) return 1;
1830   /* convert to left handed XLib coords */
1831   yc = max_y - yc;
1832   XDrawArc(display, P, lineGC, xc - r, yc - r, 2 * r, 2 * r,
1833            (int) ((theta0 / pi) * 180 * 64),
1834            (int) ((dtheta / pi) * 180 * 64));
1835   
1836   return 1;
1837 }
1838 /* Circular Arc, set by center, close */
1839 static circcclose(dat_ptr, cmd_ptr, cgm_s)
1840      unsigned char *dat_ptr;
1841      struct cmd_info_s *cmd_ptr;
1842      cgm_s_type *cgm_s;
1843 {
1844   int i, xc, yc, r, close_type, x0, y0, x1, y1;
1845   double theta0, dtheta;
1846   float dxy[4];
1847   double t0, t1;
1848   /* get the center */
1849   xc = getX(&dat_ptr, cgm_s);
1850   yc = getY(&dat_ptr, cgm_s);
1851   /* get the tangent vectors */
1852   for (i=0; i<4; ++i) dxy[i] = getVDC(&dat_ptr, cgm_s);
1853   /* get the radius */
1854   r = getVDC(&dat_ptr, cgm_s);
1855   /* get the close type */
1856   close_type = b_gsint(&dat_ptr, 16);
1857   /* get the angles */
1858   dtheta = getAngles(xc, yc, dxy, &theta0);
1859   if (dtheta == 0) return 1;
1860   /* convert to left handed XLib coords */
1861   yc = max_y - yc;
1862   /* need to get the ends */
1863   x0 = xc + r * cos(theta0);
1864   y0 = yc - r * sin(theta0);
1865   x1 = xc + r * cos(theta0 + dtheta);
1866   y1 = yc - r * sin(theta0 + dtheta);
1867   /* fill the arc, use the correct type of close */
1868   if (close_type) XSetArcMode(display, fillGC, ArcChord);
1869   else XSetArcMode(display, fillGC, ArcPieSlice);
1870   XFillArc(display, P, fillGC, xc - r, yc - r, 2 * r, 2 * r,
1871            (int) ((theta0 / pi) * 180 * 64),
1872            (int) ((dtheta / pi) * 180 * 64));
1873   /* now draw the edge */
1874   XDrawArc(display, P, edgeGC, xc - r, yc - r, 2 * r, 2 * r,
1875            (int) ((theta0 / pi) * 180 * 64),
1876            (int) ((dtheta / pi) * 180 * 64));
1877   /* and close it */
1878   if (close_type) { /* chord closure */
1879     XDrawLine(display, P, edgeGC, x0, y0, x1, y1);
1880   } else { /* pie closure */
1881     XDrawLine(display, P, edgeGC, x0, y0, xc, yc);
1882     XDrawLine(display, P, edgeGC, xc, yc, x1, y1);
1883   }
1884
1885   return 1;
1886 }
1887 /* generate a set of points for an elliptical outline between 2 angles */
1888 /* assume centred at the origin, we get two conjugate diameters */
1889 /* dxy gives tangent of angles */
1890 /* 
1891   when the ellipse is parallel to the axes we have:
1892   x = a cos(theta), y = b sin(theta), where theta is parametric
1893   when we rotate thru an angle alpha we have
1894   x = a cos(theta) * cos(alpha) - b sin(theta) * sin(alpha),
1895   y = b sin(theta) * cos(alpha) + a * cos(theta) * sin(alpha)
1896   use formulae and variable names from theory of conjugate diameters
1897   (not misleading formulae in ANSI document)
1898 */
1899 static int getEllipseXPoints(int x1, int y1, int x2, int y2,
1900                              float dxy[4], XPoint **outPtr)
1901 {
1902   int nSteps, i, rot;
1903   double D, S, alpha, a, b, ca, sa, c0, c1, s0, s1, cd, sd;
1904   double meanR, theta1, theta2, dtheta, alpha1, alpha2, dalpha, delta;
1905   double argx, argy;
1906   XPoint *myPtr;
1907   D = x2 * y1 - y2 * x1;
1908   S = (SQ(x1) + SQ(x2) + SQ(y1) + SQ(y2)) / 2.0;
1909   /* the two radii */
1910   a = sqrt(S + sqrt(SQ(S) - SQ(D)));
1911   b = sqrt(S - sqrt(SQ(S) - SQ(D)));
1912   /* the angle of axes rotation */
1913   argy = 2.0 * (x1 * y1 + x2 * y2);
1914   argx = (SQ(x1) + SQ(x2) - SQ(y1) - SQ(y2)) / 2.0;
1915
1916   /* atan2(y,x) takes the arctangent of y/x. One would assumen
1917   ** that if x is zero, then things blow up. This is not so for
1918   ** solaris. It seems that the solris math lib knows how to handle
1919   ** atan(0,0) which is the case here. However, things blow up on
1920   ** hp. So, if argx is 0, then make argy zero and argx 1.
1921   */
1922   if (argx == 0)
1923   {
1924     argy = 0;
1925     argx = 1;
1926   }
1927   alpha = atan2(argy, argx);
1928   ca = cos(alpha);
1929   sa = sin(alpha);
1930   /* we need to figure out the direction of parametric rotation */
1931   /* we always go in the direction from CD 1 to 2 thru smallest angle */
1932   alpha1 = atan2((double) y1, (double) x1);
1933   alpha2 = atan2((double) y2, (double) x2);
1934   dalpha = (alpha2 > alpha1) ? alpha2 - alpha1 : alpha1 - alpha2;
1935   rot = ((dalpha <= pi) && (alpha2 > alpha1)) ||
1936     ((dalpha <= pi) && (alpha2 < alpha1)) ? 1 : -1;
1937   /* we need to relate the incoming angles to the parametric angles */
1938   argy = a * (ca * dxy[1] - sa * dxy[0]);
1939   argx = b * (ca * dxy[0] + sa * dxy[1]);
1940   if (argx == 0)
1941   {
1942     argy = 0;
1943     argx = 1;
1944   }
1945   theta1 = atan2(argy, argx);
1946
1947   argy = a * (ca * dxy[3] - sa * dxy[2]);
1948   argx = b * (ca * dxy[2] + sa * dxy[3]);
1949   if (argx == 0)
1950   {
1951     argy = 0;
1952     argx = 1;
1953   }
1954   theta2 = atan2(argy, argx);
1955 /*
1956   theta1 = atan2(a * (ca * dxy[1] - sa * dxy[0]),
1957                  b * (ca * dxy[0] + sa * dxy[1]));
1958   theta2 = atan2(a * (ca * dxy[3] - sa * dxy[2]),
1959                  b * (ca * dxy[2] + sa * dxy[3]));
1960 */
1961   /* need to figure out angle to move thru in parameter space */
1962   /* always start at theta1 and move to theta2 */
1963   /* note (theta1 == theta2) => delta = 2 * pi */
1964   if (rot > 0) { /* move in clockwise direction */
1965     delta = (theta2 > theta1) ? theta2 - theta1 : theta2 + 2 * pi - theta1;
1966   } else { /* move in anticlockwise direction */
1967     delta = (theta2 < theta1) ? theta2 - theta1 : theta2 - 2 * pi - theta1;
1968   }
1969   /* choose a reasonable number of steps */
1970   meanR = sqrt(SQ(a) + SQ(b)) / 2;
1971   /* relate number of steps to circumference */
1972   nSteps = meanR * delta;
1973   if (nSteps < 0) nSteps = - nSteps;
1974   ++nSteps; /* so that we always have at least 2 points */
1975
1976   dtheta = delta / nSteps;
1977   /* make the points memory, always add two so it can be closed */
1978   myPtr = (XPoint *) malloc(sizeof(XPoint) * (nSteps + 2));
1979   if (myPtr == NULL)
1980     return 0;
1981   /* and fill it out */
1982   c0 = cos(theta1);
1983   s0 = sin(theta1);
1984   cd = cos(dtheta);
1985   sd = sin(dtheta);
1986   for (i=0; i<nSteps; ++i) {
1987     myPtr[i].x = a * c0 * ca - b * s0 * sa;
1988     myPtr[i].y = a * c0 * sa + b * s0 * ca;
1989     /* use recursion relation to step cos and sin */
1990     c1 = c0 * cd - s0 * sd;
1991     s1 = c0 * sd + s0 * cd;
1992     c0 = c1;
1993     s0 = s1;
1994   }
1995   /* fill out the return */
1996   *outPtr = myPtr;
1997   return nSteps;
1998 }
1999 /* Ellipse */
2000 static ellipse(dat_ptr, cmd_ptr, cgm_s)
2001      unsigned char *dat_ptr;
2002      struct cmd_info_s *cmd_ptr;
2003      cgm_s_type *cgm_s;
2004 {
2005   int xc, yc, cdx0, cdy0, cdx1, cdy1, x0, y0, w, h, noPts, i;
2006   XPoint *myPtr = NULL;
2007   static float dxy[4] = {1, 0, 1, 0}; /* make a full ellipse */
2008   /* get the Ellipse centre */
2009   xc = getX(&dat_ptr, cgm_s);
2010   yc = getY(&dat_ptr, cgm_s);
2011   /* get the first conjugate diameter endpoint */
2012   cdx0 = getX(&dat_ptr, cgm_s);
2013   cdy0 = getY(&dat_ptr, cgm_s);
2014   /* get the second conjugate diameter endpoint */
2015   cdx1 = getX(&dat_ptr, cgm_s);
2016   cdy1 = getY(&dat_ptr, cgm_s);
2017   /* have to go ahead and get the points on the curve for a polyline call */
2018   /* subtract out the centre for simplicity */
2019   noPts = getEllipseXPoints(cdx0 - xc, cdy0 - yc, cdx1 - xc, cdy1 - yc,
2020                             dxy, &myPtr);
2021   if (noPts == 0) return 0;
2022   /* convert to LH co-ord system, add centre back in */
2023   for (i=0; i<noPts; ++i) {
2024     myPtr[i].x = xc + myPtr[i].x;
2025     myPtr[i].y = max_y - (yc + myPtr[i].y);
2026   }
2027   /* make sure it closes */
2028   myPtr[noPts].x = myPtr[0].x;
2029   myPtr[noPts].y = myPtr[0].y;
2030   /* fill the ellipse */
2031   XFillPolygon(display, P, fillGC, myPtr, noPts, Convex, CoordModeOrigin);
2032   /* draw the outline */
2033   XDrawLines(display, P, edgeGC, myPtr, noPts + 1, CoordModeOrigin);  
2034   free(myPtr);
2035   return 1;
2036 }
2037 /* Elliptical arc */
2038 static elarc(dat_ptr, cmd_ptr, cgm_s)
2039      unsigned char *dat_ptr;
2040      struct cmd_info_s *cmd_ptr;
2041      cgm_s_type *cgm_s;
2042 {
2043   int xc, yc, cdx0, cdy0, cdx1, cdy1, i, noPts;
2044   float dxy[4];
2045   XPoint *myPtr = NULL;
2046   /* get the Ellipse centre */
2047   xc = getX(&dat_ptr, cgm_s);
2048   yc = getY(&dat_ptr, cgm_s);
2049   /* get the first conjugate diameter endpoint */
2050   cdx0 = getX(&dat_ptr, cgm_s);
2051   cdy0 = getY(&dat_ptr, cgm_s);
2052   /* get the second conjugate diameter endpoint */
2053   cdx1 = getX(&dat_ptr, cgm_s);
2054   cdy1 = getY(&dat_ptr, cgm_s);
2055   /* get the tangent vectors */
2056   for (i=0; i<4; ++i) dxy[i] = getVDC(&dat_ptr, cgm_s);
2057   /* have to go ahead and get the points on the curve for a polyline call */
2058   /* subtract out the centre for simplicity */
2059   noPts = getEllipseXPoints(cdx0 - xc, cdy0 - yc, cdx1 - xc, cdy1 - yc,
2060                             dxy, &myPtr);
2061   if (noPts == 0) return 0;
2062   /* convert to LH co-ord system, add centre back in */
2063   for (i=0; i<noPts; ++i) {
2064     myPtr[i].x = xc + myPtr[i].x;
2065     myPtr[i].y = max_y - (yc + myPtr[i].y);
2066   }
2067   /* draw the outline */
2068   XDrawLines(display, P, lineGC, myPtr, noPts, CoordModeOrigin);  
2069   free(myPtr);
2070   
2071   return 1;
2072 }
2073 /* Elliptical arc, close */
2074 static elarcclose(dat_ptr, cmd_ptr, cgm_s)
2075      unsigned char *dat_ptr;
2076      struct cmd_info_s *cmd_ptr;
2077      cgm_s_type *cgm_s;
2078 {
2079   int xc, yc, cdx0, cdy0, cdx1, cdy1, i, close_type, noPts;
2080   float dxy[4];
2081   XPoint *myPtr = NULL;
2082   /* get the Ellipse centre */
2083   xc = getX(&dat_ptr, cgm_s);
2084   yc = getY(&dat_ptr, cgm_s);
2085   /* get the first conjugate diameter endpoint */
2086   cdx0 = getX(&dat_ptr, cgm_s);
2087   cdy0 = getY(&dat_ptr, cgm_s);
2088   /* get the second conjugate diameter endpoint */
2089   cdx1 = getX(&dat_ptr, cgm_s);
2090   cdy1 = getY(&dat_ptr, cgm_s);
2091   /* get the tangent vectors */
2092   for (i=0; i<4; ++i) dxy[i] = getVDC(&dat_ptr, cgm_s);
2093   /* get the close type */
2094   close_type = b_gsint(&dat_ptr, 16);
2095   /* have to go ahead and get the points on the curve for a polyline call */
2096   /* subtract out the centre for simplicity */
2097   noPts = getEllipseXPoints(cdx0 - xc, cdy0 - yc, cdx1 - xc, cdy1 - yc,
2098                             dxy, &myPtr);
2099   if (noPts == 0) return 0;
2100   /* convert to LH co-ord system, add centre back in */
2101   for (i=0; i<noPts; ++i) {
2102     myPtr[i].x = xc + myPtr[i].x;
2103     myPtr[i].y = max_y - (yc + myPtr[i].y);
2104   }
2105   /* now add in the closure */
2106   if (close_type) { /* chord closure */
2107     myPtr[noPts].x = myPtr[0].x;
2108     myPtr[noPts].y = myPtr[0].y;
2109     ++noPts;
2110   } else { /* pie closure */
2111     myPtr[noPts].x = xc;
2112     myPtr[noPts].y = max_y - yc;
2113     myPtr[noPts + 1].x = myPtr[0].x;
2114     myPtr[noPts + 1].y = myPtr[0].y;
2115     noPts += 2;
2116   }
2117   /* fill the arc */
2118   XFillPolygon(display, P, fillGC, myPtr, noPts, Convex, CoordModeOrigin);  
2119   /* draw the outline */
2120   XDrawLines(display, P, edgeGC, myPtr, noPts, CoordModeOrigin);  
2121   free(myPtr);
2122   
2123   return 1;
2124 }
2125 /* Attribute elements */
2126 static int setLineType(int inType, GC inGC)
2127 {
2128   /* set the GC */
2129   switch(inType) {
2130   case 1: /* solid */
2131     myStruct.line_style = LineSolid;
2132     XChangeGC(display, inGC, GCLineStyle, &myStruct);
2133     break;
2134   case 2: /* dash */
2135     myStruct.line_style = LineOnOffDash;
2136     XChangeGC(display, inGC, GCLineStyle, &myStruct);
2137     XSetDashes(display, inGC, 0, lineArray, 2);
2138     break;
2139   case 3: /* dot */
2140     myStruct.line_style = LineOnOffDash;
2141     XChangeGC(display, inGC, GCLineStyle, &myStruct);
2142     XSetDashes(display, inGC, 0, lineArray + 2, 2);
2143     break;
2144   case 4: /* dash-dot */
2145     myStruct.line_style = LineOnOffDash;
2146     XChangeGC(display, inGC, GCLineStyle, &myStruct);
2147     XSetDashes(display, inGC, 0, lineArray, 4);
2148     break;
2149   case 5: /* dash-dot-dot */
2150     myStruct.line_style = LineOnOffDash;
2151     XChangeGC(display, inGC, GCLineStyle, &myStruct);
2152     XSetDashes(display, inGC, 0, lineArray, 6);
2153     break;
2154   default: return 1; /* no idea */
2155   }
2156   return 1;
2157 }
2158 /* Line Type */
2159 static ltype(dat_ptr, cmd_ptr, cgm_s)
2160      unsigned char *dat_ptr;
2161      struct cmd_info_s *cmd_ptr;
2162      cgm_s_type *cgm_s;
2163 {
2164   /* get the line type */
2165   cgm_s->ltype = b_gsint(&dat_ptr, cgm_s->indexprec);
2166   return setLineType(cgm_s->ltype, lineGC);
2167 }
2168 /* Line Width */
2169 static lwidth(dat_ptr, cmd_ptr, cgm_s)
2170      unsigned char *dat_ptr;
2171      struct cmd_info_s *cmd_ptr;
2172      cgm_s_type *cgm_s;
2173 {
2174   switch (cgm_s->lwidspecmode) {
2175   case ABSOLUTE:
2176     switch (cgm_s->vdctype) {
2177     case VDC_INT: cgm_s->lwidth.i = xScale * b_gsint(&dat_ptr, cgm_s->vdcintprec);
2178       break;
2179     case VDC_REAL: cgm_s->lwidth.r = xScale * b_real(&dat_ptr, &(cgm_s->vdcrprec));
2180       cgm_s->lwidth.i = cgm_s->lwidth.r;
2181       break;
2182     }
2183     break;
2184   case SCALED:  cgm_s->lwidth.s = b_real(&dat_ptr, &(cgm_s->realprec));
2185     cgm_s->lwidth.i = cgm_s->lwidth.s; /* scale from 1 */
2186     break;
2187   }
2188   /* some servers can't handle widths of 1 */
2189   myStruct.line_width = (cgm_s->lwidth.i < 2) ? 0 : cgm_s->lwidth.i;
2190   XChangeGC(display, lineGC, GCLineWidth, &myStruct);
2191   return 1;
2192 }
2193 /* Line Colour */
2194 static lcolr(dat_ptr, cmd_ptr, cgm_s)
2195      unsigned char *dat_ptr;
2196      struct cmd_info_s *cmd_ptr;
2197      cgm_s_type *cgm_s;
2198 {
2199   int i;
2200   
2201   /* may be in direct colour mode or indexed colour mode */
2202   switch (cgm_s->colselmode) {
2203   case D_C_M:   for (i=0; i<3; ++i) cgm_s->lcolr[i] = 
2204     b_guint(&dat_ptr, cgm_s->colprec);
2205     setRGB(cgm_s, cgm_s->lcolr, lineGC);
2206     break;
2207   case I_C_M:   cgm_s->lcolr[3] = b_guint(&dat_ptr, cgm_s->cindprec);
2208     setIndex(cgm_s, cgm_s->lcolr[3], lineGC);
2209     break;
2210   default: /* nothing */ break;
2211   }
2212   return 1;
2213 }
2214 /* Marker Type */
2215 static mtype(dat_ptr, cmd_ptr, cgm_s)
2216      unsigned char *dat_ptr;
2217      struct cmd_info_s *cmd_ptr;
2218      cgm_s_type *cgm_s;
2219 {
2220   /* get the line type */
2221   cgm_s->mtype = b_gsint(&dat_ptr, cgm_s->indexprec);
2222   
2223   return 1;
2224 }
2225 /* Marker Size */
2226 static msize(dat_ptr, cmd_ptr, cgm_s)
2227      unsigned char *dat_ptr;
2228      struct cmd_info_s *cmd_ptr;
2229      cgm_s_type *cgm_s;
2230 {
2231   switch (cgm_s->marksizspecmode) {
2232   case ABSOLUTE:
2233     switch (cgm_s->vdctype) {
2234     case VDC_INT:       
2235     case VDC_REAL:
2236       cgm_s->msize.i = getVDC(&dat_ptr, cgm_s);
2237       break;
2238     }
2239     break;
2240   case SCALED:  cgm_s->msize.s = b_real(&dat_ptr, &(cgm_s->realprec));
2241     cgm_s->msize.i = (int) (cgm_s->msize.s * 5);
2242     break;
2243   }
2244   return 1;
2245 }
2246 /* Marker Colour */
2247 static mcolr(dat_ptr, cmd_ptr, cgm_s)
2248      unsigned char *dat_ptr;
2249      struct cmd_info_s *cmd_ptr;
2250      cgm_s_type *cgm_s;
2251 {
2252   int i;
2253   /* may be in direct colour mode or indexed colour mode */
2254   switch (cgm_s->colselmode) {
2255   case D_C_M:   for (i=0; i<3; ++i) cgm_s->mcolr[i] = 
2256     b_guint(&dat_ptr, cgm_s->colprec);
2257     setRGB(cgm_s, cgm_s->mcolr, markGC);
2258     break;
2259   case I_C_M:   cgm_s->mcolr[3] = b_guint(&dat_ptr, cgm_s->cindprec);
2260     setIndex(cgm_s, cgm_s->mcolr[3], markGC);
2261     break;
2262   }
2263   return 1;
2264 }
2265 /* Text Font Index, ignored at the moment */
2266 static tfindex(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2267                cgm_s_type *cgm_s)
2268 {
2269   /* get the text font index */
2270   cgm_s->tfindex = b_gsint(&dat_ptr, cgm_s->indexprec);
2271   
2272   return 1;
2273 }
2274 /* Text Precision, ignored at the moment; stroke everything */
2275 static tprec(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2276              cgm_s_type *cgm_s)
2277 {
2278   /* get the text font index */
2279   cgm_s->tprec = b_gsint(&dat_ptr, 16);
2280   
2281   return 1;
2282 }
2283 /* Character Expansion Factor */
2284 static cexpfac(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2285      cgm_s_type *cgm_s)
2286 {
2287   cgm_s->cexpfac = b_real(&dat_ptr, &(cgm_s->realprec));
2288   
2289   return 1;
2290 }
2291 /* Character Space */
2292 static cspace(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2293               cgm_s_type *cgm_s)
2294 {
2295   cgm_s->cspace = b_real(&dat_ptr, &(cgm_s->realprec));
2296   
2297   return 1;
2298 }
2299 /* Text Colour */
2300 static tcolr(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2301      cgm_s_type *cgm_s)
2302 {
2303   int i, index;
2304   
2305   /* may be in direct colour mode or indexed colour mode */
2306   switch (cgm_s->colselmode) {
2307   case D_C_M:
2308     for (i=0; i<3; ++i) {
2309       cgm_s->tcolr[i] = b_guint(&dat_ptr, cgm_s->colprec);
2310     }
2311     cgm_s->tPixel = getPixel(cgm_s, cgm_s->tcolr);
2312     break;
2313   case I_C_M:
2314     cgm_s->tcolr[3] = index = b_guint(&dat_ptr, cgm_s->cindprec);
2315     if ((index >= 0) && (index < MAXCOLRS) && coltabPixels[index]) {
2316       cgm_s->tPixel = coltabPixels[index];
2317     } else cgm_s->tPixel = blackPixel; 
2318     break;
2319   }
2320   
2321   return 1;
2322 }
2323 /* Character Height */
2324 static cheight(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2325                cgm_s_type *cgm_s)
2326 {
2327   /* just 1 VDC to grab */
2328   cgm_s->cheight.i = getVDC(&dat_ptr, cgm_s);
2329   return 1;
2330 }
2331 /* Character Orientation */
2332 static corient(unsigned char *dat_ptr,struct cmd_info_s *cmd_ptr,
2333      cgm_s_type *cgm_s)
2334 {
2335   int i;
2336   
2337   /* just 4 VDC's to grab */
2338   switch (cgm_s->vdctype) {
2339   case VDC_INT: for (i=0; i<4; ++i) 
2340     cgm_s->corient[i].i = b_gsint(&dat_ptr, cgm_s->vdcintprec);
2341     break;
2342   case VDC_REAL:        for (i=0; i<4; ++i) 
2343     cgm_s->corient[i].r = b_real(&dat_ptr, &(cgm_s->vdcrprec));
2344     break;
2345   }
2346   return 1;
2347 }
2348 /* Text Path */
2349 static tpath(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2350      cgm_s_type *cgm_s)
2351 {
2352   cgm_s->tpath = b_gsint(&dat_ptr, 16);
2353   
2354   return 1;
2355 }
2356 /* Text Alignment */
2357 static talign(unsigned char *dat_ptr, struct cmd_info_s *cmd_ptr,
2358      cgm_s_type *cgm_s)
2359 {
2360   int i;
2361   
2362   /* first the 2 enumerated types */
2363   for (i=0; i<2; ++i) cgm_s->talign[i].i = b_gsint(&dat_ptr, 16);
2364   /* now the 2 real bits */
2365   for (i=0; i<2; ++i) cgm_s->talign[i].r = 
2366     b_real(&dat_ptr, &(cgm_s->realprec));
2367   
2368   return 1;
2369 }
2370 /* Character Set Index */
2371 static csetindex(dat_ptr, cmd_ptr, cgm_s)
2372      unsigned char *dat_ptr;
2373      struct cmd_info_s *cmd_ptr;
2374      cgm_s_type *cgm_s;
2375 {
2376   cgm_s->csetindex = b_gsint(&dat_ptr, cgm_s->indexprec);
2377   
2378   return 1;
2379 }
2380 /* Alternate Character Set Index */
2381 static altcsetindex(dat_ptr, cmd_ptr, cgm_s)
2382      unsigned char *dat_ptr;
2383      struct cmd_info_s *cmd_ptr;
2384      cgm_s_type *cgm_s;
2385 {
2386   cgm_s->altcsetindex = b_gsint(&dat_ptr, cgm_s->indexprec);
2387   
2388   return 1;
2389 }
2390 /* Interior Style */
2391 static intstyle(dat_ptr, cmd_ptr, cgm_s)
2392      unsigned char *dat_ptr;
2393      struct cmd_info_s *cmd_ptr;
2394      cgm_s_type *cgm_s;
2395 {
2396   cgm_s->intstyle = b_gsint(&dat_ptr, 16);
2397   switch (cgm_s->intstyle) {
2398   case 0: /* hollow, implementation dependent, make it the same as empty */
2399   case 4: /* empty, don't fill */
2400     XSetFunction(display, fillGC, GXnoop);
2401     break;
2402   case 1: /* solid */
2403   case 2: /* pattern */
2404   case 3: /* hatch, fill all of these */
2405     XSetFunction(display, fillGC, GXcopy);
2406     XSetFillStyle(display, fillGC, FillSolid);
2407     break;
2408   default: /* do nothing */
2409     break;
2410   }
2411   
2412   return 1;
2413 }
2414 /* Fill Colour */
2415 static fillcolr(dat_ptr, cmd_ptr, cgm_s)
2416      unsigned char *dat_ptr;
2417      struct cmd_info_s *cmd_ptr;
2418      cgm_s_type *cgm_s;
2419 {
2420   int i;
2421   
2422   /* may be in direct colour mode or indexed colour mode */
2423   switch (cgm_s->colselmode) {
2424   case D_C_M:   for (i=0; i<3; ++i) cgm_s->fillcolr[i] = 
2425     b_guint(&dat_ptr, cgm_s->colprec);
2426     setRGB(cgm_s, cgm_s->fillcolr, fillGC);
2427     break;
2428   case I_C_M:   cgm_s->fillcolr[3] = b_guint(&dat_ptr, cgm_s->cindprec);
2429     setIndex(cgm_s, cgm_s->fillcolr[3], fillGC);
2430     break;
2431   }
2432   
2433   return 1;
2434 }
2435 /* Hatch Index */
2436 static hatchindex(dat_ptr, cmd_ptr, cgm_s)
2437      unsigned char *dat_ptr;
2438      struct cmd_info_s *cmd_ptr;
2439      cgm_s_type *cgm_s;
2440 {
2441   cgm_s->hatchindex = b_gsint(&dat_ptr, cgm_s->indexprec);
2442   
2443   return 1;
2444 }
2445 /* Pattern Index */
2446 static patindex(dat_ptr, cmd_ptr, cgm_s)
2447      unsigned char *dat_ptr;
2448      struct cmd_info_s *cmd_ptr;
2449      cgm_s_type *cgm_s;
2450 {
2451   cgm_s->patindex = b_gsint(&dat_ptr, cgm_s->indexprec);
2452   
2453   return 1;
2454 }
2455 /* Edge Type */
2456 static etype(dat_ptr, cmd_ptr, cgm_s)
2457      unsigned char *dat_ptr;
2458      struct cmd_info_s *cmd_ptr;
2459      cgm_s_type *cgm_s;
2460 {
2461   cgm_s->etype = b_gsint(&dat_ptr, cgm_s->indexprec);
2462   return setLineType(cgm_s->etype, edgeGC);
2463 }
2464 /* Edge Width */
2465 static ewidth(dat_ptr, cmd_ptr, cgm_s)
2466      unsigned char *dat_ptr;
2467      struct cmd_info_s *cmd_ptr;
2468      cgm_s_type *cgm_s;
2469 {
2470   switch (cgm_s->edwidspecmode) {
2471   case ABSOLUTE:
2472     switch (cgm_s->vdctype) {
2473     case VDC_INT: cgm_s->ewidth.i = xScale * b_gsint(&dat_ptr, cgm_s->vdcintprec);
2474       break;
2475     case VDC_REAL: cgm_s->ewidth.r = xScale * b_real(&dat_ptr, &(cgm_s->vdcrprec));
2476       cgm_s->ewidth.i = cgm_s->ewidth.r;
2477       break;
2478     }
2479     break;
2480   case SCALED:  cgm_s->ewidth.s = b_real(&dat_ptr, &(cgm_s->realprec));
2481     cgm_s->ewidth.i = cgm_s->ewidth.s; /* scale from 1 */
2482     break;
2483   }
2484   /* some servers can't handle widths of 1 */
2485   myStruct.line_width = (cgm_s->ewidth.i < 2) ? 0 : cgm_s->ewidth.i;
2486   XChangeGC(display, edgeGC, GCLineWidth, &myStruct);
2487   return 1;
2488 }
2489 /* Edge Colour */
2490 static ecolr(dat_ptr, cmd_ptr, cgm_s)
2491      unsigned char *dat_ptr;
2492      struct cmd_info_s *cmd_ptr;
2493      cgm_s_type *cgm_s;
2494 {
2495   int i;
2496   
2497   /* may be in direct colour mode or indexed colour mode */
2498   switch (cgm_s->colselmode) {
2499   case D_C_M:   for (i=0; i<3; ++i) cgm_s->ecolr[i] = 
2500     b_guint(&dat_ptr, cgm_s->colprec);
2501     setRGB(cgm_s, cgm_s->ecolr, edgeGC);
2502     break;
2503   case I_C_M:   cgm_s->ecolr[3] = b_guint(&dat_ptr, cgm_s->cindprec);
2504     setIndex(cgm_s, cgm_s->ecolr[3], edgeGC);
2505     break;
2506   }
2507   
2508   return 1;
2509 }
2510 /* Edge Visibility */
2511 static evis(dat_ptr, cmd_ptr, cgm_s)
2512      unsigned char *dat_ptr;
2513      struct cmd_info_s *cmd_ptr;
2514      cgm_s_type *cgm_s;
2515 {
2516   cgm_s->evis = b_gsint(&dat_ptr, 16);
2517   if (cgm_s->evis) { /* visible edge */
2518     XSetFunction(display, edgeGC, GXcopy);
2519   } else { /* invisible edge */
2520     XSetFunction(display, edgeGC, GXnoop);
2521   }
2522   return 1;
2523 }
2524 /* Colour Table */
2525 static coltab(dat_ptr, cmd_ptr, cgm_s)
2526      unsigned char *dat_ptr;
2527      struct cmd_info_s *cmd_ptr;
2528      cgm_s_type *cgm_s;
2529 {
2530   int i, j, first_index, no_entries, iColrs[3];
2531   
2532   /* get the starting index */
2533   first_index = b_guint(&dat_ptr, cgm_s->cindprec);
2534   
2535   /* how many entries do we have ? */
2536   no_entries = (cmd_ptr->p_len * 8 - cgm_s->cindprec) / 
2537     (3 * cgm_s->colprec);
2538   
2539   for (i=0; (i < no_entries) && ((i+first_index) < MAXCOLRS); ++i) {
2540     for (j=0; j<3; ++j) {
2541       iColrs[j] = b_guint(&dat_ptr, cgm_s->colprec);
2542     }
2543     coltabPixels[i+first_index] = getPixel(cgm_s, iColrs);
2544   }
2545   
2546   return 1;
2547 }
2548 /* this is the external entry point */
2549 do_b_cmd(struct cmd_info_s *cmd_ptr, unsigned char *dat_ptr,
2550         cgm_s_type *cgm_s)
2551 {
2552   /* for convenience define and argument list macro */
2553 #define ARG_LIST dat_ptr,cmd_ptr, cgm_s
2554     
2555     /* split it up by classes, and then by element */
2556     switch (cmd_ptr->Class) {
2557       /* the Delimiters (Class 0) */
2558     case B_DELIMCLASS:  switch (cmd_ptr->element) {
2559     case B_NOOP:        return 1;
2560     case B_BMF:         return(bmf(ARG_LIST));
2561     case B_EMF:         return(emf(ARG_LIST));
2562     case B_BPIC:        return(bpic(ARG_LIST));
2563     case B_BPICBODY:    return(bpicbody(ARG_LIST));
2564     case B_EPIC:        return(epic(ARG_LIST));
2565     default:    burp(stderr, "illegal Delimiter element %d\n", 
2566                      cmd_ptr->element);
2567       return(0);
2568     }
2569       /* the Metafile descriptor elements (Class 1) */
2570     case B_MDESCLASS:   switch (cmd_ptr->element) {
2571     case B_MFVERSION:   return(mfversion(ARG_LIST));
2572     case B_MFDESCRIP:   return(mfdescrip(ARG_LIST));
2573     case B_VDCTYPE:     return(vdctype(ARG_LIST));
2574     case B_INTPREC:     return(intprec(ARG_LIST));
2575     case B_REALPREC:    return(realprec(ARG_LIST));
2576     case B_INDEXPREC:   return(indexprec(ARG_LIST));
2577     case B_COLPREC:     return(colprec(ARG_LIST));
2578     case B_CINDPREC:    return(cindprec(ARG_LIST));
2579     case B_MAXCIND:     return(maxcind(ARG_LIST));
2580     case B_CVEXTENT:    return(cvextent(ARG_LIST));
2581     case B_MFELLIST:    return(mfellist(ARG_LIST));
2582     case B_MFDEFREP:    return(mfdefrep(ARG_LIST));     /* special */
2583     case B_FONTLIST:    return(fontlist(ARG_LIST));
2584     case B_CHARLIST:    return(charlist(ARG_LIST));
2585     case B_CHARANNOUNCE:        return(charannounce(ARG_LIST));
2586     default:    burp(stderr, "illegal Metafile descriptor element %d\n", 
2587                      cmd_ptr->element);
2588       return(0);
2589     }
2590       
2591       /* the Picture descriptor elements (Class 2) */
2592     case B_PDESCLASS:   switch (cmd_ptr->element) {
2593     case B_SCALMODE:            return(scalmode(ARG_LIST));
2594     case B_COLSELMODE:          return(colselmode(ARG_LIST));
2595     case B_LWIDSPECMODE:        return(lwidspecmode(ARG_LIST));
2596     case B_MARKSIZSPECMODE:     return(marksizspecmode(ARG_LIST));
2597     case B_EDWIDSPECMODE:       return(edwidspecmode(ARG_LIST));
2598     case B_VDCEXTENT:           return(vdcextent(ARG_LIST));
2599     case B_BACKCOLR:            return(backcolr(ARG_LIST));
2600     default:    burp(stderr, "illegal Picture Descriptor element %d\n", 
2601                      cmd_ptr->element);
2602       return(0);
2603     }
2604       /* the Control elements (Class 3) */
2605     case B_CTRLCLASS:   switch( cmd_ptr->element) {
2606     case B_VDCINTPREC:  return(vdcintprec(ARG_LIST));
2607     case B_VDCRPREC:    return(vdcrprec(ARG_LIST));
2608     case B_AUXCOLR:     return(auxcolr(ARG_LIST));
2609     case B_TRANSP:      return(transp(ARG_LIST));
2610     case B_CLIPRECT:    return(cliprect(ARG_LIST));
2611     case B_CLIPINDIC:   return(clipindic(ARG_LIST));
2612     default:    burp(stderr, "illegal Control element %d\n", 
2613                      cmd_ptr->element);
2614       return(0);
2615     }
2616       /* the Graphical Primitives (Class 4) */
2617     case B_GPRIMCLASS:  switch (cmd_ptr->element) {
2618     case B_POLYLINE:    return(polyline(ARG_LIST));
2619     case B_DISPOLY:     return(dispoly(ARG_LIST));
2620     case B_POLYMARKER:  return(polymarker(ARG_LIST));
2621     case B_TEXT:        return(text(ARG_LIST));
2622     case B_RESTEXT:     return(restext(ARG_LIST));
2623     case B_APPTEXT:     return(apptext(ARG_LIST));
2624     case B_POLYGON:     return(polygon(ARG_LIST));
2625     case B_POLYSET:     return(polyset(ARG_LIST));
2626     case B_CELLARRAY:   return(cellarray(ARG_LIST));
2627     case B_GENDPRIM:    return 1; /* not used here */
2628     case B_RECTANGLE:   return(rectangle(ARG_LIST));
2629     case B_CIRCLE:      return(circle(ARG_LIST));
2630     case B_CIRC3:       return(circ3(ARG_LIST));
2631     case B_CIRC3CLOSE:  return(circ3close(ARG_LIST));
2632     case B_CIRCCENTRE:  return(circcentre(ARG_LIST));
2633     case B_CIRCCCLOSE:  return(circcclose(ARG_LIST));
2634     case B_ELLIPSE:     return(ellipse(ARG_LIST));
2635     case B_ELARC:       return(elarc(ARG_LIST));
2636     case B_ELARCCLOSE:  return(elarcclose(ARG_LIST));
2637     default:    burp(stderr, "illegal Graphical Primitive element %d\n",
2638                      cmd_ptr->element);
2639       return(0);
2640     }
2641       /* the Attribute elements (Class 5) */
2642     case B_ATTRCLASS:   switch (cmd_ptr->element) {
2643     case B_LBINDEX:             return 1;
2644     case B_LTYPE:               return(ltype(ARG_LIST));
2645     case B_LWIDTH:              return(lwidth(ARG_LIST));
2646     case B_LCOLR:               return(lcolr(ARG_LIST));
2647     case B_MBINDEX:             return 1;
2648     case B_MTYPE:               return(mtype(ARG_LIST));
2649     case B_MSIZE:               return(msize(ARG_LIST));
2650     case B_MCOLR:               return(mcolr(ARG_LIST));
2651     case B_TBINDEX:             return 1;
2652     case B_TFINDEX:             return(tfindex(ARG_LIST));
2653     case B_TPREC:               return(tprec(ARG_LIST));
2654     case B_CEXPFAC:             return(cexpfac(ARG_LIST));
2655     case B_CSPACE:              return(cspace(ARG_LIST));
2656     case B_TCOLR:               return(tcolr(ARG_LIST));
2657     case B_CHEIGHT:             return(cheight(ARG_LIST));
2658     case B_CORIENT:             return(corient(ARG_LIST));
2659     case B_TPATH:               return(tpath(ARG_LIST));
2660     case B_TALIGN:              return(talign(ARG_LIST));
2661     case B_CSETINDEX:           return(csetindex(ARG_LIST));
2662     case B_ALTCSETINDEX:        return(altcsetindex(ARG_LIST));
2663     case B_FILLBINDEX:          return 1;
2664     case B_INTSTYLE:            return(intstyle(ARG_LIST));
2665     case B_FILLCOLR:            return(fillcolr(ARG_LIST));
2666     case B_HATCHINDEX:          return(hatchindex(ARG_LIST));
2667     case B_PATINDEX:            return(patindex(ARG_LIST));
2668     case B_EDBINDEX:            return 1;
2669     case B_ETYPE:               return(etype(ARG_LIST));
2670     case B_EWIDTH:              return(ewidth(ARG_LIST));
2671     case B_ECOLR:               return(ecolr(ARG_LIST));
2672     case B_EVIS:                return(evis(ARG_LIST));
2673     case B_FILLREF:             return 1;
2674     case B_PATTAB:              return 1;
2675     case B_PATSIZE:             return 1;
2676     case B_COLTAB:              return(coltab(ARG_LIST));
2677     case B_ASPSFLAGS:           return 1;
2678     default:    burp(stderr, "illegal Attribute element %d\n", 
2679                      cmd_ptr->element);
2680       return(0);
2681     }
2682       /* the Escape element (Class 6) */
2683     case B_ESCCLASS: return 1;
2684       /* the External elements (Class 7) */
2685     case B_EXTCLASS: return 1;
2686       /* any other class */
2687     default:    burp(stderr, "illegal class %d\n", cmd_ptr->Class);
2688       return(0);
2689     }
2690 #undef ARG_LIST
2691 }
2692 #undef UINT