1 /* This file is part of the GNU plotutils package. Copyright (C) 1995,
2 1996, 1997, 1998, 1999, 2000, 2005, 2008, Free Software Foundation, Inc.
3
4 The GNU plotutils package is free software. You may redistribute it
5 and/or modify it under the terms of the GNU General Public License as
6 published by the Free Software foundation; either version 2, or (at your
7 option) any later version.
8
9 The GNU plotutils package is distributed in the hope that it will be
10 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with the GNU plotutils package; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin St., Fifth Floor,
17 Boston, MA 02110-1301, USA. */
18
19 /* This file defines the initialization for any CGMPlotter object,
20 including both private data and public methods. There is a one-to-one
21 correspondence between public methods and user-callable functions in the
22 C API. */
23
24 #include "sys-defines.h"
25 #include "extern.h"
26
27 /* localtime_r() is currently not used, because there is apparently _no_
28 universal way of ensuring that it is declared. On some systems
29 (e.g. Red Hat Linux), `#define _POSIX_SOURCE' will do it. But on other
30 systems, doing `#define _POSIX_SOURCE' **removes** the declaration! */
31 #ifdef HAVE_LOCALTIME_R
32 #undef HAVE_LOCALTIME_R
33 #endif
34
35 #ifdef MSDOS
36 #include <unistd.h> /* for fsync() */
37 #endif
38
39 /* song and dance to define time_t, and declare both time() and localtime() */
40 #ifdef HAVE_SYS_TYPES_H
41 #include <sys/types.h> /* for time_t on some pre-ANSI Unix systems */
42 #endif
43 #ifdef TIME_WITH_SYS_TIME
44 #include <sys/time.h> /* for time() on some pre-ANSI Unix systems */
45 #include <time.h> /* for localtime() */
46 #else /* not TIME_WITH_SYS_TIME, include only one (prefer <sys/time.h>) */
47 #ifdef HAVE_SYS_TIME_H
48 #include <sys/time.h>
49 #else /* not HAVE_SYS_TIME_H */
50 #include <time.h>
51 #endif /* not HAVE_SYS_TIME_H */
52 #endif /* not TIME_WITH_SYS_TIME */
53
54 /* forward references */
55 static void build_sdr_from_index (plOutbuf *sdr_buffer, int cgm_encoding, int x);
56 static void build_sdr_from_string (plOutbuf *sdr_buffer, int cgm_encoding, const char *s, int string_length, bool use_double_quotes);
57 static void build_sdr_from_ui8s (plOutbuf *sdr_buffer, int cgm_encoding, const int *x, int n);
58
59 #ifndef LIBPLOTTER
60 /* In libplot, this is the initialization for the function-pointer part of
61 a CGMPlotter struct. */
62 const Plotter _pl_c_default_plotter =
63 {
64 /* initialization (after creation) and termination (before deletion) */
65 _pl_c_initialize, _pl_c_terminate,
66 /* page manipulation */
67 _pl_c_begin_page, _pl_c_erase_page, _pl_c_end_page,
68 /* drawing state manipulation */
69 _pl_g_push_state, _pl_g_pop_state,
70 /* internal path-painting methods (endpath() is a wrapper for the first) */
71 _pl_c_paint_path, _pl_c_paint_paths, _pl_g_path_is_flushable, _pl_g_maybe_prepaint_segments,
72 /* internal methods for drawing of markers and points */
73 _pl_c_paint_marker, _pl_c_paint_point,
74 /* internal methods that plot strings in Hershey, non-Hershey fonts */
75 _pl_g_paint_text_string_with_escapes, _pl_c_paint_text_string,
76 _pl_g_get_text_width,
77 /* private low-level `retrieve font' method */
78 _pl_g_retrieve_font,
79 /* `flush output' method, called only if Plotter handles its own output */
80 _pl_g_flush_output,
81 /* error handlers */
82 _pl_g_warning,
83 _pl_g_error,
84 };
85 #endif /* not LIBPLOTTER */
86
87 /* The private `initialize' method, which is invoked when a Plotter is
88 created. It is used for such things as initializing capability flags
89 from the values of class variables, allocating storage, etc. When this
90 is invoked, _plotter points to the Plotter that has just been
91 created. */
92
93 void
_pl_c_initialize(S___ (Plotter * _plotter))94 _pl_c_initialize (S___(Plotter *_plotter))
95 {
96 #ifndef LIBPLOTTER
97 /* in libplot, manually invoke superclass initialization method */
98 _pl_g_initialize (S___(_plotter));
99 #endif
100
101 /* override generic initializations (which are appropriate to the base
102 Plotter class), as necessary */
103
104 #ifndef LIBPLOTTER
105 /* tag field, differs in derived classes */
106 _plotter->data->type = PL_CGM;
107 #endif
108
109 /* output model */
110 _plotter->data->output_model = PL_OUTPUT_PAGES_ALL_AT_ONCE;
111
112 /* user-queryable capabilities: 0/1/2 = no/yes/maybe */
113 _plotter->data->have_wide_lines = 1;
114 _plotter->data->have_dash_array = 0;
115 _plotter->data->have_solid_fill = 1;
116 _plotter->data->have_odd_winding_fill = 1;
117 _plotter->data->have_nonzero_winding_fill = 0;
118 _plotter->data->have_settable_bg = 1;
119 _plotter->data->have_escaped_string_support = 0;
120 _plotter->data->have_ps_fonts = 1;
121 _plotter->data->have_pcl_fonts = 0;
122 _plotter->data->have_stick_fonts = 0;
123 _plotter->data->have_extra_stick_fonts = 0;
124 _plotter->data->have_other_fonts = 0;
125
126 /* text and font-related parameters (internal, not queryable by user);
127 note that we don't set kern_stick_fonts, because it was set by the
128 superclass initialization (and it's irrelevant for this Plotter type,
129 anyway) */
130 _plotter->data->default_font_type = PL_F_POSTSCRIPT;
131 _plotter->data->pcl_before_ps = false;
132 _plotter->data->have_horizontal_justification = true;
133 _plotter->data->have_vertical_justification = true;
134 _plotter->data->issue_font_warning = true;
135
136 /* path-related parameters (also internal); note that we
137 don't set max_unfilled_path_length, because it was set by the
138 superclass initialization */
139 _plotter->data->have_mixed_paths = false;
140 _plotter->data->allowed_arc_scaling = AS_NONE;
141 _plotter->data->allowed_ellarc_scaling = AS_NONE;
142 _plotter->data->allowed_quad_scaling = AS_NONE;
143 _plotter->data->allowed_cubic_scaling = AS_NONE;
144 _plotter->data->allowed_box_scaling = AS_AXES_PRESERVED;
145 _plotter->data->allowed_circle_scaling = AS_UNIFORM;
146 _plotter->data->allowed_ellipse_scaling = AS_ANY;
147
148 /* dimensions */
149 _plotter->data->display_model_type = (int)DISP_MODEL_VIRTUAL;
150 _plotter->data->display_coors_type = (int)DISP_DEVICE_COORS_INTEGER_NON_LIBXMI;
151 _plotter->data->flipped_y = false;
152 /* we choose viewport coor range to be 1/4 of the integer range */
153 _plotter->data->imin = - ((1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) - 1);
154 _plotter->data->imax = (1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) - 1;
155 _plotter->data->jmin = - ((1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) - 1);
156 _plotter->data->jmax = (1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) - 1;
157 _plotter->data->xmin = 0.0;
158 _plotter->data->xmax = 0.0;
159 _plotter->data->ymin = 0.0;
160 _plotter->data->ymax = 0.0;
161 _plotter->data->page_data = (plPageData *)NULL;
162
163 /* initialize data members specific to this derived class */
164 /* parameters */
165 _plotter->cgm_encoding = CGM_ENCODING_BINARY;
166 _plotter->cgm_max_version = 4;
167 /* most important dynamic variables (global) */
168 _plotter->cgm_version = 1;
169 _plotter->cgm_profile = CGM_PROFILE_WEB;
170 _plotter->cgm_need_color = false;
171 /* corresponding dynamic variables (page-specific, i.e. picture-specific) */
172 _plotter->cgm_page_version = 1;
173 _plotter->cgm_page_profile = CGM_PROFILE_WEB;
174 _plotter->cgm_page_need_color = false;
175 /* colors (24-bit or 48-bit, initialized to nonphysical or dummy values) */
176 _plotter->cgm_line_color.red = -1;
177 _plotter->cgm_line_color.green = -1;
178 _plotter->cgm_line_color.blue = -1;
179 _plotter->cgm_edge_color.red = -1;
180 _plotter->cgm_edge_color.green = -1;
181 _plotter->cgm_edge_color.blue = -1;
182 _plotter->cgm_fillcolor.red = -1;
183 _plotter->cgm_fillcolor.green = -1;
184 _plotter->cgm_fillcolor.blue = -1;
185 _plotter->cgm_marker_color.red = -1;
186 _plotter->cgm_marker_color.green = -1;
187 _plotter->cgm_marker_color.blue = -1;
188 _plotter->cgm_text_color.red = -1;
189 _plotter->cgm_text_color.green = -1;
190 _plotter->cgm_text_color.blue = -1;
191 _plotter->cgm_bgcolor.red = -1; /* set in c_begin_page() */
192 _plotter->cgm_bgcolor.green = -1;
193 _plotter->cgm_bgcolor.blue = -1;
194 /* other dynamic variables */
195 _plotter->cgm_line_type = CGM_L_SOLID;
196 _plotter->cgm_dash_offset = 0.0;
197 _plotter->cgm_join_style = CGM_JOIN_UNSPEC;
198 _plotter->cgm_cap_style = CGM_CAP_UNSPEC;
199 _plotter->cgm_dash_cap_style = CGM_CAP_UNSPEC;
200 /* CGM's default line width: 1/1000 times the max VDC dimension */
201 _plotter->cgm_line_width = (1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) / 500;
202 _plotter->cgm_interior_style = CGM_INT_STYLE_HOLLOW;
203 _plotter->cgm_edge_type = CGM_L_SOLID;
204 _plotter->cgm_edge_dash_offset = 0.0;
205 _plotter->cgm_edge_join_style = CGM_JOIN_UNSPEC;
206 _plotter->cgm_edge_cap_style = CGM_CAP_UNSPEC;
207 _plotter->cgm_edge_dash_cap_style = CGM_CAP_UNSPEC;
208 /* CGM's default edge width: 1/1000 times the max VDC dimension */
209 _plotter->cgm_edge_width = (1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) / 500;
210 _plotter->cgm_edge_is_visible = false;
211 _plotter->cgm_miter_limit = 32767.0;
212 _plotter->cgm_marker_type = CGM_M_ASTERISK;
213 /* CGM's default marker size: 1/1000 times the max VDC dimension */
214 _plotter->cgm_marker_size = (1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) /500;
215 /* label-related variables */
216 _plotter->cgm_char_height = -1; /* impossible (dummy) value */
217 _plotter->cgm_char_base_vector_x = 1;
218 _plotter->cgm_char_base_vector_y = 0;
219 _plotter->cgm_char_up_vector_x = 0;
220 _plotter->cgm_char_up_vector_y = 1;
221 _plotter->cgm_horizontal_text_alignment = CGM_ALIGN_NORMAL_HORIZONTAL;
222 _plotter->cgm_vertical_text_alignment = CGM_ALIGN_NORMAL_VERTICAL;
223 _plotter->cgm_font_id = -1; /* impossible (dummy) value */
224 _plotter->cgm_charset_lower = 0; /* dummy value (we use values 1..4) */
225 _plotter->cgm_charset_upper = 0; /* dummy value (we use values 1..4) */
226 _plotter->cgm_restricted_text_type = CGM_RESTRICTED_TEXT_TYPE_BASIC;
227
228 /* initialize certain data members from device driver parameters */
229
230 /* determine page type, and viewport size and location */
231 _set_page_type (_plotter->data);
232
233 /* user may have specified a viewport aspect ratio other than 1:1, so
234 carefully compute device-space coordinate ranges (i.e. don't use above
235 default values for imin,imax,jmin,jmax, which are appropriate only for
236 a square viewport) */
237 {
238 /* our choice: the larger side of the viewport will essentially be 1/4
239 times the maximum range for integer device coordinates, i.e., half
240 the larger side will be 1/8 times the maximum range */
241 int half_side = (1 << (8*CGM_BINARY_BYTES_PER_INTEGER - 3)) - 1;
242 int half_other_side;
243 double xsize = _plotter->data->viewport_xsize;
244 double ysize = _plotter->data->viewport_ysize;
245 int xsign = xsize < 0.0 ? -1 : 1;
246 int ysign = ysize < 0.0 ? -1 : 1;
247 double fraction;
248
249 /* There are two cases, plus a degenerate case. For each,
250 `scaling_factor' is the conversion factor from virtual to physical
251 units. */
252
253 if (xsize == 0.0 && ysize == 0.0)
254 /* degenerate case, scaling_factor = 0 (or anything else :-)) */
255 {
256 _plotter->data->imin = 0;
257 _plotter->data->imax = 0;
258 _plotter->data->jmin = 0;
259 _plotter->data->jmax = 0;
260 }
261 else if (FABS(ysize) > FABS(xsize))
262 /* scaling_factor = FABS(ysize) / (2*half_side) */
263 {
264 fraction = FABS(xsize) / FABS(ysize);
265 half_other_side = IROUND(half_side * fraction);
266 _plotter->data->imin = - xsign * half_other_side;
267 _plotter->data->imax = xsign * half_other_side;
268 _plotter->data->jmin = - ysign * half_side;
269 _plotter->data->jmax = ysign * half_side;
270 }
271 else /* FABS(ysize) <= FABS(xsize), which is nonzero */
272 /* scaling_factor = FABS(xsize) / (2*half_side) */
273 {
274 fraction = FABS(ysize) / FABS(xsize);
275 half_other_side = IROUND(half_side * fraction);
276 _plotter->data->imin = - xsign * half_side;
277 _plotter->data->imax = xsign * half_side;
278 _plotter->data->jmin = - ysign * half_other_side;
279 _plotter->data->jmax = ysign * half_other_side;
280 }
281 }
282
283 /* compute the NDC to device-frame affine map, set it in Plotter */
284 _compute_ndc_to_device_map (_plotter->data);
285
286 /* determine CGM encoding */
287 {
288 const char* cgm_encoding_type;
289
290 cgm_encoding_type =
291 (const char *)_get_plot_param (_plotter->data, "CGM_ENCODING");
292 if (cgm_encoding_type != NULL)
293 {
294 if (strcmp (cgm_encoding_type, "binary") == 0)
295 _plotter->cgm_encoding = CGM_ENCODING_BINARY;
296 else if (strcmp (cgm_encoding_type, "clear text") == 0
297 || (strcmp (cgm_encoding_type, "cleartext") == 0)
298 || (strcmp (cgm_encoding_type, "clear_text") == 0))
299 _plotter->cgm_encoding = CGM_ENCODING_CLEAR_TEXT;
300 else /* we don't support the character encoding */
301 _plotter->cgm_encoding = CGM_ENCODING_BINARY;
302 }
303 else
304 _plotter->cgm_encoding = CGM_ENCODING_BINARY; /* default value */
305 }
306
307 /* determine upper bound on CGM version number */
308 {
309 const char* cgm_max_version_type;
310
311 cgm_max_version_type =
312 (const char *)_get_plot_param (_plotter->data, "CGM_MAX_VERSION");
313 if (cgm_max_version_type != NULL)
314 {
315 if (strcmp (cgm_max_version_type, "1") == 0)
316 _plotter->cgm_max_version = 1;
317 else if (strcmp (cgm_max_version_type, "2") == 0)
318 _plotter->cgm_max_version = 2;
319 else if (strcmp (cgm_max_version_type, "3") == 0)
320 _plotter->cgm_max_version = 3;
321 else if (strcmp (cgm_max_version_type, "4") == 0)
322 _plotter->cgm_max_version = 4;
323 else /* use default */
324 _plotter->cgm_max_version = 4;
325 }
326 else
327 _plotter->cgm_max_version = 4; /* use default */
328 }
329
330 /* If the maximum CGM version number is greater than 1, relax the
331 constraints on what path segments can be stored in libplot's path
332 buffer. By default, we allow only line segments. */
333
334 /* Counterclockwise circular arcs have been in the CGM standard since
335 version 1, but clockwise circular arcs were only added in version 2.
336 To include a circular arc we insist on a uniform map from user to
337 device coordinates, since otherwise it wouldn't be mapped to a
338 circle.
339
340 Similarly, we don't allow elliptic arcs into the arc buffer unless the
341 version is 2 or higher. Elliptic arcs have been in the standard since
342 version 1, but the `closed figure' construction that we use to fill
343 single elliptic (and circular!) arcs was only added in version 2. */
344 if (_plotter->cgm_max_version >= 2)
345 {
346 _plotter->data->allowed_arc_scaling = AS_UNIFORM;
347 _plotter->data->allowed_ellarc_scaling = AS_ANY;
348 }
349
350 /* Bezier cubics were added to the standard in version 3. Closed mixed
351 paths (`closed figures' in CGM jargon) have been in the standard since
352 version 2, but open mixed paths (`compound lines' in CGM jargon) were
353 only added in version 3. */
354 if (_plotter->cgm_max_version >= 3)
355 {
356 _plotter->data->allowed_cubic_scaling = AS_ANY;
357 _plotter->data->have_mixed_paths = true;
358 }
359
360 /* Beginning in version 3 CGM's, user can define line types, by
361 specifying a precise dashing style. */
362 if (_plotter->cgm_max_version >= 3)
363 _plotter->data->have_dash_array = 1;
364 }
365
366 /* Lists of metafile elements that we use, indexed by the CGM version less
367 unity, i.e., by 0,1,2,3 for CGM versions 1,2,3,4. We use a standard
368 shorthand: element class -1, and element id 0, 1, 2, etc., specifies
369 certain sets of metafile elements. E.g., class=-1 and id=1 specifies
370 all the version-1 metafile elements; in the clear text encoding this is
371 written as "DRAWINGPLUS". */
372
373 #define MAX_CGM_ELEMENT_LIST_LENGTH 1
374 typedef struct
375 {
376 const char *text_string;
377 int length; /* number of genuine entries in list */
378 int class_id[MAX_CGM_ELEMENT_LIST_LENGTH];
379 int element_id[MAX_CGM_ELEMENT_LIST_LENGTH];
380 }
381 plCGMElementList;
382
383 static const plCGMElementList _metafile_element_list[4] =
384 {
385 /* version 1 */
386 { "DRAWINGPLUS", 1, {-1}, {1} },
387 /* version 2 */
388 { "VERSION2", 1, {-1}, {2} },
389 /* version 3 */
390 { "VERSION3", 1, {-1}, {5} },
391 /* version 4 */
392 { "VERSION4", 1, {-1}, {6} }
393 };
394
395 /* CGM character sets, for upper and lower halves of both ISO-Latin-1 and
396 Symbol fonts. We use standard 8-bit encoding when writing text strings
397 in either sort of font, but the character set used in each font half
398 needs to be specified explicitly. Supported types of character set
399 include "standard 94-character set" and "standard 96-character set".
400 The character set is further specified by the "tail" string. */
401
402 typedef struct
403 {
404 int type; /* a CGM enumerative */
405 const char *type_string; /* its string representation, for cleartext */
406 const char *tail; /* the `designation sequence tail' */
407 }
408 plCGMCharset;
409
410 static const plCGMCharset _iso_latin_1_cgm_charset[2] =
411 {
412 { 0, "std94", "4/2" }, /* ISO 8859-1 LH, tail is "A" */
413 { 1, "std96", "4/1" } /* ISO 8859-1 RH, tail is "B" */
414 };
415
416 static const plCGMCharset _symbol_cgm_charset[2] =
417 {
418 { 0, "std94", "2/10 3/10" }, /* Symbol LH, tail is "*:" */
419 { 0, "std94", "2/6 3/10" } /* Symbol RH, tail is "&:" */
420 };
421
422 /* The private `terminate' method, which is invoked when a Plotter is
423 deleted. It may do such things as write to an output stream from
424 internal storage, deallocate storage, etc. When this is invoked,
425 _plotter points to the Plotter that is about to be deleted. */
426
427 /* This version is for CGM Plotters...
428
429 (CGM Plotters differ from most other plotters that do not plot in real
430 time in that they emit output only after all pages have pages have been
431 drawn, rather than at the end of each page. This is necessary in order
432 to produce the correct header lines.)
433
434 When this is called, the CGM code for the body of each page is stored in
435 a plOutbuf, and the page plOutbufs form a linked list. */
436
437 void
_pl_c_terminate(S___ (Plotter * _plotter))438 _pl_c_terminate (S___(Plotter *_plotter))
439 {
440 int i;
441 plOutbuf *current_page;
442 bool ps_font_used_in_doc[PL_NUM_PS_FONTS];
443 bool symbol_font_used_in_doc;
444 bool cgm_font_id_used_in_doc[PL_NUM_PS_FONTS];
445 bool doc_uses_fonts;
446 int max_cgm_font_id;
447
448 /* if no pages of graphics (i.e. Plotter was never opened), CGM file
449 won't contain any pictures, and won't satisfy any standard profile */
450 if (_plotter->data->first_page == (plOutbuf *)NULL)
451 _plotter->cgm_profile =
452 IMAX(_plotter->cgm_profile, CGM_PROFILE_NONE);
453
454 /* COMMENTED OUT BECAUSE USERS WOULD FIND THIS TOO CONFUSING! */
455 #if 0
456 /* only the binary encoding satisfies the WebCGM profile */
457 if (_plotter->cgm_encoding != CGM_ENCODING_BINARY)
458 _plotter->cgm_profile =
459 IMAX(_plotter->cgm_profile, CGM_PROFILE_MODEL);
460 #endif
461
462 #ifdef LIBPLOTTER
463 if (_plotter->data->outfp || _plotter->data->outstream)
464 #else
465 if (_plotter->data->outfp)
466 #endif
467 /* have an output stream, will emit CGM commands */
468 {
469 plOutbuf *doc_header, *doc_trailer;
470 int byte_count, data_byte_count, data_len, string_length;
471
472 doc_header = _new_outbuf ();
473
474 /* emit "BEGIN METAFILE" command */
475 {
476 const char *string_param;
477
478 string_param = "CGM plot";
479 string_length = strlen (string_param);
480 data_len = CGM_BINARY_BYTES_PER_STRING(string_length);
481 byte_count = data_byte_count = 0;
482 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
483 CGM_DELIMITER_ELEMENT, 1,
484 data_len, &byte_count,
485 "BEGMF");
486 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
487 string_param,
488 string_length, true,
489 data_len, &data_byte_count, &byte_count);
490 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
491 &byte_count);
492 }
493
494 /* emit "METAFILE VERSION" command */
495 {
496 data_len = CGM_BINARY_BYTES_PER_INTEGER;
497 byte_count = data_byte_count = 0;
498 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
499 CGM_METAFILE_DESCRIPTOR_ELEMENT, 1,
500 data_len, &byte_count,
501 "MFVERSION");
502 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
503 _plotter->cgm_version,
504 data_len, &data_byte_count, &byte_count);
505 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
506 &byte_count);
507 }
508
509 /* emit "METAFILE ELEMENT LIST" command; this is encoding-dependent */
510
511 {
512 const plCGMElementList *element_list =
513 &(_metafile_element_list[_plotter->cgm_version - 1]);
514 int length = element_list->length;
515 int k;
516
517 /* 1 integer, plus `length' pairs of 2-byte indices */
518 data_len = CGM_BINARY_BYTES_PER_INTEGER + 2 * 2 * length;
519 byte_count = data_byte_count = 0;
520 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
521 CGM_METAFILE_DESCRIPTOR_ELEMENT, 11,
522 data_len, &byte_count,
523 "MFELEMLIST");
524 switch (_plotter->cgm_encoding)
525 {
526 case CGM_ENCODING_BINARY:
527 default:
528 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
529 length,
530 data_len, &data_byte_count, &byte_count);
531 for (k = 0; k < length; k++)
532 {
533 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
534 element_list->class_id[k],
535 data_len, &data_byte_count, &byte_count);
536 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
537 element_list->element_id[k],
538 data_len, &data_byte_count, &byte_count);
539 }
540 break;
541 case CGM_ENCODING_CHARACTER: /* not supported */
542 break;
543
544 case CGM_ENCODING_CLEAR_TEXT:
545 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
546 element_list->text_string,
547 (int) strlen (element_list->text_string),
548 true,
549 data_len, &data_byte_count, &byte_count);
550 break;
551 }
552 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
553 &byte_count);
554 }
555
556 /* emit "METAFILE DESCRIPTION" command, including profile string etc. */
557 {
558 time_t clock;
559 const char *profile_string, *profile_edition_string;
560 char string_param[254];
561 struct tm *local_time_struct_ptr;
562 #ifdef HAVE_LOCALTIME_R
563 struct tm local_time_struct;
564 #endif
565
566 /* Work out ASCII specification of profile */
567 switch (_plotter->cgm_profile)
568 {
569 case CGM_PROFILE_WEB:
570 profile_string = "WebCGM";
571 profile_edition_string = "1.0";
572 break;
573 case CGM_PROFILE_MODEL:
574 profile_string = "Model-Profile";
575 profile_edition_string = "1";
576 break;
577 case CGM_PROFILE_NONE:
578 default:
579 profile_string = "None";
580 profile_edition_string = "0.0"; /* waggish */
581 break;
582 }
583
584 /* Compute an ASCII representation of the current time, in a
585 reentrant way if we're supporting pthreads (i.e. by using
586 localtime_r if it's available). */
587 time (&clock);
588
589 #ifdef PTHREAD_SUPPORT
590 #ifdef HAVE_PTHREAD_H
591 #ifdef HAVE_LOCALTIME_R
592 localtime_r (&clock, &local_time_struct);
593 local_time_struct_ptr = &local_time_struct;
594 #else
595 local_time_struct_ptr = localtime (&clock);
596 #endif
597 #else /* not HAVE_PTHREAD_H */
598 local_time_struct_ptr = localtime (&clock);
599 #endif /* not HAVE_PTHREAD_H */
600 #else /* not PTHREAD_SUPPORT */
601 local_time_struct_ptr = localtime (&clock);
602 #endif /* not PTHREAD_SUPPORT */
603
604 sprintf (string_param,
605 "\"ProfileId:%s\" \"ProfileEd:%s\" \"ColourClass:%s\" \"Source:GNU libplot %s\" \"Date:%04d%02d%02d\"",
606 profile_string, profile_edition_string,
607 _plotter->cgm_need_color ? "colour" : "monochrome",
608 PL_LIBPLOT_VER_STRING,
609 1900 + local_time_struct_ptr->tm_year,
610 1 + local_time_struct_ptr->tm_mon,
611 local_time_struct_ptr->tm_mday);
612
613 string_length = strlen (string_param);
614 data_len = CGM_BINARY_BYTES_PER_STRING(string_length);
615 byte_count = data_byte_count = 0;
616 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
617 CGM_METAFILE_DESCRIPTOR_ELEMENT, 2,
618 data_len, &byte_count,
619 "MFDESC");
620 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
621 string_param,
622 string_length, false, /* delimit by single quotes */
623 data_len, &data_byte_count, &byte_count);
624 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
625 &byte_count);
626 }
627
628 /* emit "VDC TYPE" command, selecting integer VDC's for the metafile */
629 {
630 data_len = 2; /* 2 bytes per enum */
631 byte_count = data_byte_count = 0;
632 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
633 CGM_METAFILE_DESCRIPTOR_ELEMENT, 3,
634 data_len, &byte_count,
635 "VDCTYPE");
636 _cgm_emit_enum (doc_header, false, _plotter->cgm_encoding,
637 0,
638 data_len, &data_byte_count, &byte_count,
639 "integer");
640 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
641 &byte_count);
642 }
643
644 /* Emit "INTEGER PRECISION" command. Parameters are
645 encoding-dependent: in the binary encoding, the number of bits k,
646 and in clear text, a pair of integers: the minimum and maximum
647 integers representable in CGM format, i.e. -(2^(k-1) - 1) and
648 (2^(k-1) - 1), where k=8*CGM_BINARY_BYTES_PER_INTEGER. */
649 {
650 int j, max_int;
651
652 data_len = 2; /* in binary, 16 bits of data; see comment */
653 byte_count = data_byte_count = 0;
654 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
655 CGM_METAFILE_DESCRIPTOR_ELEMENT, 4,
656 data_len, &byte_count,
657 "INTEGERPREC");
658 switch (_plotter->cgm_encoding)
659 {
660 case CGM_ENCODING_BINARY:
661 default:
662
663 /* The integer precision, in terms of bits, should be encoded
664 as an integer at the current precision (the default, which
665 is 16 bits), not the eventual precision. So we don't call
666 _cgm_emit_integer; we call _cgm_emit_index instead. We
667 always represent indices by 16 bits (the default). */
668
669 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
670 8 * CGM_BINARY_BYTES_PER_INTEGER,
671 data_len, &data_byte_count, &byte_count);
672 break;
673 case CGM_ENCODING_CHARACTER: /* not supported */
674 break;
675
676 case CGM_ENCODING_CLEAR_TEXT:
677 max_int = 0;
678 for (j = 0; j < (8 * CGM_BINARY_BYTES_PER_INTEGER - 1); j++)
679 max_int += (1 << j);
680 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
681 -max_int,
682 data_len, &data_byte_count, &byte_count);
683 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
684 max_int,
685 data_len, &data_byte_count, &byte_count);
686 break;
687 }
688 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
689 &byte_count);
690 }
691
692 /* Emit "REAL PRECISION" command, selecting default precision.
693
694 Parameters are encoding-dependent. In the clear text encoding,
695 three numbers: the minimum real, the maximum real, and the number
696 of significant decimal digits (an integer). Typical choices are
697 (-32767.0, 32767.0, 4) [the default]. In the binary encoding,
698 three objects: a 2-octet enumerative specifying the encoding of
699 reals (0=floating, 1=fixed), and two integers at current intege
700 precision specifying the size of each piece of the encoded real.
701 Typical choices are (1,16,16) [the default] or (0,9,23). */
702 {
703 data_len = 2 + 2 * CGM_BINARY_BYTES_PER_INTEGER;
704 byte_count = data_byte_count = 0;
705 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
706 CGM_METAFILE_DESCRIPTOR_ELEMENT, 5,
707 data_len, &byte_count,
708 "REALPREC");
709 switch (_plotter->cgm_encoding)
710 {
711 case CGM_ENCODING_BINARY:
712 default:
713 _cgm_emit_enum (doc_header, false, _plotter->cgm_encoding,
714 1,
715 data_len, &data_byte_count, &byte_count,
716 "DUMMY");
717 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
718 16,
719 data_len, &data_byte_count, &byte_count);
720 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
721 16,
722 data_len, &data_byte_count, &byte_count);
723 break;
724 case CGM_ENCODING_CHARACTER: /* not supported */
725 break;
726
727 case CGM_ENCODING_CLEAR_TEXT:
728 _cgm_emit_real_fixed_point (doc_header, false, _plotter->cgm_encoding,
729 -32767.0,
730 data_len, &data_byte_count, &byte_count);
731 _cgm_emit_real_fixed_point (doc_header, false, _plotter->cgm_encoding,
732 32767.0,
733 data_len, &data_byte_count, &byte_count);
734 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
735 4,
736 data_len, &data_byte_count, &byte_count);
737 break;
738 }
739 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
740 &byte_count);
741 }
742
743 /* Emit "COLOR PRECISION" command. Parameters are
744 encoding-dependent: in the binary encoding, an integer specifying
745 the number of bits k, and in clear text, the maximum possible
746 color component value, i.e. (2^k - 1), where
747 k=8*CGM_BINARY_BYTES_PER_COLOR_COMPONENT. */
748 {
749 int j;
750 unsigned int max_component;
751
752 data_len = CGM_BINARY_BYTES_PER_INTEGER;
753 byte_count = data_byte_count = 0;
754 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
755 CGM_METAFILE_DESCRIPTOR_ELEMENT, 7,
756 data_len, &byte_count,
757 "COLRPREC");
758 switch (_plotter->cgm_encoding)
759 {
760 case CGM_ENCODING_BINARY:
761 default:
762 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
763 8 * CGM_BINARY_BYTES_PER_COLOR_COMPONENT,
764 data_len, &data_byte_count, &byte_count);
765 break;
766 case CGM_ENCODING_CHARACTER: /* not supported */
767 break;
768
769 case CGM_ENCODING_CLEAR_TEXT:
770 max_component = 0;
771 for (j = 0; j < (8 * CGM_BINARY_BYTES_PER_COLOR_COMPONENT); j++)
772 max_component += (1 << j);
773 _cgm_emit_unsigned_integer (doc_header, false, _plotter->cgm_encoding,
774 max_component,
775 data_len, &data_byte_count, &byte_count);
776 break;
777 }
778 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
779 &byte_count);
780 }
781
782 /* emit "COLOR VALUE EXTENT" command, duplicating the information
783 we just supplied (this is necessary) */
784 {
785 int j;
786 unsigned int max_component;
787
788 data_len = 6 * CGM_BINARY_BYTES_PER_COLOR_COMPONENT;
789 byte_count = data_byte_count = 0;
790 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
791 CGM_METAFILE_DESCRIPTOR_ELEMENT, 10,
792 data_len, &byte_count,
793 "COLRVALUEEXT");
794 _cgm_emit_color_component (doc_header, false, _plotter->cgm_encoding,
795 (unsigned int)0,
796 data_len, &data_byte_count, &byte_count);
797 _cgm_emit_color_component (doc_header, false, _plotter->cgm_encoding,
798 (unsigned int)0,
799 data_len, &data_byte_count, &byte_count);
800 _cgm_emit_color_component (doc_header, false, _plotter->cgm_encoding,
801 (unsigned int)0,
802 data_len, &data_byte_count, &byte_count);
803 max_component = 0;
804 for (j = 0; j < (8 * CGM_BINARY_BYTES_PER_COLOR_COMPONENT); j++)
805 max_component += (1 << j);
806
807 _cgm_emit_color_component (doc_header, false, _plotter->cgm_encoding,
808 max_component,
809 data_len, &data_byte_count, &byte_count);
810 _cgm_emit_color_component (doc_header, false, _plotter->cgm_encoding,
811 max_component,
812 data_len, &data_byte_count, &byte_count);
813 _cgm_emit_color_component (doc_header, false, _plotter->cgm_encoding,
814 max_component,
815 data_len, &data_byte_count, &byte_count);
816 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
817 &byte_count);
818 }
819
820 /* determine fonts needed by document, by examining all pages */
821 {
822 current_page = _plotter->data->first_page;
823
824 for (i = 0; i < PL_NUM_PS_FONTS; i++)
825 ps_font_used_in_doc[i] = false;
826 while (current_page)
827 {
828 for (i = 0; i < PL_NUM_PS_FONTS; i++)
829 if (current_page->ps_font_used[i])
830 ps_font_used_in_doc[i] = true;
831 current_page = current_page->next;
832 }
833 }
834
835 /* Map our internal indexing of PS fonts to the indexing we use in a
836 CGM file (which may be different, because we want the traditional
837 `Adobe 13' to come first, out of the `Adobe 35'). Also work out
838 whether Symbol font, which has its own character sets, is used. */
839 symbol_font_used_in_doc = false;
840 for (i = 0; i < PL_NUM_PS_FONTS; i++)
841 {
842 cgm_font_id_used_in_doc[_pl_g_ps_font_to_cgm_font_id[i]] = ps_font_used_in_doc[i];
843 if (ps_font_used_in_doc[i]
844 && strcmp (_pl_g_ps_font_info[i].ps_name, "Symbol") == 0)
845 symbol_font_used_in_doc = true;
846 }
847
848 /* compute maximum used font id, if any */
849 max_cgm_font_id = 0;
850 doc_uses_fonts = false;
851 for (i = 0; i < PL_NUM_PS_FONTS; i++)
852 {
853 if (cgm_font_id_used_in_doc[i] == true)
854 {
855 doc_uses_fonts = true;
856 max_cgm_font_id = i;
857 }
858 }
859
860 if (doc_uses_fonts)
861 {
862 /* emit "FONT LIST" command */
863
864 /* command will include encoded strings, which are the names of
865 fonts in range 0..max_cgm_font_id; later in the CGM file,
866 they'll be referred to as 1..max_cgm_font_id+1 */
867 data_len = 0;
868 for (i = 0; i <= max_cgm_font_id; i++)
869 {
870 int ps_font_index;
871 int font_name_length, encoded_font_name_length;
872
873 ps_font_index = _pl_g_cgm_font_id_to_ps_font[i];
874 font_name_length = (int) strlen (_pl_g_ps_font_info[ps_font_index].ps_name);
875 encoded_font_name_length =
876 CGM_BINARY_BYTES_PER_STRING(font_name_length);
877 data_len += encoded_font_name_length;
878 }
879 byte_count = data_byte_count = 0;
880
881 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
882 CGM_METAFILE_DESCRIPTOR_ELEMENT, 13,
883 data_len, &byte_count,
884 "FONTLIST");
885 for (i = 0; i <= max_cgm_font_id; i++)
886 {
887 int ps_font_index;
888
889 ps_font_index = _pl_g_cgm_font_id_to_ps_font[i];
890 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
891 _pl_g_ps_font_info[ps_font_index].ps_name,
892 (int) strlen (_pl_g_ps_font_info[ps_font_index].ps_name),
893 true,
894 data_len, &data_byte_count, &byte_count);
895 }
896 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
897 &byte_count);
898
899 if (_plotter->cgm_version >= 3)
900 /* emit version-3 "FONT PROPERTIES" commands; note that if
901 fonts are used and CGM_MAX_VERSION is >=3, then cgm_version
902 was previously bumped up to 3 in c_closepl.c */
903 {
904 /* For each font in the font list, we specify 7 properties.
905 Each "FONT PROPERTIES" command refers to a single font.
906 Its argument list is a sequence of 3-tuples, each being of
907 the form (property type [an index], priority [an integer],
908 value), where `value' is an SDR (structured data record).
909 One of the supported property types is
910 CGM_FONT_PROP_INDEX, the value of which is an index into
911 the font list. For any invocation of the command, this
912 property type and its value must be supplied.
913
914 An SDR is a string-encoded structure, and each `run' of a
915 single CGM datatype within an SDR is encoded as (A) an
916 identifier for the datatype [an index], (B) a count of the
917 number of occurrences [an integer], and (C) the
918 occurrences of the datatype, themselves. So in the binary
919 encoding, bytes per SDR equals
920 2 + bytes_per_integer + data_bytes, since we always encode
921 CGM indices as 2 bytes.
922
923 The only SDR's that occur in this context are
924 (1) single CGM indices [used for 5 of the 7 font properties],
925 (2) single CGM strings [used for the `family' property], and
926 (3) three 8-bit unsigned integers [used for the font's
927 `design group'].
928
929 Because we always encode CGM indices as 2 bytes, bytes
930 per SDR, in the binary encoding, in these 3 cases are:
931 (1) 1+ CGM_BINARY_BYTES_PER_INTEGER + 4,
932 (2) 1+ CGM_BINARY_BYTES_PER_INTEGER + 2 + CGM_BYTES_PER_STRING
933 (3) 1+ CGM_BINARY_BYTES_PER_INTEGER + 5.
934 (This takes account of the initial byte used for the
935 string encoding of the SDR.)
936
937 And bytes per 3-tuple in these three cases are:
938 (1) 2*CGM_BINARY_BYTES_PER_INTEGER + 7,
939 (2) 2*CGM_BINARY_BYTES_PER_INTEGER + 5 + CGM_BYTES_PER_STRING
940 (3) 2*CGM_BINARY_BYTES_PER_INTEGER + 8.
941 Since for every included font, we emit 5 3-tuples of type 1,
942 1 of type 2, and 1 of type 3, bytes per emitted font equals
943 14*CGM_BINARY_BYTES_PER_INTEGER + 48 + CGM_BYTES_PER_STRING().
944
945 In the binary encoding, this is the length, in bytes, of
946 the argument list of each "FONT PROPERTIES" command. Here
947 CGM_BYTES_PER_STRING() stands for the string-encoded
948 length of the family name of the font. */
949
950 for (i = 0; i <= max_cgm_font_id; i++)
951 {
952 int family_length;
953 plOutbuf *sdr_buffer;
954
955 family_length = strlen(_pl_g_cgm_font_properties[i].family);
956 data_len = (14 * CGM_BINARY_BYTES_PER_INTEGER
957 + 48 /* hardcoded constants; see above */
958 + CGM_BINARY_BYTES_PER_STRING(family_length));
959 byte_count = data_byte_count = 0;
960
961 sdr_buffer = _new_outbuf ();
962 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
963 CGM_METAFILE_DESCRIPTOR_ELEMENT, 21,
964 data_len, &byte_count,
965 "FONTPROP");
966
967 /* now emit a sequence of 3-tuples: (index, integer, SDR);
968 for each 2nd element (a priority), we just specify `1' */
969
970 /* specify index of font in table (beginning with 1, not
971 with 0) */
972 {
973 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
974 CGM_FONT_PROP_INDEX,
975 data_len, &data_byte_count, &byte_count);
976 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
977 1, /* priority */
978 data_len, &data_byte_count, &byte_count);
979 build_sdr_from_index (sdr_buffer, _plotter->cgm_encoding,
980 i + 1); /* add 1 to index */
981 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
982 sdr_buffer->base,
983 (int)(sdr_buffer->contents),
984 false,
985 data_len, &data_byte_count, &byte_count);
986 _reset_outbuf (sdr_buffer);
987 }
988
989 /* specify font family */
990 {
991 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
992 CGM_FONT_PROP_FAMILY,
993 data_len, &data_byte_count, &byte_count);
994 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
995 1,
996 data_len, &data_byte_count, &byte_count);
997 build_sdr_from_string (sdr_buffer, _plotter->cgm_encoding,
998 _pl_g_cgm_font_properties[i].family,
999 (int)(strlen (_pl_g_cgm_font_properties[i].family)),
1000 true); /* use double quotes */
1001 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1002 sdr_buffer->base,
1003 (int)(sdr_buffer->contents),
1004 false,
1005 data_len, &data_byte_count, &byte_count);
1006 _reset_outbuf (sdr_buffer);
1007 }
1008
1009 /* specify font posture */
1010 {
1011 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
1012 CGM_FONT_PROP_POSTURE,
1013 data_len, &data_byte_count, &byte_count);
1014 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
1015 1,
1016 data_len, &data_byte_count, &byte_count);
1017 build_sdr_from_index (sdr_buffer, _plotter->cgm_encoding,
1018 _pl_g_cgm_font_properties[i].posture);
1019 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1020 sdr_buffer->base,
1021 (int)(sdr_buffer->contents),
1022 false,
1023 data_len, &data_byte_count, &byte_count);
1024 _reset_outbuf (sdr_buffer);
1025 }
1026
1027 /* specify font weight */
1028 {
1029 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
1030 CGM_FONT_PROP_WEIGHT,
1031 data_len, &data_byte_count, &byte_count);
1032 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
1033 1,
1034 data_len, &data_byte_count, &byte_count);
1035 build_sdr_from_index (sdr_buffer, _plotter->cgm_encoding,
1036 _pl_g_cgm_font_properties[i].weight);
1037 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1038 sdr_buffer->base,
1039 (int)(sdr_buffer->contents),
1040 false,
1041 data_len, &data_byte_count, &byte_count);
1042 _reset_outbuf (sdr_buffer);
1043 }
1044
1045 /* specify font width */
1046 {
1047 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
1048 CGM_FONT_PROP_WIDTH,
1049 data_len, &data_byte_count, &byte_count);
1050 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
1051 1,
1052 data_len, &data_byte_count, &byte_count);
1053 build_sdr_from_index (sdr_buffer, _plotter->cgm_encoding,
1054 _pl_g_cgm_font_properties[i].proportionate_width);
1055 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1056 sdr_buffer->base,
1057 (int)(sdr_buffer->contents),
1058 false,
1059 data_len, &data_byte_count, &byte_count);
1060 _reset_outbuf (sdr_buffer);
1061 }
1062
1063 /* specify font design group */
1064 {
1065 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
1066 CGM_FONT_PROP_DESIGN_GROUP,
1067 data_len, &data_byte_count, &byte_count);
1068 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
1069 1,
1070 data_len, &data_byte_count, &byte_count);
1071 build_sdr_from_ui8s (sdr_buffer, _plotter->cgm_encoding,
1072 _pl_g_cgm_font_properties[i].design_group,
1073 3);
1074 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1075 sdr_buffer->base,
1076 (int)(sdr_buffer->contents),
1077 false,
1078 data_len, &data_byte_count, &byte_count);
1079 _reset_outbuf (sdr_buffer);
1080 }
1081
1082 /* specify font structure */
1083 {
1084 _cgm_emit_index (doc_header, false, _plotter->cgm_encoding,
1085 CGM_FONT_PROP_STRUCTURE,
1086 data_len, &data_byte_count, &byte_count);
1087 _cgm_emit_integer (doc_header, false, _plotter->cgm_encoding,
1088 1,
1089 data_len, &data_byte_count, &byte_count);
1090 build_sdr_from_index (sdr_buffer, _plotter->cgm_encoding,
1091 _pl_g_cgm_font_properties[i].structure);
1092 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1093 sdr_buffer->base,
1094 (int)(sdr_buffer->contents),
1095 false,
1096 data_len, &data_byte_count, &byte_count);
1097 _reset_outbuf (sdr_buffer);
1098 }
1099
1100 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
1101 &byte_count);
1102 _delete_outbuf (sdr_buffer);
1103 }
1104 }
1105
1106 /* Emit a "CHARACTER SET LIST" command. Argument list is a
1107 sequence of character sets, with each character set being
1108 expressed both as a CGM enumerative and a CGM string (the
1109 `designation sequence tail').
1110
1111 We include the 2 character sets used in the 8-bit ISO-Latin-1
1112 encoding, and, if we're using the Symbol font, the two
1113 character sets that Symbol uses, also. So internally, we
1114 index these character sets by 1,2,3,4 (the latter two may not
1115 be present). */
1116
1117 data_len = 0;
1118 for (i = 0; i < 2; i++)
1119 {
1120 int tail_length, encoded_tail_length;
1121
1122 data_len += 2; /* 2 bytes per enum */
1123 tail_length = strlen (_iso_latin_1_cgm_charset[i].tail);
1124 encoded_tail_length =
1125 CGM_BINARY_BYTES_PER_STRING(tail_length);
1126 data_len += encoded_tail_length;
1127 }
1128 if (symbol_font_used_in_doc)
1129 for (i = 0; i < 2; i++)
1130 {
1131 int tail_length, encoded_tail_length;
1132
1133 data_len += 2; /* 2 bytes per enum */
1134 tail_length = (int) strlen (_symbol_cgm_charset[i].tail);
1135 encoded_tail_length =
1136 CGM_BINARY_BYTES_PER_STRING(tail_length);
1137 data_len += encoded_tail_length;
1138 }
1139 byte_count = data_byte_count = 0;
1140
1141 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
1142 CGM_METAFILE_DESCRIPTOR_ELEMENT, 14,
1143 data_len, &byte_count,
1144 "CHARSETLIST");
1145 for (i = 0; i < 2; i++)
1146 {
1147 _cgm_emit_enum (doc_header, false, _plotter->cgm_encoding,
1148 _iso_latin_1_cgm_charset[i].type,
1149 data_len, &data_byte_count, &byte_count,
1150 _iso_latin_1_cgm_charset[i].type_string);
1151 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1152 _iso_latin_1_cgm_charset[i].tail,
1153 (int) strlen (_iso_latin_1_cgm_charset[i].tail),
1154 true,
1155 data_len, &data_byte_count, &byte_count);
1156 }
1157 if (symbol_font_used_in_doc)
1158 for (i = 0; i < 2; i++)
1159 {
1160 _cgm_emit_enum (doc_header, false, _plotter->cgm_encoding,
1161 _symbol_cgm_charset[i].type,
1162 data_len, &data_byte_count, &byte_count,
1163 _symbol_cgm_charset[i].type_string);
1164 _cgm_emit_string (doc_header, false, _plotter->cgm_encoding,
1165 _symbol_cgm_charset[i].tail,
1166 (int) strlen (_symbol_cgm_charset[i].tail),
1167 true,
1168 data_len, &data_byte_count, &byte_count);
1169 }
1170 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
1171 &byte_count);
1172 }
1173
1174 /* emit "CHARACTER CODING ANNOUNCER" command, selecting 8-bit
1175 character codes (no switching between font halves for us!) */
1176 {
1177 data_len = 2; /* 2 bytes per enum */
1178 byte_count = data_byte_count = 0;
1179 _cgm_emit_command_header (doc_header, _plotter->cgm_encoding,
1180 CGM_METAFILE_DESCRIPTOR_ELEMENT, 15,
1181 data_len, &byte_count,
1182 "CHARCODING");
1183 _cgm_emit_enum (doc_header, false, _plotter->cgm_encoding,
1184 1,
1185 data_len, &data_byte_count, &byte_count,
1186 "basic8bit");
1187 _cgm_emit_command_terminator (doc_header, _plotter->cgm_encoding,
1188 &byte_count);
1189 }
1190
1191 /* WRITE DOCUMENT HEADER */
1192 _write_bytes (_plotter->data,
1193 (int)(doc_header->contents),
1194 (unsigned char *)doc_header->base);
1195 _delete_outbuf (doc_header);
1196
1197 /* loop over plOutbufs in which successive pages of graphics are
1198 stored; emit each page as a CGM picture, and delete each plOutbuf
1199 as we finish with it */
1200 current_page = _plotter->data->first_page;
1201 i = 1;
1202
1203 while (current_page)
1204 {
1205 plOutbuf *next_page;
1206 plOutbuf *current_page_header, *current_page_trailer;
1207
1208 /* prepare a page header */
1209
1210 current_page_header = _new_outbuf ();
1211
1212 /* emit "BEGIN PICTURE" command */
1213 {
1214 char picture[32];
1215 const char *string_param;
1216
1217 sprintf (picture, "picture_%d", i);
1218 string_param = picture;
1219 string_length = strlen (string_param);
1220 data_len = CGM_BINARY_BYTES_PER_STRING(string_length);
1221 byte_count = data_byte_count = 0;
1222 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1223 CGM_DELIMITER_ELEMENT, 3,
1224 data_len, &byte_count,
1225 "BEGPIC");
1226 _cgm_emit_string (current_page_header, false, _plotter->cgm_encoding,
1227 string_param,
1228 string_length,
1229 true,
1230 data_len, &data_byte_count, &byte_count);
1231 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1232 &byte_count);
1233 }
1234
1235 /* emit "VDC EXTENT" command [specify virtual device coor ranges] */
1236 {
1237 int imin_true, imax_true, jmin_true, jmax_true;
1238
1239 data_len = 2 * 2 * 2;
1240 byte_count = data_byte_count = 0;
1241 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1242 CGM_PICTURE_DESCRIPTOR_ELEMENT, 6,
1243 data_len, &byte_count,
1244 "VDCEXT");
1245
1246 /* To see how we set extent values, see the initialize()
1247 routine. In that routine, we choose device-coordinates
1248 ranges imin,imax,jmin,jmax so that the length of the longer
1249 side of the viewport is one-fourth the maximum integer
1250 range. The other side will be reduced if the user specifies
1251 (via PAGESIZE) an aspect ratio other than 1:1. With this
1252 scheme, if the user specifies xsize=ysize > 0, the same
1253 user->device coordinate map will result, no matter what
1254 xsize and ysize equal.
1255
1256 However, if the user specifies (via PAGESIZE) a negative
1257 xsize or ysize, we flip the sign of imax-imin or jmax-jmin,
1258 thereby greatly modifying the user->device coordinate map.
1259 Which means we must flip it back, right here, before
1260 emitting the VDC extents. The reason for this sign-flipping
1261 is that we don't trust CGM viewers to handle negative VDC
1262 extents. */
1263
1264 if (_plotter->data->imax < _plotter->data->imin)
1265 {
1266 imin_true = _plotter->data->imax;
1267 imax_true = _plotter->data->imin;
1268 }
1269 else
1270 {
1271 imin_true = _plotter->data->imin;
1272 imax_true = _plotter->data->imax;
1273 }
1274
1275 if (_plotter->data->jmax < _plotter->data->jmin)
1276 {
1277 jmin_true = _plotter->data->jmax;
1278 jmax_true = _plotter->data->jmin;
1279 }
1280 else
1281 {
1282 jmin_true = _plotter->data->jmin;
1283 jmax_true = _plotter->data->jmax;
1284 }
1285
1286 /* In binary, we write each of these four coordinates as a
1287 16-bit `index' i.e. integer, because we haven't yet changed
1288 the VDC integer precision to our desired value (we can't do
1289 that until the beginning of the picture). */
1290 _cgm_emit_index (current_page_header, false, _plotter->cgm_encoding,
1291 imin_true,
1292 data_len, &data_byte_count, &byte_count);
1293 _cgm_emit_index (current_page_header, false, _plotter->cgm_encoding,
1294 jmin_true,
1295 data_len, &data_byte_count, &byte_count);
1296 _cgm_emit_index (current_page_header, false, _plotter->cgm_encoding,
1297 imax_true,
1298 data_len, &data_byte_count, &byte_count);
1299 _cgm_emit_index (current_page_header, false, _plotter->cgm_encoding,
1300 jmax_true,
1301 data_len, &data_byte_count, &byte_count);
1302 _cgm_emit_command_terminator (current_page_header,
1303 _plotter->cgm_encoding,
1304 &byte_count);
1305 }
1306
1307 /* emit "SCALING MODE" command. Specify metric scaling (required
1308 by WebCGM profile). The argument is the number of millimeters
1309 per VDC unit; it must be a floating-point real. */
1310 {
1311 int irange, jrange;
1312 double scaling_factor;
1313
1314 data_len = 6; /* 2 bytes per enum, 4 per floating-pt. real */
1315 byte_count = data_byte_count = 0;
1316 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1317 CGM_PICTURE_DESCRIPTOR_ELEMENT, 1,
1318 data_len, &byte_count,
1319 "SCALEMODE");
1320 _cgm_emit_enum (current_page_header, false, _plotter->cgm_encoding,
1321 1,
1322 data_len, &data_byte_count, &byte_count,
1323 "metric");
1324
1325 /* Compute a metric scaling factor from the criterion that the
1326 nominal physical width and height of VDC space be the
1327 viewport xsize and ysize, as determined by the PAGESIZE
1328 parameter.
1329
1330 We can get this scaling factor easily, by computing a
1331 quotient, because our scheme for setting imin,imax,jmin,jmax
1332 in the initialize() method preserves aspect ratio, and
1333 signs, as well (see comment immediately above). But we must
1334 be careful not to divide by zero, since zero-width and
1335 zero-height viewports are allowed. */
1336
1337 irange = _plotter->data->imax - _plotter->data->imin;
1338 jrange = _plotter->data->jmax - _plotter->data->jmin;
1339 if (irange != 0)
1340 scaling_factor =
1341 (25.4 * _plotter->data->viewport_xsize) / irange;
1342 else if (jrange != 0)
1343 scaling_factor =
1344 (25.4 * _plotter->data->viewport_ysize) / jrange;
1345 else
1346 /* degenerate case, viewport has zero size */
1347 scaling_factor = 0.0;
1348
1349 /* yes, this needs to be a floating-point real, not fixed-point! */
1350 _cgm_emit_real_floating_point (current_page_header, false, _plotter->cgm_encoding,
1351 scaling_factor,
1352 data_len, &data_byte_count, &byte_count);
1353 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1354 &byte_count);
1355 }
1356
1357 /* emit "LINE WIDTH SPECIFICATION MODE" command [specify
1358 absolute coordinates] */
1359 {
1360 data_len = 2; /* 2 bytes per enum */
1361 byte_count = data_byte_count = 0;
1362 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1363 CGM_PICTURE_DESCRIPTOR_ELEMENT, 3,
1364 data_len, &byte_count,
1365 "LINEWIDTHMODE");
1366 _cgm_emit_enum (current_page_header, false, _plotter->cgm_encoding,
1367 0,
1368 data_len, &data_byte_count, &byte_count,
1369 "abs");
1370 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1371 &byte_count);
1372 }
1373
1374 /* emit "EDGE WIDTH SPECIFICATION MODE" command [specify absolute
1375 coordinates] */
1376 {
1377 data_len = 2; /* 2 bytes per enum */
1378 byte_count = data_byte_count = 0;
1379 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1380 CGM_PICTURE_DESCRIPTOR_ELEMENT, 5,
1381 data_len, &byte_count,
1382 "EDGEWIDTHMODE");
1383 _cgm_emit_enum (current_page_header, false, _plotter->cgm_encoding,
1384 0,
1385 data_len, &data_byte_count, &byte_count,
1386 "abs");
1387 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1388 &byte_count);
1389 }
1390
1391 /* emit "MARKER SIZE SPECIFICATION MODE" command [specify
1392 absolute coordinates] */
1393 {
1394 data_len = 2; /* 2 bytes per enum */
1395 byte_count = data_byte_count = 0;
1396 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1397 CGM_PICTURE_DESCRIPTOR_ELEMENT, 4,
1398 data_len, &byte_count,
1399 "MARKERSIZEMODE");
1400 _cgm_emit_enum (current_page_header, false, _plotter->cgm_encoding,
1401 0,
1402 data_len, &data_byte_count, &byte_count,
1403 "abs");
1404 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1405 &byte_count);
1406 }
1407
1408 /* emit "COLOR SELECTION MODE" command [specify direct color,
1409 not indexed color] */
1410 {
1411 data_len = 2; /* 2 bytes per enum */
1412 byte_count = data_byte_count = 0;
1413 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1414 CGM_PICTURE_DESCRIPTOR_ELEMENT, 2,
1415 data_len, &byte_count,
1416 "COLRMODE");
1417 _cgm_emit_enum (current_page_header, false, _plotter->cgm_encoding,
1418 1,
1419 data_len, &data_byte_count, &byte_count,
1420 "direct");
1421 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1422 &byte_count);
1423 }
1424
1425 if (current_page->bg_color_suppressed == false)
1426 /* user didn't specify "none" as background color, so emit
1427 "BACKGROUND COLOR" command. (Note that in a CGM file,
1428 background color is always a direct color specified by color
1429 components, never an indexed color.) The background color
1430 for any page is stored in the `bg_color' element of its
1431 plOutbuf at the time the page is closed; see g_closepl.c. */
1432 {
1433 data_len = 3 * CGM_BINARY_BYTES_PER_COLOR_COMPONENT;
1434 byte_count = data_byte_count = 0;
1435 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1436 CGM_PICTURE_DESCRIPTOR_ELEMENT, 7,
1437 data_len, &byte_count,
1438 "BACKCOLR");
1439 _cgm_emit_color_component (current_page_header, false, _plotter->cgm_encoding,
1440 (unsigned int)current_page->bg_color.red,
1441 data_len, &data_byte_count, &byte_count);
1442 _cgm_emit_color_component (current_page_header, false, _plotter->cgm_encoding,
1443 (unsigned int)current_page->bg_color.green,
1444 data_len, &data_byte_count, &byte_count);
1445 _cgm_emit_color_component (current_page_header, false, _plotter->cgm_encoding,
1446 (unsigned int)current_page->bg_color.blue,
1447 data_len, &data_byte_count, &byte_count);
1448 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1449 &byte_count);
1450 }
1451
1452 /* if user defined any line types, emit a sequence of "LINE AND
1453 EDGE TYPE DEFINITION" commands */
1454 {
1455 plCGMCustomLineType *linetype_ptr = (plCGMCustomLineType *)current_page->extra;
1456 int linetype = 0;
1457
1458 while (linetype_ptr)
1459 {
1460 int k, cycle_length, dash_array_len, *dash_array;
1461
1462 linetype--; /* user-defined ones are -1,-2,-3,... */
1463 dash_array_len = linetype_ptr->dash_array_len;
1464 dash_array = linetype_ptr->dashes;
1465 cycle_length = 0;
1466 for (k = 0; k < dash_array_len; k++)
1467 cycle_length += dash_array[k];
1468
1469 /* data: a 2-byte index, the cycle length, and the array of
1470 dash lengths (all integers) */
1471 data_len = 2 + (1 + dash_array_len) * CGM_BINARY_BYTES_PER_INTEGER;
1472 byte_count = data_byte_count = 0;
1473 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1474 CGM_PICTURE_DESCRIPTOR_ELEMENT, 17,
1475 data_len, &byte_count,
1476 "LINEEDGETYPEDEF");
1477 _cgm_emit_index (current_page_header, false, _plotter->cgm_encoding,
1478 linetype,
1479 data_len, &data_byte_count, &byte_count);
1480 _cgm_emit_integer (current_page_header, false, _plotter->cgm_encoding,
1481 cycle_length,
1482 data_len, &data_byte_count, &byte_count);
1483 for (k = 0; k < dash_array_len; k++)
1484 _cgm_emit_integer (current_page_header, false, _plotter->cgm_encoding,
1485 dash_array[k],
1486 data_len, &data_byte_count, &byte_count);
1487 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1488 &byte_count);
1489
1490 /* on to next user-defined line type */
1491 linetype_ptr = linetype_ptr->next;
1492 }
1493 }
1494
1495 /* emit "BEGIN PICTURE BODY" command */
1496 {
1497 data_len = 0;
1498 byte_count = data_byte_count = 0;
1499 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1500 CGM_DELIMITER_ELEMENT, 4,
1501 data_len, &byte_count,
1502 "BEGPICBODY");
1503 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1504 &byte_count);
1505 }
1506
1507 /* Emit "VDC INTEGER PRECISION" command. Very similar to the
1508 "INTEGER PRECISION" command, except we emit this at the start
1509 of each picture. */
1510 {
1511 int j, max_int;
1512
1513 data_len = CGM_BINARY_BYTES_PER_INTEGER;
1514 byte_count = data_byte_count = 0;
1515 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1516 CGM_CONTROL_ELEMENT, 1,
1517 data_len, &byte_count,
1518 "VDCINTEGERPREC");
1519 switch (_plotter->cgm_encoding)
1520 {
1521 case CGM_ENCODING_BINARY:
1522 default:
1523 _cgm_emit_integer (current_page_header, false, _plotter->cgm_encoding,
1524 8 * CGM_BINARY_BYTES_PER_INTEGER,
1525 data_len, &data_byte_count, &byte_count);
1526 break;
1527 case CGM_ENCODING_CHARACTER: /* not supported */
1528 break;
1529
1530 case CGM_ENCODING_CLEAR_TEXT:
1531 max_int = 0;
1532 for (j = 0; j < (8 * CGM_BINARY_BYTES_PER_INTEGER - 1); j++)
1533 max_int += (1 << j);
1534 _cgm_emit_integer (current_page_header, false, _plotter->cgm_encoding,
1535 -max_int,
1536 data_len, &data_byte_count, &byte_count);
1537 _cgm_emit_integer (current_page_header, false, _plotter->cgm_encoding,
1538 max_int,
1539 data_len, &data_byte_count, &byte_count);
1540 break;
1541 }
1542 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1543 &byte_count);
1544 }
1545
1546 if (doc_uses_fonts)
1547 /* emit "TEXT PRECISION" command */
1548 {
1549 data_len = 2; /* 2 bytes per enum */
1550 byte_count = data_byte_count = 0;
1551 _cgm_emit_command_header (current_page_header, _plotter->cgm_encoding,
1552 CGM_ATTRIBUTE_ELEMENT, 11,
1553 data_len, &byte_count,
1554 "TEXTPREC");
1555 _cgm_emit_enum (current_page_header, false, _plotter->cgm_encoding,
1556 2,
1557 data_len, &data_byte_count, &byte_count,
1558 "stroke");
1559 _cgm_emit_command_terminator (current_page_header, _plotter->cgm_encoding,
1560 &byte_count);
1561 }
1562
1563 /* write the page header */
1564 _write_bytes (_plotter->data,
1565 (int)(current_page_header->contents),
1566 (unsigned char *)current_page_header->base);
1567 _delete_outbuf (current_page_header);
1568
1569 /* WRITE THE PICTURE */
1570 _write_bytes (_plotter->data,
1571 (int)(current_page->contents),
1572 (unsigned char *)current_page->base);
1573
1574 /* prepare a page trailer */
1575
1576 current_page_trailer = _new_outbuf ();
1577
1578 /* emit "END PICTURE" command (no parameters) */
1579 {
1580 data_len = 0;
1581 byte_count = data_byte_count = 0;
1582 _cgm_emit_command_header (current_page_trailer, _plotter->cgm_encoding,
1583 CGM_DELIMITER_ELEMENT, 5,
1584 data_len, &byte_count,
1585 "ENDPIC");
1586 _cgm_emit_command_terminator (current_page_trailer, _plotter->cgm_encoding,
1587 &byte_count);
1588 }
1589
1590 /* write page trailer */
1591 _write_bytes (_plotter->data,
1592 (int)(current_page_trailer->contents),
1593 (unsigned char *)current_page_trailer->base);
1594 _delete_outbuf (current_page_trailer);
1595
1596 /* on to next page (if any) */
1597 next_page = current_page->next;
1598 current_page = next_page;
1599 i++;
1600 }
1601
1602 /* prepare a document trailer */
1603
1604 doc_trailer = _new_outbuf ();
1605
1606 /* emit "END METAFILE" command (no parameters) */
1607 {
1608 data_len = 0;
1609 byte_count = data_byte_count = 0;
1610 _cgm_emit_command_header (doc_trailer, _plotter->cgm_encoding,
1611 CGM_DELIMITER_ELEMENT, 2,
1612 data_len, &byte_count,
1613 "ENDMF");
1614 _cgm_emit_command_terminator (doc_trailer, _plotter->cgm_encoding,
1615 &byte_count);
1616 }
1617
1618 /* WRITE DOCUMENT TRAILER */
1619 _write_bytes (_plotter->data,
1620 (int)(doc_trailer->contents),
1621 (unsigned char *)doc_trailer->base);
1622 _delete_outbuf (doc_trailer);
1623
1624 }
1625
1626 /* delete all plOutbufs in which document pages are stored */
1627 current_page = _plotter->data->first_page;
1628 while (current_page)
1629 {
1630 plOutbuf *next_page;
1631
1632 next_page = current_page->next;
1633
1634 /* deallocate page-specific table of user-specified line types,
1635 if any */
1636 if (current_page->extra)
1637 {
1638 plCGMCustomLineType *linetype_ptr = (plCGMCustomLineType *)current_page->extra;
1639 plCGMCustomLineType *old_linetype_ptr;
1640
1641 while (linetype_ptr)
1642 {
1643 if (linetype_ptr->dash_array_len > 0 /* paranoia */
1644 && linetype_ptr->dashes)
1645 free (linetype_ptr->dashes);
1646 old_linetype_ptr = linetype_ptr;
1647 linetype_ptr = linetype_ptr->next;
1648 free (old_linetype_ptr);
1649 }
1650 _plotter->data->page->extra = (void *)NULL;
1651 }
1652
1653 _delete_outbuf (current_page);
1654 current_page = next_page;
1655 }
1656
1657 /* flush output stream if any */
1658 if (_plotter->data->outfp)
1659 {
1660 if (fflush(_plotter->data->outfp) < 0
1661 #ifdef MSDOS
1662 /* data can be caught in DOS buffers, so do an fsync() too */
1663 || fsync (_plotter->data->outfp) < 0
1664 #endif
1665 )
1666 _plotter->error (R___(_plotter) "the output stream is jammed");
1667 }
1668 #ifdef LIBPLOTTER
1669 else if (_plotter->data->outstream)
1670 {
1671 _plotter->data->outstream->flush ();
1672 if (!(*(_plotter->data->outstream)))
1673 _plotter->error (R___(_plotter) "the output stream is jammed");
1674 }
1675 #endif
1676
1677 #ifndef LIBPLOTTER
1678 /* in libplot, manually invoke superclass termination method */
1679 _pl_g_terminate (S___(_plotter));
1680 #endif
1681 }
1682
1683 static void
build_sdr_from_index(plOutbuf * sdr_buffer,int cgm_encoding,int x)1684 build_sdr_from_index (plOutbuf *sdr_buffer, int cgm_encoding, int x)
1685 {
1686 int dummy_data_len, dummy_data_byte_count, dummy_byte_count;
1687
1688 dummy_data_len = dummy_data_byte_count = dummy_byte_count = 0;
1689 _cgm_emit_index (sdr_buffer, true, cgm_encoding,
1690 CGM_SDR_DATATYPE_INDEX,
1691 dummy_data_len, &dummy_data_byte_count,
1692 &dummy_byte_count);
1693 _cgm_emit_integer (sdr_buffer, true, cgm_encoding,
1694 1,
1695 dummy_data_len, &dummy_data_byte_count,
1696 &dummy_byte_count);
1697 _cgm_emit_index (sdr_buffer, true, cgm_encoding,
1698 x,
1699 dummy_data_len, &dummy_data_byte_count,
1700 &dummy_byte_count);
1701 }
1702
1703 static void
build_sdr_from_string(plOutbuf * sdr_buffer,int cgm_encoding,const char * s,int string_length,bool use_double_quotes)1704 build_sdr_from_string (plOutbuf *sdr_buffer, int cgm_encoding, const char *s, int string_length, bool use_double_quotes)
1705 {
1706 int dummy_data_len, dummy_data_byte_count, dummy_byte_count;
1707
1708 dummy_data_len = dummy_data_byte_count = dummy_byte_count = 0;
1709 _cgm_emit_index (sdr_buffer, true, cgm_encoding,
1710 CGM_SDR_DATATYPE_STRING_FIXED,
1711 dummy_data_len, &dummy_data_byte_count,
1712 &dummy_byte_count);
1713 _cgm_emit_integer (sdr_buffer, true, cgm_encoding,
1714 1,
1715 dummy_data_len, &dummy_data_byte_count,
1716 &dummy_byte_count);
1717 _cgm_emit_string (sdr_buffer, true, cgm_encoding,
1718 s, string_length, use_double_quotes,
1719 dummy_data_len, &dummy_data_byte_count,
1720 &dummy_byte_count);
1721 }
1722
1723 static void
build_sdr_from_ui8s(plOutbuf * sdr_buffer,int cgm_encoding,const int * x,int n)1724 build_sdr_from_ui8s (plOutbuf *sdr_buffer, int cgm_encoding, const int *x, int n)
1725 {
1726 int i, dummy_data_len, dummy_data_byte_count, dummy_byte_count;
1727
1728 dummy_data_len = dummy_data_byte_count = dummy_byte_count = 0;
1729 _cgm_emit_index (sdr_buffer, true, cgm_encoding,
1730 CGM_SDR_DATATYPE_UNSIGNED_INTEGER_8BIT,
1731 dummy_data_len, &dummy_data_byte_count,
1732 &dummy_byte_count);
1733 _cgm_emit_integer (sdr_buffer, true, cgm_encoding,
1734 n,
1735 dummy_data_len, &dummy_data_byte_count,
1736 &dummy_byte_count);
1737 for (i = 0; i < n; i++)
1738 _cgm_emit_unsigned_integer_8bit (sdr_buffer, true, cgm_encoding,
1739 (unsigned int)(x[i]),
1740 dummy_data_len, &dummy_data_byte_count,
1741 &dummy_byte_count);
1742 }
1743
1744 #ifdef LIBPLOTTER
CGMPlotter(FILE * infile,FILE * outfile,FILE * errfile)1745 CGMPlotter::CGMPlotter (FILE *infile, FILE *outfile, FILE *errfile)
1746 :Plotter (infile, outfile, errfile)
1747 {
1748 _pl_c_initialize ();
1749 }
1750
CGMPlotter(FILE * outfile)1751 CGMPlotter::CGMPlotter (FILE *outfile)
1752 :Plotter (outfile)
1753 {
1754 _pl_c_initialize ();
1755 }
1756
CGMPlotter(istream & in,ostream & out,ostream & err)1757 CGMPlotter::CGMPlotter (istream& in, ostream& out, ostream& err)
1758 : Plotter (in, out, err)
1759 {
1760 _pl_c_initialize ();
1761 }
1762
CGMPlotter(ostream & out)1763 CGMPlotter::CGMPlotter (ostream& out)
1764 : Plotter (out)
1765 {
1766 _pl_c_initialize ();
1767 }
1768
CGMPlotter()1769 CGMPlotter::CGMPlotter ()
1770 {
1771 _pl_c_initialize ();
1772 }
1773
CGMPlotter(FILE * infile,FILE * outfile,FILE * errfile,PlotterParams & parameters)1774 CGMPlotter::CGMPlotter (FILE *infile, FILE *outfile, FILE *errfile, PlotterParams ¶meters)
1775 :Plotter (infile, outfile, errfile, parameters)
1776 {
1777 _pl_c_initialize ();
1778 }
1779
CGMPlotter(FILE * outfile,PlotterParams & parameters)1780 CGMPlotter::CGMPlotter (FILE *outfile, PlotterParams ¶meters)
1781 :Plotter (outfile, parameters)
1782 {
1783 _pl_c_initialize ();
1784 }
1785
CGMPlotter(istream & in,ostream & out,ostream & err,PlotterParams & parameters)1786 CGMPlotter::CGMPlotter (istream& in, ostream& out, ostream& err, PlotterParams ¶meters)
1787 : Plotter (in, out, err, parameters)
1788 {
1789 _pl_c_initialize ();
1790 }
1791
CGMPlotter(ostream & out,PlotterParams & parameters)1792 CGMPlotter::CGMPlotter (ostream& out, PlotterParams ¶meters)
1793 : Plotter (out, parameters)
1794 {
1795 _pl_c_initialize ();
1796 }
1797
CGMPlotter(PlotterParams & parameters)1798 CGMPlotter::CGMPlotter (PlotterParams ¶meters)
1799 : Plotter (parameters)
1800 {
1801 _pl_c_initialize ();
1802 }
1803
~CGMPlotter()1804 CGMPlotter::~CGMPlotter ()
1805 {
1806 /* if luser left the Plotter open, close it */
1807 if (_plotter->data->open)
1808 _API_closepl ();
1809
1810 _pl_c_terminate ();
1811 }
1812 #endif
1813