NativeEnumerated.c vars NULL init and check
[com/asn1c.git] / libasn1print / asn1print.c
1 #include <stdio.h>
2 #include <stdarg.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <assert.h>
6
7 #include <asn1_buffer.h>
8 #include <asn1_namespace.h>
9 #include <asn1parser.h>
10 #include <asn1fix_export.h>
11 #include <asn1fix_crange.h>
12
13 #include "asn1print.h"
14
15 static abuf all_output_;
16
17 typedef enum {
18     PRINT_STDOUT,
19     GLOBAL_BUFFER,
20 } print_method_e;
21 static print_method_e print_method_;
22
23 #define INDENT(fmt, args...)    do {        \
24         if(!(flags & APF_NOINDENT)) {       \
25             int tmp_i = level;              \
26             while(tmp_i--) safe_printf("    ");  \
27         }                                   \
28         safe_printf(fmt, ##args);                \
29     } while(0)
30
31 static int asn1print_module(asn1p_t *asn, asn1p_module_t *mod, enum asn1print_flags flags);
32 static int asn1print_oid(int prior_len, asn1p_oid_t *oid, enum asn1print_flags flags);
33 static int asn1print_ref(const asn1p_ref_t *ref, enum asn1print_flags flags);
34 static int asn1print_tag(const asn1p_expr_t *tc, enum asn1print_flags flags);
35 static int asn1print_params(const asn1p_paramlist_t *pl,enum asn1print_flags flags);
36 static int asn1print_with_syntax(const asn1p_wsyntx_t *wx, enum asn1print_flags flags);
37 static int asn1print_constraint(const asn1p_constraint_t *, enum asn1print_flags);
38 static int asn1print_value(const asn1p_value_t *val, enum asn1print_flags flags);
39 static int asn1print_expr(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *tc, enum asn1print_flags flags, int level);
40 static int asn1print_expr_dtd(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *tc, enum asn1print_flags flags, int level);
41
42 /* Check printf's error code, to be pedantic. */
43 static int safe_printf(const char *fmt, ...) {
44     int ret = 0;
45     va_list ap;
46     va_start(ap, fmt);
47
48     switch(print_method_) {
49     case PRINT_STDOUT:
50         ret = vprintf(fmt, ap);
51         break;
52     case GLOBAL_BUFFER:
53         ret = abuf_vprintf(&all_output_, fmt, ap);
54         break;
55     }
56     assert(ret >= 0);
57     va_end(ap);
58
59     return ret;
60 }
61
62 /* Pedantically check fwrite's return value. */
63 static size_t safe_fwrite(const void *ptr, size_t size) {
64     size_t ret;
65
66     switch(print_method_) {
67     case PRINT_STDOUT:
68         ret = fwrite(ptr, 1, size, stdout);
69         assert(ret == size);
70         break;
71     case GLOBAL_BUFFER:
72         abuf_add_bytes(&all_output_, ptr, size);
73         ret = size;
74         break;
75     }
76
77     return ret;
78 }
79
80 /*
81  * Print the contents of the parsed ASN tree.
82  */
83 int
84 asn1print(asn1p_t *asn, enum asn1print_flags flags) {
85         asn1p_module_t *mod;
86         int modno = 0;
87
88         if(asn == NULL) {
89                 errno = EINVAL;
90                 return -1;
91         }
92
93         if(flags & APF_PRINT_XML_DTD)
94                 safe_printf("<!-- XML DTD generated by asn1c-" VERSION " -->\n\n");
95
96         TQ_FOR(mod, &(asn->modules), mod_next) {
97                 if(mod->_tags & MT_STANDARD_MODULE)
98                         return 0; /* Ignore modules imported from skeletons */
99                 if(modno++) safe_printf("\n");
100                 asn1print_module(asn, mod, flags);
101         }
102
103         if(flags & APF_PRINT_XML_DTD) {
104                 /* Values for BOOLEAN */
105                 safe_printf("<!ELEMENT true EMPTY>\n");
106                 safe_printf("<!ELEMENT false EMPTY>\n");
107         }
108
109         return 0;
110 }
111
112 static int
113 asn1print_module(asn1p_t *asn, asn1p_module_t *mod, enum asn1print_flags flags) {
114         asn1p_expr_t *tc;
115
116         if(flags & APF_PRINT_XML_DTD)
117                 safe_printf("<!-- ASN.1 module\n");
118
119         safe_printf("%s ", mod->ModuleName);
120         if(mod->module_oid) {
121                 asn1print_oid(strlen(mod->ModuleName), mod->module_oid, flags);
122                 safe_printf("\n");
123         }
124
125         if(flags & APF_PRINT_XML_DTD) {
126                 if(mod->source_file_name
127                 && strcmp(mod->source_file_name, "-"))
128                         safe_printf("found in %s", mod->source_file_name);
129                 safe_printf(" -->\n\n");
130
131                 TQ_FOR(tc, &(mod->members), next) {
132                         asn1print_expr_dtd(asn, mod, tc, flags, 0);
133                 }
134
135                 return 0;
136         }
137
138         safe_printf("DEFINITIONS");
139
140         if(mod->module_flags & MSF_TAG_INSTRUCTIONS)
141                 safe_printf(" TAG INSTRUCTIONS");
142         if(mod->module_flags & MSF_XER_INSTRUCTIONS)
143                 safe_printf(" XER INSTRUCTIONS");
144         if(mod->module_flags & MSF_EXPLICIT_TAGS)
145                 safe_printf(" EXPLICIT TAGS");
146         if(mod->module_flags & MSF_IMPLICIT_TAGS)
147                 safe_printf(" IMPLICIT TAGS");
148         if(mod->module_flags & MSF_AUTOMATIC_TAGS)
149                 safe_printf(" AUTOMATIC TAGS");
150         if(mod->module_flags & MSF_EXTENSIBILITY_IMPLIED)
151                 safe_printf(" EXTENSIBILITY IMPLIED");
152
153         safe_printf(" ::=\n");
154         safe_printf("BEGIN\n\n");
155
156         TQ_FOR(tc, &(mod->members), next) {
157                 asn1print_expr(asn, mod, tc, flags, 0);
158                 if(flags & APF_PRINT_CONSTRAINTS)
159                         safe_printf("\n");
160                 else
161                         safe_printf("\n\n");
162         }
163
164         safe_printf("END\n");
165
166         return 0;
167 }
168
169 static int
170 asn1print_oid(int prior_len, asn1p_oid_t *oid, enum asn1print_flags flags) {
171         size_t accum = prior_len;
172         int ac;
173
174         (void)flags;    /* Unused argument */
175
176         safe_printf("{");
177         for(ac = 0; ac < oid->arcs_count; ac++) {
178                 const char *arcname = oid->arcs[ac].name;
179
180                 if(accum + strlen(arcname ? arcname : "") > 72) {
181                         safe_printf("\n\t");
182                         accum = 8;
183                 } else {
184                         accum += safe_printf(" ");
185                 }
186
187                 if(arcname) {
188                         accum += safe_printf("%s", arcname);
189                         if(oid->arcs[ac].number >= 0) {
190                                 accum += safe_printf("(%s)",
191                                         asn1p_itoa(oid->arcs[ac].number));
192                         }
193                 } else {
194                         accum += safe_printf("%s", asn1p_itoa(oid->arcs[ac].number));
195                 }
196         }
197         safe_printf(" }");
198
199         return 0;
200 }
201
202 static int
203 asn1print_ref(const asn1p_ref_t *ref, enum asn1print_flags flags) {
204
205         (void)flags;    /* Unused argument */
206
207         for(size_t cc = 0; cc < ref->comp_count; cc++) {
208                 if(cc) safe_printf(".");
209                 safe_printf("%s", ref->components[cc].name);
210         }
211
212         return 0;
213 }
214
215 static int
216 asn1print_tag(const asn1p_expr_t *tc, enum asn1print_flags flags) {
217         const struct asn1p_type_tag_s *tag = &tc->tag;
218
219         (void)flags;    /* Unused argument */
220
221         safe_printf("%s", asn1p_tag2string(tag, 0));
222
223         return 0;
224 }
225
226 static int
227 asn1print_value(const asn1p_value_t *val, enum asn1print_flags flags) {
228
229         if(val == NULL)
230                 return 0;
231
232         switch(val->type) {
233         case ATV_NOVALUE:
234                 break;
235         case ATV_NULL:
236                 safe_printf("NULL");
237                 return 0;
238         case ATV_REAL:
239                 safe_printf("%f", val->value.v_double);
240                 return 0;
241         case ATV_TYPE:
242                 asn1print_expr(val->value.v_type->module->asn1p,
243                         val->value.v_type->module,
244                         val->value.v_type, flags, 0);
245                 return 0;
246         case ATV_INTEGER:
247                 safe_printf("%s", asn1p_itoa(val->value.v_integer));
248                 return 0;
249         case ATV_MIN: safe_printf("MIN"); return 0;
250         case ATV_MAX: safe_printf("MAX"); return 0;
251         case ATV_FALSE: safe_printf("FALSE"); return 0;
252         case ATV_TRUE: safe_printf("TRUE"); return 0;
253         case ATV_TUPLE:
254                 safe_printf("{%d, %d}",
255                         (int)(val->value.v_integer >> 4),
256                         (int)(val->value.v_integer & 0x0f));
257                 return 0;
258         case ATV_QUADRUPLE:
259                 safe_printf("{%d, %d, %d, %d}",
260                         (int)((val->value.v_integer >> 24) & 0xff),
261                         (int)((val->value.v_integer >> 16) & 0xff),
262                         (int)((val->value.v_integer >> 8) & 0xff),
263                         (int)((val->value.v_integer >> 0) & 0xff)
264                 );
265                 return 0;
266         case ATV_STRING:
267                 {
268                         char *p = (char *)val->value.string.buf;
269                         safe_printf("\"");
270                         if(strchr(p, '"')) {
271                                 /* Mask quotes */
272                                 for(; *p; p++) {
273                                         if(*p == '"')
274                                                 safe_printf("%c", *p);
275                     safe_printf("%c", *p);
276                                 }
277                         } else {
278                                 safe_printf("%s", p);
279                         }
280                         safe_printf("\"");
281                 }
282                 return 0;
283         case ATV_UNPARSED:
284                 safe_printf("%s", (char *)val->value.string.buf);
285                 return 0;
286         case ATV_BITVECTOR:
287                 {
288                         uint8_t *bitvector;
289                         int bits;
290                         int i;
291
292                         bitvector = val->value.binary_vector.bits;
293                         bits = val->value.binary_vector.size_in_bits;
294
295                         safe_printf("'");
296                         if(bits%8) {
297                                 for(i = 0; i < bits; i++) {
298                                         uint8_t uc;
299                                         uc = bitvector[i>>3];
300                                         safe_printf("%c", ((uc >> (7-(i%8)))&1)?'1':'0');
301                                 }
302                                 safe_printf("'B");
303                         } else {
304                                 char hextable[16] = "0123456789ABCDEF";
305                                 for(i = 0; i < (bits>>3); i++) {
306                                         safe_printf("%c", hextable[bitvector[i] >> 4]);
307                                         safe_printf("%c", hextable[bitvector[i] & 0x0f]);
308                                 }
309                                 safe_printf("'H");
310                         }
311                         return 0;
312                 }
313         case ATV_REFERENCED:
314                 return asn1print_ref(val->value.reference, flags);
315         case ATV_VALUESET:
316                 return asn1print_constraint(val->value.constraint, flags);
317         case ATV_CHOICE_IDENTIFIER:
318                 safe_printf("%s: ", val->value.choice_identifier.identifier);
319                 return asn1print_value(val->value.choice_identifier.value, flags);
320         }
321
322         assert(val->type || !"Unknown");
323
324         return 0;
325 }
326
327 const char *
328 asn1p_constraint_string(const asn1p_constraint_t *ct) {
329     size_t old_len = all_output_.length;
330     print_method_e old_method = print_method_;
331     print_method_ = GLOBAL_BUFFER;
332     asn1print_constraint(ct, APF_NOINDENT);
333     print_method_ = old_method;
334     return &all_output_.buffer[old_len];
335 }
336
337 static int
338 asn1print_constraint(const asn1p_constraint_t *ct, enum asn1print_flags flags) {
339         int symno = 0;
340         int perhaps_subconstraints = 0;
341
342         if(ct == 0) return 0;
343
344         switch(ct->type) {
345         case ACT_EL_TYPE:
346                 asn1print_value(ct->containedSubtype, flags);
347                 perhaps_subconstraints = 1;
348                 break;
349         case ACT_EL_VALUE:
350                 asn1print_value(ct->value, flags);
351                 perhaps_subconstraints = 1;
352                 break;
353         case ACT_EL_RANGE:
354         case ACT_EL_LLRANGE:
355         case ACT_EL_RLRANGE:
356         case ACT_EL_ULRANGE:
357                 asn1print_value(ct->range_start, flags);
358                         switch(ct->type) {
359                         case ACT_EL_RANGE: safe_printf(".."); break;
360                         case ACT_EL_LLRANGE: safe_printf("<.."); break;
361                         case ACT_EL_RLRANGE: safe_printf("..<"); break;
362                         case ACT_EL_ULRANGE: safe_printf("<..<"); break;
363                         default: safe_printf("?..?"); break;
364                         }
365                 asn1print_value(ct->range_stop, flags);
366                 break;
367         case ACT_EL_EXT:
368                 safe_printf("...");
369                 break;
370         case ACT_CT_SIZE:
371         case ACT_CT_FROM:
372                 switch(ct->type) {
373                 case ACT_CT_SIZE: safe_printf("SIZE"); break;
374                 case ACT_CT_FROM: safe_printf("FROM"); break;
375                 default: safe_printf("??? "); break;
376                 }
377                 assert(ct->el_count != 0);
378                 assert(ct->el_count == 1);
379                 asn1print_constraint(ct->elements[0], flags);
380                 break;
381         case ACT_CT_WCOMP:
382                 assert(ct->el_count != 0);
383                 assert(ct->el_count == 1);
384                 safe_printf("WITH COMPONENT");
385                 perhaps_subconstraints = 1;
386                 break;
387         case ACT_CT_WCOMPS: {
388                         unsigned int i;
389                         safe_printf("WITH COMPONENTS { ");
390                         for(i = 0; i < ct->el_count; i++) {
391                                 asn1p_constraint_t *cel = ct->elements[i];
392                                 if(i) safe_printf(", ");
393                                 asn1print_constraint(cel, flags);
394                                 switch(cel->presence) {
395                                 case ACPRES_DEFAULT: break;
396                                 case ACPRES_PRESENT: safe_printf(" PRESENT"); break;
397                                 case ACPRES_ABSENT: safe_printf(" ABSENT"); break;
398                                 case ACPRES_OPTIONAL: safe_printf(" OPTIONAL");break;
399                                 }
400                         }
401                         safe_printf(" }");
402                 }
403                 break;
404         case ACT_CT_CTDBY:
405                 safe_printf("CONSTRAINED BY ");
406                 assert(ct->value->type == ATV_UNPARSED);
407                 safe_fwrite(ct->value->value.string.buf, ct->value->value.string.size);
408                 break;
409         case ACT_CT_CTNG:
410                 safe_printf("CONTAINING ");
411                 asn1print_expr(ct->value->value.v_type->module->asn1p,
412                         ct->value->value.v_type->module,
413                         ct->value->value.v_type,
414                         flags, 1);
415                 break;
416         case ACT_CT_PATTERN:
417                 safe_printf("PATTERN ");
418                 asn1print_value(ct->value, flags);
419                 break;
420         case ACT_CA_SET: symno++;   /* Fall through */
421         case ACT_CA_CRC: symno++;   /* Fall through */
422         case ACT_CA_CSV: symno++;   /* Fall through */
423         case ACT_CA_UNI: symno++;   /* Fall through */
424         case ACT_CA_INT: symno++;   /* Fall through */
425         case ACT_CA_EXC:
426                 {
427                         char *symtable[] = { " EXCEPT ", " ^ ", " | ", ",",
428                                         "", "(" };
429                         unsigned int i;
430             if(ct->type == ACT_CA_SET) safe_printf("(");
431                         for(i = 0; i < ct->el_count; i++) {
432                                 if(i) safe_printf("%s", symtable[symno]);
433                                 if(ct->type == ACT_CA_CRC) safe_printf("{");
434                                 asn1print_constraint(ct->elements[i], flags);
435                                 if(ct->type == ACT_CA_CRC) safe_printf("}");
436                                 if(ct->type == ACT_CA_SET && i+1 < ct->el_count)
437                                         safe_printf(") ");
438                         }
439             if(ct->type == ACT_CA_SET) safe_printf(")");
440                 }
441                 break;
442         case ACT_CA_AEX:
443                 assert(ct->el_count == 1);
444                 safe_printf("ALL EXCEPT");
445                 perhaps_subconstraints = 1;
446                 break;
447         case ACT_INVALID:
448                 assert(ct->type != ACT_INVALID);
449                 break;
450         }
451
452     if(perhaps_subconstraints && ct->el_count) {
453         safe_printf(" ");
454         assert(ct->el_count == 1);
455         asn1print_constraint(ct->elements[0], flags);
456     }
457
458         return 0;
459 }
460
461 static int
462 asn1print_params(const asn1p_paramlist_t *pl, enum asn1print_flags flags) {
463         if(pl) {
464                 int i;
465                 safe_printf("{");
466                 for(i = 0; i < pl->params_count; i++) {
467                         if(i) safe_printf(", ");
468                         if(pl->params[i].governor) {
469                                 asn1print_ref(pl->params[i].governor, flags);
470                                 safe_printf(":");
471                         }
472                         safe_printf("%s", pl->params[i].argument);
473                 }
474                 safe_printf("}");
475         }
476
477         return 0;
478 }
479
480 static int
481 asn1print_with_syntax(const asn1p_wsyntx_t *wx, enum asn1print_flags flags) {
482         if(wx) {
483                 const asn1p_wsyntx_chunk_t *wc;
484                 TQ_FOR(wc, &(wx->chunks), next) {
485                   switch(wc->type) {
486                   case WC_LITERAL:
487                   case WC_WHITESPACE:
488                   case WC_FIELD:
489                         safe_printf("%s", wc->content.token);
490                         break;
491                   case WC_OPTIONALGROUP:
492                         safe_printf("[");
493                         asn1print_with_syntax(wc->content.syntax,flags);
494                         safe_printf("]");
495                         break;
496                   }
497                 }
498         }
499
500         return 0;
501 }
502
503 static int
504 asn1print_crange_value(const asn1cnst_edge_t *edge, int as_char) {
505         switch(edge->type) {
506         case ARE_MIN: safe_printf("MIN"); break;
507         case ARE_MAX: safe_printf("MAX"); break;
508         case ARE_VALUE:
509                 if(as_char) {
510                         safe_printf("\"%c\"", (unsigned char)edge->value);
511                 } else {
512                         safe_printf("%s", asn1p_itoa(edge->value));
513                 }
514         }
515         return 0;
516 }
517
518 static int
519 asn1print_constraint_explain_type(const char *dbg_name, asn1p_expr_type_e expr_type, asn1p_constraint_t *ct, enum asn1p_constraint_type_e type, enum cpr_flags cpr) {
520         asn1cnst_range_t *range;
521         int as_char = (type==ACT_CT_FROM);
522         int i;
523
524         range = asn1constraint_compute_constraint_range(dbg_name, expr_type, ct, type, 0, 0, cpr);
525         if(!range) return -1;
526
527         if(range->incompatible) return 0;
528
529         if((cpr & CPR_strict_OER_visibility) && range->not_OER_visible) {
530                 asn1constraint_range_free(range);
531                 return 0;
532         }
533
534         if((cpr & CPR_strict_PER_visibility) && range->not_PER_visible) {
535                 asn1constraint_range_free(range);
536                 return 0;
537         }
538
539         switch(type) {
540         case ACT_CT_FROM: safe_printf("(FROM("); break;
541         case ACT_CT_SIZE: safe_printf("(SIZE("); break;
542         default: safe_printf("("); break;
543         }
544         for(i = -1; i < range->el_count; i++) {
545                 asn1cnst_range_t *r;
546                 if(i == -1) {
547                         if(range->el_count) continue;
548                         r = range;
549                 } else {
550                         r = range->elements[i];
551                 }
552                 if(i > 0) {
553                         safe_printf(" | ");
554                 }
555                 asn1print_crange_value(&r->left, as_char);
556                 if(r->left.type != r->right.type
557                 || r->left.value != r->right.value) {
558                         safe_printf("..");
559                         asn1print_crange_value(&r->right, as_char);
560                 }
561         }
562         if(range->extensible)
563                 safe_printf(",...");
564         safe_printf(type==ACT_EL_RANGE?")":"))");
565
566         if(range->empty_constraint)
567                 safe_printf(":Empty!");
568
569         asn1constraint_range_free(range);
570         return 0;
571 }
572
573 static int
574 asn1print_constraint_explain(const char *dbg_name, asn1p_expr_type_e expr_type,
575                 asn1p_constraint_t *ct, enum cpr_flags cpr) {
576
577         asn1print_constraint_explain_type(dbg_name, expr_type, ct, ACT_EL_RANGE, cpr);
578         safe_printf(" ");
579         asn1print_constraint_explain_type(dbg_name, expr_type, ct, ACT_CT_SIZE, cpr);
580         safe_printf(" ");
581         asn1print_constraint_explain_type(dbg_name, expr_type, ct, ACT_CT_FROM, cpr);
582
583         return 0;
584 }
585
586 static int
587 asn1print_expr(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *tc, enum asn1print_flags flags, int level) {
588         int SEQ_OF = 0;
589     int has_space = 0;
590
591 #define HAS_SPACE()    \
592     do {               \
593         has_space = 1; \
594     } while(0)
595 #define ENSURE_SPACE()        \
596     do {                      \
597         if(!has_space) {      \
598             has_space = 1;    \
599             safe_printf(" "); \
600         }                     \
601     } while(0)
602 #define WANT_SPACE()   \
603     do {               \
604         has_space = 0; \
605     } while(0)
606
607     if(flags & APF_LINE_COMMENTS && !(flags & APF_NOINDENT))
608                 INDENT("-- #line %d\n", tc->_lineno);
609
610         /* Reconstruct compiler directive information */
611         if((tc->marker.flags & EM_INDIRECT)
612         && (tc->marker.flags & EM_OMITABLE) != EM_OMITABLE) {
613                 if((flags & APF_NOINDENT))
614                         safe_printf(" --<ASN1C.RepresentAsPointer>-- ");
615                 else
616                         INDENT("--<ASN1C.RepresentAsPointer>--\n");
617         }
618
619         if(tc->Identifier
620         && (!(tc->meta_type == AMT_VALUE && tc->expr_type == A1TC_REFERENCE)
621          || level == 0)) {
622                 INDENT("%s", tc->Identifier);
623                 WANT_SPACE();
624     }
625
626         if(tc->lhs_params) {
627                 asn1print_params(tc->lhs_params, flags);
628         }
629
630         if(tc->meta_type != AMT_VALUE
631         && tc->meta_type != AMT_VALUESET
632         && tc->expr_type != A1TC_EXTENSIBLE) {
633                 if(level) {
634                         if(tc->Identifier && !(flags & APF_NOINDENT))
635                                 safe_printf("\t");
636                 } else if(tc->Identifier) {
637                         ENSURE_SPACE();
638                         safe_printf("::=");
639                         WANT_SPACE();
640                 }
641         }
642
643         if(tc->tag.tag_class) {
644                 ENSURE_SPACE();
645                 asn1print_tag(tc, flags);
646         WANT_SPACE();
647         }
648
649         switch(tc->expr_type) {
650         case A1TC_EXTENSIBLE:
651                 if(tc->value) {
652                         safe_printf("!");
653                         asn1print_value(tc->value, flags);
654                 }
655                 break;
656         case A1TC_COMPONENTS_OF:
657                 SEQ_OF = 1; /* Equivalent to SET OF for printint purposes */
658                 safe_printf("    COMPONENTS OF");
659                 WANT_SPACE();
660                 break;
661         case A1TC_REFERENCE:
662         case A1TC_UNIVERVAL:
663                 break;
664         case A1TC_CLASSDEF:
665                 safe_printf(" CLASS");
666                 WANT_SPACE();
667                 break;
668         case A1TC_CLASSFIELD_TFS ... A1TC_CLASSFIELD_OSFS:
669                 /* Nothing to print here */
670                 break;
671         case ASN_CONSTR_SET_OF:
672         case ASN_CONSTR_SEQUENCE_OF:
673                 SEQ_OF = 1;
674                 ENSURE_SPACE();
675                 if(tc->expr_type == ASN_CONSTR_SET_OF)
676                         safe_printf("SET");
677                 else
678                         safe_printf("SEQUENCE");
679                 if(tc->constraints) {
680                         safe_printf(" ");
681                         asn1print_constraint(tc->constraints, flags);
682                 }
683                 safe_printf(" OF");
684         WANT_SPACE();
685                 break;
686         case A1TC_VALUESET:
687                 break;
688         default:
689                 {
690                         char *p = ASN_EXPR_TYPE2STR(tc->expr_type);
691                         ENSURE_SPACE();
692                         safe_printf("%s", p?p:"<unknown type!>");
693                         WANT_SPACE();
694                 }
695                 break;
696         }
697
698         /*
699          * Put the name of the referred type.
700          */
701         if(tc->reference) {
702                 ENSURE_SPACE();
703                 asn1print_ref(tc->reference, flags);
704                 WANT_SPACE();
705         }
706
707         if(tc->meta_type == AMT_VALUESET && level == 0) {
708                 ENSURE_SPACE();
709                 safe_printf("::=");
710                 WANT_SPACE();
711         }
712
713         /*
714          * Display the descendants (children) of the current type.
715          */
716         if(TQ_FIRST(&(tc->members))
717         || (tc->expr_type & ASN_CONSTR_MASK)
718         || tc->meta_type == AMT_OBJECT
719         || tc->meta_type == AMT_OBJECTCLASS
720         || tc->meta_type == AMT_OBJECTFIELD
721         ) {
722                 asn1p_expr_t *se;       /* SubExpression */
723                 int put_braces = (!SEQ_OF) /* Don't need 'em, if SET OF... */
724                         && (tc->meta_type != AMT_OBJECTFIELD);
725
726                 if(put_braces) {
727                         if(flags & APF_NOINDENT) {
728                                 safe_printf("{");
729                                 if(!TQ_FIRST(&tc->members))
730                                         safe_printf("}");
731                         } else {
732                                 safe_printf(" {");
733                                 if(TQ_FIRST(&tc->members))
734                                         safe_printf("\n");
735                                 else
736                                         safe_printf(" }");
737                         }
738                 }
739
740                 TQ_FOR(se, &(tc->members), next) {
741                         /*
742                          * Print the expression as it were a stand-alone type.
743                          */
744                         asn1print_expr(asn, mod, se, flags, level + 1);
745                         if((se->marker.flags & EM_DEFAULT) == EM_DEFAULT) {
746                                 safe_printf(" DEFAULT ");
747                                 asn1print_value(se->marker.default_value, flags);
748                         } else if((se->marker.flags & EM_OPTIONAL)
749                                         == EM_OPTIONAL) {
750                                 safe_printf(" OPTIONAL");
751                         }
752                         if(TQ_NEXT(se, next)) {
753                                 safe_printf(",");
754                                 if(!(flags & APF_NOINDENT))
755                                         INDENT("\n");
756                         }
757                 }
758
759                 if(put_braces && TQ_FIRST(&tc->members)) {
760                         if(!(flags & APF_NOINDENT))
761                                 safe_printf("\n");
762                         INDENT("}");
763                 }
764         }
765
766         if(tc->with_syntax) {
767                 safe_printf(" WITH SYNTAX {");
768                 asn1print_with_syntax(tc->with_syntax, flags);
769                 safe_printf("}\n");
770         }
771
772         /* Right hand specialization */
773         if(tc->rhs_pspecs) {
774                 asn1p_expr_t *se;
775                 safe_printf("{");
776                 TQ_FOR(se, &(tc->rhs_pspecs->members), next) {
777                         asn1print_expr(asn, mod, se, flags, level + 1);
778                         if(TQ_NEXT(se, next)) safe_printf(", ");
779                 }
780                 safe_printf("}");
781         }
782
783         if(!SEQ_OF && tc->constraints) {
784                 safe_printf(" ");
785                 if(tc->meta_type == AMT_VALUESET)
786                         safe_printf("{");
787                 asn1print_constraint(tc->constraints, flags);
788                 if(tc->meta_type == AMT_VALUESET)
789                         safe_printf("}");
790         }
791
792         if(tc->unique) {
793                 safe_printf(" UNIQUE");
794         }
795
796         if(tc->meta_type == AMT_VALUE
797         && tc->expr_type != A1TC_EXTENSIBLE) {
798                 if(tc->expr_type == A1TC_UNIVERVAL) {
799                         if(tc->value) {
800                                 safe_printf("(");
801                                 asn1print_value(tc->value, flags);
802                                 safe_printf(")");
803                         }
804                 } else {
805                         if(level == 0 && tc->Identifier) safe_printf(" ::= ");
806                         asn1print_value(tc->value, flags);
807                 }
808         }
809
810         /*
811          * The following section exists entirely for debugging.
812          */
813         if(flags & APF_PRINT_CONSTRAINTS
814         && tc->expr_type != A1TC_EXTENSIBLE) {
815                 asn1p_expr_t *top_parent;
816
817                 if(tc->combined_constraints) {
818                         safe_printf("\n-- Combined constraints: ");
819                         asn1print_constraint(tc->combined_constraints, flags);
820                 }
821
822         top_parent = WITH_MODULE_NAMESPACE(
823             tc->module, tc_ns, asn1f_find_terminal_type_ex(asn, tc_ns, tc));
824         if(top_parent) {
825                         safe_printf("\n-- Practical constraints (%s): ",
826                                 top_parent->Identifier);
827                         asn1print_constraint_explain(top_parent->Identifier,
828                                 top_parent->expr_type,
829                                 tc->combined_constraints, 0);
830                         safe_printf("\n-- OER-visible constraints (%s): ",
831                                 top_parent->Identifier);
832                         asn1print_constraint_explain(top_parent->Identifier,
833                                 top_parent->expr_type,
834                                 tc->combined_constraints, CPR_strict_OER_visibility);
835                         safe_printf("\n-- PER-visible constraints (%s): ",
836                                 top_parent->Identifier);
837                         asn1print_constraint_explain(top_parent->Identifier,
838                                 top_parent->expr_type,
839                                 tc->combined_constraints, CPR_strict_PER_visibility);
840                 }
841                 safe_printf("\n");
842         }
843
844         if(flags & APF_PRINT_CLASS_MATRIX) do {
845                 size_t col, maxidlen;
846                 if(tc->ioc_table == NULL) {
847             if(tc->expr_type == A1TC_CLASSDEF) {
848                 safe_printf("\n-- Information Object Class table is empty");
849             }
850                         break;
851                 }
852                 safe_printf("\n-- Information Object Set has %d entr%s:\n",
853                                 tc->ioc_table->rows,
854                                 tc->ioc_table->rows==1 ? "y" : "ies");
855                 maxidlen = asn1p_ioc_table_max_identifier_length(tc->ioc_table);
856                 for(ssize_t r = -1; r < (ssize_t)tc->ioc_table->rows; r++) {
857                         asn1p_ioc_row_t *row;
858                         row = tc->ioc_table->row[r<0?0:r];
859                         if(r < 0) safe_printf("--    %s", r > 9 ? " " : "");
860             else
861                 safe_printf("-- [%*d]", (tc->ioc_table->rows > 9) + 1, r + 1);
862             for(col = 0; col < row->columns; col++) {
863                                 struct asn1p_ioc_cell_s *cell;
864                                 cell = &row->column[col];
865                                 if(r < 0) {
866                                         safe_printf("[%*s]", maxidlen,
867                                                 cell->field->Identifier);
868                                         continue;
869                                 }
870                                 if(!cell->value) {
871                                         safe_printf(" %*s ", maxidlen, "<no entry>");
872                                         continue;
873                                 }
874                                 safe_printf(" %*s ", maxidlen,
875                                         cell->value->Identifier);
876                         }
877                         safe_printf("\n");
878                 }
879         if(tc->ioc_table->extensible) {
880             safe_printf("-- [%*s] ...\n", (tc->ioc_table->rows>9)+1, "");
881         }
882     } while(0);
883
884         if(flags & APF_PRINT_CLASS_MATRIX
885         && tc->lhs_params) do {
886                 int i;
887                 if(tc->specializations.pspecs_count == 0) {
888                         safe_printf("\n-- No specializations found\n");
889                         break;
890                 }
891                 safe_printf("\n-- Specializations list has %d entr%s:\n",
892                         tc->specializations.pspecs_count,
893                         tc->specializations.pspecs_count == 1 ? "y" : "ies");
894                 for(i = 0; i < tc->specializations.pspecs_count; i++) {
895                         asn1p_expr_t *se;
896                         struct asn1p_pspec_s *pspec;
897                         pspec = &tc->specializations.pspec[i];
898                         safe_printf("-- ");
899                         TQ_FOR(se, &(pspec->rhs_pspecs->members), next) {
900                                 asn1print_expr(asn, mod, se, flags, level+1);
901                         }
902                         safe_printf("\n");
903                 }
904         } while(0);
905
906         return 0;
907 }
908
909
910 static int
911 asn1print_expr_dtd(asn1p_t *asn, asn1p_module_t *mod, asn1p_expr_t *expr, enum asn1print_flags flags, int level) {
912         asn1p_expr_t *se;
913         int expr_unordered = 0;
914         int dont_involve_children = 0;
915
916         switch(expr->meta_type) {
917         case AMT_TYPE:
918         case AMT_TYPEREF:
919                 break;
920         default:
921                 if(expr->expr_type == A1TC_UNIVERVAL)
922                         break;
923                 return 0;
924         }
925
926         if(!expr->Identifier) return 0;
927
928         if(flags & APF_LINE_COMMENTS)
929                 INDENT("<!-- #line %d -->\n", expr->_lineno);
930         INDENT("<!ELEMENT %s", expr->Identifier);
931
932         if(expr->expr_type == A1TC_REFERENCE) {
933                 se = WITH_MODULE_NAMESPACE(expr->module, expr_ns, asn1f_find_terminal_type_ex(asn, expr_ns, expr));
934                 if(!se) {
935                         safe_printf(" (ANY)");
936                         return 0;
937                 }
938                 expr = se;
939                 dont_involve_children = 1;
940         }
941
942         if(expr->expr_type == ASN_CONSTR_CHOICE
943         || expr->expr_type == ASN_CONSTR_SEQUENCE_OF
944         || expr->expr_type == ASN_CONSTR_SET_OF
945         || expr->expr_type == ASN_CONSTR_SET
946         || expr->expr_type == ASN_BASIC_INTEGER
947         || expr->expr_type == ASN_BASIC_ENUMERATED) {
948                 expr_unordered = 1;
949         }
950
951         if(TQ_FIRST(&expr->members)) {
952                 int extensible = 0;
953                 if(expr->expr_type == ASN_BASIC_BIT_STRING)
954                         dont_involve_children = 1;
955                 safe_printf(" (");
956                 TQ_FOR(se, &(expr->members), next) {
957                         if(se->expr_type == A1TC_EXTENSIBLE) {
958                                 extensible = 1;
959                                 continue;
960                         } else if(!se->Identifier
961                                         && se->expr_type == A1TC_REFERENCE) {
962                                 asn1print_ref(se->reference, flags);
963                         } else if(se->Identifier) {
964                                 safe_printf("%s", se->Identifier);
965                         } else {
966                                 safe_printf("ANY");
967                         }
968                         if(expr->expr_type != ASN_CONSTR_SET
969                         && expr->expr_type != ASN_CONSTR_CHOICE
970                         && expr->expr_type != ASN_BASIC_INTEGER
971                         && expr->expr_type != ASN_BASIC_ENUMERATED) {
972                                 if(expr_unordered)
973                                         safe_printf("*");
974                                 else if(se->marker.flags)
975                                         safe_printf("?");
976                                 else if(expr->expr_type == ASN_BASIC_BIT_STRING)
977                                         safe_printf("?");
978                         }
979                         if(TQ_NEXT(se, next)
980                         && TQ_NEXT(se, next)->expr_type != A1TC_EXTENSIBLE) {
981                                 safe_printf(expr_unordered?"|":", ");
982                         }
983                 }
984                 if(extensible) {
985                         safe_printf(expr_unordered?"|":", ");
986                         safe_printf("ANY");
987                         if(expr->expr_type != ASN_CONSTR_SET
988                         && expr->expr_type != ASN_CONSTR_CHOICE
989                         && expr->expr_type != ASN_BASIC_INTEGER
990                         && expr->expr_type != ASN_BASIC_ENUMERATED)
991                                 safe_printf("*");
992                 }
993
994                 safe_printf(")");
995                 if(expr->expr_type == ASN_CONSTR_SET)
996                         safe_printf("*");
997
998         } else switch(expr->expr_type) {
999         case ASN_BASIC_BOOLEAN:
1000                 safe_printf(" (true|false)");
1001                 break;
1002         case ASN_CONSTR_CHOICE:
1003         case ASN_CONSTR_SET:
1004         case ASN_CONSTR_SET_OF:
1005         case ASN_CONSTR_SEQUENCE:
1006         case ASN_CONSTR_SEQUENCE_OF:
1007         case ASN_BASIC_NULL:
1008         case A1TC_UNIVERVAL:
1009                 safe_printf(" EMPTY");
1010                 break;
1011         case ASN_TYPE_ANY:
1012                 safe_printf(" ANY");
1013                 break;
1014         case ASN_BASIC_BIT_STRING:
1015         case ASN_BASIC_OCTET_STRING:
1016         case ASN_BASIC_OBJECT_IDENTIFIER:
1017         case ASN_BASIC_RELATIVE_OID:
1018         case ASN_BASIC_INTEGER:
1019         case ASN_BASIC_UTCTime:
1020         case ASN_BASIC_GeneralizedTime:
1021         case ASN_STRING_NumericString:
1022         case ASN_STRING_PrintableString:
1023                 safe_printf(" (#PCDATA)");
1024                 break;
1025         case ASN_STRING_VisibleString:
1026         case ASN_STRING_ISO646String:
1027                 /* Entity references, but not XML elements may be present */
1028                 safe_printf(" (#PCDATA)");
1029                 break;
1030         case ASN_BASIC_REAL:            /* e.g. <MINUS-INFINITY/> */
1031         case ASN_BASIC_ENUMERATED:      /* e.g. <enumIdentifier1/> */
1032         default:
1033                 /*
1034                  * XML elements are allowed.
1035                  * For example, a UTF8String may contain "<bel/>".
1036                  */
1037                 safe_printf(" ANY");
1038         }
1039         safe_printf(">\n");
1040
1041         /*
1042          * Display the descendants (children) of the current type.
1043          */
1044         if(!dont_involve_children) {
1045                 TQ_FOR(se, &(expr->members), next) {
1046                         if(se->expr_type == A1TC_EXTENSIBLE) continue;
1047                         asn1print_expr_dtd(asn, mod, se, flags, level + 1);
1048                 }
1049         }
1050
1051         return 0;
1052 }