No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / src / format-scheme.c
blob326012a6e8b32b383ed31b3240dbcc3d4ce6f36e
1 /* Scheme format strings.
2 Copyright (C) 2001-2005 Free Software Foundation, Inc.
3 Written by Bruno Haible <haible@clisp.cons.org>, 2001.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
19 #ifdef HAVE_CONFIG_H
20 # include <config.h>
21 #endif
23 #include <stdbool.h>
24 #include <stdlib.h>
26 #include "format.h"
27 #include "c-ctype.h"
28 #include "gcd.h"
29 #include "xalloc.h"
30 #include "xerror.h"
31 #include "format-invalid.h"
32 #include "minmax.h"
33 #include "error.h"
34 #include "error-progname.h"
35 #include "gettext.h"
37 #define _(str) gettext (str)
40 /* Assertion macros. Could be defined to empty for speed. */
41 #define ASSERT(expr) if (!(expr)) abort ();
42 #define VERIFY_LIST(list) verify_list (list)
45 /* Scheme format strings are described in the GNU guile documentation,
46 section "Formatted Output". They are implemented in
47 guile-1.6.4/ice-9/format.scm. */
49 /* Data structure describing format string derived constraints for an
50 argument list. It is a recursive list structure. Structure sharing
51 is not allowed. */
53 enum format_cdr_type
55 FCT_REQUIRED, /* The format argument list cannot end before this argument. */
56 FCT_OPTIONAL /* The format argument list may end before this argument. */
59 enum format_arg_type
61 FAT_OBJECT, /* Any object, type T. */
62 FAT_CHARACTER_INTEGER_NULL, /* Type (OR CHARACTER INTEGER NULL). */
63 FAT_CHARACTER_NULL, /* Type (OR CHARACTER NULL). */
64 FAT_CHARACTER, /* Type CHARACTER. */
65 FAT_INTEGER_NULL, /* Type (OR INTEGER NULL). */
66 FAT_INTEGER, /* Meant for objects of type INTEGER. */
67 FAT_REAL, /* Meant for objects of type REAL. */
68 FAT_COMPLEX, /* Meant for objects of type COMPLEX. */
69 FAT_LIST, /* Meant for proper lists. */
70 FAT_FORMATSTRING /* Format strings. */
73 struct format_arg
75 unsigned int repcount; /* Number of consecutive arguments this constraint
76 applies to. Normally 1, but unconstrained
77 arguments are often repeated. */
78 enum format_cdr_type presence; /* Can the argument list end right before
79 this argument? */
80 enum format_arg_type type; /* Possible values for this argument. */
81 struct format_arg_list *list; /* For FAT_LIST: List elements. */
84 struct format_arg_list
86 /* The constraints for the potentially infinite argument list are assumed
87 to become ultimately periodic. (Too complicated argument lists without
88 a-priori period, like
89 (format t "~@{~:[-~;~S~]~}" nil t 1 t 3 nil t 4)
90 are described by a constraint that ends in a length 1 period of
91 unconstrained arguments.) Such a periodic sequence can be split into
92 an initial segment and an endlessly repeated loop segment.
93 A finite sequence is represented entirely in the initial segment; the
94 loop segment is empty. */
96 struct segment
98 unsigned int count; /* Number of format_arg records used. */
99 unsigned int allocated;
100 struct format_arg *element; /* Argument constraints. */
101 unsigned int length; /* Number of arguments represented by this segment.
102 This is the sum of all repcounts in the segment. */
104 initial, /* Initial arguments segment. */
105 repeated; /* Endlessly repeated segment. */
108 struct spec
110 unsigned int directives;
111 struct format_arg_list *list;
115 /* Parameter for a directive. */
116 enum param_type
118 PT_NIL, /* param not present */
119 PT_CHARACTER, /* character */
120 PT_INTEGER, /* integer */
121 PT_ARGCOUNT, /* number of remaining arguments */
122 PT_V /* variable taken from argument list */
125 struct param
127 enum param_type type;
128 int value; /* for PT_INTEGER: the value, for PT_V: the position */
132 /* Forward declaration of local functions. */
133 #define union make_union
134 static void verify_list (const struct format_arg_list *list);
135 static void free_list (struct format_arg_list *list);
136 static struct format_arg_list * copy_list (const struct format_arg_list *list);
137 static bool equal_list (const struct format_arg_list *list1,
138 const struct format_arg_list *list2);
139 static struct format_arg_list * make_intersected_list
140 (struct format_arg_list *list1,
141 struct format_arg_list *list2);
142 static struct format_arg_list * make_intersection_with_empty_list
143 (struct format_arg_list *list);
144 static struct format_arg_list * make_union_list
145 (struct format_arg_list *list1,
146 struct format_arg_list *list2);
149 /* ======================= Verify a format_arg_list ======================= */
151 /* Verify some invariants. */
152 static void
153 verify_element (const struct format_arg * e)
155 ASSERT (e->repcount > 0);
156 if (e->type == FAT_LIST)
157 verify_list (e->list);
160 /* Verify some invariants. */
161 /* Memory effects: none. */
162 static void
163 verify_list (const struct format_arg_list *list)
165 unsigned int i;
166 unsigned int total_repcount;
168 ASSERT (list->initial.count <= list->initial.allocated);
169 total_repcount = 0;
170 for (i = 0; i < list->initial.count; i++)
172 verify_element (&list->initial.element[i]);
173 total_repcount += list->initial.element[i].repcount;
175 ASSERT (total_repcount == list->initial.length);
177 ASSERT (list->repeated.count <= list->repeated.allocated);
178 total_repcount = 0;
179 for (i = 0; i < list->repeated.count; i++)
181 verify_element (&list->repeated.element[i]);
182 total_repcount += list->repeated.element[i].repcount;
184 ASSERT (total_repcount == list->repeated.length);
187 #define VERIFY_LIST(list) verify_list (list)
190 /* ======================== Free a format_arg_list ======================== */
192 /* Free the data belonging to an argument list element. */
193 static inline void
194 free_element (struct format_arg *element)
196 if (element->type == FAT_LIST)
197 free_list (element->list);
200 /* Free an argument list. */
201 /* Memory effects: Frees list. */
202 static void
203 free_list (struct format_arg_list *list)
205 unsigned int i;
207 for (i = 0; i < list->initial.count; i++)
208 free_element (&list->initial.element[i]);
209 if (list->initial.element != NULL)
210 free (list->initial.element);
212 for (i = 0; i < list->repeated.count; i++)
213 free_element (&list->repeated.element[i]);
214 if (list->repeated.element != NULL)
215 free (list->repeated.element);
219 /* ======================== Copy a format_arg_list ======================== */
221 /* Copy the data belonging to an argument list element. */
222 static inline void
223 copy_element (struct format_arg *newelement,
224 const struct format_arg *oldelement)
226 newelement->repcount = oldelement->repcount;
227 newelement->presence = oldelement->presence;
228 newelement->type = oldelement->type;
229 if (oldelement->type == FAT_LIST)
230 newelement->list = copy_list (oldelement->list);
233 /* Copy an argument list. */
234 /* Memory effects: Freshly allocated result. */
235 static struct format_arg_list *
236 copy_list (const struct format_arg_list *list)
238 struct format_arg_list *newlist;
239 unsigned int length;
240 unsigned int i;
242 VERIFY_LIST (list);
244 newlist =
245 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
247 newlist->initial.count = newlist->initial.allocated = list->initial.count;
248 length = 0;
249 if (list->initial.count == 0)
250 newlist->initial.element = NULL;
251 else
253 newlist->initial.element =
254 (struct format_arg *)
255 xmalloc (newlist->initial.allocated * sizeof (struct format_arg));
256 for (i = 0; i < list->initial.count; i++)
258 copy_element (&newlist->initial.element[i],
259 &list->initial.element[i]);
260 length += list->initial.element[i].repcount;
263 ASSERT (length == list->initial.length);
264 newlist->initial.length = length;
266 newlist->repeated.count = newlist->repeated.allocated = list->repeated.count;
267 length = 0;
268 if (list->repeated.count == 0)
269 newlist->repeated.element = NULL;
270 else
272 newlist->repeated.element =
273 (struct format_arg *)
274 xmalloc (newlist->repeated.allocated * sizeof (struct format_arg));
275 for (i = 0; i < list->repeated.count; i++)
277 copy_element (&newlist->repeated.element[i],
278 &list->repeated.element[i]);
279 length += list->repeated.element[i].repcount;
282 ASSERT (length == list->repeated.length);
283 newlist->repeated.length = length;
285 VERIFY_LIST (newlist);
287 return newlist;
291 /* ===================== Compare two format_arg_lists ===================== */
293 /* Tests whether two normalized argument constraints are equivalent,
294 ignoring the repcount. */
295 static bool
296 equal_element (const struct format_arg * e1, const struct format_arg * e2)
298 return (e1->presence == e2->presence
299 && e1->type == e2->type
300 && (e1->type == FAT_LIST ? equal_list (e1->list, e2->list) : true));
303 /* Tests whether two normalized argument list constraints are equivalent. */
304 /* Memory effects: none. */
305 static bool
306 equal_list (const struct format_arg_list *list1,
307 const struct format_arg_list *list2)
309 unsigned int n, i;
311 VERIFY_LIST (list1);
312 VERIFY_LIST (list2);
314 n = list1->initial.count;
315 if (n != list2->initial.count)
316 return false;
317 for (i = 0; i < n; i++)
319 const struct format_arg * e1 = &list1->initial.element[i];
320 const struct format_arg * e2 = &list2->initial.element[i];
322 if (!(e1->repcount == e2->repcount && equal_element (e1, e2)))
323 return false;
326 n = list1->repeated.count;
327 if (n != list2->repeated.count)
328 return false;
329 for (i = 0; i < n; i++)
331 const struct format_arg * e1 = &list1->repeated.element[i];
332 const struct format_arg * e2 = &list2->repeated.element[i];
334 if (!(e1->repcount == e2->repcount && equal_element (e1, e2)))
335 return false;
338 return true;
342 /* ===================== Incremental memory allocation ===================== */
344 /* Ensure list->initial.allocated >= newcount. */
345 static inline void
346 ensure_initial_alloc (struct format_arg_list *list, unsigned int newcount)
348 if (newcount > list->initial.allocated)
350 list->initial.allocated =
351 MAX (2 * list->initial.allocated + 1, newcount);
352 list->initial.element =
353 (struct format_arg *)
354 xrealloc (list->initial.element,
355 list->initial.allocated * sizeof (struct format_arg));
359 /* Ensure list->initial.allocated > list->initial.count. */
360 static inline void
361 grow_initial_alloc (struct format_arg_list *list)
363 if (list->initial.count >= list->initial.allocated)
365 list->initial.allocated =
366 MAX (2 * list->initial.allocated + 1, list->initial.count + 1);
367 list->initial.element =
368 (struct format_arg *)
369 xrealloc (list->initial.element,
370 list->initial.allocated * sizeof (struct format_arg));
374 /* Ensure list->repeated.allocated >= newcount. */
375 static inline void
376 ensure_repeated_alloc (struct format_arg_list *list, unsigned int newcount)
378 if (newcount > list->repeated.allocated)
380 list->repeated.allocated =
381 MAX (2 * list->repeated.allocated + 1, newcount);
382 list->repeated.element =
383 (struct format_arg *)
384 xrealloc (list->repeated.element,
385 list->repeated.allocated * sizeof (struct format_arg));
389 /* Ensure list->repeated.allocated > list->repeated.count. */
390 static inline void
391 grow_repeated_alloc (struct format_arg_list *list)
393 if (list->repeated.count >= list->repeated.allocated)
395 list->repeated.allocated =
396 MAX (2 * list->repeated.allocated + 1, list->repeated.count + 1);
397 list->repeated.element =
398 (struct format_arg *)
399 xrealloc (list->repeated.element,
400 list->repeated.allocated * sizeof (struct format_arg));
405 /* ====================== Normalize a format_arg_list ====================== */
407 /* Normalize an argument list constraint, assuming all sublists are already
408 normalized. */
409 /* Memory effects: Destructively modifies list. */
410 static void
411 normalize_outermost_list (struct format_arg_list *list)
413 unsigned int n, i, j;
415 /* Step 1: Combine adjacent elements.
416 Copy from i to j, keeping 0 <= j <= i. */
418 n = list->initial.count;
419 for (i = j = 0; i < n; i++)
420 if (j > 0
421 && equal_element (&list->initial.element[i],
422 &list->initial.element[j-1]))
424 list->initial.element[j-1].repcount +=
425 list->initial.element[i].repcount;
426 free_element (&list->initial.element[i]);
428 else
430 if (j < i)
431 list->initial.element[j] = list->initial.element[i];
432 j++;
434 list->initial.count = j;
436 n = list->repeated.count;
437 for (i = j = 0; i < n; i++)
438 if (j > 0
439 && equal_element (&list->repeated.element[i],
440 &list->repeated.element[j-1]))
442 list->repeated.element[j-1].repcount +=
443 list->repeated.element[i].repcount;
444 free_element (&list->repeated.element[i]);
446 else
448 if (j < i)
449 list->repeated.element[j] = list->repeated.element[i];
450 j++;
452 list->repeated.count = j;
454 /* Nothing more to be done if the loop segment is empty. */
455 if (list->repeated.count > 0)
457 unsigned int m, repcount0_extra;
459 /* Step 2: Reduce the loop period. */
460 n = list->repeated.count;
461 repcount0_extra = 0;
462 if (n > 1
463 && equal_element (&list->repeated.element[0],
464 &list->repeated.element[n-1]))
466 repcount0_extra = list->repeated.element[n-1].repcount;
467 n--;
469 /* Proceed as if the loop period were n, with
470 list->repeated.element[0].repcount incremented by repcount0_extra. */
471 for (m = 2; m <= n / 2; n++)
472 if ((n % m) == 0)
474 /* m is a divisor of n. Try to reduce the loop period to n. */
475 bool ok = true;
477 for (i = 0; i < n - m; i++)
478 if (!((list->repeated.element[i].repcount
479 + (i == 0 ? repcount0_extra : 0)
480 == list->repeated.element[i+m].repcount)
481 && equal_element (&list->repeated.element[i],
482 &list->repeated.element[i+m])))
484 ok = false;
485 break;
487 if (ok)
489 for (i = m; i < n; i++)
490 free_element (&list->repeated.element[i]);
491 if (n < list->repeated.count)
492 list->repeated.element[m] = list->repeated.element[n];
493 list->repeated.count = list->repeated.count - n + m;
494 list->repeated.length /= n / m;
495 break;
499 /* Step 3: Roll as much as possible of the initial segment's tail
500 into the loop. */
501 if (list->repeated.count == 1)
503 if (list->initial.count > 0
504 && equal_element (&list->initial.element[list->initial.count-1],
505 &list->repeated.element[0]))
507 /* Roll the last element of the initial segment into the loop.
508 Its repcount is irrelevant. The second-to-last element is
509 certainly different and doesn't need to be considered. */
510 list->initial.length -=
511 list->initial.element[list->initial.count-1].repcount;
512 list->initial.count--;
515 else
517 while (list->initial.count > 0
518 && equal_element (&list->initial.element[list->initial.count-1],
519 &list->repeated.element[list->repeated.count-1]))
521 unsigned int moved_repcount =
522 MIN (list->initial.element[list->initial.count-1].repcount,
523 list->repeated.element[list->repeated.count-1].repcount);
525 /* Add the element at the start of list->repeated. */
526 if (equal_element (&list->repeated.element[0],
527 &list->repeated.element[list->repeated.count-1]))
528 list->repeated.element[0].repcount += moved_repcount;
529 else
531 unsigned int newcount = list->repeated.count + 1;
532 ensure_repeated_alloc (list, newcount);
533 for (i = newcount - 1; i > 0; i--)
534 list->repeated.element[i] = list->repeated.element[i-1];
535 list->repeated.count = newcount;
536 copy_element (&list->repeated.element[0],
537 &list->repeated.element[list->repeated.count-1]);
538 list->repeated.element[0].repcount = moved_repcount;
541 /* Remove the element from the end of list->repeated. */
542 list->repeated.element[list->repeated.count-1].repcount -=
543 moved_repcount;
544 if (list->repeated.element[list->repeated.count-1].repcount == 0)
546 free_element (&list->repeated.element[list->repeated.count-1]);
547 list->repeated.count--;
550 /* Remove the element from the end of list->initial. */
551 list->initial.element[list->initial.count-1].repcount -=
552 moved_repcount;
553 if (list->initial.element[list->initial.count-1].repcount == 0)
555 free_element (&list->initial.element[list->initial.count-1]);
556 list->initial.count--;
558 list->initial.length -= moved_repcount;
564 /* Normalize an argument list constraint. */
565 /* Memory effects: Destructively modifies list. */
566 static void
567 normalize_list (struct format_arg_list *list)
569 unsigned int n, i;
571 VERIFY_LIST (list);
573 /* First normalize all elements, recursively. */
574 n = list->initial.count;
575 for (i = 0; i < n; i++)
576 if (list->initial.element[i].type == FAT_LIST)
577 normalize_list (list->initial.element[i].list);
578 n = list->repeated.count;
579 for (i = 0; i < n; i++)
580 if (list->repeated.element[i].type == FAT_LIST)
581 normalize_list (list->repeated.element[i].list);
583 /* Then normalize the top level list. */
584 normalize_outermost_list (list);
586 VERIFY_LIST (list);
590 /* ===================== Unconstrained and empty lists ===================== */
592 /* It's easier to allocate these on demand, than to be careful not to
593 accidentally modify statically allocated lists. */
596 /* Create an unconstrained argument list. */
597 /* Memory effects: Freshly allocated result. */
598 static struct format_arg_list *
599 make_unconstrained_list ()
601 struct format_arg_list *list;
603 list = (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
604 list->initial.count = 0;
605 list->initial.allocated = 0;
606 list->initial.element = NULL;
607 list->initial.length = 0;
608 list->repeated.count = 1;
609 list->repeated.allocated = 1;
610 list->repeated.element =
611 (struct format_arg *) xmalloc (1 * sizeof (struct format_arg));
612 list->repeated.element[0].repcount = 1;
613 list->repeated.element[0].presence = FCT_OPTIONAL;
614 list->repeated.element[0].type = FAT_OBJECT;
615 list->repeated.length = 1;
617 VERIFY_LIST (list);
619 return list;
623 /* Create an empty argument list. */
624 /* Memory effects: Freshly allocated result. */
625 static struct format_arg_list *
626 make_empty_list ()
628 struct format_arg_list *list;
630 list = (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
631 list->initial.count = 0;
632 list->initial.allocated = 0;
633 list->initial.element = NULL;
634 list->initial.length = 0;
635 list->repeated.count = 0;
636 list->repeated.allocated = 0;
637 list->repeated.element = NULL;
638 list->repeated.length = 0;
640 VERIFY_LIST (list);
642 return list;
646 /* Test for an empty list. */
647 /* Memory effects: none. */
648 static bool
649 is_empty_list (const struct format_arg_list *list)
651 return (list->initial.count == 0 && list->repeated.count == 0);
655 /* ======================== format_arg_list surgery ======================== */
657 /* Unfold list->repeated m times, where m >= 1.
658 Assumes list->repeated.count > 0. */
659 /* Memory effects: list is destructively modified. */
660 static void
661 unfold_loop (struct format_arg_list *list, unsigned int m)
663 unsigned int i, j, k;
665 if (m > 1)
667 unsigned int newcount = list->repeated.count * m;
668 ensure_repeated_alloc (list, newcount);
669 i = list->repeated.count;
670 for (k = 1; k < m; k++)
671 for (j = 0; j < list->repeated.count; j++, i++)
672 copy_element (&list->repeated.element[i], &list->repeated.element[j]);
673 list->repeated.count = newcount;
674 list->repeated.length = list->repeated.length * m;
678 /* Ensure list->initial.length := m, where m >= list->initial.length.
679 Assumes list->repeated.count > 0. */
680 /* Memory effects: list is destructively modified. */
681 static void
682 rotate_loop (struct format_arg_list *list, unsigned int m)
684 if (m == list->initial.length)
685 return;
687 if (list->repeated.count == 1)
689 /* Instead of multiple copies of list->repeated.element[0], a single
690 copy with higher repcount is appended to list->initial. */
691 unsigned int i, newcount;
693 newcount = list->initial.count + 1;
694 ensure_initial_alloc (list, newcount);
695 i = list->initial.count;
696 copy_element (&list->initial.element[i], &list->repeated.element[0]);
697 list->initial.element[i].repcount = m - list->initial.length;
698 list->initial.count = newcount;
699 list->initial.length = m;
701 else
703 unsigned int n = list->repeated.length;
705 /* Write m = list->initial.length + q * n + r with 0 <= r < n. */
706 unsigned int q = (m - list->initial.length) / n;
707 unsigned int r = (m - list->initial.length) % n;
709 /* Determine how many entries of list->repeated are needed for
710 length r. */
711 unsigned int s;
712 unsigned int t;
714 for (t = r, s = 0;
715 s < list->repeated.count && t >= list->repeated.element[s].repcount;
716 t -= list->repeated.element[s].repcount, s++)
719 /* s must be < list->repeated.count, otherwise r would have been >= n. */
720 ASSERT (s < list->repeated.count);
722 /* So we need to add to list->initial:
723 q full copies of list->repeated,
724 plus the s first elements of list->repeated,
725 plus, if t > 0, a splitoff of list->repeated.element[s]. */
727 unsigned int i, j, k, newcount;
729 i = list->initial.count;
730 newcount = i + q * list->repeated.count + s + (t > 0 ? 1 : 0);
731 ensure_initial_alloc (list, newcount);
732 for (k = 0; k < q; k++)
733 for (j = 0; j < list->repeated.count; j++, i++)
734 copy_element (&list->initial.element[i],
735 &list->repeated.element[j]);
736 for (j = 0; j < s; j++, i++)
737 copy_element (&list->initial.element[i], &list->repeated.element[j]);
738 if (t > 0)
740 copy_element (&list->initial.element[i],
741 &list->repeated.element[j]);
742 list->initial.element[i].repcount = t;
743 i++;
745 ASSERT (i == newcount);
746 list->initial.count = newcount;
747 /* The new length of the initial segment is
748 = list->initial.length
749 + q * list->repeated.length
750 + list->repeated[0..s-1].repcount + t
751 = list->initial.length + q * n + r
752 = m.
754 list->initial.length = m;
757 /* And rotate list->repeated. */
758 if (r > 0)
760 unsigned int i, j, oldcount, newcount;
761 struct format_arg *newelement;
763 oldcount = list->repeated.count;
764 newcount = list->repeated.count + (t > 0 ? 1 : 0);
765 newelement =
766 (struct format_arg *)
767 xmalloc (newcount * sizeof (struct format_arg));
768 i = 0;
769 for (j = s; j < oldcount; j++, i++)
770 newelement[i] = list->repeated.element[j];
771 for (j = 0; j < s; j++, i++)
772 newelement[i] = list->repeated.element[j];
773 if (t > 0)
775 copy_element (&newelement[oldcount], &newelement[0]);
776 newelement[0].repcount -= t;
777 newelement[oldcount].repcount = t;
779 free (list->repeated.element);
780 list->repeated.element = newelement;
786 /* Ensure index n in the initial segment falls on a split between elements,
787 i.e. if 0 < n < list->initial.length, then n-1 and n are covered by two
788 different adjacent elements. */
789 /* Memory effects: list is destructively modified. */
790 static unsigned int
791 initial_splitelement (struct format_arg_list *list, unsigned int n)
793 unsigned int s;
794 unsigned int t;
795 unsigned int oldrepcount;
796 unsigned int newcount;
797 unsigned int i;
799 VERIFY_LIST (list);
801 if (n > list->initial.length)
803 ASSERT (list->repeated.count > 0);
804 rotate_loop (list, n);
805 ASSERT (n <= list->initial.length);
808 /* Determine how many entries of list->initial need to be skipped. */
809 for (t = n, s = 0;
810 s < list->initial.count && t >= list->initial.element[s].repcount;
811 t -= list->initial.element[s].repcount, s++)
814 if (t == 0)
815 return s;
817 ASSERT (s < list->initial.count);
819 /* Split the entry into two entries. */
820 oldrepcount = list->initial.element[s].repcount;
821 newcount = list->initial.count + 1;
822 ensure_initial_alloc (list, newcount);
823 for (i = list->initial.count - 1; i > s; i--)
824 list->initial.element[i+1] = list->initial.element[i];
825 copy_element (&list->initial.element[s+1], &list->initial.element[s]);
826 list->initial.element[s].repcount = t;
827 list->initial.element[s+1].repcount = oldrepcount - t;
828 list->initial.count = newcount;
830 VERIFY_LIST (list);
832 return s+1;
836 /* Ensure index n in the initial segment is not shared. Return its index. */
837 /* Memory effects: list is destructively modified. */
838 static unsigned int
839 initial_unshare (struct format_arg_list *list, unsigned int n)
841 /* This does the same side effects as
842 initial_splitelement (list, n);
843 initial_splitelement (list, n + 1);
845 unsigned int s;
846 unsigned int t;
848 VERIFY_LIST (list);
850 if (n >= list->initial.length)
852 ASSERT (list->repeated.count > 0);
853 rotate_loop (list, n + 1);
854 ASSERT (n < list->initial.length);
857 /* Determine how many entries of list->initial need to be skipped. */
858 for (t = n, s = 0;
859 s < list->initial.count && t >= list->initial.element[s].repcount;
860 t -= list->initial.element[s].repcount, s++)
863 /* s must be < list->initial.count. */
864 ASSERT (s < list->initial.count);
866 if (list->initial.element[s].repcount > 1)
868 /* Split the entry into at most three entries: for indices < n,
869 for index n, and for indices > n. */
870 unsigned int oldrepcount = list->initial.element[s].repcount;
871 unsigned int newcount =
872 list->initial.count + (t == 0 || t == oldrepcount - 1 ? 1 : 2);
873 ensure_initial_alloc (list, newcount);
874 if (t == 0 || t == oldrepcount - 1)
876 unsigned int i;
878 for (i = list->initial.count - 1; i > s; i--)
879 list->initial.element[i+1] = list->initial.element[i];
880 copy_element (&list->initial.element[s+1], &list->initial.element[s]);
881 if (t == 0)
883 list->initial.element[s].repcount = 1;
884 list->initial.element[s+1].repcount = oldrepcount - 1;
886 else
888 list->initial.element[s].repcount = oldrepcount - 1;
889 list->initial.element[s+1].repcount = 1;
892 else
894 unsigned int i;
896 for (i = list->initial.count - 1; i > s; i--)
897 list->initial.element[i+2] = list->initial.element[i];
898 copy_element (&list->initial.element[s+2], &list->initial.element[s]);
899 copy_element (&list->initial.element[s+1], &list->initial.element[s]);
900 list->initial.element[s].repcount = t;
901 list->initial.element[s+1].repcount = 1;
902 list->initial.element[s+2].repcount = oldrepcount - 1 - t;
904 list->initial.count = newcount;
905 if (t > 0)
906 s++;
909 /* Now the entry for index n has repcount 1. */
910 ASSERT (list->initial.element[s].repcount == 1);
912 VERIFY_LIST (list);
914 return s;
918 /* Add n unconstrained elements at the front of the list. */
919 /* Memory effects: list is destructively modified. */
920 static void
921 shift_list (struct format_arg_list *list, unsigned int n)
923 VERIFY_LIST (list);
925 if (n > 0)
927 unsigned int i;
929 grow_initial_alloc (list);
930 for (i = list->initial.count; i > 0; i--)
931 list->initial.element[i] = list->initial.element[i-1];
932 list->initial.element[0].repcount = n;
933 list->initial.element[0].presence = FCT_REQUIRED;
934 list->initial.element[0].type = FAT_OBJECT;
935 list->initial.count++;
936 list->initial.length += n;
938 normalize_outermost_list (list);
941 VERIFY_LIST (list);
945 /* ================= Intersection of two format_arg_lists ================= */
947 /* Create the intersection (i.e. combined constraints) of two argument
948 constraints. Return false if the intersection is empty, i.e. if the
949 two constraints give a contradiction. */
950 /* Memory effects: Freshly allocated element's sublist. */
951 static bool
952 make_intersected_element (struct format_arg *re,
953 const struct format_arg * e1,
954 const struct format_arg * e2)
956 /* Intersect the cdr types. */
957 if (e1->presence == FCT_REQUIRED || e2->presence == FCT_REQUIRED)
958 re->presence = FCT_REQUIRED;
959 else
960 re->presence = FCT_OPTIONAL;
962 /* Intersect the arg types. */
963 if (e1->type == FAT_OBJECT)
965 re->type = e2->type;
966 if (re->type == FAT_LIST)
967 re->list = copy_list (e2->list);
969 else if (e2->type == FAT_OBJECT)
971 re->type = e1->type;
972 if (re->type == FAT_LIST)
973 re->list = copy_list (e1->list);
975 else if (e1->type == FAT_LIST
976 && (e2->type == FAT_CHARACTER_INTEGER_NULL
977 || e2->type == FAT_CHARACTER_NULL
978 || e2->type == FAT_INTEGER_NULL))
980 re->type = e1->type;
981 re->list = make_intersection_with_empty_list (e1->list);
982 if (re->list == NULL)
983 return false;
985 else if (e2->type == FAT_LIST
986 && (e1->type == FAT_CHARACTER_INTEGER_NULL
987 || e1->type == FAT_CHARACTER_NULL
988 || e1->type == FAT_INTEGER_NULL))
990 re->type = e2->type;
991 re->list = make_intersection_with_empty_list (e2->list);
992 if (re->list == NULL)
993 return false;
995 else if (e1->type == FAT_CHARACTER_INTEGER_NULL
996 && (e2->type == FAT_CHARACTER_NULL || e2->type == FAT_CHARACTER
997 || e2->type == FAT_INTEGER_NULL || e2->type == FAT_INTEGER))
999 re->type = e2->type;
1001 else if (e2->type == FAT_CHARACTER_INTEGER_NULL
1002 && (e1->type == FAT_CHARACTER_NULL || e1->type == FAT_CHARACTER
1003 || e1->type == FAT_INTEGER_NULL || e1->type == FAT_INTEGER))
1005 re->type = e1->type;
1007 else if (e1->type == FAT_CHARACTER_NULL && e2->type == FAT_CHARACTER)
1009 re->type = e2->type;
1011 else if (e2->type == FAT_CHARACTER_NULL && e1->type == FAT_CHARACTER)
1013 re->type = e1->type;
1015 else if (e1->type == FAT_INTEGER_NULL && e2->type == FAT_INTEGER)
1017 re->type = e2->type;
1019 else if (e2->type == FAT_INTEGER_NULL && e1->type == FAT_INTEGER)
1021 re->type = e1->type;
1023 else if (e1->type == FAT_REAL && e2->type == FAT_INTEGER)
1025 re->type = e2->type;
1027 else if (e2->type == FAT_REAL && e1->type == FAT_INTEGER)
1029 re->type = e1->type;
1031 else if (e1->type == FAT_COMPLEX
1032 && (e2->type == FAT_REAL || e2->type == FAT_INTEGER))
1034 re->type = e2->type;
1036 else if (e2->type == FAT_COMPLEX
1037 && (e1->type == FAT_REAL || e1->type == FAT_INTEGER))
1039 re->type = e1->type;
1041 else if (e1->type == e2->type)
1043 re->type = e1->type;
1044 if (re->type == FAT_LIST)
1046 re->list = make_intersected_list (copy_list (e1->list),
1047 copy_list (e2->list));
1048 if (re->list == NULL)
1049 return false;
1052 else
1053 /* Each of FAT_CHARACTER, FAT_INTEGER, FAT_LIST, FAT_FORMATSTRING
1054 matches only itself. Contradiction. */
1055 return false;
1057 return true;
1060 /* Append list->repeated to list->initial, and clear list->repeated. */
1061 /* Memory effects: list is destructively modified. */
1062 static void
1063 append_repeated_to_initial (struct format_arg_list *list)
1065 if (list->repeated.count > 0)
1067 /* Move list->repeated over to list->initial. */
1068 unsigned int i, j, newcount;
1070 newcount = list->initial.count + list->repeated.count;
1071 ensure_initial_alloc (list, newcount);
1072 i = list->initial.count;
1073 for (j = 0; j < list->repeated.count; j++, i++)
1074 list->initial.element[i] = list->repeated.element[j];
1075 list->initial.count = newcount;
1076 list->initial.length = list->initial.length + list->repeated.length;
1077 free (list->repeated.element);
1078 list->repeated.element = NULL;
1079 list->repeated.allocated = 0;
1080 list->repeated.count = 0;
1081 list->repeated.length = 0;
1085 /* Handle a contradiction during building of a format_arg_list.
1086 The list consists only of an initial segment. The repeated segment is
1087 empty. This function searches the last FCT_OPTIONAL and cuts off the
1088 list at this point, or - if none is found - returns NULL. */
1089 /* Memory effects: list is destructively modified. If NULL is returned,
1090 list is freed. */
1091 static struct format_arg_list *
1092 backtrack_in_initial (struct format_arg_list *list)
1094 ASSERT (list->repeated.count == 0);
1096 while (list->initial.count > 0)
1098 unsigned int i = list->initial.count - 1;
1099 if (list->initial.element[i].presence == FCT_REQUIRED)
1101 /* Throw away this element. */
1102 list->initial.length -= list->initial.element[i].repcount;
1103 free_element (&list->initial.element[i]);
1104 list->initial.count = i;
1106 else /* list->initial.element[i].presence == FCT_OPTIONAL */
1108 /* The list must end here. */
1109 list->initial.length--;
1110 if (list->initial.element[i].repcount > 1)
1111 list->initial.element[i].repcount--;
1112 else
1114 free_element (&list->initial.element[i]);
1115 list->initial.count = i;
1117 VERIFY_LIST (list);
1118 return list;
1122 free_list (list);
1123 return NULL;
1126 /* Create the intersection (i.e. combined constraints) of two argument list
1127 constraints. Free both argument lists when done. Return NULL if the
1128 intersection is empty, i.e. if the two constraints give a contradiction. */
1129 /* Memory effects: list1 and list2 are freed. The result, if non-NULL, is
1130 freshly allocated. */
1131 static struct format_arg_list *
1132 make_intersected_list (struct format_arg_list *list1,
1133 struct format_arg_list *list2)
1135 struct format_arg_list *result;
1137 VERIFY_LIST (list1);
1138 VERIFY_LIST (list2);
1140 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1141 /* Step 1: Ensure list1->repeated.length == list2->repeated.length. */
1143 unsigned int n1 = list1->repeated.length;
1144 unsigned int n2 = list2->repeated.length;
1145 unsigned int g = gcd (n1, n2);
1146 unsigned int m1 = n2 / g; /* = lcm(n1,n2) / n1 */
1147 unsigned int m2 = n1 / g; /* = lcm(n1,n2) / n2 */
1149 unfold_loop (list1, m1);
1150 unfold_loop (list2, m2);
1151 /* Now list1->repeated.length = list2->repeated.length = lcm(n1,n2). */
1154 if (list1->repeated.length > 0 || list2->repeated.length > 0)
1155 /* Step 2: Ensure the initial segment of the result can be computed
1156 from the initial segments of list1 and list2. If both have a
1157 repeated segment, this means to ensure
1158 list1->initial.length == list2->initial.length. */
1160 unsigned int m = MAX (list1->initial.length, list2->initial.length);
1162 if (list1->repeated.length > 0)
1163 rotate_loop (list1, m);
1164 if (list2->repeated.length > 0)
1165 rotate_loop (list2, m);
1168 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1170 ASSERT (list1->initial.length == list2->initial.length);
1171 ASSERT (list1->repeated.length == list2->repeated.length);
1174 /* Step 3: Allocate the result. */
1175 result =
1176 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
1177 result->initial.count = 0;
1178 result->initial.allocated = 0;
1179 result->initial.element = NULL;
1180 result->initial.length = 0;
1181 result->repeated.count = 0;
1182 result->repeated.allocated = 0;
1183 result->repeated.element = NULL;
1184 result->repeated.length = 0;
1186 /* Step 4: Elementwise intersection of list1->initial, list2->initial. */
1188 struct format_arg *e1;
1189 struct format_arg *e2;
1190 unsigned int c1;
1191 unsigned int c2;
1193 e1 = list1->initial.element; c1 = list1->initial.count;
1194 e2 = list2->initial.element; c2 = list2->initial.count;
1195 while (c1 > 0 && c2 > 0)
1197 struct format_arg *re;
1199 /* Ensure room in result->initial. */
1200 grow_initial_alloc (result);
1201 re = &result->initial.element[result->initial.count];
1202 re->repcount = MIN (e1->repcount, e2->repcount);
1204 /* Intersect the argument types. */
1205 if (!make_intersected_element (re, e1, e2))
1207 /* If re->presence == FCT_OPTIONAL, the result list ends here. */
1208 if (re->presence == FCT_REQUIRED)
1209 /* Contradiction. Backtrack. */
1210 result = backtrack_in_initial (result);
1211 goto done;
1214 result->initial.count++;
1215 result->initial.length += re->repcount;
1217 e1->repcount -= re->repcount;
1218 if (e1->repcount == 0)
1220 e1++;
1221 c1--;
1223 e2->repcount -= re->repcount;
1224 if (e2->repcount == 0)
1226 e2++;
1227 c2--;
1231 if (list1->repeated.count == 0 && list2->repeated.count == 0)
1233 /* Intersecting two finite lists. */
1234 if (c1 > 0)
1236 /* list1 longer than list2. */
1237 if (e1->presence == FCT_REQUIRED)
1238 /* Contradiction. Backtrack. */
1239 result = backtrack_in_initial (result);
1241 else if (c2 > 0)
1243 /* list2 longer than list1. */
1244 if (e2->presence == FCT_REQUIRED)
1245 /* Contradiction. Backtrack. */
1246 result = backtrack_in_initial (result);
1248 goto done;
1250 else if (list1->repeated.count == 0)
1252 /* Intersecting a finite and an infinite list. */
1253 ASSERT (c1 == 0);
1254 if ((c2 > 0 ? e2->presence : list2->repeated.element[0].presence)
1255 == FCT_REQUIRED)
1256 /* Contradiction. Backtrack. */
1257 result = backtrack_in_initial (result);
1258 goto done;
1260 else if (list2->repeated.count == 0)
1262 /* Intersecting an infinite and a finite list. */
1263 ASSERT (c2 == 0);
1264 if ((c1 > 0 ? e1->presence : list1->repeated.element[0].presence)
1265 == FCT_REQUIRED)
1266 /* Contradiction. Backtrack. */
1267 result = backtrack_in_initial (result);
1268 goto done;
1270 /* Intersecting two infinite lists. */
1271 ASSERT (c1 == 0 && c2 == 0);
1274 /* Step 5: Elementwise intersection of list1->repeated, list2->repeated. */
1276 struct format_arg *e1;
1277 struct format_arg *e2;
1278 unsigned int c1;
1279 unsigned int c2;
1281 e1 = list1->repeated.element; c1 = list1->repeated.count;
1282 e2 = list2->repeated.element; c2 = list2->repeated.count;
1283 while (c1 > 0 && c2 > 0)
1285 struct format_arg *re;
1287 /* Ensure room in result->repeated. */
1288 grow_repeated_alloc (result);
1289 re = &result->repeated.element[result->repeated.count];
1290 re->repcount = MIN (e1->repcount, e2->repcount);
1292 /* Intersect the argument types. */
1293 if (!make_intersected_element (re, e1, e2))
1295 append_repeated_to_initial (result);
1297 /* If re->presence == FCT_OPTIONAL, the result list ends here. */
1298 if (re->presence == FCT_REQUIRED)
1299 /* Contradiction. Backtrack. */
1300 result = backtrack_in_initial (result);
1302 goto done;
1305 result->repeated.count++;
1306 result->repeated.length += re->repcount;
1308 e1->repcount -= re->repcount;
1309 if (e1->repcount == 0)
1311 e1++;
1312 c1--;
1314 e2->repcount -= re->repcount;
1315 if (e2->repcount == 0)
1317 e2++;
1318 c2--;
1321 ASSERT (c1 == 0 && c2 == 0);
1324 done:
1325 free_list (list1);
1326 free_list (list2);
1327 if (result != NULL)
1329 /* Undo the loop unfolding and unrolling done above. */
1330 normalize_outermost_list (result);
1331 VERIFY_LIST (result);
1333 return result;
1337 /* Create the intersection of an argument list and the empty list.
1338 Return NULL if the intersection is empty. */
1339 /* Memory effects: The result, if non-NULL, is freshly allocated. */
1340 static struct format_arg_list *
1341 make_intersection_with_empty_list (struct format_arg_list *list)
1343 #if 0 /* equivalent but slower */
1344 return make_intersected_list (copy_list (list), make_empty_list ());
1345 #else
1346 if (list->initial.count > 0
1347 ? list->initial.element[0].presence == FCT_REQUIRED
1348 : list->repeated.count > 0
1349 && list->repeated.element[0].presence == FCT_REQUIRED)
1350 return NULL;
1351 else
1352 return make_empty_list ();
1353 #endif
1357 #ifdef unused
1358 /* Create the intersection of two argument list constraints. NULL stands
1359 for an impossible situation, i.e. a contradiction. */
1360 /* Memory effects: list1 and list2 are freed if non-NULL. The result,
1361 if non-NULL, is freshly allocated. */
1362 static struct format_arg_list *
1363 intersection (struct format_arg_list *list1, struct format_arg_list *list2)
1365 if (list1 != NULL)
1367 if (list2 != NULL)
1368 return make_intersected_list (list1, list2);
1369 else
1371 free_list (list1);
1372 return NULL;
1375 else
1377 if (list2 != NULL)
1379 free_list (list2);
1380 return NULL;
1382 else
1383 return NULL;
1386 #endif
1389 /* ===================== Union of two format_arg_lists ===================== */
1391 /* Create the union (i.e. alternative constraints) of two argument
1392 constraints. */
1393 static void
1394 make_union_element (struct format_arg *re,
1395 const struct format_arg * e1,
1396 const struct format_arg * e2)
1398 /* Union of the cdr types. */
1399 if (e1->presence == FCT_REQUIRED && e2->presence == FCT_REQUIRED)
1400 re->presence = FCT_REQUIRED;
1401 else /* Either one of them is FCT_OPTIONAL. */
1402 re->presence = FCT_OPTIONAL;
1404 /* Union of the arg types. */
1405 if (e1->type == e2->type)
1407 re->type = e1->type;
1408 if (re->type == FAT_LIST)
1409 re->list = make_union_list (copy_list (e1->list),
1410 copy_list (e2->list));
1412 else if (e1->type == FAT_CHARACTER_INTEGER_NULL
1413 && (e2->type == FAT_CHARACTER_NULL || e2->type == FAT_CHARACTER
1414 || e2->type == FAT_INTEGER_NULL || e2->type == FAT_INTEGER))
1416 re->type = e1->type;
1418 else if (e2->type == FAT_CHARACTER_INTEGER_NULL
1419 && (e1->type == FAT_CHARACTER_NULL || e1->type == FAT_CHARACTER
1420 || e1->type == FAT_INTEGER_NULL || e1->type == FAT_INTEGER))
1422 re->type = e2->type;
1424 else if (e1->type == FAT_CHARACTER_NULL && e2->type == FAT_CHARACTER)
1426 re->type = e1->type;
1428 else if (e2->type == FAT_CHARACTER_NULL && e1->type == FAT_CHARACTER)
1430 re->type = e2->type;
1432 else if (e1->type == FAT_INTEGER_NULL && e2->type == FAT_INTEGER)
1434 re->type = e1->type;
1436 else if (e2->type == FAT_INTEGER_NULL && e1->type == FAT_INTEGER)
1438 re->type = e2->type;
1440 else if (e1->type == FAT_REAL && e2->type == FAT_INTEGER)
1442 re->type = e1->type;
1444 else if (e2->type == FAT_REAL && e1->type == FAT_INTEGER)
1446 re->type = e2->type;
1448 else if (e1->type == FAT_COMPLEX
1449 && (e2->type == FAT_REAL || e2->type == FAT_INTEGER))
1451 re->type = e1->type;
1453 else if (e2->type == FAT_COMPLEX
1454 && (e1->type == FAT_REAL || e1->type == FAT_INTEGER))
1456 re->type = e2->type;
1458 else if (e1->type == FAT_LIST && is_empty_list (e1->list))
1460 if (e2->type == FAT_CHARACTER_INTEGER_NULL
1461 || e2->type == FAT_CHARACTER_NULL
1462 || e2->type == FAT_INTEGER_NULL)
1463 re->type = e2->type;
1464 else if (e2->type == FAT_CHARACTER)
1465 re->type = FAT_CHARACTER_NULL;
1466 else if (e2->type == FAT_INTEGER)
1467 re->type = FAT_INTEGER_NULL;
1468 else
1469 re->type = FAT_OBJECT;
1471 else if (e2->type == FAT_LIST && is_empty_list (e2->list))
1473 if (e1->type == FAT_CHARACTER_INTEGER_NULL
1474 || e1->type == FAT_CHARACTER_NULL
1475 || e1->type == FAT_INTEGER_NULL)
1476 re->type = e1->type;
1477 else if (e1->type == FAT_CHARACTER)
1478 re->type = FAT_CHARACTER_NULL;
1479 else if (e1->type == FAT_INTEGER)
1480 re->type = FAT_INTEGER_NULL;
1481 else
1482 re->type = FAT_OBJECT;
1484 else if ((e1->type == FAT_CHARACTER || e1->type == FAT_CHARACTER_NULL)
1485 && (e2->type == FAT_INTEGER || e2->type == FAT_INTEGER_NULL))
1487 re->type = FAT_CHARACTER_INTEGER_NULL;
1489 else if ((e2->type == FAT_CHARACTER || e2->type == FAT_CHARACTER_NULL)
1490 && (e1->type == FAT_INTEGER || e1->type == FAT_INTEGER_NULL))
1492 re->type = FAT_CHARACTER_INTEGER_NULL;
1494 else
1496 /* Other union types are too hard to describe precisely. */
1497 re->type = FAT_OBJECT;
1501 /* Create the union (i.e. alternative constraints) of two argument list
1502 constraints. Free both argument lists when done. */
1503 /* Memory effects: list1 and list2 are freed. The result is freshly
1504 allocated. */
1505 static struct format_arg_list *
1506 make_union_list (struct format_arg_list *list1, struct format_arg_list *list2)
1508 struct format_arg_list *result;
1510 VERIFY_LIST (list1);
1511 VERIFY_LIST (list2);
1513 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1515 /* Step 1: Ensure list1->repeated.length == list2->repeated.length. */
1517 unsigned int n1 = list1->repeated.length;
1518 unsigned int n2 = list2->repeated.length;
1519 unsigned int g = gcd (n1, n2);
1520 unsigned int m1 = n2 / g; /* = lcm(n1,n2) / n1 */
1521 unsigned int m2 = n1 / g; /* = lcm(n1,n2) / n2 */
1523 unfold_loop (list1, m1);
1524 unfold_loop (list2, m2);
1525 /* Now list1->repeated.length = list2->repeated.length = lcm(n1,n2). */
1528 /* Step 2: Ensure that list1->initial.length == list2->initial.length. */
1530 unsigned int m = MAX (list1->initial.length, list2->initial.length);
1532 rotate_loop (list1, m);
1533 rotate_loop (list2, m);
1536 ASSERT (list1->initial.length == list2->initial.length);
1537 ASSERT (list1->repeated.length == list2->repeated.length);
1539 else if (list1->repeated.length > 0)
1541 /* Ensure the initial segment of the result can be computed from the
1542 initial segment of list1. */
1543 if (list2->initial.length >= list1->initial.length)
1545 rotate_loop (list1, list2->initial.length);
1546 if (list1->repeated.element[0].presence == FCT_REQUIRED)
1547 rotate_loop (list1, list1->initial.length + 1);
1550 else if (list2->repeated.length > 0)
1552 /* Ensure the initial segment of the result can be computed from the
1553 initial segment of list2. */
1554 if (list1->initial.length >= list2->initial.length)
1556 rotate_loop (list2, list1->initial.length);
1557 if (list2->repeated.element[0].presence == FCT_REQUIRED)
1558 rotate_loop (list2, list2->initial.length + 1);
1562 /* Step 3: Allocate the result. */
1563 result =
1564 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
1565 result->initial.count = 0;
1566 result->initial.allocated = 0;
1567 result->initial.element = NULL;
1568 result->initial.length = 0;
1569 result->repeated.count = 0;
1570 result->repeated.allocated = 0;
1571 result->repeated.element = NULL;
1572 result->repeated.length = 0;
1574 /* Step 4: Elementwise union of list1->initial, list2->initial. */
1576 struct format_arg *e1;
1577 struct format_arg *e2;
1578 unsigned int c1;
1579 unsigned int c2;
1581 e1 = list1->initial.element; c1 = list1->initial.count;
1582 e2 = list2->initial.element; c2 = list2->initial.count;
1583 while (c1 > 0 && c2 > 0)
1585 struct format_arg *re;
1587 /* Ensure room in result->initial. */
1588 grow_initial_alloc (result);
1589 re = &result->initial.element[result->initial.count];
1590 re->repcount = MIN (e1->repcount, e2->repcount);
1592 /* Union of the argument types. */
1593 make_union_element (re, e1, e2);
1595 result->initial.count++;
1596 result->initial.length += re->repcount;
1598 e1->repcount -= re->repcount;
1599 if (e1->repcount == 0)
1601 e1++;
1602 c1--;
1604 e2->repcount -= re->repcount;
1605 if (e2->repcount == 0)
1607 e2++;
1608 c2--;
1612 if (c1 > 0)
1614 /* list2 already terminated, but still more elements in list1->initial.
1615 Copy them all, but turn the first presence to FCT_OPTIONAL. */
1616 ASSERT (list2->repeated.count == 0);
1618 if (e1->presence == FCT_REQUIRED)
1620 struct format_arg *re;
1622 /* Ensure room in result->initial. */
1623 grow_initial_alloc (result);
1624 re = &result->initial.element[result->initial.count];
1625 copy_element (re, e1);
1626 re->presence = FCT_OPTIONAL;
1627 re->repcount = 1;
1628 result->initial.count++;
1629 result->initial.length += 1;
1630 e1->repcount -= 1;
1631 if (e1->repcount == 0)
1633 e1++;
1634 c1--;
1638 /* Ensure room in result->initial. */
1639 ensure_initial_alloc (result, result->initial.count + c1);
1640 while (c1 > 0)
1642 struct format_arg *re;
1644 re = &result->initial.element[result->initial.count];
1645 copy_element (re, e1);
1646 result->initial.count++;
1647 result->initial.length += re->repcount;
1648 e1++;
1649 c1--;
1652 else if (c2 > 0)
1654 /* list1 already terminated, but still more elements in list2->initial.
1655 Copy them all, but turn the first presence to FCT_OPTIONAL. */
1656 ASSERT (list1->repeated.count == 0);
1658 if (e2->presence == FCT_REQUIRED)
1660 struct format_arg *re;
1662 /* Ensure room in result->initial. */
1663 grow_initial_alloc (result);
1664 re = &result->initial.element[result->initial.count];
1665 copy_element (re, e2);
1666 re->presence = FCT_OPTIONAL;
1667 re->repcount = 1;
1668 result->initial.count++;
1669 result->initial.length += 1;
1670 e2->repcount -= 1;
1671 if (e2->repcount == 0)
1673 e2++;
1674 c2--;
1678 /* Ensure room in result->initial. */
1679 ensure_initial_alloc (result, result->initial.count + c2);
1680 while (c2 > 0)
1682 struct format_arg *re;
1684 re = &result->initial.element[result->initial.count];
1685 copy_element (re, e2);
1686 result->initial.count++;
1687 result->initial.length += re->repcount;
1688 e2++;
1689 c2--;
1692 ASSERT (c1 == 0 && c2 == 0);
1695 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1696 /* Step 5: Elementwise union of list1->repeated, list2->repeated. */
1698 struct format_arg *e1;
1699 struct format_arg *e2;
1700 unsigned int c1;
1701 unsigned int c2;
1703 e1 = list1->repeated.element; c1 = list1->repeated.count;
1704 e2 = list2->repeated.element; c2 = list2->repeated.count;
1705 while (c1 > 0 && c2 > 0)
1707 struct format_arg *re;
1709 /* Ensure room in result->repeated. */
1710 grow_repeated_alloc (result);
1711 re = &result->repeated.element[result->repeated.count];
1712 re->repcount = MIN (e1->repcount, e2->repcount);
1714 /* Union of the argument types. */
1715 make_union_element (re, e1, e2);
1717 result->repeated.count++;
1718 result->repeated.length += re->repcount;
1720 e1->repcount -= re->repcount;
1721 if (e1->repcount == 0)
1723 e1++;
1724 c1--;
1726 e2->repcount -= re->repcount;
1727 if (e2->repcount == 0)
1729 e2++;
1730 c2--;
1733 ASSERT (c1 == 0 && c2 == 0);
1735 else if (list1->repeated.length > 0)
1737 /* Turning FCT_REQUIRED into FCT_OPTIONAL was already handled in the
1738 initial segment. Just copy the repeated segment of list1. */
1739 unsigned int i;
1741 result->repeated.count = list1->repeated.count;
1742 result->repeated.allocated = result->repeated.count;
1743 result->repeated.element =
1744 (struct format_arg *)
1745 xmalloc (result->repeated.allocated * sizeof (struct format_arg));
1746 for (i = 0; i < list1->repeated.count; i++)
1747 copy_element (&result->repeated.element[i],
1748 &list1->repeated.element[i]);
1749 result->repeated.length = list1->repeated.length;
1751 else if (list2->repeated.length > 0)
1753 /* Turning FCT_REQUIRED into FCT_OPTIONAL was already handled in the
1754 initial segment. Just copy the repeated segment of list2. */
1755 unsigned int i;
1757 result->repeated.count = list2->repeated.count;
1758 result->repeated.allocated = result->repeated.count;
1759 result->repeated.element =
1760 (struct format_arg *)
1761 xmalloc (result->repeated.allocated * sizeof (struct format_arg));
1762 for (i = 0; i < list2->repeated.count; i++)
1763 copy_element (&result->repeated.element[i],
1764 &list2->repeated.element[i]);
1765 result->repeated.length = list2->repeated.length;
1768 free_list (list1);
1769 free_list (list2);
1770 /* Undo the loop unfolding and unrolling done above. */
1771 normalize_outermost_list (result);
1772 VERIFY_LIST (result);
1773 return result;
1777 /* Create the union of an argument list and the empty list. */
1778 /* Memory effects: list is freed. The result is freshly allocated. */
1779 static struct format_arg_list *
1780 make_union_with_empty_list (struct format_arg_list *list)
1782 #if 0 /* equivalent but slower */
1783 return make_union_list (list, make_empty_list ());
1784 #else
1785 VERIFY_LIST (list);
1787 if (list->initial.count > 0
1788 ? list->initial.element[0].presence == FCT_REQUIRED
1789 : list->repeated.count > 0
1790 && list->repeated.element[0].presence == FCT_REQUIRED)
1792 initial_splitelement (list, 1);
1793 ASSERT (list->initial.count > 0);
1794 ASSERT (list->initial.element[0].repcount == 1);
1795 ASSERT (list->initial.element[0].presence == FCT_REQUIRED);
1796 list->initial.element[0].presence = FCT_OPTIONAL;
1798 /* We might need to merge list->initial.element[0] and
1799 list->initial.element[1]. */
1800 normalize_outermost_list (list);
1803 VERIFY_LIST (list);
1805 return list;
1806 #endif
1810 /* Create the union of two argument list constraints. NULL stands for an
1811 impossible situation, i.e. a contradiction. */
1812 /* Memory effects: list1 and list2 are freed if non-NULL. The result,
1813 if non-NULL, is freshly allocated. */
1814 static struct format_arg_list *
1815 union (struct format_arg_list *list1, struct format_arg_list *list2)
1817 if (list1 != NULL)
1819 if (list2 != NULL)
1820 return make_union_list (list1, list2);
1821 else
1822 return list1;
1824 else
1826 if (list2 != NULL)
1827 return list2;
1828 else
1829 return NULL;
1834 /* =========== Adding specific constraints to a format_arg_list =========== */
1837 /* Test whether arguments 0..n are required arguments in a list. */
1838 static bool
1839 is_required (const struct format_arg_list *list, unsigned int n)
1841 unsigned int s;
1842 unsigned int t;
1844 /* We'll check whether the first n+1 presence flags are FCT_REQUIRED. */
1845 t = n + 1;
1847 /* Walk the list->initial segment. */
1848 for (s = 0;
1849 s < list->initial.count && t >= list->initial.element[s].repcount;
1850 t -= list->initial.element[s].repcount, s++)
1851 if (list->initial.element[s].presence != FCT_REQUIRED)
1852 return false;
1854 if (t == 0)
1855 return true;
1857 if (s < list->initial.count)
1859 if (list->initial.element[s].presence != FCT_REQUIRED)
1860 return false;
1861 else
1862 return true;
1865 /* Walk the list->repeated segment. */
1866 if (list->repeated.count == 0)
1867 return false;
1869 for (s = 0;
1870 s < list->repeated.count && t >= list->repeated.element[s].repcount;
1871 t -= list->repeated.element[s].repcount, s++)
1872 if (list->repeated.element[s].presence != FCT_REQUIRED)
1873 return false;
1875 if (t == 0)
1876 return true;
1878 if (s < list->repeated.count)
1880 if (list->repeated.element[s].presence != FCT_REQUIRED)
1881 return false;
1882 else
1883 return true;
1886 /* The list->repeated segment consists only of FCT_REQUIRED. So,
1887 regardless how many more passes through list->repeated would be
1888 needed until t becomes 0, the result is true. */
1889 return true;
1893 /* Add a constraint to an argument list, namely that the arguments 0...n are
1894 present. NULL stands for an impossible situation, i.e. a contradiction. */
1895 /* Memory effects: list is freed. The result is freshly allocated. */
1896 static struct format_arg_list *
1897 add_required_constraint (struct format_arg_list *list, unsigned int n)
1899 unsigned int i, rest;
1901 if (list == NULL)
1902 return NULL;
1904 VERIFY_LIST (list);
1906 if (list->repeated.count == 0 && list->initial.length <= n)
1908 /* list is already constrained to have at most length n.
1909 Contradiction. */
1910 free_list (list);
1911 return NULL;
1914 initial_splitelement (list, n + 1);
1916 for (i = 0, rest = n + 1; rest > 0; )
1918 list->initial.element[i].presence = FCT_REQUIRED;
1919 rest -= list->initial.element[i].repcount;
1920 i++;
1923 VERIFY_LIST (list);
1925 return list;
1929 /* Add a constraint to an argument list, namely that the argument n is
1930 never present. NULL stands for an impossible situation, i.e. a
1931 contradiction. */
1932 /* Memory effects: list is freed. The result is freshly allocated. */
1933 static struct format_arg_list *
1934 add_end_constraint (struct format_arg_list *list, unsigned int n)
1936 unsigned int s, i;
1937 enum format_cdr_type n_presence;
1939 if (list == NULL)
1940 return NULL;
1942 VERIFY_LIST (list);
1944 if (list->repeated.count == 0 && list->initial.length <= n)
1945 /* list is already constrained to have at most length n. */
1946 return list;
1948 s = initial_splitelement (list, n);
1949 n_presence =
1950 (s < list->initial.count
1951 ? /* n < list->initial.length */ list->initial.element[s].presence
1952 : /* n >= list->initial.length */ list->repeated.element[0].presence);
1954 for (i = s; i < list->initial.count; i++)
1956 list->initial.length -= list->initial.element[i].repcount;
1957 free_element (&list->initial.element[i]);
1959 list->initial.count = s;
1961 for (i = 0; i < list->repeated.count; i++)
1962 free_element (&list->repeated.element[i]);
1963 if (list->repeated.element != NULL)
1964 free (list->repeated.element);
1965 list->repeated.element = NULL;
1966 list->repeated.allocated = 0;
1967 list->repeated.count = 0;
1968 list->repeated.length = 0;
1970 if (n_presence == FCT_REQUIRED)
1971 return backtrack_in_initial (list);
1972 else
1973 return list;
1977 /* Add a constraint to an argument list, namely that the argument n is
1978 of a given type. NULL stands for an impossible situation, i.e. a
1979 contradiction. Assumes a preceding add_required_constraint (list, n). */
1980 /* Memory effects: list is freed. The result is freshly allocated. */
1981 static struct format_arg_list *
1982 add_type_constraint (struct format_arg_list *list, unsigned int n,
1983 enum format_arg_type type)
1985 unsigned int s;
1986 struct format_arg newconstraint;
1987 struct format_arg tmpelement;
1989 if (list == NULL)
1990 return NULL;
1992 /* Through the previous add_required_constraint, we can assume
1993 list->initial.length >= n+1. */
1995 s = initial_unshare (list, n);
1997 newconstraint.presence = FCT_OPTIONAL;
1998 newconstraint.type = type;
1999 if (!make_intersected_element (&tmpelement,
2000 &list->initial.element[s], &newconstraint))
2001 return add_end_constraint (list, n);
2002 free_element (&list->initial.element[s]);
2003 list->initial.element[s].type = tmpelement.type;
2004 list->initial.element[s].list = tmpelement.list;
2006 VERIFY_LIST (list);
2008 return list;
2012 /* Add a constraint to an argument list, namely that the argument n is
2013 of a given list type. NULL stands for an impossible situation, i.e. a
2014 contradiction. Assumes a preceding add_required_constraint (list, n). */
2015 /* Memory effects: list is freed. The result is freshly allocated. */
2016 static struct format_arg_list *
2017 add_listtype_constraint (struct format_arg_list *list, unsigned int n,
2018 enum format_arg_type type,
2019 struct format_arg_list *sublist)
2021 unsigned int s;
2022 struct format_arg newconstraint;
2023 struct format_arg tmpelement;
2025 if (list == NULL)
2026 return NULL;
2028 /* Through the previous add_required_constraint, we can assume
2029 list->initial.length >= n+1. */
2031 s = initial_unshare (list, n);
2033 newconstraint.presence = FCT_OPTIONAL;
2034 newconstraint.type = type;
2035 newconstraint.list = sublist;
2036 if (!make_intersected_element (&tmpelement,
2037 &list->initial.element[s], &newconstraint))
2038 return add_end_constraint (list, n);
2039 free_element (&list->initial.element[s]);
2040 list->initial.element[s].type = tmpelement.type;
2041 list->initial.element[s].list = tmpelement.list;
2043 VERIFY_LIST (list);
2045 return list;
2049 /* ============= Subroutines used by the format string parser ============= */
2051 static void
2052 add_req_type_constraint (struct format_arg_list **listp,
2053 unsigned int position, enum format_arg_type type)
2055 *listp = add_required_constraint (*listp, position);
2056 *listp = add_type_constraint (*listp, position, type);
2060 static void
2061 add_req_listtype_constraint (struct format_arg_list **listp,
2062 unsigned int position, enum format_arg_type type,
2063 struct format_arg_list *sublist)
2065 *listp = add_required_constraint (*listp, position);
2066 *listp = add_listtype_constraint (*listp, position, type, sublist);
2070 /* Create an endless repeated list whose elements are lists constrained
2071 by sublist. */
2072 /* Memory effects: sublist is freed. The result is freshly allocated. */
2073 static struct format_arg_list *
2074 make_repeated_list_of_lists (struct format_arg_list *sublist)
2076 if (sublist == NULL)
2077 /* The list cannot have a single element. */
2078 return make_empty_list ();
2079 else
2081 struct format_arg_list *listlist;
2083 listlist =
2084 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
2086 listlist->initial.count = 0;
2087 listlist->initial.allocated = 0;
2088 listlist->initial.element = NULL;
2089 listlist->initial.length = 0;
2090 listlist->repeated.count = 1;
2091 listlist->repeated.allocated = 1;
2092 listlist->repeated.element =
2093 (struct format_arg *) xmalloc (1 * sizeof (struct format_arg));
2094 listlist->repeated.element[0].repcount = 1;
2095 listlist->repeated.element[0].presence = FCT_OPTIONAL;
2096 listlist->repeated.element[0].type = FAT_LIST;
2097 listlist->repeated.element[0].list = sublist;
2098 listlist->repeated.length = 1;
2100 VERIFY_LIST (listlist);
2102 return listlist;
2107 /* Create an endless repeated list which represents the union of a finite
2108 number of copies of L, each time shifted by period:
2111 L and (*^period L)
2112 L and (*^period L) and (*^{2 period} L)
2113 L and (*^period L) and (*^{2 period} L) and (*^{3 period} L)
2116 /* Memory effects: sublist is freed. The result is freshly allocated. */
2117 static struct format_arg_list *
2118 make_repeated_list (struct format_arg_list *sublist, unsigned int period)
2120 struct segment tmp;
2121 struct segment *srcseg;
2122 struct format_arg_list *list;
2123 unsigned int p, n, i, si, ti, j, sj, tj, splitindex, newcount;
2124 bool ended;
2126 VERIFY_LIST (sublist);
2128 ASSERT (period > 0);
2130 if (sublist->repeated.count == 0)
2132 /* L is a finite list. */
2134 if (sublist->initial.length < period)
2135 /* L and (*^period L) is a contradition, so we need to consider
2136 only 1 and 0 iterations. */
2137 return make_union_with_empty_list (sublist);
2139 srcseg = &sublist->initial;
2140 p = period;
2142 else
2144 /* L is an infinite list. */
2145 /* p := lcm (period, period of L) */
2146 unsigned int Lp = sublist->repeated.length;
2147 unsigned int m = period / gcd (period, Lp); /* = lcm(period,Lp) / Lp */
2149 unfold_loop (sublist, m);
2150 p = m * Lp;
2152 /* Concatenate the initial and the repeated segments into a single
2153 segment. */
2154 tmp.count = sublist->initial.count + sublist->repeated.count;
2155 tmp.allocated = tmp.count;
2156 tmp.element =
2157 (struct format_arg *)
2158 xmalloc (tmp.allocated * sizeof (struct format_arg));
2159 for (i = 0; i < sublist->initial.count; i++)
2160 tmp.element[i] = sublist->initial.element[i];
2161 for (j = 0; j < sublist->repeated.count; i++, j++)
2162 tmp.element[i] = sublist->initial.element[j];
2163 tmp.length = sublist->initial.length + sublist->repeated.length;
2165 srcseg = &tmp;
2168 n = srcseg->length;
2170 /* Example: n = 7, p = 2
2171 Let L = (A B C D E F G).
2173 L = A B C D E F G
2174 L & L<<p = A B C&A D&B E&C F&D G&E
2175 L & L<<p & L<<2p = A B C&A D&B E&C&A F&D&B G&E&C
2176 ... = A B C&A D&B E&C&A F&D&B G&E&C&A
2178 Thus the result has an initial segment of length n - p and a period
2179 of p, and can be computed by floor(n/p) intersection operations.
2180 Or by a single incremental intersection operation, going from left
2181 to right. */
2183 list = (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
2184 list->initial.count = 0;
2185 list->initial.allocated = 0;
2186 list->initial.element = NULL;
2187 list->initial.length = 0;
2188 list->repeated.count = 0;
2189 list->repeated.allocated = 0;
2190 list->repeated.element = NULL;
2191 list->repeated.length = 0;
2193 /* Sketch:
2194 for (i = 0; i < p; i++)
2195 list->initial.element[i] = srcseg->element[i];
2196 list->initial.element[0].presence = FCT_OPTIONAL; // union with empty list
2197 for (i = p, j = 0; i < n; i++, j++)
2198 list->initial.element[i] = srcseg->element[i] & list->initial.element[j];
2201 ended = false;
2203 i = 0, ti = 0, si = 0;
2204 while (i < p)
2206 unsigned int k = MIN (srcseg->element[si].repcount - ti, p - i);
2208 /* Ensure room in list->initial. */
2209 grow_initial_alloc (list);
2210 copy_element (&list->initial.element[list->initial.count],
2211 &srcseg->element[si]);
2212 list->initial.element[list->initial.count].repcount = k;
2213 list->initial.count++;
2214 list->initial.length += k;
2216 i += k;
2217 ti += k;
2218 if (ti == srcseg->element[si].repcount)
2220 ti = 0;
2221 si++;
2225 ASSERT (list->initial.count > 0);
2226 if (list->initial.element[0].presence == FCT_REQUIRED)
2228 initial_splitelement (list, 1);
2229 ASSERT (list->initial.element[0].presence == FCT_REQUIRED);
2230 ASSERT (list->initial.element[0].repcount == 1);
2231 list->initial.element[0].presence = FCT_OPTIONAL;
2234 j = 0, tj = 0, sj = 0;
2235 while (i < n)
2237 unsigned int k =
2238 MIN (srcseg->element[si].repcount - ti,
2239 list->initial.element[sj].repcount - tj);
2241 /* Ensure room in list->initial. */
2242 grow_initial_alloc (list);
2243 if (!make_intersected_element (&list->initial.element[list->initial.count],
2244 &srcseg->element[si],
2245 &list->initial.element[sj]))
2247 if (list->initial.element[list->initial.count].presence == FCT_REQUIRED)
2249 /* Contradiction. Backtrack. */
2250 list = backtrack_in_initial (list);
2251 ASSERT (list != NULL); /* at least the empty list is valid */
2252 return list;
2254 else
2256 /* The list ends here. */
2257 ended = true;
2258 break;
2261 list->initial.element[list->initial.count].repcount = k;
2262 list->initial.count++;
2263 list->initial.length += k;
2265 i += k;
2266 ti += k;
2267 if (ti == srcseg->element[si].repcount)
2269 ti = 0;
2270 si++;
2273 j += k;
2274 tj += k;
2275 if (tj == list->initial.element[sj].repcount)
2277 tj = 0;
2278 sj++;
2281 if (!ended)
2282 ASSERT (list->initial.length == n);
2284 /* Add optional exit points at 0, period, 2*period etc.
2285 FIXME: Not sure this is correct in all cases. */
2286 for (i = 0; i < list->initial.length; i += period)
2288 si = initial_unshare (list, i);
2289 list->initial.element[si].presence = FCT_OPTIONAL;
2292 if (!ended)
2294 /* Now split off the repeated part. */
2295 splitindex = initial_splitelement (list, n - p);
2296 newcount = list->initial.count - splitindex;
2297 if (newcount > list->repeated.allocated)
2299 list->repeated.allocated = newcount;
2300 list->repeated.element =
2301 (struct format_arg *) xmalloc (newcount * sizeof (struct format_arg));
2303 for (i = splitindex, j = 0; i < n; i++, j++)
2304 list->repeated.element[j] = list->initial.element[i];
2305 list->repeated.count = newcount;
2306 list->repeated.length = p;
2307 list->initial.count = splitindex;
2308 list->initial.length = n - p;
2311 VERIFY_LIST (list);
2313 return list;
2317 /* ================= Handling of format string directives ================= */
2319 /* Possible signatures of format directives. */
2320 static const enum format_arg_type I [1] = { FAT_INTEGER_NULL };
2321 static const enum format_arg_type II [2] = {
2322 FAT_INTEGER_NULL, FAT_INTEGER_NULL
2324 static const enum format_arg_type IIC [3] = {
2325 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL
2327 static const enum format_arg_type ICCI [4] = {
2328 FAT_INTEGER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL, FAT_INTEGER_NULL
2330 static const enum format_arg_type IIIC [4] = {
2331 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL
2333 static const enum format_arg_type IICCI [5] = {
2334 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL,
2335 FAT_INTEGER_NULL
2337 static const enum format_arg_type IIICC [5] = {
2338 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL,
2339 FAT_CHARACTER_NULL
2341 static const enum format_arg_type IIIICCC [7] = {
2342 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL,
2343 FAT_CHARACTER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL
2345 static const enum format_arg_type THREE [3] = {
2346 FAT_CHARACTER_INTEGER_NULL, FAT_CHARACTER_INTEGER_NULL,
2347 FAT_CHARACTER_INTEGER_NULL
2351 /* Check the parameters. For V params, add the constraint to the argument
2352 list. Return false and fill in *invalid_reason if the format string is
2353 invalid. */
2354 static bool
2355 check_params (struct format_arg_list **listp,
2356 unsigned int paramcount, struct param *params,
2357 unsigned int t_count, const enum format_arg_type *t_types,
2358 unsigned int directives, char **invalid_reason)
2360 unsigned int orig_paramcount = paramcount;
2361 unsigned int orig_t_count = t_count;
2363 for (; paramcount > 0 && t_count > 0;
2364 params++, paramcount--, t_types++, t_count--)
2366 switch (*t_types)
2368 case FAT_CHARACTER_INTEGER_NULL:
2369 break;
2370 case FAT_CHARACTER_NULL:
2371 switch (params->type)
2373 case PT_NIL: case PT_CHARACTER: case PT_V:
2374 break;
2375 case PT_INTEGER: case PT_ARGCOUNT:
2376 /* wrong param type */
2377 *invalid_reason =
2378 xasprintf (_("In the directive number %u, parameter %u is of type '%s' but a parameter of type '%s' is expected."), directives, orig_paramcount - paramcount + 1, "integer", "character");
2379 return false;
2381 break;
2382 case FAT_INTEGER_NULL:
2383 switch (params->type)
2385 case PT_NIL: case PT_INTEGER: case PT_ARGCOUNT: case PT_V:
2386 break;
2387 case PT_CHARACTER:
2388 /* wrong param type */
2389 *invalid_reason =
2390 xasprintf (_("In the directive number %u, parameter %u is of type '%s' but a parameter of type '%s' is expected."), directives, orig_paramcount - paramcount + 1, "character", "integer");
2391 return false;
2393 break;
2394 default:
2395 abort ();
2397 if (params->type == PT_V)
2399 int position = params->value;
2400 if (position >= 0)
2401 add_req_type_constraint (listp, position, *t_types);
2405 for (; paramcount > 0; params++, paramcount--)
2406 switch (params->type)
2408 case PT_NIL:
2409 break;
2410 case PT_CHARACTER: case PT_INTEGER: case PT_ARGCOUNT:
2411 /* too many params for directive */
2412 *invalid_reason =
2413 xasprintf (ngettext ("In the directive number %u, too many parameters are given; expected at most %u parameter.",
2414 "In the directive number %u, too many parameters are given; expected at most %u parameters.",
2415 orig_t_count),
2416 directives, orig_t_count);
2417 return false;
2418 case PT_V:
2419 /* Force argument to be NIL. */
2421 int position = params->value;
2422 if (position >= 0)
2424 struct format_arg_list *empty_list = make_empty_list ();
2425 add_req_listtype_constraint (listp, position,
2426 FAT_LIST, empty_list);
2427 free_list (empty_list);
2430 break;
2433 return true;
2437 /* ======================= The format string parser ======================= */
2439 /* Parse a piece of format string, until the matching terminating format
2440 directive is encountered.
2441 format is the remainder of the format string.
2442 position is the position in this argument list, if known, or -1 if unknown.
2443 list represents the argument list constraints at the current parse point.
2444 NULL stands for a contradiction.
2445 escape represents the union of the argument list constraints at all the
2446 currently pending FORMAT-UP-AND-OUT points. NULL stands for a contradiction
2447 or an empty union.
2448 All four are updated upon valid return.
2449 *separatorp is set to true if the parse terminated due to a ~; separator,
2450 more precisely to 2 if with colon, or to 1 if without colon.
2451 spec is the global struct spec.
2452 terminator is the directive that terminates this parse.
2453 separator specifies if ~; separators are allowed.
2454 If the format string is invalid, false is returned and *invalid_reason is
2455 set to an error message explaining why. */
2456 static bool
2457 parse_upto (const char **formatp,
2458 int *positionp, struct format_arg_list **listp,
2459 struct format_arg_list **escapep, int *separatorp,
2460 struct spec *spec, char terminator, bool separator,
2461 char **invalid_reason)
2463 const char *format = *formatp;
2464 int position = *positionp;
2465 struct format_arg_list *list = *listp;
2466 struct format_arg_list *escape = *escapep;
2468 for (; *format != '\0'; )
2469 if (*format++ == '~')
2471 bool colon_p = false;
2472 bool atsign_p = false;
2473 unsigned int paramcount = 0;
2474 struct param *params = NULL;
2476 /* Count number of directives. */
2477 spec->directives++;
2479 /* Parse parameters. */
2480 for (;;)
2482 enum param_type type = PT_NIL;
2483 int value = 0;
2485 if (c_isdigit (*format))
2487 type = PT_INTEGER;
2490 value = 10 * value + (*format - '0');
2491 format++;
2493 while (c_isdigit (*format));
2495 else if (*format == '+' || *format == '-')
2497 bool negative = (*format == '-');
2498 type = PT_INTEGER;
2499 format++;
2500 if (!c_isdigit (*format))
2502 *invalid_reason =
2503 (*format == '\0'
2504 ? INVALID_UNTERMINATED_DIRECTIVE ()
2505 : xasprintf (_("In the directive number %u, '%c' is not followed by a digit."), spec->directives, format[-1]));
2506 return false;
2510 value = 10 * value + (*format - '0');
2511 format++;
2513 while (c_isdigit (*format));
2514 if (negative)
2515 value = -value;
2517 else if (*format == '\'')
2519 type = PT_CHARACTER;
2520 format++;
2521 if (*format == '\0')
2523 *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
2524 return false;
2526 format++;
2528 else if (*format == 'V' || *format == 'v')
2530 type = PT_V;
2531 format++;
2532 value = position;
2533 /* Consumes an argument. */
2534 if (position >= 0)
2535 position++;
2537 else if (*format == '#')
2539 type = PT_ARGCOUNT;
2540 format++;
2543 params =
2544 (struct param *)
2545 xrealloc (params, (paramcount + 1) * sizeof (struct param));
2546 params[paramcount].type = type;
2547 params[paramcount].value = value;
2548 paramcount++;
2550 if (*format == ',')
2551 format++;
2552 else
2553 break;
2556 /* Parse modifiers. */
2557 for (;;)
2559 if (*format == ':')
2561 format++;
2562 colon_p = true;
2564 else if (*format == '@')
2566 format++;
2567 atsign_p = true;
2569 else
2570 break;
2573 /* Parse directive. */
2574 switch (*format++)
2576 case 'A': case 'a': /* 22.3.4.1 FORMAT-ASCII */
2577 case 'S': case 's': /* 22.3.4.2 FORMAT-S-EXPRESSION */
2578 if (!check_params (&list, paramcount, params, 4, IIIC,
2579 spec->directives, invalid_reason))
2580 return false;
2581 if (position >= 0)
2582 add_req_type_constraint (&list, position++, FAT_OBJECT);
2583 break;
2585 case 'C': case 'c': /* FORMAT-CHARACTER */
2586 if (!check_params (&list, paramcount, params, 1, I,
2587 spec->directives, invalid_reason))
2588 return false;
2589 if (paramcount == 0
2590 || (paramcount == 1 && params[0].type == PT_NIL))
2591 if (position >= 0)
2592 add_req_type_constraint (&list, position++, FAT_CHARACTER);
2593 break;
2595 case 'D': case 'd': /* 22.3.2.2 FORMAT-DECIMAL */
2596 case 'B': case 'b': /* 22.3.2.3 FORMAT-BINARY */
2597 case 'O': case 'o': /* 22.3.2.4 FORMAT-OCTAL */
2598 case 'X': case 'x': /* 22.3.2.5 FORMAT-HEXADECIMAL */
2599 if (!check_params (&list, paramcount, params, 4, ICCI,
2600 spec->directives, invalid_reason))
2601 return false;
2602 if (position >= 0)
2603 add_req_type_constraint (&list, position++, FAT_INTEGER);
2604 break;
2606 case 'R': case 'r': /* 22.3.2.1 FORMAT-RADIX */
2607 if (!check_params (&list, paramcount, params, 5, IICCI,
2608 spec->directives, invalid_reason))
2609 return false;
2610 if (position >= 0)
2611 add_req_type_constraint (&list, position++, FAT_INTEGER);
2612 break;
2614 case 'P': case 'p': /* 22.3.8.3 FORMAT-PLURAL */
2615 if (!check_params (&list, paramcount, params, 0, NULL,
2616 spec->directives, invalid_reason))
2617 return false;
2618 if (colon_p)
2620 /* Go back by 1 argument. */
2621 if (position > 0)
2622 position--;
2624 if (position >= 0)
2625 add_req_type_constraint (&list, position++, FAT_OBJECT);
2626 break;
2628 case 'F': case 'f': /* 22.3.3.1 FORMAT-FIXED-FLOAT */
2629 if (!check_params (&list, paramcount, params, 5, IIICC,
2630 spec->directives, invalid_reason))
2631 return false;
2632 if (position >= 0)
2633 add_req_type_constraint (&list, position++, FAT_REAL);
2634 break;
2636 case 'E': case 'e': /* 22.3.3.2 FORMAT-EXPONENTIAL-FLOAT */
2637 case 'G': case 'g': /* 22.3.3.3 FORMAT-GENERAL-FLOAT */
2638 if (!check_params (&list, paramcount, params, 7, IIIICCC,
2639 spec->directives, invalid_reason))
2640 return false;
2641 if (position >= 0)
2642 add_req_type_constraint (&list, position++, FAT_REAL);
2643 break;
2645 case '$': /* 22.3.3.4 FORMAT-DOLLARS-FLOAT */
2646 if (!check_params (&list, paramcount, params, 4, IIIC,
2647 spec->directives, invalid_reason))
2648 return false;
2649 if (position >= 0)
2650 add_req_type_constraint (&list, position++, FAT_REAL);
2651 break;
2653 case 'I': case 'i': /* FORMAT-FIXED-FLOAT-COMPLEX */
2654 if (!check_params (&list, paramcount, params, 5, IIICC,
2655 spec->directives, invalid_reason))
2656 return false;
2657 if (position >= 0)
2658 add_req_type_constraint (&list, position++, FAT_COMPLEX);
2659 break;
2661 case 'Y': case 'y': /* FORMAT-PRETTY */
2662 if (!check_params (&list, paramcount, params, 0, NULL,
2663 spec->directives, invalid_reason))
2664 return false;
2665 if (position >= 0)
2666 add_req_type_constraint (&list, position++, FAT_OBJECT);
2667 break;
2669 case '%': /* 22.3.1.2 FORMAT-TERPRI */
2670 case '&': /* 22.3.1.3 FORMAT-FRESH-LINE */
2671 case '_': /* FORMAT-SPACE */
2672 case '/': /* FORMAT-TAB */
2673 case '|': /* 22.3.1.4 FORMAT-PAGE */
2674 case '~': /* 22.3.1.5 FORMAT-TILDE */
2675 if (!check_params (&list, paramcount, params, 1, I,
2676 spec->directives, invalid_reason))
2677 return false;
2678 break;
2680 case '!': /* FORMAT-FORCE-OUTPUT */
2681 case '\n': /* 22.3.9.3 #\Newline */
2682 case 'Q': case 'q': /* FORMAT-IMPLEMENTATION */
2683 if (!check_params (&list, paramcount, params, 0, NULL,
2684 spec->directives, invalid_reason))
2685 return false;
2686 break;
2688 case 'T': case 't': /* FORMAT-TABULATE */
2689 if (!check_params (&list, paramcount, params, 3, IIC,
2690 spec->directives, invalid_reason))
2691 return false;
2692 break;
2694 case '*': /* 22.3.7.1 FORMAT-GOTO */
2695 if (!check_params (&list, paramcount, params, 1, I,
2696 spec->directives, invalid_reason))
2697 return false;
2699 int n; /* value of first parameter */
2700 if (paramcount == 0
2701 || (paramcount >= 1 && params[0].type == PT_NIL))
2702 n = (atsign_p ? 0 : 1);
2703 else if (paramcount >= 1 && params[0].type == PT_INTEGER)
2704 n = params[0].value;
2705 else
2707 /* Unknown argument, leads to an unknown position. */
2708 position = -1;
2709 break;
2711 if (n < 0)
2713 /* invalid argument */
2714 *invalid_reason =
2715 xasprintf (_("In the directive number %u, the argument %d is negative."), spec->directives, n);
2716 return false;
2718 if (atsign_p)
2720 /* Absolute goto. */
2721 position = n;
2723 else if (colon_p)
2725 /* Backward goto. */
2726 if (n > 0)
2728 if (position >= 0)
2730 if (position >= n)
2731 position -= n;
2732 else
2733 position = 0;
2735 else
2736 position = -1;
2739 else
2741 /* Forward goto. */
2742 if (position >= 0)
2743 position += n;
2746 break;
2748 case '?': case 'K': case 'k': /* 22.3.7.6 FORMAT-INDIRECTION */
2749 if (!check_params (&list, paramcount, params, 0, NULL,
2750 spec->directives, invalid_reason))
2751 return false;
2752 if (position >= 0)
2753 add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
2754 if (atsign_p)
2755 position = -1;
2756 else
2757 if (position >= 0)
2759 struct format_arg_list *sublist = make_unconstrained_list ();
2760 add_req_listtype_constraint (&list, position++,
2761 FAT_LIST, sublist);
2762 free_list (sublist);
2764 break;
2766 case '(': /* 22.3.8.1 FORMAT-CASE-CONVERSION */
2767 if (!check_params (&list, paramcount, params, 0, NULL,
2768 spec->directives, invalid_reason))
2769 return false;
2770 *formatp = format;
2771 *positionp = position;
2772 *listp = list;
2773 *escapep = escape;
2775 if (!parse_upto (formatp, positionp, listp, escapep,
2776 NULL, spec, ')', false,
2777 invalid_reason))
2778 return false;
2780 format = *formatp;
2781 position = *positionp;
2782 list = *listp;
2783 escape = *escapep;
2784 break;
2786 case ')': /* 22.3.8.2 FORMAT-CASE-CONVERSION-END */
2787 if (terminator != ')')
2789 *invalid_reason =
2790 xasprintf (_("Found '~%c' without matching '~%c'."), ')', '(');
2791 return false;
2793 if (!check_params (&list, paramcount, params, 0, NULL,
2794 spec->directives, invalid_reason))
2795 return false;
2796 *formatp = format;
2797 *positionp = position;
2798 *listp = list;
2799 *escapep = escape;
2800 return true;
2802 case '[': /* 22.3.7.2 FORMAT-CONDITIONAL */
2803 if (atsign_p && colon_p)
2805 *invalid_reason =
2806 xasprintf (_("In the directive number %u, both the @ and the : modifiers are given."), spec->directives);
2807 return false;
2809 else if (atsign_p)
2811 struct format_arg_list *nil_list;
2812 struct format_arg_list *union_list;
2814 if (!check_params (&list, paramcount, params, 0, NULL,
2815 spec->directives, invalid_reason))
2816 return false;
2818 *formatp = format;
2819 *escapep = escape;
2821 /* First alternative: argument is NIL. */
2822 nil_list = (list != NULL ? copy_list (list) : NULL);
2823 if (position >= 0)
2825 struct format_arg_list *empty_list = make_empty_list ();
2826 add_req_listtype_constraint (&nil_list, position,
2827 FAT_LIST, empty_list);
2828 free_list (empty_list);
2831 /* Second alternative: use sub-format. */
2833 int sub_position = position;
2834 struct format_arg_list *sub_list =
2835 (list != NULL ? copy_list (list) : NULL);
2836 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2837 NULL, spec, ']', false,
2838 invalid_reason))
2839 return false;
2840 if (sub_list != NULL)
2842 if (position >= 0)
2844 if (sub_position == position + 1)
2845 /* new position is branch independent */
2846 position = position + 1;
2847 else
2848 /* new position is branch dependent */
2849 position = -1;
2852 else
2854 if (position >= 0)
2855 position = position + 1;
2857 union_list = union (nil_list, sub_list);
2860 format = *formatp;
2861 escape = *escapep;
2863 if (list != NULL)
2864 free_list (list);
2865 list = union_list;
2867 else if (colon_p)
2869 int union_position;
2870 struct format_arg_list *union_list;
2872 if (!check_params (&list, paramcount, params, 0, NULL,
2873 spec->directives, invalid_reason))
2874 return false;
2876 if (position >= 0)
2877 add_req_type_constraint (&list, position++, FAT_OBJECT);
2879 *formatp = format;
2880 *escapep = escape;
2881 union_position = -2;
2882 union_list = NULL;
2884 /* First alternative. */
2886 int sub_position = position;
2887 struct format_arg_list *sub_list =
2888 (list != NULL ? copy_list (list) : NULL);
2889 int sub_separator = 0;
2890 if (position >= 0)
2892 struct format_arg_list *empty_list = make_empty_list ();
2893 add_req_listtype_constraint (&sub_list, position - 1,
2894 FAT_LIST, empty_list);
2895 free_list (empty_list);
2897 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2898 &sub_separator, spec, ']', true,
2899 invalid_reason))
2900 return false;
2901 if (!sub_separator)
2903 *invalid_reason =
2904 xasprintf (_("In the directive number %u, '~:[' is not followed by two clauses, separated by '~;'."), spec->directives);
2905 return false;
2907 if (sub_list != NULL)
2908 union_position = sub_position;
2909 union_list = union (union_list, sub_list);
2912 /* Second alternative. */
2914 int sub_position = position;
2915 struct format_arg_list *sub_list =
2916 (list != NULL ? copy_list (list) : NULL);
2917 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2918 NULL, spec, ']', false,
2919 invalid_reason))
2920 return false;
2921 if (sub_list != NULL)
2923 if (union_position == -2)
2924 union_position = sub_position;
2925 else if (sub_position < 0
2926 || sub_position != union_position)
2927 union_position = -1;
2929 union_list = union (union_list, sub_list);
2932 format = *formatp;
2933 escape = *escapep;
2935 if (union_position != -2)
2936 position = union_position;
2937 if (list != NULL)
2938 free_list (list);
2939 list = union_list;
2941 else
2943 int arg_position;
2944 int union_position;
2945 struct format_arg_list *union_list;
2946 bool last_alternative;
2948 if (!check_params (&list, paramcount, params, 1, I,
2949 spec->directives, invalid_reason))
2950 return false;
2952 /* If there was no first parameter, an argument is consumed. */
2953 arg_position = -1;
2954 if (!(paramcount >= 1 && params[0].type != PT_NIL))
2955 if (position >= 0)
2957 arg_position = position;
2958 add_req_type_constraint (&list, position++, FAT_OBJECT);
2961 *formatp = format;
2962 *escapep = escape;
2964 union_position = -2;
2965 union_list = NULL;
2966 last_alternative = false;
2967 for (;;)
2969 /* Next alternative. */
2970 int sub_position = position;
2971 struct format_arg_list *sub_list =
2972 (list != NULL ? copy_list (list) : NULL);
2973 int sub_separator = 0;
2974 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2975 &sub_separator, spec, ']', !last_alternative,
2976 invalid_reason))
2977 return false;
2978 /* If this alternative is chosen, the argument arg_position
2979 is an integer, namely the index of this alternative. */
2980 if (!last_alternative && arg_position >= 0)
2981 add_req_type_constraint (&sub_list, arg_position,
2982 FAT_INTEGER);
2983 if (sub_list != NULL)
2985 if (union_position == -2)
2986 union_position = sub_position;
2987 else if (sub_position < 0
2988 || sub_position != union_position)
2989 union_position = -1;
2991 union_list = union (union_list, sub_list);
2992 if (sub_separator == 2)
2993 last_alternative = true;
2994 if (!sub_separator)
2995 break;
2997 if (!last_alternative)
2999 /* An implicit default alternative. */
3000 if (union_position == -2)
3001 union_position = position;
3002 else if (position < 0 || position != union_position)
3003 union_position = -1;
3004 if (list != NULL)
3005 union_list = union (union_list, copy_list (list));
3008 format = *formatp;
3009 escape = *escapep;
3011 if (union_position != -2)
3012 position = union_position;
3013 if (list != NULL)
3014 free_list (list);
3015 list = union_list;
3017 break;
3019 case ']': /* 22.3.7.3 FORMAT-CONDITIONAL-END */
3020 if (terminator != ']')
3022 *invalid_reason =
3023 xasprintf (_("Found '~%c' without matching '~%c'."), ']', '[');
3024 return false;
3026 if (!check_params (&list, paramcount, params, 0, NULL,
3027 spec->directives, invalid_reason))
3028 return false;
3029 *formatp = format;
3030 *positionp = position;
3031 *listp = list;
3032 *escapep = escape;
3033 return true;
3035 case '{': /* 22.3.7.4 FORMAT-ITERATION */
3036 if (!check_params (&list, paramcount, params, 1, I,
3037 spec->directives, invalid_reason))
3038 return false;
3039 *formatp = format;
3041 int sub_position = 0;
3042 struct format_arg_list *sub_list = make_unconstrained_list ();
3043 struct format_arg_list *sub_escape = NULL;
3044 struct spec sub_spec;
3045 sub_spec.directives = 0;
3046 sub_spec.list = sub_list;
3047 if (!parse_upto (formatp, &sub_position, &sub_list, &sub_escape,
3048 NULL, &sub_spec, '}', false,
3049 invalid_reason))
3050 return false;
3051 spec->directives += sub_spec.directives;
3053 /* If the sub-formatstring is empty, except for the terminating
3054 ~} directive, a formatstring argument is consumed. */
3055 if (*format == '~' && sub_spec.directives == 1)
3056 if (position >= 0)
3057 add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
3059 if (colon_p)
3061 /* Each iteration uses a new sublist. */
3062 struct format_arg_list *listlist;
3064 /* ~{ catches ~^. */
3065 sub_list = union (sub_list, sub_escape);
3067 listlist = make_repeated_list_of_lists (sub_list);
3069 sub_list = listlist;
3071 else
3073 /* Each iteration's arguments are all concatenated in a
3074 single list. */
3075 struct format_arg_list *looplist;
3077 /* FIXME: This is far from correct. Test cases:
3078 abc~{~^~}
3079 abc~{~S~^~S~}
3080 abc~{~D~^~C~}
3081 abc~{~D~^~D~}
3082 abc~{~D~^~S~}
3083 abc~{~D~^~C~}~:*~{~S~^~D~}
3086 /* ~{ catches ~^. */
3087 sub_list = union (sub_list, sub_escape);
3089 if (sub_list == NULL)
3090 looplist = make_empty_list ();
3091 else
3092 if (sub_position < 0 || sub_position == 0)
3093 /* Too hard to track the possible argument types
3094 when the iteration is performed 2 times or more.
3095 So be satisfied with the constraints of executing
3096 the iteration 1 or 0 times. */
3097 looplist = make_union_with_empty_list (sub_list);
3098 else
3099 looplist = make_repeated_list (sub_list, sub_position);
3101 sub_list = looplist;
3104 if (atsign_p)
3106 /* All remaining arguments are used. */
3107 if (list != NULL && position >= 0)
3109 shift_list (sub_list, position);
3110 list = make_intersected_list (list, sub_list);
3112 position = -1;
3114 else
3116 /* The argument is a list. */
3117 if (position >= 0)
3118 add_req_listtype_constraint (&list, position++,
3119 FAT_LIST, sub_list);
3122 format = *formatp;
3123 break;
3125 case '}': /* 22.3.7.5 FORMAT-ITERATION-END */
3126 if (terminator != '}')
3128 *invalid_reason =
3129 xasprintf (_("Found '~%c' without matching '~%c'."), '}', '{');
3130 return false;
3132 if (!check_params (&list, paramcount, params, 0, NULL,
3133 spec->directives, invalid_reason))
3134 return false;
3135 *formatp = format;
3136 *positionp = position;
3137 *listp = list;
3138 *escapep = escape;
3139 return true;
3141 case '^': /* 22.3.9.2 FORMAT-UP-AND-OUT */
3142 if (!check_params (&list, paramcount, params, 3, THREE,
3143 spec->directives, invalid_reason))
3144 return false;
3145 if (position >= 0 && list != NULL && is_required (list, position))
3146 /* This ~^ can never be executed. Ignore it. */
3147 break;
3148 if (list != NULL)
3150 struct format_arg_list *this_escape = copy_list (list);
3151 if (position >= 0)
3152 this_escape = add_end_constraint (this_escape, position);
3153 escape = union (escape, this_escape);
3155 if (position >= 0)
3156 list = add_required_constraint (list, position);
3157 break;
3159 case ';': /* 22.3.9.1 FORMAT-SEPARATOR */
3160 if (!separator)
3162 *invalid_reason =
3163 xasprintf (_("In the directive number %u, '~;' is used in an invalid position."), spec->directives);
3164 return false;
3166 if (terminator == '>')
3168 if (!check_params (&list, paramcount, params, 1, I,
3169 spec->directives, invalid_reason))
3170 return false;
3172 else
3174 if (!check_params (&list, paramcount, params, 0, NULL,
3175 spec->directives, invalid_reason))
3176 return false;
3178 *formatp = format;
3179 *positionp = position;
3180 *listp = list;
3181 *escapep = escape;
3182 *separatorp = (colon_p ? 2 : 1);
3183 return true;
3185 default:
3186 --format;
3187 *invalid_reason =
3188 (*format == '\0'
3189 ? INVALID_UNTERMINATED_DIRECTIVE ()
3190 : INVALID_CONVERSION_SPECIFIER (spec->directives, *format));
3191 return false;
3194 free (params);
3197 *formatp = format;
3198 *positionp = position;
3199 *listp = list;
3200 *escapep = escape;
3201 if (terminator != '\0')
3203 *invalid_reason =
3204 xasprintf (_("Found '~%c' without matching '~%c'."), terminator - 1, terminator);
3205 return false;
3207 return true;
3211 /* ============== Top level format string handling functions ============== */
3213 static void *
3214 format_parse (const char *format, bool translated, char **invalid_reason)
3216 struct spec spec;
3217 struct spec *result;
3218 int position = 0;
3219 struct format_arg_list *escape;
3221 spec.directives = 0;
3222 spec.list = make_unconstrained_list ();
3223 escape = NULL;
3225 if (!parse_upto (&format, &position, &spec.list, &escape,
3226 NULL, &spec, '\0', false,
3227 invalid_reason))
3228 /* Invalid format string. */
3229 return NULL;
3231 /* Catch ~^ here. */
3232 spec.list = union (spec.list, escape);
3234 if (spec.list == NULL)
3236 /* Contradictory argument type information. */
3237 *invalid_reason =
3238 xstrdup (_("The string refers to some argument in incompatible ways."));
3239 return NULL;
3242 /* Normalize the result. */
3243 normalize_list (spec.list);
3245 result = (struct spec *) xmalloc (sizeof (struct spec));
3246 *result = spec;
3247 return result;
3250 static void
3251 format_free (void *descr)
3253 struct spec *spec = (struct spec *) descr;
3255 free_list (spec->list);
3258 static int
3259 format_get_number_of_directives (void *descr)
3261 struct spec *spec = (struct spec *) descr;
3263 return spec->directives;
3266 static bool
3267 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
3268 formatstring_error_logger_t error_logger,
3269 const char *pretty_msgstr)
3271 struct spec *spec1 = (struct spec *) msgid_descr;
3272 struct spec *spec2 = (struct spec *) msgstr_descr;
3273 bool err = false;
3275 if (equality)
3277 if (!equal_list (spec1->list, spec2->list))
3279 if (error_logger)
3280 error_logger (_("format specifications in 'msgid' and '%s' are not equivalent"),
3281 pretty_msgstr);
3282 err = true;
3285 else
3287 struct format_arg_list *intersection =
3288 make_intersected_list (copy_list (spec1->list),
3289 copy_list (spec2->list));
3291 if (!(intersection != NULL
3292 && (normalize_list (intersection),
3293 equal_list (intersection, spec2->list))))
3295 if (error_logger)
3296 error_logger (_("format specifications in '%s' are not a subset of those in 'msgid'"),
3297 pretty_msgstr);
3298 err = true;
3302 return err;
3306 struct formatstring_parser formatstring_scheme =
3308 format_parse,
3309 format_free,
3310 format_get_number_of_directives,
3311 format_check
3315 /* ============================= Testing code ============================= */
3317 #undef union
3319 #ifdef TEST
3321 /* Test program: Print the argument list specification returned by
3322 format_parse for strings read from standard input. */
3324 #include <stdio.h>
3325 #include "getline.h"
3327 static void print_list (struct format_arg_list *list);
3329 static void
3330 print_element (struct format_arg *element)
3332 switch (element->presence)
3334 case FCT_REQUIRED:
3335 break;
3336 case FCT_OPTIONAL:
3337 printf (". ");
3338 break;
3339 default:
3340 abort ();
3343 switch (element->type)
3345 case FAT_OBJECT:
3346 printf ("*");
3347 break;
3348 case FAT_CHARACTER_INTEGER_NULL:
3349 printf ("ci()");
3350 break;
3351 case FAT_CHARACTER_NULL:
3352 printf ("c()");
3353 break;
3354 case FAT_CHARACTER:
3355 printf ("c");
3356 break;
3357 case FAT_INTEGER_NULL:
3358 printf ("i()");
3359 break;
3360 case FAT_INTEGER:
3361 printf ("i");
3362 break;
3363 case FAT_REAL:
3364 printf ("r");
3365 break;
3366 case FAT_COMPLEX:
3367 printf ("C");
3368 break;
3369 case FAT_LIST:
3370 print_list (element->list);
3371 break;
3372 case FAT_FORMATSTRING:
3373 printf ("~");
3374 break;
3375 default:
3376 abort ();
3380 static void
3381 print_list (struct format_arg_list *list)
3383 unsigned int i, j;
3385 printf ("(");
3387 for (i = 0; i < list->initial.count; i++)
3388 for (j = 0; j < list->initial.element[i].repcount; j++)
3390 if (i > 0 || j > 0)
3391 printf (" ");
3392 print_element (&list->initial.element[i]);
3395 if (list->repeated.count > 0)
3397 printf (" |");
3398 for (i = 0; i < list->repeated.count; i++)
3399 for (j = 0; j < list->repeated.element[i].repcount; j++)
3401 printf (" ");
3402 print_element (&list->repeated.element[i]);
3406 printf (")");
3409 static void
3410 format_print (void *descr)
3412 struct spec *spec = (struct spec *) descr;
3414 if (spec == NULL)
3416 printf ("INVALID");
3417 return;
3420 print_list (spec->list);
3424 main ()
3426 for (;;)
3428 char *line = NULL;
3429 size_t line_size = 0;
3430 int line_len;
3431 char *invalid_reason;
3432 void *descr;
3434 line_len = getline (&line, &line_size, stdin);
3435 if (line_len < 0)
3436 break;
3437 if (line_len > 0 && line[line_len - 1] == '\n')
3438 line[--line_len] = '\0';
3440 invalid_reason = NULL;
3441 descr = format_parse (line, false, &invalid_reason);
3443 format_print (descr);
3444 printf ("\n");
3445 if (descr == NULL)
3446 printf ("%s\n", invalid_reason);
3448 free (invalid_reason);
3449 free (line);
3452 return 0;
3456 * For Emacs M-x compile
3457 * Local Variables:
3458 * compile-command: "/bin/sh ../libtool --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../lib -I../intl -DHAVE_CONFIG_H -DTEST format-scheme.c ../lib/libgettextlib.la"
3459 * End:
3462 #endif /* TEST */