0023663: Removing 2D viewer library
[occt.git] / src / CGM / cgmobin.c
1 /*
2  Copyright (c) 1999-2012 OPEN CASCADE SAS
3
4  The content of this file is subject to the Open CASCADE Technology Public
5  License Version 6.5 (the "License"). You may not use the content of this file
6  except in compliance with the License. Please obtain a copy of the License
7  at http://www.opencascade.org and read it completely before using this file.
8
9  The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
10  main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
11
12  The Original Code and all software distributed under the License is
13  distributed on an "AS IS" basis, without warranty of any kind, and the
14  Initial Developer hereby disclaims all such warranties, including without
15  limitation, any warranties of merchantability, fitness for a particular
16  purpose or non-infringement. Please see the License for the specific terms
17  and conditions governing the rights and limitations under the License.
18
19 */
20
21 #include <limits.h>
22 #include "cgmout.h"
23
24 /* File stream name */
25
26 static FILE *cgmob;
27
28 /* declare internal functions */
29 # if (defined __STDC__ && __STDC__) || defined __cplusplus
30 /* use function prototypes, they are requred for ANSI C and C++ compilers */
31 void CGMObin(FILE *stream, Code c, Long *pi, Float *pr, char *str);
32 /* Main Output Routine */
33 static void MOBopcode(Code c, Long len),                         /* Output an Op code */
34             MOBint(Long n, Prec prec, Enum sign),                /* Output an Integer */
35             MOBreal(Double x, Enum real_type, Enum real_or_vdc), /* Output a real number */
36             MOBcolour(struct colour *col, Enum type),            /* Output a colour */
37             MOBvdc(Int n, Long *pi, Float *pr),                  /* Output a number of VDCs */
38             MOBpointlist(Long n, Long *pi, Float *pr, Enum set), /* Output a Points List */
39             MOBclist(register Long num, register Long *col,
40                      Prec mode, Enum type, Prec prec),           /* Output a colour list */
41             MOBbits(Posint value, Prec prec, Long *bit),         /* Output a value to a bit stream */
42             MOBstring(char *s),                                  /* Output a string */
43             MOBout(Posint hex, Prec bytes),                      /* Output values to the output buffer */
44             MOBcharci(Code c, Int *class, Int *id);              /* Convert Op code value to Class and Id */
45 #else
46 void CGMObin();  /* Main Output Routine */
47 static void MOBopcode(),    /* Output an Op code */
48             MOBint(),       /* Output an Integer */
49             MOBreal(),      /* Output a real number */
50             MOBcolour(),    /* Output a colour */
51             MOBvdc(),       /* Output a number of VDCs */
52             MOBpointlist(), /* Output a Points List */
53             MOBclist(),     /* Output a colour list */
54             MOBbits(),      /* Output a value to a bit stream */
55             MOBstring(),    /* Output a string */
56             MOBout(),       /* Output values to the output buffer */
57             MOBcharci();    /* Convert Op code value to Class and Id */
58 #endif
59 /*  Local Parameters */
60
61 #define ENUMERATED   (Prec) 16
62
63 #define PARTITION    (Code) 0xff
64
65 #define UNSIGNED     (Enum) 0
66 #define SIGNED       (Enum) 1
67
68 #define FLOATING     (Enum) 0
69 #define FIXED        (Enum) 1
70
71 #define RUNLENGTH    (Enum) 0
72 #define PACKED       (Enum) 1
73
74 #define BYTE         (Prec) 1
75 #define WORD         (Prec) 2
76 #define LONGINT      (Prec) 4
77
78 /*  Parameter sizes */
79
80 #define ENUMSIZE     ( (Long) 2 )
81 #define INDEXSIZE    ( (Long) curbin.index_prec>>3 )
82 #define COLINDEXSIZE ( (Long) curbin.colind_prec>>3 )
83 #define INTSIZE      ( (Long) curbin.int_prec>>3 )
84 #define REALSIZE     ( (Long) (curbin.real_whole + curbin.real_fraction)>>3 )
85 #define VDCSIZE      ( (Long) (cur.vdc_type == REAL\
86                        ? (curbin.vdc_whole + curbin.vdc_fraction)>>3 \
87                        : curbin.vdcint_prec>>3 ) )
88 #define COLOURSIZE    ( (Long) (cur.color_mode == DIRECT\
89                        ? 3*curbin.col_prec>>3 : curbin.colind_prec>>3 ) )
90 #define STRINGSIZE(x) ( (Long) (256 * strlen(x) / 255 + 1) )
91
92 /*  Basic Common Output functions */
93
94 #define PUTBYTE(x)    MOBout( (Posint) x, (Prec) 1 )
95 #define PUTWORD(x)    MOBout( (Posint) x, (Prec) 2 )
96 #define PUTINT(x)     MOBint( (Long) x, curbin.int_prec, SIGNED )
97 #define PUTREAL(x)    MOBreal ( (Double)x, curbin.real_type, REAL )
98 #define PUTINDEX(x)   MOBint( (Long) x, curbin.index_prec, SIGNED )
99 #define PUTENUM(x)    MOBint( (Long) x, ENUMERATED, SIGNED )
100 #define PUTINTVDC(x)  MOBint( (Long) x, curbin.vdcint_prec, SIGNED )
101 #define PUTREALVDC(x) MOBreal( (Double)x, curbin.vdc_type, VDC )
102
103 /* Local Variables */
104
105 static size_t mobblen = BUFF_LEN,   /* Normal Output Buffer length */
106             mobparmlen,           /* Parameter length in bytes */
107             mobremainder,         /* Bytes left after partition */
108             mobdeflen,            /* MF Defaults replacement length */
109             mobindex = 0;         /* Output buffer pointer */
110 static char mobstdbuff[BUFF_LEN], /* Normal Output buffer */
111            *mobbuff = mobstdbuff, /* Buffer origin */
112            *mobdefbuff;           /* MF Defaults replacement buffer */
113
114 /*static char *func="CGMobin", mess[40];*/
115 static char mess[40];
116
117 /********************************************************* CGMObin *****/
118 void
119 CGMObin(FILE *stream, Code c, Long *pi, Float *pr, char *str)
120 {
121    register Long j, n, num;
122    Code major;
123    Long parmlen = ZERO;
124    static Long defindex, saveparmlen;
125    static Logical first = TRUE, first_pic = TRUE;
126    Int class, id;
127
128    if ( c == (Code) EOF )
129    {
130       MOBout ( (Posint) 0, (Prec) 0); /* flush output buffer */
131       exit(0);
132    }
133
134    major=c>>8;
135    num = *pi++;
136
137    switch(major)
138    {
139       case 0x00: /* Graphics Primitives */
140
141          switch(c)
142          {
143             case NONOP:  /* Ignore Non-Op */
144                break;
145
146             case LINE:      /* Polyline */
147             case DISJTLINE: /* Disjoint Polyline */
148             case MARKER: /* Polymarker */
149                parmlen = 2*num*VDCSIZE;
150                if ( first ) MOBopcode(c, parmlen);
151                else         MOBopcode(PARTITION, parmlen);
152                first = ( parmlen >= ZERO );
153                MOBpointlist(num, pi, pr, NOSET);
154                break;
155
156             case TEXT: /* Text */
157                parmlen = 2*VDCSIZE + ENUMSIZE + STRINGSIZE(str);
158                MOBopcode(c, parmlen);
159                MOBvdc( (Int)2, pi, pr);
160                PUTENUM ( num );
161                MOBstring(str);
162                break;
163
164             case RESTRTEXT: /* Restricted Text */
165                parmlen = 4*VDCSIZE + ENUMSIZE + STRINGSIZE(str);
166                MOBopcode(c, parmlen);
167                MOBvdc( (Int)4, pi, pr);
168                PUTENUM ( num );
169                MOBstring(str);
170                break;
171
172             case APNDTEXT: /* Append Text */
173                parmlen = ENUMSIZE + STRINGSIZE(str);
174                MOBopcode(c, parmlen);
175                PUTENUM ( num );
176                MOBstring(str);
177                break;
178
179             case POLYGON: /* Polygon */
180                parmlen = 2*num*VDCSIZE;
181                if ( first ) MOBopcode(c, parmlen);
182                else         MOBopcode(PARTITION, parmlen);
183                first = ( parmlen >= ZERO );
184                MOBpointlist(num, pi, pr, NOSET);
185                break;
186
187             case POLYGONSET: /* Polygon Set */
188                parmlen = num * ( 2*VDCSIZE + ENUMSIZE );
189                if ( first ) MOBopcode(c, parmlen);
190                else         MOBopcode(PARTITION, parmlen);
191                first = ( parmlen >= ZERO );
192                MOBpointlist(num, pi, pr, SET);
193                break;
194
195             case CELLARRAY: /* Cell Array */
196             {
197                register Long *pt = pi, i, k;
198                Long red, green, blue, nc, ncol;
199                Long run, packed;
200                Long last, lastred, lastgreen, lastblue;
201                static Long nx, ny;
202                static Prec lprec;
203                static Enum runlength;
204
205 /*  Number of colour cells */
206
207                nc = abs( num );
208                ncol = abs(cur.color_mode == DIRECT ? 3*num : num );
209
210                if ( first )
211                {
212
213 /*  set up basic parameter length */
214                   parmlen = 6*VDCSIZE + 3*INTSIZE + ENUMSIZE;
215                   pt += 6;    /* skip 3 points */
216                   nx = *pt++;     /* Number of columns */
217                   ny = *pt++;     /* Number of rows */
218                   j  = *pt++;     /* Local precision */
219
220                   if ( j == ZERO || num > 0 )
221                   {
222
223 /*  Find largest colour value if cell within buffer */
224
225                      for ( i = 0, k = 0; i < ncol; i++, pt++ )
226                      {
227                         if ( *pt > k ) k = *pt;
228                      }
229                      j = 0;
230                      while ( k )
231                      {
232                         k >>= 1; j++;
233                      }
234                   }
235                   lprec = ( j <= 1  ?  1
236                           : j <= 2  ?  2
237                           : j <= 4  ?  4
238                           : j <= 8  ?  8
239                           : j <= 16 ? 16
240                           : j <= 24 ? 24
241                                     : 32 );
242                   pt = pi + 9;
243                }
244
245 /*  Find number of bytes for both coding methods */
246
247                run = 0; packed = 0;
248                for ( j = 0; j < nc; j += nx )
249                {
250
251 /*  Make sure row starts on a word boundary  */
252
253                   if ( packed & 1 ) packed++;
254                   if ( run & 1 ) run++;
255
256 /*  Calculate length of packed list in bytes per row */
257
258                   packed += ( (cur.color_mode == DIRECT ? 3*nx : nx)
259                                * lprec + 7 )>>3;
260
261 /*  Calculate length of run length in bits */
262
263                   k = 0;
264                   if ( cur.color_mode == INDEXED )
265                   {
266                      last = -1;
267                      for ( i = 0; i < nx; i++, pt++ )
268                      {
269                         if ( *pt != last)
270                         {
271                            k += curbin.int_prec + lprec;
272                            last = *pt;
273                         }
274                      }
275                   }
276                   else
277                   {
278                      lastred = -1; lastgreen = -1; lastblue = -1;
279                      for ( i = 0; i < nx; i++ )
280                      {
281                         red = *pt++; green = *pt++; blue = *pt++;
282                         if ( red != lastred || green != lastgreen
283                                        || blue != lastblue )
284                         {
285                            k += curbin.int_prec + 3*lprec;
286                            lastred = red;
287                            lastgreen = green;
288                            lastblue = blue;
289                         }
290                      }
291                   }
292
293 /*  Convert runlength to bytes */
294                   run += (k + 7) >>3;
295                }
296
297                if ( first )
298                {
299
300 /*  Decide which encoding is smallest  */
301
302                   if ( run < packed )
303                   {
304                      runlength = RUNLENGTH;
305                      parmlen += run;
306                   }
307                   else
308                   {
309                      runlength = PACKED;
310                      parmlen += packed;
311                   }
312
313                   if ( num < 0 ) parmlen = - parmlen;
314                   MOBopcode(c, parmlen);
315
316                   MOBvdc ( (Int)6, pi, pr );
317                   PUTINT ( nx );
318                   PUTINT ( ny );
319                   PUTINT ( lprec );
320
321                   pi += 9;
322                   PUTENUM ( runlength );
323                }
324                else
325                {
326                   parmlen = ( runlength = RUNLENGTH ? run : packed );
327                   if ( num < 0 ) parmlen = - parmlen;
328                   MOBopcode(PARTITION, parmlen);
329                }
330
331                first = ( num >= ZERO );
332
333 /*  Output cell array a row at a time */
334
335                for ( j = 0; j < nc; j += nx )
336                {
337                   MOBclist (nx, pi, cur.color_mode, runlength, lprec);
338                   pi += ( cur.color_mode == DIRECT ? 3*nx : nx );
339                }
340                break;
341             }
342
343             case GDP: /* Generalised Drawing Primitive */
344                parmlen = 2*INTSIZE + 2*num*VDCSIZE + STRINGSIZE(str);
345                if ( first ) MOBopcode(c, parmlen);
346                else         MOBopcode(PARTITION, parmlen);
347                first = ( parmlen >= ZERO );
348                PUTINT ( *pi );
349                PUTINT ( num );
350                MOBpointlist(num, pi, pr, NOSET);
351                MOBstring(str);
352                break;
353
354             case RECT: /* Rectangle */
355                parmlen = 4*VDCSIZE;
356                MOBopcode(c, parmlen);
357                MOBvdc( (Int)4, pi, pr);
358                break;
359
360             default:
361                (void) sprintf( mess, "(code: 0x%x)", c);
362                break;
363          }
364          break;
365
366       case 0x30:  /*  Delimiter Elements  */
367
368          switch(c)
369          {
370
371             case BEGMF: /* Begin Metafile */
372                cgmob = stream;
373                curbin = bindef;
374                parmlen = STRINGSIZE(str);
375                MOBopcode(c, parmlen);
376                MOBstring(str);
377                break;
378
379             case ENDMF: /* End Metafile */
380                MOBopcode(c, (Long)0 );
381                break;
382
383             case BEGPIC: /* Begin Picture Descriptor */
384                parmlen = STRINGSIZE(str);
385                MOBopcode(c, parmlen);
386                MOBstring(str);
387                if ( first_pic )
388                {
389                   first_pic = FALSE;
390                   mfbin = curbin;
391                }
392                else
393                   curbin = mfbin;
394                break;
395
396             case BEGPICBODY: /* Begin Picture Body */
397                MOBopcode(c, (Long)0 );
398                break;
399
400             case ENDPIC: /* End  Picture */
401                MOBopcode(c, (Long)0 );
402                break;
403
404             default:
405                (void) sprintf( mess, "(code: 0x%x)", c);
406                break;
407          }
408          break;
409
410
411       case 0x31: /* Metafile Descriptor Elements */
412          switch(c)
413          {
414             case MFVERSION: /* Metafile version */
415                parmlen = INTSIZE;
416                MOBopcode(c, parmlen);
417                PUTINT ( num );
418                break;
419
420             case MFDESC: /* Metafile Description */
421                parmlen = STRINGSIZE(str);
422                MOBopcode(c, parmlen);
423                MOBstring(str);
424                break;
425
426             case VDCTYPE: /* VDC Type */
427                parmlen = ENUMSIZE;
428                MOBopcode(c, parmlen);
429                PUTENUM ( cur.vdc_type );
430                break;
431
432             case INTEGERPREC: /* Integer Precision */
433                parmlen = INTSIZE;
434                MOBopcode(c, parmlen);
435                j = ( cur.int_bits <= 8  ?  8
436                    : cur.int_bits <= 16 ? 16
437                    : cur.int_bits <= 24 ? 24
438                                         :32 );
439                PUTINT ( j );
440                curbin.int_prec = j;
441                break;
442
443             case REALPREC: /* Real Precision */
444                parmlen = ENUMSIZE + 2*INTSIZE;
445                MOBopcode(c, parmlen);
446                PUTENUM ( curbin.real_type );
447                if ( curbin.real_type == FIXED )
448                { /* NB: only 16,16 and 32,32 are permitted */
449                   curbin.real_whole =
450                      (cur.real_bits > 16 || -cur.real_places > 16 ? 32 : 16);
451                   curbin.real_fraction = curbin.real_whole;
452                }
453                PUTINT ( curbin.real_whole );
454                PUTINT ( curbin.real_fraction );
455                break;
456
457             case INDEXPREC: /* Index Precision */
458                parmlen = INTSIZE;
459                MOBopcode(c, parmlen);
460                curbin.index_prec = ( cur.index_bits <=  8 ?  8
461                                    : cur.index_bits <= 16 ? 16
462                                    : cur.index_bits <= 24 ? 24
463                                                           : 32 );
464                PUTINT ( curbin.index_prec );
465                break;
466
467             case COLRPREC: /* Colour Precision */
468                parmlen = INTSIZE;
469                MOBopcode(c, parmlen);
470                curbin.col_prec = ( cur.col_bits <=  8 ?  8
471                                  : cur.col_bits <= 16 ? 16
472                                  : cur.col_bits <= 24 ? 24
473                                                       : 32 );
474                PUTINT ( curbin.col_prec );
475                break;
476
477             case COLRINDEXPREC: /* Colour Index Precision */
478                parmlen = INTSIZE;
479                MOBopcode(c, parmlen);
480                curbin.colind_prec = ( cur.colind_bits <=  8 ?  8
481                                     : cur.colind_bits <= 16 ? 16
482                                     : cur.colind_bits <= 24 ? 24
483                                                             : 32 );
484                PUTINT ( curbin.colind_prec );
485                break;
486
487             case MAXCOLRINDEX: /* Maximum Colour Index */
488                parmlen = COLINDEXSIZE;
489                MOBopcode(c, parmlen);
490                MOBint (cur.max_colind, curbin.colind_prec, UNSIGNED);
491                break;
492
493             case COLRVALUEEXT: /* Colour value extent */
494                parmlen = 6 * curbin.col_prec >>3;
495                MOBopcode(c, parmlen);
496                curbin.min_rgb.red   = cur.min_rgb.red;
497                curbin.min_rgb.green = cur.min_rgb.green;
498                curbin.min_rgb.blue  = cur.min_rgb.blue;
499                MOBcolour ( &curbin.min_rgb, DIRECT );
500                curbin.max_rgb.red   = cur.max_rgb.red;
501                curbin.max_rgb.green = cur.max_rgb.green;
502                curbin.max_rgb.blue  = cur.max_rgb.blue;
503                MOBcolour ( &curbin.max_rgb, DIRECT );
504                break;
505
506             case MFELEMLIST: /* Metafile element List */
507                parmlen = INTSIZE + 2*num*INDEXSIZE;
508                MOBopcode(c, parmlen);
509                PUTINT ( num );
510                for(n = 0; n < num; n++, pi++)
511                {
512                   switch ( (Int)*pi )
513                   {
514                      case 0:
515                      case 1:
516                         class = -1; id = (Int)*pi;
517                         break;
518                      default:
519                         MOBcharci( (Code)*pi, &class, &id);
520                         break;
521                   }
522                   PUTINDEX ( class );
523                   PUTINDEX ( id );
524                }
525                break;
526
527             case BEGMFDEFAULTS: /* Begin Metafile defaults Replacement */
528 /*  Save current index value */
529                defindex = mobindex;
530                saveparmlen = mobparmlen;
531                mobparmlen = 0;
532 /*  Create new buffer  */
533                mobblen = ARRAY_MAX;
534                mobbuff = mobdefbuff = (char *) malloc( (size_t)mobblen );
535                mobindex = 0;
536                break;
537
538             case ENDMFDEFAULTS: /* End Metafile defaults Replacement */
539 /*  reset buffer and index  */
540                mobbuff = mobstdbuff;
541                mobdeflen = mobindex;
542                mobindex = defindex;
543                mobblen = BUFF_LEN;
544                mobparmlen = saveparmlen;
545                MOBopcode(BEGMFDEFAULTS, mobdeflen);
546
547 /* copy defaults buffer to output */
548                for ( n = 0; n < (int)mobdeflen; n++ )
549                      PUTBYTE( mobdefbuff[n] );
550                FREE( mobdefbuff );
551                break;
552
553             case FONTLIST: /* Font List */
554             {
555                register Long *pt = pi;
556
557                for ( j=0, parmlen=0; j < num; j = *pt++ )
558                                    parmlen += STRINGSIZE( &str[j] );
559                MOBopcode(c, parmlen);
560                for ( j=0, pt = pi; j < num; j = *pt++ )
561                                    MOBstring( &str[j] );
562                break;
563             }
564
565             case CHARSETLIST: /* Character set list */
566             {
567                register Long *pt = pi;
568
569                for ( j=0, parmlen=0; j < num; j = *pt++ )
570                {
571                   parmlen += ENUMSIZE + STRINGSIZE(&str[j]);
572                   pt++;
573                }
574                MOBopcode(c, parmlen);
575                for ( j=0, pt = pi; j < num; j = *pt++ )
576                {
577                   PUTENUM ( *pt++ );
578                   MOBstring( &str[j] );
579                }
580                break;
581             }
582
583             case CHARCODING: /* Character coding Announcer */
584                parmlen = ENUMSIZE;
585                MOBopcode(c, parmlen);
586                PUTENUM ( num );
587                break;
588
589             default:
590                (void) sprintf( mess, "(code: 0x%x)", c);
591                break;
592          }
593          break;
594
595       case 0x32: /* Picture Descriptor Elements */
596          switch(c)
597          {
598             case SCALEMODE: /* Scaling Mode */
599                parmlen = ENUMSIZE + REALSIZE;
600                MOBopcode(c, parmlen);
601                PUTENUM ( cur.scale_mode );
602                MOBreal ( (Double)cur.scale_factor, FLOATING, REAL );
603                break;
604
605             case COLRMODE: /* Colour Selection Mode */
606                parmlen = ENUMSIZE;
607                MOBopcode(c, parmlen);
608                PUTENUM ( cur.color_mode );
609                break;
610
611             case LINEWIDTHMODE: /* Line width Specification */
612                parmlen = ENUMSIZE;
613                MOBopcode(c, parmlen);
614                PUTENUM ( cur.linewidth_mode );
615                break;
616
617             case MARKERSIZEMODE: /* Marker size Specification */
618                parmlen = ENUMSIZE;
619                MOBopcode(c, parmlen);
620                PUTENUM ( cur.markersize_mode );
621                break;
622
623             case EDGEWIDTHMODE: /* Edge width Specification */
624                parmlen = ENUMSIZE;
625                MOBopcode(c, parmlen);
626                PUTENUM ( cur.edgewidth_mode );
627                break;
628
629             case VDCEXT: /* VDC Extent */
630                parmlen = 4*VDCSIZE;
631                MOBopcode(c, parmlen);
632                if (cur.vdc_type == REAL)
633                {
634                  PUTREALVDC ( cur.vdc_extent.a.x.real );
635                  PUTREALVDC ( cur.vdc_extent.a.y.real );
636                  PUTREALVDC ( cur.vdc_extent.b.x.real );
637                  PUTREALVDC ( cur.vdc_extent.b.y.real );
638                }
639                else
640                {
641                  PUTINTVDC ( cur.vdc_extent.a.x.intr );
642                  PUTINTVDC ( cur.vdc_extent.a.y.intr );
643                  PUTINTVDC ( cur.vdc_extent.b.x.intr );
644                  PUTINTVDC ( cur.vdc_extent.b.y.intr );
645                }
646                break;
647
648             case BACKCOLR: /* Background Colour */
649                parmlen = 3 * curbin.col_prec >>3;
650                MOBopcode(c, parmlen);
651                MOBcolour( &cur.back, DIRECT );
652                break;
653
654             default:
655                (void) sprintf( mess, "(code: 0x%x)", c);
656          }
657          break;
658
659       case 0x33:  /* Control Elements */
660          switch(c)
661          {
662             case VDCINTEGERPREC: /* VDC Integer Precision */
663                parmlen = INTSIZE;
664                MOBopcode(c, parmlen);
665                curbin.vdcint_prec = ( cur.vdcint_bits <= 8  ?  8
666                                     : cur.int_bits <= 16 ? 16
667                                     : cur.int_bits <= 24 ? 24
668                                                          :32 );
669                PUTINT ( curbin.vdcint_prec );
670                break;
671
672             case VDCREALPREC: /* VDC Real Precision */
673                parmlen = ENUMSIZE + 2*INTSIZE;
674                MOBopcode(c, parmlen);
675                PUTENUM ( curbin.vdc_type );
676                if ( curbin.real_type == FIXED )
677                {  /* NB: only 16,16 or 32,32 permitted */
678                   curbin.vdc_whole =
679                      (cur.vdc_bits > 16 || -cur.vdc_places > 16 ? 32 : 16);
680                   curbin.vdc_fraction = curbin.vdc_whole;
681                }
682                PUTINT ( curbin.vdc_whole );
683                PUTINT ( curbin.vdc_fraction );
684                break;
685
686             case AUXCOLR: /* Auxiliary Colour */
687                parmlen = COLOURSIZE;
688                MOBopcode(c, parmlen);
689                MOBcolour( &cur.aux, cur.color_mode );
690                break;
691
692             case TRANSPARENCY: /* Transparency */
693                parmlen = ENUMSIZE;
694                MOBopcode(c, parmlen);
695                PUTENUM ( cur.transparency );
696                break;
697
698             case CLIPRECT: /* Clip Rectangle */
699                parmlen = 4*VDCSIZE;
700                MOBopcode(c, parmlen);
701                if ( cur.vdc_type == REAL )
702                {
703                  PUTREALVDC ( cur.clip_rect.a.x.real );
704                  PUTREALVDC ( cur.clip_rect.a.y.real );
705                  PUTREALVDC ( cur.clip_rect.b.x.real );
706                  PUTREALVDC ( cur.clip_rect.b.y.real );
707                }
708                else
709                {
710                  PUTINTVDC ( cur.clip_rect.a.x.intr );
711                  PUTINTVDC ( cur.clip_rect.a.y.intr );
712                  PUTINTVDC ( cur.clip_rect.b.x.intr );
713                  PUTINTVDC ( cur.clip_rect.b.y.intr );
714                }
715                break;
716
717             case CLIP: /* Clip Indicator */
718                parmlen = ENUMSIZE;
719                MOBopcode(c, parmlen);
720                PUTENUM ( cur.clip_ind );
721                break;
722
723             default:
724                (void) sprintf( mess, "(code: 0x%x)", c);
725                break;
726          }
727          break;
728
729       case 0x34: /* Circles and Ellipses */
730          switch(c)
731          {
732             case CIRCLE: /* Circle */
733                parmlen = 3*VDCSIZE;
734                MOBopcode(c, parmlen);
735                MOBvdc( (Int)3, pi, pr );
736                break;
737
738             case ARC3PT: /* Circular Arc  3 point */
739                parmlen = 6*VDCSIZE;
740                MOBopcode(c, parmlen);
741                MOBvdc( (Int)6, pi, pr );
742                break;
743
744             case ARC3PTCLOSE: /* Circular Arc  3 point close */
745                parmlen = 6*VDCSIZE + ENUMSIZE;
746                MOBopcode(c, parmlen);
747                MOBvdc( (Int)6, pi, pr );
748                PUTENUM ( *(pi+6) );
749                break;
750
751             case ARCCTR: /* Circle Arc centre */
752                parmlen = 7*VDCSIZE;
753                MOBopcode(c, parmlen);
754                MOBvdc( (Int)7, pi, pr );
755                break;
756
757             case ARCCTRCLOSE: /* Circle Arc centre close */
758                parmlen = 7*VDCSIZE + ENUMSIZE;
759                MOBopcode(c, parmlen);
760                MOBvdc( (Int)7, pi, pr );
761                PUTENUM ( *(pi+7) );
762                break;
763
764             case ELLIPSE: /* Ellipse */
765                parmlen = 6*VDCSIZE;
766                MOBopcode(c, parmlen);
767                MOBvdc( (Int)6, pi, pr );
768                break;
769
770             case ELLIPARC: /* Elliptical Arc */
771                parmlen = 10*VDCSIZE;
772                MOBopcode(c, parmlen);
773                MOBvdc( (Int)10, pi, pr );
774                break;
775
776             case ELLIPARCCLOSE: /* Elliptical Arc close */
777                parmlen = 10*VDCSIZE + ENUMSIZE;
778                MOBopcode(c, parmlen);
779                MOBvdc( (Int)10, pi, pr );
780                PUTENUM ( *(pi+10) );
781                break;
782
783             default:
784                (void) sprintf( mess, "(code: 0x%x)", c);
785                break;
786          }
787          break;
788
789       case 0x35: /* Attributes */
790
791          switch(c)
792          {
793             case LINEINDEX: /* Line Bundle index */
794                parmlen = INDEXSIZE;
795                MOBopcode(c, parmlen);
796                PUTINDEX ( curatt.line_ind );
797                break;
798
799             case LINETYPE: /* Line Type */
800                parmlen = INDEXSIZE;
801                MOBopcode(c, parmlen);
802                PUTINDEX ( curatt.line_type );
803                break;
804
805             case LINEWIDTH: /* Line Width */
806                if(cur.linewidth_mode == SCALED)
807                {
808                  parmlen = REALSIZE;
809                  MOBopcode(c, parmlen);
810                  PUTREAL ( curatt.line_width.real );
811                }
812                else
813                {
814                  parmlen = VDCSIZE;
815                  MOBopcode(c, parmlen);
816                  if ( cur.vdc_type == REAL )
817                       PUTREALVDC ( curatt.line_width.real );
818                  else PUTINTVDC ( curatt.line_width.intr );
819                }
820                break;
821
822             case LINECOLR: /* Line Colour */
823                parmlen = COLOURSIZE;
824                MOBopcode(c, parmlen);
825                MOBcolour( &curatt.line, cur.color_mode);
826                break;
827
828             case MARKERINDEX: /* Marker Bundle index */
829                parmlen = INDEXSIZE;
830                MOBopcode(c, parmlen);
831                PUTINDEX ( curatt.mark_ind );
832                break;
833
834             case MARKERTYPE: /* Marker Type */
835                parmlen = INDEXSIZE;
836                MOBopcode(c, parmlen);
837                PUTINDEX ( curatt.mark_type );
838                break;
839
840             case MARKERSIZE: /* Marker Size */
841                if(cur.markersize_mode == SCALED)
842                {
843                  parmlen = REALSIZE;
844                  MOBopcode(c, parmlen);
845                  PUTREAL ( curatt.mark_size.real );
846                }
847                else
848                {
849                  parmlen = VDCSIZE;
850                  MOBopcode(c, parmlen);
851                  if ( cur.vdc_type == REAL )
852                       PUTREALVDC ( curatt.mark_size.real );
853                  else PUTINTVDC ( curatt.mark_size.intr );
854                }
855                break;
856
857             case MARKERCOLR: /* Marker Colour */
858                parmlen = COLOURSIZE;
859                MOBopcode(c, parmlen);
860                MOBcolour( &curatt.marker, cur.color_mode);
861                break;
862
863             case TEXTINDEX: /* Text Bundle index */
864                parmlen = INDEXSIZE;
865                MOBopcode(c, parmlen);
866                PUTINDEX ( curatt.text_ind );
867                break;
868
869             case TEXTFONTINDEX: /* Text Font Index */
870                parmlen = INDEXSIZE;
871                MOBopcode(c, parmlen);
872                PUTINDEX ( curatt.text_font );
873                break;
874
875             case TEXTPREC: /* Text Precision */
876                parmlen = ENUMSIZE;
877                MOBopcode(c, parmlen);
878                PUTENUM ( curatt.text_prec );
879                break;
880
881             case CHAREXPAN: /* Character Expansion Factor */
882                parmlen = REALSIZE;
883                MOBopcode(c, parmlen);
884                PUTREAL ( curatt.char_exp );
885                break;
886
887             case CHARSPACE: /* Character Spacing */
888                parmlen = REALSIZE;
889                MOBopcode(c, parmlen);
890                PUTREAL ( curatt.char_space );
891                break;
892
893             case TEXTCOLR: /* Text Colour */
894                parmlen = COLOURSIZE;
895                MOBopcode(c, parmlen);
896                MOBcolour( &curatt.text, cur.color_mode);
897                break;
898
899             case CHARHEIGHT: /* Character Height */
900                parmlen = VDCSIZE;
901                MOBopcode(c, parmlen);
902                if ( cur.vdc_type == REAL )
903                     PUTREALVDC ( curatt.char_height.real );
904                else PUTINTVDC ( curatt.char_height.intr );
905                break;
906
907             case CHARORI: /* Character Orientation */
908                parmlen = 4*VDCSIZE;
909                MOBopcode(c, parmlen);
910                if ( cur.vdc_type == REAL )
911                {
912                   PUTREALVDC ( curatt.char_up.x.real );
913                   PUTREALVDC ( curatt.char_up.y.real );
914                   PUTREALVDC ( curatt.char_base.x.real );
915                   PUTREALVDC ( curatt.char_base.y.real );
916                }
917                else
918                {
919                   PUTINTVDC (curatt.char_up.x.intr );
920                   PUTINTVDC (curatt.char_up.y.intr );
921                   PUTINTVDC (curatt.char_base.x.intr );
922                   PUTINTVDC (curatt.char_base.y.intr );
923                }
924                break;
925
926             case TEXTPATH: /* Text Path */
927                parmlen = ENUMSIZE;
928                MOBopcode(c, parmlen);
929                PUTENUM ( curatt.text_path );
930                break;
931
932             case TEXTALIGN:       /*  Text Alignment */
933                parmlen = 2*ENUMSIZE + 2*REALSIZE;
934                MOBopcode(c, parmlen);
935                PUTENUM ( curatt.text_halign );
936                PUTENUM ( curatt.text_valign );
937                PUTREAL ( curatt.text_hcont );
938                PUTREAL ( curatt.text_vcont );
939                break;
940
941             case CHARSETINDEX: /* Character Set Index */
942                parmlen = INDEXSIZE;
943                MOBopcode(c, parmlen);
944                PUTINDEX ( curatt.char_set );
945                break;
946
947             case ALTCHARSETINDEX: /* Alt Character Set Index */
948                parmlen = INDEXSIZE;
949                MOBopcode(c, parmlen);
950                PUTINDEX ( curatt.altchar_set );
951                break;
952
953             default:
954                (void) sprintf( mess, "(code: 0x%x)", c);
955                break;
956          }
957          break;
958
959       case 0x36: /* More Attributes */
960          switch(c)
961          {
962             case FILLINDEX: /* Fill Bundle index */
963                parmlen = INDEXSIZE;
964                MOBopcode(c, parmlen);
965                PUTINDEX ( curatt.fill_ind );
966                break;
967
968             case INTSTYLE: /* Interior Style */
969                parmlen = ENUMSIZE;
970                MOBopcode(c, parmlen);
971                PUTENUM ( curatt.int_style );
972                break;
973
974             case FILLCOLR: /* Fill Colour */
975                parmlen = COLOURSIZE;
976                MOBopcode(c, parmlen);
977                MOBcolour( &curatt.fill, cur.color_mode);
978                break;
979
980             case HATCHINDEX: /* Hatch Index */
981                parmlen = INDEXSIZE;
982                MOBopcode(c, parmlen);
983                PUTINDEX(curatt.hatch_ind );
984                break;
985
986             case PATINDEX: /* Pattern Index */
987                parmlen = INDEXSIZE;
988                MOBopcode(c, parmlen);
989                PUTINDEX(curatt.pat_ind );
990                break;
991
992             case EDGEINDEX: /* Edge Bundle index */
993                parmlen = INDEXSIZE;
994                MOBopcode(c, parmlen);
995                PUTINDEX(curatt.edge_ind );
996                break;
997
998             case EDGETYPE: /* Edge Type */
999                parmlen = INDEXSIZE;
1000                MOBopcode(c, parmlen);
1001                PUTINDEX(curatt.edge_type );
1002                break;
1003
1004             case EDGEWIDTH: /* Edge Width */
1005                if(cur.edgewidth_mode == SCALED)
1006                {
1007                  parmlen = REALSIZE;
1008                  MOBopcode(c, parmlen);
1009                  PUTREAL ( curatt.edge_width.real );
1010                }
1011                else
1012                {
1013                  parmlen = VDCSIZE;
1014                  MOBopcode(c, parmlen);
1015                  if ( cur.vdc_type == REAL )
1016                       PUTREALVDC ( curatt.edge_width.real );
1017                  else PUTINTVDC ( curatt.edge_width.intr );
1018                }
1019                break;
1020
1021             case EDGECOLR: /* Edge Colour */
1022                parmlen = COLOURSIZE;
1023                MOBopcode(c, parmlen);
1024                MOBcolour( &curatt.edge, cur.color_mode);
1025                break;
1026
1027             case EDGEVIS: /* Edge Visibility */
1028                parmlen = ENUMSIZE;
1029                MOBopcode(c, parmlen);
1030                PUTENUM ( curatt.edge_vis );
1031                break;
1032
1033             case FILLREFPT: /* Fill Reference Point */
1034                parmlen = 2*VDCSIZE;
1035                MOBopcode(c, parmlen);
1036                if ( cur.vdc_type == REAL )
1037                {
1038                   PUTREALVDC ( curatt.fill_ref.x.real );
1039                   PUTREALVDC ( curatt.fill_ref.y.real );
1040                }
1041                else
1042                {
1043                   PUTINTVDC ( curatt.fill_ref.x.intr );
1044                   PUTINTVDC ( curatt.fill_ref.y.intr );
1045                }
1046                break;
1047
1048             case PATTABLE: /* Pattern Table */
1049             {
1050                register Long *pt = pi, patind, i, k;
1051                Long nx, ny;
1052                Prec lprec;
1053
1054                parmlen = INDEXSIZE + 3*INTSIZE;
1055                patind = *pt++;
1056                nx = *pt++;
1057                ny = *pt++;
1058                pt++;   /* ignore previous local precision */
1059
1060 /*  Find local precision */
1061
1062                n = (cur.color_mode == DIRECT ? 3*num : num );
1063                for ( i = 0, k = 0; i < n; i++, pt++ )
1064                {
1065                   if ( *pt > k ) k = *pt;
1066                }
1067                j = 0;
1068                while ( k )
1069                {
1070                   k >>= 1; j++;
1071                }
1072                lprec = ( j <=  1 ?  1
1073                        : j <=  2 ?  2
1074                        : j <=  4 ?  4
1075                        : j <=  8 ?  8
1076                        : j <= 16 ? 16
1077                        : j <= 24 ? 24
1078                                  : 32 );
1079
1080 /* Work out parameter length in bytes  */
1081
1082                parmlen += ( lprec * (cur.color_mode == DIRECT ? 3*num : num )
1083                           + 7 )>>3;
1084
1085                MOBopcode(c, parmlen);
1086
1087                PUTINDEX ( patind );
1088                PUTINT ( nx );
1089                PUTINT ( ny );
1090                PUTINT ( lprec );
1091
1092 /*  Output whole cell array */
1093
1094                MOBclist ( num, pi + 4, cur.color_mode, PACKED, lprec);
1095                break;
1096             }
1097
1098             case PATSIZE: /* Pattern Size */
1099                parmlen = 4*VDCSIZE;
1100                MOBopcode(c, parmlen);
1101                if ( cur.vdc_type == REAL )
1102                {
1103                   PUTREALVDC ( curatt.pat_size.a.x.real );
1104                   PUTREALVDC ( curatt.pat_size.a.y.real );
1105                   PUTREALVDC ( curatt.pat_size.b.x.real );
1106                   PUTREALVDC ( curatt.pat_size.b.y.real );
1107                }
1108                else
1109                {
1110                   PUTINTVDC ( curatt.pat_size.a.x.intr );
1111                   PUTINTVDC ( curatt.pat_size.a.y.intr );
1112                   PUTINTVDC ( curatt.pat_size.b.x.intr );
1113                   PUTINTVDC ( curatt.pat_size.b.y.intr );
1114                }
1115                break;
1116
1117             case COLRTABLE: /* Colour Table */
1118                parmlen = COLINDEXSIZE + ((3*num*curbin.col_prec)>>3);
1119                MOBopcode(c, parmlen);
1120                MOBint(*pi++, curbin.colind_prec, UNSIGNED);
1121                for ( j=0; j < num; j++)
1122                {
1123                      MOBint(*pi++, curbin.col_prec, UNSIGNED);
1124                      MOBint(*pi++, curbin.col_prec, UNSIGNED);
1125                      MOBint(*pi++, curbin.col_prec, UNSIGNED);
1126                }
1127                break;
1128
1129             case ASF: /* Aspect source flags */
1130             {
1131                Long k, l, *pt=pi;
1132                Int type, value;
1133                Logical asflag[ASFS];
1134
1135                for ( j=0; j < ASFS; j++) asflag[j] = FALSE;
1136                for ( j=0; j < num; j++ )
1137                {
1138                   type = *pt++; value = (*pt++) + 1;
1139                   if ( type < ASFS ) asflag[type] = value;
1140                   else
1141                   {
1142                      switch ( type )
1143                      {
1144                         case 506:     /* all edge */
1145                            k = 15; l = 17; break;
1146                         case 507:     /* all fill */
1147                            k = 11; l = 14; break;
1148                         case 508:     /* all text */
1149                            k = 6; l = 10; break;
1150                         case 509:     /* all marker */
1151                            k = 3; l = 5; break;
1152                         case 510:     /* all line */
1153                            k = 0; l = 2; break;
1154                         case 511:     /* all */
1155                            k = 0; l = 17; break;
1156                         default:      /* ignore  */
1157                            k = 1; l = 0; break;
1158                      }
1159                      for ( n = k; n < l; n++ ) asflag[n] = value;
1160                   }
1161                }
1162                for ( j=0; j < ASFS; j++)
1163                   if ( asflag[j] ) parmlen += 2*ENUMSIZE;
1164                MOBopcode(c, parmlen);
1165                for ( j=0; j < ASFS; j++)
1166                   if ( asflag[j] )
1167                   {
1168                      PUTENUM ( j );
1169                      PUTENUM ( curatt.asf[j] );
1170                   }
1171                break;
1172             }
1173
1174             default:
1175                (void) sprintf( mess, "(code: 0x%x)", c);
1176                break;
1177          }
1178          break;
1179
1180       case 0x37: /* Escape And External Elements */
1181          switch(c)
1182          {
1183             case ESCAPE: /* Escape */
1184                parmlen = INTSIZE + STRINGSIZE(str);
1185                MOBopcode(c, parmlen);
1186                PUTINT ( num );
1187                MOBstring(str);
1188                break;
1189
1190             case MESSAGE: /* Message */
1191                parmlen = ENUMSIZE + STRINGSIZE(str);
1192                MOBopcode(c, parmlen);
1193                PUTENUM ( num );
1194                MOBstring(str);
1195                break;
1196
1197             case APPLDATA: /* Application Data */
1198                parmlen = INTSIZE + STRINGSIZE(str);
1199                MOBopcode(c, parmlen);
1200                PUTINT ( num );
1201                MOBstring(str);
1202                break;
1203
1204             default:
1205                (void) sprintf( mess, "(code: 0x%x)", c);
1206                break;
1207          }
1208          break;
1209
1210       default:
1211         (void) sprintf( mess, "(code: 0x%x)", c);
1212         break;
1213    }
1214    return;
1215 }
1216
1217 /******************************************************** MOBopcode ****/
1218
1219 static void
1220 MOBopcode( Code c, Long len )
1221 {
1222    Int class, id;
1223    unsigned Long oneword, plen, remainder;
1224    Logical part;
1225
1226 /* Pad out last element if necessary */
1227    while ( mobparmlen && mobparmlen < 0x8000 ) PUTBYTE( ZERO );
1228
1229    plen = abs(len);
1230    part = (len < 0);
1231
1232 /*  check for parameter length > 32766 */
1233
1234    if ( plen > 0x7ffe )
1235    {
1236       remainder = plen - 0x7ffe;
1237       part = TRUE;
1238       plen = 0x7ffe;
1239    }
1240    else remainder = 0;
1241
1242    if ( c != PARTITION )
1243    {
1244       MOBcharci(c, &class, &id);
1245       oneword = (class<<12) + (id<<5) + ( part || (plen > 0x1e) ? 0x1f : plen );
1246       PUTWORD ( oneword );
1247    }
1248
1249 /* Put out parameter length as integer */
1250
1251    if ( c == PARTITION || plen > 0x1e )
1252    {
1253       oneword = ( part ? plen | 0x8000 : plen );
1254       PUTWORD ( oneword );
1255    }
1256
1257    mobparmlen = plen;
1258    mobremainder = remainder;
1259    if (mobparmlen & 1) mobparmlen++;
1260    return;
1261 }
1262
1263 /******************************************************** MOBcharci ****/
1264 static void
1265 MOBcharci( Code c, Int *class, Int *id )
1266 {
1267 /*  Converts Code c to class and Id  */
1268
1269    Code major = c>>8, minor = c & 0xff;
1270
1271    *class = -1; *id = 0;
1272    switch ( major )
1273    {
1274       case 0x00:  /* Graphics Primitives */
1275          if ( minor >= 0x20 && minor <= 0x2A )
1276          {
1277             *class = 4; *id = minor - 0x20 + 1;
1278          }
1279          else if ( minor == 0 ) *class = ZERO;  /*  Non-Op */
1280          break;
1281
1282       case 0x30:  /* Metafile delimiters */
1283          if ( minor >= 0x20 && minor <= 0x24 )
1284          {
1285             *class = 0; *id = minor - 0x20 + 1;
1286          }
1287          break;
1288
1289       case 0x31:  /* Metafile Descriptor Elements */
1290          if ( minor >= 0x20 && minor <= 0x2b )
1291          {
1292             *class = 1; *id = minor - 0x20 + 1;
1293          }
1294          else if ( minor > 0x2c && minor <= 0x2f )
1295          {
1296             *class = 1; *id = minor - 0x20;
1297          }
1298          break;
1299
1300       case 0x32:  /* Picture Descriptor Elements */
1301          if ( minor >= 0x20 && minor <= 0x26 )
1302          {
1303             *class = 2; *id = minor - 0x20 + 1;
1304          }
1305          break;
1306
1307       case 0x33:  /* Control Elements */
1308          if ( minor >= 0x20 && minor <= 0x25 )
1309          {
1310             *class = 3; *id = minor - 0x20 + 1;
1311          }
1312          break;
1313
1314       case 0x34:  /* More Graphics Primitives */
1315          if ( minor >= 0x20 && minor <= 0x27 )
1316          {
1317             *class = 4; *id = minor - 0x20 + 12;
1318          }
1319          break;
1320
1321       case 0x35:  /* Attributes */
1322          if ( minor >= 0x20 && minor <= 0x27 )
1323          {
1324             *class = 5; *id = minor - 0x20 + 1;
1325          }
1326          else if ( minor >= 0x30 && minor <= 0x3b )
1327          {
1328             *class = 5; *id = minor - 0x30 + 9;
1329          }
1330          break;
1331
1332       case 0x36:  /* More Attributes */
1333          if ( minor >= 0x20 && minor <= 0x2c )
1334          {
1335             *class = 5; *id = minor - 0x20 + 21;
1336          }
1337          else if ( minor >= 0x30 && minor <= 0x31 )
1338          {
1339             *class = 5; *id = minor - 0x30 + 34;
1340          }
1341          break;
1342
1343       case 0x37:  /* External elements */
1344          if ( minor == 0x20 )
1345          {
1346             *class = 6; *id = 1;
1347          }
1348          else if ( minor >= 0x21 && minor <= 0x22 )
1349          {
1350             *class = 7; *id = minor - 0x20;
1351          }
1352          break;
1353
1354       default:
1355          break;
1356    }
1357
1358    if ( *class < 0 )
1359    {
1360       (void) sprintf( mess, "(code: 0x%x)", c);
1361       *class = 0;
1362    }
1363
1364    return;
1365 }
1366
1367 /******************************************************** MOBint *******/
1368 static void
1369 MOBint( Long n, Prec prec, Enum sign )
1370 {
1371 /*
1372    if ( sign == SIGNED && n < 0 )
1373       n = (-n | (Posint) 1L<<(prec-1));
1374 */
1375    MOBout( (Posint) n, prec>>3 );
1376    return;
1377 }
1378
1379 /******************************************************** MOBcolour ****/
1380 static void
1381 MOBcolour( struct colour *col, Enum type )
1382 {
1383
1384    if ( type == DIRECT )
1385    {
1386       MOBint( (Long) col->red, curbin.col_prec, UNSIGNED );
1387       MOBint( (Long) col->green, curbin.col_prec, UNSIGNED );
1388       MOBint( (Long) col->blue, curbin.col_prec, UNSIGNED );
1389    }
1390    else
1391    {
1392       MOBint( (Long) col->index, curbin.colind_prec, UNSIGNED );
1393    }
1394
1395    return;
1396 }
1397
1398 /******************************************************** MOBvdc *******/
1399 static void
1400 MOBvdc( Int n, Long *pi, Float *pr)
1401 {
1402    Int i;
1403    for ( i = 0; i < n; i++)
1404    {
1405       if ( cur.vdc_type == INTEGER )
1406       {
1407          PUTINTVDC ( *pi++ );
1408       }
1409       else
1410       {
1411          PUTREALVDC ( *pr++ );
1412       }
1413    }
1414
1415    return;
1416 }
1417
1418 /******************************************************** MOBpointlist */
1419 static void
1420 MOBpointlist(Long n, Long *pi, Float *pr, Enum set)
1421 {
1422    Int i;
1423    for ( i = 0; i < n; i++)
1424    {
1425       if ( cur.vdc_type == INTEGER )
1426       {
1427          PUTINTVDC ( *pi++ );
1428          PUTINTVDC ( *pi++ );
1429       }
1430       else
1431       {
1432          PUTREALVDC ( *pr++ );
1433          PUTREALVDC ( *pr++ );
1434       }
1435       if ( set ) PUTENUM ( *pi++ );
1436    }
1437
1438    return;
1439 }
1440
1441 /******************************************************** MOBreal ******/
1442 static void
1443 MOBreal(Double x, Enum real_type, Enum real_or_vdc )
1444 {
1445    Posint whole, exponent, fract, neg;
1446    Prec prec;
1447    Double f;
1448    neg = ( x < 0.0 ) << 15;
1449
1450    if ( real_type == FIXED )
1451    {
1452       prec = (real_or_vdc == VDC ? curbin.vdc_whole
1453                                  : curbin.real_whole);
1454       whole = (Posint)( neg ? -((floor(x))) : x );
1455       fract = (Posint)( ( neg ? x + (Double)whole : x - (Double)whole )
1456                             * ( 1L<<(prec-2) ) * 4.0 );
1457
1458       if ( prec == 32 )
1459       {
1460          PUTWORD( whole>>16 | neg );
1461          PUTWORD( whole & (Posint)0xffff );
1462          PUTWORD( fract>>16 );
1463          PUTWORD( fract & (Posint)0xffff );
1464       }
1465       else
1466       {
1467          PUTWORD( whole | neg );
1468          PUTWORD( fract );
1469       }
1470    }
1471    else
1472    {
1473 /*  IEEE Floating point reals */
1474
1475       prec = (real_or_vdc == VDC ? curbin.vdc_whole + curbin.vdc_fraction
1476                                  : curbin.real_whole + curbin.real_fraction);
1477       prec = (prec == 64 ? 12 : 9);
1478       f = ( neg ? -x : x );
1479
1480       if ( f < (Double)(real_or_vdc == VDC ? cur.vdcmin : cur.realmin) )
1481       {
1482          exponent = ZERO;
1483          fract = ZERO;
1484       }
1485       else
1486       {
1487
1488 /*  check if greater than smallest exponent  */
1489
1490          exponent = ( prec == 12 ? 1023 : 127 );
1491
1492          if ( f <= 1.0 / (Double) (prec-1) )
1493          {
1494             exponent = ZERO;
1495          }
1496          else
1497          {
1498             while ( f >= 2.0 )
1499             {
1500                f /= 2.0;
1501                exponent++;
1502             }
1503             while ( f < 1.0 )
1504             {
1505                f *= 2.0;
1506                exponent--;
1507             }
1508          }
1509          fract = (Long) ( (f - 1.0) * (Double)(1L<<(prec == 12 ? 52 : 23)) );
1510       }
1511
1512 #if defined(_LP64)
1513       if ( prec == 12 )
1514       {
1515          PUTWORD( (exponent<<4) | neg | (fract>>48) );
1516          PUTWORD( (fract >> 32) & (Posint)0xffff );
1517          PUTWORD( (fract >> 16) & (Posint)0xffff );
1518          PUTWORD( fract & (Posint)0xffff );
1519       }
1520       else
1521 #endif
1522       {
1523          PUTWORD( (exponent<<7) | neg | (fract>>16) );
1524          PUTWORD( fract & (Posint)0xffff );
1525       }
1526    }
1527    return;
1528 }
1529
1530 /******************************************************** MOBstring ****/
1531 static void
1532 MOBstring( char *s )
1533 {
1534 /*  Output a text string if CMS translate from EBCDIC to ASCII  */
1535
1536    register Int i, len, slen = strlen(s);
1537    register char chr;
1538    len = slen;
1539    do
1540    {
1541       PUTBYTE ( len >= 0xff ? 0xff : len );
1542       len -= 0xff;
1543    } while ( len >= 0 );
1544
1545    for (i = 0; i < slen; i++)
1546    {
1547    chr = *s++;
1548    PUTBYTE ( chr );
1549    }
1550 return;
1551 }
1552
1553 /******************************************************** MOBclist *****/
1554 static void
1555 MOBclist( register Long num, register Long *col,
1556           Prec mode, Enum type, Prec prec )
1557 {
1558 /*  Output a colour list */
1559
1560    register Long j, k, n;
1561    Long bits, bytes = 0;
1562    if ( type == RUNLENGTH )
1563    {
1564       Long run = 1, bit = 0;
1565
1566       if ( mode == DIRECT )
1567       {
1568          Posint red, green, blue, lastred, lastgreen, lastblue;
1569
1570          lastred = (*col++);
1571          lastgreen = (*col++);
1572          lastblue = (*col++);
1573          for ( j = 1; j <= num; j++ )
1574          {
1575             red = (*col++); green = (*col++); blue = (*col++);
1576             if ( j == num ||
1577                  red != lastred || green != lastgreen || blue != lastblue )
1578             {
1579                MOBbits ( run, curbin.int_prec, &bit );
1580                MOBbits ( lastred, prec, &bit );
1581                MOBbits ( lastgreen, prec, &bit );
1582                MOBbits ( lastblue, prec, &bit );
1583                if ( j == num ) break;
1584                lastred = red; lastgreen = green; lastblue = blue;
1585                run = 1;
1586             }
1587             else run++;
1588          }
1589       }
1590       else   /* Indexed runlength */
1591       {
1592          Long lastcol;
1593
1594          lastcol = (*col++);
1595          for ( j = 1; j <= num; j++, col++ )
1596          {
1597             if ( j == num || *col != lastcol )
1598             {
1599                MOBbits ( run, curbin.int_prec, &bit );
1600                MOBbits ( lastcol, prec, &bit );
1601                if ( j == num ) break;
1602                lastcol = *col;
1603                run = 1;
1604             }
1605             else run++;
1606          }
1607       }
1608
1609 /* make sure list ends on a word boundary */
1610
1611       if ( bit ) MOBbits ( (Posint) 0 , (Prec) 16, &bit );
1612
1613    }
1614    else   /* Packed mode */
1615    {
1616       n = ( mode == DIRECT ? 3*num : num );
1617       bytes = ( n*prec + 7 ) >>3;
1618
1619       for ( j = 0, bits = 0, k = 0; j < n; j++)
1620       {
1621          if ( bits ) k <<= prec;
1622          else        k = 0;
1623          k += (*col++);
1624          bits += prec;
1625
1626          while ( bits >= 8 )
1627          {
1628             bits -= 8;
1629             PUTBYTE ( (k>>bits) & 0xff );
1630          }
1631       }
1632       if ( bits > 0 ) PUTBYTE ( k<<(8-bits) );
1633
1634 /* Pad buffer if necessary */
1635       if ( bytes & 1 ) PUTBYTE ( 0 );
1636    }
1637    return;
1638 }
1639
1640 /******************************************************** MOBbits ******/
1641 static void
1642 MOBbits ( Posint value, Prec prec, Long *bit )
1643 {
1644 /*  Output 'value' as 'prec' bits
1645     using 'word' to hold current value
1646     returns number of bits left in 'bits'  */
1647
1648    static Posint oneword = 0;
1649    Posint mask = (Posint)0xffffffff;
1650    *bit += prec;
1651    if ( *bit <= 16 )
1652    {
1653       oneword |= value<<(16 - *bit);
1654    }
1655    else
1656    {
1657       while ( *bit > 16 )
1658       {
1659          *bit -= 16;
1660 /*       k = prec + *bit - 16; */
1661          oneword |= value>>*bit;
1662          value &= mask>>(32 - *bit);
1663          MOBout ( oneword, WORD );
1664          oneword = value<<16;
1665       }
1666       oneword = value<<(16 - *bit);
1667    }
1668    return;
1669 }
1670
1671 /******************************************************** MOBout *******/
1672 static void
1673 MOBout( Posint hex, Prec bytes )
1674 {
1675 /*  Output 'hex' as 'bytes' bytes to output file 'cgmob'
1676     which is either the file or MF defaults buffer */
1677
1678    register Int /*i,*/ b_len;
1679    b_len = bytes;
1680    mobindex = ZERO;
1681    if ( bytes > 0 ) for( ; bytes ; mobindex++ )
1682    {
1683       bytes--;
1684       mobbuff[mobindex] = (char)((hex >> (8*bytes) ) & 0xff);
1685       mobparmlen--;
1686    }
1687    fwrite(mobbuff,b_len,(size_t)1,cgmob);
1688 /*
1689 start:
1690    if ( bytes > 0 ) for( ; bytes ; mobindex++ )
1691    {
1692       if ( mobindex == mobblen )
1693       {
1694          if ( cgmstate != MF_DEFAULTS )
1695          {
1696             fwrite(mobbuff,mobblen,(size_t)1,cgmob);
1697             mobindex=ZERO;
1698          }
1699          else
1700          {
1701             mobblen += BUFF_LEN;
1702             mobbuff = (char *)realloc (mobbuff, (size_t)mobblen);
1703          }
1704       }
1705       if ( mobindex == ZERO )
1706       {
1707          for(i = ZERO; i < mobblen ; i++) mobbuff[i] = '\0';
1708       }
1709       bytes--;
1710       mobbuff[mobindex] = ( hex>>(8*bytes) ) & 0xff;
1711       mobparmlen--;
1712    }
1713    else
1714    {
1715       fwrite(mobbuff,BUFF_LEN,(size_t)1,cgmob);
1716       mobindex = ZERO;
1717    }
1718    fflush(cgmob);
1719    if ( mobremainder && mobparmlen == 0 )
1720    {
1721       if ( mobremainder > 0x7ffe )
1722       {
1723          hex = 0xfffe;
1724          mobremainder -= 0x7ffe;
1725       }
1726       else
1727       {
1728          hex = mobremainder;
1729          mobremainder = 0;
1730       }
1731       mobparmlen = hex & 0x7fff;
1732       bytes = 2;
1733       mobparmlen += 2;
1734       goto start;
1735    }
1736 */
1737    return;
1738 }