1 /* GNUPLOT - save.c */
2 
3 /*[
4  * Copyright 1986 - 1993, 1998, 2004   Thomas Williams, Colin Kelley
5  *
6  * Permission to use, copy, and distribute this software and its
7  * documentation for any purpose with or without fee is hereby granted,
8  * provided that the above copyright notice appear in all copies and
9  * that both that copyright notice and this permission notice appear
10  * in supporting documentation.
11  *
12  * Permission to modify the software is granted, but not the right to
13  * distribute the complete modified source code.  Modifications are to
14  * be distributed as patches to the released version.  Permission to
15  * distribute binaries produced by compiling modified sources is granted,
16  * provided you
17  *   1. distribute the corresponding source modifications from the
18  *    released version in the form of a patch file along with the binaries,
19  *   2. add special version identification to distinguish your version
20  *    in addition to the base release version number,
21  *   3. provide your name and address as the primary contact for the
22  *    support of your modified version, and
23  *   4. retain our contact information in regard to use of the base
24  *    software.
25  * Permission to distribute the released version of the source code along
26  * with corresponding source modifications in the form of a patch file is
27  * granted with same provisions 2 through 4 for binary distributions.
28  *
29  * This software is provided "as is" without express or implied warranty
30  * to the extent permitted by applicable law.
31 ]*/
32 
33 #include "save.h"
34 
35 #include "command.h"
36 #include "contour.h"
37 #include "datafile.h"
38 #include "eval.h"
39 #include "fit.h"
40 #include "gp_time.h"
41 #include "graphics.h"
42 #include "hidden3d.h"
43 #include "jitter.h"
44 #include "misc.h"
45 #include "plot2d.h"
46 #include "plot3d.h"
47 #include "setshow.h"
48 #include "term_api.h"
49 #include "util.h"
50 #include "variable.h"
51 #include "pm3d.h"
52 #include "getcolor.h"
53 
54 static void save_functions__sub(FILE *);
55 static void save_variables__sub(FILE *);
56 static void save_tics(FILE *, struct axis *);
57 static void save_mtics(FILE *, struct axis *);
58 static void save_zeroaxis(FILE *,AXIS_INDEX);
59 static void save_set_all(FILE *);
60 static void save_justification(int just, FILE *fp);
61 
62 const char *coord_msg[] = {"first ", "second ", "graph ", "screen ", "character ", "polar "};
63 /*
64  *  functions corresponding to the arguments of the GNUPLOT `save` command
65  */
66 void
save_functions(FILE * fp)67 save_functions(FILE *fp)
68 {
69     /* I _love_ information written at the top and the end
70      * of a human readable ASCII file. */
71     show_version(fp);
72     save_functions__sub(fp);
73     fputs("#    EOF\n", fp);
74 }
75 
76 
77 void
save_variables(FILE * fp)78 save_variables(FILE *fp)
79 {
80 	show_version(fp);
81 	save_variables__sub(fp);
82 	fputs("#    EOF\n", fp);
83 }
84 
85 
86 void
save_set(FILE * fp)87 save_set(FILE *fp)
88 {
89 	show_version(fp);
90 	save_set_all(fp);
91 	fputs("#    EOF\n", fp);
92 }
93 
94 
95 void
save_all(FILE * fp)96 save_all(FILE *fp)
97 {
98 	show_version(fp);
99 	save_set_all(fp);
100 	save_functions__sub(fp);
101 	save_variables__sub(fp);
102 	if (df_filename)
103 	    fprintf(fp, "## Last datafile plotted: \"%s\"\n", df_filename);
104 	fprintf(fp, "%s\n", replot_line);
105 	if (wri_to_fil_last_fit_cmd(NULL)) {
106 	    fputs("## ", fp);
107 	    wri_to_fil_last_fit_cmd(fp);
108 	    putc('\n', fp);
109 	}
110 	fputs("#    EOF\n", fp);
111 }
112 
113 /*
114  *  auxiliary functions
115  */
116 
117 static void
save_functions__sub(FILE * fp)118 save_functions__sub(FILE *fp)
119 {
120     struct udft_entry *udf = first_udf;
121 
122     while (udf) {
123 	if (udf->definition) {
124 	    fprintf(fp, "%s\n", udf->definition);
125 	}
126 	udf = udf->next_udf;
127     }
128 }
129 
130 static void
save_variables__sub(FILE * fp)131 save_variables__sub(FILE *fp)
132 {
133     /* always skip pi */
134     struct udvt_entry *udv = first_udv->next_udv;
135 
136     while (udv) {
137 	if (udv->udv_value.type != NOTDEFINED) {
138 	    if ((udv->udv_value.type == ARRAY)
139 		&& strncmp(udv->udv_name,"ARGV",4)) {
140 		fprintf(fp,"array %s[%d] = ", udv->udv_name,
141 			(int)(udv->udv_value.v.value_array[0].v.int_val));
142 		save_array_content(fp, udv->udv_value.v.value_array);
143 	    } else if (strncmp(udv->udv_name,"GPVAL_",6)
144 		 && strncmp(udv->udv_name,"GPFUN_",6)
145 		 && strncmp(udv->udv_name,"MOUSE_",6)
146 		 && strncmp(udv->udv_name,"$",1)
147 		 && (strncmp(udv->udv_name,"ARG",3) || (strlen(udv->udv_name) != 4))
148 		 && strncmp(udv->udv_name,"NaN",4)) {
149 		    fprintf(fp, "%s = ", udv->udv_name);
150 		    disp_value(fp, &(udv->udv_value), TRUE);
151 		    (void) putc('\n', fp);
152 	    }
153 	}
154 	udv = udv->next_udv;
155     }
156 }
157 
158 void
save_array_content(FILE * fp,struct value * array)159 save_array_content(FILE *fp, struct value *array)
160 {
161     int i;
162     int size = array[0].v.int_val;
163     fprintf(fp, "[");
164     for (i=1; i<=size; i++) {
165 	if (array[i].type != NOTDEFINED)
166 	    disp_value(fp, &(array[i]), TRUE);
167 	if (i < size)
168 	    fprintf(fp, ",");
169     }
170     fprintf(fp, "]\n");
171 }
172 
173 /* HBB 19990823: new function 'save term'. This will be mainly useful
174  * for the typical 'set term post ... plot ... set term <normal term>
175  * sequence. It's the only 'save' function that will write the
176  * current term setting to a file uncommentedly. */
177 void
save_term(FILE * fp)178 save_term(FILE *fp)
179 {
180 	show_version(fp);
181 
182 	/* A possible gotcha: the default initialization often doesn't set
183 	 * term_options, but a 'set term <type>' without options doesn't
184 	 * reset the options to startup defaults. This may have to be
185 	 * changed on a per-terminal driver basis... */
186 	if (term)
187 	    fprintf(fp, "set terminal %s %s\n", term->name, term_options);
188 	else
189 	    fputs("set terminal unknown\n", fp);
190 
191 	/* output will still be written in commented form.  Otherwise, the
192 	 * risk of overwriting files is just too high */
193 	if (outstr)
194 	    fprintf(fp, "# set output '%s'\n", outstr);
195 	else
196 	    fputs("# set output\n", fp);
197 	fputs("#    EOF\n", fp);
198 }
199 
200 /* helper function */
201 void
save_axis_label_or_title(FILE * fp,char * name,char * suffix,struct text_label * label,TBOOLEAN savejust)202 save_axis_label_or_title(FILE *fp, char *name, char *suffix,
203 			struct text_label *label, TBOOLEAN savejust)
204 {
205     fprintf(fp, "set %s%s \"%s\" ",
206 	    name, suffix, label->text ? conv_text(label->text) : "");
207     fprintf(fp, "\nset %s%s ", name, suffix);
208     save_position(fp, &(label->offset), 3, TRUE);
209     fprintf(fp, " font \"%s\"", label->font ? conv_text(label->font) : "");
210     save_textcolor(fp, &(label->textcolor));
211     if (savejust && (label->pos != CENTRE)) save_justification(label->pos,fp);
212     if (label->tag == ROTATE_IN_3D_LABEL_TAG)
213 	fprintf(fp, " rotate parallel");
214     else if (label->rotate == TEXT_VERTICAL)
215 	fprintf(fp, " rotate");
216     else if (label->rotate)
217 	fprintf(fp, " rotate by %d", label->rotate);
218     else
219 	fprintf(fp, " norotate");
220 
221     if (label == &title && label->boxed) {
222 	fprintf(fp," boxed ");
223 	if (label->boxed > 0)
224 	    fprintf(fp,"bs %d ",label->boxed);
225     }
226     fprintf(fp, "%s\n", (label->noenhanced) ? " noenhanced" : "");
227 }
228 
229 static void
save_justification(int just,FILE * fp)230 save_justification(int just, FILE *fp)
231 {
232     switch (just) {
233 	case RIGHT:
234 	    fputs(" right", fp);
235 	    break;
236 	case LEFT:
237 	    fputs(" left", fp);
238 	    break;
239 	case CENTRE:
240 	    fputs(" center", fp);
241 	    break;
242     }
243 }
244 
245 static void
save_set_all(FILE * fp)246 save_set_all(FILE *fp)
247 {
248     struct text_label *this_label;
249     struct arrow_def *this_arrow;
250     struct linestyle_def *this_linestyle;
251     struct arrowstyle_def *this_arrowstyle;
252     legend_key *key = &keyT;
253     int axis;
254 
255     /* opinions are split as to whether we save term and outfile
256      * as a compromise, we output them as comments !
257      */
258     if (term)
259 	fprintf(fp, "# set terminal %s %s\n", term->name, term_options);
260     else
261 	fputs("# set terminal unknown\n", fp);
262 
263     if (outstr)
264 	fprintf(fp, "# set output '%s'\n", outstr);
265     else
266 	fputs("# set output\n", fp);
267 
268     fprintf(fp, "\
269 %sset clip points\n\
270 %sset clip one\n\
271 %sset clip two\n\
272 %sset clip radial\n",
273 	    (clip_points) ? "" : "un",
274 	    (clip_lines1) ? "" : "un",
275 	    (clip_lines2) ? "" : "un",
276 	    (clip_radial) ? "" : "un"
277 	    );
278 
279     save_bars(fp);
280 
281     if (draw_border) {
282 	fprintf(fp, "set border %d %s", draw_border,
283 	    border_layer == LAYER_BEHIND ? "behind" : border_layer == LAYER_BACK ? "back" : "front");
284 	save_linetype(fp, &border_lp, FALSE);
285 	fprintf(fp, "\n");
286     } else
287 	fputs("unset border\n", fp);
288 
289     for (axis = 0; axis < NUMBER_OF_MAIN_VISIBLE_AXES; axis++) {
290 	if (axis == SAMPLE_AXIS) continue;
291 	if (axis == COLOR_AXIS) continue;
292 	if (axis == POLAR_AXIS) continue;
293 	fprintf(fp, "set %sdata %s\n", axis_name(axis),
294 		axis_array[axis].datatype == DT_TIMEDATE ? "time" :
295 		axis_array[axis].datatype == DT_DMS ? "geographic" :
296 		"");
297     }
298 
299     if (boxwidth < 0.0)
300 	fputs("set boxwidth\n", fp);
301     else
302 	fprintf(fp, "set boxwidth %g %s\n", boxwidth,
303 		(boxwidth_is_absolute) ? "absolute" : "relative");
304     fprintf(fp, "set boxdepth %g\n", boxdepth > 0 ? boxdepth : 0.0);
305 
306     fprintf(fp, "set style fill ");
307     save_fillstyle(fp, &default_fillstyle);
308 
309     /* Default rectangle style */
310     fprintf(fp, "set style rectangle %s fc ",
311 	    default_rectangle.layer > 0 ? "front" :
312 	    default_rectangle.layer < 0 ? "behind" : "back");
313     save_pm3dcolor(fp, &default_rectangle.lp_properties.pm3d_color);
314     fprintf(fp, " fillstyle ");
315     save_fillstyle(fp, &default_rectangle.fillstyle);
316 
317     /* Default circle properties */
318     fprintf(fp, "set style circle radius ");
319     save_position(fp, &default_circle.o.circle.extent, 1, FALSE);
320     fputs(" \n", fp);
321 
322     /* Default ellipse properties */
323     fprintf(fp, "set style ellipse size ");
324     save_position(fp, &default_ellipse.o.ellipse.extent, 2, FALSE);
325     fprintf(fp, " angle %g ", default_ellipse.o.ellipse.orientation);
326     fputs("units ", fp);
327     switch (default_ellipse.o.ellipse.type) {
328 	case ELLIPSEAXES_XY:
329 	    fputs("xy\n", fp);
330 	    break;
331 	case ELLIPSEAXES_XX:
332 	    fputs("xx\n", fp);
333 	    break;
334 	case ELLIPSEAXES_YY:
335 	    fputs("yy\n", fp);
336 	    break;
337     }
338 
339     if (dgrid3d) {
340       if (dgrid3d_mode == DGRID3D_QNORM) {
341 	fprintf(fp, "set dgrid3d %d,%d, %d\n",
342 	  	dgrid3d_row_fineness,
343 	  	dgrid3d_col_fineness,
344 	  	dgrid3d_norm_value);
345       } else if (dgrid3d_mode == DGRID3D_SPLINES) {
346 	fprintf(fp, "set dgrid3d %d,%d splines\n",
347 	  	dgrid3d_row_fineness, dgrid3d_col_fineness );
348       } else {
349 	fprintf(fp, "set dgrid3d %d,%d %s%s %f,%f\n",
350 	  	dgrid3d_row_fineness,
351 	  	dgrid3d_col_fineness,
352 		reverse_table_lookup(dgrid3d_mode_tbl, dgrid3d_mode),
353 		dgrid3d_kdensity ? " kdensity2d" : "",
354 	  	dgrid3d_x_scale,
355 	  	dgrid3d_y_scale );
356       }
357     }
358 
359     /* Dummy variable names */
360     fprintf(fp, "set dummy %s", set_dummy_var[0]);
361     for (axis=1; axis<MAX_NUM_VAR; axis++) {
362 	if (*set_dummy_var[axis] == '\0')
363 	    break;
364 	fprintf(fp, ", %s", set_dummy_var[axis]);
365     }
366     fprintf(fp, "\n");
367 
368     save_axis_format(fp, FIRST_X_AXIS );
369     save_axis_format(fp, FIRST_Y_AXIS );
370     save_axis_format(fp, SECOND_X_AXIS);
371     save_axis_format(fp, SECOND_Y_AXIS);
372     save_axis_format(fp, FIRST_Z_AXIS );
373     save_axis_format(fp, COLOR_AXIS);
374     save_axis_format(fp, POLAR_AXIS);
375     fprintf(fp, "set ttics format \"%s\"\n", THETA_AXIS.formatstring);
376 
377     fprintf(fp, "set timefmt \"%s\"\n", timefmt);
378 
379     fprintf(fp, "set angles %s\n",
380 	    (ang2rad == 1.0) ? "radians" : "degrees");
381 
382     fprintf(fp,"set tics %s\n", grid_tics_in_front ? "front" : "back");
383 
384     if (! some_grid_selected())
385 	fputs("unset grid\n", fp);
386     else {
387 	if (polar_grid_angle) 	/* set angle already output */
388 	    fprintf(fp, "set grid polar %f\n", polar_grid_angle / ang2rad);
389 	else
390 	    fputs("set grid nopolar\n", fp);
391 
392 #define SAVE_GRID(axis)					\
393 	fprintf(fp, " %s%stics %sm%stics",		\
394 		axis_array[axis].gridmajor ? "" : "no",	\
395 		axis_name(axis),		\
396 		axis_array[axis].gridminor ? "" : "no",	\
397 		axis_name(axis));
398 	fputs("set grid", fp);
399 	SAVE_GRID(FIRST_X_AXIS);
400 	SAVE_GRID(FIRST_Y_AXIS);
401 	SAVE_GRID(FIRST_Z_AXIS);
402 	SAVE_GRID(POLAR_AXIS);
403 	fputs(" \\\n", fp);
404 	SAVE_GRID(SECOND_X_AXIS);
405 	SAVE_GRID(SECOND_Y_AXIS);
406 	SAVE_GRID(COLOR_AXIS);
407 	fputs("\n", fp);
408 #undef SAVE_GRID
409 
410 	fprintf(fp, "set grid %s%s  ",
411 		(grid_vertical_lines) ? "vertical " : "",
412 		(grid_layer==-1) ? "layerdefault" : ((grid_layer==0) ? "back" : "front"));
413 	save_linetype(fp, &grid_lp, FALSE);
414 	fprintf(fp, ", ");
415 	save_linetype(fp, &mgrid_lp, FALSE);
416 	fputc('\n', fp);
417     }
418     fprintf(fp, "%sset raxis\n", raxis ? "" : "un");
419 
420     /* Theta axis origin and direction */
421     fprintf(fp, "set theta %s %s\n",
422 	theta_direction > 0 ? "counterclockwise" : "clockwise",
423 	theta_origin == 180 ? "left" : theta_origin ==  90 ? "top" :
424 	theta_origin == -90 ? "bottom" : "right");
425 
426     /* Save parallel axis state */
427     save_style_parallel(fp);
428 
429     if (key->title.text == NULL)
430 	fprintf(fp, "set key notitle\n");
431     else {
432 	fprintf(fp, "set key title \"%s\"", conv_text(key->title.text));
433 	if (key->title.font)
434 	    fprintf(fp, " font \"%s\" ", key->title.font);
435 	save_justification(key->title.pos, fp);
436 	fputs("\n", fp);
437     }
438 
439     fputs("set key ", fp);
440     switch (key->region) {
441 	case GPKEY_AUTO_INTERIOR_LRTBC:
442 	    fputs(key->fixed ? "fixed" : "inside", fp);
443 	    break;
444 	case GPKEY_AUTO_EXTERIOR_LRTBC:
445 	    fputs("outside", fp);
446 	    break;
447 	case GPKEY_AUTO_EXTERIOR_MARGIN:
448 	    switch (key->margin) {
449 	    case GPKEY_TMARGIN:
450 		fputs("tmargin", fp);
451 		break;
452 	    case GPKEY_BMARGIN:
453 		fputs("bmargin", fp);
454 		break;
455 	    case GPKEY_LMARGIN:
456 		fputs("lmargin", fp);
457 		break;
458 	    case GPKEY_RMARGIN:
459 		fputs("rmargin", fp);
460 		break;
461 	    }
462 	    break;
463 	case GPKEY_USER_PLACEMENT:
464 	    fputs("at ", fp);
465 	    save_position(fp, &key->user_pos, 2, FALSE);
466 	    break;
467     }
468     if (!(key->region == GPKEY_AUTO_EXTERIOR_MARGIN
469 	      && (key->margin == GPKEY_LMARGIN || key->margin == GPKEY_RMARGIN))) {
470 	save_justification(key->hpos, fp);
471     }
472     if (!(key->region == GPKEY_AUTO_EXTERIOR_MARGIN
473 	      && (key->margin == GPKEY_TMARGIN || key->margin == GPKEY_BMARGIN))) {
474 	switch (key->vpos) {
475 	    case JUST_TOP:
476 		fputs(" top", fp);
477 		break;
478 	    case JUST_BOT:
479 		fputs(" bottom", fp);
480 		break;
481 	    case JUST_CENTRE:
482 		fputs(" center", fp);
483 		break;
484 	}
485     }
486     fprintf(fp, " %s %s %sreverse %senhanced %s ",
487 		key->stack_dir == GPKEY_VERTICAL ? "vertical" : "horizontal",
488 		key->just == GPKEY_LEFT ? "Left" : "Right",
489 		key->reverse ? "" : "no",
490 		key->enhanced ? "" : "no",
491 		key->auto_titles == COLUMNHEAD_KEYTITLES ? "autotitle columnhead"
492 		: key->auto_titles == FILENAME_KEYTITLES ? "autotitle"
493 		: "noautotitle" );
494     if (key->box.l_type > LT_NODRAW) {
495 	fputs("box", fp);
496 	save_linetype(fp, &(key->box), FALSE);
497     } else
498 	fputs("nobox", fp);
499 
500     /* These are for the key entries, not the key title */
501     if (key->font)
502 	fprintf(fp, " font \"%s\"", key->font);
503     if (key->textcolor.type != TC_LT || key->textcolor.lt != LT_BLACK)
504 	save_textcolor(fp, &key->textcolor);
505 
506     /* Put less common options on separate lines */
507     fprintf(fp, "\nset key %sinvert samplen %g spacing %g width %g height %g ",
508 		key->invert ? "" : "no",
509 		key->swidth, key->vert_factor, key->width_fix, key->height_fix);
510     fprintf(fp, "\nset key maxcolumns %d maxrows %d",key->maxcols,key->maxrows);
511     fputc('\n', fp);
512     fprintf(fp, "set key %sopaque\n", key->front ? "" : "no");
513 
514     if (!(key->visible))
515 	fputs("unset key\n", fp);
516 
517     fputs("unset label\n", fp);
518     for (this_label = first_label; this_label != NULL;
519 	 this_label = this_label->next) {
520 	fprintf(fp, "set label %d \"%s\" at ",
521 		this_label->tag,
522 		conv_text(this_label->text));
523 	save_position(fp, &this_label->place, 3, FALSE);
524 	if (this_label->hypertext)
525 	    fprintf(fp, " hypertext");
526 
527 	save_justification(this_label->pos, fp);
528 	if (this_label->rotate)
529 	    fprintf(fp, " rotate by %d", this_label->rotate);
530 	else
531 	    fprintf(fp, " norotate");
532 	if (this_label->font != NULL)
533 	    fprintf(fp, " font \"%s\"", this_label->font);
534 	fprintf(fp, " %s", (this_label->layer==0) ? "back" : "front");
535 	if (this_label->noenhanced)
536 	    fprintf(fp, " noenhanced");
537 	save_textcolor(fp, &(this_label->textcolor));
538 	if ((this_label->lp_properties.flags & LP_SHOW_POINTS) == 0)
539 	    fprintf(fp, " nopoint");
540 	else {
541 	    fprintf(fp, " point");
542 	    save_linetype(fp, &(this_label->lp_properties), TRUE);
543 	}
544 	save_position(fp, &this_label->offset, 3, TRUE);
545 	if (this_label->boxed) {
546 	    fprintf(fp," boxed ");
547 	    if (this_label->boxed > 0)
548 		fprintf(fp,"bs %d ",this_label->boxed);
549 	}
550 	fputc('\n', fp);
551     }
552     fputs("unset arrow\n", fp);
553     for (this_arrow = first_arrow; this_arrow != NULL;
554 	 this_arrow = this_arrow->next) {
555 	fprintf(fp, "set arrow %d from ", this_arrow->tag);
556 	save_position(fp, &this_arrow->start, 3, FALSE);
557 	if (this_arrow->type == arrow_end_absolute) {
558 	    fputs(" to ", fp);
559 	    save_position(fp, &this_arrow->end, 3, FALSE);
560 	} else if (this_arrow->type == arrow_end_absolute) {
561 	    fputs(" rto ", fp);
562 	    save_position(fp, &this_arrow->end, 3, FALSE);
563 	} else { /* type arrow_end_oriented */
564 	    struct position *e = &this_arrow->end;
565 	    fputs(" length ", fp);
566 	    fprintf(fp, "%s%g", e->scalex == first_axes ? "" : coord_msg[e->scalex], e->x);
567 	    fprintf(fp, " angle %g", this_arrow->angle);
568 	}
569 	fprintf(fp, " %s %s %s",
570 		arrow_head_names[this_arrow->arrow_properties.head],
571 		(this_arrow->arrow_properties.layer==0) ? "back" : "front",
572 		(this_arrow->arrow_properties.headfill==AS_FILLED) ? "filled" :
573 		(this_arrow->arrow_properties.headfill==AS_EMPTY) ? "empty" :
574 		(this_arrow->arrow_properties.headfill==AS_NOBORDER) ? "noborder" :
575 		    "nofilled");
576 	save_linetype(fp, &(this_arrow->arrow_properties.lp_properties), FALSE);
577 	if (this_arrow->arrow_properties.head_length > 0) {
578 	    fprintf(fp, " size %s %.3f,%.3f,%.3f",
579 		    coord_msg[this_arrow->arrow_properties.head_lengthunit],
580 		    this_arrow->arrow_properties.head_length,
581 		    this_arrow->arrow_properties.head_angle,
582 		    this_arrow->arrow_properties.head_backangle);
583 	}
584 	fprintf(fp, "\n");
585     }
586 
587     /* Mostly for backwards compatibility */
588     if (prefer_line_styles)
589 	fprintf(fp, "set style increment userstyles\n");
590     fputs("unset style line\n", fp);
591     for (this_linestyle = first_linestyle; this_linestyle != NULL;
592 	 this_linestyle = this_linestyle->next) {
593 	fprintf(fp, "set style line %d ", this_linestyle->tag);
594 	save_linetype(fp, &(this_linestyle->lp_properties), TRUE);
595 	fprintf(fp, "\n");
596     }
597 
598     fputs("unset style arrow\n", fp);
599     for (this_arrowstyle = first_arrowstyle; this_arrowstyle != NULL;
600 	 this_arrowstyle = this_arrowstyle->next) {
601 	fprintf(fp, "set style arrow %d", this_arrowstyle->tag);
602 	fprintf(fp, " %s %s %s",
603 		arrow_head_names[this_arrowstyle->arrow_properties.head],
604 		(this_arrowstyle->arrow_properties.layer==0)?"back":"front",
605 		(this_arrowstyle->arrow_properties.headfill==AS_FILLED)?"filled":
606 		(this_arrowstyle->arrow_properties.headfill==AS_EMPTY)?"empty":
607 		(this_arrowstyle->arrow_properties.headfill==AS_NOBORDER)?"noborder":
608 		   "nofilled");
609 	save_linetype(fp, &(this_arrowstyle->arrow_properties.lp_properties), FALSE);
610 	if (this_arrowstyle->arrow_properties.head_length > 0) {
611 	    fprintf(fp, " size %s %.3f,%.3f,%.3f",
612 		    coord_msg[this_arrowstyle->arrow_properties.head_lengthunit],
613 		    this_arrowstyle->arrow_properties.head_length,
614 		    this_arrowstyle->arrow_properties.head_angle,
615 		    this_arrowstyle->arrow_properties.head_backangle);
616 	    if (this_arrowstyle->arrow_properties.head_fixedsize) {
617 		fputs(" ", fp);
618 		fputs(" fixed", fp);
619 	    }
620 	}
621 	fprintf(fp, "\n");
622     }
623 
624     fprintf(fp, "set style histogram ");
625     save_histogram_opts(fp);
626 
627     save_pixmaps(fp);
628 
629     fprintf(fp, "unset object\n");
630     save_object(fp, 0);
631     fprintf(fp, "unset walls\n");
632     save_walls(fp);
633 
634     save_style_textbox(fp);
635 
636     save_offsets(fp, "set offsets");
637 
638     fprintf(fp, "\
639 set pointsize %g\n\
640 set pointintervalbox %g\n\
641 set encoding %s\n\
642 %sset polar\n\
643 %sset parametric\n",
644 	    pointsize, pointintervalbox,
645 	    encoding_names[encoding],
646 	    (polar) ? "" : "un",
647 	    (parametric) ? "" : "un");
648 
649     if (spiderplot) {
650 	fprintf(fp, "set spiderplot\n");
651 	save_style_spider(fp);
652     } else
653 	fprintf(fp, "unset spiderplot\n");
654 
655     if (numeric_locale)
656 	fprintf(fp, "set decimalsign locale \"%s\"\n", numeric_locale);
657     if (decimalsign != NULL)
658 	fprintf(fp, "set decimalsign '%s'\n", decimalsign);
659     if (!numeric_locale && !decimalsign)
660 	fprintf(fp, "unset decimalsign\n");
661 
662     fprintf(fp, "%sset micro\n", use_micro ? "" : "un");
663     fprintf(fp, "%sset minussign\n", use_minus_sign ? "" : "un");
664 
665     fputs("set view ", fp);
666     if (splot_map == TRUE)
667 	fprintf(fp, "map scale %g", mapview_scale);
668     else if (xz_projection)
669 	fprintf(fp, "projection xz");
670     else if (yz_projection)
671 	fprintf(fp, "projection yz");
672     else {
673 	fprintf(fp, "%g, %g, %g, %g",
674 	    surface_rot_x, surface_rot_z, surface_scale, surface_zscale);
675 	fprintf(fp, "\nset view azimuth %g", azimuth);
676     }
677     if (aspect_ratio_3D)
678 	fprintf(fp, "\nset view  %s", aspect_ratio_3D == 2 ? "equal xy" :
679 			aspect_ratio_3D == 3 ? "equal xyz": "");
680 
681     fprintf(fp, "\nset rgbmax %g", rgbmax);
682 
683     fprintf(fp, "\n\
684 set samples %d, %d\n\
685 set isosamples %d, %d\n\
686 %sset surface %s",
687 	    samples_1, samples_2,
688 	    iso_samples_1, iso_samples_2,
689 	    (draw_surface) ? "" : "un",
690 	    (implicit_surface) ? "" : "explicit");
691 
692     fprintf(fp, "\n\
693 %sset contour", (draw_contour) ? "" : "un");
694     switch (draw_contour) {
695     case CONTOUR_NONE:
696 	fputc('\n', fp);
697 	break;
698     case CONTOUR_BASE:
699 	fputs(" base\n", fp);
700 	break;
701     case CONTOUR_SRF:
702 	fputs(" surface\n", fp);
703 	break;
704     case CONTOUR_BOTH:
705 	fputs(" both\n", fp);
706 	break;
707     }
708 
709     /* Contour label options */
710     fprintf(fp, "set cntrlabel %s format '%s' font '%s' start %d interval %d\n",
711 	clabel_onecolor ? "onecolor" : "", contour_format,
712 	clabel_font ? clabel_font : "",
713 	clabel_start, clabel_interval);
714 
715     fputs("set mapping ", fp);
716     switch (mapping3d) {
717     case MAP3D_SPHERICAL:
718 	fputs("spherical\n", fp);
719 	break;
720     case MAP3D_CYLINDRICAL:
721 	fputs("cylindrical\n", fp);
722 	break;
723     case MAP3D_CARTESIAN:
724     default:
725 	fputs("cartesian\n", fp);
726 	break;
727     }
728 
729     if (missing_val != NULL)
730 	fprintf(fp, "set datafile missing '%s'\n", missing_val);
731     if (df_separators)
732 	fprintf(fp, "set datafile separator \"%s\"\n",df_separators);
733     else
734 	fprintf(fp, "set datafile separator whitespace\n");
735     if (strcmp(df_commentschars, DEFAULT_COMMENTS_CHARS))
736 	fprintf(fp, "set datafile commentschars '%s'\n", df_commentschars);
737     if (df_fortran_constants)
738 	fprintf(fp, "set datafile fortran\n");
739     if (df_nofpe_trap)
740 	fprintf(fp, "set datafile nofpe_trap\n");
741     fprintf(fp, "set datafile %scolumnheaders\n", df_columnheaders ? "" : "no");
742 
743     save_hidden3doptions(fp);
744     fprintf(fp, "set cntrparam order %d\n", contour_order);
745     fputs("set cntrparam ", fp);
746     switch (contour_kind) {
747     case CONTOUR_KIND_LINEAR:
748 	fputs("linear\n", fp);
749 	break;
750     case CONTOUR_KIND_CUBIC_SPL:
751 	fputs("cubicspline\n", fp);
752 	break;
753     case CONTOUR_KIND_BSPLINE:
754 	fputs("bspline\n", fp);
755 	break;
756     }
757     fprintf(fp, "set cntrparam levels %d\nset cntrparam levels ", contour_levels);
758     switch (contour_levels_kind) {
759     case LEVELS_AUTO:
760 	fprintf(fp, "auto");
761 	break;
762     case LEVELS_INCREMENTAL:
763 	fprintf(fp, "incremental %g,%g",
764 		contour_levels_list[0], contour_levels_list[1]);
765 	break;
766     case LEVELS_DISCRETE:
767 	{
768 	    int i;
769 	    fprintf(fp, "discrete %g", contour_levels_list[0]);
770 	    for (i = 1; i < contour_levels; i++)
771 		fprintf(fp, ",%g ", contour_levels_list[i]);
772 	}
773     }
774     fprintf(fp, "\nset cntrparam firstlinetype %d", contour_firstlinetype);
775     fprintf(fp, " %ssorted\n", contour_sortlevels ? "" : "un");
776     fprintf(fp, "\
777 set cntrparam points %d\n\
778 set size ratio %g %g,%g\n\
779 set origin %g,%g\n",
780 	    contour_pts,
781 	    aspect_ratio, xsize, ysize,
782 	    xoffset, yoffset);
783 
784     fprintf(fp, "set style data ");
785     save_data_func_style(fp,"data",data_style);
786     fprintf(fp, "set style function ");
787     save_data_func_style(fp,"function",func_style);
788 
789     save_zeroaxis(fp, FIRST_X_AXIS);
790     save_zeroaxis(fp, FIRST_Y_AXIS);
791     save_zeroaxis(fp, FIRST_Z_AXIS);
792     save_zeroaxis(fp, SECOND_X_AXIS);
793     save_zeroaxis(fp, SECOND_Y_AXIS);
794 
795     if (xyplane.absolute)
796 	fprintf(fp, "set xyplane at %g\n", xyplane.z);
797     else
798 	fprintf(fp, "set xyplane relative %g\n", xyplane.z);
799 
800     {
801     int i;
802     fprintf(fp, "set tics scale ");
803     for (i=0; i<MAX_TICLEVEL; i++)
804 	fprintf(fp, " %g%c", ticscale[i], i<MAX_TICLEVEL-1 ? ',' : '\n');
805     }
806 
807     save_mtics(fp, &axis_array[FIRST_X_AXIS]);
808     save_mtics(fp, &axis_array[FIRST_Y_AXIS]);
809     save_mtics(fp, &axis_array[FIRST_Z_AXIS]);
810     save_mtics(fp, &axis_array[SECOND_X_AXIS]);
811     save_mtics(fp, &axis_array[SECOND_Y_AXIS]);
812     save_mtics(fp, &axis_array[COLOR_AXIS]);
813     save_mtics(fp, &R_AXIS);
814     save_mtics(fp, &THETA_AXIS);
815 
816     save_tics(fp, &axis_array[FIRST_X_AXIS]);
817     save_tics(fp, &axis_array[FIRST_Y_AXIS]);
818     save_tics(fp, &axis_array[FIRST_Z_AXIS]);
819     save_tics(fp, &axis_array[SECOND_X_AXIS]);
820     save_tics(fp, &axis_array[SECOND_Y_AXIS]);
821     save_tics(fp, &axis_array[COLOR_AXIS]);
822     save_tics(fp, &R_AXIS);
823     save_tics(fp, &THETA_AXIS);
824     for (axis=0; axis<num_parallel_axes; axis++)
825 	save_tics(fp, &parallel_axis_array[axis]);
826 
827     save_axis_label_or_title(fp, "", "title", &title, TRUE);
828 
829     fprintf(fp, "set timestamp %s \n", timelabel_bottom ? "bottom" : "top");
830     save_axis_label_or_title(fp, "", "timestamp", &timelabel, FALSE);
831 
832     save_prange(fp, axis_array + T_AXIS);
833     save_prange(fp, axis_array + U_AXIS);
834     save_prange(fp, axis_array + V_AXIS);
835 
836 #define SAVE_AXISLABEL(axis)					\
837     save_axis_label_or_title(fp, axis_name(axis), "label", &axis_array[axis].label, TRUE)
838 
839     SAVE_AXISLABEL(FIRST_X_AXIS);
840     SAVE_AXISLABEL(SECOND_X_AXIS);
841     save_prange(fp, axis_array + FIRST_X_AXIS);
842     save_prange(fp, axis_array + SECOND_X_AXIS);
843 
844     SAVE_AXISLABEL(FIRST_Y_AXIS);
845     SAVE_AXISLABEL(SECOND_Y_AXIS);
846     save_prange(fp, axis_array + FIRST_Y_AXIS);
847     save_prange(fp, axis_array + SECOND_Y_AXIS);
848 
849     SAVE_AXISLABEL(FIRST_Z_AXIS);
850     save_prange(fp, axis_array + FIRST_Z_AXIS);
851 
852     SAVE_AXISLABEL(COLOR_AXIS);
853     save_prange(fp, axis_array + COLOR_AXIS);
854 
855     SAVE_AXISLABEL(POLAR_AXIS);
856     save_prange(fp, axis_array + POLAR_AXIS);
857 
858     for (axis=0; axis<num_parallel_axes; axis++) {
859 	struct axis *paxis = &parallel_axis_array[axis];
860 	save_prange(fp, paxis);
861 	if (paxis->label.text)
862 	    save_axis_label_or_title(fp,
863 				axis_name(paxis->index),"label",
864 				&paxis->label, TRUE);
865 	if (paxis->zeroaxis) {
866 	    fprintf(fp, "set paxis %d", axis+1);
867 	    save_linetype(fp, paxis->zeroaxis, FALSE);
868 	    fprintf(fp, "\n");
869 	}
870     }
871 
872 #undef SAVE_AXISLABEL
873 
874     fputs("unset logscale\n", fp);
875     for (axis = 0; axis < NUMBER_OF_MAIN_VISIBLE_AXES; axis++) {
876 	if (axis_array[axis].log)
877 	    fprintf(fp, "set logscale %s %g\n", axis_name(axis),
878 		axis_array[axis].base);
879 	else
880 	    save_nonlinear(fp, &axis_array[axis]);
881     }
882 
883     /* These will only print something if the axis is, in fact, linked */
884     save_link(fp, axis_array + SECOND_X_AXIS);
885     save_link(fp, axis_array + SECOND_Y_AXIS);
886 
887     save_jitter(fp);
888 
889     fprintf(fp, "set zero %g\n", zero);
890 
891     fprintf(fp, "set lmargin %s %g\n",
892 	    lmargin.scalex == screen ? "at screen" : "", lmargin.x);
893     fprintf(fp, "set bmargin %s %g\n",
894 	    bmargin.scalex == screen ? "at screen" : "", bmargin.x);
895     fprintf(fp, "set rmargin %s %g\n",
896 	    rmargin.scalex == screen ? "at screen" : "", rmargin.x);
897     fprintf(fp, "set tmargin %s %g\n",
898 	    tmargin.scalex == screen ? "at screen" : "", tmargin.x);
899 
900     fprintf(fp, "set locale \"%s\"\n", get_time_locale());
901 
902     /* pm3d options */
903     fputs("set pm3d ", fp);
904     fputs((PM3D_IMPLICIT == pm3d.implicit ? "implicit" : "explicit"), fp);
905     fprintf(fp, " at %s\n", pm3d.where);
906     fputs("set pm3d ", fp);
907     switch (pm3d.direction) {
908     case PM3D_SCANS_AUTOMATIC: fputs("scansautomatic\n", fp); break;
909     case PM3D_SCANS_FORWARD: fputs("scansforward\n", fp); break;
910     case PM3D_SCANS_BACKWARD: fputs("scansbackward\n", fp); break;
911     case PM3D_DEPTH: fprintf(fp, "depthorder %s\n", pm3d.base_sort ? "base" : ""); break;
912     }
913     fprintf(fp, "set pm3d interpolate %d,%d", pm3d.interp_i, pm3d.interp_j);
914     fputs(" flush ", fp);
915     switch (pm3d.flush) {
916     case PM3D_FLUSH_CENTER: fputs("center", fp); break;
917     case PM3D_FLUSH_BEGIN: fputs("begin", fp); break;
918     case PM3D_FLUSH_END: fputs("end", fp); break;
919     }
920     fputs((pm3d.ftriangles ? " " : " no"), fp);
921     fputs("ftriangles", fp);
922     if (pm3d.border.l_type == LT_NODRAW) {
923 	fprintf(fp," noborder");
924     } else {
925 	fprintf(fp," border");
926 	save_linetype(fp, &(pm3d.border), FALSE);
927     }
928     fputs(" corners2color ", fp);
929     switch (pm3d.which_corner_color) {
930 	case PM3D_WHICHCORNER_MEAN:    fputs("mean", fp); break;
931 	case PM3D_WHICHCORNER_GEOMEAN: fputs("geomean", fp); break;
932 	case PM3D_WHICHCORNER_HARMEAN: fputs("harmean", fp); break;
933 	case PM3D_WHICHCORNER_MEDIAN:  fputs("median", fp); break;
934 	case PM3D_WHICHCORNER_MIN:     fputs("min", fp); break;
935 	case PM3D_WHICHCORNER_MAX:     fputs("max", fp); break;
936 	case PM3D_WHICHCORNER_RMS:     fputs("rms", fp); break;
937 
938 	default: /* PM3D_WHICHCORNER_C1 ... _C4 */
939 	     fprintf(fp, "c%i", pm3d.which_corner_color - PM3D_WHICHCORNER_C1 + 1);
940     }
941     fputs("\n", fp);
942 
943     fprintf(fp, "set pm3d %s %s\n",
944 		pm3d.clip == PM3D_CLIP_1IN ? "clip1in" :
945 		pm3d.clip == PM3D_CLIP_4IN ? "clip4in" : "clip z",
946 		pm3d.no_clipcb ? "noclipcb" : "");
947 
948     if (pm3d_shade.strength <= 0)
949 	fputs("set pm3d nolighting\n",fp);
950     else
951 	fprintf(fp, "set pm3d lighting primary %g specular %g spec2 %g\n",
952 		pm3d_shade.strength, pm3d_shade.spec, pm3d_shade.spec2);
953 
954     /*
955      *  Save palette information
956      */
957 
958     fprintf( fp, "set palette %s %s maxcolors %d ",
959 	     sm_palette.positive==SMPAL_POSITIVE ? "positive" : "negative",
960 	     sm_palette.ps_allcF ? "ps_allcF" : "nops_allcF",
961 	sm_palette.use_maxcolors);
962     fprintf( fp, "gamma %g ", sm_palette.gamma );
963     if (sm_palette.colorMode == SMPAL_COLOR_MODE_GRAY) {
964       fputs( "gray\n", fp );
965     }
966     else {
967       fputs( "color model ", fp );
968       switch( sm_palette.cmodel ) {
969 	default:
970 	case C_MODEL_RGB: fputs( "RGB ", fp ); break;
971 	case C_MODEL_HSV: fputs( "HSV ", fp ); break;
972 	case C_MODEL_CMY: fputs( "CMY ", fp ); break;
973       }
974       fputs( "\nset palette ", fp );
975       switch( sm_palette.colorMode ) {
976       default:
977       case SMPAL_COLOR_MODE_RGB:
978 	fprintf( fp, "rgbformulae %d, %d, %d\n", sm_palette.formulaR,
979 		 sm_palette.formulaG, sm_palette.formulaB );
980 	break;
981       case SMPAL_COLOR_MODE_GRADIENT: {
982 	int i=0;
983 	fprintf( fp, "defined (" );
984 	for (i=0; i<sm_palette.gradient_num; i++) {
985 	  fprintf( fp, " %.4g %.4g %.4g %.4g", sm_palette.gradient[i].pos,
986 		   sm_palette.gradient[i].col.r, sm_palette.gradient[i].col.g,
987 		   sm_palette.gradient[i].col.b );
988 	  if (i<sm_palette.gradient_num-1)  {
989 	      fputs( ",", fp);
990 	      if (i==2 || i%4==2)  fputs( "\\\n    ", fp );
991 	  }
992 	}
993 	fputs( " )\n", fp );
994 	break;
995       }
996       case SMPAL_COLOR_MODE_FUNCTIONS:
997 	fprintf( fp, "functions %s, %s, %s\n", sm_palette.Afunc.definition,
998 		 sm_palette.Bfunc.definition, sm_palette.Cfunc.definition );
999 	break;
1000       case SMPAL_COLOR_MODE_CUBEHELIX:
1001 	fprintf( fp, "cubehelix start %.2g cycles %.2g saturation %.2g\n",
1002 		sm_palette.cubehelix_start, sm_palette.cubehelix_cycles,
1003 		sm_palette.cubehelix_saturation);
1004 	break;
1005       }
1006     }
1007 
1008     /*
1009      *  Save colorbox info
1010      */
1011     if (color_box.where != SMCOLOR_BOX_NO)
1012 	fprintf(fp,"set colorbox %s\n", color_box.where==SMCOLOR_BOX_DEFAULT ? "default" : "user");
1013     fprintf(fp, "set colorbox %sal origin ", color_box.rotation ==  'v' ? "vertic" : "horizont");
1014     save_position(fp, &color_box.origin, 2, FALSE);
1015     fputs(" size ", fp);
1016     save_position(fp, &color_box.size, 2, FALSE);
1017     fprintf(fp, " %s ", color_box.layer ==  LAYER_FRONT ? "front" : "back");
1018     fprintf(fp, " %sinvert ", color_box.invert ? "" : "no");
1019     if (color_box.border == 0) fputs("noborder", fp);
1020 	else if (color_box.border_lt_tag < 0) fputs("bdefault", fp);
1021 		 else fprintf(fp, "border %d", color_box.border_lt_tag);
1022     if (color_box.where == SMCOLOR_BOX_NO) fputs("\nunset colorbox\n", fp);
1023 	else fputs("\n", fp);
1024 
1025     fprintf(fp, "set style boxplot %s %s %5.2f %soutliers pt %d separation %g labels %s %ssorted\n",
1026 		boxplot_opts.plotstyle == FINANCEBARS ? "financebars" : "candles",
1027 		boxplot_opts.limit_type == 1 ? "fraction" : "range",
1028 		boxplot_opts.limit_value,
1029 		boxplot_opts.outliers ? "" : "no",
1030 		boxplot_opts.pointtype+1,
1031 		boxplot_opts.separation,
1032 		(boxplot_opts.labels == BOXPLOT_FACTOR_LABELS_X)  ? "x"  :
1033 		(boxplot_opts.labels == BOXPLOT_FACTOR_LABELS_X2) ? "x2" :
1034 		(boxplot_opts.labels == BOXPLOT_FACTOR_LABELS_AUTO) ? "auto" :"off",
1035 		boxplot_opts.sort_factors ? "" : "un");
1036 
1037     fputs("set loadpath ", fp);
1038     {
1039 	char *s;
1040 	while ((s = save_loadpath()) != NULL)
1041 	    fprintf(fp, "\"%s\" ", s);
1042 	fputc('\n', fp);
1043     }
1044 
1045     if (PS_fontpath)
1046 	fprintf(fp, "set fontpath \"%s\"\n", PS_fontpath);
1047     else
1048 	fprintf(fp, "set fontpath\n");
1049 
1050     if (PS_psdir)
1051 	fprintf(fp, "set psdir \"%s\"\n", PS_psdir);
1052     else
1053 	fprintf(fp, "set psdir\n");
1054 
1055     fprintf(fp, "set fit");
1056     if (fit_suppress_log)
1057 	fprintf(fp, " nologfile");
1058     else if (fitlogfile)
1059 	fprintf(fp, " logfile \'%s\'", fitlogfile);
1060     fprintf(fp, " %s", reverse_table_lookup(fit_verbosity_level, fit_verbosity));
1061     fprintf(fp, " %serrorvariables",
1062 	fit_errorvariables ? "" : "no");
1063     fprintf(fp, " %scovariancevariables",
1064 	fit_covarvariables ? "" : "no");
1065     fprintf(fp, " %serrorscaling",
1066 	fit_errorscaling ? "" : "no");
1067     fprintf(fp, " %sprescale", fit_prescale ? "" : "no");
1068     {
1069 	struct udvt_entry *v;
1070 	double d;
1071 	int i;
1072 
1073 	v = get_udv_by_name((char *)FITLIMIT);
1074 	d = ((v != NULL) && (v->udv_value.type != NOTDEFINED)) ? real(&(v->udv_value)) : -1.0;
1075 	if ((d > 0.) && (d < 1.))
1076 	    fprintf(fp, " limit %g", d);
1077 
1078 	if (epsilon_abs > 0.)
1079 	    fprintf(fp, " limit_abs %g", epsilon_abs);
1080 
1081 	v = get_udv_by_name((char *)FITMAXITER);
1082 	i = ((v != NULL) && (v->udv_value.type != NOTDEFINED)) ? real(&(v->udv_value)) : -1;
1083 	if (i > 0)
1084 	    fprintf(fp, " maxiter %i", i);
1085 
1086 	v = get_udv_by_name((char *)FITSTARTLAMBDA);
1087 	d = ((v != NULL) && (v->udv_value.type != NOTDEFINED)) ? real(&(v->udv_value)) : -1.0;
1088 	if (d > 0.)
1089 	    fprintf(fp, " start_lambda %g", d);
1090 
1091 	v = get_udv_by_name((char *)FITLAMBDAFACTOR);
1092 	d = ((v != NULL) && (v->udv_value.type != NOTDEFINED)) ? real(&(v->udv_value)) : -1.0;
1093 	if (d > 0.)
1094 	    fprintf(fp, " lambda_factor %g", d);
1095     }
1096     if (fit_script != NULL)
1097 	fprintf(fp, " script \'%s\'", fit_script);
1098     if (fit_wrap != 0)
1099 	fprintf(fp, " wrap %i", fit_wrap);
1100     else
1101 	fprintf(fp, " nowrap");
1102     fprintf(fp, " v%i", fit_v4compatible ? 4 : 5);
1103     fputc('\n', fp);
1104 }
1105 
1106 
1107 static void
save_tics(FILE * fp,struct axis * this_axis)1108 save_tics(FILE *fp, struct axis *this_axis)
1109 {
1110     if ((this_axis->ticmode & TICS_MASK) == NO_TICS) {
1111 	fprintf(fp, "unset %stics\n", axis_name(this_axis->index));
1112 	return;
1113     }
1114     fprintf(fp, "set %stics %s %s scale %g,%g %smirror %s ",
1115 	    axis_name(this_axis->index),
1116 	    ((this_axis->ticmode & TICS_MASK) == TICS_ON_AXIS)
1117 	    ? "axis" : "border",
1118 	    (this_axis->tic_in) ? "in" : "out",
1119 	    this_axis->ticscale, this_axis->miniticscale,
1120 	    (this_axis->ticmode & TICS_MIRROR) ? "" : "no",
1121 	    this_axis->tic_rotate ? "rotate" : "norotate");
1122     if (this_axis->tic_rotate)
1123 	fprintf(fp,"by %d ",this_axis->tic_rotate);
1124     save_position(fp, &this_axis->ticdef.offset, 3, TRUE);
1125     if (this_axis->manual_justify)
1126 	save_justification(this_axis->tic_pos, fp);
1127     else
1128 	fputs(" autojustify", fp);
1129     fprintf(fp, "\nset %stics ", axis_name(this_axis->index));
1130 
1131     fprintf(fp, (this_axis->ticdef.rangelimited)?" rangelimit ":" norangelimit ");
1132 
1133     if (this_axis->ticdef.logscaling)
1134 	fputs("logscale ", fp);
1135 
1136     switch (this_axis->ticdef.type) {
1137     case TIC_COMPUTED:{
1138 	    fputs("autofreq ", fp);
1139 	    break;
1140 	}
1141     case TIC_MONTH:{
1142 	    fprintf(fp, "\nset %smtics", axis_name(this_axis->index));
1143 	    break;
1144 	}
1145     case TIC_DAY:{
1146 	    fprintf(fp, "\nset %sdtics", axis_name(this_axis->index));
1147 	    break;
1148 	}
1149     case TIC_SERIES:
1150 	if (this_axis->ticdef.def.series.start != -VERYLARGE) {
1151 	    save_num_or_time_input(fp,
1152 			     (double) this_axis->ticdef.def.series.start,
1153 			     this_axis);
1154 	    putc(',', fp);
1155 	}
1156 	fprintf(fp, "%g", this_axis->ticdef.def.series.incr);
1157 	if (this_axis->ticdef.def.series.end != VERYLARGE) {
1158 	    putc(',', fp);
1159 	    save_num_or_time_input(fp,
1160 			     (double) this_axis->ticdef.def.series.end,
1161 			     this_axis);
1162 	}
1163 	break;
1164     case TIC_USER:
1165 	break;
1166     }
1167 
1168     if (this_axis->ticdef.font && *this_axis->ticdef.font)
1169 	fprintf(fp, " font \"%s\"", this_axis->ticdef.font);
1170 
1171     if (this_axis->ticdef.enhanced == FALSE)
1172 	fprintf(fp, " noenhanced");
1173 
1174     if (this_axis->ticdef.textcolor.type != TC_DEFAULT)
1175 	save_textcolor(fp, &this_axis->ticdef.textcolor);
1176 
1177     putc('\n', fp);
1178 
1179     if (this_axis->ticdef.def.user) {
1180 	struct ticmark *t;
1181 	fprintf(fp, "set %stics %s ", axis_name(this_axis->index),
1182 		(this_axis->ticdef.type == TIC_USER) ? "" : "add");
1183 	fputs(" (", fp);
1184 	for (t = this_axis->ticdef.def.user; t != NULL; t = t->next) {
1185 	    if (t->level < 0)	/* Don't save ticlabels read from data file */
1186 		continue;
1187 	    if (t->label)
1188 		fprintf(fp, "\"%s\" ", conv_text(t->label));
1189 	    save_num_or_time_input(fp, (double) t->position, this_axis);
1190 	    if (t->level)
1191 		fprintf(fp, " %d", t->level);
1192 	    if (t->next) {
1193 		fputs(", ", fp);
1194 	    }
1195 	}
1196 	fputs(")\n", fp);
1197     }
1198 
1199 }
1200 
1201 static void
save_mtics(FILE * fp,struct axis * axis)1202 save_mtics(FILE *fp, struct axis *axis)
1203 {
1204     char *name = axis_name(axis->index);
1205 
1206     switch(axis->minitics & TICS_MASK) {
1207     case 0:
1208 	fprintf(fp, "set nom%stics\n", name);
1209 	break;
1210     case MINI_AUTO:
1211 	fprintf(fp, "set m%stics\n", name);
1212 	break;
1213     case MINI_DEFAULT:
1214 	fprintf(fp, "set m%stics default\n", name);
1215 	break;
1216     case MINI_USER:
1217 	fprintf(fp, "set m%stics %f\n", name, axis->mtic_freq);
1218 	break;
1219     }
1220 }
1221 
1222 void
save_num_or_time_input(FILE * fp,double x,struct axis * this_axis)1223 save_num_or_time_input(FILE *fp, double x, struct axis *this_axis)
1224 {
1225     if (this_axis->datatype == DT_TIMEDATE) {
1226 	char s[80];
1227 
1228 	putc('"', fp);
1229 	gstrftime(s,80,timefmt,(double)(x));
1230 	fputs(conv_text(s), fp);
1231 	putc('"', fp);
1232     } else {
1233 	fprintf(fp,"%#g",x);
1234     }
1235 }
1236 
1237 void
save_axis_format(FILE * fp,AXIS_INDEX axis)1238 save_axis_format(FILE *fp, AXIS_INDEX axis)
1239 {
1240     fprintf(fp,
1241 	    (fp == stderr) ? "\t  %s-axis: \"%s\"%s\n" : "set format %s \"%s\" %s\n",
1242 	     axis_name(axis), conv_text(axis_array[axis].formatstring),
1243 	    axis_array[axis].tictype == DT_DMS ? "geographic" :
1244 	    axis_array[axis].tictype == DT_TIMEDATE ? "timedate" :
1245 	    "");
1246 }
1247 
1248 void
save_style_parallel(FILE * fp)1249 save_style_parallel(FILE *fp)
1250 {
1251     if (fp == stderr)
1252 	fputs("\t",fp);
1253     fprintf(fp, "set style parallel %s ",
1254 	parallel_axis_style.layer == LAYER_BACK ? "back" : "front");
1255     save_linetype(fp, &(parallel_axis_style.lp_properties), FALSE);
1256     fprintf(fp, "\n");
1257 }
1258 
1259 void
save_style_spider(FILE * fp)1260 save_style_spider(FILE *fp)
1261 {
1262     fprintf(fp, "set style spiderplot ");
1263     save_linetype(fp, &(spiderplot_style.lp_properties), TRUE);
1264     fprintf(fp, "\nset style spiderplot fillstyle ");
1265     save_fillstyle(fp, &spiderplot_style.fillstyle);
1266 }
1267 
1268 void
save_style_textbox(FILE * fp)1269 save_style_textbox(FILE *fp)
1270 {
1271     int bs;
1272     for (bs = 0; bs < NUM_TEXTBOX_STYLES; bs++) {
1273 	textbox_style *textbox = &textbox_opts[bs];
1274 	if (textbox->linewidth <= 0)
1275 	    continue;
1276 	fprintf(fp, "set style textbox ");
1277 	if (bs > 0)
1278 	    fprintf(fp,"%d ", bs);
1279 	fprintf(fp, " %s margins %4.1f, %4.1f",
1280 		textbox->opaque ? "opaque": "transparent",
1281 		textbox->xmargin, textbox->ymargin);
1282 	if (textbox->opaque) {
1283 	    fprintf(fp, " fc ");
1284 	    save_pm3dcolor(fp, &(textbox->fillcolor));
1285 	}
1286 	if (textbox->noborder) {
1287 	    fprintf(fp, " noborder");
1288 	} else {
1289 	    fprintf(fp, " border ");
1290 	    save_pm3dcolor(fp, &(textbox->border_color));
1291 	}
1292 	fprintf(fp, " linewidth %4.1f", textbox->linewidth);
1293 	fputs("\n",fp);
1294     }
1295 }
1296 
1297 void
save_position(FILE * fp,struct position * pos,int ndim,TBOOLEAN offset)1298 save_position(FILE *fp, struct position *pos, int ndim, TBOOLEAN offset)
1299 {
1300     if (offset) {
1301 	if (pos->x == 0 && pos->y == 0 && pos->z == 0)
1302 	    return;
1303 	fprintf(fp, " offset ");
1304     }
1305 
1306     /* Save in time coordinates if appropriate */
1307     if (pos->scalex == first_axes) {
1308 	save_num_or_time_input(fp, pos->x, &axis_array[FIRST_X_AXIS]);
1309     } else {
1310 	fprintf(fp, "%s%g", coord_msg[pos->scalex], pos->x);
1311     }
1312 
1313     if (ndim == 1)
1314 	return;
1315     else
1316 	fprintf(fp, ", ");
1317 
1318     if (pos->scaley == first_axes || pos->scalex == polar_axes) {
1319 	if (pos->scaley != pos->scalex) fprintf(fp, "first ");
1320 	save_num_or_time_input(fp, pos->y, &axis_array[FIRST_Y_AXIS]);
1321     } else {
1322 	fprintf(fp, "%s%g",
1323 	    pos->scaley == pos->scalex ? "" : coord_msg[pos->scaley], pos->y);
1324     }
1325 
1326     if (ndim == 2)
1327 	return;
1328     else
1329 	fprintf(fp, ", ");
1330 
1331     if (pos->scalez == first_axes) {
1332 	if (pos->scalez != pos->scaley) fprintf(fp, "first ");
1333 	save_num_or_time_input(fp, pos->z, &axis_array[FIRST_Z_AXIS]);
1334     } else {
1335 	fprintf(fp, "%s%g",
1336 	    pos->scalez == pos->scaley ? "" : coord_msg[pos->scalez], pos->z);
1337     }
1338 }
1339 
1340 
1341 void
save_prange(FILE * fp,struct axis * this_axis)1342 save_prange(FILE *fp, struct axis *this_axis)
1343 {
1344     TBOOLEAN noextend = FALSE;
1345 
1346     fprintf(fp, "set %srange [ ", axis_name(this_axis->index));
1347     if (this_axis->set_autoscale & AUTOSCALE_MIN) {
1348 	if (this_axis->min_constraint & CONSTRAINT_LOWER ) {
1349 	    save_num_or_time_input(fp, this_axis->min_lb, this_axis);
1350 	    fputs(" < ", fp);
1351 	}
1352 	putc('*', fp);
1353 	if (this_axis->min_constraint & CONSTRAINT_UPPER ) {
1354 	    fputs(" < ", fp);
1355 	    save_num_or_time_input(fp, this_axis->min_ub, this_axis);
1356 	}
1357     } else {
1358 	save_num_or_time_input(fp, this_axis->set_min, this_axis);
1359     }
1360     fputs(" : ", fp);
1361     if (this_axis->set_autoscale & AUTOSCALE_MAX) {
1362 	if (this_axis->max_constraint & CONSTRAINT_LOWER ) {
1363 	    save_num_or_time_input(fp, this_axis->max_lb, this_axis);
1364 	    fputs(" < ", fp);
1365 	}
1366 	putc('*', fp);
1367 	if (this_axis->max_constraint & CONSTRAINT_UPPER ) {
1368 	    fputs(" < ", fp);
1369 	    save_num_or_time_input(fp, this_axis->max_ub, this_axis);
1370 	}
1371     } else {
1372 	save_num_or_time_input(fp, this_axis->set_max, this_axis);
1373     }
1374 
1375     if (this_axis->index < PARALLEL_AXES)
1376 	fprintf(fp, " ] %sreverse %swriteback",
1377 	    ((this_axis->range_flags & RANGE_IS_REVERSED)) ? "" : "no",
1378 	    this_axis->range_flags & RANGE_WRITEBACK ? "" : "no");
1379     else
1380 	fprintf(fp, " ] ");
1381 
1382     if ((this_axis->set_autoscale & AUTOSCALE_FIXMIN)
1383     &&  (this_axis->set_autoscale & AUTOSCALE_FIXMAX)) {
1384 	fprintf(fp, " noextend");
1385 	noextend = TRUE;
1386     }
1387 
1388     if (this_axis->set_autoscale && fp == stderr) {
1389 	/* add current (hidden) range as comments */
1390 	fputs("  # (currently [", fp);
1391 	save_num_or_time_input(fp, this_axis->min, this_axis);
1392 	putc(':', fp);
1393 	save_num_or_time_input(fp, this_axis->max, this_axis);
1394 	fputs("] )\n", fp);
1395     } else
1396 	putc('\n', fp);
1397 
1398     if (!noextend && (fp != stderr)) {
1399 	if (this_axis->set_autoscale & (AUTOSCALE_FIXMIN))
1400 	    fprintf(fp, "set autoscale %sfixmin\n", axis_name(this_axis->index));
1401 	if (this_axis->set_autoscale & AUTOSCALE_FIXMAX)
1402 	    fprintf(fp, "set autoscale %sfixmax\n", axis_name(this_axis->index));
1403     }
1404 }
1405 
1406 void
save_link(FILE * fp,AXIS * this_axis)1407 save_link(FILE *fp, AXIS *this_axis)
1408 {
1409     if (this_axis->linked_to_primary
1410     &&  this_axis->index != -this_axis->linked_to_primary->index) {
1411 	fprintf(fp, "set link %s ", axis_name(this_axis->index));
1412 	if (this_axis->link_udf->at)
1413 	    fprintf(fp, "via %s ", this_axis->link_udf->definition);
1414 	if (this_axis->linked_to_primary->link_udf->at)
1415 	    fprintf(fp, "inverse %s ", this_axis->linked_to_primary->link_udf->definition);
1416 	fputs("\n", fp);
1417     }
1418 }
1419 
1420 void
save_nonlinear(FILE * fp,AXIS * this_axis)1421 save_nonlinear(FILE *fp, AXIS *this_axis)
1422 {
1423     AXIS *primary = this_axis->linked_to_primary;
1424 
1425     if (primary &&  this_axis->index == -primary->index) {
1426 	fprintf(fp, "set nonlinear %s ", axis_name(this_axis->index));
1427 	if (primary->link_udf->at)
1428 	    fprintf(fp, "via %s ", primary->link_udf->definition);
1429 	else
1430 	    fprintf(stderr, "[corrupt linkage] ");
1431 	if (this_axis->link_udf->at)
1432 	    fprintf(fp, "inverse %s ", this_axis->link_udf->definition);
1433 	else
1434 	    fprintf(stderr, "[corrupt linkage] ");
1435 	fputs("\n", fp);
1436     }
1437 }
1438 
1439 static void
save_zeroaxis(FILE * fp,AXIS_INDEX axis)1440 save_zeroaxis(FILE *fp, AXIS_INDEX axis)
1441 {
1442     if (axis_array[axis].zeroaxis == NULL) {
1443 	fprintf(fp, "unset %szeroaxis", axis_name(axis));
1444     } else {
1445 	fprintf(fp, "set %szeroaxis", axis_name(axis));
1446 	if (axis_array[axis].zeroaxis != &default_axis_zeroaxis)
1447 	    save_linetype(fp, axis_array[axis].zeroaxis, FALSE);
1448     }
1449     putc('\n', fp);
1450 }
1451 
1452 void
save_fillstyle(FILE * fp,const struct fill_style_type * fs)1453 save_fillstyle(FILE *fp, const struct fill_style_type *fs)
1454 {
1455     switch(fs->fillstyle) {
1456     case FS_SOLID:
1457     case FS_TRANSPARENT_SOLID:
1458 	fprintf(fp, " %s solid %.2f ",
1459 		fs->fillstyle == FS_SOLID ? "" : "transparent",
1460 		fs->filldensity / 100.0);
1461 	break;
1462     case FS_PATTERN:
1463     case FS_TRANSPARENT_PATTERN:
1464 	fprintf(fp, " %s pattern %d ",
1465 		fs->fillstyle == FS_PATTERN ? "" : "transparent",
1466 		fs->fillpattern);
1467 	break;
1468     case FS_DEFAULT:
1469 	fprintf(fp, " default\n");
1470 	return;
1471     default:
1472 	fprintf(fp, " empty ");
1473 	break;
1474     }
1475     if (fs->border_color.type == TC_LT && fs->border_color.lt == LT_NODRAW) {
1476 	fprintf(fp, "noborder\n");
1477     } else {
1478 	fprintf(fp, "border");
1479 	save_pm3dcolor(fp, &fs->border_color);
1480 	fprintf(fp, "\n");
1481     }
1482 }
1483 
1484 void
save_textcolor(FILE * fp,const struct t_colorspec * tc)1485 save_textcolor(FILE *fp, const struct t_colorspec *tc)
1486 {
1487     if (tc->type) {
1488 	fprintf(fp, " textcolor");
1489 	if (tc->type == TC_VARIABLE)
1490 	    fprintf(fp, " variable");
1491 	else
1492 	    save_pm3dcolor(fp, tc);
1493     }
1494 }
1495 
1496 
1497 void
save_pm3dcolor(FILE * fp,const struct t_colorspec * tc)1498 save_pm3dcolor(FILE *fp, const struct t_colorspec *tc)
1499 {
1500     if (tc->type) {
1501 	switch(tc->type) {
1502 	case TC_LT:   if (tc->lt == LT_NODRAW)
1503 			fprintf(fp," nodraw");
1504 		      else if (tc->lt == LT_BACKGROUND)
1505 			fprintf(fp," bgnd");
1506 		      else
1507 			fprintf(fp," lt %d", tc->lt+1);
1508 		      break;
1509 	case TC_LINESTYLE:   fprintf(fp," linestyle %d", tc->lt);
1510 		      break;
1511 	case TC_Z:    fprintf(fp," palette z");
1512 		      break;
1513 	case TC_CB:   fprintf(fp," palette cb %g", tc->value);
1514 		      break;
1515 	case TC_FRAC: fprintf(fp," palette fraction %4.2f", tc->value);
1516 		      break;
1517 	case TC_RGB:  {
1518 		      const char *color = reverse_table_lookup(pm3d_color_names_tbl, tc->lt);
1519 		      if (tc->value < 0)
1520 		  	fprintf(fp," rgb variable ");
1521 		      else if (color)
1522 	    		fprintf(fp," rgb \"%s\" ", color);
1523 		      else
1524 	    		fprintf(fp," rgb \"#%6.6x\" ", tc->lt);
1525 		      break;
1526 	    	      }
1527 	default:      break;
1528 	}
1529     }
1530 }
1531 
1532 void
save_data_func_style(FILE * fp,const char * which,enum PLOT_STYLE style)1533 save_data_func_style(FILE *fp, const char *which, enum PLOT_STYLE style)
1534 {
1535     char *answer = strdup(reverse_table_lookup(plotstyle_tbl, style));
1536     char *idollar = strchr(answer, '$');
1537     if (idollar) {
1538 	do {
1539 	    *idollar = *(idollar+1);
1540 	    idollar++;
1541 	} while (*idollar);
1542 
1543     }
1544     fputs(answer, fp);
1545     free(answer);
1546 
1547     if (style == FILLEDCURVES) {
1548 	fputs(" ", fp);
1549 	if (!strcmp(which, "data") || !strcmp(which, "Data"))
1550 	    filledcurves_options_tofile(&filledcurves_opts_data, fp);
1551 	else
1552 	    filledcurves_options_tofile(&filledcurves_opts_func, fp);
1553     }
1554     fputc('\n', fp);
1555 }
1556 
1557 void
save_dashtype(FILE * fp,int d_type,const t_dashtype * dt)1558 save_dashtype(FILE *fp, int d_type, const t_dashtype *dt)
1559 {
1560     /* this is indicated by LT_AXIS (lt 0) instead */
1561     if (d_type == DASHTYPE_AXIS)
1562 	return;
1563 
1564     fprintf(fp, " dashtype");
1565     if (d_type == DASHTYPE_CUSTOM) {
1566 	if (dt->dstring[0] != '\0')
1567 	    fprintf(fp, " \"%s\"", dt->dstring);
1568 	if (fp == stderr || dt->dstring[0] == '\0') {
1569 	    int i;
1570 	    fputs(" (", fp);
1571 	    for (i = 0; i < DASHPATTERN_LENGTH && dt->pattern[i] > 0; i++)
1572 		fprintf(fp, i ? ", %.2f" : "%.2f", dt->pattern[i]);
1573 	    fputs(")", fp);
1574 	}
1575     } else if (d_type == DASHTYPE_SOLID) {
1576 	fprintf(fp, " solid");
1577     } else {
1578 	fprintf(fp, " %d", d_type + 1);
1579     }
1580 }
1581 
1582 void
save_linetype(FILE * fp,lp_style_type * lp,TBOOLEAN show_point)1583 save_linetype(FILE *fp, lp_style_type *lp, TBOOLEAN show_point)
1584 {
1585     if (lp->l_type == LT_NODRAW)
1586 	fprintf(fp, " lt nodraw");
1587     else if (lp->l_type == LT_BACKGROUND)
1588 	fprintf(fp, " lt bgnd");
1589     else if (lp->l_type == LT_DEFAULT)
1590 	; /* Dont' print anything */
1591     else if (lp->l_type == LT_AXIS)
1592 	fprintf(fp, " lt 0");
1593 
1594     if (lp->l_type == LT_BLACK && lp->pm3d_color.type == TC_LT)
1595 	fprintf(fp, " lt black");
1596     else if (lp->pm3d_color.type != TC_DEFAULT) {
1597 	fprintf(fp, " linecolor");
1598 	if (lp->pm3d_color.type == TC_LT)
1599 	    fprintf(fp, " %d", lp->pm3d_color.lt+1);
1600 	else if (lp->pm3d_color.type == TC_LINESTYLE && lp->l_type == LT_COLORFROMCOLUMN)
1601 	    fprintf(fp, " variable");
1602 	else
1603 	    save_pm3dcolor(fp,&(lp->pm3d_color));
1604     }
1605     fprintf(fp, " linewidth %.3f", lp->l_width);
1606 
1607     save_dashtype(fp, lp->d_type, &lp->custom_dash_pattern);
1608 
1609     if (show_point) {
1610 	if (lp->p_type == PT_CHARACTER)
1611 	    fprintf(fp, " pointtype \"%s\"", lp->p_char);
1612 	else if (lp->p_type == PT_VARIABLE)
1613 	    fprintf(fp, " pointtype variable");
1614 	else
1615 	    fprintf(fp, " pointtype %d", lp->p_type + 1);
1616 	if (lp->p_size == PTSZ_VARIABLE)
1617 	    fprintf(fp, " pointsize variable");
1618 	else if (lp->p_size == PTSZ_DEFAULT)
1619 	    fprintf(fp, " pointsize default");
1620 	else
1621 	    fprintf(fp, " pointsize %.3f", lp->p_size);
1622 	if (lp->p_interval != 0)
1623 	    fprintf(fp, " pointinterval %d", lp->p_interval);
1624 	if (lp->p_number != 0)
1625 	    fprintf(fp, " pointnumber %d", lp->p_number);
1626     }
1627 
1628 }
1629 
1630 
1631 void
save_offsets(FILE * fp,char * lead)1632 save_offsets(FILE *fp, char *lead)
1633 {
1634     fprintf(fp, "%s %s%g, %s%g, %s%g, %s%g\n", lead,
1635 	loff.scalex == graph ? "graph " : "", loff.x,
1636 	roff.scalex == graph ? "graph " : "", roff.x,
1637 	toff.scaley == graph ? "graph " : "", toff.y,
1638 	boff.scaley == graph ? "graph " : "", boff.y);
1639 }
1640 
1641 void
save_bars(FILE * fp)1642 save_bars(FILE *fp)
1643 {
1644     if (bar_size == 0.0) {
1645 	fprintf(fp, "unset errorbars\n");
1646 	return;
1647     }
1648     fprintf(fp, "set errorbars %s", (bar_layer == LAYER_BACK) ? "back" : "front");
1649     if (bar_size > 0.0)
1650 	fprintf(fp, " %f ", bar_size);
1651     else
1652 	fprintf(fp," fullwidth ");
1653     if ((bar_lp.flags & LP_ERRORBAR_SET) != 0)
1654 	save_linetype(fp, &bar_lp, FALSE);
1655     fputs("\n",fp);
1656 }
1657 
1658 void
save_histogram_opts(FILE * fp)1659 save_histogram_opts (FILE *fp)
1660 {
1661     switch (histogram_opts.type) {
1662 	default:
1663 	case HT_CLUSTERED:
1664 	    fprintf(fp,"clustered gap %d ",histogram_opts.gap); break;
1665 	case HT_ERRORBARS:
1666 	    fprintf(fp,"errorbars gap %d lw %g",histogram_opts.gap,histogram_opts.bar_lw); break;
1667 	case HT_STACKED_IN_LAYERS:
1668 	    fprintf(fp,"rowstacked "); break;
1669 	case HT_STACKED_IN_TOWERS:
1670 	    fprintf(fp,"columnstacked "); break;
1671     }
1672     if (fp == stderr)
1673 	fprintf(fp,"\n\t\t");
1674     fprintf(fp,"title");
1675     save_textcolor(fp, &histogram_opts.title.textcolor);
1676     if (histogram_opts.title.font)
1677 	fprintf(fp, " font \"%s\" ", histogram_opts.title.font);
1678     save_position(fp, &histogram_opts.title.offset, 2, TRUE);
1679     fprintf(fp, "\n");
1680 }
1681 
1682 void
save_pixmaps(FILE * fp)1683 save_pixmaps(FILE *fp)
1684 {
1685     t_pixmap *pixmap;
1686     for (pixmap = pixmap_listhead; pixmap; pixmap = pixmap->next) {
1687 	fprintf(fp, "set pixmap %d '%s' # (%d x %d pixmap)\n",
1688 		pixmap->tag, pixmap->filename, pixmap->ncols, pixmap->nrows);
1689 	fprintf(fp, "set pixmap %d at ", pixmap->tag);
1690 	save_position(fp,&pixmap->pin, 3, FALSE);
1691 	fprintf(fp, "  size ");
1692 	save_position(fp,&pixmap->extent, 2, FALSE);
1693 	fprintf(fp, " %s %s\n",
1694 		pixmap->layer == LAYER_FRONT ? "front" : "behind",
1695 		pixmap->center ? "center" : "");
1696     }
1697 }
1698 
1699 /* Save/show rectangle <tag> (0 means show all) */
1700 void
save_object(FILE * fp,int tag)1701 save_object(FILE *fp, int tag)
1702 {
1703     t_object *this_object;
1704     t_rectangle *this_rect;
1705     t_circle *this_circle;
1706     t_ellipse *this_ellipse;
1707     TBOOLEAN showed = FALSE;
1708 
1709     for (this_object = first_object; this_object != NULL; this_object = this_object->next) {
1710 	if ((this_object->object_type == OBJ_RECTANGLE)
1711 	    && (tag == 0 || tag == this_object->tag)) {
1712 	    this_rect = &this_object->o.rectangle;
1713 	    showed = TRUE;
1714 	    fprintf(fp, "%sobject %2d rect ", (fp==stderr) ? "\t" : "set ",this_object->tag);
1715 
1716 	    if (this_rect->type == 1) {
1717 		fprintf(fp, "center ");
1718 		save_position(fp, &this_rect->center, 2, FALSE);
1719 		fprintf(fp, " size ");
1720 		save_position(fp, &this_rect->extent, 2, FALSE);
1721 	    } else {
1722 		fprintf(fp, "from ");
1723 		save_position(fp, &this_rect->bl, 2, FALSE);
1724 		fprintf(fp, " to ");
1725 		save_position(fp, &this_rect->tr, 2, FALSE);
1726 	    }
1727 	}
1728 
1729 	else if ((this_object->object_type == OBJ_CIRCLE)
1730 	    && (tag == 0 || tag == this_object->tag)) {
1731 	    struct position *e = &this_object->o.circle.extent;
1732 	    this_circle = &this_object->o.circle;
1733 	    showed = TRUE;
1734 	    fprintf(fp, "%sobject %2d circle ", (fp==stderr) ? "\t" : "set ",this_object->tag);
1735 
1736 	    fprintf(fp, "center ");
1737 	    save_position(fp, &this_circle->center, 3, FALSE);
1738 	    fprintf(fp, " size ");
1739 	    fprintf(fp, "%s%g", e->scalex == first_axes ? "" : coord_msg[e->scalex], e->x);
1740 	    fprintf(fp, " arc [%g:%g] ", this_circle->arc_begin, this_circle->arc_end);
1741 	    fprintf(fp, this_circle->wedge ? "wedge " : "nowedge");
1742 	}
1743 
1744 	else if ((this_object->object_type == OBJ_ELLIPSE)
1745 	    && (tag == 0 || tag == this_object->tag)) {
1746 	    struct position *e = &this_object->o.ellipse.extent;
1747 	    this_ellipse = &this_object->o.ellipse;
1748 	    showed = TRUE;
1749 	    fprintf(fp, "%sobject %2d ellipse ", (fp==stderr) ? "\t" : "set ",this_object->tag);
1750 	    fprintf(fp, "center ");
1751 	    save_position(fp, &this_ellipse->center, 3, FALSE);
1752 	    fprintf(fp, " size ");
1753 	    fprintf(fp, "%s%g", e->scalex == first_axes ? "" : coord_msg[e->scalex], e->x);
1754 	    fprintf(fp, ", %s%g", e->scaley == e->scalex ? "" : coord_msg[e->scaley], e->y);
1755 	    fprintf(fp, "  angle %g", this_ellipse->orientation);
1756 	    fputs(" units ", fp);
1757 	    switch (this_ellipse->type) {
1758 		case ELLIPSEAXES_XY:
1759 		    fputs("xy", fp);
1760 		    break;
1761 		case ELLIPSEAXES_XX:
1762 		    fputs("xx", fp);
1763 		    break;
1764 		case ELLIPSEAXES_YY:
1765 		    fputs("yy", fp);
1766 		    break;
1767 	    }
1768 	}
1769 
1770 	else if ((this_object->object_type == OBJ_POLYGON)
1771 	    && (tag == 0 || tag == this_object->tag)) {
1772 	    t_polygon *this_polygon = &this_object->o.polygon;
1773 	    int nv;
1774 	    showed = TRUE;
1775 	    fprintf(fp, "%sobject %2d polygon ", (fp==stderr) ? "\t" : "set ",this_object->tag);
1776 	    if (this_polygon->vertex) {
1777 		fprintf(fp, "from ");
1778 		save_position(fp, &this_polygon->vertex[0], 3, FALSE);
1779 	    }
1780 	    for (nv=1; nv < this_polygon->type; nv++) {
1781 		fprintf(fp, (fp==stderr) ? "\n\t\t\t    to " : " to ");
1782 		save_position(fp, &this_polygon->vertex[nv], 3, FALSE);
1783 	    }
1784 	}
1785 
1786 	/* Properties common to all objects */
1787 	if (tag == 0 || tag == this_object->tag) {
1788 	    fprintf(fp, "\n%sobject %2d ", (fp==stderr) ? "\t" : "set ",this_object->tag);
1789 	    fprintf(fp, "%s ", this_object->layer == LAYER_FRONT ? "front" :
1790 				this_object->layer == LAYER_DEPTHORDER ? "depthorder" :
1791 				this_object->layer == LAYER_BEHIND ? "behind" :
1792 				"back");
1793 	    if (this_object->clip == OBJ_NOCLIP)
1794 		fputs("noclip ", fp);
1795 	    else
1796 		fputs("clip ", fp);
1797 
1798 	    if (this_object->lp_properties.l_width)
1799 		    fprintf(fp, "lw %.1f ",this_object->lp_properties.l_width);
1800 	    if (this_object->lp_properties.d_type)
1801 		    save_dashtype(fp, this_object->lp_properties.d_type,
1802 					&this_object->lp_properties.custom_dash_pattern);
1803 	    fprintf(fp, " fc ");
1804 	    if (this_object->lp_properties.l_type == LT_DEFAULT)
1805 		    fprintf(fp,"default");
1806 	    else
1807 		    save_pm3dcolor(fp, &this_object->lp_properties.pm3d_color);
1808 	    fprintf(fp, " fillstyle ");
1809 	    save_fillstyle(fp, &this_object->fillstyle);
1810 	}
1811 
1812     }
1813     if (tag > 0 && !showed)
1814 	int_error(c_token, "object not found");
1815 }
1816 
1817 /* Save/show special polygon objects created by "set wall" */
1818 void
save_walls(FILE * fp)1819 save_walls(FILE *fp)
1820 {
1821     static const char* wall_name[5] = {"y0", "x0", "y1", "x1", "z0"};
1822     t_object *this_object;
1823     int i;
1824 
1825     for (i = 0; i < 5; i++) {
1826     	this_object = &grid_wall[i];
1827 	if (this_object->layer == LAYER_FRONTBACK) {
1828 	    fprintf(fp, "set wall %s ", wall_name[i]);
1829 	    fprintf(fp, " fc ");
1830 	    save_pm3dcolor(fp, &this_object->lp_properties.pm3d_color);
1831 	    fprintf(fp, " fillstyle ");
1832 	    save_fillstyle(fp, &this_object->fillstyle);
1833 	}
1834 
1835     }
1836 }
1837 
1838