No empty .Rs/.Re
[netbsd-mini2440.git] / gnu / dist / gettext / gettext-tools / src / format-lisp.c
blob22caeb75a41c433ace870dedd43fce7f06d5382b
1 /* Lisp format strings.
2 Copyright (C) 2001-2004 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 "gettext.h"
35 #define _(str) gettext (str)
38 /* Assertion macros. Could be defined to empty for speed. */
39 #define ASSERT(expr) if (!(expr)) abort ();
40 #define VERIFY_LIST(list) verify_list (list)
43 /* Lisp format strings are described in the Common Lisp HyperSpec,
44 chapter 22.3 "Formatted Output". */
46 /* Data structure describing format string derived constraints for an
47 argument list. It is a recursive list structure. Structure sharing
48 is not allowed. */
50 enum format_cdr_type
52 FCT_REQUIRED, /* The format argument list cannot end before this argument. */
53 FCT_OPTIONAL /* The format argument list may end before this argument. */
56 enum format_arg_type
58 FAT_OBJECT, /* Any object, type T. */
59 FAT_CHARACTER_INTEGER_NULL, /* Type (OR CHARACTER INTEGER NULL). */
60 FAT_CHARACTER_NULL, /* Type (OR CHARACTER NULL). */
61 FAT_CHARACTER, /* Type CHARACTER. */
62 FAT_INTEGER_NULL, /* Type (OR INTEGER NULL). */
63 FAT_INTEGER, /* Meant for objects of type INTEGER. */
64 FAT_REAL, /* Meant for objects of type REAL. */
65 FAT_LIST, /* Meant for proper lists. */
66 FAT_FORMATSTRING, /* Format strings. */
67 FAT_FUNCTION /* Function. */
70 struct format_arg
72 unsigned int repcount; /* Number of consecutive arguments this constraint
73 applies to. Normally 1, but unconstrained
74 arguments are often repeated. */
75 enum format_cdr_type presence; /* Can the argument list end right before
76 this argument? */
77 enum format_arg_type type; /* Possible values for this argument. */
78 struct format_arg_list *list; /* For FAT_LIST: List elements. */
81 struct format_arg_list
83 /* The constraints for the potentially infinite argument list are assumed
84 to become ultimately periodic. (Too complicated argument lists without
85 a-priori period, like
86 (format t "~@{~:[-~;~S~]~}" nil t 1 t 3 nil t 4)
87 are described by a constraint that ends in a length 1 period of
88 unconstrained arguments.) Such a periodic sequence can be split into
89 an initial segment and an endlessly repeated loop segment.
90 A finite sequence is represented entirely in the initial segment; the
91 loop segment is empty. */
93 struct segment
95 unsigned int count; /* Number of format_arg records used. */
96 unsigned int allocated;
97 struct format_arg *element; /* Argument constraints. */
98 unsigned int length; /* Number of arguments represented by this segment.
99 This is the sum of all repcounts in the segment. */
101 initial, /* Initial arguments segment. */
102 repeated; /* Endlessly repeated segment. */
105 struct spec
107 unsigned int directives;
108 struct format_arg_list *list;
112 /* Parameter for a directive. */
113 enum param_type
115 PT_NIL, /* param not present */
116 PT_CHARACTER, /* character */
117 PT_INTEGER, /* integer */
118 PT_ARGCOUNT, /* number of remaining arguments */
119 PT_V /* variable taken from argument list */
122 struct param
124 enum param_type type;
125 int value; /* for PT_INTEGER: the value, for PT_V: the position */
129 /* Forward declaration of local functions. */
130 #define union make_union
131 static void verify_list (const struct format_arg_list *list);
132 static void free_list (struct format_arg_list *list);
133 static struct format_arg_list * copy_list (const struct format_arg_list *list);
134 static bool equal_list (const struct format_arg_list *list1,
135 const struct format_arg_list *list2);
136 static struct format_arg_list * make_intersected_list
137 (struct format_arg_list *list1,
138 struct format_arg_list *list2);
139 static struct format_arg_list * make_intersection_with_empty_list
140 (struct format_arg_list *list);
141 static struct format_arg_list * make_union_list
142 (struct format_arg_list *list1,
143 struct format_arg_list *list2);
146 /* ======================= Verify a format_arg_list ======================= */
148 /* Verify some invariants. */
149 static void
150 verify_element (const struct format_arg * e)
152 ASSERT (e->repcount > 0);
153 if (e->type == FAT_LIST)
154 verify_list (e->list);
157 /* Verify some invariants. */
158 /* Memory effects: none. */
159 static void
160 verify_list (const struct format_arg_list *list)
162 unsigned int i;
163 unsigned int total_repcount;
165 ASSERT (list->initial.count <= list->initial.allocated);
166 total_repcount = 0;
167 for (i = 0; i < list->initial.count; i++)
169 verify_element (&list->initial.element[i]);
170 total_repcount += list->initial.element[i].repcount;
172 ASSERT (total_repcount == list->initial.length);
174 ASSERT (list->repeated.count <= list->repeated.allocated);
175 total_repcount = 0;
176 for (i = 0; i < list->repeated.count; i++)
178 verify_element (&list->repeated.element[i]);
179 total_repcount += list->repeated.element[i].repcount;
181 ASSERT (total_repcount == list->repeated.length);
184 #define VERIFY_LIST(list) verify_list (list)
187 /* ======================== Free a format_arg_list ======================== */
189 /* Free the data belonging to an argument list element. */
190 static inline void
191 free_element (struct format_arg *element)
193 if (element->type == FAT_LIST)
194 free_list (element->list);
197 /* Free an argument list. */
198 /* Memory effects: Frees list. */
199 static void
200 free_list (struct format_arg_list *list)
202 unsigned int i;
204 for (i = 0; i < list->initial.count; i++)
205 free_element (&list->initial.element[i]);
206 if (list->initial.element != NULL)
207 free (list->initial.element);
209 for (i = 0; i < list->repeated.count; i++)
210 free_element (&list->repeated.element[i]);
211 if (list->repeated.element != NULL)
212 free (list->repeated.element);
216 /* ======================== Copy a format_arg_list ======================== */
218 /* Copy the data belonging to an argument list element. */
219 static inline void
220 copy_element (struct format_arg *newelement,
221 const struct format_arg *oldelement)
223 newelement->repcount = oldelement->repcount;
224 newelement->presence = oldelement->presence;
225 newelement->type = oldelement->type;
226 if (oldelement->type == FAT_LIST)
227 newelement->list = copy_list (oldelement->list);
230 /* Copy an argument list. */
231 /* Memory effects: Freshly allocated result. */
232 static struct format_arg_list *
233 copy_list (const struct format_arg_list *list)
235 struct format_arg_list *newlist;
236 unsigned int length;
237 unsigned int i;
239 VERIFY_LIST (list);
241 newlist =
242 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
244 newlist->initial.count = newlist->initial.allocated = list->initial.count;
245 length = 0;
246 if (list->initial.count == 0)
247 newlist->initial.element = NULL;
248 else
250 newlist->initial.element =
251 (struct format_arg *)
252 xmalloc (newlist->initial.allocated * sizeof (struct format_arg));
253 for (i = 0; i < list->initial.count; i++)
255 copy_element (&newlist->initial.element[i],
256 &list->initial.element[i]);
257 length += list->initial.element[i].repcount;
260 ASSERT (length == list->initial.length);
261 newlist->initial.length = length;
263 newlist->repeated.count = newlist->repeated.allocated = list->repeated.count;
264 length = 0;
265 if (list->repeated.count == 0)
266 newlist->repeated.element = NULL;
267 else
269 newlist->repeated.element =
270 (struct format_arg *)
271 xmalloc (newlist->repeated.allocated * sizeof (struct format_arg));
272 for (i = 0; i < list->repeated.count; i++)
274 copy_element (&newlist->repeated.element[i],
275 &list->repeated.element[i]);
276 length += list->repeated.element[i].repcount;
279 ASSERT (length == list->repeated.length);
280 newlist->repeated.length = length;
282 VERIFY_LIST (newlist);
284 return newlist;
288 /* ===================== Compare two format_arg_lists ===================== */
290 /* Tests whether two normalized argument constraints are equivalent,
291 ignoring the repcount. */
292 static bool
293 equal_element (const struct format_arg * e1, const struct format_arg * e2)
295 return (e1->presence == e2->presence
296 && e1->type == e2->type
297 && (e1->type == FAT_LIST ? equal_list (e1->list, e2->list) : true));
300 /* Tests whether two normalized argument list constraints are equivalent. */
301 /* Memory effects: none. */
302 static bool
303 equal_list (const struct format_arg_list *list1,
304 const struct format_arg_list *list2)
306 unsigned int n, i;
308 VERIFY_LIST (list1);
309 VERIFY_LIST (list2);
311 n = list1->initial.count;
312 if (n != list2->initial.count)
313 return false;
314 for (i = 0; i < n; i++)
316 const struct format_arg * e1 = &list1->initial.element[i];
317 const struct format_arg * e2 = &list2->initial.element[i];
319 if (!(e1->repcount == e2->repcount && equal_element (e1, e2)))
320 return false;
323 n = list1->repeated.count;
324 if (n != list2->repeated.count)
325 return false;
326 for (i = 0; i < n; i++)
328 const struct format_arg * e1 = &list1->repeated.element[i];
329 const struct format_arg * e2 = &list2->repeated.element[i];
331 if (!(e1->repcount == e2->repcount && equal_element (e1, e2)))
332 return false;
335 return true;
339 /* ===================== Incremental memory allocation ===================== */
341 /* Ensure list->initial.allocated >= newcount. */
342 static inline void
343 ensure_initial_alloc (struct format_arg_list *list, unsigned int newcount)
345 if (newcount > list->initial.allocated)
347 list->initial.allocated =
348 MAX (2 * list->initial.allocated + 1, newcount);
349 list->initial.element =
350 (struct format_arg *)
351 xrealloc (list->initial.element,
352 list->initial.allocated * sizeof (struct format_arg));
356 /* Ensure list->initial.allocated > list->initial.count. */
357 static inline void
358 grow_initial_alloc (struct format_arg_list *list)
360 if (list->initial.count >= list->initial.allocated)
362 list->initial.allocated =
363 MAX (2 * list->initial.allocated + 1, list->initial.count + 1);
364 list->initial.element =
365 (struct format_arg *)
366 xrealloc (list->initial.element,
367 list->initial.allocated * sizeof (struct format_arg));
371 /* Ensure list->repeated.allocated >= newcount. */
372 static inline void
373 ensure_repeated_alloc (struct format_arg_list *list, unsigned int newcount)
375 if (newcount > list->repeated.allocated)
377 list->repeated.allocated =
378 MAX (2 * list->repeated.allocated + 1, newcount);
379 list->repeated.element =
380 (struct format_arg *)
381 xrealloc (list->repeated.element,
382 list->repeated.allocated * sizeof (struct format_arg));
386 /* Ensure list->repeated.allocated > list->repeated.count. */
387 static inline void
388 grow_repeated_alloc (struct format_arg_list *list)
390 if (list->repeated.count >= list->repeated.allocated)
392 list->repeated.allocated =
393 MAX (2 * list->repeated.allocated + 1, list->repeated.count + 1);
394 list->repeated.element =
395 (struct format_arg *)
396 xrealloc (list->repeated.element,
397 list->repeated.allocated * sizeof (struct format_arg));
402 /* ====================== Normalize a format_arg_list ====================== */
404 /* Normalize an argument list constraint, assuming all sublists are already
405 normalized. */
406 /* Memory effects: Destructively modifies list. */
407 static void
408 normalize_outermost_list (struct format_arg_list *list)
410 unsigned int n, i, j;
412 /* Step 1: Combine adjacent elements.
413 Copy from i to j, keeping 0 <= j <= i. */
415 n = list->initial.count;
416 for (i = j = 0; i < n; i++)
417 if (j > 0
418 && equal_element (&list->initial.element[i],
419 &list->initial.element[j-1]))
421 list->initial.element[j-1].repcount +=
422 list->initial.element[i].repcount;
423 free_element (&list->initial.element[i]);
425 else
427 if (j < i)
428 list->initial.element[j] = list->initial.element[i];
429 j++;
431 list->initial.count = j;
433 n = list->repeated.count;
434 for (i = j = 0; i < n; i++)
435 if (j > 0
436 && equal_element (&list->repeated.element[i],
437 &list->repeated.element[j-1]))
439 list->repeated.element[j-1].repcount +=
440 list->repeated.element[i].repcount;
441 free_element (&list->repeated.element[i]);
443 else
445 if (j < i)
446 list->repeated.element[j] = list->repeated.element[i];
447 j++;
449 list->repeated.count = j;
451 /* Nothing more to be done if the loop segment is empty. */
452 if (list->repeated.count > 0)
454 unsigned int m, repcount0_extra;
456 /* Step 2: Reduce the loop period. */
457 n = list->repeated.count;
458 repcount0_extra = 0;
459 if (n > 1
460 && equal_element (&list->repeated.element[0],
461 &list->repeated.element[n-1]))
463 repcount0_extra = list->repeated.element[n-1].repcount;
464 n--;
466 /* Proceed as if the loop period were n, with
467 list->repeated.element[0].repcount incremented by repcount0_extra. */
468 for (m = 2; m <= n / 2; n++)
469 if ((n % m) == 0)
471 /* m is a divisor of n. Try to reduce the loop period to n. */
472 bool ok = true;
474 for (i = 0; i < n - m; i++)
475 if (!((list->repeated.element[i].repcount
476 + (i == 0 ? repcount0_extra : 0)
477 == list->repeated.element[i+m].repcount)
478 && equal_element (&list->repeated.element[i],
479 &list->repeated.element[i+m])))
481 ok = false;
482 break;
484 if (ok)
486 for (i = m; i < n; i++)
487 free_element (&list->repeated.element[i]);
488 if (n < list->repeated.count)
489 list->repeated.element[m] = list->repeated.element[n];
490 list->repeated.count = list->repeated.count - n + m;
491 list->repeated.length /= n / m;
492 break;
496 /* Step 3: Roll as much as possible of the initial segment's tail
497 into the loop. */
498 if (list->repeated.count == 1)
500 if (list->initial.count > 0
501 && equal_element (&list->initial.element[list->initial.count-1],
502 &list->repeated.element[0]))
504 /* Roll the last element of the initial segment into the loop.
505 Its repcount is irrelevant. The second-to-last element is
506 certainly different and doesn't need to be considered. */
507 list->initial.length -=
508 list->initial.element[list->initial.count-1].repcount;
509 list->initial.count--;
512 else
514 while (list->initial.count > 0
515 && equal_element (&list->initial.element[list->initial.count-1],
516 &list->repeated.element[list->repeated.count-1]))
518 unsigned int moved_repcount =
519 MIN (list->initial.element[list->initial.count-1].repcount,
520 list->repeated.element[list->repeated.count-1].repcount);
522 /* Add the element at the start of list->repeated. */
523 if (equal_element (&list->repeated.element[0],
524 &list->repeated.element[list->repeated.count-1]))
525 list->repeated.element[0].repcount += moved_repcount;
526 else
528 unsigned int newcount = list->repeated.count + 1;
529 ensure_repeated_alloc (list, newcount);
530 for (i = newcount - 1; i > 0; i--)
531 list->repeated.element[i] = list->repeated.element[i-1];
532 list->repeated.count = newcount;
533 copy_element (&list->repeated.element[0],
534 &list->repeated.element[list->repeated.count-1]);
535 list->repeated.element[0].repcount = moved_repcount;
538 /* Remove the element from the end of list->repeated. */
539 list->repeated.element[list->repeated.count-1].repcount -=
540 moved_repcount;
541 if (list->repeated.element[list->repeated.count-1].repcount == 0)
543 free_element (&list->repeated.element[list->repeated.count-1]);
544 list->repeated.count--;
547 /* Remove the element from the end of list->initial. */
548 list->initial.element[list->initial.count-1].repcount -=
549 moved_repcount;
550 if (list->initial.element[list->initial.count-1].repcount == 0)
552 free_element (&list->initial.element[list->initial.count-1]);
553 list->initial.count--;
555 list->initial.length -= moved_repcount;
561 /* Normalize an argument list constraint. */
562 /* Memory effects: Destructively modifies list. */
563 static void
564 normalize_list (struct format_arg_list *list)
566 unsigned int n, i;
568 VERIFY_LIST (list);
570 /* First normalize all elements, recursively. */
571 n = list->initial.count;
572 for (i = 0; i < n; i++)
573 if (list->initial.element[i].type == FAT_LIST)
574 normalize_list (list->initial.element[i].list);
575 n = list->repeated.count;
576 for (i = 0; i < n; i++)
577 if (list->repeated.element[i].type == FAT_LIST)
578 normalize_list (list->repeated.element[i].list);
580 /* Then normalize the top level list. */
581 normalize_outermost_list (list);
583 VERIFY_LIST (list);
587 /* ===================== Unconstrained and empty lists ===================== */
589 /* It's easier to allocate these on demand, than to be careful not to
590 accidentally modify statically allocated lists. */
593 /* Create an unconstrained argument list. */
594 /* Memory effects: Freshly allocated result. */
595 static struct format_arg_list *
596 make_unconstrained_list ()
598 struct format_arg_list *list;
600 list = (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
601 list->initial.count = 0;
602 list->initial.allocated = 0;
603 list->initial.element = NULL;
604 list->initial.length = 0;
605 list->repeated.count = 1;
606 list->repeated.allocated = 1;
607 list->repeated.element =
608 (struct format_arg *) xmalloc (1 * sizeof (struct format_arg));
609 list->repeated.element[0].repcount = 1;
610 list->repeated.element[0].presence = FCT_OPTIONAL;
611 list->repeated.element[0].type = FAT_OBJECT;
612 list->repeated.length = 1;
614 VERIFY_LIST (list);
616 return list;
620 /* Create an empty argument list. */
621 /* Memory effects: Freshly allocated result. */
622 static struct format_arg_list *
623 make_empty_list ()
625 struct format_arg_list *list;
627 list = (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
628 list->initial.count = 0;
629 list->initial.allocated = 0;
630 list->initial.element = NULL;
631 list->initial.length = 0;
632 list->repeated.count = 0;
633 list->repeated.allocated = 0;
634 list->repeated.element = NULL;
635 list->repeated.length = 0;
637 VERIFY_LIST (list);
639 return list;
643 /* Test for an empty list. */
644 /* Memory effects: none. */
645 static bool
646 is_empty_list (const struct format_arg_list *list)
648 return (list->initial.count == 0 && list->repeated.count == 0);
652 /* ======================== format_arg_list surgery ======================== */
654 /* Unfold list->repeated m times, where m >= 1.
655 Assumes list->repeated.count > 0. */
656 /* Memory effects: list is destructively modified. */
657 static void
658 unfold_loop (struct format_arg_list *list, unsigned int m)
660 unsigned int i, j, k;
662 if (m > 1)
664 unsigned int newcount = list->repeated.count * m;
665 ensure_repeated_alloc (list, newcount);
666 i = list->repeated.count;
667 for (k = 1; k < m; k++)
668 for (j = 0; j < list->repeated.count; j++, i++)
669 copy_element (&list->repeated.element[i], &list->repeated.element[j]);
670 list->repeated.count = newcount;
671 list->repeated.length = list->repeated.length * m;
675 /* Ensure list->initial.length := m, where m >= list->initial.length.
676 Assumes list->repeated.count > 0. */
677 /* Memory effects: list is destructively modified. */
678 static void
679 rotate_loop (struct format_arg_list *list, unsigned int m)
681 if (m == list->initial.length)
682 return;
684 if (list->repeated.count == 1)
686 /* Instead of multiple copies of list->repeated.element[0], a single
687 copy with higher repcount is appended to list->initial. */
688 unsigned int i, newcount;
690 newcount = list->initial.count + 1;
691 ensure_initial_alloc (list, newcount);
692 i = list->initial.count;
693 copy_element (&list->initial.element[i], &list->repeated.element[0]);
694 list->initial.element[i].repcount = m - list->initial.length;
695 list->initial.count = newcount;
696 list->initial.length = m;
698 else
700 unsigned int n = list->repeated.length;
702 /* Write m = list->initial.length + q * n + r with 0 <= r < n. */
703 unsigned int q = (m - list->initial.length) / n;
704 unsigned int r = (m - list->initial.length) % n;
706 /* Determine how many entries of list->repeated are needed for
707 length r. */
708 unsigned int s;
709 unsigned int t;
711 for (t = r, s = 0;
712 s < list->repeated.count && t >= list->repeated.element[s].repcount;
713 t -= list->repeated.element[s].repcount, s++)
716 /* s must be < list->repeated.count, otherwise r would have been >= n. */
717 ASSERT (s < list->repeated.count);
719 /* So we need to add to list->initial:
720 q full copies of list->repeated,
721 plus the s first elements of list->repeated,
722 plus, if t > 0, a splitoff of list->repeated.element[s]. */
724 unsigned int i, j, k, newcount;
726 i = list->initial.count;
727 newcount = i + q * list->repeated.count + s + (t > 0 ? 1 : 0);
728 ensure_initial_alloc (list, newcount);
729 for (k = 0; k < q; k++)
730 for (j = 0; j < list->repeated.count; j++, i++)
731 copy_element (&list->initial.element[i],
732 &list->repeated.element[j]);
733 for (j = 0; j < s; j++, i++)
734 copy_element (&list->initial.element[i], &list->repeated.element[j]);
735 if (t > 0)
737 copy_element (&list->initial.element[i],
738 &list->repeated.element[j]);
739 list->initial.element[i].repcount = t;
740 i++;
742 ASSERT (i == newcount);
743 list->initial.count = newcount;
744 /* The new length of the initial segment is
745 = list->initial.length
746 + q * list->repeated.length
747 + list->repeated[0..s-1].repcount + t
748 = list->initial.length + q * n + r
749 = m.
751 list->initial.length = m;
754 /* And rotate list->repeated. */
755 if (r > 0)
757 unsigned int i, j, oldcount, newcount;
758 struct format_arg *newelement;
760 oldcount = list->repeated.count;
761 newcount = list->repeated.count + (t > 0 ? 1 : 0);
762 newelement =
763 (struct format_arg *)
764 xmalloc (newcount * sizeof (struct format_arg));
765 i = 0;
766 for (j = s; j < oldcount; j++, i++)
767 newelement[i] = list->repeated.element[j];
768 for (j = 0; j < s; j++, i++)
769 newelement[i] = list->repeated.element[j];
770 if (t > 0)
772 copy_element (&newelement[oldcount], &newelement[0]);
773 newelement[0].repcount -= t;
774 newelement[oldcount].repcount = t;
776 free (list->repeated.element);
777 list->repeated.element = newelement;
783 /* Ensure index n in the initial segment falls on a split between elements,
784 i.e. if 0 < n < list->initial.length, then n-1 and n are covered by two
785 different adjacent elements. */
786 /* Memory effects: list is destructively modified. */
787 static unsigned int
788 initial_splitelement (struct format_arg_list *list, unsigned int n)
790 unsigned int s;
791 unsigned int t;
792 unsigned int oldrepcount;
793 unsigned int newcount;
794 unsigned int i;
796 VERIFY_LIST (list);
798 if (n > list->initial.length)
800 ASSERT (list->repeated.count > 0);
801 rotate_loop (list, n);
802 ASSERT (n <= list->initial.length);
805 /* Determine how many entries of list->initial need to be skipped. */
806 for (t = n, s = 0;
807 s < list->initial.count && t >= list->initial.element[s].repcount;
808 t -= list->initial.element[s].repcount, s++)
811 if (t == 0)
812 return s;
814 ASSERT (s < list->initial.count);
816 /* Split the entry into two entries. */
817 oldrepcount = list->initial.element[s].repcount;
818 newcount = list->initial.count + 1;
819 ensure_initial_alloc (list, newcount);
820 for (i = list->initial.count - 1; i > s; i--)
821 list->initial.element[i+1] = list->initial.element[i];
822 copy_element (&list->initial.element[s+1], &list->initial.element[s]);
823 list->initial.element[s].repcount = t;
824 list->initial.element[s+1].repcount = oldrepcount - t;
825 list->initial.count = newcount;
827 VERIFY_LIST (list);
829 return s+1;
833 /* Ensure index n in the initial segment is not shared. Return its index. */
834 /* Memory effects: list is destructively modified. */
835 static unsigned int
836 initial_unshare (struct format_arg_list *list, unsigned int n)
838 /* This does the same side effects as
839 initial_splitelement (list, n);
840 initial_splitelement (list, n + 1);
842 unsigned int s;
843 unsigned int t;
845 VERIFY_LIST (list);
847 if (n >= list->initial.length)
849 ASSERT (list->repeated.count > 0);
850 rotate_loop (list, n + 1);
851 ASSERT (n < list->initial.length);
854 /* Determine how many entries of list->initial need to be skipped. */
855 for (t = n, s = 0;
856 s < list->initial.count && t >= list->initial.element[s].repcount;
857 t -= list->initial.element[s].repcount, s++)
860 /* s must be < list->initial.count. */
861 ASSERT (s < list->initial.count);
863 if (list->initial.element[s].repcount > 1)
865 /* Split the entry into at most three entries: for indices < n,
866 for index n, and for indices > n. */
867 unsigned int oldrepcount = list->initial.element[s].repcount;
868 unsigned int newcount =
869 list->initial.count + (t == 0 || t == oldrepcount - 1 ? 1 : 2);
870 ensure_initial_alloc (list, newcount);
871 if (t == 0 || t == oldrepcount - 1)
873 unsigned int i;
875 for (i = list->initial.count - 1; i > s; i--)
876 list->initial.element[i+1] = list->initial.element[i];
877 copy_element (&list->initial.element[s+1], &list->initial.element[s]);
878 if (t == 0)
880 list->initial.element[s].repcount = 1;
881 list->initial.element[s+1].repcount = oldrepcount - 1;
883 else
885 list->initial.element[s].repcount = oldrepcount - 1;
886 list->initial.element[s+1].repcount = 1;
889 else
891 unsigned int i;
893 for (i = list->initial.count - 1; i > s; i--)
894 list->initial.element[i+2] = list->initial.element[i];
895 copy_element (&list->initial.element[s+2], &list->initial.element[s]);
896 copy_element (&list->initial.element[s+1], &list->initial.element[s]);
897 list->initial.element[s].repcount = t;
898 list->initial.element[s+1].repcount = 1;
899 list->initial.element[s+2].repcount = oldrepcount - 1 - t;
901 list->initial.count = newcount;
902 if (t > 0)
903 s++;
906 /* Now the entry for index n has repcount 1. */
907 ASSERT (list->initial.element[s].repcount == 1);
909 VERIFY_LIST (list);
911 return s;
915 /* Add n unconstrained elements at the front of the list. */
916 /* Memory effects: list is destructively modified. */
917 static void
918 shift_list (struct format_arg_list *list, unsigned int n)
920 VERIFY_LIST (list);
922 if (n > 0)
924 unsigned int i;
926 grow_initial_alloc (list);
927 for (i = list->initial.count; i > 0; i--)
928 list->initial.element[i] = list->initial.element[i-1];
929 list->initial.element[0].repcount = n;
930 list->initial.element[0].presence = FCT_REQUIRED;
931 list->initial.element[0].type = FAT_OBJECT;
932 list->initial.count++;
933 list->initial.length += n;
935 normalize_outermost_list (list);
938 VERIFY_LIST (list);
942 /* ================= Intersection of two format_arg_lists ================= */
944 /* Create the intersection (i.e. combined constraints) of two argument
945 constraints. Return false if the intersection is empty, i.e. if the
946 two constraints give a contradiction. */
947 /* Memory effects: Freshly allocated element's sublist. */
948 static bool
949 make_intersected_element (struct format_arg *re,
950 const struct format_arg * e1,
951 const struct format_arg * e2)
953 /* Intersect the cdr types. */
954 if (e1->presence == FCT_REQUIRED || e2->presence == FCT_REQUIRED)
955 re->presence = FCT_REQUIRED;
956 else
957 re->presence = FCT_OPTIONAL;
959 /* Intersect the arg types. */
960 if (e1->type == FAT_OBJECT)
962 re->type = e2->type;
963 if (re->type == FAT_LIST)
964 re->list = copy_list (e2->list);
966 else if (e2->type == FAT_OBJECT)
968 re->type = e1->type;
969 if (re->type == FAT_LIST)
970 re->list = copy_list (e1->list);
972 else if (e1->type == FAT_LIST
973 && (e2->type == FAT_CHARACTER_INTEGER_NULL
974 || e2->type == FAT_CHARACTER_NULL
975 || e2->type == FAT_INTEGER_NULL))
977 re->type = e1->type;
978 re->list = make_intersection_with_empty_list (e1->list);
979 if (re->list == NULL)
980 return false;
982 else if (e2->type == FAT_LIST
983 && (e1->type == FAT_CHARACTER_INTEGER_NULL
984 || e1->type == FAT_CHARACTER_NULL
985 || e1->type == FAT_INTEGER_NULL))
987 re->type = e2->type;
988 re->list = make_intersection_with_empty_list (e2->list);
989 if (re->list == NULL)
990 return false;
992 else if (e1->type == FAT_CHARACTER_INTEGER_NULL
993 && (e2->type == FAT_CHARACTER_NULL || e2->type == FAT_CHARACTER
994 || e2->type == FAT_INTEGER_NULL || e2->type == FAT_INTEGER))
996 re->type = e2->type;
998 else if (e2->type == FAT_CHARACTER_INTEGER_NULL
999 && (e1->type == FAT_CHARACTER_NULL || e1->type == FAT_CHARACTER
1000 || e1->type == FAT_INTEGER_NULL || e1->type == FAT_INTEGER))
1002 re->type = e1->type;
1004 else if (e1->type == FAT_CHARACTER_NULL && e2->type == FAT_CHARACTER)
1006 re->type = e2->type;
1008 else if (e2->type == FAT_CHARACTER_NULL && e1->type == FAT_CHARACTER)
1010 re->type = e1->type;
1012 else if (e1->type == FAT_INTEGER_NULL && e2->type == FAT_INTEGER)
1014 re->type = e2->type;
1016 else if (e2->type == FAT_INTEGER_NULL && e1->type == FAT_INTEGER)
1018 re->type = e1->type;
1020 else if (e1->type == FAT_REAL && e2->type == FAT_INTEGER)
1022 re->type = e2->type;
1024 else if (e2->type == FAT_REAL && e1->type == FAT_INTEGER)
1026 re->type = e1->type;
1028 else if (e1->type == e2->type)
1030 re->type = e1->type;
1031 if (re->type == FAT_LIST)
1033 re->list = make_intersected_list (copy_list (e1->list),
1034 copy_list (e2->list));
1035 if (re->list == NULL)
1036 return false;
1039 else
1040 /* Each of FAT_CHARACTER, FAT_INTEGER, FAT_LIST, FAT_FORMATSTRING,
1041 FAT_FUNCTION matches only itself. Contradiction. */
1042 return false;
1044 return true;
1047 /* Append list->repeated to list->initial, and clear list->repeated. */
1048 /* Memory effects: list is destructively modified. */
1049 static void
1050 append_repeated_to_initial (struct format_arg_list *list)
1052 if (list->repeated.count > 0)
1054 /* Move list->repeated over to list->initial. */
1055 unsigned int i, j, newcount;
1057 newcount = list->initial.count + list->repeated.count;
1058 ensure_initial_alloc (list, newcount);
1059 i = list->initial.count;
1060 for (j = 0; j < list->repeated.count; j++, i++)
1061 list->initial.element[i] = list->repeated.element[j];
1062 list->initial.count = newcount;
1063 list->initial.length = list->initial.length + list->repeated.length;
1064 free (list->repeated.element);
1065 list->repeated.element = NULL;
1066 list->repeated.allocated = 0;
1067 list->repeated.count = 0;
1068 list->repeated.length = 0;
1072 /* Handle a contradiction during building of a format_arg_list.
1073 The list consists only of an initial segment. The repeated segment is
1074 empty. This function searches the last FCT_OPTIONAL and cuts off the
1075 list at this point, or - if none is found - returns NULL. */
1076 /* Memory effects: list is destructively modified. If NULL is returned,
1077 list is freed. */
1078 static struct format_arg_list *
1079 backtrack_in_initial (struct format_arg_list *list)
1081 ASSERT (list->repeated.count == 0);
1083 while (list->initial.count > 0)
1085 unsigned int i = list->initial.count - 1;
1086 if (list->initial.element[i].presence == FCT_REQUIRED)
1088 /* Throw away this element. */
1089 list->initial.length -= list->initial.element[i].repcount;
1090 free_element (&list->initial.element[i]);
1091 list->initial.count = i;
1093 else /* list->initial.element[i].presence == FCT_OPTIONAL */
1095 /* The list must end here. */
1096 list->initial.length--;
1097 if (list->initial.element[i].repcount > 1)
1098 list->initial.element[i].repcount--;
1099 else
1101 free_element (&list->initial.element[i]);
1102 list->initial.count = i;
1104 VERIFY_LIST (list);
1105 return list;
1109 free_list (list);
1110 return NULL;
1113 /* Create the intersection (i.e. combined constraints) of two argument list
1114 constraints. Free both argument lists when done. Return NULL if the
1115 intersection is empty, i.e. if the two constraints give a contradiction. */
1116 /* Memory effects: list1 and list2 are freed. The result, if non-NULL, is
1117 freshly allocated. */
1118 static struct format_arg_list *
1119 make_intersected_list (struct format_arg_list *list1,
1120 struct format_arg_list *list2)
1122 struct format_arg_list *result;
1124 VERIFY_LIST (list1);
1125 VERIFY_LIST (list2);
1127 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1128 /* Step 1: Ensure list1->repeated.length == list2->repeated.length. */
1130 unsigned int n1 = list1->repeated.length;
1131 unsigned int n2 = list2->repeated.length;
1132 unsigned int g = gcd (n1, n2);
1133 unsigned int m1 = n2 / g; /* = lcm(n1,n2) / n1 */
1134 unsigned int m2 = n1 / g; /* = lcm(n1,n2) / n2 */
1136 unfold_loop (list1, m1);
1137 unfold_loop (list2, m2);
1138 /* Now list1->repeated.length = list2->repeated.length = lcm(n1,n2). */
1141 if (list1->repeated.length > 0 || list2->repeated.length > 0)
1142 /* Step 2: Ensure the initial segment of the result can be computed
1143 from the initial segments of list1 and list2. If both have a
1144 repeated segment, this means to ensure
1145 list1->initial.length == list2->initial.length. */
1147 unsigned int m = MAX (list1->initial.length, list2->initial.length);
1149 if (list1->repeated.length > 0)
1150 rotate_loop (list1, m);
1151 if (list2->repeated.length > 0)
1152 rotate_loop (list2, m);
1155 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1157 ASSERT (list1->initial.length == list2->initial.length);
1158 ASSERT (list1->repeated.length == list2->repeated.length);
1161 /* Step 3: Allocate the result. */
1162 result =
1163 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
1164 result->initial.count = 0;
1165 result->initial.allocated = 0;
1166 result->initial.element = NULL;
1167 result->initial.length = 0;
1168 result->repeated.count = 0;
1169 result->repeated.allocated = 0;
1170 result->repeated.element = NULL;
1171 result->repeated.length = 0;
1173 /* Step 4: Elementwise intersection of list1->initial, list2->initial. */
1175 struct format_arg *e1;
1176 struct format_arg *e2;
1177 unsigned int c1;
1178 unsigned int c2;
1180 e1 = list1->initial.element; c1 = list1->initial.count;
1181 e2 = list2->initial.element; c2 = list2->initial.count;
1182 while (c1 > 0 && c2 > 0)
1184 struct format_arg *re;
1186 /* Ensure room in result->initial. */
1187 grow_initial_alloc (result);
1188 re = &result->initial.element[result->initial.count];
1189 re->repcount = MIN (e1->repcount, e2->repcount);
1191 /* Intersect the argument types. */
1192 if (!make_intersected_element (re, e1, e2))
1194 /* If re->presence == FCT_OPTIONAL, the result list ends here. */
1195 if (re->presence == FCT_REQUIRED)
1196 /* Contradiction. Backtrack. */
1197 result = backtrack_in_initial (result);
1198 goto done;
1201 result->initial.count++;
1202 result->initial.length += re->repcount;
1204 e1->repcount -= re->repcount;
1205 if (e1->repcount == 0)
1207 e1++;
1208 c1--;
1210 e2->repcount -= re->repcount;
1211 if (e2->repcount == 0)
1213 e2++;
1214 c2--;
1218 if (list1->repeated.count == 0 && list2->repeated.count == 0)
1220 /* Intersecting two finite lists. */
1221 if (c1 > 0)
1223 /* list1 longer than list2. */
1224 if (e1->presence == FCT_REQUIRED)
1225 /* Contradiction. Backtrack. */
1226 result = backtrack_in_initial (result);
1228 else if (c2 > 0)
1230 /* list2 longer than list1. */
1231 if (e2->presence == FCT_REQUIRED)
1232 /* Contradiction. Backtrack. */
1233 result = backtrack_in_initial (result);
1235 goto done;
1237 else if (list1->repeated.count == 0)
1239 /* Intersecting a finite and an infinite list. */
1240 ASSERT (c1 == 0);
1241 if ((c2 > 0 ? e2->presence : list2->repeated.element[0].presence)
1242 == FCT_REQUIRED)
1243 /* Contradiction. Backtrack. */
1244 result = backtrack_in_initial (result);
1245 goto done;
1247 else if (list2->repeated.count == 0)
1249 /* Intersecting an infinite and a finite list. */
1250 ASSERT (c2 == 0);
1251 if ((c1 > 0 ? e1->presence : list1->repeated.element[0].presence)
1252 == FCT_REQUIRED)
1253 /* Contradiction. Backtrack. */
1254 result = backtrack_in_initial (result);
1255 goto done;
1257 /* Intersecting two infinite lists. */
1258 ASSERT (c1 == 0 && c2 == 0);
1261 /* Step 5: Elementwise intersection of list1->repeated, list2->repeated. */
1263 struct format_arg *e1;
1264 struct format_arg *e2;
1265 unsigned int c1;
1266 unsigned int c2;
1268 e1 = list1->repeated.element; c1 = list1->repeated.count;
1269 e2 = list2->repeated.element; c2 = list2->repeated.count;
1270 while (c1 > 0 && c2 > 0)
1272 struct format_arg *re;
1274 /* Ensure room in result->repeated. */
1275 grow_repeated_alloc (result);
1276 re = &result->repeated.element[result->repeated.count];
1277 re->repcount = MIN (e1->repcount, e2->repcount);
1279 /* Intersect the argument types. */
1280 if (!make_intersected_element (re, e1, e2))
1282 append_repeated_to_initial (result);
1284 /* If re->presence == FCT_OPTIONAL, the result list ends here. */
1285 if (re->presence == FCT_REQUIRED)
1286 /* Contradiction. Backtrack. */
1287 result = backtrack_in_initial (result);
1289 goto done;
1292 result->repeated.count++;
1293 result->repeated.length += re->repcount;
1295 e1->repcount -= re->repcount;
1296 if (e1->repcount == 0)
1298 e1++;
1299 c1--;
1301 e2->repcount -= re->repcount;
1302 if (e2->repcount == 0)
1304 e2++;
1305 c2--;
1308 ASSERT (c1 == 0 && c2 == 0);
1311 done:
1312 free_list (list1);
1313 free_list (list2);
1314 if (result != NULL)
1316 /* Undo the loop unfolding and unrolling done above. */
1317 normalize_outermost_list (result);
1318 VERIFY_LIST (result);
1320 return result;
1324 /* Create the intersection of an argument list and the empty list.
1325 Return NULL if the intersection is empty. */
1326 /* Memory effects: The result, if non-NULL, is freshly allocated. */
1327 static struct format_arg_list *
1328 make_intersection_with_empty_list (struct format_arg_list *list)
1330 #if 0 /* equivalent but slower */
1331 return make_intersected_list (copy_list (list), make_empty_list ());
1332 #else
1333 if (list->initial.count > 0
1334 ? list->initial.element[0].presence == FCT_REQUIRED
1335 : list->repeated.count > 0
1336 && list->repeated.element[0].presence == FCT_REQUIRED)
1337 return NULL;
1338 else
1339 return make_empty_list ();
1340 #endif
1344 #ifdef unused
1345 /* Create the intersection of two argument list constraints. NULL stands
1346 for an impossible situation, i.e. a contradiction. */
1347 /* Memory effects: list1 and list2 are freed if non-NULL. The result,
1348 if non-NULL, is freshly allocated. */
1349 static struct format_arg_list *
1350 intersection (struct format_arg_list *list1, struct format_arg_list *list2)
1352 if (list1 != NULL)
1354 if (list2 != NULL)
1355 return make_intersected_list (list1, list2);
1356 else
1358 free_list (list1);
1359 return NULL;
1362 else
1364 if (list2 != NULL)
1366 free_list (list2);
1367 return NULL;
1369 else
1370 return NULL;
1373 #endif
1376 /* ===================== Union of two format_arg_lists ===================== */
1378 /* Create the union (i.e. alternative constraints) of two argument
1379 constraints. */
1380 static void
1381 make_union_element (struct format_arg *re,
1382 const struct format_arg * e1,
1383 const struct format_arg * e2)
1385 /* Union of the cdr types. */
1386 if (e1->presence == FCT_REQUIRED && e2->presence == FCT_REQUIRED)
1387 re->presence = FCT_REQUIRED;
1388 else /* Either one of them is FCT_OPTIONAL. */
1389 re->presence = FCT_OPTIONAL;
1391 /* Union of the arg types. */
1392 if (e1->type == e2->type)
1394 re->type = e1->type;
1395 if (re->type == FAT_LIST)
1396 re->list = make_union_list (copy_list (e1->list),
1397 copy_list (e2->list));
1399 else if (e1->type == FAT_CHARACTER_INTEGER_NULL
1400 && (e2->type == FAT_CHARACTER_NULL || e2->type == FAT_CHARACTER
1401 || e2->type == FAT_INTEGER_NULL || e2->type == FAT_INTEGER))
1403 re->type = e1->type;
1405 else if (e2->type == FAT_CHARACTER_INTEGER_NULL
1406 && (e1->type == FAT_CHARACTER_NULL || e1->type == FAT_CHARACTER
1407 || e1->type == FAT_INTEGER_NULL || e1->type == FAT_INTEGER))
1409 re->type = e2->type;
1411 else if (e1->type == FAT_CHARACTER_NULL && e2->type == FAT_CHARACTER)
1413 re->type = e1->type;
1415 else if (e2->type == FAT_CHARACTER_NULL && e1->type == FAT_CHARACTER)
1417 re->type = e2->type;
1419 else if (e1->type == FAT_INTEGER_NULL && e2->type == FAT_INTEGER)
1421 re->type = e1->type;
1423 else if (e2->type == FAT_INTEGER_NULL && e1->type == FAT_INTEGER)
1425 re->type = e2->type;
1427 else if (e1->type == FAT_REAL && e2->type == FAT_INTEGER)
1429 re->type = e1->type;
1431 else if (e2->type == FAT_REAL && e1->type == FAT_INTEGER)
1433 re->type = e2->type;
1435 else if (e1->type == FAT_LIST && is_empty_list (e1->list))
1437 if (e2->type == FAT_CHARACTER_INTEGER_NULL
1438 || e2->type == FAT_CHARACTER_NULL
1439 || e2->type == FAT_INTEGER_NULL)
1440 re->type = e2->type;
1441 else if (e2->type == FAT_CHARACTER)
1442 re->type = FAT_CHARACTER_NULL;
1443 else if (e2->type == FAT_INTEGER)
1444 re->type = FAT_INTEGER_NULL;
1445 else
1446 re->type = FAT_OBJECT;
1448 else if (e2->type == FAT_LIST && is_empty_list (e2->list))
1450 if (e1->type == FAT_CHARACTER_INTEGER_NULL
1451 || e1->type == FAT_CHARACTER_NULL
1452 || e1->type == FAT_INTEGER_NULL)
1453 re->type = e1->type;
1454 else if (e1->type == FAT_CHARACTER)
1455 re->type = FAT_CHARACTER_NULL;
1456 else if (e1->type == FAT_INTEGER)
1457 re->type = FAT_INTEGER_NULL;
1458 else
1459 re->type = FAT_OBJECT;
1461 else if ((e1->type == FAT_CHARACTER || e1->type == FAT_CHARACTER_NULL)
1462 && (e2->type == FAT_INTEGER || e2->type == FAT_INTEGER_NULL))
1464 re->type = FAT_CHARACTER_INTEGER_NULL;
1466 else if ((e2->type == FAT_CHARACTER || e2->type == FAT_CHARACTER_NULL)
1467 && (e1->type == FAT_INTEGER || e1->type == FAT_INTEGER_NULL))
1469 re->type = FAT_CHARACTER_INTEGER_NULL;
1471 else
1473 /* Other union types are too hard to describe precisely. */
1474 re->type = FAT_OBJECT;
1478 /* Create the union (i.e. alternative constraints) of two argument list
1479 constraints. Free both argument lists when done. */
1480 /* Memory effects: list1 and list2 are freed. The result is freshly
1481 allocated. */
1482 static struct format_arg_list *
1483 make_union_list (struct format_arg_list *list1, struct format_arg_list *list2)
1485 struct format_arg_list *result;
1487 VERIFY_LIST (list1);
1488 VERIFY_LIST (list2);
1490 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1492 /* Step 1: Ensure list1->repeated.length == list2->repeated.length. */
1494 unsigned int n1 = list1->repeated.length;
1495 unsigned int n2 = list2->repeated.length;
1496 unsigned int g = gcd (n1, n2);
1497 unsigned int m1 = n2 / g; /* = lcm(n1,n2) / n1 */
1498 unsigned int m2 = n1 / g; /* = lcm(n1,n2) / n2 */
1500 unfold_loop (list1, m1);
1501 unfold_loop (list2, m2);
1502 /* Now list1->repeated.length = list2->repeated.length = lcm(n1,n2). */
1505 /* Step 2: Ensure that list1->initial.length == list2->initial.length. */
1507 unsigned int m = MAX (list1->initial.length, list2->initial.length);
1509 rotate_loop (list1, m);
1510 rotate_loop (list2, m);
1513 ASSERT (list1->initial.length == list2->initial.length);
1514 ASSERT (list1->repeated.length == list2->repeated.length);
1516 else if (list1->repeated.length > 0)
1518 /* Ensure the initial segment of the result can be computed from the
1519 initial segment of list1. */
1520 if (list2->initial.length >= list1->initial.length)
1522 rotate_loop (list1, list2->initial.length);
1523 if (list1->repeated.element[0].presence == FCT_REQUIRED)
1524 rotate_loop (list1, list1->initial.length + 1);
1527 else if (list2->repeated.length > 0)
1529 /* Ensure the initial segment of the result can be computed from the
1530 initial segment of list2. */
1531 if (list1->initial.length >= list2->initial.length)
1533 rotate_loop (list2, list1->initial.length);
1534 if (list2->repeated.element[0].presence == FCT_REQUIRED)
1535 rotate_loop (list2, list2->initial.length + 1);
1539 /* Step 3: Allocate the result. */
1540 result =
1541 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
1542 result->initial.count = 0;
1543 result->initial.allocated = 0;
1544 result->initial.element = NULL;
1545 result->initial.length = 0;
1546 result->repeated.count = 0;
1547 result->repeated.allocated = 0;
1548 result->repeated.element = NULL;
1549 result->repeated.length = 0;
1551 /* Step 4: Elementwise union of list1->initial, list2->initial. */
1553 struct format_arg *e1;
1554 struct format_arg *e2;
1555 unsigned int c1;
1556 unsigned int c2;
1558 e1 = list1->initial.element; c1 = list1->initial.count;
1559 e2 = list2->initial.element; c2 = list2->initial.count;
1560 while (c1 > 0 && c2 > 0)
1562 struct format_arg *re;
1564 /* Ensure room in result->initial. */
1565 grow_initial_alloc (result);
1566 re = &result->initial.element[result->initial.count];
1567 re->repcount = MIN (e1->repcount, e2->repcount);
1569 /* Union of the argument types. */
1570 make_union_element (re, e1, e2);
1572 result->initial.count++;
1573 result->initial.length += re->repcount;
1575 e1->repcount -= re->repcount;
1576 if (e1->repcount == 0)
1578 e1++;
1579 c1--;
1581 e2->repcount -= re->repcount;
1582 if (e2->repcount == 0)
1584 e2++;
1585 c2--;
1589 if (c1 > 0)
1591 /* list2 already terminated, but still more elements in list1->initial.
1592 Copy them all, but turn the first presence to FCT_OPTIONAL. */
1593 ASSERT (list2->repeated.count == 0);
1595 if (e1->presence == FCT_REQUIRED)
1597 struct format_arg *re;
1599 /* Ensure room in result->initial. */
1600 grow_initial_alloc (result);
1601 re = &result->initial.element[result->initial.count];
1602 copy_element (re, e1);
1603 re->presence = FCT_OPTIONAL;
1604 re->repcount = 1;
1605 result->initial.count++;
1606 result->initial.length += 1;
1607 e1->repcount -= 1;
1608 if (e1->repcount == 0)
1610 e1++;
1611 c1--;
1615 /* Ensure room in result->initial. */
1616 ensure_initial_alloc (result, result->initial.count + c1);
1617 while (c1 > 0)
1619 struct format_arg *re;
1621 re = &result->initial.element[result->initial.count];
1622 copy_element (re, e1);
1623 result->initial.count++;
1624 result->initial.length += re->repcount;
1625 e1++;
1626 c1--;
1629 else if (c2 > 0)
1631 /* list1 already terminated, but still more elements in list2->initial.
1632 Copy them all, but turn the first presence to FCT_OPTIONAL. */
1633 ASSERT (list1->repeated.count == 0);
1635 if (e2->presence == FCT_REQUIRED)
1637 struct format_arg *re;
1639 /* Ensure room in result->initial. */
1640 grow_initial_alloc (result);
1641 re = &result->initial.element[result->initial.count];
1642 copy_element (re, e2);
1643 re->presence = FCT_OPTIONAL;
1644 re->repcount = 1;
1645 result->initial.count++;
1646 result->initial.length += 1;
1647 e2->repcount -= 1;
1648 if (e2->repcount == 0)
1650 e2++;
1651 c2--;
1655 /* Ensure room in result->initial. */
1656 ensure_initial_alloc (result, result->initial.count + c2);
1657 while (c2 > 0)
1659 struct format_arg *re;
1661 re = &result->initial.element[result->initial.count];
1662 copy_element (re, e2);
1663 result->initial.count++;
1664 result->initial.length += re->repcount;
1665 e2++;
1666 c2--;
1669 ASSERT (c1 == 0 && c2 == 0);
1672 if (list1->repeated.length > 0 && list2->repeated.length > 0)
1673 /* Step 5: Elementwise union of list1->repeated, list2->repeated. */
1675 struct format_arg *e1;
1676 struct format_arg *e2;
1677 unsigned int c1;
1678 unsigned int c2;
1680 e1 = list1->repeated.element; c1 = list1->repeated.count;
1681 e2 = list2->repeated.element; c2 = list2->repeated.count;
1682 while (c1 > 0 && c2 > 0)
1684 struct format_arg *re;
1686 /* Ensure room in result->repeated. */
1687 grow_repeated_alloc (result);
1688 re = &result->repeated.element[result->repeated.count];
1689 re->repcount = MIN (e1->repcount, e2->repcount);
1691 /* Union of the argument types. */
1692 make_union_element (re, e1, e2);
1694 result->repeated.count++;
1695 result->repeated.length += re->repcount;
1697 e1->repcount -= re->repcount;
1698 if (e1->repcount == 0)
1700 e1++;
1701 c1--;
1703 e2->repcount -= re->repcount;
1704 if (e2->repcount == 0)
1706 e2++;
1707 c2--;
1710 ASSERT (c1 == 0 && c2 == 0);
1712 else if (list1->repeated.length > 0)
1714 /* Turning FCT_REQUIRED into FCT_OPTIONAL was already handled in the
1715 initial segment. Just copy the repeated segment of list1. */
1716 unsigned int i;
1718 result->repeated.count = list1->repeated.count;
1719 result->repeated.allocated = result->repeated.count;
1720 result->repeated.element =
1721 (struct format_arg *)
1722 xmalloc (result->repeated.allocated * sizeof (struct format_arg));
1723 for (i = 0; i < list1->repeated.count; i++)
1724 copy_element (&result->repeated.element[i],
1725 &list1->repeated.element[i]);
1726 result->repeated.length = list1->repeated.length;
1728 else if (list2->repeated.length > 0)
1730 /* Turning FCT_REQUIRED into FCT_OPTIONAL was already handled in the
1731 initial segment. Just copy the repeated segment of list2. */
1732 unsigned int i;
1734 result->repeated.count = list2->repeated.count;
1735 result->repeated.allocated = result->repeated.count;
1736 result->repeated.element =
1737 (struct format_arg *)
1738 xmalloc (result->repeated.allocated * sizeof (struct format_arg));
1739 for (i = 0; i < list2->repeated.count; i++)
1740 copy_element (&result->repeated.element[i],
1741 &list2->repeated.element[i]);
1742 result->repeated.length = list2->repeated.length;
1745 free_list (list1);
1746 free_list (list2);
1747 /* Undo the loop unfolding and unrolling done above. */
1748 normalize_outermost_list (result);
1749 VERIFY_LIST (result);
1750 return result;
1754 /* Create the union of an argument list and the empty list. */
1755 /* Memory effects: list is freed. The result is freshly allocated. */
1756 static struct format_arg_list *
1757 make_union_with_empty_list (struct format_arg_list *list)
1759 #if 0 /* equivalent but slower */
1760 return make_union_list (list, make_empty_list ());
1761 #else
1762 VERIFY_LIST (list);
1764 if (list->initial.count > 0
1765 ? list->initial.element[0].presence == FCT_REQUIRED
1766 : list->repeated.count > 0
1767 && list->repeated.element[0].presence == FCT_REQUIRED)
1769 initial_splitelement (list, 1);
1770 ASSERT (list->initial.count > 0);
1771 ASSERT (list->initial.element[0].repcount == 1);
1772 ASSERT (list->initial.element[0].presence == FCT_REQUIRED);
1773 list->initial.element[0].presence = FCT_OPTIONAL;
1775 /* We might need to merge list->initial.element[0] and
1776 list->initial.element[1]. */
1777 normalize_outermost_list (list);
1780 VERIFY_LIST (list);
1782 return list;
1783 #endif
1787 /* Create the union of two argument list constraints. NULL stands for an
1788 impossible situation, i.e. a contradiction. */
1789 /* Memory effects: list1 and list2 are freed if non-NULL. The result,
1790 if non-NULL, is freshly allocated. */
1791 static struct format_arg_list *
1792 union (struct format_arg_list *list1, struct format_arg_list *list2)
1794 if (list1 != NULL)
1796 if (list2 != NULL)
1797 return make_union_list (list1, list2);
1798 else
1799 return list1;
1801 else
1803 if (list2 != NULL)
1804 return list2;
1805 else
1806 return NULL;
1811 /* =========== Adding specific constraints to a format_arg_list =========== */
1814 /* Test whether arguments 0..n are required arguments in a list. */
1815 static bool
1816 is_required (const struct format_arg_list *list, unsigned int n)
1818 unsigned int s;
1819 unsigned int t;
1821 /* We'll check whether the first n+1 presence flags are FCT_REQUIRED. */
1822 t = n + 1;
1824 /* Walk the list->initial segment. */
1825 for (s = 0;
1826 s < list->initial.count && t >= list->initial.element[s].repcount;
1827 t -= list->initial.element[s].repcount, s++)
1828 if (list->initial.element[s].presence != FCT_REQUIRED)
1829 return false;
1831 if (t == 0)
1832 return true;
1834 if (s < list->initial.count)
1836 if (list->initial.element[s].presence != FCT_REQUIRED)
1837 return false;
1838 else
1839 return true;
1842 /* Walk the list->repeated segment. */
1843 if (list->repeated.count == 0)
1844 return false;
1846 for (s = 0;
1847 s < list->repeated.count && t >= list->repeated.element[s].repcount;
1848 t -= list->repeated.element[s].repcount, s++)
1849 if (list->repeated.element[s].presence != FCT_REQUIRED)
1850 return false;
1852 if (t == 0)
1853 return true;
1855 if (s < list->repeated.count)
1857 if (list->repeated.element[s].presence != FCT_REQUIRED)
1858 return false;
1859 else
1860 return true;
1863 /* The list->repeated segment consists only of FCT_REQUIRED. So,
1864 regardless how many more passes through list->repeated would be
1865 needed until t becomes 0, the result is true. */
1866 return true;
1870 /* Add a constraint to an argument list, namely that the arguments 0...n are
1871 present. NULL stands for an impossible situation, i.e. a contradiction. */
1872 /* Memory effects: list is freed. The result is freshly allocated. */
1873 static struct format_arg_list *
1874 add_required_constraint (struct format_arg_list *list, unsigned int n)
1876 unsigned int i, rest;
1878 if (list == NULL)
1879 return NULL;
1881 VERIFY_LIST (list);
1883 if (list->repeated.count == 0 && list->initial.length <= n)
1885 /* list is already constrained to have at most length n.
1886 Contradiction. */
1887 free_list (list);
1888 return NULL;
1891 initial_splitelement (list, n + 1);
1893 for (i = 0, rest = n + 1; rest > 0; )
1895 list->initial.element[i].presence = FCT_REQUIRED;
1896 rest -= list->initial.element[i].repcount;
1897 i++;
1900 VERIFY_LIST (list);
1902 return list;
1906 /* Add a constraint to an argument list, namely that the argument n is
1907 never present. NULL stands for an impossible situation, i.e. a
1908 contradiction. */
1909 /* Memory effects: list is freed. The result is freshly allocated. */
1910 static struct format_arg_list *
1911 add_end_constraint (struct format_arg_list *list, unsigned int n)
1913 unsigned int s, i;
1914 enum format_cdr_type n_presence;
1916 if (list == NULL)
1917 return NULL;
1919 VERIFY_LIST (list);
1921 if (list->repeated.count == 0 && list->initial.length <= n)
1922 /* list is already constrained to have at most length n. */
1923 return list;
1925 s = initial_splitelement (list, n);
1926 n_presence =
1927 (s < list->initial.count
1928 ? /* n < list->initial.length */ list->initial.element[s].presence
1929 : /* n >= list->initial.length */ list->repeated.element[0].presence);
1931 for (i = s; i < list->initial.count; i++)
1933 list->initial.length -= list->initial.element[i].repcount;
1934 free_element (&list->initial.element[i]);
1936 list->initial.count = s;
1938 for (i = 0; i < list->repeated.count; i++)
1939 free_element (&list->repeated.element[i]);
1940 if (list->repeated.element != NULL)
1941 free (list->repeated.element);
1942 list->repeated.element = NULL;
1943 list->repeated.allocated = 0;
1944 list->repeated.count = 0;
1945 list->repeated.length = 0;
1947 if (n_presence == FCT_REQUIRED)
1948 return backtrack_in_initial (list);
1949 else
1950 return list;
1954 /* Add a constraint to an argument list, namely that the argument n is
1955 of a given type. NULL stands for an impossible situation, i.e. a
1956 contradiction. Assumes a preceding add_required_constraint (list, n). */
1957 /* Memory effects: list is freed. The result is freshly allocated. */
1958 static struct format_arg_list *
1959 add_type_constraint (struct format_arg_list *list, unsigned int n,
1960 enum format_arg_type type)
1962 unsigned int s;
1963 struct format_arg newconstraint;
1964 struct format_arg tmpelement;
1966 if (list == NULL)
1967 return NULL;
1969 /* Through the previous add_required_constraint, we can assume
1970 list->initial.length >= n+1. */
1972 s = initial_unshare (list, n);
1974 newconstraint.presence = FCT_OPTIONAL;
1975 newconstraint.type = type;
1976 if (!make_intersected_element (&tmpelement,
1977 &list->initial.element[s], &newconstraint))
1978 return add_end_constraint (list, n);
1979 free_element (&list->initial.element[s]);
1980 list->initial.element[s].type = tmpelement.type;
1981 list->initial.element[s].list = tmpelement.list;
1983 VERIFY_LIST (list);
1985 return list;
1989 /* Add a constraint to an argument list, namely that the argument n is
1990 of a given list type. NULL stands for an impossible situation, i.e. a
1991 contradiction. Assumes a preceding add_required_constraint (list, n). */
1992 /* Memory effects: list is freed. The result is freshly allocated. */
1993 static struct format_arg_list *
1994 add_listtype_constraint (struct format_arg_list *list, unsigned int n,
1995 enum format_arg_type type,
1996 struct format_arg_list *sublist)
1998 unsigned int s;
1999 struct format_arg newconstraint;
2000 struct format_arg tmpelement;
2002 if (list == NULL)
2003 return NULL;
2005 /* Through the previous add_required_constraint, we can assume
2006 list->initial.length >= n+1. */
2008 s = initial_unshare (list, n);
2010 newconstraint.presence = FCT_OPTIONAL;
2011 newconstraint.type = type;
2012 newconstraint.list = sublist;
2013 if (!make_intersected_element (&tmpelement,
2014 &list->initial.element[s], &newconstraint))
2015 return add_end_constraint (list, n);
2016 free_element (&list->initial.element[s]);
2017 list->initial.element[s].type = tmpelement.type;
2018 list->initial.element[s].list = tmpelement.list;
2020 VERIFY_LIST (list);
2022 return list;
2026 /* ============= Subroutines used by the format string parser ============= */
2028 static void
2029 add_req_type_constraint (struct format_arg_list **listp,
2030 unsigned int position, enum format_arg_type type)
2032 *listp = add_required_constraint (*listp, position);
2033 *listp = add_type_constraint (*listp, position, type);
2037 static void
2038 add_req_listtype_constraint (struct format_arg_list **listp,
2039 unsigned int position, enum format_arg_type type,
2040 struct format_arg_list *sublist)
2042 *listp = add_required_constraint (*listp, position);
2043 *listp = add_listtype_constraint (*listp, position, type, sublist);
2047 /* Create an endless repeated list whose elements are lists constrained
2048 by sublist. */
2049 /* Memory effects: sublist is freed. The result is freshly allocated. */
2050 static struct format_arg_list *
2051 make_repeated_list_of_lists (struct format_arg_list *sublist)
2053 if (sublist == NULL)
2054 /* The list cannot have a single element. */
2055 return make_empty_list ();
2056 else
2058 struct format_arg_list *listlist;
2060 listlist =
2061 (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
2063 listlist->initial.count = 0;
2064 listlist->initial.allocated = 0;
2065 listlist->initial.element = NULL;
2066 listlist->initial.length = 0;
2067 listlist->repeated.count = 1;
2068 listlist->repeated.allocated = 1;
2069 listlist->repeated.element =
2070 (struct format_arg *) xmalloc (1 * sizeof (struct format_arg));
2071 listlist->repeated.element[0].repcount = 1;
2072 listlist->repeated.element[0].presence = FCT_OPTIONAL;
2073 listlist->repeated.element[0].type = FAT_LIST;
2074 listlist->repeated.element[0].list = sublist;
2075 listlist->repeated.length = 1;
2077 VERIFY_LIST (listlist);
2079 return listlist;
2084 /* Create an endless repeated list which represents the union of a finite
2085 number of copies of L, each time shifted by period:
2088 L and (*^period L)
2089 L and (*^period L) and (*^{2 period} L)
2090 L and (*^period L) and (*^{2 period} L) and (*^{3 period} L)
2093 /* Memory effects: sublist is freed. The result is freshly allocated. */
2094 static struct format_arg_list *
2095 make_repeated_list (struct format_arg_list *sublist, unsigned int period)
2097 struct segment tmp;
2098 struct segment *srcseg;
2099 struct format_arg_list *list;
2100 unsigned int p, n, i, si, ti, j, sj, tj, splitindex, newcount;
2101 bool ended;
2103 VERIFY_LIST (sublist);
2105 ASSERT (period > 0);
2107 if (sublist->repeated.count == 0)
2109 /* L is a finite list. */
2111 if (sublist->initial.length < period)
2112 /* L and (*^period L) is a contradition, so we need to consider
2113 only 1 and 0 iterations. */
2114 return make_union_with_empty_list (sublist);
2116 srcseg = &sublist->initial;
2117 p = period;
2119 else
2121 /* L is an infinite list. */
2122 /* p := lcm (period, period of L) */
2123 unsigned int Lp = sublist->repeated.length;
2124 unsigned int m = period / gcd (period, Lp); /* = lcm(period,Lp) / Lp */
2126 unfold_loop (sublist, m);
2127 p = m * Lp;
2129 /* Concatenate the initial and the repeated segments into a single
2130 segment. */
2131 tmp.count = sublist->initial.count + sublist->repeated.count;
2132 tmp.allocated = tmp.count;
2133 tmp.element =
2134 (struct format_arg *)
2135 xmalloc (tmp.allocated * sizeof (struct format_arg));
2136 for (i = 0; i < sublist->initial.count; i++)
2137 tmp.element[i] = sublist->initial.element[i];
2138 for (j = 0; j < sublist->repeated.count; i++, j++)
2139 tmp.element[i] = sublist->initial.element[j];
2140 tmp.length = sublist->initial.length + sublist->repeated.length;
2142 srcseg = &tmp;
2145 n = srcseg->length;
2147 /* Example: n = 7, p = 2
2148 Let L = (A B C D E F G).
2150 L = A B C D E F G
2151 L & L<<p = A B C&A D&B E&C F&D G&E
2152 L & L<<p & L<<2p = A B C&A D&B E&C&A F&D&B G&E&C
2153 ... = A B C&A D&B E&C&A F&D&B G&E&C&A
2155 Thus the result has an initial segment of length n - p and a period
2156 of p, and can be computed by floor(n/p) intersection operations.
2157 Or by a single incremental intersection operation, going from left
2158 to right. */
2160 list = (struct format_arg_list *) xmalloc (sizeof (struct format_arg_list));
2161 list->initial.count = 0;
2162 list->initial.allocated = 0;
2163 list->initial.element = NULL;
2164 list->initial.length = 0;
2165 list->repeated.count = 0;
2166 list->repeated.allocated = 0;
2167 list->repeated.element = NULL;
2168 list->repeated.length = 0;
2170 /* Sketch:
2171 for (i = 0; i < p; i++)
2172 list->initial.element[i] = srcseg->element[i];
2173 list->initial.element[0].presence = FCT_OPTIONAL; // union with empty list
2174 for (i = p, j = 0; i < n; i++, j++)
2175 list->initial.element[i] = srcseg->element[i] & list->initial.element[j];
2178 ended = false;
2180 i = 0, ti = 0, si = 0;
2181 while (i < p)
2183 unsigned int k = MIN (srcseg->element[si].repcount - ti, p - i);
2185 /* Ensure room in list->initial. */
2186 grow_initial_alloc (list);
2187 copy_element (&list->initial.element[list->initial.count],
2188 &srcseg->element[si]);
2189 list->initial.element[list->initial.count].repcount = k;
2190 list->initial.count++;
2191 list->initial.length += k;
2193 i += k;
2194 ti += k;
2195 if (ti == srcseg->element[si].repcount)
2197 ti = 0;
2198 si++;
2202 ASSERT (list->initial.count > 0);
2203 if (list->initial.element[0].presence == FCT_REQUIRED)
2205 initial_splitelement (list, 1);
2206 ASSERT (list->initial.element[0].presence == FCT_REQUIRED);
2207 ASSERT (list->initial.element[0].repcount == 1);
2208 list->initial.element[0].presence = FCT_OPTIONAL;
2211 j = 0, tj = 0, sj = 0;
2212 while (i < n)
2214 unsigned int k =
2215 MIN (srcseg->element[si].repcount - ti,
2216 list->initial.element[sj].repcount - tj);
2218 /* Ensure room in list->initial. */
2219 grow_initial_alloc (list);
2220 if (!make_intersected_element (&list->initial.element[list->initial.count],
2221 &srcseg->element[si],
2222 &list->initial.element[sj]))
2224 if (list->initial.element[list->initial.count].presence == FCT_REQUIRED)
2226 /* Contradiction. Backtrack. */
2227 list = backtrack_in_initial (list);
2228 ASSERT (list != NULL); /* at least the empty list is valid */
2229 return list;
2231 else
2233 /* The list ends here. */
2234 ended = true;
2235 break;
2238 list->initial.element[list->initial.count].repcount = k;
2239 list->initial.count++;
2240 list->initial.length += k;
2242 i += k;
2243 ti += k;
2244 if (ti == srcseg->element[si].repcount)
2246 ti = 0;
2247 si++;
2250 j += k;
2251 tj += k;
2252 if (tj == list->initial.element[sj].repcount)
2254 tj = 0;
2255 sj++;
2258 if (!ended)
2259 ASSERT (list->initial.length == n);
2261 /* Add optional exit points at 0, period, 2*period etc.
2262 FIXME: Not sure this is correct in all cases. */
2263 for (i = 0; i < list->initial.length; i += period)
2265 si = initial_unshare (list, i);
2266 list->initial.element[si].presence = FCT_OPTIONAL;
2269 if (!ended)
2271 /* Now split off the repeated part. */
2272 splitindex = initial_splitelement (list, n - p);
2273 newcount = list->initial.count - splitindex;
2274 if (newcount > list->repeated.allocated)
2276 list->repeated.allocated = newcount;
2277 list->repeated.element =
2278 (struct format_arg *) xmalloc (newcount * sizeof (struct format_arg));
2280 for (i = splitindex, j = 0; i < n; i++, j++)
2281 list->repeated.element[j] = list->initial.element[i];
2282 list->repeated.count = newcount;
2283 list->repeated.length = p;
2284 list->initial.count = splitindex;
2285 list->initial.length = n - p;
2288 VERIFY_LIST (list);
2290 return list;
2294 /* ================= Handling of format string directives ================= */
2296 /* Possible signatures of format directives. */
2297 static const enum format_arg_type I [1] = { FAT_INTEGER_NULL };
2298 static const enum format_arg_type II [2] = {
2299 FAT_INTEGER_NULL, FAT_INTEGER_NULL
2301 static const enum format_arg_type ICCI [4] = {
2302 FAT_INTEGER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL, FAT_INTEGER_NULL
2304 static const enum format_arg_type IIIC [4] = {
2305 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL
2307 static const enum format_arg_type IICCI [5] = {
2308 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL,
2309 FAT_INTEGER_NULL
2311 static const enum format_arg_type IIICC [5] = {
2312 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL,
2313 FAT_CHARACTER_NULL
2315 static const enum format_arg_type IIIICCC [7] = {
2316 FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL,
2317 FAT_CHARACTER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL
2319 static const enum format_arg_type THREE [3] = {
2320 FAT_CHARACTER_INTEGER_NULL, FAT_CHARACTER_INTEGER_NULL,
2321 FAT_CHARACTER_INTEGER_NULL
2325 /* Check the parameters. For V params, add the constraint to the argument
2326 list. Return false and fill in *invalid_reason if the format string is
2327 invalid. */
2328 static bool
2329 check_params (struct format_arg_list **listp,
2330 unsigned int paramcount, struct param *params,
2331 unsigned int t_count, const enum format_arg_type *t_types,
2332 unsigned int directives, char **invalid_reason)
2334 unsigned int orig_paramcount = paramcount;
2335 unsigned int orig_t_count = t_count;
2337 for (; paramcount > 0 && t_count > 0;
2338 params++, paramcount--, t_types++, t_count--)
2340 switch (*t_types)
2342 case FAT_CHARACTER_INTEGER_NULL:
2343 break;
2344 case FAT_CHARACTER_NULL:
2345 switch (params->type)
2347 case PT_NIL: case PT_CHARACTER: case PT_V:
2348 break;
2349 case PT_INTEGER: case PT_ARGCOUNT:
2350 /* wrong param type */
2351 *invalid_reason =
2352 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");
2353 return false;
2355 break;
2356 case FAT_INTEGER_NULL:
2357 switch (params->type)
2359 case PT_NIL: case PT_INTEGER: case PT_ARGCOUNT: case PT_V:
2360 break;
2361 case PT_CHARACTER:
2362 /* wrong param type */
2363 *invalid_reason =
2364 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");
2365 return false;
2367 break;
2368 default:
2369 abort ();
2371 if (params->type == PT_V)
2373 int position = params->value;
2374 if (position >= 0)
2375 add_req_type_constraint (listp, position, *t_types);
2379 for (; paramcount > 0; params++, paramcount--)
2380 switch (params->type)
2382 case PT_NIL:
2383 break;
2384 case PT_CHARACTER: case PT_INTEGER: case PT_ARGCOUNT:
2385 /* too many params for directive */
2386 *invalid_reason =
2387 xasprintf (ngettext ("In the directive number %u, too many parameters are given; expected at most %u parameter.",
2388 "In the directive number %u, too many parameters are given; expected at most %u parameters.",
2389 orig_t_count),
2390 directives, orig_t_count);
2391 return false;
2392 case PT_V:
2393 /* Force argument to be NIL. */
2395 int position = params->value;
2396 if (position >= 0)
2398 struct format_arg_list *empty_list = make_empty_list ();
2399 add_req_listtype_constraint (listp, position,
2400 FAT_LIST, empty_list);
2401 free_list (empty_list);
2404 break;
2407 return true;
2411 /* Handle the parameters, without a priori type information.
2412 For V params, add the constraint to the argument list.
2413 Return false and fill in *invalid_reason if the format string is
2414 invalid. */
2415 static bool
2416 nocheck_params (struct format_arg_list **listp,
2417 unsigned int paramcount, struct param *params,
2418 unsigned int directives, char **invalid_reason)
2420 (void) directives;
2421 (void) invalid_reason;
2423 for (; paramcount > 0; params++, paramcount--)
2424 if (params->type == PT_V)
2426 int position = params->value;
2427 add_req_type_constraint (listp, position, FAT_CHARACTER_INTEGER_NULL);
2430 return true;
2434 /* ======================= The format string parser ======================= */
2436 /* Parse a piece of format string, until the matching terminating format
2437 directive is encountered.
2438 format is the remainder of the format string.
2439 position is the position in this argument list, if known, or -1 if unknown.
2440 list represents the argument list constraints at the current parse point.
2441 NULL stands for a contradiction.
2442 escape represents the union of the argument list constraints at all the
2443 currently pending FORMAT-UP-AND-OUT points. NULL stands for a contradiction
2444 or an empty union.
2445 All four are updated upon valid return.
2446 *separatorp is set to true if the parse terminated due to a ~; separator,
2447 more precisely to 2 if with colon, or to 1 if without colon.
2448 spec is the global struct spec.
2449 terminator is the directive that terminates this parse.
2450 separator specifies if ~; separators are allowed.
2451 If the format string is invalid, false is returned and *invalid_reason is
2452 set to an error message explaining why. */
2453 static bool
2454 parse_upto (const char **formatp,
2455 int *positionp, struct format_arg_list **listp,
2456 struct format_arg_list **escapep, int *separatorp,
2457 struct spec *spec, char terminator, bool separator,
2458 char **invalid_reason)
2460 const char *format = *formatp;
2461 int position = *positionp;
2462 struct format_arg_list *list = *listp;
2463 struct format_arg_list *escape = *escapep;
2465 for (; *format != '\0'; )
2466 if (*format++ == '~')
2468 bool colon_p = false;
2469 bool atsign_p = false;
2470 unsigned int paramcount = 0;
2471 struct param *params = NULL;
2473 /* Count number of directives. */
2474 spec->directives++;
2476 /* Parse parameters. */
2477 for (;;)
2479 enum param_type type = PT_NIL;
2480 int value = 0;
2482 if (c_isdigit (*format))
2484 type = PT_INTEGER;
2487 value = 10 * value + (*format - '0');
2488 format++;
2490 while (c_isdigit (*format));
2492 else if (*format == '+' || *format == '-')
2494 bool negative = (*format == '-');
2495 type = PT_INTEGER;
2496 format++;
2497 if (!c_isdigit (*format))
2499 *invalid_reason =
2500 (*format == '\0'
2501 ? INVALID_UNTERMINATED_DIRECTIVE ()
2502 : xasprintf (_("In the directive number %u, '%c' is not followed by a digit."), spec->directives, format[-1]));
2503 return false;
2507 value = 10 * value + (*format - '0');
2508 format++;
2510 while (c_isdigit (*format));
2511 if (negative)
2512 value = -value;
2514 else if (*format == '\'')
2516 type = PT_CHARACTER;
2517 format++;
2518 if (*format == '\0')
2520 *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
2521 return false;
2523 format++;
2525 else if (*format == 'V' || *format == 'v')
2527 type = PT_V;
2528 format++;
2529 value = position;
2530 /* Consumes an argument. */
2531 if (position >= 0)
2532 position++;
2534 else if (*format == '#')
2536 type = PT_ARGCOUNT;
2537 format++;
2540 params =
2541 (struct param *)
2542 xrealloc (params, (paramcount + 1) * sizeof (struct param));
2543 params[paramcount].type = type;
2544 params[paramcount].value = value;
2545 paramcount++;
2547 if (*format == ',')
2548 format++;
2549 else
2550 break;
2553 /* Parse modifiers. */
2554 for (;;)
2556 if (*format == ':')
2558 format++;
2559 colon_p = true;
2561 else if (*format == '@')
2563 format++;
2564 atsign_p = true;
2566 else
2567 break;
2570 /* Parse directive. */
2571 switch (*format++)
2573 case 'A': case 'a': /* 22.3.4.1 FORMAT-ASCII */
2574 case 'S': case 's': /* 22.3.4.2 FORMAT-S-EXPRESSION */
2575 if (!check_params (&list, paramcount, params, 4, IIIC,
2576 spec->directives, invalid_reason))
2577 return false;
2578 if (position >= 0)
2579 add_req_type_constraint (&list, position++, FAT_OBJECT);
2580 break;
2582 case 'W': case 'w': /* 22.3.4.3 FORMAT-WRITE */
2583 if (!check_params (&list, paramcount, params, 0, NULL,
2584 spec->directives, invalid_reason))
2585 return false;
2586 if (position >= 0)
2587 add_req_type_constraint (&list, position++, FAT_OBJECT);
2588 break;
2590 case 'D': case 'd': /* 22.3.2.2 FORMAT-DECIMAL */
2591 case 'B': case 'b': /* 22.3.2.3 FORMAT-BINARY */
2592 case 'O': case 'o': /* 22.3.2.4 FORMAT-OCTAL */
2593 case 'X': case 'x': /* 22.3.2.5 FORMAT-HEXADECIMAL */
2594 if (!check_params (&list, paramcount, params, 4, ICCI,
2595 spec->directives, invalid_reason))
2596 return false;
2597 if (position >= 0)
2598 add_req_type_constraint (&list, position++, FAT_INTEGER);
2599 break;
2601 case 'R': case 'r': /* 22.3.2.1 FORMAT-RADIX */
2602 if (!check_params (&list, paramcount, params, 5, IICCI,
2603 spec->directives, invalid_reason))
2604 return false;
2605 if (position >= 0)
2606 add_req_type_constraint (&list, position++, FAT_INTEGER);
2607 break;
2609 case 'P': case 'p': /* 22.3.8.3 FORMAT-PLURAL */
2610 if (!check_params (&list, paramcount, params, 0, NULL,
2611 spec->directives, invalid_reason))
2612 return false;
2613 if (colon_p)
2615 /* Go back by 1 argument. */
2616 if (position > 0)
2617 position--;
2619 if (position >= 0)
2620 add_req_type_constraint (&list, position++, FAT_OBJECT);
2621 break;
2623 case 'C': case 'c': /* 22.3.1.1 FORMAT-CHARACTER */
2624 if (!check_params (&list, paramcount, params, 0, NULL,
2625 spec->directives, invalid_reason))
2626 return false;
2627 if (position >= 0)
2628 add_req_type_constraint (&list, position++, FAT_CHARACTER);
2629 break;
2631 case 'F': case 'f': /* 22.3.3.1 FORMAT-FIXED-FLOAT */
2632 if (!check_params (&list, paramcount, params, 5, IIICC,
2633 spec->directives, invalid_reason))
2634 return false;
2635 if (position >= 0)
2636 add_req_type_constraint (&list, position++, FAT_REAL);
2637 break;
2639 case 'E': case 'e': /* 22.3.3.2 FORMAT-EXPONENTIAL-FLOAT */
2640 case 'G': case 'g': /* 22.3.3.3 FORMAT-GENERAL-FLOAT */
2641 if (!check_params (&list, paramcount, params, 7, IIIICCC,
2642 spec->directives, invalid_reason))
2643 return false;
2644 if (position >= 0)
2645 add_req_type_constraint (&list, position++, FAT_REAL);
2646 break;
2648 case '$': /* 22.3.3.4 FORMAT-DOLLARS-FLOAT */
2649 if (!check_params (&list, paramcount, params, 4, IIIC,
2650 spec->directives, invalid_reason))
2651 return false;
2652 if (position >= 0)
2653 add_req_type_constraint (&list, position++, FAT_REAL);
2654 break;
2656 case '%': /* 22.3.1.2 FORMAT-TERPRI */
2657 case '&': /* 22.3.1.3 FORMAT-FRESH-LINE */
2658 case '|': /* 22.3.1.4 FORMAT-PAGE */
2659 case '~': /* 22.3.1.5 FORMAT-TILDE */
2660 case 'I': case 'i': /* 22.3.5.3 */
2661 if (!check_params (&list, paramcount, params, 1, I,
2662 spec->directives, invalid_reason))
2663 return false;
2664 break;
2666 case '\n': /* 22.3.9.3 #\Newline */
2667 case '_': /* 22.3.5.1 */
2668 if (!check_params (&list, paramcount, params, 0, NULL,
2669 spec->directives, invalid_reason))
2670 return false;
2671 break;
2673 case 'T': case 't': /* 22.3.6.1 FORMAT-TABULATE */
2674 if (!check_params (&list, paramcount, params, 2, II,
2675 spec->directives, invalid_reason))
2676 return false;
2677 break;
2679 case '*': /* 22.3.7.1 FORMAT-GOTO */
2680 if (!check_params (&list, paramcount, params, 1, I,
2681 spec->directives, invalid_reason))
2682 return false;
2684 int n; /* value of first parameter */
2685 if (paramcount == 0
2686 || (paramcount >= 1 && params[0].type == PT_NIL))
2687 n = (atsign_p ? 0 : 1);
2688 else if (paramcount >= 1 && params[0].type == PT_INTEGER)
2689 n = params[0].value;
2690 else
2692 /* Unknown argument, leads to an unknown position. */
2693 position = -1;
2694 break;
2696 if (n < 0)
2698 /* invalid argument */
2699 *invalid_reason =
2700 xasprintf (_("In the directive number %u, the argument %d is negative."), spec->directives, n);
2701 return false;
2703 if (atsign_p)
2705 /* Absolute goto. */
2706 position = n;
2708 else if (colon_p)
2710 /* Backward goto. */
2711 if (n > 0)
2713 if (position >= 0)
2715 if (position >= n)
2716 position -= n;
2717 else
2718 position = 0;
2720 else
2721 position = -1;
2724 else
2726 /* Forward goto. */
2727 if (position >= 0)
2728 position += n;
2731 break;
2733 case '?': /* 22.3.7.6 FORMAT-INDIRECTION */
2734 if (!check_params (&list, paramcount, params, 0, NULL,
2735 spec->directives, invalid_reason))
2736 return false;
2737 if (position >= 0)
2738 add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
2739 if (atsign_p)
2740 position = -1;
2741 else
2742 if (position >= 0)
2744 struct format_arg_list *sublist = make_unconstrained_list ();
2745 add_req_listtype_constraint (&list, position++,
2746 FAT_LIST, sublist);
2747 free_list (sublist);
2749 break;
2751 case '/': /* 22.3.5.4 FORMAT-CALL-USER-FUNCTION */
2752 if (!check_params (&list, paramcount, params, 0, NULL,
2753 spec->directives, invalid_reason))
2754 return false;
2755 if (position >= 0)
2756 add_req_type_constraint (&list, position++, FAT_OBJECT);
2757 while (*format != '\0' && *format != '/')
2758 format++;
2759 if (*format == '\0')
2761 *invalid_reason =
2762 xstrdup (_("The string ends in the middle of a ~/.../ directive."));
2763 return false;
2765 format++;
2766 break;
2768 case '(': /* 22.3.8.1 FORMAT-CASE-CONVERSION */
2769 if (!check_params (&list, paramcount, params, 0, NULL,
2770 spec->directives, invalid_reason))
2771 return false;
2772 *formatp = format;
2773 *positionp = position;
2774 *listp = list;
2775 *escapep = escape;
2777 if (!parse_upto (formatp, positionp, listp, escapep,
2778 NULL, spec, ')', false,
2779 invalid_reason))
2780 return false;
2782 format = *formatp;
2783 position = *positionp;
2784 list = *listp;
2785 escape = *escapep;
2786 break;
2788 case ')': /* 22.3.8.2 FORMAT-CASE-CONVERSION-END */
2789 if (terminator != ')')
2791 *invalid_reason =
2792 xasprintf (_("Found '~%c' without matching '~%c'."), ')', '(');
2793 return false;
2795 if (!check_params (&list, paramcount, params, 0, NULL,
2796 spec->directives, invalid_reason))
2797 return false;
2798 *formatp = format;
2799 *positionp = position;
2800 *listp = list;
2801 *escapep = escape;
2802 return true;
2804 case '[': /* 22.3.7.2 FORMAT-CONDITIONAL */
2805 if (atsign_p && colon_p)
2807 *invalid_reason =
2808 xasprintf (_("In the directive number %u, both the @ and the : modifiers are given."), spec->directives);
2809 return false;
2811 else if (atsign_p)
2813 struct format_arg_list *nil_list;
2814 struct format_arg_list *union_list;
2816 if (!check_params (&list, paramcount, params, 0, NULL,
2817 spec->directives, invalid_reason))
2818 return false;
2820 *formatp = format;
2821 *escapep = escape;
2823 /* First alternative: argument is NIL. */
2824 nil_list = (list != NULL ? copy_list (list) : NULL);
2825 if (position >= 0)
2827 struct format_arg_list *empty_list = make_empty_list ();
2828 add_req_listtype_constraint (&nil_list, position,
2829 FAT_LIST, empty_list);
2830 free_list (empty_list);
2833 /* Second alternative: use sub-format. */
2835 int sub_position = position;
2836 struct format_arg_list *sub_list =
2837 (list != NULL ? copy_list (list) : NULL);
2838 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2839 NULL, spec, ']', false,
2840 invalid_reason))
2841 return false;
2842 if (sub_list != NULL)
2844 if (position >= 0)
2846 if (sub_position == position + 1)
2847 /* new position is branch independent */
2848 position = position + 1;
2849 else
2850 /* new position is branch dependent */
2851 position = -1;
2854 else
2856 if (position >= 0)
2857 position = position + 1;
2859 union_list = union (nil_list, sub_list);
2862 format = *formatp;
2863 escape = *escapep;
2865 if (list != NULL)
2866 free_list (list);
2867 list = union_list;
2869 else if (colon_p)
2871 int union_position;
2872 struct format_arg_list *union_list;
2874 if (!check_params (&list, paramcount, params, 0, NULL,
2875 spec->directives, invalid_reason))
2876 return false;
2878 if (position >= 0)
2879 add_req_type_constraint (&list, position++, FAT_OBJECT);
2881 *formatp = format;
2882 *escapep = escape;
2883 union_position = -2;
2884 union_list = NULL;
2886 /* First alternative. */
2888 int sub_position = position;
2889 struct format_arg_list *sub_list =
2890 (list != NULL ? copy_list (list) : NULL);
2891 int sub_separator = 0;
2892 if (position >= 0)
2894 struct format_arg_list *empty_list = make_empty_list ();
2895 add_req_listtype_constraint (&sub_list, position - 1,
2896 FAT_LIST, empty_list);
2897 free_list (empty_list);
2899 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2900 &sub_separator, spec, ']', true,
2901 invalid_reason))
2902 return false;
2903 if (!sub_separator)
2905 *invalid_reason =
2906 xasprintf (_("In the directive number %u, '~:[' is not followed by two clauses, separated by '~;'."), spec->directives);
2907 return false;
2909 if (sub_list != NULL)
2910 union_position = sub_position;
2911 union_list = union (union_list, sub_list);
2914 /* Second alternative. */
2916 int sub_position = position;
2917 struct format_arg_list *sub_list =
2918 (list != NULL ? copy_list (list) : NULL);
2919 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2920 NULL, spec, ']', false,
2921 invalid_reason))
2922 return false;
2923 if (sub_list != NULL)
2925 if (union_position == -2)
2926 union_position = sub_position;
2927 else if (sub_position < 0
2928 || sub_position != union_position)
2929 union_position = -1;
2931 union_list = union (union_list, sub_list);
2934 format = *formatp;
2935 escape = *escapep;
2937 if (union_position != -2)
2938 position = union_position;
2939 if (list != NULL)
2940 free_list (list);
2941 list = union_list;
2943 else
2945 int arg_position;
2946 int union_position;
2947 struct format_arg_list *union_list;
2948 bool last_alternative;
2950 if (!check_params (&list, paramcount, params, 1, I,
2951 spec->directives, invalid_reason))
2952 return false;
2954 /* If there was no first parameter, an argument is consumed. */
2955 arg_position = -1;
2956 if (!(paramcount >= 1 && params[0].type != PT_NIL))
2957 if (position >= 0)
2959 arg_position = position;
2960 add_req_type_constraint (&list, position++, FAT_OBJECT);
2963 *formatp = format;
2964 *escapep = escape;
2966 union_position = -2;
2967 union_list = NULL;
2968 last_alternative = false;
2969 for (;;)
2971 /* Next alternative. */
2972 int sub_position = position;
2973 struct format_arg_list *sub_list =
2974 (list != NULL ? copy_list (list) : NULL);
2975 int sub_separator = 0;
2976 if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2977 &sub_separator, spec, ']', !last_alternative,
2978 invalid_reason))
2979 return false;
2980 /* If this alternative is chosen, the argument arg_position
2981 is an integer, namely the index of this alternative. */
2982 if (!last_alternative && arg_position >= 0)
2983 add_req_type_constraint (&sub_list, arg_position,
2984 FAT_INTEGER);
2985 if (sub_list != NULL)
2987 if (union_position == -2)
2988 union_position = sub_position;
2989 else if (sub_position < 0
2990 || sub_position != union_position)
2991 union_position = -1;
2993 union_list = union (union_list, sub_list);
2994 if (sub_separator == 2)
2995 last_alternative = true;
2996 if (!sub_separator)
2997 break;
2999 if (!last_alternative)
3001 /* An implicit default alternative. */
3002 if (union_position == -2)
3003 union_position = position;
3004 else if (position < 0 || position != union_position)
3005 union_position = -1;
3006 if (list != NULL)
3007 union_list = union (union_list, copy_list (list));
3010 format = *formatp;
3011 escape = *escapep;
3013 if (union_position != -2)
3014 position = union_position;
3015 if (list != NULL)
3016 free_list (list);
3017 list = union_list;
3019 break;
3021 case ']': /* 22.3.7.3 FORMAT-CONDITIONAL-END */
3022 if (terminator != ']')
3024 *invalid_reason =
3025 xasprintf (_("Found '~%c' without matching '~%c'."), ']', '[');
3026 return false;
3028 if (!check_params (&list, paramcount, params, 0, NULL,
3029 spec->directives, invalid_reason))
3030 return false;
3031 *formatp = format;
3032 *positionp = position;
3033 *listp = list;
3034 *escapep = escape;
3035 return true;
3037 case '{': /* 22.3.7.4 FORMAT-ITERATION */
3038 if (!check_params (&list, paramcount, params, 1, I,
3039 spec->directives, invalid_reason))
3040 return false;
3041 *formatp = format;
3043 int sub_position = 0;
3044 struct format_arg_list *sub_list = make_unconstrained_list ();
3045 struct format_arg_list *sub_escape = NULL;
3046 struct spec sub_spec;
3047 sub_spec.directives = 0;
3048 sub_spec.list = sub_list;
3049 if (!parse_upto (formatp, &sub_position, &sub_list, &sub_escape,
3050 NULL, &sub_spec, '}', false,
3051 invalid_reason))
3052 return false;
3053 spec->directives += sub_spec.directives;
3055 /* If the sub-formatstring is empty, except for the terminating
3056 ~} directive, a formatstring argument is consumed. */
3057 if (*format == '~' && sub_spec.directives == 1)
3058 if (position >= 0)
3059 add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
3061 if (colon_p)
3063 /* Each iteration uses a new sublist. */
3064 struct format_arg_list *listlist;
3066 /* ~{ catches ~^. */
3067 sub_list = union (sub_list, sub_escape);
3069 listlist = make_repeated_list_of_lists (sub_list);
3071 sub_list = listlist;
3073 else
3075 /* Each iteration's arguments are all concatenated in a
3076 single list. */
3077 struct format_arg_list *looplist;
3079 /* FIXME: This is far from correct. Test cases:
3080 abc~{~^~}
3081 abc~{~S~^~S~}
3082 abc~{~D~^~C~}
3083 abc~{~D~^~D~}
3084 abc~{~D~^~S~}
3085 abc~{~D~^~C~}~:*~{~S~^~D~}
3088 /* ~{ catches ~^. */
3089 sub_list = union (sub_list, sub_escape);
3091 if (sub_list == NULL)
3092 looplist = make_empty_list ();
3093 else
3094 if (sub_position < 0 || sub_position == 0)
3095 /* Too hard to track the possible argument types
3096 when the iteration is performed 2 times or more.
3097 So be satisfied with the constraints of executing
3098 the iteration 1 or 0 times. */
3099 looplist = make_union_with_empty_list (sub_list);
3100 else
3101 looplist = make_repeated_list (sub_list, sub_position);
3103 sub_list = looplist;
3106 if (atsign_p)
3108 /* All remaining arguments are used. */
3109 if (list != NULL && position >= 0)
3111 shift_list (sub_list, position);
3112 list = make_intersected_list (list, sub_list);
3114 position = -1;
3116 else
3118 /* The argument is a list. */
3119 if (position >= 0)
3120 add_req_listtype_constraint (&list, position++,
3121 FAT_LIST, sub_list);
3124 format = *formatp;
3125 break;
3127 case '}': /* 22.3.7.5 FORMAT-ITERATION-END */
3128 if (terminator != '}')
3130 *invalid_reason =
3131 xasprintf (_("Found '~%c' without matching '~%c'."), '}', '{');
3132 return false;
3134 if (!check_params (&list, paramcount, params, 0, NULL,
3135 spec->directives, invalid_reason))
3136 return false;
3137 *formatp = format;
3138 *positionp = position;
3139 *listp = list;
3140 *escapep = escape;
3141 return true;
3143 case '<': /* 22.3.6.2, 22.3.5.2 FORMAT-JUSTIFICATION */
3144 if (!check_params (&list, paramcount, params, 4, IIIC,
3145 spec->directives, invalid_reason))
3146 return false;
3148 struct format_arg_list *sub_escape = NULL;
3150 *formatp = format;
3151 *positionp = position;
3152 *listp = list;
3154 for (;;)
3156 int sub_separator = 0;
3157 if (!parse_upto (formatp, positionp, listp, &sub_escape,
3158 &sub_separator, spec, '>', true,
3159 invalid_reason))
3160 return false;
3161 if (!sub_separator)
3162 break;
3165 format = *formatp;
3166 position = *positionp;
3167 list = *listp;
3169 /* ~< catches ~^. */
3170 if (sub_escape != NULL)
3171 position = -1;
3172 list = union (list, sub_escape);
3174 break;
3176 case '>': /* 22.3.6.3 FORMAT-JUSTIFICATION-END */
3177 if (terminator != '>')
3179 *invalid_reason =
3180 xasprintf (_("Found '~%c' without matching '~%c'."), '>', '<');
3181 return false;
3183 if (!check_params (&list, paramcount, params, 0, NULL,
3184 spec->directives, invalid_reason))
3185 return false;
3186 *formatp = format;
3187 *positionp = position;
3188 *listp = list;
3189 *escapep = escape;
3190 return true;
3192 case '^': /* 22.3.9.2 FORMAT-UP-AND-OUT */
3193 if (!check_params (&list, paramcount, params, 3, THREE,
3194 spec->directives, invalid_reason))
3195 return false;
3196 if (position >= 0 && list != NULL && is_required (list, position))
3197 /* This ~^ can never be executed. Ignore it. */
3198 break;
3199 if (list != NULL)
3201 struct format_arg_list *this_escape = copy_list (list);
3202 if (position >= 0)
3203 this_escape = add_end_constraint (this_escape, position);
3204 escape = union (escape, this_escape);
3206 if (position >= 0)
3207 list = add_required_constraint (list, position);
3208 break;
3210 case ';': /* 22.3.9.1 FORMAT-SEPARATOR */
3211 if (!separator)
3213 *invalid_reason =
3214 xasprintf (_("In the directive number %u, '~;' is used in an invalid position."), spec->directives);
3215 return false;
3217 if (terminator == '>')
3219 if (!check_params (&list, paramcount, params, 1, I,
3220 spec->directives, invalid_reason))
3221 return false;
3223 else
3225 if (!check_params (&list, paramcount, params, 0, NULL,
3226 spec->directives, invalid_reason))
3227 return false;
3229 *formatp = format;
3230 *positionp = position;
3231 *listp = list;
3232 *escapep = escape;
3233 *separatorp = (colon_p ? 2 : 1);
3234 return true;
3236 case '!': /* FORMAT-CALL, a CLISP extension */
3237 if (!nocheck_params (&list, paramcount, params,
3238 spec->directives, invalid_reason))
3239 return false;
3240 if (position >= 0)
3242 add_req_type_constraint (&list, position++, FAT_FUNCTION);
3243 add_req_type_constraint (&list, position++, FAT_OBJECT);
3245 break;
3247 default:
3248 --format;
3249 *invalid_reason =
3250 (*format == '\0'
3251 ? INVALID_UNTERMINATED_DIRECTIVE ()
3252 : INVALID_CONVERSION_SPECIFIER (spec->directives, *format));
3253 return false;
3256 free (params);
3259 *formatp = format;
3260 *positionp = position;
3261 *listp = list;
3262 *escapep = escape;
3263 if (terminator != '\0')
3265 *invalid_reason =
3266 xasprintf (_("Found '~%c' without matching '~%c'."), terminator - 1, terminator);
3267 return false;
3269 return true;
3273 /* ============== Top level format string handling functions ============== */
3275 static void *
3276 format_parse (const char *format, bool translated, char **invalid_reason)
3278 struct spec spec;
3279 struct spec *result;
3280 int position = 0;
3281 struct format_arg_list *escape;
3283 spec.directives = 0;
3284 spec.list = make_unconstrained_list ();
3285 escape = NULL;
3287 if (!parse_upto (&format, &position, &spec.list, &escape,
3288 NULL, &spec, '\0', false,
3289 invalid_reason))
3290 /* Invalid format string. */
3291 return NULL;
3293 /* Catch ~^ here. */
3294 spec.list = union (spec.list, escape);
3296 if (spec.list == NULL)
3298 /* Contradictory argument type information. */
3299 *invalid_reason =
3300 xstrdup (_("The string refers to some argument in incompatible ways."));
3301 return NULL;
3304 /* Normalize the result. */
3305 normalize_list (spec.list);
3307 result = (struct spec *) xmalloc (sizeof (struct spec));
3308 *result = spec;
3309 return result;
3312 static void
3313 format_free (void *descr)
3315 struct spec *spec = (struct spec *) descr;
3317 free_list (spec->list);
3320 static int
3321 format_get_number_of_directives (void *descr)
3323 struct spec *spec = (struct spec *) descr;
3325 return spec->directives;
3328 static bool
3329 format_check (void *msgid_descr, void *msgstr_descr, bool equality,
3330 formatstring_error_logger_t error_logger,
3331 const char *pretty_msgstr)
3333 struct spec *spec1 = (struct spec *) msgid_descr;
3334 struct spec *spec2 = (struct spec *) msgstr_descr;
3335 bool err = false;
3337 if (equality)
3339 if (!equal_list (spec1->list, spec2->list))
3341 if (error_logger)
3342 error_logger (_("format specifications in 'msgid' and '%s' are not equivalent"),
3343 pretty_msgstr);
3344 err = true;
3347 else
3349 struct format_arg_list *intersection =
3350 make_intersected_list (copy_list (spec1->list),
3351 copy_list (spec2->list));
3353 if (!(intersection != NULL
3354 && (normalize_list (intersection),
3355 equal_list (intersection, spec2->list))))
3357 if (error_logger)
3358 error_logger (_("format specifications in '%s' are not a subset of those in 'msgid'"),
3359 pretty_msgstr);
3360 err = true;
3364 return err;
3368 struct formatstring_parser formatstring_lisp =
3370 format_parse,
3371 format_free,
3372 format_get_number_of_directives,
3373 format_check
3377 /* ============================= Testing code ============================= */
3379 #undef union
3381 #ifdef TEST
3383 /* Test program: Print the argument list specification returned by
3384 format_parse for strings read from standard input. */
3386 #include <stdio.h>
3387 #include "getline.h"
3389 static void print_list (struct format_arg_list *list);
3391 static void
3392 print_element (struct format_arg *element)
3394 switch (element->presence)
3396 case FCT_REQUIRED:
3397 break;
3398 case FCT_OPTIONAL:
3399 printf (". ");
3400 break;
3401 default:
3402 abort ();
3405 switch (element->type)
3407 case FAT_OBJECT:
3408 printf ("*");
3409 break;
3410 case FAT_CHARACTER_INTEGER_NULL:
3411 printf ("ci()");
3412 break;
3413 case FAT_CHARACTER_NULL:
3414 printf ("c()");
3415 break;
3416 case FAT_CHARACTER:
3417 printf ("c");
3418 break;
3419 case FAT_INTEGER_NULL:
3420 printf ("i()");
3421 break;
3422 case FAT_INTEGER:
3423 printf ("i");
3424 break;
3425 case FAT_REAL:
3426 printf ("r");
3427 break;
3428 case FAT_LIST:
3429 print_list (element->list);
3430 break;
3431 case FAT_FORMATSTRING:
3432 printf ("~");
3433 break;
3434 case FAT_FUNCTION:
3435 printf ("f");
3436 break;
3437 default:
3438 abort ();
3442 static void
3443 print_list (struct format_arg_list *list)
3445 unsigned int i, j;
3447 printf ("(");
3449 for (i = 0; i < list->initial.count; i++)
3450 for (j = 0; j < list->initial.element[i].repcount; j++)
3452 if (i > 0 || j > 0)
3453 printf (" ");
3454 print_element (&list->initial.element[i]);
3457 if (list->repeated.count > 0)
3459 printf (" |");
3460 for (i = 0; i < list->repeated.count; i++)
3461 for (j = 0; j < list->repeated.element[i].repcount; j++)
3463 printf (" ");
3464 print_element (&list->repeated.element[i]);
3468 printf (")");
3471 static void
3472 format_print (void *descr)
3474 struct spec *spec = (struct spec *) descr;
3476 if (spec == NULL)
3478 printf ("INVALID");
3479 return;
3482 print_list (spec->list);
3486 main ()
3488 for (;;)
3490 char *line = NULL;
3491 size_t line_size = 0;
3492 int line_len;
3493 char *invalid_reason;
3494 void *descr;
3496 line_len = getline (&line, &line_size, stdin);
3497 if (line_len < 0)
3498 break;
3499 if (line_len > 0 && line[line_len - 1] == '\n')
3500 line[--line_len] = '\0';
3502 invalid_reason = NULL;
3503 descr = format_parse (line, false, &invalid_reason);
3505 format_print (descr);
3506 printf ("\n");
3507 if (descr == NULL)
3508 printf ("%s\n", invalid_reason);
3510 free (invalid_reason);
3511 free (line);
3514 return 0;
3518 * For Emacs M-x compile
3519 * Local Variables:
3520 * 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-lisp.c ../lib/libgettextlib.la"
3521 * End:
3524 #endif /* TEST */