1
2 /* addendum to session.c, for handling the saving of session info to
3 an XML file, and the re-building of a session from same.
4 */
5
6 #include "usermat.h"
7 #include "boxplots.h"
8 #include "libset.h"
9
check_graph_file(const char * fname,int type)10 static int check_graph_file (const char *fname, int type)
11 {
12 char fullname[MAXLEN];
13 FILE *fp;
14 int err = 0;
15
16 session_file_make_path(fullname, fname);
17 fp = gretl_fopen(fullname, "r");
18
19 if (fp == NULL) {
20 file_read_errbox(fname);
21 err = 1;
22 } else {
23 fprintf(stderr, "Opened '%s' OK\n", fullname);
24 if (type == GRETL_OBJ_PLOT) {
25 char line[32] = {0};
26
27 if (fgets(line, sizeof line, fp) != NULL) {
28 if (!strncmp(line, "# boxplot generated", 19)) {
29 fprintf(stderr, "Ignoring old boxplot file\n");
30 err = 1;
31 }
32 } else {
33 err = 1;
34 }
35 fclose(fp);
36 } else {
37 fclose(fp);
38 }
39 }
40
41 return err;
42 }
43
44 /* Arrange things so that when a session file is opened, any graph
45 files are numbered consecutively, starting at 1. This avoids a
46 situation where adding a graph to an existing session results in
47 over-writing an existing graph file. (The graph files in a saved
48 session may not be numbered consecutively if some graphs were
49 initially saved, then deleted; and it's easier to fix this on
50 opening a session file than on saving one, since on opening we're
51 constructing the graph list de novo.)
52 */
53
normalize_graph_filename(char * fname,int gnum)54 static void normalize_graph_filename (char *fname, int gnum)
55 {
56 char s[16];
57 int i;
58
59 if (sscanf(fname, "%15[^.].%d", s, &i) == 2) {
60 char oldname[MAXLEN];
61 char newname[MAXLEN];
62 gchar *tmp = NULL;
63
64 if (i != gnum && (!strcmp(s, "graph") || !strcmp(s, "plot"))) {
65 session_file_make_path(oldname, fname);
66 tmp = g_strdup_printf("graph.%d", gnum);
67 session_file_make_path(newname, tmp);
68 }
69
70 if (tmp != NULL) {
71 gretl_rename(oldname, newname);
72 strcpy(fname, tmp);
73 g_free(tmp);
74 }
75 }
76 }
77
restore_session_graphs(xmlNodePtr node)78 static int restore_session_graphs (xmlNodePtr node)
79 {
80 xmlNodePtr cur;
81 int gnum = 0;
82 int errs = 0;
83
84 /* reset prior to parsing */
85 session.ngraphs = 0;
86
87 cur = node->xmlChildrenNode;
88
89 fprintf(stderr, "Doing restore_session_graphs\n");
90
91 while (cur != NULL) {
92 SESSION_GRAPH *sg;
93 xmlChar *name = NULL;
94 xmlChar *fname = NULL;
95 int type, err = 0;
96
97 name = xmlGetProp(cur, (XUC) "name");
98 if (name == NULL) {
99 err = 1;
100 }
101
102 if (!err && !gretl_xml_get_prop_as_int(cur, "type", &type)) {
103 err = 1;
104 }
105
106 if (!err) {
107 fname = xmlGetProp(cur, (XUC) "fname");
108 if (fname == NULL) {
109 err = 1;
110 } else {
111 fprintf(stderr, "checking '%s'\n", name);
112 err = check_graph_file((const char *) fname, type);
113 if (!err) {
114 normalize_graph_filename((char *) fname, ++gnum);
115 }
116 }
117 }
118
119 if (!err) {
120 sg = session_append_graph((const char *) name,
121 (const char *) fname,
122 type);
123 err = (sg == NULL);
124 }
125
126 if (!err) {
127 int inpage, has_datafile;
128
129 if (gretl_xml_get_prop_as_int(cur, "inpage", &inpage)) {
130 graph_page_add_file((const char *) fname); /* FIXME path? */
131 }
132 if (gretl_xml_get_prop_as_int(cur, "has_datafile", &has_datafile)) {
133 sg->has_datafile = 1;
134 }
135 }
136
137 if (err) {
138 errs++;
139 }
140
141 free(name);
142 free(fname);
143
144 cur = cur->next;
145 }
146
147 return errs;
148 }
149
restore_session_texts(xmlNodePtr node,xmlDocPtr doc)150 static int restore_session_texts (xmlNodePtr node, xmlDocPtr doc)
151 {
152 xmlNodePtr cur;
153 int errs = 0;
154
155 session.ntexts = 0;
156
157 cur = node->xmlChildrenNode;
158
159 while (cur != NULL) {
160 xmlChar *name = NULL;
161 xmlChar *buf = NULL;
162 int err = 0;
163
164 name = xmlGetProp(cur, (XUC) "name");
165 if (name == NULL) {
166 err = 1;
167 } else {
168 buf = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
169 if (buf == NULL) {
170 err = 1;
171 } else {
172 err = session_append_text((const char *) name,
173 (char *) buf);
174 }
175 }
176
177 if (err) {
178 errs++;
179 }
180
181 free(name);
182
183 cur = cur->next;
184 }
185
186 return errs;
187 }
188
data_submask_from_xml(xmlNodePtr node,xmlDocPtr doc,struct sample_info * sinfo)189 static int data_submask_from_xml (xmlNodePtr node, xmlDocPtr doc,
190 struct sample_info *sinfo)
191 {
192 char *mask;
193 int err;
194
195 err = gretl_xml_get_submask(node, doc, &mask);
196 if (!err) {
197 sinfo->mask = mask;
198 }
199
200 return err;
201 }
202
data_restrict_from_xml(xmlNodePtr node,xmlDocPtr doc,struct sample_info * sinfo)203 static int data_restrict_from_xml (xmlNodePtr node, xmlDocPtr doc,
204 struct sample_info *sinfo)
205 {
206 char *s = NULL;
207
208 if (gretl_xml_node_get_trimmed_string(node, doc, &s)) {
209 sinfo->restriction = s;
210 }
211
212 return 0;
213 }
214
rebuild_session_model(const char * fname,const char * name,GretlObjType type,int tablepos)215 static int rebuild_session_model (const char *fname,
216 const char *name,
217 GretlObjType type,
218 int tablepos)
219 {
220 gpointer ptr = NULL;
221 SavedObjectFlags flags = 0;
222 xmlDocPtr doc;
223 xmlNodePtr node;
224 int iflag, err;
225
226 err = gretl_xml_open_doc_root(fname,
227 (type == GRETL_OBJ_EQN)? "gretl-model" :
228 (type == GRETL_OBJ_VAR)? "gretl-VAR" :
229 "gretl-equation-system", &doc, &node);
230 if (err) {
231 return err;
232 }
233
234 if (gretl_xml_get_prop_as_int(node, "saveflags", &iflag)) {
235 flags = iflag;
236 } else {
237 flags = IN_GUI_SESSION | IN_NAMED_STACK;
238 }
239
240 if (type == GRETL_OBJ_EQN) {
241 ptr = gretl_model_from_XML(node, doc, dataset, &err);
242 } else if (type == GRETL_OBJ_VAR) {
243 ptr = gretl_VAR_from_XML(node, doc, dataset, &err);
244 } else {
245 ptr = equation_system_from_XML(node, doc, &err);
246 }
247
248 xmlFreeDoc(doc);
249
250 if (!err && ptr != NULL) {
251 #if 1
252 fprintf(stderr, "rebuild_session_model: IN_GUI_SESSION %s, IN_MODEL_TABLE %s\n"
253 " IN_NAMED_STACK %s, IS_LAST_MODEL %s\n",
254 (flags & IN_GUI_SESSION)? "yes" : "no",
255 (flags & IN_MODEL_TABLE)? "yes" : "no",
256 (flags & IN_NAMED_STACK)? "yes" : "no",
257 (flags & IS_LAST_MODEL)? "yes" : "no");
258 #endif
259
260 if (flags & IN_GUI_SESSION) {
261 SESSION_MODEL *smod;
262
263 smod = session_model_new(ptr, name, type);
264 if (smod == NULL) {
265 fprintf(stderr, "error from session_model_new\n");
266 err = E_ALLOC;
267 } else {
268 err = session_append_model(smod);
269 fprintf(stderr, "error %d from session_append_model\n", err);
270 }
271 }
272
273 if (!err && (flags & IN_MODEL_TABLE)) {
274 add_to_model_table(ptr, MODEL_ADD_BY_CMD, tablepos, NULL);
275 }
276
277 if (!err && (flags & IN_NAMED_STACK)) {
278 err = gretl_stack_object(ptr, type);
279 }
280
281 if (!err && (flags & IS_LAST_MODEL)) {
282 set_as_last_model(ptr, type);
283 }
284 }
285
286 /* need to clean up on error here (also: clean up XML parser?) */
287
288 return err;
289 }
290
restore_session_models(xmlNodePtr node,xmlDocPtr doc)291 static int restore_session_models (xmlNodePtr node, xmlDocPtr doc)
292 {
293 char fullname[MAXLEN];
294 xmlNodePtr cur;
295 int errs = 0;
296
297 /* reset prior to parsing */
298 session.nmodels = 0;
299
300 cur = node->xmlChildrenNode;
301
302 while (cur != NULL) {
303 xmlChar *fname = NULL;
304 xmlChar *name = NULL;
305 int type = GRETL_OBJ_EQN;
306 int tablepos = 0;
307 int err = 0;
308
309 fname = xmlGetProp(cur, (XUC) "fname");
310 if (fname == NULL) {
311 err = 1;
312 } else {
313 name = xmlGetProp(cur, (XUC) "name");
314 if (name == NULL) {
315 err = 1;
316 }
317 }
318
319 if (!err) {
320 session_file_make_path(fullname, (const char *) fname);
321 gretl_xml_get_prop_as_int(cur, "type", &type);
322 if (type == GRETL_OBJ_EQN) {
323 gretl_xml_get_prop_as_int(cur, "tablepos", &tablepos);
324 }
325 fprintf(stderr, "model file: fname='%s', type=%d\n", fullname, type);
326 err = rebuild_session_model(fullname, (const char *) name,
327 type, tablepos);
328 }
329
330 if (!err) {
331 model_count_plus();
332 } else {
333 fprintf(stderr, "rebuild_session_model: failed on %s (err = %d)\n",
334 fullname, err);
335 errs++;
336 }
337
338 free(fname);
339 free(name);
340
341 cur = cur->next;
342 }
343
344 #if SESSION_DEBUG
345 fprintf(stderr, "restore_session_models: %d errors\n", errs);
346 #endif
347
348 return errs;
349 }
350
351 /* peek inside the session file and retrieve the name of the
352 data file, only */
353
get_session_datafile_name(const char * fname,struct sample_info * sinfo,int * nodata)354 static int get_session_datafile_name (const char *fname, struct sample_info *sinfo,
355 int *nodata)
356 {
357 xmlDocPtr doc = NULL;
358 xmlNodePtr cur = NULL;
359 xmlChar *tmp;
360 int err = 0;
361
362 err = gretl_xml_open_doc_root(fname, "gretl-session", &doc, &cur);
363 if (err) {
364 gui_errmsg(err);
365 return 1;
366 }
367
368 /* read datafile attribute, if present */
369 tmp = xmlGetProp(cur, (XUC) "datafile");
370 if (tmp != NULL) {
371 if (!strcmp((const char *) tmp, "none")) {
372 *nodata = 1;
373 } else {
374 strcpy(sinfo->datafile, (char *) tmp);
375 }
376 free(tmp);
377 }
378
379 if (doc != NULL) {
380 xmlFreeDoc(doc);
381 }
382
383 return err;
384 }
385
386 /* (having previously grabbed the data file name) get the rest
387 of the info from session.xml */
388
389 static int
read_session_xml(const char * fname,struct sample_info * sinfo)390 read_session_xml (const char *fname, struct sample_info *sinfo)
391 {
392 xmlDocPtr doc = NULL;
393 xmlNodePtr cur = NULL;
394 xmlChar *tmp;
395 int object_errs = 0;
396 int err = 0;
397
398 err = gretl_xml_open_doc_root(fname, "gretl-session", &doc, &cur);
399 if (err) {
400 gui_errmsg(err);
401 return err;
402 }
403
404 /* Now walk the tree */
405 cur = cur->xmlChildrenNode;
406 while (cur != NULL && !err) {
407 if (!xmlStrcmp(cur->name, (XUC) "sample")) {
408 tmp = xmlGetProp(cur, (XUC) "t1");
409 if (tmp != NULL) {
410 sinfo->t1 = atoi((const char *) tmp);
411 free(tmp);
412 } else {
413 err = 1;
414 }
415 tmp = xmlGetProp(cur, (XUC) "t2");
416 if (tmp != NULL) {
417 sinfo->t2 = atoi((const char *) tmp);
418 free(tmp);
419 } else {
420 err = 1;
421 }
422 } else if (!xmlStrcmp(cur->name, (XUC) "submask")) {
423 err = data_submask_from_xml(cur, doc, sinfo);
424 } else if (!xmlStrcmp(cur->name, (XUC) "restriction")) {
425 err = data_restrict_from_xml(cur, doc, sinfo);
426 } else if (!xmlStrcmp(cur->name, (XUC) "resample")) {
427 tmp = xmlGetProp(cur, (XUC) "seed");
428 if (tmp != NULL) {
429 sinfo->seed = (unsigned) atoi((const char *) tmp);
430 free(tmp);
431 }
432 tmp = xmlGetProp(cur, (XUC) "n");
433 if (tmp != NULL) {
434 sinfo->resample_n = atoi((const char *) tmp);
435 free(tmp);
436 }
437 if (sinfo->resample_n <= 0) {
438 sinfo->seed = 0;
439 sinfo->resample_n = 0;
440 }
441 } else if (!xmlStrcmp(cur->name, (XUC) "models")) {
442 tmp = xmlGetProp(cur, (XUC) "count");
443 if (tmp != NULL) {
444 session.nmodels = atoi((const char *) tmp);
445 free(tmp);
446 if (session.nmodels > 0) {
447 object_errs += restore_session_models(cur, doc);
448 }
449 }
450 } else if (!xmlStrcmp(cur->name, (XUC) "graphs")) {
451 tmp = xmlGetProp(cur, (XUC) "count");
452 if (tmp != NULL) {
453 session.ngraphs = atoi((const char *) tmp);
454 free(tmp);
455 if (session.ngraphs > 0) {
456 object_errs += restore_session_graphs(cur);
457 }
458 }
459 } else if (!xmlStrcmp(cur->name, (XUC) "texts")) {
460 tmp = xmlGetProp(cur, (XUC) "count");
461 if (tmp != NULL) {
462 session.ntexts = atoi((const char *) tmp);
463 free(tmp);
464 if (session.ntexts > 0) {
465 object_errs += restore_session_texts(cur, doc);
466 }
467 }
468 } else if (!xmlStrcmp(cur->name, (XUC) "notes")) {
469 session.notes =
470 (char *) xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
471 if (session.notes == NULL) {
472 object_errs++;
473 } else {
474 tmp = xmlGetProp(cur, (XUC) "auto-show");
475 if (tmp != NULL) {
476 session.show_notes = 1;
477 free(tmp);
478 }
479 }
480 }
481 if (!err) {
482 cur = cur->next;
483 }
484 }
485
486 if (doc != NULL) {
487 xmlFreeDoc(doc);
488 }
489
490 if (!err && object_errs > 0) {
491 errbox_printf("%d session object(s) could not be rebuilt", object_errs);
492 }
493
494 return err;
495 }
496
maybe_read_functions_file(const char * fname)497 static int maybe_read_functions_file (const char *fname)
498 {
499 FILE *fp;
500
501 fp = gretl_fopen(fname, "r");
502 if (fp == NULL) {
503 /* nothing to be read */
504 return 0;
505 }
506
507 fclose(fp);
508
509 return read_session_functions_file(fname);
510 }
511
maybe_read_settings_file(const char * fname)512 static int maybe_read_settings_file (const char *fname)
513 {
514 FILE *fp;
515
516 fp = gretl_fopen(fname, "r");
517 if (fp == NULL) {
518 /* nothing to be read */
519 return 0;
520 }
521
522 fclose(fp);
523
524 return libset_read_script(fname);
525 }
526
model_in_session(const void * ptr)527 static int model_in_session (const void *ptr)
528 {
529 int i;
530
531 for (i=0; i<session.nmodels; i++) {
532 if (session.models[i]->ptr == ptr) {
533 return 1;
534 }
535 }
536
537 return 0;
538 }
539
model_save_flags(const void * ptr,GretlObjType type)540 static SavedObjectFlags model_save_flags (const void *ptr,
541 GretlObjType type)
542 {
543 SavedObjectFlags flags = 0;
544
545 if (model_in_session(ptr)) {
546 flags |= IN_GUI_SESSION;
547 }
548
549 if (object_is_on_stack(ptr)) {
550 flags |= IN_NAMED_STACK;
551 }
552
553 if (get_last_model(NULL) == ptr) {
554 flags |= IS_LAST_MODEL;
555 }
556
557 if (type == GRETL_OBJ_EQN && in_model_table(ptr)) {
558 flags |= IN_MODEL_TABLE;
559 }
560
561 return flags;
562 }
563
maybe_write_function_file(char * fullname)564 static int maybe_write_function_file (char *fullname)
565 {
566 session_file_make_path(fullname, "functions.xml");
567 return write_loaded_functions_file(fullname, 0);
568 }
569
write_settings_file(char * fullname)570 static int write_settings_file (char *fullname)
571 {
572 session_file_make_path(fullname, "settings.inp");
573 return libset_write_script(fullname);
574 }
575
get_xmlname(char * objname,int * err)576 static char *get_xmlname (char *objname, int *err)
577 {
578 char *ret;
579
580 if (gretl_xml_validate(objname)) {
581 ret = objname;
582 } else {
583 ret = gretl_xml_encode(objname);
584 if (ret == NULL) {
585 *err = E_ALLOC;
586 }
587 }
588
589 return ret;
590 }
591
session_graph_wanted(const char * fname)592 static int session_graph_wanted (const char *fname)
593 {
594 int i;
595
596 for (i=0; i<session.ngraphs; i++) {
597 if (!strcmp(session.graphs[i]->fname, fname)) {
598 return 1;
599 }
600 }
601
602 return 0;
603 }
604
605 /* on re-saving a session, avoid keeping model files for
606 models that have been dropped from the session, and
607 similarly for graph files
608 */
609
trash_old_session_files(const char * path)610 static void trash_old_session_files (const char *path)
611 {
612 GDir *sdir = gretl_opendir(path);
613
614 if (sdir != NULL) {
615 const gchar *dname;
616 char tmp[2*MAXLEN];
617 int fnum;
618
619 while ((dname = g_dir_read_name(sdir)) != NULL) {
620 if (!strncmp(dname, "model.", 6)) {
621 fnum = atoi(dname + 6);
622 sprintf(tmp, "model.%d", fnum);
623 if (!strcmp(dname, tmp)) {
624 sprintf(tmp, "%s%cmodel.%d", path, SLASH, fnum);
625 gretl_remove(tmp);
626 }
627 } else if (!strncmp(dname, "graph.", 6)) {
628 fnum = atoi(dname + 6);
629 sprintf(tmp, "graph.%d", fnum);
630 if (!strcmp(dname, tmp) &&
631 !session_graph_wanted(tmp)) {
632 sprintf(tmp, "%s%cgraph.%d", path, SLASH, fnum);
633 gretl_remove(tmp);
634 }
635 }
636 }
637 g_dir_close(sdir);
638 }
639 }
640
write_session_xml(const char * datname)641 static int write_session_xml (const char *datname)
642 {
643 MODEL *pmod;
644 char fname[2*MAXLEN];
645 char tmpname[2*MAXLEN];
646 char *objname, *xmlname;
647 PRN *prn;
648 int nmodels;
649 int tabmodels;
650 int i, modnum;
651 int err = 0;
652
653 /* we should be in dotdir already when this is called */
654
655 sprintf(fname, "%s%csession.xml", session.dirname, SLASH);
656 prn = gretl_print_new_with_filename(fname, &err);
657
658 if (err) {
659 fprintf(stderr, " write_session_xml: failed on '%s'\n", fname);
660 file_write_errbox(fname);
661 return err;
662 }
663
664 gretl_xml_header(prn);
665
666 if (*datname != '\0') {
667 pprintf(prn, "<gretl-session datafile=\"%s\" date=\"%s\">\n",
668 datname, print_today());
669 } else {
670 pprintf(prn, "<gretl-session date=\"%s\">\n", print_today());
671 }
672
673 if (data_status) {
674 pprintf(prn, " <sample t1=\"%d\" t2=\"%d\"/>\n", dataset->t1, dataset->t2);
675 write_dataset_submask(dataset, prn);
676 }
677
678 nmodels = session.nmodels;
679 tabmodels = model_table_n_models();
680
681 for (i=0; i<tabmodels; i++) {
682 pmod = model_table_model_by_index(i);
683 if (!model_in_session(pmod)) {
684 nmodels++;
685 }
686 }
687
688 trash_old_session_files(session.dirname);
689
690 pprintf(prn, " <models count=\"%d\">\n", nmodels);
691
692 modnum = 1;
693
694 for (i=0; i<session.nmodels && !err; i++) {
695 int type = session.models[i]->type;
696 void *ptr = session.models[i]->ptr;
697 SavedObjectFlags sflags;
698 int tablepos = 0;
699 PRN *pm;
700
701 sprintf(tmpname, "%s%cmodel.%d", session.dirname, SLASH, modnum);
702 pm = gretl_print_new_with_filename(tmpname, &err);
703
704 if (err) {
705 file_write_errbox(tmpname);
706 } else {
707 sprintf(tmpname, "model.%d", modnum++);
708 objname = session.models[i]->name;
709 xmlname = get_xmlname(objname, &err);
710 if (err) {
711 break;
712 }
713 if (type == GRETL_OBJ_EQN) {
714 tablepos = model_table_position(ptr);
715 }
716 if (tablepos > 0) {
717 pprintf(prn, " <session-model name=\"%s\" fname=\"%s\" type=\"%d\" tablepos=\"%d\"/>\n",
718 xmlname, tmpname, type, tablepos);
719 } else {
720 pprintf(prn, " <session-model name=\"%s\" fname=\"%s\" type=\"%d\"/>\n",
721 xmlname, tmpname, type);
722 }
723 if (xmlname != objname) {
724 free(xmlname);
725 }
726 gretl_xml_header(pm);
727 sflags = model_save_flags(ptr, type);
728 if (type == GRETL_OBJ_EQN) {
729 gretl_model_serialize(ptr, sflags, pm);
730 } else if (type == GRETL_OBJ_VAR) {
731 gretl_VAR_serialize(ptr, sflags, pm);
732 } else if (type == GRETL_OBJ_SYS) {
733 equation_system_serialize(ptr, sflags, pm);
734 }
735 gretl_print_destroy(pm);
736 }
737 }
738
739 for (i=0; i<tabmodels && !err; i++) {
740 PRN *pm;
741
742 pmod = model_table_model_by_index(i);
743 if (!model_in_session(pmod)) {
744 sprintf(tmpname, "%s%cmodel.%d", session.dirname, SLASH, modnum);
745 pm = gretl_print_new_with_filename(tmpname, &err);
746
747 if (err) {
748 file_write_errbox(tmpname);
749 } else {
750 int tablepos = model_table_position(pmod);
751
752 if (pmod->name == NULL) {
753 objname = xmlname = NULL;
754 } else {
755 objname = pmod->name;
756 xmlname = get_xmlname(objname, &err);
757 }
758 if (err) {
759 break;
760 }
761 sprintf(tmpname, "model.%d", modnum++);
762 pprintf(prn, " <session-model name=\"%s\" fname=\"%s\" type=\"%d\" tablepos=\"%d\"/>\n",
763 (xmlname != NULL)? xmlname : "none", tmpname, GRETL_OBJ_EQN, tablepos);
764 if (xmlname != NULL && xmlname != objname) {
765 free(xmlname);
766 }
767 gretl_xml_header(pm);
768 gretl_model_serialize(pmod, model_save_flags(pmod, GRETL_OBJ_EQN),
769 pm);
770 gretl_print_destroy(pm);
771 }
772 }
773 }
774
775 if (err) {
776 gretl_print_destroy(prn);
777 gretl_remove(fname);
778 return err;
779 }
780
781 pputs(prn, " </models>\n");
782
783 pprintf(prn, " <graphs count=\"%d\">\n", session.ngraphs);
784
785 for (i=0; i<session.ngraphs; i++) {
786 objname = session.graphs[i]->name;
787 xmlname = get_xmlname(objname, &err);
788 if (err) {
789 break;
790 }
791 pprintf(prn, " <session-graph name=\"%s\" fname=\"%s\" type=\"%d\"",
792 xmlname, session.graphs[i]->fname, session.graphs[i]->type);
793 if (xmlname != objname) {
794 free(xmlname);
795 }
796 if (in_graph_page(session.graphs[i]->fname)) {
797 pputs(prn, " inpage=\"1\"");
798 }
799 if (session.graphs[i]->has_datafile) {
800 pputs(prn, " has_datafile=\"1\"");
801 }
802 pputs(prn, "/>\n");
803 }
804 pputs(prn, " </graphs>\n");
805
806 pprintf(prn, " <texts count=\"%d\">\n", session.ntexts);
807
808 for (i=0; i<session.ntexts; i++) {
809 objname = session.texts[i]->name;
810 xmlname = get_xmlname(objname, &err);
811 if (err) {
812 break;
813 }
814 pprintf(prn, " <session-text name=\"%s\">", xmlname);
815 if (xmlname != objname) {
816 free(xmlname);
817 }
818 gretl_xml_put_string(session.texts[i]->buf, prn);
819 pputs(prn, "</session-text>\n");
820 }
821 pputs(prn, " </texts>\n");
822
823 if (session.notes != NULL) {
824 if (session.show_notes) {
825 pputs(prn, "<notes auto-show=\"true\">");
826 } else {
827 pputs(prn, "<notes>");
828 }
829 gretl_xml_put_string(session.notes, prn);
830 pputs(prn, "</notes>\n");
831 }
832
833 pputs(prn, "</gretl-session>\n");
834
835 gretl_print_destroy(prn);
836
837 serialize_user_vars(session.dirname);
838
839 maybe_write_function_file(tmpname);
840 write_settings_file(tmpname);
841
842 return 0;
843 }
844