1 /* JitterLisp: printer.
2
3 Copyright (C) 2017, 2018, 2019, 2020 Luca Saiu
4 Written by Luca Saiu
5
6 This file is part of the JitterLisp language implementation, distributed as
7 an example along with Jitter under the same license.
8
9 Jitter is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13
14 Jitter is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with Jitter. If not, see <http://www.gnu.org/licenses/>. */
21
22
23 /* Include the Gnulib header. */
24 #include <config.h>
25
26 #include "jitterlisp-printer.h"
27
28 #include <stdio.h>
29 #include <unistd.h>
30
31 #include <jitter/jitter-dynamic-buffer.h>
32 #include <jitter/jitter-fatal.h>
33 #include <jitter/jitter-print.h>
34
35 #include "jitterlisp-settings.h"
36 #include "jitterlisp-sexpression.h"
37 #include "jitterlisp-ast.h"
38
39
40
41
42 /* Sharing-recognition hashing.
43 * ************************************************************************** */
44
45 /* This hash table data structure serves to avoid infinite loops when printing
46 circular structures, and to show which substructures are shared (currently
47 without showing *what* is shared, but this can be improved).
48 Since this data structure and the printing process in general doesn't use
49 Lisp heap allocation in this case it's safe to simply hash on tagged
50 objects, even if they are pointers, even with a moving GC -- which is not
51 there yet but should come at some point. */
52
53 /* Initialize a sharing table, already allocated by the user. This is
54 intended to be used on a pointer to an automatic variable. */
55 static void
jitterlisp_sharing_table_initialize(struct jitter_hash_table * t)56 jitterlisp_sharing_table_initialize (struct jitter_hash_table *t)
57 {
58 jitter_hash_initialize (t);
59 }
60
61 /* Finalize a sharing table, already allocated by the user. This is
62 intended to be used on a pointer to an automatic variable. */
63 static void
jitterlisp_sharing_table_finalize(struct jitter_hash_table * t)64 jitterlisp_sharing_table_finalize (struct jitter_hash_table *t)
65 {
66 jitter_word_hash_finalize (t, jitter_do_nothing_on_word);
67 }
68
69 /* Return non-false iff the given object is already in the sharing table. */
70 static bool
jitterlisp_sharing_table_has(struct jitter_hash_table * t,jitterlisp_object o)71 jitterlisp_sharing_table_has (struct jitter_hash_table *t,
72 jitterlisp_object o)
73 {
74 return jitter_word_hash_table_has (t, o);
75 }
76
77 /* Add the given object to the sharing table, if the object can potentially
78 be circular. Do nothing otherwise. This doesn't check whether the object is
79 already in the table: it would be a useless source of inefficiency. */
80 static void
jitterlisp_sharing_table_add(struct jitter_hash_table * t,jitterlisp_object o)81 jitterlisp_sharing_table_add (struct jitter_hash_table *t,
82 jitterlisp_object o)
83 {
84 /* A Lisp object whose printed representation cannot contain other Lisp
85 object should not be kept in the table; do nothing in that case. */
86 if (! JITTERLISP_IS_RECURSIVE(o))
87 return;
88
89 /* Add an entry to the table. The value is not used. */
90 union jitter_word useless = { .fixnum = 0 };
91 jitter_word_hash_table_add (t, o, useless);
92 }
93
94
95
96
97 /* Character names.
98 * ************************************************************************** */
99
100 const struct jitterlisp_character_name_binding
101 jitterlisp_non_ordinary_character_name_bindings []
102 =
103 {
104 { '\0', "nul" },
105 { ' ', "space" },
106 { '\n', "newline" },
107 { '\n', "linefeed" },
108 { '\r', "cr" },
109 { '\r', "return" },
110 { '\f', "page" }
111 };
112
113 const size_t
114 jitterlisp_non_ordinary_character_name_binding_no
115 = (sizeof (jitterlisp_non_ordinary_character_name_bindings)
116 / sizeof (const struct jitterlisp_character_name_binding));
117
118
119
120
121 /* Char-printing utility.
122 * ************************************************************************** */
123
124 /* Use the given char-printer to emit a printed representation of the given
125 character, be it ordinary or non-ordinary. */
126 static void
jitterlisp_print_character_name(jitter_print_context cx,jitter_int c)127 jitterlisp_print_character_name (jitter_print_context cx, jitter_int c)
128 {
129 /* Print the #\ prefix, which is the same for ordinary and non-ordinary
130 characters. */
131 jitter_print_char_star (cx, "#\\");
132
133 /* Look for the first name binding for c as a non-ordinary character. If one
134 exists, print it and return. */
135 int i;
136 for (i = 0; i < jitterlisp_non_ordinary_character_name_binding_no; i ++)
137 if (jitterlisp_non_ordinary_character_name_bindings [i].character == c)
138 {
139 char *name = jitterlisp_non_ordinary_character_name_bindings [i].name;
140 jitter_print_char_star (cx, name);
141 return;
142 }
143
144 /* Since we haven't found a binding c must be an ordinary character. Print it
145 as it is. */
146 jitter_print_char (cx, c);
147 }
148
149 /* Begin the named class in the given print context, unless colorising has
150 been disabled. */
151 void
jitterlisp_begin_class(jitter_print_context cx,const char * name_suffix)152 jitterlisp_begin_class (jitter_print_context cx, const char *name_suffix)
153 {
154 char buffer [1000];
155 sprintf (buffer, "jitterlisp-%s", name_suffix);
156 jitter_print_begin_class (cx, buffer);
157 }
158
159 /* End the last begun class in the given print context, unless colorising has
160 been disabled. */
161 void
jitterlisp_end_class(jitter_print_context cx)162 jitterlisp_end_class (jitter_print_context cx)
163 {
164 jitter_print_end_class (cx);
165 }
166
167
168
169
170 /* S-expression printer.
171 * ************************************************************************** */
172
173 /* Forward declaration. Print the given object in the given print context using
174 the pointed sharing table. */
175 static void
176 jitterlisp_print_recursive (jitter_print_context cx,
177 struct jitter_hash_table *st,
178 jitterlisp_object o);
179
180
181 /* Print o as the cdr of a cons, with the car already printed and the
182 surrounding parentheses printed by the caller, using the given
183 char-printer. */
184 static void
jitterlisp_print_cdr(jitter_print_context cx,struct jitter_hash_table * st,jitterlisp_object o)185 jitterlisp_print_cdr (jitter_print_context cx,
186 struct jitter_hash_table *st, jitterlisp_object o)
187 {
188 /* Show sharing. */
189 if (jitterlisp_sharing_table_has (st, o))
190 {
191 jitterlisp_begin_class (cx, "cons");
192 jitter_print_char_star (cx, " . ");
193 jitterlisp_end_class (cx);
194 jitterlisp_begin_class (cx, "circular");
195 jitter_print_char_star (cx, "...");
196 jitterlisp_end_class (cx);
197 return;
198 }
199 jitterlisp_sharing_table_add (st, o);
200
201 if (JITTERLISP_IS_EMPTY_LIST(o))
202 {
203 /* There is nothing to print, not even a space: the caller has already
204 written the open parens and will append the matching closed parens
205 right after this function returns. */
206 }
207 else if (JITTERLISP_IS_CONS(o))
208 {
209 /* So, o is another cons: print o's car as the next list element, but
210 first separate it from the previous element, which must exist if we got
211 here, with a space. */
212 jitterlisp_begin_class (cx, "cons");
213 jitter_print_char (cx, ' ');
214 jitterlisp_end_class (cx);
215 struct jitterlisp_cons * const c = JITTERLISP_CONS_DECODE(o);
216 jitterlisp_print_recursive (cx, st, c->car);
217
218 /* We're still within a list or improper/dotted list and so we'll keep
219 using cdr notation for o's cdr, without adding more parens. If o's cdr
220 is still a cons then the recursive call will prepend a space to the
221 elements. */
222 jitterlisp_print_cdr (cx, st, c->cdr);
223 }
224 else
225 {
226 /* The innermost cdr of the spine is not (): this is an improper/dotted
227 list. */
228 jitterlisp_begin_class (cx, "cons");
229 jitter_print_char_star (cx, " . ");
230 jitterlisp_end_class (cx);
231 jitterlisp_print_recursive (cx, st, o);
232 }
233 }
234
235 /* Print the pointed s-expressions in order starting from the given initial
236 pointer and going on for element_no elements. Use a single space as a
237 separator before each element, including the first. */
238 static void
jitterlisp_print_subs(jitter_print_context cx,struct jitter_hash_table * st,jitterlisp_object * elements,size_t element_no)239 jitterlisp_print_subs (jitter_print_context cx,
240 struct jitter_hash_table *st,
241 jitterlisp_object *elements, size_t element_no)
242 {
243 int i;
244 for (i = 0; i < element_no; i ++)
245 {
246 jitterlisp_begin_class (cx, "ast");
247 jitter_print_char (cx, ' ');
248 jitterlisp_end_class (cx);
249 jitterlisp_print_recursive (cx, st, elements [i]);
250 }
251 }
252
253 /* Print the pointed AST to the given context using the pointed share table. */
254 static void
jitterlisp_print_ast(jitter_print_context cx,struct jitter_hash_table * st,struct jitterlisp_ast * ast)255 jitterlisp_print_ast (jitter_print_context cx,
256 struct jitter_hash_table *st, struct jitterlisp_ast *ast)
257 {
258 /* There's no need to check for sharing here: this function is only called
259 by jitterlisp_print_recursive which has already done it on the same
260 argument, and the AST subs are printed thru jitterlisp_print_recursive . */
261
262 jitterlisp_begin_class (cx, "ast");
263 jitter_print_char_star (cx, "[");
264 switch (ast->case_)
265 {
266 case jitterlisp_ast_case_literal:
267 jitter_print_char_star (cx, "literal");
268 break;
269 case jitterlisp_ast_case_variable:
270 jitter_print_char_star (cx, "variable");
271 break;
272 case jitterlisp_ast_case_define:
273 jitter_print_char_star (cx, "define");
274 break;
275 case jitterlisp_ast_case_if:
276 jitter_print_char_star (cx, "if");
277 break;
278 case jitterlisp_ast_case_setb:
279 jitter_print_char_star (cx, "set!");
280 break;
281 case jitterlisp_ast_case_while:
282 jitter_print_char_star (cx, "while");
283 break;
284 case jitterlisp_ast_case_primitive:
285 jitter_print_char_star (cx, "primitive "); /* Space. See below. */
286 break;
287 case jitterlisp_ast_case_call:
288 jitter_print_char_star (cx, "call");
289 break;
290 case jitterlisp_ast_case_lambda:
291 jitter_print_char_star (cx, "lambda");
292 break;
293 case jitterlisp_ast_case_let:
294 jitter_print_char_star (cx, "let");
295 break;
296 case jitterlisp_ast_case_sequence:
297 jitter_print_char_star (cx, "sequence");
298 break;
299 default:
300 jitter_print_char_star (cx, "invalid]");
301 jitterlisp_end_class (cx);
302 return;
303 }
304 jitterlisp_end_class (cx);
305 /* I can have a special case for primitives: instead of printing the entire
306 primitive object, which is very verbose, just print the primitive name when
307 occurring within a primitive AST. There is no ambiguity, and the notation
308 gets much leaner: */
309 if (ast->case_ == jitterlisp_ast_case_primitive)
310 {
311 struct jitterlisp_primitive * const primitive
312 = JITTERLISP_PRIMITIVE_DECODE(ast->subs [0]);
313 jitterlisp_begin_class (cx, "primitive");
314 jitter_print_char_star (cx, primitive->name);
315 jitterlisp_end_class (cx);
316 jitterlisp_print_subs (cx, st, ast->subs + 1, ast->sub_no - 1);
317 }
318 else
319 /* Default non-primitive case: print every sub using its own decoration. */
320 jitterlisp_print_subs (cx, st, ast->subs, ast->sub_no);
321 jitterlisp_begin_class (cx, "ast");
322 jitter_print_char_star (cx, "]");
323 jitterlisp_end_class (cx);
324 }
325
326 static void
jitterlisp_print_recursive(jitter_print_context cx,struct jitter_hash_table * st,jitterlisp_object o)327 jitterlisp_print_recursive (jitter_print_context cx,
328 struct jitter_hash_table *st, jitterlisp_object o)
329 {
330 /* Before printing anything, check whether we have printed this object
331 already. If so print a sharing indicator and just return; otherwise add
332 the object to the table for the next time (as long as it's a potential
333 source of sharing) and go on.
334
335 A special case: ignore AST sharing when printing. Sharing sub-ASTs,
336 particularly literals and variables, is harmless, and ASTs must not be
337 circular anyway: if they were, we'd in trouble for reasons much worse than
338 printing. Shared literal *values* inside ASTs are treated as always. We
339 still keep track of ASTs in the table, since the information may be needed
340 for an output notation when we print shared structures in an explicit way
341 in the future. */
342 if (JITTERLISP_IS_AST(o))
343 {
344 if (! jitterlisp_sharing_table_has (st, o))
345 jitterlisp_sharing_table_add (st, o);
346 }
347 else if (jitterlisp_sharing_table_has (st, o))
348 {
349 jitterlisp_begin_class (cx, "circular");
350 jitter_print_char_star (cx, "...");
351 jitterlisp_end_class (cx);
352 return;
353 }
354 else
355 jitterlisp_sharing_table_add (st, o);
356
357 /* Print the object according to its type. */
358 if (JITTERLISP_IS_FIXNUM(o))
359 {
360 jitter_int decoded = JITTERLISP_FIXNUM_DECODE(o);
361 jitterlisp_begin_class (cx, "fixnum");
362 jitter_print_long_long (cx, 10, decoded);
363 jitterlisp_end_class (cx);
364 }
365 else if (JITTERLISP_IS_UNIQUE(o))
366 {
367 jitter_uint index = JITTERLISP_UNIQUE_DECODE(o);
368 if (index < JITTERLISP_UNIQUE_OBJECT_NO)
369 {
370 jitterlisp_begin_class (cx, "unique");
371 jitter_print_char_star (cx,
372 jitterlisp_unique_object_names [index]);
373 }
374 else
375 {
376 jitterlisp_begin_class (cx, "invalid");
377 jitter_print_char_star (cx, "#<invalid-unique-object:");
378 jitter_print_long_long (cx, 10, index);
379 jitter_print_char (cx, '>');
380 }
381 jitterlisp_end_class (cx);
382 }
383 else if (JITTERLISP_IS_CHARACTER(o))
384 {
385 jitterlisp_begin_class (cx, "character");
386 jitter_int c = JITTERLISP_CHARACTER_DECODE(o);
387 jitterlisp_print_character_name (cx, c);
388 jitterlisp_end_class (cx);
389 }
390 else if (JITTERLISP_IS_SYMBOL(o))
391 {
392 struct jitterlisp_symbol *s = JITTERLISP_SYMBOL_DECODE(o);
393 if (s->name_or_NULL != NULL)
394 {
395 /* Print an interned symbol. */
396 jitterlisp_begin_class (cx, "interned-symbol");
397 jitter_print_char_star (cx, s->name_or_NULL);
398 }
399 else if (jitterlisp_settings.print_compact_uninterned_symbols)
400 {
401 /* Print an uninterned symbol in compact notation. */
402 jitterlisp_begin_class (cx, "uninterned-symbol");
403 jitter_print_char_star (cx, "#<u");
404 jitter_print_long_long (cx, 10, (jitter_long_long) s->index);
405 jitter_print_char_star (cx, ">");
406 }
407 else
408 {
409 /* Print an uninterned symbol in the default notation. */
410 jitterlisp_begin_class (cx, "uninterned-symbol");
411 jitter_print_char_star (cx, "#<uninterned:");
412 jitter_print_char_star (cx, "0x");
413 jitter_print_long_long (cx, 16, (jitter_uint) s);
414 jitter_print_char_star (cx, ">");
415 }
416 jitterlisp_end_class (cx);
417 }
418 else if (JITTERLISP_IS_COMPILED_CLOSURE(o))
419 {
420 struct jitterlisp_closure *c = JITTERLISP_CLOSURE_DECODE(o);
421 struct jitterlisp_compiled_closure *cc = & c->compiled;
422 jitterlisp_begin_class (cx, "closure");
423 jitter_print_char_star (cx, "#<compiled-closure ");
424 jitter_print_long_long (cx, 10, c->in_arity);
425 jitter_print_char_star (cx, "-ary");
426 jitter_print_char_star (cx, " nonlocals ");
427 jitterlisp_print_recursive (cx, st, cc->nonlocals);
428 jitter_print_char_star (cx, ">");
429 jitterlisp_end_class (cx);
430 }
431 else if (JITTERLISP_IS_INTERPRETED_CLOSURE(o))
432 {
433 struct jitterlisp_interpreted_closure * const ic
434 = & JITTERLISP_CLOSURE_DECODE(o)->interpreted;
435 jitterlisp_begin_class (cx, "closure");
436 jitter_print_char_star (cx, "#<interpreted-closure ");
437 jitterlisp_print_recursive (cx, st, ic->environment);
438 jitter_print_char (cx, ' ');
439 jitterlisp_print_recursive (cx, st, ic->formals);
440 jitter_print_char (cx, ' ');
441 jitterlisp_print_recursive (cx, st, ic->body);
442 jitter_print_char (cx, '>');
443 jitterlisp_end_class (cx);
444 }
445 else if (JITTERLISP_IS_NON_PRIMITIVE_MACRO(o))
446 {
447 struct jitterlisp_interpreted_closure * const closure
448 = JITTERLISP_NON_PRIMITIVE_MACRO_DECODE(o);
449 jitterlisp_begin_class (cx, "non-primitive-macro");
450 jitter_print_char_star (cx, "#<macro ");
451 jitterlisp_print_recursive (cx, st, closure->environment);
452 jitter_print_char (cx, ' ');
453 jitterlisp_print_recursive (cx, st, closure->formals);
454 jitter_print_char (cx, ' ');
455 jitterlisp_print_recursive (cx, st, closure->body);
456 jitter_print_char_star (cx, ">");
457 jitterlisp_end_class (cx);
458 }
459 else if (JITTERLISP_IS_PRIMITIVE(o))
460 {
461 struct jitterlisp_primitive * const primitive
462 = JITTERLISP_PRIMITIVE_DECODE(o);
463 jitterlisp_begin_class (cx, "primitive");
464 jitter_print_char_star (cx, "#<primitive ");
465 jitter_print_char_star (cx, primitive->name);
466 jitter_print_char_star (cx, " ");
467 jitter_print_long_long (cx, 10, primitive->in_arity);
468 jitter_print_char_star (cx, "-ary>");
469 jitterlisp_end_class (cx);
470 }
471 else if (JITTERLISP_IS_PRIMITIVE_MACRO(o))
472 {
473 struct jitterlisp_primitive * const primitive
474 = JITTERLISP_PRIMITIVE_MACRO_DECODE(o);
475 jitterlisp_begin_class (cx, "primitive_macro");
476 jitter_print_char_star (cx, "#<primitive macro ");
477 jitter_print_char_star (cx, primitive->name);
478 jitter_print_char_star (cx, ">");
479 jitterlisp_end_class (cx);
480 }
481 else if (JITTERLISP_IS_BOX(o))
482 {
483 jitterlisp_begin_class (cx, "box");
484 jitter_print_char_star (cx, "#<box ");
485 jitterlisp_print_recursive (cx, st, JITTERLISP_EXP_B_A_GET(o));
486 jitter_print_char (cx, '>');
487 jitterlisp_end_class (cx);
488 }
489 else if (JITTERLISP_IS_CONS(o))
490 {
491 struct jitterlisp_cons * const c = JITTERLISP_CONS_DECODE(o);
492 jitterlisp_object car = c->car;
493 jitterlisp_object cdr = c->cdr;
494 jitterlisp_begin_class (cx, "cons");
495 jitter_print_char (cx, '(');
496 jitterlisp_print_recursive (cx, st, car);
497 jitterlisp_print_cdr (cx, st, cdr);
498 jitter_print_char (cx, ')');
499 jitterlisp_end_class (cx);
500 }
501 else if (JITTERLISP_IS_AST(o))
502 {
503 struct jitterlisp_ast * const ast = JITTERLISP_AST_DECODE(o);
504 jitterlisp_print_ast (cx, st, ast);
505 }
506 else if (JITTERLISP_IS_VECTOR(o))
507 {
508 const struct jitterlisp_vector * const v = JITTERLISP_VECTOR_DECODE(o);
509 jitterlisp_begin_class (cx, "vector");
510 jitter_print_char_star (cx, "#(");
511 int i;
512 int element_no = JITTERLISP_FIXNUM_DECODE(v->element_no);
513 for (i = 0; i < element_no; i ++)
514 {
515 jitterlisp_print_recursive (cx, st, v->elements [i]);
516 if (i < (element_no - 1))
517 jitter_print_char (cx, ' ');
518 }
519 jitter_print_char (cx, ')');
520 jitterlisp_end_class (cx);
521 }
522 else
523 {
524 jitterlisp_begin_class (cx, "invalid");
525 jitter_print_char_star (cx, "#<invalid-or-unknown>");
526 jitterlisp_end_class (cx);
527 }
528 }
529
530
531
532
533 /* Lisp object printer: user functions.
534 * ************************************************************************** */
535
536 void
jitterlisp_print(jitter_print_context cx,jitterlisp_object o)537 jitterlisp_print (jitter_print_context cx, jitterlisp_object o)
538 {
539 /* Make a sharing table. */
540 struct jitter_hash_table st;
541 jitterlisp_sharing_table_initialize (& st);
542
543 /* Print the object using the table. */
544 jitterlisp_print_recursive (cx, & st, o);
545
546 /* We're done with the sharing table. */
547 jitterlisp_sharing_table_finalize (& st);
548 }
549
550 char *
jitterlisp_print_to_string(jitterlisp_object o)551 jitterlisp_print_to_string (jitterlisp_object o)
552 {
553 /* Make a temporary memory print context. */
554 jitter_print_context cx = jitter_print_context_make_memory ();
555
556 /* Print to it. */
557 jitterlisp_print (cx, o);
558
559 /* Return a copy of the printed content into in already malloc-allocated
560 buffer. Destroy the context, which does not destroy the copy. */
561 char *res = jitter_print_context_get_memory (cx, NULL);
562 jitter_print_context_destroy (cx);
563 return res;
564 }
565
566
567
568
569 /* Print error, warning and logging messages.
570 * ************************************************************************** */
571
572 static void
jitterlisp_print_char_star_internal(char * class_suffix,const char * message)573 jitterlisp_print_char_star_internal (char *class_suffix, const char *message)
574 {
575 jitterlisp_begin_class (jitterlisp_print_context, class_suffix);
576 jitter_print_char_star (jitterlisp_print_context, message);
577 jitterlisp_end_class (jitterlisp_print_context);
578 jitter_print_flush (jitterlisp_print_context);
579
580 }
581 static void
jitterlisp_print_internal(char * class_suffix,jitterlisp_object o)582 jitterlisp_print_internal (char *class_suffix, jitterlisp_object o)
583 {
584 jitterlisp_begin_class (jitterlisp_print_context, class_suffix);
585 jitterlisp_print (jitterlisp_print_context, o);
586 jitterlisp_end_class (jitterlisp_print_context);
587 jitter_print_flush (jitterlisp_print_context);
588 }
589
590 void
jitterlisp_print_error_char_star(const char * message)591 jitterlisp_print_error_char_star (const char *message)
592 {
593 jitterlisp_print_char_star_internal ("error", message);
594 }
595 void
jitterlisp_print_error(jitterlisp_object o)596 jitterlisp_print_error (jitterlisp_object o)
597 {
598 jitterlisp_print_internal ("error", o);
599 }
600 void
jitterlisp_log_char_star(const char * message)601 jitterlisp_log_char_star (const char *message)
602 {
603 jitterlisp_print_char_star_internal ("log", message);
604 }
605 void
jitterlisp_log(jitterlisp_object o)606 jitterlisp_log (jitterlisp_object o)
607 {
608 jitterlisp_print_internal ("log", o);
609 }
610
611
612
613
614
615
616 /* Initialisation and finalisation.
617 * ************************************************************************** */
618
619 /* The global print context */
620 jitter_print_context
621 jitterlisp_print_context = NULL /* For defensiveness's sake. */;
622
623 void
jitterlisp_printer_initialize(void)624 jitterlisp_printer_initialize (void)
625 {
626 /* Initialise the GNU Libtextstyle wrapper, if used. */
627 #ifdef JITTER_WITH_LIBTEXTSTYLE
628 jitter_print_libtextstyle_initialize ();
629 #endif // #ifdef JITTER_WITH_LIBTEXTSTYLE
630
631 /* If GNU Libtextstyle is used and colorisation is enabled, initialise the
632 print context using a Libtextstyle ostream... */
633 #ifdef JITTER_WITH_LIBTEXTSTYLE
634 if (jitterlisp_settings.colorize)
635 {
636 char *style_file_name = "jitterlisp-style.css"; // FIXME: this is barbaric.
637 styled_ostream_t ostream
638 = styled_ostream_create (STDOUT_FILENO, "(stdout)", TTYCTL_AUTO,
639 style_file_name);
640 jitterlisp_print_context
641 = jitter_print_context_make_libtextstyle (ostream);
642 }
643 else
644 #endif // #ifdef JITTER_WITH_LIBTEXTSTYLE
645 {
646 /* ...Otherwise use a non-styling context. */
647 jitterlisp_print_context
648 = jitter_print_context_make_file_star (stdout);
649 }
650 }
651
652 void
jitterlisp_printer_finalize(void)653 jitterlisp_printer_finalize (void)
654 {
655 jitter_print_context_destroy (jitterlisp_print_context);
656 jitterlisp_print_context = NULL /* For defensiveness's sake. */;
657
658 #ifdef JITTER_WITH_LIBTEXTSTYLE
659 jitter_print_libtextstyle_finalize ();
660 #endif // #ifdef JITTER_WITH_LIBTEXTSTYLE
661 }
662