- Optification is done by auto builder now
[gnuplot] / term / cgm.trm
1 /* Hey Emacs this is -*- C -*-
2  * $Id: cgm.trm,v 1.77.2.5 2009/02/16 21:41:56 sfeam Exp $
3  */
4
5 /* GNUPLOT - cgm.trm */
6
7 /*[
8  * Copyright 1998, 2004
9  *
10  * Permission to use, copy, and distribute this software and its
11  * documentation for any purpose with or without fee is hereby granted,
12  * provided that the above copyright notice appear in all copies and
13  * that both that copyright notice and this permission notice appear
14  * in supporting documentation.
15  *
16  * Permission to modify the software is granted, but not the right to
17  * distribute the complete modified source code.  Modifications are to
18  * be distributed as patches to the released version.  Permission to
19  * distribute binaries produced by compiling modified sources is granted,
20  * provided you
21  *   1. distribute the corresponding source modifications from the
22  *    released version in the form of a patch file along with the binaries,
23  *   2. add special version identification to distinguish your version
24  *    in addition to the base release version number,
25  *   3. provide your name and address as the primary contact for the
26  *    support of your modified version, and
27  *   4. retain our contact information in regard to use of the base
28  *    software.
29  * Permission to distribute the released version of the source code along
30  * with corresponding source modifications in the form of a patch file is
31  * granted with same provisions 2 through 4 for binary distributions.
32  *
33  * This software is provided "as is" without express or implied warranty
34  * to the extent permitted by applicable law.
35 ]*/
36
37 /*
38  * This file is included by ../term.c and ../docs/termdoc.c.
39  *
40  * This terminal driver supports:
41  *   Computer Graphics Metafile
42  *
43  * TODO
44  *   better control over plot size (never cutting off labels, correct font
45  *   sizes)
46
47  * REFERENCES
48  *
49  *   ISO 8632-1:1992 Computer Graphics Metafile (CGM), Part 1,
50  *   Functional Specification.
51  *
52  *   ISO 8632-1:1992 Computer Graphics Metafile (CGM), Part 3,
53  *   Binary Encoding.
54  *
55  *   FIPS PUB 128 - Computer Graphics Metafile (CGM).
56  *
57  *   MIL-STD-2301A Computer Graphics Metafile (CGM) Implementation
58  *   Standard for the National Imagery Transmission Format Standard, 5
59  *   June 1998, http://164.214.2.51/ntb/baseline/docs/2301a/.  Only a
60  *   subset of CGM version 1, but does include the binary format for
61  *   that subset.
62  *
63  *   MIL-D-28003A "Digital Representation for Communication of
64  *   Illustration Data: CGM Application Profile", 15 November 1991,
65  *   http://www-cals.itsi.disa.mil/core/standards/28003aa1.pdf.
66  *
67  *   "The computer graphics metafile", Lofton R. Henderson and Anne
68  *   M. Mumford, Butterworths, London, 1990, ISBN 0-408-02680-4.
69  *
70  * AUTHOR
71  *   Jim Van Zandt <jrvz@comcast.net>
72  *
73  * send your comments or suggestions to the author or
74  * gnuplot-info@lists.sourceforge.net.
75 */
76
77 #include "driver.h"
78
79 #ifdef TERM_REGISTER
80 register_term(cgm)
81 #endif
82
83 #ifdef TERM_PROTO
84 TERM_PUBLIC void CGM_options __PROTO((void));
85 TERM_PUBLIC void CGM_init __PROTO((void));
86 TERM_PUBLIC void CGM_reset __PROTO((void));
87 TERM_PUBLIC void CGM_text __PROTO((void));
88 TERM_PUBLIC void CGM_graphics __PROTO((void));
89 TERM_PUBLIC void CGM_move __PROTO((unsigned int x, unsigned int y));
90 TERM_PUBLIC void CGM_dashed_vector __PROTO((unsigned int ux, unsigned int uy));
91 TERM_PUBLIC void CGM_solid_vector __PROTO((unsigned int ux, unsigned int uy));
92 TERM_PUBLIC void CGM_linetype __PROTO((int linetype));
93 TERM_PUBLIC void CGM_linecolor __PROTO((int color));
94 TERM_PUBLIC void CGM_dashtype __PROTO((int dashtype));
95 TERM_PUBLIC void CGM_linewidth __PROTO((double width));
96 TERM_PUBLIC void CGM_put_text __PROTO((unsigned int x, unsigned int y,
97                                        const char *str));
98 TERM_PUBLIC int CGM_text_angle __PROTO((int ang));
99 TERM_PUBLIC int CGM_justify_text __PROTO((enum JUSTIFY mode));
100 TERM_PUBLIC int CGM_set_font __PROTO((const char *font));
101 TERM_PUBLIC void CGM_point __PROTO((unsigned int x, unsigned int y,
102                                     int number));
103 TERM_PUBLIC void CGM_fillbox __PROTO((int style, unsigned int x1, unsigned int y1,
104                                 unsigned int width, unsigned int height));
105 TERM_PUBLIC int CGM_make_palette __PROTO((t_sm_palette *palette));
106 TERM_PUBLIC void CGM_set_color __PROTO((t_colorspec *));
107
108 TERM_PUBLIC void CGM_filled_polygon __PROTO((int points, gpiPoint *corner));
109
110 TERM_PUBLIC void CGM_set_pointsize __PROTO((double size));
111
112 #define FATAL(msg) { fprintf(stderr, "%s\nFile %s line %d\n", msg, __FILE__, __LINE__); exit(EXIT_FAILURE); }
113
114 #define CGM_LARGE 32767
115 #define CGM_SMALL 32767/18*13   /* aspect ratio 1:.7222 */
116 #define CGM_MARGIN (CGM_LARGE/180)
117                                 /* convert from plot units to pt */
118 #define CGM_PT ((term->xmax + CGM_MARGIN)/cgm_plotwidth)
119 #define CGM_LINE_TYPES 9        /* number of line types we support */
120 #define CGM_COLORS WEB_N_COLORS /* sizeof(web_color_rgbs)  currently in bitmap.c */
121 #define CGM_POINTS 13           /* number of markers we support */
122 #define CGM_MAX_SEGMENTS 16382  /* maximum # polyline coordinates */
123 #define CGM_VCHAR (CGM_SMALL/360*12)
124 #define CGM_HCHAR (CGM_SMALL/360*12*5/9)
125 #define CGM_VTIC (CGM_LARGE/80)
126 #define CGM_HTIC (CGM_LARGE/80)
127 #endif
128
129 #ifndef TERM_PROTO_ONLY
130 #ifdef TERM_BODY
131
132 static int CGM_find_font __PROTO((const char *name, int len, double *relwidth));
133 static int CGM_find_nearest_color __PROTO((t_colorspec *colorspec));
134 /*
135  * on NeXTstep, id is an identifier (in ObjC) and causes a parse error
136  * since some asserts below are mistaken as casts. datum is a type
137  * defined in ndbm.h which also causes a parse error (ndbm.h is
138  * included as part of appkit.h, I think).  Strangely enough, both
139  * errors only happen with cpp-precomp -smart, not with the regular
140  * cpp. (AL)
141  */
142
143 #ifdef NEXT
144 #define id id_
145 #define datum datum_
146 #endif
147
148 #include <ctype.h>              /* for isspace() */
149
150 #ifndef assert
151 #define assert(x) 0             /* defeat assertions */
152 #endif
153
154 /* uncomment the following to enable assertions for this module only,
155    regardless of compiler switches
156 #ifdef NDEBUG
157 #define DEFEAT_ASSERTIONS
158 #endif
159 #undef NDEBUG
160 #include <assert.h>
161  */
162
163 #define CGM_ADJ (sizeof(int)/sizeof(short))
164
165 static unsigned int cgm_posx;
166 static unsigned int cgm_posy;
167 static unsigned int cgm_linetype = 1;
168 static unsigned int cgm_linetypes = CGM_LINE_TYPES + 3;
169 static unsigned int cgm_dashtype = 0;
170 static unsigned int cgm_color = 0;
171 static int *cgm_polyline; /* stored polyline coordinates */
172 static int cgm_coords = 0;      /* # polyline coordinates saved */
173 static int cgm_doing_polygon = 0; /* nonzero if creating polygon, else
174                                    * creating polyline */
175 /* static enum JUSTIFY cgm_justify = LEFT; */ /* unused */
176 static int cgm_step_sizes[8];   /* array of currently used dash
177                                    lengths in plot units */
178 static int cgm_step_index = 0;  /* index into cgm_step_sizes[] */
179 static int cgm_step = 0;        /* amount of current dash not yet
180                                    drawn, in plot units */
181 static int cgm_tic, cgm_tic707, cgm_tic866, cgm_tic500, cgm_tic1241, cgm_tic1077, cgm_tic621;   /* marker dimensions */
182 struct cgm_properties {
183   double angle;                 /* angle of text baseline (radians
184                                    counter-clockwise from horizontal) */
185   int font_index;               /* font index */
186   int char_height;              /* character height in picture units */
187   enum JUSTIFY justify_mode;    /* how text is justified */
188
189   int edge_visibility;          /* nonzero if edge is visible */
190   int edge_color;
191   int fill_color;
192   int interior_style;
193   int hatch_index;
194 };
195
196 static struct cgm_properties
197     cgm_current={-1,-1,-1,(enum JUSTIFY)-1,-1,-1,-1,-1,-1}, /* written to file */
198     cgm_next={0,-2,-2,LEFT,-2,-2,-2,-1,-1}, /* needed for next text string/marker */
199     cgm_reset={-1,-1,-1,(enum JUSTIFY)-1,-1,-1,-1,-1,-1}; /* invalid entries */
200
201 static int cgm_user_color_count = 0;
202 static int cgm_user_color_max = 0;
203 static int cgm_smooth_colors = 0;
204 static int GPFAR *cgm_user_color_table = (int GPFAR*)0;
205 static int cgm_maximum_color_index = 255;       /* Size of color table we will write */
206
207 struct fontdata {
208   char *name;                   /* the name of the font */
209   double width;                 /* the width of the font, relative to
210                                    Times Bold Italic.  The width
211                                    adjustment can only be approximate.
212                                    Of the standard fonts, only the
213                                    four versions of "Courier" are
214                                    monospaced. Also, metrics of the
215                                    same font from different foundaries
216                                    are sometimes different.  */
217 };
218
219 static struct fontdata cgm_basic_font_data[]={
220     /* these are WebCGM recommended fonts */
221     {"Helvetica",1.039},
222     {"Helvetica Oblique",1.099},
223     {"Helvetica Bold",1.083},
224     {"Helvetica Bold Oblique",1.011},
225     {"Times Roman",.981},
226     {"Times Bold",.985},
227     {"Times Italic",.959},
228     {"Times Bold Italic",1.0},
229     {"Courier",1.327},
230     {"Courier Bold",1.327},
231     {"Courier Oblique",1.218},
232     {"Courier Bold Oblique",1.341},
233     {"Symbol",.897},
234
235     /* These are basic public domain fonts required by MIL-D-28003A */
236     {"Hershey/Cartographic_Roman",1.2404},
237     {"Hershey/Cartographic_Greek",.9094},
238     {"Hershey/Simplex_Roman",1.2369},
239     {"Hershey/Simplex_Greek",.9129},
240     {"Hershey/Simplex_Script",1.4181},
241     {"Hershey/Complex_Roman",1.1150},
242     {"Hershey/Complex_Greek",.9059},
243     {"Hershey/Complex_Script",1.3868},
244     {"Hershey/Complex_Italic",1.4146},
245     {"Hershey/Complex_Cyrillic",1.2056},
246     {"Hershey/Duplex_Roman",1.1707},
247     {"Hershey/Triplex_Roman",1.3240},
248     {"Hershey/Triplex_Italic",1.3310},
249     {"Hershey/Gothic_German",1.2056},
250     {"Hershey/Gothic_English",1.2021},
251     {"Hershey/Gothic_Italian",1.2021},
252     {"Hershey/Symbol_Set_1",.9059},
253     {"Hershey/Symbol_Set_2",.9059},
254     {"Hershey/Symbol_Math",.9059},
255
256     /* These are available in the Microsoft Office import filter.  By
257        default, the script font can apparently be accessed only via
258        the name "15".  */
259     {"ZapfDingbats",1.583},
260     {"Script",1.139},
261     {"15",1.139},
262
263     /* in the Microsoft Office and Corel Draw import filters, these
264        are pseudonyms for some of the above */
265     {"Helvetica Italic",1.099},
266     {"Helvetica Bold Italic",1.011},
267     {"Courier Italic",1.218},
268     {"Courier Bold Italic",1.341},
269     {"Times Oblique",.959},
270     {"Times Bold Oblique",1.0},
271
272     {0,0}
273 };
274
275 static struct fontdata *cgm_font_data = cgm_basic_font_data;
276
277 #define DEFAULT_CGMFONT "Helvetica Bold"
278 static char CGM_default_font[MAX_ID_LEN+1] = {'\0'};
279
280 /* variables to record the options */
281 static char cgm_font[32] = DEFAULT_CGMFONT;
282 static unsigned int cgm_fontsize = 12;
283 static unsigned cgm_linewidth;  /* line width in plot units */
284 static unsigned cgm_linewidth_pt = 1;   /* line width in pt */
285 static TBOOLEAN cgm_monochrome = FALSE;         /* colors enabled? */
286 static int cgm_plotwidth = 432; /* assumed width of plot in pt. */
287 static TBOOLEAN cgm_portrait = FALSE;   /* portrait orientation? */
288 static TBOOLEAN cgm_rotate = TRUE;      /* text rotation enabled? */
289 static TBOOLEAN cgm_dashed = TRUE;      /* dashed linestyles enabled? */
290 static TBOOLEAN cgm_nofontlist_mode = FALSE;    /* omit font list? */
291
292 /* prototypes for static functions */
293 static void CGM_local_reset __PROTO((void));
294 static void CGM_flush_polyline __PROTO((void));
295 static void CGM_flush_polygon __PROTO((void));
296 static void CGM_write_char_record __PROTO((int class, int cgm_id, int length,
297                                            char *data));
298 static void CGM_write_code __PROTO((int class, int cgm_id, int length));
299 static void CGM_write_int __PROTO((int value));
300 static void CGM_write_int_record __PROTO((int class, int cgm_id, int length,
301                                           int *data));
302 static void CGM_write_mixed_record __PROTO((int class, int cgm_id,
303                                             int numint, int *int_data,
304                                             int numchar, const char *char_data));
305 static void CGM_write_byte_record __PROTO((int class, int cgm_id, int length,
306                                            char *data));
307
308 enum CGM_id {
309     /* cgm mode */
310     CGM_PORTRAIT, CGM_LANDSCAPE, CGM_DEFAULT,
311     /* color */
312     CGM_MONOCHROME, CGM_COLOR,
313     /* rotation */
314     CGM_ROTATE, CGM_NOROTATE,
315     CGM_DASHED, CGM_SOLID,
316     CGM_LINEWIDTH, CGM_WIDTH, CGM_NOFONTLIST, CGM_OTHER
317 };
318
319 static struct gen_table CGM_opts[] =
320 {
321     { "p$ortrait", CGM_PORTRAIT },
322     { "la$ndscape", CGM_LANDSCAPE },
323     { "de$fault", CGM_DEFAULT },
324     { "nof$ontlist", CGM_NOFONTLIST },
325     { "win$word6", CGM_NOFONTLIST }, /* deprecated */
326     { "m$onochrome", CGM_MONOCHROME },
327     { "c$olor", CGM_COLOR },
328     { "c$olour", CGM_COLOR },
329     { "r$otate", CGM_ROTATE },
330     { "nor$otate", CGM_NOROTATE },
331     { "da$shed", CGM_DASHED },
332     { "s$olid", CGM_SOLID },
333     { "li$newidth", CGM_LINEWIDTH },
334     { "lw", CGM_LINEWIDTH },
335     { "wid$th", CGM_WIDTH },
336     { NULL, CGM_OTHER }
337 };
338
339
340 TERM_PUBLIC void
341 CGM_options()
342 {
343     struct value a;
344     char *string;
345
346     /* Annoying hack to handle the case of 'set termoption' after */
347     /* we have already initialized the terminal.                  */
348     if (c_token != 2)
349         CGM_local_reset();
350
351     while (!END_OF_COMMAND) {
352         switch(lookup_table(&CGM_opts[0],c_token)) {
353         case CGM_PORTRAIT:
354             cgm_portrait = TRUE;
355             c_token++;
356             break;
357         case CGM_LANDSCAPE:
358             cgm_portrait = FALSE;
359             c_token++;
360             break;
361         case CGM_DEFAULT:
362             CGM_local_reset();
363             c_token++;
364             break;
365         case CGM_NOFONTLIST:
366             cgm_nofontlist_mode = TRUE;
367             c_token++;
368             break;
369         case CGM_MONOCHROME:
370             cgm_monochrome = TRUE;
371             c_token++;
372             break;
373         case CGM_COLOR:
374             cgm_monochrome = FALSE;
375             c_token++;
376             break;
377         case CGM_ROTATE:
378             cgm_rotate = TRUE;
379             c_token++;
380             break;
381         case CGM_NOROTATE:
382             cgm_rotate = FALSE;
383             c_token++;
384             break;
385         case CGM_DASHED:
386             cgm_dashed = TRUE;
387             c_token++;
388             break;
389         case CGM_SOLID:
390             cgm_dashed = FALSE;
391             c_token++;
392             break;
393         case CGM_LINEWIDTH:
394             c_token++;
395             if (!END_OF_COMMAND) {
396                 cgm_linewidth_pt = (unsigned int) real(const_express(&a));
397                 if (cgm_linewidth_pt == 0 || cgm_linewidth_pt > 10000) {
398                     int_warn(c_token,"linewidth out of range");
399                     cgm_linewidth_pt = 1;
400                 }
401             }
402             break;
403         case CGM_WIDTH:
404             c_token++;
405             if (!END_OF_COMMAND) {
406                 cgm_plotwidth = (int) real(const_express(&a));
407                 if (cgm_plotwidth < 0 || cgm_plotwidth > 10000) {
408                     int_warn(c_token,"width out of range");
409                     cgm_plotwidth = 6 * 72;
410                 }
411             }
412             break;
413         case CGM_OTHER:
414         default:
415             string = gp_input_line + token[c_token].start_index;
416
417             if (string[0] == 'x') { /* set color */
418                 unsigned short red, green, blue;
419
420                 if (sscanf(string, "x%2hx%2hx%2hx", &red, &green, &blue ) != 3)
421                      int_error(c_token, "invalid color spec, must be xRRGGBB");
422                 if (cgm_user_color_count >= cgm_user_color_max) {
423                      cgm_user_color_max = cgm_user_color_max*2 + 4;
424                      cgm_user_color_table =
425                           gp_realloc(cgm_user_color_table,
426                                      (cgm_user_color_max*3+1)*sizeof(int),
427                                      "CGM color table");
428                      /* 1st table entry is the minimum color index value */
429                      cgm_user_color_table[0] = 0;
430                 }
431                 cgm_user_color_table[1 + 3*cgm_user_color_count] = red;
432                 cgm_user_color_table[2 + 3*cgm_user_color_count] = green;
433                 cgm_user_color_table[3 + 3*cgm_user_color_count] = blue;
434                 cgm_user_color_count++;
435                 ++c_token;
436             } else {
437                 if (equals(c_token,"font"))
438                     c_token++;
439                 if (isstring(c_token)) {
440                       double relwidth;
441                       char *comma;
442                       quote_str(cgm_font, c_token, MAX_ID_LEN);
443                       comma = strchr(cgm_font,',');
444                       if (comma && (1 == sscanf(comma+1,"%d",&cgm_fontsize))) {
445                            *comma = '\0';
446                       }
447                       if (CGM_find_font(cgm_font, strlen(cgm_font),
448                                         &relwidth) == 0) {
449                            /* insert the font in the font table */
450                            size_t l = strlen(cgm_font);
451                            int n;
452                            for (n=0; cgm_font_data[n].name; n++)
453                                 ;
454                            if (l <= 255) {
455                                 struct fontdata *new_font_data;
456                                 int i;
457                                 new_font_data =
458                                      gp_alloc((n + 2)*sizeof(struct fontdata),
459                                               "CGM font list");
460                                 new_font_data->name = gp_alloc(l+1,"CGM font list");
461                                 strcpy(new_font_data->name, cgm_font);
462                                 /* punt, since we don't know the real font width */
463                                 new_font_data->width = 1.0;
464                                 for (i = 0; i <= n; i++)
465                                      new_font_data[i+1] = cgm_font_data[i];
466                                 cgm_font_data = new_font_data;
467                            }
468                       }
469                       c_token++;
470                 } else {
471                       /* the user is specifying the font size */
472                       cgm_fontsize = (int) real(const_express(&a));
473                 }
474                  break;
475             }
476         }
477     }
478
479     if (cgm_portrait) {
480         term->xmax = CGM_SMALL - CGM_MARGIN;
481         term->ymax = CGM_LARGE - CGM_MARGIN;
482     } else {
483         term->xmax = CGM_LARGE - CGM_MARGIN;
484         term->ymax = CGM_SMALL - CGM_MARGIN;
485     }
486
487     {   /* cgm_font, cgm_fontsize, and/or term->v_char may have changed */
488         double w;
489         CGM_find_font(cgm_font, strlen(cgm_font), &w);
490         term->v_char = (unsigned int) (cgm_fontsize*CGM_PT);
491         term->h_char = (unsigned int) (cgm_fontsize*CGM_PT*.527*w);
492     }
493
494     sprintf(CGM_default_font, "%s,%d", cgm_font, cgm_fontsize);
495     /* CGM_default_font holds the font and size set at 'set term' */
496     sprintf(term_options, "%s %s %s %s %s width %d linewidth %d \"%s\" %d",
497             cgm_portrait ? "portrait" : "landscape",
498             cgm_monochrome ? "monochrome" : "color",
499             cgm_rotate ? "rotate" : "norotate",
500             cgm_dashed ? "dashed" : "solid",
501             cgm_nofontlist_mode ? "nofontlist" : "",
502             cgm_plotwidth,
503             cgm_linewidth_pt,
504             cgm_font, cgm_fontsize);
505
506     if (cgm_user_color_count) {
507          int i, red, green, blue;
508          for (i = 0; i < cgm_user_color_count &&
509                    (strlen(term_options) + 9 < MAX_LINE_LEN); i++) {
510               red = cgm_user_color_table[1 + 3*i];
511               green = cgm_user_color_table[2 + 3*i];
512               blue = cgm_user_color_table[3 + 3*i];
513               sprintf(term_options + strlen(term_options),
514                       " x%02x%02x%02x", red, green, blue);
515          }
516     }
517
518     if (cgm_user_color_count < CGM_COLORS) {
519         int i, j;
520
521         /* fill in colors not set by the user with the default colors */
522
523         /* 1st table entry is the minimum color index value */
524         cgm_user_color_table = gp_realloc(cgm_user_color_table,
525                 (CGM_COLORS * 3 + 1) * sizeof (int), "CGM color table");
526         cgm_user_color_table[0] = 0;
527
528         for (i = cgm_user_color_count, j = cgm_user_color_count * 3;
529                      i < CGM_COLORS; i++, j+=3) {
530                 cgm_user_color_table[j+1] = web_color_rgbs[i].r;
531                 cgm_user_color_table[j+2] = web_color_rgbs[i].g;
532                 cgm_user_color_table[j+3] = web_color_rgbs[i].b;
533         }
534
535         cgm_user_color_count = CGM_COLORS;
536     }
537
538 }
539
540 static void
541 CGM_local_reset()
542 {
543     double w;
544     strcpy(cgm_font, DEFAULT_CGMFONT);
545     CGM_find_font(cgm_font, strlen(cgm_font), &w);
546     cgm_fontsize = 12;
547     term->v_char = (unsigned int) (cgm_fontsize * CGM_PT);
548     term->h_char = (unsigned int) (cgm_fontsize * CGM_PT * .527 * w);
549     cgm_linewidth_pt = 1;
550     cgm_monochrome = FALSE;
551     cgm_plotwidth = 6 * 72;
552     cgm_portrait = FALSE;
553     cgm_rotate = TRUE;
554     cgm_dashed = TRUE;
555     cgm_nofontlist_mode = FALSE;
556     cgm_current = cgm_reset;
557     cgm_user_color_count = 0;
558 }
559
560 TERM_PUBLIC void
561 CGM_init()
562 {
563     cgm_posx = cgm_posy = 0;
564     cgm_linetype = 0;
565     cgm_next.angle = 0;
566     cgm_next.interior_style = 1;
567     cgm_next.hatch_index = 1;
568     cgm_polyline = gp_alloc(CGM_MAX_SEGMENTS*sizeof(int), "cgm_polylines");
569 }
570
571 TERM_PUBLIC void
572 CGM_graphics()
573 {
574     register struct termentry *t = term;
575     static int version_data[] = { 1 };
576     static int vdc_type_data[] = { 0 };
577     static int integer_precision_data[] = { 16 };
578     static int real_precision_data[] = { 1, 16, 16 };
579     static int index_precision_data[] = { 16 };
580     static int color_precision_data[] = { 16 };
581     static int color_index_precision_data[] = { 16 };
582     static int scaling_mode_data[] = { 0, 0, 0 };
583     static int color_value_extent_data[] = { 0, 0, 0, 255, 255, 255 };
584     static int color_selection_mode_data[] = { 0 };
585     static int linewidth_specification_mode_data[] = { 0 };
586     static int edge_width_specification_mode_data[] = { 0 };
587     static int marker_size_specification_mode_data[] = { 0 };
588     static int vdc_extent_data[] = { 0, 0, 0, 0 };
589     static int line_type_data[] = { 1 };
590     static int interior_style_data[] = { 1 }; /* 0=hollow 1=filled
591                                                * 2=pattern 3=hatch
592                                                * 4=empty */
593     static int hatch_index_data[] = { 1 }; /* 1=horizontal 2=vertical
594                                             * 3=positive slope
595                                             * 4=negative slope
596                                             * 5=horizontal/vertical
597                                             * crosshatch
598                                             * 6=positive/negative
599                                             * slope crosshatch */
600
601     static int GPFAR elements_list_data[] =
602     {
603         0,                      /* will be set to # elements in this list */
604         0, 1,                   /* Begin Metafile */
605         0, 2,                   /* End Metafile */
606         0, 3,                   /* Begin Picture */
607         0, 4,                   /* Begin Picture Body */
608         0, 5,                   /* End Picture */
609         1, 1,                   /* Metafile Version */
610         1, 2,                   /* Metafile Description */
611         1, 3,                   /* VDC Type */
612         1, 4,                   /* Integer Precision */
613         1, 5,                   /* Real Precision */
614         1, 6,                   /* Index Precision */
615         1, 7,                   /* Color Precision */
616         1, 8,                   /* Color Index Precision */
617         1, 9,                   /* Maximum Color Index */
618         1, 10,                  /* Color Value Extent */
619         1, 13,                  /* Font List */
620         2, 1,                   /* Scaling Mode */
621         2, 2,                   /* Color Selection Mode */
622         2, 3,                   /* Line Width Specification Mode */
623         2, 4,                   /* Marker Size Specification Mode */
624         2, 5,                   /* Edge Width Specification Mode */
625         2, 6,                   /* VDC Extent */
626 #ifdef NEVER
627         /* disabled due to complaints from CGM import filters */
628         3, 1,                   /* VDC Integer Precision */
629         3, 4,                   /* Transparency */
630         3, 6,                   /* Clip Indicator */
631 #endif
632         4, 1,                   /* Polyline */
633         4, 3,                   /* Polymarker */
634         4, 4,                   /* Text */
635         4, 7,                   /* Polygon */
636         4, 11,                  /* Rectangle */
637         4, 12,                  /* Circle */
638         4, 15,                  /* Circular Arc Center */
639         4, 16,                  /* Circular Arc Center Close */
640         4, 17,                  /* Ellipse */
641         4, 18,                  /* Elliptical Arc */
642         4, 19,                  /* Elliptical Arc Close */
643         5, 2,                   /* Line Type */
644         5, 3,                   /* Line Width */
645         5, 4,                   /* Line Color */
646         5, 6,                   /* Marker Type */
647         5, 7,                   /* Marker Size */
648         5, 8,                   /* Marker Color */
649         5, 10,                  /* Text Font Index */
650         5, 14,                  /* Text Color */
651         5, 15,                  /* Character Height */
652         5, 16,                  /* Character Orientation */
653         5, 18,                  /* Text Alignment */
654         5, 22,                  /* Interior Style */
655         5, 23,                  /* Fill Color */
656         5, 24,                  /* Hatch Index */
657         5, 27,                  /* Edge Type */
658         5, 28,                  /* Edge Width */
659         5, 29,                  /* Edge Color */
660         5, 30,                  /* Edge Visibility */
661         5, 34,                  /* Color Table */
662         6, 1,                   /* Escape */
663         7, 2                    /* Application Data */
664     };
665
666     /* metafile description (class 1), including filename if available */
667     if (!outstr)
668         CGM_write_char_record(0, 1, 1, outstr);
669     else
670         CGM_write_char_record(0, 1, strlen(outstr) + 1, outstr);
671     CGM_write_int_record(1, 1, 2, version_data);
672     {
673       char description_data[256];
674       sprintf(description_data, "\
675 Gnuplot version %s patchlevel %s,\
676  Computer Graphics Metafile version 1 per MIL-D-28003A/BASIC-1.%d",
677               gnuplot_version, gnuplot_patchlevel, cgm_monochrome?0:2);
678         CGM_write_char_record(1, 2, strlen(description_data),
679                               description_data);
680     }
681     elements_list_data[0] = (sizeof(elements_list_data) / CGM_ADJ - 2) / 4;
682     CGM_write_int_record(1, 11, sizeof(elements_list_data) / CGM_ADJ,
683                          elements_list_data);
684     CGM_write_int_record(1, 3, 2, vdc_type_data);
685     CGM_write_int_record(1, 4, 2, integer_precision_data);
686     CGM_write_int_record(1, 5, 6, real_precision_data);
687     CGM_write_int_record(1, 6, 2, index_precision_data);
688     CGM_write_int_record(1, 7, 2, color_precision_data);
689     CGM_write_int_record(1, 8, 2, color_index_precision_data);
690     CGM_write_int_record(1, 9, 2, &cgm_maximum_color_index);
691     CGM_write_int_record(1, 10, sizeof(color_value_extent_data) / CGM_ADJ,
692                          color_value_extent_data);
693     if (cgm_nofontlist_mode == FALSE)
694       {
695         char *buf, *s;
696         int i, lgh = 0;
697         for (i = 0; cgm_font_data[i].name; i++)
698           lgh += strlen(cgm_font_data[i].name) + 1;
699         buf = gp_alloc(lgh + 1, "CGM font list");
700         for (s = buf, i = 0; cgm_font_data[i].name; i++)
701           {
702             int lgh = strlen(cgm_font_data[i].name);
703             *s++ = (char)lgh;
704             strcpy(s, cgm_font_data[i].name);
705             s += lgh;
706           }
707         CGM_write_byte_record(1, 13, lgh, buf);
708         free(buf);
709       }
710
711     /* picture description (classes 2 and 3) */
712     CGM_write_char_record(0, 3, 8, "PICTURE1");
713     CGM_write_int_record(2, 1, 6, scaling_mode_data);
714     CGM_write_int_record(2, 2, 2, color_selection_mode_data);
715     CGM_write_int_record(2, 3, 2, linewidth_specification_mode_data);
716     CGM_write_int_record(2, 4, 2, marker_size_specification_mode_data);
717     CGM_write_int_record(2, 5, 2, edge_width_specification_mode_data);
718     vdc_extent_data[2] = t->xmax + CGM_MARGIN;
719     vdc_extent_data[3] = t->ymax + CGM_MARGIN;
720     CGM_write_int_record(2, 6, 8, vdc_extent_data);
721
722     /* picture body (classes 4 and 5) */
723     CGM_write_int_record(0, 4, 0, NULL);
724
725 #ifdef NEVER            /* no need for these, since we accept the defaults */
726     {
727       static int vdc_integer_precision_data[] = { 16 };
728       CGM_write_int_record(3, 1, 2, vdc_integer_precision_data);
729     }
730     {
731       static int transparency_data[] = { 1 }; /* text background:
732                                                  0=auxiliary color
733                                                  1=transparent */
734       CGM_write_int_record(3, 4, sizeof(transparency_data) / CGM_ADJ,
735                            transparency_data);
736     }
737     {
738       static int clip_indicator_data[] = { 0 };
739       CGM_write_int_record(3, 6, sizeof(clip_indicator_data) / CGM_ADJ,
740                            clip_indicator_data);
741     }
742 #endif
743     if (!cgm_monochrome)
744         CGM_write_int_record(5, 34, (cgm_user_color_count*3+1)*
745                              sizeof(cgm_user_color_table[0])/CGM_ADJ,
746                              cgm_user_color_table);
747     CGM_write_int_record(5, 2, sizeof(line_type_data) / CGM_ADJ,
748                          line_type_data); /* line type 1=SOLID */
749     cgm_linewidth = cgm_linewidth_pt * CGM_PT;
750     CGM_write_int_record(5, 3, sizeof(cgm_linewidth) / CGM_ADJ,
751                          (int *) &cgm_linewidth); /* line width */
752     CGM_write_int_record(5, 28, sizeof(cgm_linewidth) / CGM_ADJ,
753                          (int *) &cgm_linewidth); /* edge width */
754     CGM_write_int_record(5, 27,  sizeof(line_type_data) / CGM_ADJ,
755                          line_type_data); /* edge type 1=SOLID */
756     CGM_linecolor(0);
757
758     cgm_current = cgm_reset;
759     cgm_next.char_height = t->v_char;
760
761     CGM_write_int_record(5, 22, 2, interior_style_data);
762     CGM_write_int_record(5, 24, 2, hatch_index_data);
763     {
764         char buf[45];
765         sprintf(buf, "%.31s,%d", cgm_font, cgm_fontsize);
766         CGM_set_font(buf);
767     }
768     CGM_set_pointsize(pointsize);
769
770     /* Fill with background color if user has specified one */
771     if (!cgm_monochrome && cgm_user_color_count > 0) {
772         CGM_linecolor(LT_BACKGROUND);
773         CGM_fillbox(FS_SOLID, 0, 0, t->xmax, t->ymax);
774     }
775
776 }
777
778 /* Return the index for the font with the name `name'.  The index for
779    the first font is 1.  Set relwidth to the width of the font,
780    relative to Times Bold Italic.  If the font is not in the table,
781    set *relwidth to 1.0 and return 0. */
782 static int
783 CGM_find_font(const char *name, int numchar, double *relwidth)
784 {
785     int i;
786     *relwidth = 1.;
787     for (i=0; cgm_font_data[i].name; i++)
788       /* strncasecmp is not standard, but defined by stdfn.c if not available */
789       if (strlen(cgm_font_data[i].name) == numchar &&
790           strncasecmp(name, cgm_font_data[i].name, numchar) == 0)
791         {
792           *relwidth = cgm_font_data[i].width;
793           return i+1;
794         }
795
796     return 0;
797 }
798
799 TERM_PUBLIC int
800 CGM_set_font(const char *font)
801 {
802     register struct termentry *t = term;
803     int size, font_index;
804     char *comma = strchr(font, ',');
805     int len;
806     double width;
807
808     /* Allow null string to indicaute default font */
809     if (!font || !(*font))
810         font = CGM_default_font;
811
812     /* find font in font table, or use 1st font */
813     if (comma)
814         len = comma - font;
815     else
816         len = strlen(font);
817
818     font_index = CGM_find_font(font, len, &width);
819     if (font_index == 0)
820         font_index = 1;
821     cgm_next.font_index = font_index;
822
823     {
824       char *s = cgm_font_data[font_index-1].name;
825
826       len = strlen(s);
827       if (len > 31)
828         len = 31;
829       strncpy(cgm_font, s, len);
830       cgm_font[len] = NUL;
831     }
832
833     /* set font size */
834     size = cgm_fontsize;
835     if (comma)
836         sscanf(comma + 1, "%d", &size);
837     t->v_char = size * CGM_PT;
838     t->h_char = size * CGM_PT * .527 * width;
839
840     cgm_next.char_height = t->v_char;
841
842     return TRUE;
843 }
844
845 TERM_PUBLIC void
846 CGM_text()
847 {
848     CGM_flush_polyline();
849     CGM_write_int_record(0, 5, 0, NULL);        /* end picture */
850     CGM_write_int_record(0, 2, 0, NULL);        /* end metafile */
851 }
852
853 TERM_PUBLIC void
854 CGM_linetype(int linetype)
855 {
856     if (linetype < LT_NODRAW)
857         linetype = LT_NODRAW;
858
859     if (linetype == cgm_linetype)
860         return;
861     cgm_linetype = linetype;
862
863     CGM_linecolor(linetype);
864     if (cgm_dashed) {
865         CGM_dashtype(linetype); /* DBT 10-8-98    use dashes */
866     } else {
867         /* dashes for gridlines, solid for everything else */
868         CGM_dashtype(linetype == -1 ? 2 : 0);
869     }
870 }
871
872 TERM_PUBLIC void
873 CGM_linecolor(int linecolor)
874 {
875     if (linecolor >= 0) {
876         /* subtract 2 due to linetypes -2 / -1 */
877         if (cgm_linetypes > 3)
878             linecolor %= (cgm_linetypes - 3);
879         else
880             linecolor = 0;
881     } else if (linecolor == LT_BACKGROUND && !cgm_monochrome) {
882         linecolor = -3;
883     } else if (linecolor <= LT_NODRAW)
884         return;
885
886     linecolor += 3;
887     if (cgm_monochrome)
888         cgm_color = linecolor = 1;
889     if (linecolor == cgm_color)
890         return;
891     cgm_color = linecolor;
892     cgm_next.fill_color = linecolor;
893
894     CGM_flush_polyline();
895     CGM_write_int_record(5,  4, 2, (int *) &cgm_color);  /* line color */
896     CGM_write_int_record(5, 14, 2, (int *) &cgm_color); /* text color */
897 }
898
899 TERM_PUBLIC void
900 CGM_fillbox(
901      int style,
902      unsigned int x1, unsigned int y1,
903      unsigned int width, unsigned int height)
904 {
905     gpiPoint corner[5];
906
907     corner[0].x = x1;        corner[0].y = y1;
908     corner[1].x = x1+width;  corner[1].y = y1;
909     corner[2].x = x1+width;  corner[2].y = y1+height;
910     corner[3].x = x1;        corner[3].y = y1+height;
911     corner[4].x = x1;        corner[4].y = y1;
912
913     corner->style = style;
914     CGM_filled_polygon(5, corner);
915 }
916
917 TERM_PUBLIC void
918 CGM_linewidth(double width)
919 {
920     int new_linewidth;
921
922     if (width <= 0)
923         width = 0.5;
924
925     new_linewidth = width * cgm_linewidth_pt * CGM_PT;
926     if (new_linewidth == cgm_linewidth)
927         return;
928
929     CGM_flush_polyline();
930
931     cgm_linewidth = new_linewidth;
932     CGM_write_int_record(5, 3, sizeof(cgm_linewidth) / CGM_ADJ,
933                          (int *) &cgm_linewidth);
934     CGM_dashtype(cgm_dashtype); /* have dash lengths recalculated */
935 }
936
937 TERM_PUBLIC void
938 CGM_dashtype(int dashtype)
939 {
940     int i, j;
941     /* Each group of 8 entries in dot_length[] defines a dash
942        pattern.  Entries in each group are alternately length of
943        whitespace and length of line, in units of 2/3 of the
944        linewidth. */
945     static int dot_length[CGM_LINE_TYPES * 8] =
946     {                           /* 0 - solid             */
947         5, 8, 5, 8, 5, 8, 5, 8, /* 1 - dashes            */
948         5, 3, 5, 3, 5, 3, 5, 3, /* 2 - short dashes      */
949         4, 1, 4, 1, 4, 1, 4, 1, /* 3 - dotted            */
950         4, 8, 4, 1, 4, 8, 4, 1, /* 4 - dash-dot          */
951         4, 9, 4, 1, 4, 1, 0, 0, /* 5 - dash-dot-dot      */
952         4, 10, 4, 1, 4, 1, 4, 1,        /* 6 - dash-dot-dot-dot  */
953         4, 10, 4, 10, 4, 1, 0, 0,       /* 7 - dash-dash-dot     */
954         4, 10, 4, 10, 4, 1, 4, 1};      /* 8 - dash-dash-dot-dot */
955
956
957     if (dashtype == cgm_dashtype)
958         return;
959     cgm_dashtype = dashtype;
960
961     CGM_flush_polyline();
962
963     if (dashtype >= CGM_LINE_TYPES)
964         dashtype = dashtype % CGM_LINE_TYPES;
965     if (dashtype < 1) {
966         term->vector = CGM_solid_vector;
967         return;
968     }
969     term->vector = CGM_dashed_vector;
970
971     /* set up dash dimensions */
972     j = (dashtype - 1) * 8;
973     for (i = 0; i < 8; i++, j++) {
974         if (dot_length[j])
975             cgm_step_sizes[i] = (dot_length[j] * cgm_linewidth) * 2 / 3;
976         else
977             cgm_step_sizes[i] = 0;
978     }
979     /* first thing drawn will be a line */
980     cgm_step = cgm_step_sizes[1];
981     cgm_step_index = 1;
982 }
983
984 TERM_PUBLIC void
985 CGM_move(unsigned int x, unsigned int y)
986 {
987     if (x >= term->xmax)
988         x = term->xmax;
989     if (y >= term->ymax)
990         y = term->ymax;
991
992     if (x == cgm_posx && y == cgm_posy)
993         return;
994     CGM_flush_polyline();
995     cgm_posx = x;
996     cgm_posy = y;
997 }
998
999 TERM_PUBLIC int
1000 CGM_make_palette(t_sm_palette *palette)
1001 {
1002     if (palette) {
1003          int i, k;
1004
1005          cgm_smooth_colors = palette->colors;
1006          if (CGM_COLORS + cgm_smooth_colors > cgm_user_color_max) {
1007               cgm_user_color_max = CGM_COLORS + cgm_smooth_colors;
1008               cgm_user_color_table =
1009                    gp_realloc(cgm_user_color_table,
1010                               (cgm_user_color_max*3+1)*sizeof(int),
1011                               "CGM color table");
1012          }
1013          k = 1 + (CGM_COLORS)*3;
1014          for (i = 0; i < cgm_smooth_colors; i++) {
1015               cgm_user_color_table[k++] = palette->color[i].r*255.9;
1016               cgm_user_color_table[k++] = palette->color[i].g*255.9;
1017               cgm_user_color_table[k++] = palette->color[i].b*255.9;
1018          }
1019          cgm_user_color_count = CGM_COLORS + cgm_smooth_colors;
1020          CGM_write_int_record(5, 34, (cgm_user_color_count*3+1)*
1021                               sizeof(cgm_user_color_table[0])/CGM_ADJ,
1022                               cgm_user_color_table);
1023          return 0;
1024     } else {
1025       return (cgm_maximum_color_index - CGM_COLORS);
1026     }
1027 }
1028
1029 TERM_PUBLIC void
1030 CGM_set_color(t_colorspec *colorspec)
1031 {
1032     if (colorspec->type == TC_LT) {
1033          CGM_linecolor(colorspec->lt);
1034          cgm_linetype = colorspec->lt;
1035          return;
1036
1037     } else if (colorspec->type == TC_FRAC) {
1038          double gray = colorspec->value;
1039          /* map [0...1] to interval [0...cgm_smooth_colors-1], then add
1040             offset to get past the default colors */
1041          cgm_next.fill_color = (gray <= 0) ? 0 : (int)(gray * cgm_smooth_colors);
1042          if (cgm_next.fill_color >= cgm_smooth_colors)
1043              cgm_next.fill_color = cgm_smooth_colors - 1;
1044          cgm_next.fill_color += CGM_COLORS;
1045
1046     } else if (colorspec->type == TC_RGB) {
1047         /* To truly support RGB we would have to write a new color table to the */
1048         /* output file every time the RGB matched no previous color. That seems */
1049         /* prohibitive, so instead we just look for the closest match.          */
1050          cgm_next.fill_color = CGM_find_nearest_color(colorspec);
1051
1052     } else
1053         /* Should not happen! */
1054         return;
1055
1056      /* EAM - force color immediately so that lines and text can use it */
1057      if (cgm_color != cgm_next.fill_color) {
1058             cgm_color = cgm_next.fill_color;
1059             cgm_linetype = cgm_color;
1060             CGM_flush_polyline();
1061             CGM_write_int_record(5,  4, 2, (int *) &cgm_color); /* line color */
1062             CGM_write_int_record(5, 14, 2, (int *) &cgm_color); /* text color */
1063      }
1064 }
1065
1066 TERM_PUBLIC void
1067 CGM_filled_polygon(int points, gpiPoint *corner)
1068 {
1069     /* Note: This implementation cannot handle polygons with more than
1070      * about 8190 edges.  The best fix is to implement continuation
1071      * blocks.  If the high order bit of the "length" field of a block
1072      * is set, then it is followed by another block with more data.
1073      * This allows an arbitrary amount of data in a record.  However,
1074      * we implement a big enough block that problems should be rare.
1075      */
1076
1077     /* We will use solid fill for patterns 0 and 3 */
1078     int hatch_index[]={0, 6, 5, 0, 4, 3};
1079     int style = corner->style;
1080     int pattern = (style >> 4) % 6;
1081     int i;
1082
1083     switch( style & 0xf ) {
1084
1085     case FS_SOLID:
1086         cgm_next.interior_style = 1;
1087         break;
1088
1089     case FS_PATTERN:
1090         if (pattern == 0) {
1091             /* FIXME - for unknown reasons, solid fill messes up the subsequent */
1092             /* color state.  Just leave it empty and let the background show */
1093             cgm_next.interior_style = 0; /* empty */
1094             break;
1095         }
1096         if (pattern == 3) {
1097             /* Fill with solid color */
1098             cgm_next.interior_style = 1;
1099             break;
1100         }
1101
1102         /* The rest of the patterns are hatch-filled */
1103         cgm_next.interior_style = 3; /* hatched */
1104         cgm_next.hatch_index = hatch_index[pattern];
1105         break;
1106
1107     default: /* style == 0 or unknown --> fill with background color */
1108         cgm_next.fill_color = 0;
1109         cgm_next.interior_style = 1; /* solid */
1110         break;
1111     }
1112
1113     if (cgm_current.interior_style != cgm_next.interior_style){
1114       cgm_current.interior_style = cgm_next.interior_style;
1115       CGM_write_int_record(5, 22, 2, &cgm_next.interior_style);
1116     }
1117
1118     if (cgm_current.fill_color != cgm_next.fill_color){
1119       cgm_current.fill_color = cgm_next.fill_color;
1120       CGM_write_int_record(5, 23, 2, &cgm_next.fill_color);  /* fill color */
1121     }
1122
1123     if (cgm_current.hatch_index != cgm_next.hatch_index &&
1124         cgm_next.interior_style == 3){
1125       cgm_current.hatch_index = cgm_next.hatch_index;
1126       CGM_write_int_record(5, 24, 2, &cgm_next.hatch_index);
1127     }
1128
1129     cgm_next.edge_visibility = 0;       /* We draw the borders elsewhere */
1130     if (cgm_current.edge_visibility != cgm_next.edge_visibility){
1131       cgm_current.edge_visibility = cgm_next.edge_visibility;
1132       CGM_write_int_record(5, 30, 2, &cgm_current.edge_visibility);
1133     }
1134
1135     CGM_move(corner[0].x, corner[0].y);
1136     cgm_doing_polygon = 1;
1137     for (i = 1; i < points; i++)
1138          CGM_solid_vector(corner[i].x, corner[i].y);
1139     CGM_flush_polygon();
1140     cgm_doing_polygon = 0;
1141 }
1142
1143 static void
1144 CGM_flush_polyline()
1145 {
1146     if (cgm_coords == 0)
1147         return;
1148     CGM_write_int_record(4, 1, cgm_coords * 2, cgm_polyline);
1149     cgm_coords = 0;
1150 }
1151
1152 static void
1153 CGM_write_char_record(int class, int cgm_id, int numbytes, char *data)
1154 {
1155     int i, pad, length;
1156     static unsigned char flag = 0xff;
1157     static unsigned char paddata = 0;
1158     char short_len;
1159
1160     pad = 0;
1161     length = numbytes + 1;
1162     if (numbytes >= 255)
1163         length += 2;    /* long string */
1164     if (length & 1)
1165         pad = 1;        /* needs pad */
1166     CGM_write_code(class, cgm_id, length);
1167     if (numbytes < 255)
1168     {
1169         short_len = (char)numbytes;
1170         fwrite(&short_len, 1, 1, gpoutfile);    /* write true length */
1171     } else {
1172         fwrite(&flag, 1, 1, gpoutfile);
1173         CGM_write_int(numbytes);
1174     }
1175
1176     if (data)
1177         fwrite(data, 1, numbytes, gpoutfile);           /* write string */
1178     else
1179         for (i=0; i<numbytes+pad; i++)
1180             fputc('\0', gpoutfile);                     /* write null bytes */
1181
1182     if(pad)
1183       fwrite(&paddata, 1, 1, gpoutfile);
1184 }
1185
1186 static void
1187 CGM_write_byte_record(int class, int cgm_id, int numbytes, char *data)
1188 {
1189     int pad;
1190     static unsigned char paddata = 0;
1191
1192     pad = numbytes & 1;
1193     CGM_write_code(class, cgm_id, numbytes);
1194     fwrite(data, 1, numbytes, gpoutfile);               /* write string */
1195     if(pad)
1196       fwrite(&paddata, 1, 1, gpoutfile);
1197 }
1198
1199 static void
1200 CGM_write_int_record(int class, int cgm_id, int numbytes, int *data)
1201 {
1202     int i;
1203     assert((numbytes & 1) == 0);
1204     CGM_write_code(class, cgm_id, numbytes);
1205     numbytes >>= 1;
1206     for (i = 0; i < numbytes; i++)
1207         CGM_write_int(data[i]);
1208 }
1209
1210 static void
1211 CGM_write_mixed_record(
1212      int class, int cgm_id,
1213      int numint, int *int_data,
1214      int numchar, const char *char_data)
1215 {
1216     int i, pad, length;
1217     static unsigned char paddata = 0;
1218     static unsigned char flag = 0xff;
1219     char short_len;
1220
1221     pad = 0;
1222     length = numchar + 1;
1223     if (numchar >= 255)
1224         length += 2;    /* long string */
1225     if (length & 1)
1226         pad = 1;        /* needs pad */
1227
1228     CGM_write_code(class, cgm_id, numint * 2 + length);
1229
1230     for (i = 0; i < numint; i++)
1231         CGM_write_int(int_data[i]);     /* write integers */
1232
1233     if (numchar < 255) {
1234         short_len = (char)numchar;
1235         fwrite(&short_len, 1, 1, gpoutfile);    /* write string length */
1236     } else {
1237         fwrite(&flag, 1, 1, gpoutfile);
1238         CGM_write_int(numchar);
1239     }
1240     fwrite(char_data, 1, numchar, gpoutfile);   /* write string */
1241     if(pad)
1242       fwrite(&paddata, 1, 1, gpoutfile);
1243 }
1244
1245 /*
1246    Write the code word that starts a CGM record.
1247    bits in code word are as follows...
1248    cccciiiiiiilllll
1249    where
1250    cccc is a 4-bit class number
1251    iiiiiii is a 7-bit ID number
1252    lllll is a 5-bit length (# bytes following the code word, or
1253             31 followed by a word with the actual number)
1254    */
1255 static void
1256 CGM_write_code(int class, int cgm_id, int length)
1257 {
1258     unsigned int code;
1259
1260     assert((0 <= class) &&(class <16));
1261     assert((0 <= cgm_id) && (cgm_id < 128));
1262     assert(0 <= length);
1263     if (length < 31) {
1264         code = ((class &0x0f) <<12) |
1265             ((cgm_id & 0x7f) << 5) |
1266             ((length & 0x1f));
1267         CGM_write_int(code);
1268     } else {
1269         code = ((class &0x0f) <<12) |
1270             ((cgm_id & 0x7f) << 5) |
1271             0x1f;
1272         CGM_write_int(code);
1273         CGM_write_int(length);
1274     }
1275 }
1276
1277 static void
1278 CGM_write_int(int value)
1279 {
1280     union {
1281         short s;
1282         char c[2];
1283     } u;
1284
1285 #if !defined(DOS16) && !defined(WIN16)
1286     assert( -32768 <= value );
1287     assert( value <= 32767 );
1288 #endif
1289
1290     u.c[0] = (value >> 8) & 255;        /* convert to network order */
1291     u.c[1] = value & 255;
1292
1293     fwrite(&u.s, 1, 2, gpoutfile);
1294 }
1295
1296 /* Draw a dashed line to (ux,uy).  CGM has linestyles, but they are
1297  * not usable -- at least with the Word for Windows 6.0 filter, where
1298  * lines of significant width (even 1 pt) always come out solid.
1299  * Therefore, we implement dashed lines here instead. */
1300 TERM_PUBLIC void
1301 CGM_dashed_vector(unsigned int ux, unsigned int uy)
1302 {
1303     int xa, ya;
1304     int dx, dy, adx, ady;
1305     int dist;                   /* approximate distance in plot units
1306                                    from starting point to specified end
1307                                    point. */
1308     long remain;                /* approximate distance in plot units
1309                                    remaining to specified end point. */
1310
1311     if (ux >= term->xmax)
1312         ux = term->xmax;
1313     if (uy >= term->ymax)
1314         uy = term->ymax;
1315
1316     dx = (ux - cgm_posx);
1317     dy = (uy - cgm_posy);
1318     adx = abs(dx);
1319     ady = abs(dy * 10);
1320
1321     /* using the approximation
1322        sqrt(x**2 + y**2)  ~  x + (5*x*x)/(12*y)   when x > y.
1323        Note ordering of calculations to avoid overflow on 16 bit
1324        architectures */
1325     if (10 * adx < ady)
1326         dist = (ady / 2 + 25 * adx / ady * adx / 6 * 5) / 5;
1327     else {
1328         if (adx == 0)
1329             return;
1330         dist = (adx * 10 + (ady / 24) * (ady / adx)) / 10;
1331     }
1332     remain = dist;
1333     xa = cgm_posx;
1334     ya = cgm_posy;
1335     while (remain > cgm_step) {
1336         remain -= cgm_step;
1337         if (cgm_step_index & 1)
1338             CGM_solid_vector((int) (ux - (remain * dx) / dist),
1339                              (int) (uy - (remain * dy) / dist));
1340         else {
1341             xa = (int) (ux - (remain * dx) / dist);
1342             ya = (int) (uy - (remain * dy) / dist);
1343             CGM_move(xa, ya);
1344         }
1345         if (++cgm_step_index >= 8)
1346             cgm_step_index = 0;
1347         cgm_step = cgm_step_sizes[cgm_step_index];
1348     }
1349     if (cgm_step_index & 1)
1350         CGM_solid_vector(ux, uy);
1351     else
1352         CGM_move(ux, uy);
1353     cgm_step -= (int) remain;
1354 }
1355
1356 TERM_PUBLIC void
1357 CGM_solid_vector(unsigned int ux, unsigned int uy)
1358 {
1359     if (ux >= term->xmax)
1360         ux = term->xmax;
1361     if (uy >= term->ymax)
1362         uy = term->ymax;
1363
1364     if (ux == cgm_posx && uy == cgm_posy)
1365         return;
1366     if (cgm_coords > CGM_MAX_SEGMENTS - 2) {
1367         if (cgm_doing_polygon)
1368               CGM_flush_polygon();
1369         else
1370               CGM_flush_polyline();
1371         cgm_polyline[cgm_coords++] = cgm_posx;
1372         cgm_polyline[cgm_coords++] = cgm_posy + CGM_MARGIN;
1373     } else if (cgm_coords == 0) {
1374         cgm_polyline[cgm_coords++] = cgm_posx;
1375         cgm_polyline[cgm_coords++] = cgm_posy + CGM_MARGIN;
1376     }
1377     cgm_polyline[cgm_coords++] = ux;
1378     cgm_polyline[cgm_coords++] = uy + CGM_MARGIN;
1379     cgm_posx = ux;
1380     cgm_posy = uy;
1381 }
1382
1383 TERM_PUBLIC void
1384 CGM_put_text(unsigned int x, unsigned int y, const char str[])
1385 {
1386     static int where[3] = { 0, 0, 1 }; /* the final "1" signals that
1387                                           this is the last text in the
1388                                           string */
1389     const char *s = str;
1390
1391     /* sanity check - labels are not clipped */
1392     if ((x > 32767) || (y > 32767))
1393       return;
1394
1395     while (*s)
1396         if (!isspace((unsigned char) *s++))
1397             goto showit;
1398     return;
1399
1400   showit:
1401
1402     CGM_flush_polyline();
1403
1404     /* update the text characteristics if they have changed since the
1405        last text string was output */
1406     if (cgm_current.font_index != cgm_next.font_index) {
1407       cgm_current.font_index = cgm_next.font_index;
1408       CGM_write_int_record(5, 10, 2, &cgm_next.font_index);
1409     }
1410     if (cgm_current.justify_mode != cgm_next.justify_mode) {
1411       static int data[6] = { 1, 3, 0, 0, 0, 0 };
1412       cgm_current.justify_mode = cgm_next.justify_mode;
1413
1414       switch (cgm_current.justify_mode) {
1415       case LEFT:
1416         data[0] = 1;
1417         break;
1418       case CENTRE:
1419         data[0] = 2;
1420         break;
1421       case RIGHT:
1422         data[0] = 3;
1423         break;
1424       default:
1425         assert(0);
1426       }
1427       CGM_write_int_record(5, 18, 12, data);
1428     }
1429
1430     if (cgm_current.char_height != cgm_next.char_height) {
1431       int h = cgm_next.char_height;
1432       cgm_current.char_height = h;
1433       h = h*2/3;                /* gnuplot measures fonts by the
1434                                    baseline-to-baseline distance,
1435                                    while the CGM file needs the actual
1436                                    height of the upper case
1437                                    characters. */
1438       CGM_write_int_record(5, 15, 2, &h);
1439     }
1440
1441     /* "angle" is the angle of the text baseline (counter-clockwise in
1442        radians from horizontal).  This is a bit more general than
1443        gnuplot needs right now. */
1444     if (cgm_current.angle != cgm_next.angle) {
1445       /* The first two elements of orient are components of a vector
1446          "upward" with respect to the text.  The next two elements are
1447          components of a vector along the baseline of the text. The
1448          lengths of both vectors are equal to the baseline-to-baseline
1449          distance in plot units. */
1450       static int orient[4];
1451       cgm_current.angle = cgm_next.angle;
1452
1453       orient[0] = (int)cgm_next.char_height*cos(cgm_next.angle+M_PI_2);
1454       orient[1] = (int)cgm_next.char_height*sin(cgm_next.angle+M_PI_2);
1455       orient[2] = (int)cgm_next.char_height*cos(cgm_next.angle);
1456       orient[3] = (int)cgm_next.char_height*sin(cgm_next.angle);
1457       CGM_write_int_record(5, 16, 8, orient);
1458     }
1459
1460     where[0] = x;
1461     where[1] = y + CGM_MARGIN;
1462     CGM_write_mixed_record(4, 4, 3, where, strlen(str), str);
1463
1464     cgm_posx = cgm_posy = -2000;
1465 }
1466
1467 TERM_PUBLIC int
1468 CGM_text_angle(int ang)
1469 {
1470     if (cgm_rotate) {
1471         cgm_next.angle = ang * M_PI_2 / 90.;
1472         return TRUE;
1473     }
1474     return ang ? FALSE : TRUE;
1475 }
1476
1477 TERM_PUBLIC int
1478 CGM_justify_text(enum JUSTIFY mode)
1479 {
1480   cgm_next.justify_mode = mode;
1481   return (TRUE);
1482 }
1483
1484 TERM_PUBLIC void
1485 CGM_reset()
1486 {
1487     cgm_posx = cgm_posy = 0;
1488     free(cgm_polyline);
1489 }
1490
1491 TERM_PUBLIC void
1492 CGM_point(unsigned int x, unsigned int y, int number)
1493 {
1494     int old_dashtype;
1495
1496     if (number < 0) {           /* draw dot */
1497         CGM_move(x, y);
1498         CGM_solid_vector(x + 1, y);
1499         return;
1500     }
1501     number %= CGM_POINTS;
1502
1503     CGM_flush_polyline();
1504     old_dashtype = cgm_dashtype;
1505     CGM_dashtype(0);
1506     if (number >= 3)            /* using a polygon */
1507       cgm_next.interior_style = 1; /* solid */
1508     if (number == 4 || number == 6 || number == 8
1509             || number == 10 || number == 12) {
1510         /* filled */
1511       cgm_next.edge_visibility = 0;
1512       cgm_next.fill_color = cgm_color;
1513     } else {
1514         /* NOT filled */
1515       cgm_next.edge_visibility = 1;
1516       cgm_next.interior_style = 0; /* empty */
1517       cgm_next.edge_color = cgm_color;
1518     }
1519
1520     if (cgm_current.interior_style != cgm_next.interior_style){
1521       cgm_current.interior_style = cgm_next.interior_style;
1522       CGM_write_int_record(5, 22, 2, &cgm_next.interior_style);
1523     }
1524     if (cgm_current.fill_color != cgm_next.fill_color){
1525       cgm_current.fill_color = cgm_next.fill_color;
1526       CGM_write_int_record(5, 23, 2, &cgm_next.fill_color);
1527     }
1528     if (cgm_current.edge_visibility != cgm_next.edge_visibility){
1529       cgm_current.edge_visibility = cgm_next.edge_visibility;
1530       CGM_write_int_record(5, 30, 2, &cgm_current.edge_visibility);
1531     }
1532     if (cgm_current.edge_visibility &&
1533         cgm_current.edge_color != cgm_next.edge_color){
1534       cgm_current.edge_color = cgm_next.edge_color;
1535       CGM_write_int_record(5, 29, 2, &cgm_current.edge_color);
1536     }
1537
1538     switch (number) {
1539     case 0:                     /* draw plus */
1540         CGM_move(x - cgm_tic, y);
1541         CGM_solid_vector(x + cgm_tic, y);
1542         CGM_move(x, y - cgm_tic);
1543         CGM_solid_vector(x, y + cgm_tic);
1544         break;
1545     case 1:                     /* draw X */
1546         CGM_move(x - cgm_tic707, y - cgm_tic707);
1547         CGM_solid_vector(x + cgm_tic707, y + cgm_tic707);
1548         CGM_move(x - cgm_tic707, y + cgm_tic707);
1549         CGM_solid_vector(x + cgm_tic707, y - cgm_tic707);
1550         break;
1551     case 2:                     /* draw star (asterisk) */
1552         CGM_move(x, y - cgm_tic);
1553         CGM_solid_vector(x, y + cgm_tic);
1554         CGM_move(x + cgm_tic866, y - cgm_tic500);
1555         CGM_solid_vector(x - cgm_tic866, y + cgm_tic500);
1556         CGM_move(x + cgm_tic866, y + cgm_tic500);
1557         CGM_solid_vector(x - cgm_tic866, y - cgm_tic500);
1558         break;
1559     case 3:                     /* draw box */
1560     case 4:
1561         CGM_move(x - cgm_tic707, y - cgm_tic707);
1562         CGM_solid_vector(x + cgm_tic707, y - cgm_tic707);
1563         CGM_solid_vector(x + cgm_tic707, y + cgm_tic707);
1564         CGM_solid_vector(x - cgm_tic707, y + cgm_tic707);
1565         CGM_flush_polygon();
1566         break;
1567     case 5:
1568     case 6:                     /* draw circle (actually, dodecagon)
1569                                    (WinWord 6 accepts the CGM "circle"
1570                                    element, but the resulting circle
1571                                    is not correctly centered!) */
1572         CGM_move(x, y - cgm_tic);
1573         CGM_solid_vector(x + cgm_tic500, y - cgm_tic866);
1574         CGM_solid_vector(x + cgm_tic866, y - cgm_tic500);
1575         CGM_solid_vector(x + cgm_tic, y);
1576         CGM_solid_vector(x + cgm_tic866, y + cgm_tic500);
1577         CGM_solid_vector(x + cgm_tic500, y + cgm_tic866);
1578         CGM_solid_vector(x, y + cgm_tic);
1579         CGM_solid_vector(x - cgm_tic500, y + cgm_tic866);
1580         CGM_solid_vector(x - cgm_tic866, y + cgm_tic500);
1581         CGM_solid_vector(x - cgm_tic, y);
1582         CGM_solid_vector(x - cgm_tic866, y - cgm_tic500);
1583         CGM_solid_vector(x - cgm_tic500, y - cgm_tic866);
1584         CGM_flush_polygon();
1585         break;
1586     case 7:                     /* draw triangle (point up) */
1587     case 8:
1588         CGM_move(x, y + cgm_tic1241);
1589         CGM_solid_vector(x - cgm_tic1077, y - cgm_tic621);
1590         CGM_solid_vector(x + cgm_tic1077, y - cgm_tic621);
1591         CGM_flush_polygon();
1592         break;
1593     case 9:                     /* draw triangle (point down) */
1594     case 10:
1595         CGM_move(x, y - cgm_tic1241);
1596         CGM_solid_vector(x - cgm_tic1077, y + cgm_tic621);
1597         CGM_solid_vector(x + cgm_tic1077, y + cgm_tic621);
1598         CGM_flush_polygon();
1599         break;
1600     case 11:                    /* draw diamond */
1601     case 12:
1602         CGM_move(x - cgm_tic, y);
1603         CGM_solid_vector(x, y - cgm_tic);
1604         CGM_solid_vector(x + cgm_tic, y);
1605         CGM_solid_vector(x, y + cgm_tic);
1606         CGM_flush_polygon();
1607         break;
1608     }
1609     CGM_dashtype(old_dashtype);
1610 }
1611
1612
1613 TERM_PUBLIC void
1614 CGM_set_pointsize(double size)
1615 {
1616     /* Markers were chosen to have approximately equal
1617        areas.  Dimensions are as follows, in units of
1618        cgm_tic:
1619
1620        plus, diamond: half height = 1
1621
1622        square, cross: half height = sqrt(1/2) ~ 12/17
1623
1624        triangle: half width = sqrt(sqrt(4/3)) ~ 14/13,
1625        height = sqrt(3*sqrt(4/3)) ~ 54/29
1626
1627        star: half height = 1, half width = sqrt(3/4) ~ 13/15
1628
1629        dodecagon: coordinates of vertices are 0,
1630        sin(30) = 1/2, cos(30) = sqrt(3/4) ~ 13/15, or 1
1631
1632        The fractions are approximates of the equivalent
1633        continued fractions. */
1634     if (size < 0)
1635         size = 1;
1636     cgm_tic = (size * term->h_tic / 2);
1637     cgm_tic707 = cgm_tic * 12 / 17;
1638     cgm_tic866 = cgm_tic * 13 / 15;
1639     cgm_tic500 = cgm_tic / 2;
1640     cgm_tic1241 = cgm_tic * 36 / 29;
1641     cgm_tic1077 = cgm_tic * 14 / 13;
1642     cgm_tic621 = cgm_tic * 18 / 29;
1643 }
1644
1645 static void
1646 CGM_flush_polygon()
1647 {
1648     if (cgm_coords == 0)
1649         return;
1650     CGM_write_int_record(4, 7, cgm_coords * 2, cgm_polyline);
1651     cgm_coords = 0;
1652 }
1653
1654 /*
1655  * This terminal driver does not support true RGB color,
1656  * but we can at least try to find some reasonable approximation.
1657  */
1658 #define CLOSE_ENOUGH 32         /* 0 would require a perfect match */
1659 static int
1660 CGM_find_nearest_color(t_colorspec *colorspec)
1661 {
1662     int red   = (colorspec->lt >> 16) & 0xff;
1663     int green = (colorspec->lt >> 8) & 0xff;
1664     int blue  = colorspec->lt & 0xff;
1665     int closest = 0;
1666     int howclose = 1<<16;
1667     int i = 0;
1668     int k;
1669     int dr, dg, db, distance;
1670
1671     for (k=0; k<cgm_user_color_max; k++) {
1672         dr = cgm_user_color_table[++i] - red;
1673         dg = cgm_user_color_table[++i] - green;
1674         db = cgm_user_color_table[++i] - blue;
1675         distance = (dr*dr + dg*dg + db*db);
1676         if (distance < howclose) {
1677             closest = k;
1678             howclose = distance;
1679         }
1680         if (distance < CLOSE_ENOUGH)
1681             break;
1682     }
1683
1684     FPRINTF((stderr,"CGM_find_nearest_color:  asked for %d %d %d\n",red,green,blue));
1685     FPRINTF((stderr,"         got index %3d             %d %d %d\n", closest,
1686             cgm_user_color_table[closest*3], cgm_user_color_table[closest*3+1],
1687             cgm_user_color_table[closest*3+2]));
1688
1689     return closest;
1690 }
1691 #undef CLOSE_ENOUGH
1692
1693 #ifdef DEFEAT_ASSERTIONS
1694 #define NDEBUG
1695 #include <assert.h>
1696 #undef DEFEAT_ASSERTIONS
1697 #endif /* DEFEAT_ASSERTIONS */
1698
1699 #ifdef NEXT
1700 #undef id
1701 #undef datum
1702 #endif
1703
1704 #endif /* TERM_BODY */
1705
1706 #ifdef TERM_TABLE
1707 TERM_TABLE_START(cgm_driver)
1708     "cgm", "Computer Graphics Metafile",
1709     CGM_LARGE - CGM_MARGIN, CGM_SMALL - CGM_MARGIN, CGM_VCHAR, CGM_HCHAR,
1710     CGM_VTIC, CGM_HTIC, CGM_options, CGM_init, CGM_reset,
1711     CGM_text, null_scale, CGM_graphics, CGM_move, CGM_solid_vector,
1712     CGM_linetype, CGM_put_text, CGM_text_angle,
1713     CGM_justify_text, CGM_point, do_arrow, CGM_set_font,
1714     CGM_set_pointsize,
1715     TERM_BINARY,                /* various flags */
1716     NULL,                       /* after one plot of multiplot */
1717     NULL,                       /* before subsequent plot of multiplot */
1718     CGM_fillbox,
1719     CGM_linewidth
1720 #ifdef USE_MOUSE
1721     , NULL, NULL, NULL, NULL, NULL
1722 /*  , waitforinput, put_tmptext, set_ruler, set_cursor, set_clipboard */
1723 #endif
1724     , CGM_make_palette,
1725     NULL /* _previous_palette */,
1726     CGM_set_color,
1727     CGM_filled_polygon
1728 TERM_TABLE_END(cgm_driver)
1729
1730 #undef LAST_TERM
1731 #define LAST_TERM cgm_driver
1732
1733 #endif /* TERM_TABLE */
1734 #endif /* TERM_PROTO_ONLY */
1735
1736 #ifdef TERM_HELP
1737 START_HELP(cgm)
1738 "1 cgm",
1739 "?commands set terminal cgm",
1740 "?set terminal cgm",
1741 "?set term cgm",
1742 "?terminal cgm",
1743 "?term cgm",
1744 "?cgm",
1745 " The `cgm` terminal generates a Computer Graphics Metafile, Version 1. ",
1746 " This file format is a subset of the ANSI X3.122-1986 standard entitled",
1747 " \"Computer Graphics - Metafile for the Storage and Transfer of Picture",
1748 " Description Information\".",
1749 "",
1750 " Syntax:",
1751 "       set terminal cgm {color | monochrome} {solid | dashed} {{no}rotate}",
1752 "                        {<mode>} {width <plot_width>} {linewidth <line_width>}",
1753 "                        {font \"<fontname>,<fontsize>\"}",
1754 "                        {<color0> <color1> <color2> ...}",
1755 "",
1756 " `solid` draws all curves with solid lines, overriding any dashed patterns;",
1757 " <mode> is `landscape`, `portrait`, or `default`;",
1758 " <plot_width> is the assumed width of the plot in points; ",
1759 " <line_width> is the line width in points (default 1); ",
1760 " <fontname> is the name of a font (see list of fonts below)",
1761 " <fontsize> is the size of the font in points (default 12).",
1762 "",
1763 " The first six options can be in any order.  Selecting `default` sets all",
1764 " options to their default values.",
1765 "",
1766 " Each color must be of the form 'xrrggbb', where x is the literal",
1767 " character 'x' and 'rrggbb' are the red, green and blue components in",
1768 " hex.  For example, 'x00ff00' is green.  The background color is set",
1769 " first, then the plotting colors.",
1770 "",
1771 " Examples:",
1772 "       set terminal cgm landscape color rotate dashed width 432 \\",
1773 "                      linewidth 1  'Helvetica Bold' 12       # defaults",
1774 "       set terminal cgm linewidth 2  14  # wider lines & larger font",
1775 "       set terminal cgm portrait \"Times Italic\" 12",
1776 "       set terminal cgm color solid      # no pesky dashes!",
1777
1778 "2 cgm fonts",
1779 "?commands set terminal cgm font",
1780 "?set terminal cgm font",
1781 "?set term cgm font",
1782 "?cgm font",
1783 " The first part of a Computer Graphics Metafile, the metafile description,",
1784 " includes a font table.  In the picture body, a font is designated by an",
1785 " index into this table.  By default, this terminal generates a table with",
1786 " the following 35 fonts, plus six more with `italic` replaced by",
1787 " `oblique`, or vice-versa (since at least the Microsoft Office and Corel",
1788 " Draw CGM import filters treat `italic` and `oblique` as equivalent):",
1789 "@start table - first is interactive cleartext form",
1790 "       Helvetica",
1791 "       Helvetica Bold",
1792 "       Helvetica Oblique",
1793 "       Helvetica Bold Oblique",
1794 "       Times Roman",
1795 "       Times Bold",
1796 "       Times Italic",
1797 "       Times Bold Italic",
1798 "       Courier",
1799 "       Courier Bold",
1800 "       Courier Oblique",
1801 "       Courier Bold Oblique",
1802 "       Symbol",
1803 "       Hershey/Cartographic_Roman",
1804 "       Hershey/Cartographic_Greek",
1805 "       Hershey/Simplex_Roman",
1806 "       Hershey/Simplex_Greek",
1807 "       Hershey/Simplex_Script",
1808 "       Hershey/Complex_Roman",
1809 "       Hershey/Complex_Greek",
1810 "       Hershey/Complex_Script",
1811 "       Hershey/Complex_Italic",
1812 "       Hershey/Complex_Cyrillic",
1813 "       Hershey/Duplex_Roman",
1814 "       Hershey/Triplex_Roman",
1815 "       Hershey/Triplex_Italic",
1816 "       Hershey/Gothic_German",
1817 "       Hershey/Gothic_English",
1818 "       Hershey/Gothic_Italian",
1819 "       Hershey/Symbol_Set_1",
1820 "       Hershey/Symbol_Set_2",
1821 "       Hershey/Symbol_Math",
1822 "       ZapfDingbats",
1823 "       Script",
1824 "       15",
1825 "#\\begin{tabular}{|ccl|} \\hline",
1826 "#\\multicolumn{3}{|c|}{CGM fonts}\\\\",
1827 "#&Helvetica&\\\\",
1828 "#&Helvetica Bold&\\\\",
1829 "#&Helvetica Oblique&\\\\",
1830 "#&Helvetica Bold Oblique&\\\\",
1831 "#&Times Roman&\\\\",
1832 "#&Times Bold&\\\\",
1833 "#&Times Italic&\\\\",
1834 "#&Times Bold Italic&\\\\",
1835 "#&Courier&\\\\",
1836 "#&Courier Bold&\\\\",
1837 "#&Courier Oblique&\\\\",
1838 "#&Courier Bold Oblique&\\\\",
1839 "#&Symbol&\\\\",
1840 "#&Hershey/Cartographic\\_Roman&\\\\",
1841 "#&Hershey/Cartographic\\_Greek&\\\\",
1842 "#&Hershey/Simplex\\_Roman&\\\\",
1843 "#&Hershey/Simplex\\_Greek&\\\\",
1844 "#&Hershey/Simplex\\_Script&\\\\",
1845 "#&Hershey/Complex\\_Roman&\\\\",
1846 "#&Hershey/Complex\\_Greek&\\\\",
1847 "#&Hershey/Complex\\_Script&\\\\",
1848 "#&Hershey/Complex\\_Italic&\\\\",
1849 "#&Hershey/Complex\\_Cyrillic&\\\\",
1850 "#&Hershey/Duplex\\_Roman&\\\\",
1851 "#&Hershey/Triplex\\_Roman&\\\\",
1852 "#&Hershey/Triplex\\_Italic&\\\\",
1853 "#&Hershey/Gothic\\_German&\\\\",
1854 "#&Hershey/Gothic\\_English&\\\\",
1855 "#&Hershey/Gothic\\_Italian&\\\\",
1856 "#&Hershey/Symbol\\_Set\\_1&\\\\",
1857 "#&Hershey/Symbol\\_Set\\_2&\\\\",
1858 "#&Hershey/Symbol\\_Math&\\\\",
1859 "#&ZapfDingbats&\\\\",
1860 "#&Script&\\\\",
1861 "#&15&\\\\",
1862 "%c c l .",
1863 "%@@CGM fonts",
1864 "%_",
1865 "%@@Helvetica",
1866 "%@@Helvetica Bold",
1867 "%@@Helvetica Oblique",
1868 "%@@Helvetica Bold Oblique",
1869 "%@@Times Roman",
1870 "%@@Times Bold",
1871 "%@@Times Italic",
1872 "%@@Times Bold Italic",
1873 "%@@Courier",
1874 "%@@Courier Bold",
1875 "%@@Courier Oblique",
1876 "%@@Courier Bold Oblique",
1877 "%@@Symbol",
1878 "%@@Hershey/Cartographic_Roman",
1879 "%@@Hershey/Cartographic_Greek",
1880 "%@@Hershey/Simplex_Roman",
1881 "%@@Hershey/Simplex_Greek",
1882 "%@@Hershey/Simplex_Script",
1883 "%@@Hershey/Complex_Roman",
1884 "%@@Hershey/Complex_Greek",
1885 "%@@Hershey/Complex_Script",
1886 "%@@Hershey/Complex_Italic",
1887 "%@@Hershey/Complex_Cyrillic",
1888 "%@@Hershey/Duplex_Roman",
1889 "%@@Hershey/Triplex_Roman",
1890 "%@@Hershey/Triplex_Italic",
1891 "%@@Hershey/Gothic_German",
1892 "%@@Hershey/Gothic_English",
1893 "%@@Hershey/Gothic_Italian",
1894 "%@@Hershey/Symbol_Set_1",
1895 "%@@Hershey/Symbol_Set_2",
1896 "%@@Hershey/Symbol_Math",
1897 "%@@ZapfDingbats",
1898 "%@@Script",
1899 "%@@15",
1900 "@end table",
1901
1902 " The first thirteen of these fonts are required for WebCGM.  The",
1903 " Microsoft Office CGM import filter implements the 13 standard fonts",
1904 " listed above, and also 'ZapfDingbats' and 'Script'.  However, the",
1905 " script font may only be accessed under the name '15'.  For more on",
1906 " Microsoft import filter font substitutions, check its help file which",
1907 " you may find here:",
1908 "   C:\\Program Files\\Microsoft Office\\Office\\Cgmimp32.hlp",
1909 " and/or its configuration file, which you may find here:",
1910 "   C:\\Program Files\\Common Files\\Microsoft Shared\\Grphflt\\Cgmimp32.cfg",
1911 "",
1912 " In the `set term` command, you may specify a font name which does not",
1913 " appear in the default font table.  In that case, a new font table is",
1914 " constructed with the specified font as its first entry. You must ensure",
1915 " that the spelling, capitalization, and spacing of the name are",
1916 " appropriate for the application that will read the CGM file.  (Gnuplot",
1917 " and any MIL-D-28003A compliant application ignore case in font names.)",
1918 " If you need to add several new fonts, use several `set term` commands.",
1919 "",
1920 " Example:",
1921 "       set terminal cgm 'Old English'",
1922 "       set terminal cgm 'Tengwar'",
1923 "       set terminal cgm 'Arabic'",
1924 "       set output 'myfile.cgm'",
1925 "       plot ...",
1926 "       set output",
1927 "",
1928 " You cannot introduce a new font in a `set label` command.",
1929
1930 "2 cgm fontsize",
1931 "?commands set terminal cgm fontsize",
1932 "?set terminal cgm fontsize",
1933 "?set term cgm fontsize",
1934 "?cgm fontsize",
1935 " Fonts are scaled assuming the page is 6 inches wide.  If the `size`",
1936 " command is used to change the aspect ratio of the page or the CGM file",
1937 " is converted to a different width, the resulting font sizes will be",
1938 " scaled up or down accordingly.  To change the assumed width, use the",
1939 " `width` option.",
1940
1941 "2 cgm linewidth",
1942 "?commands set terminal cgm linewidth",
1943 "?set terminal cgm linewidth",
1944 "?set term cgm linewidth",
1945 "?cgm linewidth",
1946 " The `linewidth` option sets the width of lines in pt.  The default width",
1947 " is 1 pt.  Scaling is affected by the actual width of the page, as",
1948 " discussed under the `fontsize` and `width` options.",
1949
1950 "2 cgm rotate",
1951 "?commands set terminal cgm rotate",
1952 "?set terminal cgm rotate",
1953 "?set term cgm rotate",
1954 "?cgm rotate",
1955 " The `norotate` option may be used to disable text rotation.  For",
1956 " example, the CGM input filter for Word for Windows 6.0c can accept",
1957 " rotated text, but the DRAW editor within Word cannot.  If you edit a",
1958 " graph (for example, to label a curve), all rotated text is restored to",
1959 " horizontal.  The Y axis label will then extend beyond the clip boundary.",
1960 " With `norotate`, the Y axis label starts in a less attractive location,",
1961 " but the page can be edited without damage.  The `rotate` option confirms",
1962 " the default behavior.",
1963
1964 "2 cgm solid",
1965 "?set terminal cgm solid",
1966 "?set term cgm solid",
1967 "?cgm solid",
1968 " The `solid` option may be used to disable dashed line styles in the",
1969 " plots.  This is useful when color is enabled and the dashing of the",
1970 " lines detracts from the appearance of the plot. The `dashed` option",
1971 " confirms the default behavior, which gives a different dash pattern to",
1972 " each line type.",
1973
1974 "2 cgm size",
1975 "?commands set terminal cgm size",
1976 "?set terminal cgm size",
1977 "?set term cgm size",
1978 "?cgm size",
1979 " Default size of a CGM plot is 32599 units wide and 23457 units high for",
1980 " landscape, or 23457 units wide by 32599 units high for portrait.",
1981
1982 "2 cgm width",
1983 "?commands set terminal cgm width",
1984 "?set terminal cgm width",
1985 "?set term cgm width",
1986 "?cgm width",
1987 " All distances in the CGM file are in abstract units.  The application",
1988 " that reads the file determines the size of the final plot.  By default,",
1989 " the width of the final plot is assumed to be 6 inches (15.24 cm).  This",
1990 " distance is used to calculate the correct font size, and may be changed",
1991 " with the `width` option.  The keyword should be followed by the width in",
1992 " points.  (Here, a point is 1/72 inch, as in PostScript.  This unit is",
1993 " known as a \"big point\" in TeX.)  Gnuplot `expressions` can be used to",
1994 " convert from other units.",
1995 "",
1996 " Example:",
1997 "       set terminal cgm width 432            # default",
1998 "       set terminal cgm width 6*72           # same as above",
1999 "       set terminal cgm width 10/2.54*72     # 10 cm wide",
2000
2001 "2 cgm nofontlist",
2002 "?commands set terminal cgm nofontlist",
2003 "?set terminal cgm nofontlist",
2004 "?set term cgm nofontlist",
2005 "?cgm nofontlist",
2006 "?set terminal cgm winword6",
2007 "?set term cgm winword6",
2008 "?cgm winword6",
2009 " The default font table includes the fonts recommended for WebCGM, which",
2010 " are compatible with the Computer Graphics Metafile input filter for",
2011 " Microsoft Office and Corel Draw.  Another application might use",
2012 " different fonts and/or different font names, which may not be",
2013 " documented.  The `nofontlist` (synonym `winword6`) option deletes the font",
2014 " table from the CGM file.  In this case, the reading application should",
2015 " use a default table.  Gnuplot will still use its own default font table",
2016 " to select font indices.  Thus, 'Helvetica' will give you an index of 1,",
2017 " which should get you the first entry in your application's default font",
2018 " table. 'Helvetica Bold' will give you its second entry, etc.",
2019 ""
2020
2021 END_HELP(cgm)
2022 #endif /* TERM_HELP */
2023
2024
2025 /*
2026  * Local Variables:
2027  * mode:C
2028  * eval: (c-set-style "k&r")
2029  * End:
2030  */