Coverage Report

Created: 2026-02-26 07:48

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gettext/gettext-tools/src/format-lisp.c
Line
Count
Source
1
/* Lisp format strings.
2
   Copyright (C) 2001-2026 Free Software Foundation, Inc.
3
4
   This program is free software: you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3 of the License, or
7
   (at your option) any later version.
8
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
16
17
/* Written by Bruno Haible.  */
18
19
#include <config.h>
20
21
#include <stdbool.h>
22
#include <stdlib.h>
23
24
#include "format.h"
25
#include "attribute.h"
26
#include "c-ctype.h"
27
#include "gcd.h"
28
#include "xalloc.h"
29
#include "xvasprintf.h"
30
#include "format-invalid.h"
31
#include "minmax.h"
32
#include "gettext.h"
33
34
0
#define _(str) gettext (str)
35
36
37
/* Assertion macro.  Could be defined to empty for speed.  */
38
0
#define ASSERT(expr) if (!(expr)) abort ();
39
40
41
/* Lisp format strings are described in the Common Lisp HyperSpec,
42
   chapter 22.3 "Formatted Output".  */
43
44
/* Data structure describing format string derived constraints for an
45
   argument list.  It is a recursive list structure.  Structure sharing
46
   is not allowed.  */
47
48
enum format_cdr_type
49
{
50
  FCT_REQUIRED, /* The format argument list cannot end before this argument.  */
51
  FCT_OPTIONAL  /* The format argument list may end before this argument.  */
52
};
53
54
enum format_arg_type
55
{
56
  FAT_OBJECT,                   /* Any object, type T.  */
57
  FAT_CHARACTER_INTEGER_NULL,   /* Type (OR CHARACTER INTEGER NULL).  */
58
  FAT_CHARACTER_NULL,           /* Type (OR CHARACTER NULL).  */
59
  FAT_CHARACTER,                /* Type CHARACTER.  */
60
  FAT_INTEGER_NULL,             /* Type (OR INTEGER NULL).  */
61
  FAT_INTEGER,                  /* Meant for objects of type INTEGER.  */
62
  FAT_REAL,                     /* Meant for objects of type REAL.  */
63
  FAT_LIST,                     /* Meant for proper lists.  */
64
  FAT_FORMATSTRING,             /* Format strings.  */
65
  FAT_FUNCTION                  /* Function.  */
66
};
67
68
struct format_arg
69
{
70
  size_t repcount;       /* Number of consecutive arguments this constraint
71
                            applies to.  Normally 1, but unconstrained
72
                            arguments are often repeated.  */
73
  enum format_cdr_type presence; /* Can the argument list end right before
74
                                    this argument?  */
75
  enum format_arg_type type;    /* Possible values for this argument.  */
76
  struct format_arg_list *list; /* For FAT_LIST: List elements.  */
77
};
78
79
struct segment
80
{
81
  size_t count;          /* Number of format_arg records used.  */
82
  size_t allocated;
83
  struct format_arg *element;   /* Argument constraints.  */
84
  size_t length;         /* Number of arguments represented by this segment.
85
                            This is the sum of all repcounts in the segment.  */
86
};
87
88
struct format_arg_list
89
{
90
  /* The constraints for the potentially infinite argument list are assumed
91
     to become ultimately periodic.  (Too complicated argument lists without
92
     a-priori period, like
93
            (format t "~@{~:[-~;~S~]~}" nil t 1 t 3 nil t 4)
94
     are described by a constraint that ends in a length 1 period of
95
     unconstrained arguments.)  Such a periodic sequence can be split into
96
     an initial segment and an endlessly repeated loop segment.
97
     A finite sequence is represented entirely in the initial segment; the
98
     loop segment is empty.  */
99
100
  struct segment initial;       /* Initial arguments segment.  */
101
  struct segment repeated;      /* Endlessly repeated segment.  */
102
};
103
104
struct spec
105
{
106
  size_t directives;
107
  struct format_arg_list *list;
108
};
109
110
111
/* Parameter for a directive.  */
112
enum param_type
113
{
114
  PT_NIL,       /* param not present */
115
  PT_CHARACTER, /* character */
116
  PT_INTEGER,   /* integer */
117
  PT_ARGCOUNT,  /* number of remaining arguments */
118
  PT_V          /* variable taken from argument list */
119
};
120
121
struct param
122
{
123
  enum param_type type;
124
  int value;            /* for PT_INTEGER: the value, for PT_V: the position */
125
};
126
127
128
/* Forward declaration of local functions.  */
129
0
#define union make_union
130
static void verify_list (const struct format_arg_list *list);
131
static void free_list (struct format_arg_list *list);
132
static struct format_arg_list * copy_list (const struct format_arg_list *list);
133
static bool equal_list (const struct format_arg_list *list1,
134
                        const struct format_arg_list *list2);
135
static struct format_arg_list * make_intersected_list
136
                                               (struct format_arg_list *list1,
137
                                                struct format_arg_list *list2);
138
static struct format_arg_list * make_intersection_with_empty_list
139
                                                (struct format_arg_list *list);
140
static struct format_arg_list * make_union_list
141
                                               (struct format_arg_list *list1,
142
                                                struct format_arg_list *list2);
143
144
145
/* ======================= Verify a format_arg_list ======================= */
146
147
/* Verify some invariants.  */
148
static void
149
verify_element (const struct format_arg * e)
150
0
{
151
0
  ASSERT (e->repcount > 0);
152
0
  if (e->type == FAT_LIST)
153
0
    verify_list (e->list);
154
0
}
155
156
/* Verify some invariants.  */
157
/* Memory effects: none.  */
158
static void
159
verify_list (const struct format_arg_list *list)
160
0
{
161
0
  ASSERT (list->initial.count <= list->initial.allocated);
162
0
  {
163
0
    size_t total_repcount;
164
165
0
    total_repcount = 0;
166
0
    for (size_t i = 0; i < list->initial.count; i++)
167
0
      {
168
0
        verify_element (&list->initial.element[i]);
169
0
        total_repcount += list->initial.element[i].repcount;
170
0
      }
171
172
0
    ASSERT (total_repcount == list->initial.length);
173
0
  }
174
175
0
  ASSERT (list->repeated.count <= list->repeated.allocated);
176
0
  {
177
0
    size_t total_repcount;
178
179
0
    total_repcount = 0;
180
0
    for (size_t i = 0; i < list->repeated.count; i++)
181
0
      {
182
0
        verify_element (&list->repeated.element[i]);
183
0
        total_repcount += list->repeated.element[i].repcount;
184
0
      }
185
186
0
    ASSERT (total_repcount == list->repeated.length);
187
0
  }
188
0
}
189
190
/* Assertion macro.  Could be defined to empty for speed.  */
191
0
#define VERIFY_LIST(list) verify_list (list)
192
193
194
/* ======================== Free a format_arg_list ======================== */
195
196
/* Free the data belonging to an argument list element.  */
197
static inline void
198
free_element (struct format_arg *element)
199
0
{
200
0
  if (element->type == FAT_LIST)
201
0
    free_list (element->list);
202
0
}
203
204
/* Free an argument list.  */
205
/* Memory effects: Frees list.  */
206
static void
207
free_list (struct format_arg_list *list)
208
0
{
209
0
  for (size_t i = 0; i < list->initial.count; i++)
210
0
    free_element (&list->initial.element[i]);
211
0
  if (list->initial.element != NULL)
212
0
    free (list->initial.element);
213
214
0
  for (size_t i = 0; i < list->repeated.count; i++)
215
0
    free_element (&list->repeated.element[i]);
216
0
  if (list->repeated.element != NULL)
217
0
    free (list->repeated.element);
218
0
}
219
220
221
/* ======================== Copy a format_arg_list ======================== */
222
223
/* Copy the data belonging to an argument list element.  */
224
static inline void
225
copy_element (struct format_arg *newelement,
226
              const struct format_arg *oldelement)
227
0
{
228
0
  newelement->repcount = oldelement->repcount;
229
0
  newelement->presence = oldelement->presence;
230
0
  newelement->type = oldelement->type;
231
0
  if (oldelement->type == FAT_LIST)
232
0
    newelement->list = copy_list (oldelement->list);
233
0
}
234
235
/* Copy an argument list.  */
236
/* Memory effects: Freshly allocated result.  */
237
static struct format_arg_list *
238
copy_list (const struct format_arg_list *list)
239
0
{
240
0
  VERIFY_LIST (list);
241
242
0
  struct format_arg_list *newlist = XMALLOC (struct format_arg_list);
243
244
0
  newlist->initial.count = newlist->initial.allocated = list->initial.count;
245
0
  {
246
0
    size_t length = 0;
247
0
    if (list->initial.count == 0)
248
0
      newlist->initial.element = NULL;
249
0
    else
250
0
      {
251
0
        newlist->initial.element =
252
0
          XNMALLOC (newlist->initial.allocated, struct format_arg);
253
0
        for (size_t i = 0; i < list->initial.count; i++)
254
0
          {
255
0
            copy_element (&newlist->initial.element[i],
256
0
                          &list->initial.element[i]);
257
0
            length += list->initial.element[i].repcount;
258
0
          }
259
0
      }
260
0
    ASSERT (length == list->initial.length);
261
0
    newlist->initial.length = length;
262
0
  }
263
264
0
  newlist->repeated.count = newlist->repeated.allocated = list->repeated.count;
265
0
  {
266
0
    size_t length = 0;
267
0
    if (list->repeated.count == 0)
268
0
      newlist->repeated.element = NULL;
269
0
    else
270
0
      {
271
0
        newlist->repeated.element =
272
0
          XNMALLOC (newlist->repeated.allocated, struct format_arg);
273
0
        for (size_t i = 0; i < list->repeated.count; i++)
274
0
          {
275
0
            copy_element (&newlist->repeated.element[i],
276
0
                          &list->repeated.element[i]);
277
0
            length += list->repeated.element[i].repcount;
278
0
          }
279
0
      }
280
0
    ASSERT (length == list->repeated.length);
281
0
    newlist->repeated.length = length;
282
0
  }
283
284
0
  VERIFY_LIST (newlist);
285
286
0
  return newlist;
287
0
}
288
289
290
/* ===================== Compare two format_arg_lists ===================== */
291
292
/* Tests whether two normalized argument constraints are equivalent,
293
   ignoring the repcount.  */
294
static bool
295
equal_element (const struct format_arg * e1, const struct format_arg * e2)
296
0
{
297
0
  return (e1->presence == e2->presence
298
0
          && e1->type == e2->type
299
0
          && (e1->type == FAT_LIST ? equal_list (e1->list, e2->list) : true));
300
0
}
301
302
/* Tests whether two normalized argument list constraints are equivalent.  */
303
/* Memory effects: none.  */
304
static bool
305
equal_list (const struct format_arg_list *list1,
306
            const struct format_arg_list *list2)
307
0
{
308
0
  VERIFY_LIST (list1);
309
0
  VERIFY_LIST (list2);
310
311
0
  {
312
0
    size_t n = list1->initial.count;
313
0
    if (n != list2->initial.count)
314
0
      return false;
315
0
    for (size_t i = 0; i < n; i++)
316
0
      {
317
0
        const struct format_arg * e1 = &list1->initial.element[i];
318
0
        const struct format_arg * e2 = &list2->initial.element[i];
319
320
0
        if (!(e1->repcount == e2->repcount && equal_element (e1, e2)))
321
0
          return false;
322
0
      }
323
0
  }
324
0
  {
325
0
    size_t n = list1->repeated.count;
326
0
    if (n != list2->repeated.count)
327
0
      return false;
328
0
    for (size_t i = 0; i < n; i++)
329
0
      {
330
0
        const struct format_arg * e1 = &list1->repeated.element[i];
331
0
        const struct format_arg * e2 = &list2->repeated.element[i];
332
333
0
        if (!(e1->repcount == e2->repcount && equal_element (e1, e2)))
334
0
          return false;
335
0
      }
336
0
  }
337
338
0
  return true;
339
0
}
340
341
342
/* ===================== Incremental memory allocation ===================== */
343
344
/* Ensure list->initial.allocated >= newcount.  */
345
static inline void
346
ensure_initial_alloc (struct format_arg_list *list, size_t newcount)
347
0
{
348
0
  if (newcount > list->initial.allocated)
349
0
    {
350
0
      list->initial.allocated =
351
0
        MAX (2 * list->initial.allocated + 1, newcount);
352
0
      list->initial.element =
353
0
        (struct format_arg *)
354
0
        xrealloc (list->initial.element,
355
0
                  list->initial.allocated * sizeof (struct format_arg));
356
0
    }
357
0
}
358
359
/* Ensure list->initial.allocated > list->initial.count.  */
360
static inline void
361
grow_initial_alloc (struct format_arg_list *list)
362
0
{
363
0
  if (list->initial.count >= list->initial.allocated)
364
0
    {
365
0
      list->initial.allocated =
366
0
        MAX (2 * list->initial.allocated + 1, list->initial.count + 1);
367
0
      list->initial.element =
368
0
        (struct format_arg *)
369
0
        xrealloc (list->initial.element,
370
0
                  list->initial.allocated * sizeof (struct format_arg));
371
0
    }
372
0
}
373
374
/* Ensure list->repeated.allocated >= newcount.  */
375
static inline void
376
ensure_repeated_alloc (struct format_arg_list *list, size_t newcount)
377
0
{
378
0
  if (newcount > list->repeated.allocated)
379
0
    {
380
0
      list->repeated.allocated =
381
0
        MAX (2 * list->repeated.allocated + 1, newcount);
382
0
      list->repeated.element =
383
0
        (struct format_arg *)
384
0
        xrealloc (list->repeated.element,
385
0
                  list->repeated.allocated * sizeof (struct format_arg));
386
0
    }
387
0
}
388
389
/* Ensure list->repeated.allocated > list->repeated.count.  */
390
static inline void
391
grow_repeated_alloc (struct format_arg_list *list)
392
0
{
393
0
  if (list->repeated.count >= list->repeated.allocated)
394
0
    {
395
0
      list->repeated.allocated =
396
0
        MAX (2 * list->repeated.allocated + 1, list->repeated.count + 1);
397
0
      list->repeated.element =
398
0
        (struct format_arg *)
399
0
        xrealloc (list->repeated.element,
400
0
                  list->repeated.allocated * sizeof (struct format_arg));
401
0
    }
402
0
}
403
404
405
/* ====================== Normalize a format_arg_list ====================== */
406
407
/* Normalize an argument list constraint, assuming all sublists are already
408
   normalized.  */
409
/* Memory effects: Destructively modifies list.  */
410
static void
411
normalize_outermost_list (struct format_arg_list *list)
412
0
{
413
  /* Step 1: Combine adjacent elements.
414
     Copy from i to j, keeping 0 <= j <= i.  */
415
0
  {
416
0
    size_t n = list->initial.count;
417
0
    size_t i, j;
418
0
    for (i = j = 0; i < n; i++)
419
0
      if (j > 0
420
0
          && equal_element (&list->initial.element[i],
421
0
                            &list->initial.element[j-1]))
422
0
        {
423
0
          list->initial.element[j-1].repcount +=
424
0
            list->initial.element[i].repcount;
425
0
          free_element (&list->initial.element[i]);
426
0
        }
427
0
      else
428
0
        {
429
0
          if (j < i)
430
0
            list->initial.element[j] = list->initial.element[i];
431
0
          j++;
432
0
        }
433
0
    list->initial.count = j;
434
0
  }
435
0
  {
436
0
    size_t n = list->repeated.count;
437
0
    size_t i, j;
438
0
    for (i = j = 0; i < n; i++)
439
0
      if (j > 0
440
0
          && equal_element (&list->repeated.element[i],
441
0
                            &list->repeated.element[j-1]))
442
0
        {
443
0
          list->repeated.element[j-1].repcount +=
444
0
            list->repeated.element[i].repcount;
445
0
          free_element (&list->repeated.element[i]);
446
0
        }
447
0
      else
448
0
        {
449
0
          if (j < i)
450
0
            list->repeated.element[j] = list->repeated.element[i];
451
0
          j++;
452
0
        }
453
0
    list->repeated.count = j;
454
0
  }
455
456
  /* Nothing more to be done if the loop segment is empty.  */
457
0
  if (list->repeated.count > 0)
458
0
    {
459
0
      size_t repcount0_extra;
460
461
      /* Step 2: Reduce the loop period.  */
462
0
      size_t n = list->repeated.count;
463
0
      repcount0_extra = 0;
464
0
      if (n > 1
465
0
          && equal_element (&list->repeated.element[0],
466
0
                            &list->repeated.element[n-1]))
467
0
        {
468
0
          repcount0_extra = list->repeated.element[n-1].repcount;
469
0
          n--;
470
0
        }
471
      /* Proceed as if the loop period were n, with
472
         list->repeated.element[0].repcount incremented by repcount0_extra.  */
473
0
      for (size_t m = 2; m <= n / 2; m++)
474
0
        if ((n % m) == 0)
475
0
          {
476
            /* m is a divisor of n.  Try to reduce the loop period to n.  */
477
0
            bool ok = true;
478
479
0
            for (size_t i = 0; i < n - m; i++)
480
0
              if (!((list->repeated.element[i].repcount
481
0
                     + (i == 0 ? repcount0_extra : 0)
482
0
                     == list->repeated.element[i+m].repcount)
483
0
                    && equal_element (&list->repeated.element[i],
484
0
                                      &list->repeated.element[i+m])))
485
0
                {
486
0
                  ok = false;
487
0
                  break;
488
0
                }
489
0
            if (ok)
490
0
              {
491
0
                for (size_t i = m; i < n; i++)
492
0
                  free_element (&list->repeated.element[i]);
493
0
                if (n < list->repeated.count)
494
0
                  list->repeated.element[m] = list->repeated.element[n];
495
0
                list->repeated.count = list->repeated.count - n + m;
496
0
                list->repeated.length /= n / m;
497
0
                break;
498
0
              }
499
0
          }
500
0
      if (list->repeated.count == 1)
501
0
        {
502
          /* The loop has period 1.  Normalize the repcount.  */
503
0
          list->repeated.element[0].repcount = 1;
504
0
          list->repeated.length = 1;
505
0
        }
506
507
      /* Step 3: Roll as much as possible of the initial segment's tail
508
         into the loop.  */
509
0
      if (list->repeated.count == 1)
510
0
        {
511
0
          if (list->initial.count > 0
512
0
              && equal_element (&list->initial.element[list->initial.count-1],
513
0
                                &list->repeated.element[0]))
514
0
            {
515
              /* Roll the last element of the initial segment into the loop.
516
                 Its repcount is irrelevant.  The second-to-last element is
517
                 certainly different and doesn't need to be considered.  */
518
0
              list->initial.length -=
519
0
                list->initial.element[list->initial.count-1].repcount;
520
0
              free_element (&list->initial.element[list->initial.count-1]);
521
0
              list->initial.count--;
522
0
            }
523
0
        }
524
0
      else
525
0
        {
526
0
          while (list->initial.count > 0
527
0
                 && equal_element (&list->initial.element[list->initial.count-1],
528
0
                                   &list->repeated.element[list->repeated.count-1]))
529
0
            {
530
0
              size_t moved_repcount =
531
0
                MIN (list->initial.element[list->initial.count-1].repcount,
532
0
                     list->repeated.element[list->repeated.count-1].repcount);
533
534
              /* Add the element at the start of list->repeated.  */
535
0
              if (equal_element (&list->repeated.element[0],
536
0
                                 &list->repeated.element[list->repeated.count-1]))
537
0
                list->repeated.element[0].repcount += moved_repcount;
538
0
              else
539
0
                {
540
0
                  size_t newcount = list->repeated.count + 1;
541
0
                  ensure_repeated_alloc (list, newcount);
542
0
                  for (size_t i = newcount - 1; i > 0; i--)
543
0
                    list->repeated.element[i] = list->repeated.element[i-1];
544
0
                  list->repeated.count = newcount;
545
0
                  copy_element (&list->repeated.element[0],
546
0
                                &list->repeated.element[list->repeated.count-1]);
547
0
                  list->repeated.element[0].repcount = moved_repcount;
548
0
                }
549
550
              /* Remove the element from the end of list->repeated.  */
551
0
              list->repeated.element[list->repeated.count-1].repcount -=
552
0
                moved_repcount;
553
0
              if (list->repeated.element[list->repeated.count-1].repcount == 0)
554
0
                {
555
0
                  free_element (&list->repeated.element[list->repeated.count-1]);
556
0
                  list->repeated.count--;
557
0
                }
558
559
              /* Remove the element from the end of list->initial.  */
560
0
              list->initial.element[list->initial.count-1].repcount -=
561
0
                moved_repcount;
562
0
              if (list->initial.element[list->initial.count-1].repcount == 0)
563
0
                {
564
0
                  free_element (&list->initial.element[list->initial.count-1]);
565
0
                  list->initial.count--;
566
0
                }
567
0
              list->initial.length -= moved_repcount;
568
0
            }
569
0
        }
570
0
    }
571
0
}
572
573
/* Normalize an argument list constraint.  */
574
/* Memory effects: Destructively modifies list.  */
575
static void
576
normalize_list (struct format_arg_list *list)
577
0
{
578
0
  VERIFY_LIST (list);
579
580
  /* First normalize all elements, recursively.  */
581
0
  {
582
0
    size_t n = list->initial.count;
583
0
    for (size_t i = 0; i < n; i++)
584
0
      if (list->initial.element[i].type == FAT_LIST)
585
0
        normalize_list (list->initial.element[i].list);
586
0
  }
587
0
  {
588
0
    size_t n = list->repeated.count;
589
0
    for (size_t i = 0; i < n; i++)
590
0
      if (list->repeated.element[i].type == FAT_LIST)
591
0
        normalize_list (list->repeated.element[i].list);
592
0
  }
593
594
  /* Then normalize the top level list.  */
595
0
  normalize_outermost_list (list);
596
597
0
  VERIFY_LIST (list);
598
0
}
599
600
601
/* ===================== Unconstrained and empty lists ===================== */
602
603
/* It's easier to allocate these on demand, than to be careful not to
604
   accidentally modify statically allocated lists.  */
605
606
607
/* Create an unconstrained argument list.  */
608
/* Memory effects: Freshly allocated result.  */
609
static struct format_arg_list *
610
make_unconstrained_list ()
611
0
{
612
0
  struct format_arg_list *list = XMALLOC (struct format_arg_list);
613
0
  list->initial.count = 0;
614
0
  list->initial.allocated = 0;
615
0
  list->initial.element = NULL;
616
0
  list->initial.length = 0;
617
0
  list->repeated.count = 1;
618
0
  list->repeated.allocated = 1;
619
0
  list->repeated.element = XNMALLOC (1, struct format_arg);
620
0
  list->repeated.element[0].repcount = 1;
621
0
  list->repeated.element[0].presence = FCT_OPTIONAL;
622
0
  list->repeated.element[0].type = FAT_OBJECT;
623
0
  list->repeated.length = 1;
624
625
0
  VERIFY_LIST (list);
626
627
0
  return list;
628
0
}
629
630
631
/* Create an empty argument list.  */
632
/* Memory effects: Freshly allocated result.  */
633
static struct format_arg_list *
634
make_empty_list ()
635
0
{
636
0
  struct format_arg_list *list = XMALLOC (struct format_arg_list);
637
0
  list->initial.count = 0;
638
0
  list->initial.allocated = 0;
639
0
  list->initial.element = NULL;
640
0
  list->initial.length = 0;
641
0
  list->repeated.count = 0;
642
0
  list->repeated.allocated = 0;
643
0
  list->repeated.element = NULL;
644
0
  list->repeated.length = 0;
645
646
0
  VERIFY_LIST (list);
647
648
0
  return list;
649
0
}
650
651
652
/* Test for an empty list.  */
653
/* Memory effects: none.  */
654
static bool
655
is_empty_list (const struct format_arg_list *list)
656
0
{
657
0
  return (list->initial.count == 0 && list->repeated.count == 0);
658
0
}
659
660
661
/* ======================== format_arg_list surgery ======================== */
662
663
/* Unfold list->repeated m times, where m >= 1.
664
   Assumes list->repeated.count > 0.  */
665
/* Memory effects: list is destructively modified.  */
666
static void
667
unfold_loop (struct format_arg_list *list, size_t m)
668
0
{
669
0
  if (m > 1)
670
0
    {
671
0
      size_t newcount = list->repeated.count * m;
672
0
      ensure_repeated_alloc (list, newcount);
673
0
      size_t i = list->repeated.count;
674
0
      for (size_t k = 1; k < m; k++)
675
0
        for (size_t j = 0; j < list->repeated.count; j++)
676
0
          {
677
0
            copy_element (&list->repeated.element[i], &list->repeated.element[j]);
678
0
            i++;
679
0
          }
680
0
      list->repeated.count = newcount;
681
0
      list->repeated.length = list->repeated.length * m;
682
0
    }
683
0
}
684
685
/* Ensure list->initial.length := m, where m >= list->initial.length.
686
   Assumes list->repeated.count > 0.  */
687
/* Memory effects: list is destructively modified.  */
688
static void
689
rotate_loop (struct format_arg_list *list, size_t m)
690
0
{
691
0
  if (m == list->initial.length)
692
0
    return;
693
694
0
  if (list->repeated.count == 1)
695
0
    {
696
      /* Instead of multiple copies of list->repeated.element[0], a single
697
         copy with higher repcount is appended to list->initial.  */
698
0
      size_t newcount = list->initial.count + 1;
699
0
      ensure_initial_alloc (list, newcount);
700
0
      size_t i = list->initial.count;
701
0
      copy_element (&list->initial.element[i], &list->repeated.element[0]);
702
0
      list->initial.element[i].repcount = m - list->initial.length;
703
0
      list->initial.count = newcount;
704
0
      list->initial.length = m;
705
0
    }
706
0
  else
707
0
    {
708
0
      size_t n = list->repeated.length;
709
710
      /* Write m = list->initial.length + q * n + r with 0 <= r < n.  */
711
0
      size_t q = (m - list->initial.length) / n;
712
0
      size_t r = (m - list->initial.length) % n;
713
714
      /* Determine how many entries of list->repeated are needed for
715
         length r.  */
716
0
      size_t s;
717
0
      size_t t;
718
719
0
      for (t = r, s = 0;
720
0
           s < list->repeated.count && t >= list->repeated.element[s].repcount;
721
0
           t -= list->repeated.element[s].repcount, s++)
722
0
        ;
723
724
      /* s must be < list->repeated.count, otherwise r would have been >= n.  */
725
0
      ASSERT (s < list->repeated.count);
726
727
      /* So we need to add to list->initial:
728
         q full copies of list->repeated,
729
         plus the s first elements of list->repeated,
730
         plus, if t > 0, a splitoff of list->repeated.element[s].  */
731
0
      {
732
0
        size_t i = list->initial.count;
733
0
        size_t newcount = i + q * list->repeated.count + s + (t > 0 ? 1 : 0);
734
0
        ensure_initial_alloc (list, newcount);
735
0
        for (size_t k = 0; k < q; k++)
736
0
          for (size_t j = 0; j < list->repeated.count; j++)
737
0
            {
738
0
              copy_element (&list->initial.element[i], &list->repeated.element[j]);
739
0
              i++;
740
0
            }
741
0
        for (size_t j = 0; j < s; j++)
742
0
          {
743
0
            copy_element (&list->initial.element[i], &list->repeated.element[j]);
744
0
            i++;
745
0
          }
746
0
        if (t > 0)
747
0
          {
748
0
            copy_element (&list->initial.element[i], &list->repeated.element[s]);
749
0
            list->initial.element[i].repcount = t;
750
0
            i++;
751
0
          }
752
0
        ASSERT (i == newcount);
753
0
        list->initial.count = newcount;
754
        /* The new length of the initial segment is
755
           = list->initial.length
756
             + q * list->repeated.length
757
             + list->repeated[0..s-1].repcount + t
758
           = list->initial.length + q * n + r
759
           = m.
760
         */
761
0
        list->initial.length = m;
762
0
      }
763
764
      /* And rotate list->repeated.  */
765
0
      if (r > 0)
766
0
        {
767
0
          size_t oldcount = list->repeated.count;
768
0
          size_t newcount = list->repeated.count + (t > 0 ? 1 : 0);
769
0
          struct format_arg *newelement = XNMALLOC (newcount, struct format_arg);
770
0
          size_t i = 0;
771
0
          for (size_t j = s; j < oldcount; j++)
772
0
            {
773
0
              newelement[i] = list->repeated.element[j];
774
0
              i++;
775
0
            }
776
0
          for (size_t j = 0; j < s; j++)
777
0
            {
778
0
              newelement[i] = list->repeated.element[j];
779
0
              i++;
780
0
            }
781
0
          if (t > 0)
782
0
            {
783
0
              copy_element (&newelement[oldcount], &newelement[0]);
784
0
              newelement[0].repcount -= t;
785
0
              newelement[oldcount].repcount = t;
786
0
            }
787
0
          free (list->repeated.element);
788
0
          list->repeated.element = newelement;
789
0
          list->repeated.count = newcount;
790
0
        }
791
0
    }
792
0
}
793
794
795
/* Ensure index n in the initial segment falls on a split between elements,
796
   i.e. if 0 < n < list->initial.length, then n-1 and n are covered by two
797
   different adjacent elements.  */
798
/* Memory effects: list is destructively modified.  */
799
static size_t
800
initial_splitelement (struct format_arg_list *list, size_t n)
801
0
{
802
0
  VERIFY_LIST (list);
803
804
0
  if (n > list->initial.length)
805
0
    {
806
0
      ASSERT (list->repeated.count > 0);
807
0
      rotate_loop (list, n);
808
0
      ASSERT (n <= list->initial.length);
809
0
    }
810
811
  /* Determine how many entries of list->initial need to be skipped.  */
812
0
  size_t s;
813
0
  size_t t;
814
0
  for (t = n, s = 0;
815
0
       s < list->initial.count && t >= list->initial.element[s].repcount;
816
0
       t -= list->initial.element[s].repcount, s++)
817
0
    ;
818
819
0
  if (t == 0)
820
0
    return s;
821
822
0
  ASSERT (s < list->initial.count);
823
824
  /* Split the entry into two entries.  */
825
0
  size_t oldrepcount = list->initial.element[s].repcount;
826
0
  size_t newcount = list->initial.count + 1;
827
0
  ensure_initial_alloc (list, newcount);
828
0
  for (size_t i = list->initial.count - 1; i > s; i--)
829
0
    list->initial.element[i+1] = list->initial.element[i];
830
0
  copy_element (&list->initial.element[s+1], &list->initial.element[s]);
831
0
  list->initial.element[s].repcount = t;
832
0
  list->initial.element[s+1].repcount = oldrepcount - t;
833
0
  list->initial.count = newcount;
834
835
0
  VERIFY_LIST (list);
836
837
0
  return s+1;
838
0
}
839
840
841
/* Ensure index n in the initial segment is not shared.  Return its index.  */
842
/* Memory effects: list is destructively modified.  */
843
static size_t
844
initial_unshare (struct format_arg_list *list, size_t n)
845
0
{
846
  /* This does the same side effects as
847
       initial_splitelement (list, n);
848
       initial_splitelement (list, n + 1);
849
   */
850
851
0
  VERIFY_LIST (list);
852
853
0
  if (n >= list->initial.length)
854
0
    {
855
0
      ASSERT (list->repeated.count > 0);
856
0
      rotate_loop (list, n + 1);
857
0
      ASSERT (n < list->initial.length);
858
0
    }
859
860
  /* Determine how many entries of list->initial need to be skipped.  */
861
0
  size_t s;
862
0
  size_t t;
863
0
  for (t = n, s = 0;
864
0
       s < list->initial.count && t >= list->initial.element[s].repcount;
865
0
       t -= list->initial.element[s].repcount, s++)
866
0
    ;
867
868
  /* s must be < list->initial.count.  */
869
0
  ASSERT (s < list->initial.count);
870
871
0
  if (list->initial.element[s].repcount > 1)
872
0
    {
873
      /* Split the entry into at most three entries: for indices < n,
874
         for index n, and for indices > n.  */
875
0
      size_t oldrepcount = list->initial.element[s].repcount;
876
0
      size_t newcount =
877
0
        list->initial.count + (t == 0 || t == oldrepcount - 1 ? 1 : 2);
878
0
      ensure_initial_alloc (list, newcount);
879
0
      if (t == 0 || t == oldrepcount - 1)
880
0
        {
881
0
          for (size_t i = list->initial.count - 1; i > s; i--)
882
0
            list->initial.element[i+1] = list->initial.element[i];
883
0
          copy_element (&list->initial.element[s+1], &list->initial.element[s]);
884
0
          if (t == 0)
885
0
            {
886
0
              list->initial.element[s].repcount = 1;
887
0
              list->initial.element[s+1].repcount = oldrepcount - 1;
888
0
            }
889
0
          else
890
0
            {
891
0
              list->initial.element[s].repcount = oldrepcount - 1;
892
0
              list->initial.element[s+1].repcount = 1;
893
0
            }
894
0
        }
895
0
      else
896
0
        {
897
0
          for (size_t i = list->initial.count - 1; i > s; i--)
898
0
            list->initial.element[i+2] = list->initial.element[i];
899
0
          copy_element (&list->initial.element[s+2], &list->initial.element[s]);
900
0
          copy_element (&list->initial.element[s+1], &list->initial.element[s]);
901
0
          list->initial.element[s].repcount = t;
902
0
          list->initial.element[s+1].repcount = 1;
903
0
          list->initial.element[s+2].repcount = oldrepcount - 1 - t;
904
0
        }
905
0
      list->initial.count = newcount;
906
0
      if (t > 0)
907
0
        s++;
908
0
    }
909
910
  /* Now the entry for index n has repcount 1.  */
911
0
  ASSERT (list->initial.element[s].repcount == 1);
912
913
0
  VERIFY_LIST (list);
914
915
0
  return s;
916
0
}
917
918
919
/* Add n unconstrained elements at the front of the list.  */
920
/* Memory effects: list is destructively modified.  */
921
static void
922
shift_list (struct format_arg_list *list, size_t n)
923
0
{
924
0
  VERIFY_LIST (list);
925
926
0
  if (n > 0)
927
0
    {
928
0
      grow_initial_alloc (list);
929
0
      for (size_t i = list->initial.count; i > 0; i--)
930
0
        list->initial.element[i] = list->initial.element[i-1];
931
0
      list->initial.element[0].repcount = n;
932
0
      list->initial.element[0].presence = FCT_REQUIRED;
933
0
      list->initial.element[0].type = FAT_OBJECT;
934
0
      list->initial.count++;
935
0
      list->initial.length += n;
936
937
0
      normalize_outermost_list (list);
938
0
    }
939
940
0
  VERIFY_LIST (list);
941
0
}
942
943
944
/* ================= Intersection of two format_arg_lists ================= */
945
946
/* Create the intersection (i.e. combined constraints) of two argument
947
   constraints.  Return false if the intersection is empty, i.e. if the
948
   two constraints give a contradiction.  */
949
/* Memory effects: Freshly allocated element's sublist.  */
950
static bool
951
make_intersected_element (struct format_arg *re,
952
                          const struct format_arg * e1,
953
                          const struct format_arg * e2)
954
0
{
955
  /* Intersect the cdr types.  */
956
0
  if (e1->presence == FCT_REQUIRED || e2->presence == FCT_REQUIRED)
957
0
    re->presence = FCT_REQUIRED;
958
0
  else
959
0
    re->presence = FCT_OPTIONAL;
960
961
  /* Intersect the arg types.  */
962
0
  if (e1->type == FAT_OBJECT)
963
0
    {
964
0
      re->type = e2->type;
965
0
      if (re->type == FAT_LIST)
966
0
        re->list = copy_list (e2->list);
967
0
    }
968
0
  else if (e2->type == FAT_OBJECT)
969
0
    {
970
0
      re->type = e1->type;
971
0
      if (re->type == FAT_LIST)
972
0
        re->list = copy_list (e1->list);
973
0
    }
974
0
  else if (e1->type == FAT_LIST
975
0
           && (e2->type == FAT_CHARACTER_INTEGER_NULL
976
0
               || e2->type == FAT_CHARACTER_NULL
977
0
               || e2->type == FAT_INTEGER_NULL))
978
0
    {
979
0
      re->type = e1->type;
980
0
      re->list = make_intersection_with_empty_list (e1->list);
981
0
      if (re->list == NULL)
982
0
        return false;
983
0
    }
984
0
  else if (e2->type == FAT_LIST
985
0
           && (e1->type == FAT_CHARACTER_INTEGER_NULL
986
0
               || e1->type == FAT_CHARACTER_NULL
987
0
               || e1->type == FAT_INTEGER_NULL))
988
0
    {
989
0
      re->type = e2->type;
990
0
      re->list = make_intersection_with_empty_list (e2->list);
991
0
      if (re->list == NULL)
992
0
        return false;
993
0
    }
994
0
  else if (e1->type == FAT_CHARACTER_INTEGER_NULL
995
0
           && (e2->type == FAT_CHARACTER_NULL || e2->type == FAT_CHARACTER
996
0
               || e2->type == FAT_INTEGER_NULL || e2->type == FAT_INTEGER))
997
0
    {
998
0
      re->type = e2->type;
999
0
    }
1000
0
  else if (e2->type == FAT_CHARACTER_INTEGER_NULL
1001
0
           && (e1->type == FAT_CHARACTER_NULL || e1->type == FAT_CHARACTER
1002
0
               || e1->type == FAT_INTEGER_NULL || e1->type == FAT_INTEGER))
1003
0
    {
1004
0
      re->type = e1->type;
1005
0
    }
1006
0
  else if (e1->type == FAT_CHARACTER_NULL && e2->type == FAT_CHARACTER)
1007
0
    {
1008
0
      re->type = e2->type;
1009
0
    }
1010
0
  else if (e2->type == FAT_CHARACTER_NULL && e1->type == FAT_CHARACTER)
1011
0
    {
1012
0
      re->type = e1->type;
1013
0
    }
1014
0
  else if (e1->type == FAT_INTEGER_NULL && e2->type == FAT_INTEGER)
1015
0
    {
1016
0
      re->type = e2->type;
1017
0
    }
1018
0
  else if (e2->type == FAT_INTEGER_NULL && e1->type == FAT_INTEGER)
1019
0
    {
1020
0
      re->type = e1->type;
1021
0
    }
1022
0
  else if (e1->type == FAT_REAL && e2->type == FAT_INTEGER)
1023
0
    {
1024
0
      re->type = e2->type;
1025
0
    }
1026
0
  else if (e2->type == FAT_REAL && e1->type == FAT_INTEGER)
1027
0
    {
1028
0
      re->type = e1->type;
1029
0
    }
1030
0
  else if (e1->type == e2->type)
1031
0
    {
1032
0
      re->type = e1->type;
1033
0
      if (re->type == FAT_LIST)
1034
0
        {
1035
0
          re->list = make_intersected_list (copy_list (e1->list),
1036
0
                                            copy_list (e2->list));
1037
0
          if (re->list == NULL)
1038
0
            return false;
1039
0
        }
1040
0
    }
1041
0
  else
1042
    /* Each of FAT_CHARACTER, FAT_INTEGER, FAT_LIST, FAT_FORMATSTRING,
1043
       FAT_FUNCTION matches only itself.  Contradiction.  */
1044
0
    return false;
1045
1046
0
  return true;
1047
0
}
1048
1049
/* Append list->repeated to list->initial, and clear list->repeated.  */
1050
/* Memory effects: list is destructively modified.  */
1051
static void
1052
append_repeated_to_initial (struct format_arg_list *list)
1053
0
{
1054
0
  if (list->repeated.count > 0)
1055
0
    {
1056
      /* Move list->repeated over to list->initial.  */
1057
0
      size_t newcount = list->initial.count + list->repeated.count;
1058
0
      ensure_initial_alloc (list, newcount);
1059
0
      size_t i = list->initial.count;
1060
0
      for (size_t j = 0; j < list->repeated.count; j++)
1061
0
        {
1062
0
          list->initial.element[i] = list->repeated.element[j];
1063
0
          i++;
1064
0
        }
1065
0
      list->initial.count = newcount;
1066
0
      list->initial.length = list->initial.length + list->repeated.length;
1067
0
      free (list->repeated.element);
1068
0
      list->repeated.element = NULL;
1069
0
      list->repeated.allocated = 0;
1070
0
      list->repeated.count = 0;
1071
0
      list->repeated.length = 0;
1072
0
    }
1073
0
}
1074
1075
/* Handle a contradiction during building of a format_arg_list.
1076
   The list consists only of an initial segment.  The repeated segment is
1077
   empty.  This function searches the last FCT_OPTIONAL and cuts off the
1078
   list at this point, or - if none is found - returns NULL.  */
1079
/* Memory effects: list is destructively modified.  If NULL is returned,
1080
   list is freed.  */
1081
static struct format_arg_list *
1082
backtrack_in_initial (struct format_arg_list *list)
1083
0
{
1084
0
  ASSERT (list->repeated.count == 0);
1085
1086
0
  while (list->initial.count > 0)
1087
0
    {
1088
0
      size_t i = list->initial.count - 1;
1089
0
      if (list->initial.element[i].presence == FCT_REQUIRED)
1090
0
        {
1091
          /* Throw away this element.  */
1092
0
          list->initial.length -= list->initial.element[i].repcount;
1093
0
          free_element (&list->initial.element[i]);
1094
0
          list->initial.count = i;
1095
0
        }
1096
0
      else /* list->initial.element[i].presence == FCT_OPTIONAL */
1097
0
        {
1098
          /* The list must end here.  */
1099
0
          list->initial.length--;
1100
0
          if (list->initial.element[i].repcount > 1)
1101
0
            list->initial.element[i].repcount--;
1102
0
          else
1103
0
            {
1104
0
              free_element (&list->initial.element[i]);
1105
0
              list->initial.count = i;
1106
0
            }
1107
0
          VERIFY_LIST (list);
1108
0
          return list;
1109
0
        }
1110
0
    }
1111
1112
0
  free_list (list);
1113
0
  return NULL;
1114
0
}
1115
1116
/* Create the intersection (i.e. combined constraints) of two argument list
1117
   constraints.  Free both argument lists when done.  Return NULL if the
1118
   intersection is empty, i.e. if the two constraints give a contradiction.  */
1119
/* Memory effects: list1 and list2 are freed.  The result, if non-NULL, is
1120
   freshly allocated.  */
1121
static struct format_arg_list *
1122
make_intersected_list (struct format_arg_list *list1,
1123
                       struct format_arg_list *list2)
1124
0
{
1125
0
  struct format_arg_list *result;
1126
1127
0
  VERIFY_LIST (list1);
1128
0
  VERIFY_LIST (list2);
1129
1130
0
  if (list1->repeated.length > 0 && list2->repeated.length > 0)
1131
    /* Step 1: Ensure list1->repeated.length == list2->repeated.length.  */
1132
0
    {
1133
0
      size_t n1 = list1->repeated.length;
1134
0
      size_t n2 = list2->repeated.length;
1135
0
      size_t g = gcd (n1, n2);
1136
0
      size_t m1 = n2 / g; /* = lcm(n1,n2) / n1 */
1137
0
      size_t m2 = n1 / g; /* = lcm(n1,n2) / n2 */
1138
1139
0
      unfold_loop (list1, m1);
1140
0
      unfold_loop (list2, m2);
1141
      /* Now list1->repeated.length = list2->repeated.length = lcm(n1,n2).  */
1142
0
    }
1143
1144
0
  if (list1->repeated.length > 0 || list2->repeated.length > 0)
1145
    /* Step 2: Ensure the initial segment of the result can be computed
1146
       from the initial segments of list1 and list2.  If both have a
1147
       repeated segment, this means to ensure
1148
       list1->initial.length == list2->initial.length.  */
1149
0
    {
1150
0
      size_t m = MAX (list1->initial.length, list2->initial.length);
1151
1152
0
      if (list1->repeated.length > 0)
1153
0
        rotate_loop (list1, m);
1154
0
      if (list2->repeated.length > 0)
1155
0
        rotate_loop (list2, m);
1156
0
    }
1157
1158
0
  if (list1->repeated.length > 0 && list2->repeated.length > 0)
1159
0
    {
1160
0
      ASSERT (list1->initial.length == list2->initial.length);
1161
0
      ASSERT (list1->repeated.length == list2->repeated.length);
1162
0
    }
1163
1164
  /* Step 3: Allocate the result.  */
1165
0
  result = XMALLOC (struct format_arg_list);
1166
0
  result->initial.count = 0;
1167
0
  result->initial.allocated = 0;
1168
0
  result->initial.element = NULL;
1169
0
  result->initial.length = 0;
1170
0
  result->repeated.count = 0;
1171
0
  result->repeated.allocated = 0;
1172
0
  result->repeated.element = NULL;
1173
0
  result->repeated.length = 0;
1174
1175
  /* Step 4: Elementwise intersection of list1->initial, list2->initial.  */
1176
0
  {
1177
0
    struct format_arg *e1 = list1->initial.element;
1178
0
    size_t c1 = list1->initial.count;
1179
0
    struct format_arg *e2 = list2->initial.element;
1180
0
    size_t c2 = list2->initial.count;
1181
0
    while (c1 > 0 && c2 > 0)
1182
0
      {
1183
        /* Ensure room in result->initial.  */
1184
0
        grow_initial_alloc (result);
1185
0
        struct format_arg *re = &result->initial.element[result->initial.count];
1186
0
        re->repcount = MIN (e1->repcount, e2->repcount);
1187
1188
        /* Intersect the argument types.  */
1189
0
        if (!make_intersected_element (re, e1, e2))
1190
0
          {
1191
            /* If re->presence == FCT_OPTIONAL, the result list ends here.  */
1192
0
            if (re->presence == FCT_REQUIRED)
1193
              /* Contradiction.  Backtrack.  */
1194
0
              result = backtrack_in_initial (result);
1195
0
            goto done;
1196
0
          }
1197
1198
0
        result->initial.count++;
1199
0
        result->initial.length += re->repcount;
1200
1201
0
        e1->repcount -= re->repcount;
1202
0
        if (e1->repcount == 0)
1203
0
          {
1204
0
            e1++;
1205
0
            c1--;
1206
0
          }
1207
0
        e2->repcount -= re->repcount;
1208
0
        if (e2->repcount == 0)
1209
0
          {
1210
0
            e2++;
1211
0
            c2--;
1212
0
          }
1213
0
      }
1214
1215
0
    if (list1->repeated.count == 0 && list2->repeated.count == 0)
1216
0
      {
1217
        /* Intersecting two finite lists.  */
1218
0
        if (c1 > 0)
1219
0
          {
1220
            /* list1 longer than list2.  */
1221
0
            if (e1->presence == FCT_REQUIRED)
1222
              /* Contradiction.  Backtrack.  */
1223
0
              result = backtrack_in_initial (result);
1224
0
          }
1225
0
        else if (c2 > 0)
1226
0
          {
1227
            /* list2 longer than list1.  */
1228
0
            if (e2->presence == FCT_REQUIRED)
1229
              /* Contradiction.  Backtrack.  */
1230
0
              result = backtrack_in_initial (result);
1231
0
          }
1232
0
        goto done;
1233
0
      }
1234
0
    else if (list1->repeated.count == 0)
1235
0
      {
1236
        /* Intersecting a finite and an infinite list.  */
1237
0
        ASSERT (c1 == 0);
1238
0
        if ((c2 > 0 ? e2->presence : list2->repeated.element[0].presence)
1239
0
            == FCT_REQUIRED)
1240
          /* Contradiction.  Backtrack.  */
1241
0
          result = backtrack_in_initial (result);
1242
0
        goto done;
1243
0
      }
1244
0
    else if (list2->repeated.count == 0)
1245
0
      {
1246
        /* Intersecting an infinite and a finite list.  */
1247
0
        ASSERT (c2 == 0);
1248
0
        if ((c1 > 0 ? e1->presence : list1->repeated.element[0].presence)
1249
0
            == FCT_REQUIRED)
1250
          /* Contradiction.  Backtrack.  */
1251
0
          result = backtrack_in_initial (result);
1252
0
        goto done;
1253
0
      }
1254
    /* Intersecting two infinite lists.  */
1255
0
    ASSERT (c1 == 0 && c2 == 0);
1256
0
  }
1257
1258
  /* Step 5: Elementwise intersection of list1->repeated, list2->repeated.  */
1259
0
  {
1260
0
    struct format_arg *e1 = list1->repeated.element;
1261
0
    size_t c1 = list1->repeated.count;
1262
0
    struct format_arg *e2 = list2->repeated.element;
1263
0
    size_t c2 = list2->repeated.count;
1264
0
    while (c1 > 0 && c2 > 0)
1265
0
      {
1266
        /* Ensure room in result->repeated.  */
1267
0
        grow_repeated_alloc (result);
1268
0
        struct format_arg *re = &result->repeated.element[result->repeated.count];
1269
0
        re->repcount = MIN (e1->repcount, e2->repcount);
1270
1271
        /* Intersect the argument types.  */
1272
0
        if (!make_intersected_element (re, e1, e2))
1273
0
          {
1274
0
            bool re_is_required = re->presence == FCT_REQUIRED;
1275
1276
0
            append_repeated_to_initial (result);
1277
1278
            /* If re->presence == FCT_OPTIONAL, the result list ends here.  */
1279
0
            if (re_is_required)
1280
              /* Contradiction.  Backtrack.  */
1281
0
              result = backtrack_in_initial (result);
1282
1283
0
            goto done;
1284
0
          }
1285
1286
0
        result->repeated.count++;
1287
0
        result->repeated.length += re->repcount;
1288
1289
0
        e1->repcount -= re->repcount;
1290
0
        if (e1->repcount == 0)
1291
0
          {
1292
0
            e1++;
1293
0
            c1--;
1294
0
          }
1295
0
        e2->repcount -= re->repcount;
1296
0
        if (e2->repcount == 0)
1297
0
          {
1298
0
            e2++;
1299
0
            c2--;
1300
0
          }
1301
0
      }
1302
0
    ASSERT (c1 == 0 && c2 == 0);
1303
0
  }
1304
1305
0
 done:
1306
0
  free_list (list1);
1307
0
  free_list (list2);
1308
0
  if (result != NULL)
1309
0
    {
1310
      /* Undo the loop unfolding and unrolling done above.  */
1311
0
      normalize_outermost_list (result);
1312
0
      VERIFY_LIST (result);
1313
0
    }
1314
0
  return result;
1315
0
}
1316
1317
1318
/* Create the intersection of an argument list and the empty list.
1319
   Return NULL if the intersection is empty.  */
1320
/* Memory effects: The result, if non-NULL, is freshly allocated.  */
1321
static struct format_arg_list *
1322
make_intersection_with_empty_list (struct format_arg_list *list)
1323
0
{
1324
#if 0 /* equivalent but slower */
1325
  return make_intersected_list (copy_list (list), make_empty_list ());
1326
#else
1327
0
  if (list->initial.count > 0
1328
0
      ? list->initial.element[0].presence == FCT_REQUIRED
1329
0
      : list->repeated.count > 0
1330
0
        && list->repeated.element[0].presence == FCT_REQUIRED)
1331
0
    return NULL;
1332
0
  else
1333
0
    return make_empty_list ();
1334
0
#endif
1335
0
}
1336
1337
1338
/* Create the intersection of two argument list constraints.  NULL stands
1339
   for an impossible situation, i.e. a contradiction.  */
1340
/* Memory effects: list1 and list2 are freed if non-NULL.  The result,
1341
   if non-NULL, is freshly allocated.  */
1342
MAYBE_UNUSED static struct format_arg_list *
1343
intersection (struct format_arg_list *list1, struct format_arg_list *list2)
1344
0
{
1345
0
  if (list1 != NULL)
1346
0
    {
1347
0
      if (list2 != NULL)
1348
0
        return make_intersected_list (list1, list2);
1349
0
      else
1350
0
        {
1351
0
          free_list (list1);
1352
0
          return NULL;
1353
0
        }
1354
0
    }
1355
0
  else
1356
0
    {
1357
0
      if (list2 != NULL)
1358
0
        {
1359
0
          free_list (list2);
1360
0
          return NULL;
1361
0
        }
1362
0
      else
1363
0
        return NULL;
1364
0
    }
1365
0
}
1366
1367
1368
/* ===================== Union of two format_arg_lists ===================== */
1369
1370
/* Create the union (i.e. alternative constraints) of two argument
1371
   constraints.  */
1372
static void
1373
make_union_element (struct format_arg *re,
1374
                    const struct format_arg * e1,
1375
                    const struct format_arg * e2)
1376
0
{
1377
  /* Union of the cdr types.  */
1378
0
  if (e1->presence == FCT_REQUIRED && e2->presence == FCT_REQUIRED)
1379
0
    re->presence = FCT_REQUIRED;
1380
0
  else /* Either one of them is FCT_OPTIONAL.  */
1381
0
    re->presence = FCT_OPTIONAL;
1382
1383
  /* Union of the arg types.  */
1384
0
  if (e1->type == e2->type)
1385
0
    {
1386
0
      re->type = e1->type;
1387
0
      if (re->type == FAT_LIST)
1388
0
        re->list = make_union_list (copy_list (e1->list),
1389
0
                                    copy_list (e2->list));
1390
0
    }
1391
0
  else if (e1->type == FAT_CHARACTER_INTEGER_NULL
1392
0
           && (e2->type == FAT_CHARACTER_NULL || e2->type == FAT_CHARACTER
1393
0
               || e2->type == FAT_INTEGER_NULL || e2->type == FAT_INTEGER))
1394
0
    {
1395
0
      re->type = e1->type;
1396
0
    }
1397
0
  else if (e2->type == FAT_CHARACTER_INTEGER_NULL
1398
0
           && (e1->type == FAT_CHARACTER_NULL || e1->type == FAT_CHARACTER
1399
0
               || e1->type == FAT_INTEGER_NULL || e1->type == FAT_INTEGER))
1400
0
    {
1401
0
      re->type = e2->type;
1402
0
    }
1403
0
  else if (e1->type == FAT_CHARACTER_NULL && e2->type == FAT_CHARACTER)
1404
0
    {
1405
0
      re->type = e1->type;
1406
0
    }
1407
0
  else if (e2->type == FAT_CHARACTER_NULL && e1->type == FAT_CHARACTER)
1408
0
    {
1409
0
      re->type = e2->type;
1410
0
    }
1411
0
  else if (e1->type == FAT_INTEGER_NULL && e2->type == FAT_INTEGER)
1412
0
    {
1413
0
      re->type = e1->type;
1414
0
    }
1415
0
  else if (e2->type == FAT_INTEGER_NULL && e1->type == FAT_INTEGER)
1416
0
    {
1417
0
      re->type = e2->type;
1418
0
    }
1419
0
  else if (e1->type == FAT_REAL && e2->type == FAT_INTEGER)
1420
0
    {
1421
0
      re->type = e1->type;
1422
0
    }
1423
0
  else if (e2->type == FAT_REAL && e1->type == FAT_INTEGER)
1424
0
    {
1425
0
      re->type = e2->type;
1426
0
    }
1427
0
  else if (e1->type == FAT_LIST && is_empty_list (e1->list))
1428
0
    {
1429
0
      if (e2->type == FAT_CHARACTER_INTEGER_NULL
1430
0
          || e2->type == FAT_CHARACTER_NULL
1431
0
          || e2->type == FAT_INTEGER_NULL)
1432
0
        re->type = e2->type;
1433
0
      else if (e2->type == FAT_CHARACTER)
1434
0
        re->type = FAT_CHARACTER_NULL;
1435
0
      else if (e2->type == FAT_INTEGER)
1436
0
        re->type = FAT_INTEGER_NULL;
1437
0
      else
1438
0
        re->type = FAT_OBJECT;
1439
0
    }
1440
0
  else if (e2->type == FAT_LIST && is_empty_list (e2->list))
1441
0
    {
1442
0
      if (e1->type == FAT_CHARACTER_INTEGER_NULL
1443
0
          || e1->type == FAT_CHARACTER_NULL
1444
0
          || e1->type == FAT_INTEGER_NULL)
1445
0
        re->type = e1->type;
1446
0
      else if (e1->type == FAT_CHARACTER)
1447
0
        re->type = FAT_CHARACTER_NULL;
1448
0
      else if (e1->type == FAT_INTEGER)
1449
0
        re->type = FAT_INTEGER_NULL;
1450
0
      else
1451
0
        re->type = FAT_OBJECT;
1452
0
    }
1453
0
  else if ((e1->type == FAT_CHARACTER || e1->type == FAT_CHARACTER_NULL)
1454
0
           && (e2->type == FAT_INTEGER || e2->type == FAT_INTEGER_NULL))
1455
0
    {
1456
0
      re->type = FAT_CHARACTER_INTEGER_NULL;
1457
0
    }
1458
0
  else if ((e2->type == FAT_CHARACTER || e2->type == FAT_CHARACTER_NULL)
1459
0
           && (e1->type == FAT_INTEGER || e1->type == FAT_INTEGER_NULL))
1460
0
    {
1461
0
      re->type = FAT_CHARACTER_INTEGER_NULL;
1462
0
    }
1463
0
  else
1464
0
    {
1465
      /* Other union types are too hard to describe precisely.  */
1466
0
      re->type = FAT_OBJECT;
1467
0
    }
1468
0
}
1469
1470
/* Create the union (i.e. alternative constraints) of two argument list
1471
   constraints.  Free both argument lists when done.  */
1472
/* Memory effects: list1 and list2 are freed.  The result is freshly
1473
   allocated.  */
1474
static struct format_arg_list *
1475
make_union_list (struct format_arg_list *list1, struct format_arg_list *list2)
1476
0
{
1477
0
  struct format_arg_list *result;
1478
1479
0
  VERIFY_LIST (list1);
1480
0
  VERIFY_LIST (list2);
1481
1482
0
  if (list1->repeated.length > 0 && list2->repeated.length > 0)
1483
0
    {
1484
      /* Step 1: Ensure list1->repeated.length == list2->repeated.length.  */
1485
0
      {
1486
0
        size_t n1 = list1->repeated.length;
1487
0
        size_t n2 = list2->repeated.length;
1488
0
        size_t g = gcd (n1, n2);
1489
0
        size_t m1 = n2 / g; /* = lcm(n1,n2) / n1 */
1490
0
        size_t m2 = n1 / g; /* = lcm(n1,n2) / n2 */
1491
1492
0
        unfold_loop (list1, m1);
1493
0
        unfold_loop (list2, m2);
1494
        /* Now list1->repeated.length = list2->repeated.length = lcm(n1,n2).  */
1495
0
      }
1496
1497
      /* Step 2: Ensure that list1->initial.length == list2->initial.length.  */
1498
0
      {
1499
0
        size_t m = MAX (list1->initial.length, list2->initial.length);
1500
1501
0
        rotate_loop (list1, m);
1502
0
        rotate_loop (list2, m);
1503
0
      }
1504
1505
0
      ASSERT (list1->initial.length == list2->initial.length);
1506
0
      ASSERT (list1->repeated.length == list2->repeated.length);
1507
0
    }
1508
0
  else if (list1->repeated.length > 0)
1509
0
    {
1510
      /* Ensure the initial segment of the result can be computed from the
1511
         initial segment of list1.  */
1512
0
      if (list2->initial.length >= list1->initial.length)
1513
0
        {
1514
0
          rotate_loop (list1, list2->initial.length);
1515
0
          if (list1->repeated.element[0].presence == FCT_REQUIRED)
1516
0
            rotate_loop (list1, list1->initial.length + 1);
1517
0
        }
1518
0
    }
1519
0
  else if (list2->repeated.length > 0)
1520
0
    {
1521
      /* Ensure the initial segment of the result can be computed from the
1522
         initial segment of list2.  */
1523
0
      if (list1->initial.length >= list2->initial.length)
1524
0
        {
1525
0
          rotate_loop (list2, list1->initial.length);
1526
0
          if (list2->repeated.element[0].presence == FCT_REQUIRED)
1527
0
            rotate_loop (list2, list2->initial.length + 1);
1528
0
        }
1529
0
    }
1530
1531
  /* Step 3: Allocate the result.  */
1532
0
  result = XMALLOC (struct format_arg_list);
1533
0
  result->initial.count = 0;
1534
0
  result->initial.allocated = 0;
1535
0
  result->initial.element = NULL;
1536
0
  result->initial.length = 0;
1537
0
  result->repeated.count = 0;
1538
0
  result->repeated.allocated = 0;
1539
0
  result->repeated.element = NULL;
1540
0
  result->repeated.length = 0;
1541
1542
  /* Step 4: Elementwise union of list1->initial, list2->initial.  */
1543
0
  {
1544
0
    struct format_arg *e1 = list1->initial.element; size_t c1 = list1->initial.count;
1545
0
    struct format_arg *e2 = list2->initial.element; size_t c2 = list2->initial.count;
1546
0
    while (c1 > 0 && c2 > 0)
1547
0
      {
1548
        /* Ensure room in result->initial.  */
1549
0
        grow_initial_alloc (result);
1550
0
        struct format_arg *re = &result->initial.element[result->initial.count];
1551
0
        re->repcount = MIN (e1->repcount, e2->repcount);
1552
1553
        /* Union of the argument types.  */
1554
0
        make_union_element (re, e1, e2);
1555
1556
0
        result->initial.count++;
1557
0
        result->initial.length += re->repcount;
1558
1559
0
        e1->repcount -= re->repcount;
1560
0
        if (e1->repcount == 0)
1561
0
          {
1562
0
            e1++;
1563
0
            c1--;
1564
0
          }
1565
0
        e2->repcount -= re->repcount;
1566
0
        if (e2->repcount == 0)
1567
0
          {
1568
0
            e2++;
1569
0
            c2--;
1570
0
          }
1571
0
       }
1572
1573
0
    if (c1 > 0)
1574
0
      {
1575
        /* list2 already terminated, but still more elements in list1->initial.
1576
           Copy them all, but turn the first presence to FCT_OPTIONAL.  */
1577
0
        ASSERT (list2->repeated.count == 0);
1578
1579
0
        if (e1->presence == FCT_REQUIRED)
1580
0
          {
1581
            /* Ensure room in result->initial.  */
1582
0
            grow_initial_alloc (result);
1583
0
            struct format_arg *re = &result->initial.element[result->initial.count];
1584
0
            copy_element (re, e1);
1585
0
            re->presence = FCT_OPTIONAL;
1586
0
            re->repcount = 1;
1587
0
            result->initial.count++;
1588
0
            result->initial.length += 1;
1589
0
            e1->repcount -= 1;
1590
0
            if (e1->repcount == 0)
1591
0
              {
1592
0
                e1++;
1593
0
                c1--;
1594
0
              }
1595
0
          }
1596
1597
        /* Ensure room in result->initial.  */
1598
0
        ensure_initial_alloc (result, result->initial.count + c1);
1599
0
        while (c1 > 0)
1600
0
          {
1601
0
            struct format_arg *re = &result->initial.element[result->initial.count];
1602
0
            copy_element (re, e1);
1603
0
            result->initial.count++;
1604
0
            result->initial.length += re->repcount;
1605
0
            e1++;
1606
0
            c1--;
1607
0
          }
1608
0
      }
1609
0
    else if (c2 > 0)
1610
0
      {
1611
        /* list1 already terminated, but still more elements in list2->initial.
1612
           Copy them all, but turn the first presence to FCT_OPTIONAL.  */
1613
0
        ASSERT (list1->repeated.count == 0);
1614
1615
0
        if (e2->presence == FCT_REQUIRED)
1616
0
          {
1617
            /* Ensure room in result->initial.  */
1618
0
            grow_initial_alloc (result);
1619
0
            struct format_arg *re = &result->initial.element[result->initial.count];
1620
0
            copy_element (re, e2);
1621
0
            re->presence = FCT_OPTIONAL;
1622
0
            re->repcount = 1;
1623
0
            result->initial.count++;
1624
0
            result->initial.length += 1;
1625
0
            e2->repcount -= 1;
1626
0
            if (e2->repcount == 0)
1627
0
              {
1628
0
                e2++;
1629
0
                c2--;
1630
0
              }
1631
0
          }
1632
1633
        /* Ensure room in result->initial.  */
1634
0
        ensure_initial_alloc (result, result->initial.count + c2);
1635
0
        while (c2 > 0)
1636
0
          {
1637
0
            struct format_arg *re = &result->initial.element[result->initial.count];
1638
0
            copy_element (re, e2);
1639
0
            result->initial.count++;
1640
0
            result->initial.length += re->repcount;
1641
0
            e2++;
1642
0
            c2--;
1643
0
          }
1644
0
      }
1645
0
    ASSERT (c1 == 0 && c2 == 0);
1646
0
  }
1647
1648
0
  if (list1->repeated.length > 0 && list2->repeated.length > 0)
1649
    /* Step 5: Elementwise union of list1->repeated, list2->repeated.  */
1650
0
    {
1651
0
      struct format_arg *e1 = list1->repeated.element;
1652
0
      size_t c1 = list1->repeated.count;
1653
0
      struct format_arg *e2 = list2->repeated.element;
1654
0
      size_t c2 = list2->repeated.count;
1655
0
      while (c1 > 0 && c2 > 0)
1656
0
        {
1657
          /* Ensure room in result->repeated.  */
1658
0
          grow_repeated_alloc (result);
1659
0
          struct format_arg *re = &result->repeated.element[result->repeated.count];
1660
0
          re->repcount = MIN (e1->repcount, e2->repcount);
1661
1662
          /* Union of the argument types.  */
1663
0
          make_union_element (re, e1, e2);
1664
1665
0
          result->repeated.count++;
1666
0
          result->repeated.length += re->repcount;
1667
1668
0
          e1->repcount -= re->repcount;
1669
0
          if (e1->repcount == 0)
1670
0
            {
1671
0
              e1++;
1672
0
              c1--;
1673
0
            }
1674
0
          e2->repcount -= re->repcount;
1675
0
          if (e2->repcount == 0)
1676
0
            {
1677
0
              e2++;
1678
0
              c2--;
1679
0
            }
1680
0
        }
1681
0
      ASSERT (c1 == 0 && c2 == 0);
1682
0
    }
1683
0
  else if (list1->repeated.length > 0)
1684
0
    {
1685
      /* Turning FCT_REQUIRED into FCT_OPTIONAL was already handled in the
1686
         initial segment.  Just copy the repeated segment of list1.  */
1687
0
      result->repeated.count = list1->repeated.count;
1688
0
      result->repeated.allocated = result->repeated.count;
1689
0
      result->repeated.element =
1690
0
        XNMALLOC (result->repeated.allocated, struct format_arg);
1691
0
      for (size_t i = 0; i < list1->repeated.count; i++)
1692
0
        copy_element (&result->repeated.element[i],
1693
0
                      &list1->repeated.element[i]);
1694
0
      result->repeated.length = list1->repeated.length;
1695
0
    }
1696
0
  else if (list2->repeated.length > 0)
1697
0
    {
1698
      /* Turning FCT_REQUIRED into FCT_OPTIONAL was already handled in the
1699
         initial segment.  Just copy the repeated segment of list2.  */
1700
0
      result->repeated.count = list2->repeated.count;
1701
0
      result->repeated.allocated = result->repeated.count;
1702
0
      result->repeated.element =
1703
0
        XNMALLOC (result->repeated.allocated, struct format_arg);
1704
0
      for (size_t i = 0; i < list2->repeated.count; i++)
1705
0
        copy_element (&result->repeated.element[i],
1706
0
                      &list2->repeated.element[i]);
1707
0
      result->repeated.length = list2->repeated.length;
1708
0
    }
1709
1710
0
  free_list (list1);
1711
0
  free_list (list2);
1712
  /* Undo the loop unfolding and unrolling done above.  */
1713
0
  normalize_outermost_list (result);
1714
0
  VERIFY_LIST (result);
1715
0
  return result;
1716
0
}
1717
1718
1719
/* Create the union of an argument list and the empty list.  */
1720
/* Memory effects: list is freed.  The result is freshly allocated.  */
1721
static struct format_arg_list *
1722
make_union_with_empty_list (struct format_arg_list *list)
1723
0
{
1724
#if 0 /* equivalent but slower */
1725
  return make_union_list (list, make_empty_list ());
1726
#else
1727
0
  VERIFY_LIST (list);
1728
1729
0
  if (list->initial.count > 0
1730
0
      ? list->initial.element[0].presence == FCT_REQUIRED
1731
0
      : list->repeated.count > 0
1732
0
        && list->repeated.element[0].presence == FCT_REQUIRED)
1733
0
    {
1734
0
      initial_splitelement (list, 1);
1735
0
      ASSERT (list->initial.count > 0);
1736
0
      ASSERT (list->initial.element[0].repcount == 1);
1737
0
      ASSERT (list->initial.element[0].presence == FCT_REQUIRED);
1738
0
      list->initial.element[0].presence = FCT_OPTIONAL;
1739
1740
      /* We might need to merge list->initial.element[0] and
1741
         list->initial.element[1].  */
1742
0
      normalize_outermost_list (list);
1743
0
    }
1744
1745
0
  VERIFY_LIST (list);
1746
1747
0
  return list;
1748
0
#endif
1749
0
}
1750
1751
1752
/* Create the union of two argument list constraints.  NULL stands for an
1753
   impossible situation, i.e. a contradiction.  */
1754
/* Memory effects: list1 and list2 are freed if non-NULL.  The result,
1755
   if non-NULL, is freshly allocated.  */
1756
static struct format_arg_list *
1757
union (struct format_arg_list *list1, struct format_arg_list *list2)
1758
0
{
1759
0
  if (list1 != NULL)
1760
0
    {
1761
0
      if (list2 != NULL)
1762
0
        return make_union_list (list1, list2);
1763
0
      else
1764
0
        return list1;
1765
0
    }
1766
0
  else
1767
0
    {
1768
0
      if (list2 != NULL)
1769
0
        return list2;
1770
0
      else
1771
0
        return NULL;
1772
0
    }
1773
0
}
1774
1775
1776
/* =========== Adding specific constraints to a format_arg_list =========== */
1777
1778
1779
/* Test whether arguments 0..n are required arguments in a list.  */
1780
static bool
1781
is_required (const struct format_arg_list *list, size_t n)
1782
0
{
1783
0
  size_t t;
1784
1785
  /* We'll check whether the first n+1 presence flags are FCT_REQUIRED.  */
1786
0
  t = n + 1;
1787
1788
  /* Walk the list->initial segment.  */
1789
0
  {
1790
0
    size_t s;
1791
1792
0
    for (s = 0;
1793
0
         s < list->initial.count && t >= list->initial.element[s].repcount;
1794
0
         t -= list->initial.element[s].repcount, s++)
1795
0
      if (list->initial.element[s].presence != FCT_REQUIRED)
1796
0
        return false;
1797
1798
0
    if (t == 0)
1799
0
      return true;
1800
1801
0
    if (s < list->initial.count)
1802
0
      {
1803
0
        if (list->initial.element[s].presence != FCT_REQUIRED)
1804
0
          return false;
1805
0
        else
1806
0
          return true;
1807
0
      }
1808
0
  }
1809
1810
  /* Walk the list->repeated segment.  */
1811
0
  if (list->repeated.count == 0)
1812
0
    return false;
1813
1814
0
  {
1815
0
    size_t s;
1816
1817
0
    for (s = 0;
1818
0
         s < list->repeated.count && t >= list->repeated.element[s].repcount;
1819
0
         t -= list->repeated.element[s].repcount, s++)
1820
0
      if (list->repeated.element[s].presence != FCT_REQUIRED)
1821
0
        return false;
1822
1823
0
    if (t == 0)
1824
0
      return true;
1825
1826
0
    if (s < list->repeated.count)
1827
0
      {
1828
0
        if (list->repeated.element[s].presence != FCT_REQUIRED)
1829
0
          return false;
1830
0
        else
1831
0
          return true;
1832
0
      }
1833
0
  }
1834
1835
  /* The list->repeated segment consists only of FCT_REQUIRED.  So,
1836
     regardless how many more passes through list->repeated would be
1837
     needed until t becomes 0, the result is true.  */
1838
0
  return true;
1839
0
}
1840
1841
1842
/* Add a constraint to an argument list, namely that the arguments 0...n are
1843
   present.  NULL stands for an impossible situation, i.e. a contradiction.  */
1844
/* Memory effects: list is freed.  The result is freshly allocated.  */
1845
static struct format_arg_list *
1846
add_required_constraint (struct format_arg_list *list, size_t n)
1847
0
{
1848
0
  if (list == NULL)
1849
0
    return NULL;
1850
1851
0
  VERIFY_LIST (list);
1852
1853
0
  if (list->repeated.count == 0 && list->initial.length <= n)
1854
0
    {
1855
      /* list is already constrained to have at most length n.
1856
         Contradiction.  */
1857
0
      free_list (list);
1858
0
      return NULL;
1859
0
    }
1860
1861
0
  initial_splitelement (list, n + 1);
1862
1863
0
  {
1864
0
    size_t i = 0;
1865
0
    for (size_t rest = n + 1; rest > 0; )
1866
0
      {
1867
0
        list->initial.element[i].presence = FCT_REQUIRED;
1868
0
        rest -= list->initial.element[i].repcount;
1869
0
        i++;
1870
0
      }
1871
0
  }
1872
1873
0
  VERIFY_LIST (list);
1874
1875
0
  return list;
1876
0
}
1877
1878
1879
/* Add a constraint to an argument list, namely that the argument n is
1880
   never present.  NULL stands for an impossible situation, i.e. a
1881
   contradiction.  */
1882
/* Memory effects: list is freed.  The result is freshly allocated.  */
1883
static struct format_arg_list *
1884
add_end_constraint (struct format_arg_list *list, size_t n)
1885
0
{
1886
0
  if (list == NULL)
1887
0
    return NULL;
1888
1889
0
  VERIFY_LIST (list);
1890
1891
0
  if (list->repeated.count == 0 && list->initial.length <= n)
1892
    /* list is already constrained to have at most length n.  */
1893
0
    return list;
1894
1895
0
  size_t s = initial_splitelement (list, n);
1896
0
  enum format_cdr_type n_presence =
1897
0
    (s < list->initial.count
1898
0
     ? /* n < list->initial.length */ list->initial.element[s].presence
1899
0
     : /* n >= list->initial.length */ list->repeated.element[0].presence);
1900
1901
0
  for (size_t i = s; i < list->initial.count; i++)
1902
0
    {
1903
0
      list->initial.length -= list->initial.element[i].repcount;
1904
0
      free_element (&list->initial.element[i]);
1905
0
    }
1906
0
  list->initial.count = s;
1907
1908
0
  for (size_t i = 0; i < list->repeated.count; i++)
1909
0
    free_element (&list->repeated.element[i]);
1910
0
  if (list->repeated.element != NULL)
1911
0
    free (list->repeated.element);
1912
0
  list->repeated.element = NULL;
1913
0
  list->repeated.allocated = 0;
1914
0
  list->repeated.count = 0;
1915
0
  list->repeated.length = 0;
1916
1917
0
  if (n_presence == FCT_REQUIRED)
1918
0
    return backtrack_in_initial (list);
1919
0
  else
1920
0
    return list;
1921
0
}
1922
1923
1924
/* Add a constraint to an argument list, namely that the argument n is
1925
   of a given type.  NULL stands for an impossible situation, i.e. a
1926
   contradiction.  Assumes a preceding add_required_constraint (list, n).  */
1927
/* Memory effects: list is freed.  The result is freshly allocated.  */
1928
static struct format_arg_list *
1929
add_type_constraint (struct format_arg_list *list, size_t n,
1930
                     enum format_arg_type type)
1931
0
{
1932
0
  if (list == NULL)
1933
0
    return NULL;
1934
1935
  /* Through the previous add_required_constraint, we can assume
1936
     list->initial.length >= n+1.  */
1937
1938
0
  size_t s = initial_unshare (list, n);
1939
1940
0
  struct format_arg newconstraint;
1941
0
  newconstraint.presence = FCT_OPTIONAL;
1942
0
  newconstraint.type = type;
1943
1944
0
  struct format_arg tmpelement;
1945
0
  if (!make_intersected_element (&tmpelement,
1946
0
                                 &list->initial.element[s], &newconstraint))
1947
0
    list = add_end_constraint (list, n);
1948
0
  else
1949
0
    {
1950
0
      free_element (&list->initial.element[s]);
1951
0
      list->initial.element[s].type = tmpelement.type;
1952
0
      list->initial.element[s].list = tmpelement.list;
1953
0
    }
1954
1955
0
  if (list != NULL)
1956
0
    VERIFY_LIST (list);
1957
1958
0
  return list;
1959
0
}
1960
1961
1962
/* Add a constraint to an argument list, namely that the argument n is
1963
   of a given list type.  NULL stands for an impossible situation, i.e. a
1964
   contradiction.  Assumes a preceding add_required_constraint (list, n).  */
1965
/* Memory effects: list is freed.  The result is freshly allocated.  */
1966
static struct format_arg_list *
1967
add_listtype_constraint (struct format_arg_list *list, size_t n,
1968
                         enum format_arg_type type,
1969
                         struct format_arg_list *sublist)
1970
0
{
1971
0
  if (list == NULL)
1972
0
    return NULL;
1973
1974
  /* Through the previous add_required_constraint, we can assume
1975
     list->initial.length >= n+1.  */
1976
1977
0
  size_t s = initial_unshare (list, n);
1978
1979
0
  struct format_arg newconstraint;
1980
0
  newconstraint.presence = FCT_OPTIONAL;
1981
0
  newconstraint.type = type;
1982
0
  newconstraint.list = sublist;
1983
1984
0
  struct format_arg tmpelement;
1985
0
  if (!make_intersected_element (&tmpelement,
1986
0
                                 &list->initial.element[s], &newconstraint))
1987
0
    list = add_end_constraint (list, n);
1988
0
  else
1989
0
    {
1990
0
      free_element (&list->initial.element[s]);
1991
0
      list->initial.element[s].type = tmpelement.type;
1992
0
      list->initial.element[s].list = tmpelement.list;
1993
0
    }
1994
1995
0
  if (list != NULL)
1996
0
    VERIFY_LIST (list);
1997
1998
0
  return list;
1999
0
}
2000
2001
2002
/* ============= Subroutines used by the format string parser ============= */
2003
2004
static void
2005
add_req_type_constraint (struct format_arg_list **listp,
2006
                         size_t position, enum format_arg_type type)
2007
0
{
2008
0
  *listp = add_required_constraint (*listp, position);
2009
0
  *listp = add_type_constraint (*listp, position, type);
2010
0
}
2011
2012
2013
static void
2014
add_req_listtype_constraint (struct format_arg_list **listp,
2015
                             size_t position, enum format_arg_type type,
2016
                             struct format_arg_list *sublist)
2017
0
{
2018
0
  *listp = add_required_constraint (*listp, position);
2019
0
  *listp = add_listtype_constraint (*listp, position, type, sublist);
2020
0
}
2021
2022
2023
/* Create an endless repeated list whose elements are lists constrained
2024
   by sublist.  */
2025
/* Memory effects: sublist is freed.  The result is freshly allocated.  */
2026
static struct format_arg_list *
2027
make_repeated_list_of_lists (struct format_arg_list *sublist)
2028
0
{
2029
0
  if (sublist == NULL)
2030
    /* The list cannot have a single element.  */
2031
0
    return make_empty_list ();
2032
0
  else
2033
0
    {
2034
0
      struct format_arg_list *listlist = XMALLOC (struct format_arg_list);
2035
0
      listlist->initial.count = 0;
2036
0
      listlist->initial.allocated = 0;
2037
0
      listlist->initial.element = NULL;
2038
0
      listlist->initial.length = 0;
2039
0
      listlist->repeated.count = 1;
2040
0
      listlist->repeated.allocated = 1;
2041
0
      listlist->repeated.element = XNMALLOC (1, struct format_arg);
2042
0
      listlist->repeated.element[0].repcount = 1;
2043
0
      listlist->repeated.element[0].presence = FCT_OPTIONAL;
2044
0
      listlist->repeated.element[0].type = FAT_LIST;
2045
0
      listlist->repeated.element[0].list = sublist;
2046
0
      listlist->repeated.length = 1;
2047
2048
0
      VERIFY_LIST (listlist);
2049
2050
0
      return listlist;
2051
0
    }
2052
0
}
2053
2054
2055
/* Create an endless repeated list which represents the union of a finite
2056
   number of copies of L, each time shifted by period:
2057
     ()
2058
     L
2059
     L and (*^period L)
2060
     L and (*^period L) and (*^{2 period} L)
2061
     L and (*^period L) and (*^{2 period} L) and (*^{3 period} L)
2062
     ...
2063
 */
2064
/* Memory effects: sublist is freed.  The result is freshly allocated.  */
2065
static struct format_arg_list *
2066
make_repeated_list (struct format_arg_list *sublist, size_t period)
2067
0
{
2068
0
  VERIFY_LIST (sublist);
2069
2070
0
  ASSERT (period > 0);
2071
2072
0
  struct segment *srcseg;
2073
0
  struct segment tmp;
2074
0
  size_t p;
2075
0
  if (sublist->repeated.count == 0)
2076
0
    {
2077
      /* L is a finite list.  */
2078
2079
0
      if (sublist->initial.length < period)
2080
        /* L and (*^period L) is a contradition, so we need to consider
2081
           only 1 and 0 iterations.  */
2082
0
        return make_union_with_empty_list (sublist);
2083
2084
0
      srcseg = &sublist->initial;
2085
0
      p = period;
2086
0
    }
2087
0
  else
2088
0
    {
2089
      /* L is an infinite list.  */
2090
      /* p := lcm (period, period of L)  */
2091
0
      size_t Lp = sublist->repeated.length;
2092
0
      size_t m = period / gcd (period, Lp); /* = lcm(period,Lp) / Lp */
2093
2094
0
      unfold_loop (sublist, m);
2095
0
      p = m * Lp;
2096
2097
      /* Concatenate the initial and the repeated segments into a single
2098
         segment.  */
2099
0
      tmp.count = sublist->initial.count + sublist->repeated.count;
2100
0
      tmp.allocated = tmp.count;
2101
0
      tmp.element = XNMALLOC (tmp.allocated, struct format_arg);
2102
0
      {
2103
0
        size_t i;
2104
0
        for (i = 0; i < sublist->initial.count; i++)
2105
0
          tmp.element[i] = sublist->initial.element[i];
2106
0
        for (size_t j = 0; j < sublist->repeated.count; j++)
2107
0
          {
2108
0
            tmp.element[i] = sublist->repeated.element[j];
2109
0
            i++;
2110
0
          }
2111
0
      }
2112
0
      tmp.length = sublist->initial.length + sublist->repeated.length;
2113
2114
0
      srcseg = &tmp;
2115
0
    }
2116
2117
0
  size_t n = srcseg->length;
2118
2119
  /* Example: n = 7, p = 2
2120
     Let L = (A B C D E F G).
2121
2122
     L                 =    A     B     C     D      E      F      G
2123
     L & L<<p          =    A     B    C&A   D&B    E&C    F&D    G&E
2124
     L & L<<p & L<<2p  =    A     B    C&A   D&B   E&C&A  F&D&B  G&E&C
2125
     ...               =    A     B    C&A   D&B   E&C&A  F&D&B G&E&C&A
2126
2127
     Thus the result has an initial segment of length n - p and a period
2128
     of p, and can be computed by floor(n/p) intersection operations.
2129
     Or by a single incremental intersection operation, going from left
2130
     to right.  */
2131
2132
0
  struct format_arg_list *list = XMALLOC (struct format_arg_list);
2133
0
  list->initial.count = 0;
2134
0
  list->initial.allocated = 0;
2135
0
  list->initial.element = NULL;
2136
0
  list->initial.length = 0;
2137
0
  list->repeated.count = 0;
2138
0
  list->repeated.allocated = 0;
2139
0
  list->repeated.element = NULL;
2140
0
  list->repeated.length = 0;
2141
2142
  /* Sketch:
2143
     for (i = 0; i < p; i++)
2144
       list->initial.element[i] = srcseg->element[i];
2145
     list->initial.element[0].presence = FCT_OPTIONAL;  // union with empty list
2146
     for (i = p, j = 0; i < n; i++, j++)
2147
       list->initial.element[i] = srcseg->element[i] & list->initial.element[j];
2148
   */
2149
2150
0
  bool ended = false;
2151
2152
0
  {
2153
0
    size_t i = 0;
2154
0
    size_t ti = 0;
2155
0
    size_t si = 0;
2156
0
    while (i < p)
2157
0
      {
2158
0
        size_t k = MIN (srcseg->element[si].repcount - ti, p - i);
2159
2160
        /* Ensure room in list->initial.  */
2161
0
        grow_initial_alloc (list);
2162
0
        copy_element (&list->initial.element[list->initial.count],
2163
0
                      &srcseg->element[si]);
2164
0
        list->initial.element[list->initial.count].repcount = k;
2165
0
        list->initial.count++;
2166
0
        list->initial.length += k;
2167
2168
0
        i += k;
2169
0
        ti += k;
2170
0
        if (ti == srcseg->element[si].repcount)
2171
0
          {
2172
0
            ti = 0;
2173
0
            si++;
2174
0
          }
2175
0
      }
2176
2177
0
    ASSERT (list->initial.count > 0);
2178
0
    if (list->initial.element[0].presence == FCT_REQUIRED)
2179
0
      {
2180
0
        initial_splitelement (list, 1);
2181
0
        ASSERT (list->initial.element[0].presence == FCT_REQUIRED);
2182
0
        ASSERT (list->initial.element[0].repcount == 1);
2183
0
        list->initial.element[0].presence = FCT_OPTIONAL;
2184
0
      }
2185
2186
0
    size_t j = 0;
2187
0
    size_t tj = 0;
2188
0
    size_t sj = 0;
2189
0
    while (i < n)
2190
0
      {
2191
0
        size_t k =
2192
0
          MIN (srcseg->element[si].repcount - ti,
2193
0
               list->initial.element[sj].repcount - tj);
2194
2195
        /* Ensure room in list->initial.  */
2196
0
        grow_initial_alloc (list);
2197
0
        if (!make_intersected_element (&list->initial.element[list->initial.count],
2198
0
                                       &srcseg->element[si],
2199
0
                                       &list->initial.element[sj]))
2200
0
          {
2201
0
            if (list->initial.element[list->initial.count].presence == FCT_REQUIRED)
2202
0
              {
2203
                /* Contradiction.  Backtrack.  */
2204
0
                list = backtrack_in_initial (list);
2205
0
                ASSERT (list != NULL); /* at least the empty list is valid */
2206
0
                return list;
2207
0
              }
2208
0
            else
2209
0
              {
2210
                /* The list ends here.  */
2211
0
                ended = true;
2212
0
                break;
2213
0
              }
2214
0
          }
2215
0
        list->initial.element[list->initial.count].repcount = k;
2216
0
        list->initial.count++;
2217
0
        list->initial.length += k;
2218
2219
0
        i += k;
2220
0
        ti += k;
2221
0
        if (ti == srcseg->element[si].repcount)
2222
0
          {
2223
0
            ti = 0;
2224
0
            si++;
2225
0
          }
2226
2227
0
        j += k;
2228
0
        tj += k;
2229
0
        if (tj == list->initial.element[sj].repcount)
2230
0
          {
2231
0
            tj = 0;
2232
0
            sj++;
2233
0
          }
2234
0
      }
2235
0
    if (!ended)
2236
0
      ASSERT (list->initial.length == n);
2237
0
  }
2238
2239
  /* Add optional exit points at 0, period, 2*period etc.
2240
     FIXME: Not sure this is correct in all cases.  */
2241
0
  for (size_t i = 0; i < list->initial.length; i += period)
2242
0
    {
2243
0
      size_t si = initial_unshare (list, i);
2244
0
      list->initial.element[si].presence = FCT_OPTIONAL;
2245
0
    }
2246
2247
0
  if (!ended)
2248
0
    {
2249
      /* Now split off the repeated part.  */
2250
0
      size_t splitindex = initial_splitelement (list, n - p);
2251
0
      size_t newcount = list->initial.count - splitindex;
2252
0
      if (newcount > list->repeated.allocated)
2253
0
        {
2254
0
          list->repeated.allocated = newcount;
2255
0
          list->repeated.element = XNMALLOC (newcount, struct format_arg);
2256
0
        }
2257
0
      {
2258
0
        size_t i = splitindex;
2259
0
        for (size_t j = 0; j < newcount; j++)
2260
0
          {
2261
0
            list->repeated.element[j] = list->initial.element[i];
2262
0
            i++;
2263
0
          }
2264
0
      }
2265
0
      list->repeated.count = newcount;
2266
0
      list->repeated.length = p;
2267
0
      list->initial.count = splitindex;
2268
0
      list->initial.length = n - p;
2269
0
    }
2270
2271
0
  VERIFY_LIST (list);
2272
2273
0
  return list;
2274
0
}
2275
2276
2277
/* ================= Handling of format string directives ================= */
2278
2279
/* Possible signatures of format directives.  */
2280
static const enum format_arg_type I [1] = { FAT_INTEGER_NULL };
2281
static const enum format_arg_type II [2] = {
2282
  FAT_INTEGER_NULL, FAT_INTEGER_NULL
2283
};
2284
static const enum format_arg_type ICCI [4] = {
2285
  FAT_INTEGER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL, FAT_INTEGER_NULL
2286
};
2287
static const enum format_arg_type IIIC [4] = {
2288
  FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL
2289
};
2290
static const enum format_arg_type IICCI [5] = {
2291
  FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL,
2292
  FAT_INTEGER_NULL
2293
};
2294
static const enum format_arg_type IIICC [5] = {
2295
  FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_CHARACTER_NULL,
2296
  FAT_CHARACTER_NULL
2297
};
2298
static const enum format_arg_type IIIICCC [7] = {
2299
  FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL, FAT_INTEGER_NULL,
2300
  FAT_CHARACTER_NULL, FAT_CHARACTER_NULL, FAT_CHARACTER_NULL
2301
};
2302
static const enum format_arg_type THREE [3] = {
2303
  FAT_CHARACTER_INTEGER_NULL, FAT_CHARACTER_INTEGER_NULL,
2304
  FAT_CHARACTER_INTEGER_NULL
2305
};
2306
2307
2308
/* Check the parameters.  For V params, add the constraint to the argument
2309
   list.  Return false and fill in *invalid_reason if the format string is
2310
   invalid.  */
2311
static bool
2312
check_params (struct format_arg_list **listp,
2313
              size_t paramcount, struct param *params,
2314
              size_t t_count, const enum format_arg_type *t_types,
2315
              size_t directives, char **invalid_reason)
2316
0
{
2317
0
  size_t orig_paramcount = paramcount;
2318
0
  size_t orig_t_count = t_count;
2319
2320
0
  for (; paramcount > 0 && t_count > 0;
2321
0
         params++, paramcount--, t_types++, t_count--)
2322
0
    {
2323
0
      switch (*t_types)
2324
0
        {
2325
0
        case FAT_CHARACTER_INTEGER_NULL:
2326
0
          break;
2327
0
        case FAT_CHARACTER_NULL:
2328
0
          switch (params->type)
2329
0
            {
2330
0
            case PT_NIL: case PT_CHARACTER: case PT_V:
2331
0
              break;
2332
0
            case PT_INTEGER: case PT_ARGCOUNT:
2333
              /* wrong param type */
2334
0
              *invalid_reason =
2335
0
                xasprintf (_("In the directive number %zu, parameter %zu is of type '%s' but a parameter of type '%s' is expected."), directives, orig_paramcount - paramcount + 1, "integer", "character");
2336
0
              return false;
2337
0
            }
2338
0
          break;
2339
0
        case FAT_INTEGER_NULL:
2340
0
          switch (params->type)
2341
0
            {
2342
0
            case PT_NIL: case PT_INTEGER: case PT_ARGCOUNT: case PT_V:
2343
0
              break;
2344
0
            case PT_CHARACTER:
2345
              /* wrong param type */
2346
0
              *invalid_reason =
2347
0
                xasprintf (_("In the directive number %zu, parameter %zu is of type '%s' but a parameter of type '%s' is expected."), directives, orig_paramcount - paramcount + 1, "character", "integer");
2348
0
              return false;
2349
0
            }
2350
0
          break;
2351
0
        default:
2352
0
          abort ();
2353
0
        }
2354
0
      if (params->type == PT_V)
2355
0
        {
2356
0
          int position = params->value;
2357
0
          if (position >= 0)
2358
0
            add_req_type_constraint (listp, position, *t_types);
2359
0
        }
2360
0
    }
2361
2362
0
  for (; paramcount > 0; params++, paramcount--)
2363
0
    switch (params->type)
2364
0
      {
2365
0
      case PT_NIL:
2366
0
        break;
2367
0
      case PT_CHARACTER: case PT_INTEGER: case PT_ARGCOUNT:
2368
        /* too many params for directive */
2369
0
        *invalid_reason =
2370
0
          xasprintf (ngettext ("In the directive number %zu, too many parameters are given; expected at most %zu parameter.",
2371
0
                               "In the directive number %zu, too many parameters are given; expected at most %zu parameters.",
2372
0
                               orig_t_count),
2373
0
                     directives, orig_t_count);
2374
0
        return false;
2375
0
      case PT_V:
2376
        /* Force argument to be NIL.  */
2377
0
        {
2378
0
          int position = params->value;
2379
0
          if (position >= 0)
2380
0
            {
2381
0
              struct format_arg_list *empty_list = make_empty_list ();
2382
0
              add_req_listtype_constraint (listp, position,
2383
0
                                           FAT_LIST, empty_list);
2384
0
              free_list (empty_list);
2385
0
            }
2386
0
        }
2387
0
        break;
2388
0
      }
2389
2390
0
  return true;
2391
0
}
2392
2393
2394
/* Handle the parameters, without a priori type information.
2395
   For V params, add the constraint to the argument list.
2396
   Return false and fill in *invalid_reason if the format string is
2397
   invalid.  */
2398
static bool
2399
nocheck_params (struct format_arg_list **listp,
2400
                size_t paramcount, struct param *params,
2401
                size_t directives, char **invalid_reason)
2402
0
{
2403
0
  (void) directives;
2404
0
  (void) invalid_reason;
2405
2406
0
  for (; paramcount > 0; params++, paramcount--)
2407
0
    if (params->type == PT_V)
2408
0
      {
2409
0
        int position = params->value;
2410
0
        if (position >= 0)
2411
0
          add_req_type_constraint (listp, position, FAT_CHARACTER_INTEGER_NULL);
2412
0
      }
2413
2414
0
  return true;
2415
0
}
2416
2417
2418
/* ======================= The format string parser ======================= */
2419
2420
/* Parse a piece of format string, until the matching terminating format
2421
   directive is encountered.
2422
   format is the remainder of the format string.
2423
   position is the position in this argument list, if known, or -1 if unknown.
2424
   list represents the argument list constraints at the current parse point.
2425
   NULL stands for a contradiction.
2426
   escape represents the union of the argument list constraints at all the
2427
   currently pending FORMAT-UP-AND-OUT points. NULL stands for a contradiction
2428
   or an empty union.
2429
   All four are updated upon valid return.
2430
   *separatorp is set to true if the parse terminated due to a ~; separator,
2431
   more precisely to 2 if with colon, or to 1 if without colon.
2432
   spec is the global struct spec.
2433
   terminator is the directive that terminates this parse.
2434
   separator specifies if ~; separators are allowed.
2435
   fdi is an array to be filled with format directive indicators, or NULL.
2436
   If the format string is invalid, false is returned and *invalid_reason is
2437
   set to an error message explaining why.  */
2438
static bool
2439
parse_upto (const char **formatp,
2440
            int *positionp, struct format_arg_list **listp,
2441
            struct format_arg_list **escapep, int *separatorp,
2442
            struct spec *spec, char terminator, bool separator,
2443
            char *fdi, char **invalid_reason)
2444
0
{
2445
0
  const char *format = *formatp;
2446
0
  const char *const format_start = format;
2447
0
  int position = *positionp;
2448
0
  struct format_arg_list *list = *listp;
2449
0
  struct format_arg_list *escape = *escapep;
2450
2451
0
  for (; *format != '\0'; )
2452
0
    if (*format++ == '~')
2453
0
      {
2454
0
        FDI_SET (format - 1, FMTDIR_START);
2455
2456
        /* Count number of directives.  */
2457
0
        spec->directives++;
2458
2459
        /* Parse parameters.  */
2460
0
        size_t paramcount = 0;
2461
0
        struct param *params = NULL;
2462
0
        for (;;)
2463
0
          {
2464
0
            enum param_type type = PT_NIL;
2465
0
            int value = 0;
2466
2467
0
            if (c_isdigit (*format))
2468
0
              {
2469
0
                type = PT_INTEGER;
2470
0
                do
2471
0
                  {
2472
0
                    value = 10 * value + (*format - '0');
2473
0
                    format++;
2474
0
                  }
2475
0
                while (c_isdigit (*format));
2476
0
              }
2477
0
            else if (*format == '+' || *format == '-')
2478
0
              {
2479
0
                bool negative = (*format == '-');
2480
0
                type = PT_INTEGER;
2481
0
                format++;
2482
0
                if (!c_isdigit (*format))
2483
0
                  {
2484
0
                    if (*format == '\0')
2485
0
                      {
2486
0
                        *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
2487
0
                        FDI_SET (format - 1, FMTDIR_ERROR);
2488
0
                      }
2489
0
                    else
2490
0
                      {
2491
0
                        *invalid_reason =
2492
0
                          xasprintf (_("In the directive number %zu, '%c' is not followed by a digit."), spec->directives, format[-1]);
2493
0
                        FDI_SET (format, FMTDIR_ERROR);
2494
0
                      }
2495
0
                    return false;
2496
0
                  }
2497
0
                do
2498
0
                  {
2499
0
                    value = 10 * value + (*format - '0');
2500
0
                    format++;
2501
0
                  }
2502
0
                while (c_isdigit (*format));
2503
0
                if (negative)
2504
0
                  value = -value;
2505
0
              }
2506
0
            else if (*format == '\'')
2507
0
              {
2508
0
                type = PT_CHARACTER;
2509
0
                format++;
2510
0
                if (*format == '\0')
2511
0
                  {
2512
0
                    *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
2513
0
                    FDI_SET (format - 1, FMTDIR_ERROR);
2514
0
                    return false;
2515
0
                  }
2516
0
                format++;
2517
0
              }
2518
0
            else if (*format == 'V' || *format == 'v')
2519
0
              {
2520
0
                type = PT_V;
2521
0
                format++;
2522
0
                value = position;
2523
                /* Consumes an argument.  */
2524
0
                if (position >= 0)
2525
0
                  position++;
2526
0
              }
2527
0
            else if (*format == '#')
2528
0
              {
2529
0
                type = PT_ARGCOUNT;
2530
0
                format++;
2531
0
              }
2532
2533
0
            params =
2534
0
              (struct param *)
2535
0
              xrealloc (params, (paramcount + 1) * sizeof (struct param));
2536
0
            params[paramcount].type = type;
2537
0
            params[paramcount].value = value;
2538
0
            paramcount++;
2539
2540
0
            if (*format == ',')
2541
0
              format++;
2542
0
            else
2543
0
              break;
2544
0
          }
2545
2546
        /* Parse modifiers.  */
2547
0
        bool colon_p = false;
2548
0
        bool atsign_p = false;
2549
0
        for (;;)
2550
0
          {
2551
0
            if (*format == ':')
2552
0
              {
2553
0
                format++;
2554
0
                colon_p = true;
2555
0
              }
2556
0
            else if (*format == '@')
2557
0
              {
2558
0
                format++;
2559
0
                atsign_p = true;
2560
0
              }
2561
0
            else
2562
0
              break;
2563
0
          }
2564
2565
        /* Parse directive.  */
2566
0
        switch (*format++)
2567
0
          {
2568
0
          case 'A': case 'a': /* 22.3.4.1 FORMAT-ASCII */
2569
0
          case 'S': case 's': /* 22.3.4.2 FORMAT-S-EXPRESSION */
2570
0
            if (!check_params (&list, paramcount, params, 4, IIIC,
2571
0
                               spec->directives, invalid_reason))
2572
0
              {
2573
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2574
0
                return false;
2575
0
              }
2576
0
            if (position >= 0)
2577
0
              add_req_type_constraint (&list, position++, FAT_OBJECT);
2578
0
            break;
2579
2580
0
          case 'W': case 'w': /* 22.3.4.3 FORMAT-WRITE */
2581
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2582
0
                               spec->directives, invalid_reason))
2583
0
              {
2584
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2585
0
                return false;
2586
0
              }
2587
0
            if (position >= 0)
2588
0
              add_req_type_constraint (&list, position++, FAT_OBJECT);
2589
0
            break;
2590
2591
0
          case 'D': case 'd': /* 22.3.2.2 FORMAT-DECIMAL */
2592
0
          case 'B': case 'b': /* 22.3.2.3 FORMAT-BINARY */
2593
0
          case 'O': case 'o': /* 22.3.2.4 FORMAT-OCTAL */
2594
0
          case 'X': case 'x': /* 22.3.2.5 FORMAT-HEXADECIMAL */
2595
0
            if (!check_params (&list, paramcount, params, 4, ICCI,
2596
0
                               spec->directives, invalid_reason))
2597
0
              {
2598
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2599
0
                return false;
2600
0
              }
2601
0
            if (position >= 0)
2602
0
              add_req_type_constraint (&list, position++, FAT_INTEGER);
2603
0
            break;
2604
2605
0
          case 'R': case 'r': /* 22.3.2.1 FORMAT-RADIX */
2606
0
            if (!check_params (&list, paramcount, params, 5, IICCI,
2607
0
                               spec->directives, invalid_reason))
2608
0
              {
2609
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2610
0
                return false;
2611
0
              }
2612
0
            if (position >= 0)
2613
0
              add_req_type_constraint (&list, position++, FAT_INTEGER);
2614
0
            break;
2615
2616
0
          case 'P': case 'p': /* 22.3.8.3 FORMAT-PLURAL */
2617
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2618
0
                               spec->directives, invalid_reason))
2619
0
              {
2620
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2621
0
                return false;
2622
0
              }
2623
0
            if (colon_p)
2624
0
              {
2625
                /* Go back by 1 argument.  */
2626
0
                if (position > 0)
2627
0
                  position--;
2628
0
              }
2629
0
            if (position >= 0)
2630
0
              add_req_type_constraint (&list, position++, FAT_OBJECT);
2631
0
            break;
2632
2633
0
          case 'C': case 'c': /* 22.3.1.1 FORMAT-CHARACTER */
2634
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2635
0
                               spec->directives, invalid_reason))
2636
0
              {
2637
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2638
0
                return false;
2639
0
              }
2640
0
            if (position >= 0)
2641
0
              add_req_type_constraint (&list, position++, FAT_CHARACTER);
2642
0
            break;
2643
2644
0
          case 'F': case 'f': /* 22.3.3.1 FORMAT-FIXED-FLOAT */
2645
0
            if (!check_params (&list, paramcount, params, 5, IIICC,
2646
0
                               spec->directives, invalid_reason))
2647
0
              {
2648
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2649
0
                return false;
2650
0
              }
2651
0
            if (position >= 0)
2652
0
              add_req_type_constraint (&list, position++, FAT_REAL);
2653
0
            break;
2654
2655
0
          case 'E': case 'e': /* 22.3.3.2 FORMAT-EXPONENTIAL-FLOAT */
2656
0
          case 'G': case 'g': /* 22.3.3.3 FORMAT-GENERAL-FLOAT */
2657
0
            if (!check_params (&list, paramcount, params, 7, IIIICCC,
2658
0
                               spec->directives, invalid_reason))
2659
0
              {
2660
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2661
0
                return false;
2662
0
              }
2663
0
            if (position >= 0)
2664
0
              add_req_type_constraint (&list, position++, FAT_REAL);
2665
0
            break;
2666
2667
0
          case '$': /* 22.3.3.4 FORMAT-DOLLARS-FLOAT */
2668
0
            if (!check_params (&list, paramcount, params, 4, IIIC,
2669
0
                               spec->directives, invalid_reason))
2670
0
              {
2671
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2672
0
                return false;
2673
0
              }
2674
0
            if (position >= 0)
2675
0
              add_req_type_constraint (&list, position++, FAT_REAL);
2676
0
            break;
2677
2678
0
          case '%': /* 22.3.1.2 FORMAT-TERPRI */
2679
0
          case '&': /* 22.3.1.3 FORMAT-FRESH-LINE */
2680
0
          case '|': /* 22.3.1.4 FORMAT-PAGE */
2681
0
          case '~': /* 22.3.1.5 FORMAT-TILDE */
2682
0
          case 'I': case 'i': /* 22.3.5.3 */
2683
0
            if (!check_params (&list, paramcount, params, 1, I,
2684
0
                               spec->directives, invalid_reason))
2685
0
              {
2686
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2687
0
                return false;
2688
0
              }
2689
0
            break;
2690
2691
0
          case '\n': /* 22.3.9.3 #\Newline */
2692
0
          case '_': /* 22.3.5.1 */
2693
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2694
0
                               spec->directives, invalid_reason))
2695
0
              {
2696
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2697
0
                return false;
2698
0
              }
2699
0
            break;
2700
2701
0
          case 'T': case 't': /* 22.3.6.1 FORMAT-TABULATE */
2702
0
            if (!check_params (&list, paramcount, params, 2, II,
2703
0
                               spec->directives, invalid_reason))
2704
0
              {
2705
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2706
0
                return false;
2707
0
              }
2708
0
            break;
2709
2710
0
          case '*': /* 22.3.7.1 FORMAT-GOTO */
2711
0
            if (!check_params (&list, paramcount, params, 1, I,
2712
0
                               spec->directives, invalid_reason))
2713
0
              {
2714
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2715
0
                return false;
2716
0
              }
2717
0
            {
2718
0
              int n; /* value of first parameter */
2719
0
              if (paramcount == 0
2720
0
                  || (paramcount >= 1 && params[0].type == PT_NIL))
2721
0
                n = (atsign_p ? 0 : 1);
2722
0
              else if (paramcount >= 1 && params[0].type == PT_INTEGER)
2723
0
                n = params[0].value;
2724
0
              else
2725
0
                {
2726
                  /* Unknown argument, leads to an unknown position.  */
2727
0
                  position = -1;
2728
0
                  break;
2729
0
                }
2730
0
              if (n < 0)
2731
0
                {
2732
                  /* invalid argument */
2733
0
                  *invalid_reason =
2734
0
                    xasprintf (_("In the directive number %zu, the argument %d is negative."), spec->directives, n);
2735
0
                  FDI_SET (format - 1, FMTDIR_ERROR);
2736
0
                  return false;
2737
0
                }
2738
0
              if (atsign_p)
2739
0
                {
2740
                  /* Absolute goto.  */
2741
0
                  position = n;
2742
0
                }
2743
0
              else if (colon_p)
2744
0
                {
2745
                  /* Backward goto.  */
2746
0
                  if (n > 0)
2747
0
                    {
2748
0
                      if (position >= 0)
2749
0
                        {
2750
0
                          if (position >= n)
2751
0
                            position -= n;
2752
0
                          else
2753
0
                            position = 0;
2754
0
                        }
2755
0
                      else
2756
0
                        position = -1;
2757
0
                   }
2758
0
                }
2759
0
              else
2760
0
                {
2761
                  /* Forward goto.  */
2762
0
                  if (position >= 0)
2763
0
                    position += n;
2764
0
                }
2765
0
            }
2766
0
            break;
2767
2768
0
          case '?': /* 22.3.7.6 FORMAT-INDIRECTION */
2769
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2770
0
                               spec->directives, invalid_reason))
2771
0
              {
2772
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2773
0
                return false;
2774
0
              }
2775
0
            if (position >= 0)
2776
0
              add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
2777
0
            if (atsign_p)
2778
0
              position = -1;
2779
0
            else
2780
0
              if (position >= 0)
2781
0
                {
2782
0
                  struct format_arg_list *sublist = make_unconstrained_list ();
2783
0
                  add_req_listtype_constraint (&list, position++,
2784
0
                                               FAT_LIST, sublist);
2785
0
                  free_list (sublist);
2786
0
                }
2787
0
            break;
2788
2789
0
          case '/': /* 22.3.5.4 FORMAT-CALL-USER-FUNCTION */
2790
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2791
0
                               spec->directives, invalid_reason))
2792
0
              {
2793
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2794
0
                return false;
2795
0
              }
2796
0
            if (position >= 0)
2797
0
              add_req_type_constraint (&list, position++, FAT_OBJECT);
2798
0
            while (*format != '\0' && *format != '/')
2799
0
              format++;
2800
0
            if (*format == '\0')
2801
0
              {
2802
0
                *invalid_reason =
2803
0
                  xstrdup (_("The string ends in the middle of a ~/.../ directive."));
2804
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2805
0
                return false;
2806
0
              }
2807
0
            format++;
2808
0
            break;
2809
2810
0
          case '(': /* 22.3.8.1 FORMAT-CASE-CONVERSION */
2811
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2812
0
                               spec->directives, invalid_reason))
2813
0
              {
2814
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2815
0
                return false;
2816
0
              }
2817
0
            *formatp = format;
2818
0
            *positionp = position;
2819
0
            *listp = list;
2820
0
            *escapep = escape;
2821
0
            {
2822
0
              if (!parse_upto (formatp, positionp, listp, escapep,
2823
0
                               NULL, spec, ')', false,
2824
0
                               NULL, invalid_reason))
2825
0
                {
2826
0
                  FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
2827
0
                           FMTDIR_ERROR);
2828
0
                  return false;
2829
0
                }
2830
0
            }
2831
0
            format = *formatp;
2832
0
            position = *positionp;
2833
0
            list = *listp;
2834
0
            escape = *escapep;
2835
0
            break;
2836
2837
0
          case ')': /* 22.3.8.2 FORMAT-CASE-CONVERSION-END */
2838
0
            if (terminator != ')')
2839
0
              {
2840
0
                *invalid_reason =
2841
0
                  xasprintf (_("Found '~%c' without matching '~%c'."), ')', '(');
2842
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2843
0
                return false;
2844
0
              }
2845
0
            if (!check_params (&list, paramcount, params, 0, NULL,
2846
0
                               spec->directives, invalid_reason))
2847
0
              {
2848
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2849
0
                return false;
2850
0
              }
2851
0
            *formatp = format;
2852
0
            *positionp = position;
2853
0
            *listp = list;
2854
0
            *escapep = escape;
2855
0
            return true;
2856
2857
0
          case '[': /* 22.3.7.2 FORMAT-CONDITIONAL */
2858
0
            if (atsign_p && colon_p)
2859
0
              {
2860
0
                *invalid_reason =
2861
0
                  xasprintf (_("In the directive number %zu, both the @ and the : modifiers are given."), spec->directives);
2862
0
                FDI_SET (format - 1, FMTDIR_ERROR);
2863
0
                return false;
2864
0
              }
2865
0
            else if (atsign_p)
2866
0
              {
2867
0
                if (!check_params (&list, paramcount, params, 0, NULL,
2868
0
                                   spec->directives, invalid_reason))
2869
0
                  {
2870
0
                    FDI_SET (format - 1, FMTDIR_ERROR);
2871
0
                    return false;
2872
0
                  }
2873
2874
0
                *formatp = format;
2875
0
                *escapep = escape;
2876
2877
                /* First alternative: argument is NIL.  */
2878
0
                struct format_arg_list *nil_list =
2879
0
                  (list != NULL ? copy_list (list) : NULL);
2880
0
                if (position >= 0)
2881
0
                  {
2882
0
                    struct format_arg_list *empty_list = make_empty_list ();
2883
0
                    add_req_listtype_constraint (&nil_list, position,
2884
0
                                                 FAT_LIST, empty_list);
2885
0
                    free_list (empty_list);
2886
0
                  }
2887
2888
                /* Second alternative: use sub-format.  */
2889
0
                struct format_arg_list *union_list;
2890
0
                {
2891
0
                  int sub_position = position;
2892
0
                  struct format_arg_list *sub_list =
2893
0
                    (list != NULL ? copy_list (list) : NULL);
2894
0
                  if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2895
0
                                   NULL, spec, ']', false,
2896
0
                                   NULL, invalid_reason))
2897
0
                    {
2898
0
                      FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
2899
0
                               FMTDIR_ERROR);
2900
0
                      return false;
2901
0
                    }
2902
0
                  if (sub_list != NULL)
2903
0
                    {
2904
0
                      if (position >= 0)
2905
0
                        {
2906
0
                          if (sub_position == position + 1)
2907
                            /* new position is branch independent */
2908
0
                            position = position + 1;
2909
0
                          else
2910
                            /* new position is branch dependent */
2911
0
                            position = -1;
2912
0
                        }
2913
0
                    }
2914
0
                  else
2915
0
                    {
2916
0
                      if (position >= 0)
2917
0
                        position = position + 1;
2918
0
                    }
2919
0
                  union_list = union (nil_list, sub_list);
2920
0
                }
2921
2922
0
                format = *formatp;
2923
0
                escape = *escapep;
2924
2925
0
                if (list != NULL)
2926
0
                  free_list (list);
2927
0
                list = union_list;
2928
0
              }
2929
0
            else if (colon_p)
2930
0
              {
2931
0
                if (!check_params (&list, paramcount, params, 0, NULL,
2932
0
                                   spec->directives, invalid_reason))
2933
0
                  {
2934
0
                    FDI_SET (format - 1, FMTDIR_ERROR);
2935
0
                    return false;
2936
0
                  }
2937
2938
0
                if (position >= 0)
2939
0
                  add_req_type_constraint (&list, position++, FAT_OBJECT);
2940
2941
0
                *formatp = format;
2942
0
                *escapep = escape;
2943
0
                int union_position = -2;
2944
0
                struct format_arg_list *union_list = NULL;
2945
2946
                /* First alternative.  */
2947
0
                {
2948
0
                  int sub_position = position;
2949
0
                  struct format_arg_list *sub_list =
2950
0
                    (list != NULL ? copy_list (list) : NULL);
2951
0
                  int sub_separator = 0;
2952
0
                  if (position >= 0)
2953
0
                    {
2954
0
                      struct format_arg_list *empty_list = make_empty_list ();
2955
0
                      add_req_listtype_constraint (&sub_list, position - 1,
2956
0
                                                   FAT_LIST, empty_list);
2957
0
                      free_list (empty_list);
2958
0
                    }
2959
0
                  if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2960
0
                                   &sub_separator, spec, ']', true,
2961
0
                                   NULL, invalid_reason))
2962
0
                    {
2963
0
                      FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
2964
0
                               FMTDIR_ERROR);
2965
0
                      return false;
2966
0
                    }
2967
0
                  if (!sub_separator)
2968
0
                    {
2969
0
                      *invalid_reason =
2970
0
                        xasprintf (_("In the directive number %zu, '~:[' is not followed by two clauses, separated by '~;'."), spec->directives);
2971
0
                      FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
2972
0
                               FMTDIR_ERROR);
2973
0
                      return false;
2974
0
                    }
2975
0
                  if (sub_list != NULL)
2976
0
                    union_position = sub_position;
2977
0
                  union_list = union (union_list, sub_list);
2978
0
                }
2979
2980
                /* Second alternative.  */
2981
0
                {
2982
0
                  int sub_position = position;
2983
0
                  struct format_arg_list *sub_list =
2984
0
                    (list != NULL ? copy_list (list) : NULL);
2985
0
                  if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
2986
0
                                   NULL, spec, ']', false,
2987
0
                                   NULL, invalid_reason))
2988
0
                    {
2989
0
                      FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
2990
0
                               FMTDIR_ERROR);
2991
0
                      return false;
2992
0
                    }
2993
0
                  if (sub_list != NULL)
2994
0
                    {
2995
0
                      if (union_position == -2)
2996
0
                        union_position = sub_position;
2997
0
                      else if (sub_position < 0
2998
0
                               || sub_position != union_position)
2999
0
                        union_position = -1;
3000
0
                    }
3001
0
                  union_list = union (union_list, sub_list);
3002
0
                }
3003
3004
0
                format = *formatp;
3005
0
                escape = *escapep;
3006
3007
0
                if (union_position != -2)
3008
0
                  position = union_position;
3009
0
                if (list != NULL)
3010
0
                  free_list (list);
3011
0
                list = union_list;
3012
0
              }
3013
0
            else
3014
0
              {
3015
0
                if (!check_params (&list, paramcount, params, 1, I,
3016
0
                                   spec->directives, invalid_reason))
3017
0
                  {
3018
0
                    FDI_SET (format - 1, FMTDIR_ERROR);
3019
0
                    return false;
3020
0
                  }
3021
3022
                /* If there was no first parameter, an argument is consumed.  */
3023
0
                int arg_position = -1;
3024
0
                if (!(paramcount >= 1 && params[0].type != PT_NIL))
3025
0
                  if (position >= 0)
3026
0
                    {
3027
0
                      arg_position = position;
3028
0
                      add_req_type_constraint (&list, position++, FAT_OBJECT);
3029
0
                    }
3030
3031
0
                *formatp = format;
3032
0
                *escapep = escape;
3033
3034
0
                int union_position = -2;
3035
0
                struct format_arg_list *union_list = NULL;
3036
0
                bool last_alternative = false;
3037
0
                for (;;)
3038
0
                  {
3039
                    /* Next alternative.  */
3040
0
                    int sub_position = position;
3041
0
                    struct format_arg_list *sub_list =
3042
0
                      (list != NULL ? copy_list (list) : NULL);
3043
0
                    int sub_separator = 0;
3044
0
                    if (!parse_upto (formatp, &sub_position, &sub_list, escapep,
3045
0
                                     &sub_separator, spec, ']', !last_alternative,
3046
0
                                     NULL, invalid_reason))
3047
0
                      {
3048
0
                        FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
3049
0
                                 FMTDIR_ERROR);
3050
0
                        return false;
3051
0
                      }
3052
                    /* If this alternative is chosen, the argument arg_position
3053
                       is an integer, namely the index of this alternative.  */
3054
0
                    if (!last_alternative && arg_position >= 0)
3055
0
                      add_req_type_constraint (&sub_list, arg_position,
3056
0
                                               FAT_INTEGER);
3057
0
                    if (sub_list != NULL)
3058
0
                      {
3059
0
                        if (union_position == -2)
3060
0
                          union_position = sub_position;
3061
0
                        else if (sub_position < 0
3062
0
                                 || sub_position != union_position)
3063
0
                          union_position = -1;
3064
0
                      }
3065
0
                    union_list = union (union_list, sub_list);
3066
0
                    if (sub_separator == 2)
3067
0
                      last_alternative = true;
3068
0
                    if (!sub_separator)
3069
0
                      break;
3070
0
                  }
3071
0
                if (!last_alternative)
3072
0
                  {
3073
                    /* An implicit default alternative.  */
3074
0
                    if (union_position == -2)
3075
0
                      union_position = position;
3076
0
                    else if (position < 0 || position != union_position)
3077
0
                      union_position = -1;
3078
0
                    if (list != NULL)
3079
0
                      union_list = union (union_list, copy_list (list));
3080
0
                  }
3081
3082
0
                format = *formatp;
3083
0
                escape = *escapep;
3084
3085
0
                if (union_position != -2)
3086
0
                  position = union_position;
3087
0
                if (list != NULL)
3088
0
                  free_list (list);
3089
0
                list = union_list;
3090
0
              }
3091
0
            break;
3092
3093
0
          case ']': /* 22.3.7.3 FORMAT-CONDITIONAL-END */
3094
0
            if (terminator != ']')
3095
0
              {
3096
0
                *invalid_reason =
3097
0
                  xasprintf (_("Found '~%c' without matching '~%c'."), ']', '[');
3098
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3099
0
                return false;
3100
0
              }
3101
0
            if (!check_params (&list, paramcount, params, 0, NULL,
3102
0
                               spec->directives, invalid_reason))
3103
0
              {
3104
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3105
0
                return false;
3106
0
              }
3107
0
            *formatp = format;
3108
0
            *positionp = position;
3109
0
            *listp = list;
3110
0
            *escapep = escape;
3111
0
            return true;
3112
3113
0
          case '{': /* 22.3.7.4 FORMAT-ITERATION */
3114
0
            if (!check_params (&list, paramcount, params, 1, I,
3115
0
                               spec->directives, invalid_reason))
3116
0
              {
3117
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3118
0
                return false;
3119
0
              }
3120
0
            *formatp = format;
3121
0
            {
3122
0
              int sub_position = 0;
3123
0
              struct format_arg_list *sub_list = make_unconstrained_list ();
3124
0
              struct format_arg_list *sub_escape = NULL;
3125
0
              struct spec sub_spec;
3126
0
              sub_spec.directives = 0;
3127
0
              sub_spec.list = sub_list;
3128
0
              if (!parse_upto (formatp, &sub_position, &sub_list, &sub_escape,
3129
0
                               NULL, &sub_spec, '}', false,
3130
0
                               NULL, invalid_reason))
3131
0
                {
3132
0
                  FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
3133
0
                           FMTDIR_ERROR);
3134
0
                  return false;
3135
0
                }
3136
0
              spec->directives += sub_spec.directives;
3137
3138
              /* If the sub-formatstring is empty, except for the terminating
3139
                 ~} directive, a formatstring argument is consumed.  */
3140
0
              if (*format == '~' && sub_spec.directives == 1)
3141
0
                if (position >= 0)
3142
0
                  add_req_type_constraint (&list, position++, FAT_FORMATSTRING);
3143
3144
0
              if (colon_p)
3145
0
                {
3146
                  /* Each iteration uses a new sublist.  */
3147
3148
                  /* ~{ catches ~^.  */
3149
0
                  sub_list = union (sub_list, sub_escape);
3150
3151
0
                  struct format_arg_list *listlist =
3152
0
                    make_repeated_list_of_lists (sub_list);
3153
3154
0
                  sub_list = listlist;
3155
0
                }
3156
0
              else
3157
0
                {
3158
                  /* Each iteration's arguments are all concatenated in a
3159
                     single list.  */
3160
3161
                  /* FIXME: This is far from correct.  Test cases:
3162
                     abc~{~^~}
3163
                     abc~{~S~^~S~}
3164
                     abc~{~D~^~C~}
3165
                     abc~{~D~^~D~}
3166
                     abc~{~D~^~S~}
3167
                     abc~{~D~^~C~}~:*~{~S~^~D~}
3168
                   */
3169
3170
                  /* ~{ catches ~^.  */
3171
0
                  sub_list = union (sub_list, sub_escape);
3172
3173
0
                  struct format_arg_list *looplist;
3174
0
                  if (sub_list == NULL)
3175
0
                    looplist = make_empty_list ();
3176
0
                  else
3177
0
                    if (sub_position < 0 || sub_position == 0)
3178
                      /* Too hard to track the possible argument types
3179
                         when the iteration is performed 2 times or more.
3180
                         So be satisfied with the constraints of executing
3181
                         the iteration 1 or 0 times.  */
3182
0
                      looplist = make_union_with_empty_list (sub_list);
3183
0
                    else
3184
0
                      looplist = make_repeated_list (sub_list, sub_position);
3185
3186
0
                  sub_list = looplist;
3187
0
                }
3188
3189
0
              if (atsign_p)
3190
0
                {
3191
                  /* All remaining arguments are used.  */
3192
0
                  if (list != NULL && position >= 0)
3193
0
                    {
3194
0
                      shift_list (sub_list, position);
3195
0
                      list = make_intersected_list (list, sub_list);
3196
0
                    }
3197
0
                  position = -1;
3198
0
                }
3199
0
              else
3200
0
                {
3201
                  /* The argument is a list.  */
3202
0
                  if (position >= 0)
3203
0
                    add_req_listtype_constraint (&list, position++,
3204
0
                                                 FAT_LIST, sub_list);
3205
0
                }
3206
0
            }
3207
0
            format = *formatp;
3208
0
            break;
3209
3210
0
          case '}': /* 22.3.7.5 FORMAT-ITERATION-END */
3211
0
            if (terminator != '}')
3212
0
              {
3213
0
                *invalid_reason =
3214
0
                  xasprintf (_("Found '~%c' without matching '~%c'."), '}', '{');
3215
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3216
0
                return false;
3217
0
              }
3218
0
            if (!check_params (&list, paramcount, params, 0, NULL,
3219
0
                               spec->directives, invalid_reason))
3220
0
              {
3221
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3222
0
                return false;
3223
0
              }
3224
0
            *formatp = format;
3225
0
            *positionp = position;
3226
0
            *listp = list;
3227
0
            *escapep = escape;
3228
0
            return true;
3229
3230
0
          case '<': /* 22.3.6.2, 22.3.5.2 FORMAT-JUSTIFICATION */
3231
0
            if (!check_params (&list, paramcount, params, 4, IIIC,
3232
0
                               spec->directives, invalid_reason))
3233
0
              {
3234
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3235
0
                return false;
3236
0
              }
3237
0
            {
3238
0
              struct format_arg_list *sub_escape = NULL;
3239
3240
0
              *formatp = format;
3241
0
              *positionp = position;
3242
0
              *listp = list;
3243
3244
0
              for (;;)
3245
0
                {
3246
0
                  int sub_separator = 0;
3247
0
                  if (!parse_upto (formatp, positionp, listp, &sub_escape,
3248
0
                                   &sub_separator, spec, '>', true,
3249
0
                                   NULL, invalid_reason))
3250
0
                    {
3251
0
                      FDI_SET (**formatp == '\0' ? *formatp - 1 : *formatp,
3252
0
                               FMTDIR_ERROR);
3253
0
                      return false;
3254
0
                    }
3255
0
                  if (!sub_separator)
3256
0
                    break;
3257
0
                }
3258
3259
0
              format = *formatp;
3260
0
              position = *positionp;
3261
0
              list = *listp;
3262
3263
              /* ~< catches ~^.  */
3264
0
              if (sub_escape != NULL)
3265
0
                position = -1;
3266
0
              list = union (list, sub_escape);
3267
0
            }
3268
0
            break;
3269
3270
0
          case '>': /* 22.3.6.3 FORMAT-JUSTIFICATION-END */
3271
0
            if (terminator != '>')
3272
0
              {
3273
0
                *invalid_reason =
3274
0
                  xasprintf (_("Found '~%c' without matching '~%c'."), '>', '<');
3275
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3276
0
                return false;
3277
0
              }
3278
0
            if (!check_params (&list, paramcount, params, 0, NULL,
3279
0
                               spec->directives, invalid_reason))
3280
0
              {
3281
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3282
0
                return false;
3283
0
              }
3284
0
            *formatp = format;
3285
0
            *positionp = position;
3286
0
            *listp = list;
3287
0
            *escapep = escape;
3288
0
            return true;
3289
3290
0
          case '^': /* 22.3.9.2 FORMAT-UP-AND-OUT */
3291
0
            if (!check_params (&list, paramcount, params, 3, THREE,
3292
0
                               spec->directives, invalid_reason))
3293
0
              {
3294
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3295
0
                return false;
3296
0
              }
3297
0
            if (position >= 0 && list != NULL && is_required (list, position))
3298
              /* This ~^ can never be executed.  Ignore it.  */
3299
0
              break;
3300
0
            if (list != NULL)
3301
0
              {
3302
0
                struct format_arg_list *this_escape = copy_list (list);
3303
0
                if (position >= 0)
3304
0
                  this_escape = add_end_constraint (this_escape, position);
3305
0
                escape = union (escape, this_escape);
3306
0
              }
3307
0
            if (position >= 0)
3308
0
              list = add_required_constraint (list, position);
3309
0
            break;
3310
3311
0
          case ';': /* 22.3.9.1 FORMAT-SEPARATOR */
3312
0
            if (!separator)
3313
0
              {
3314
0
                *invalid_reason =
3315
0
                  xasprintf (_("In the directive number %zu, '~;' is used in an invalid position."), spec->directives);
3316
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3317
0
                return false;
3318
0
              }
3319
0
            if (terminator == '>')
3320
0
              {
3321
0
                if (!check_params (&list, paramcount, params, 1, I,
3322
0
                                   spec->directives, invalid_reason))
3323
0
                  {
3324
0
                    FDI_SET (format - 1, FMTDIR_ERROR);
3325
0
                    return false;
3326
0
                  }
3327
0
              }
3328
0
            else
3329
0
              {
3330
0
                if (!check_params (&list, paramcount, params, 0, NULL,
3331
0
                                   spec->directives, invalid_reason))
3332
0
                  {
3333
0
                    FDI_SET (format - 1, FMTDIR_ERROR);
3334
0
                    return false;
3335
0
                  }
3336
0
              }
3337
0
            *formatp = format;
3338
0
            *positionp = position;
3339
0
            *listp = list;
3340
0
            *escapep = escape;
3341
0
            *separatorp = (colon_p ? 2 : 1);
3342
0
            return true;
3343
3344
0
          case '!': /* FORMAT-CALL, a CLISP extension */
3345
0
            if (!nocheck_params (&list, paramcount, params,
3346
0
                                 spec->directives, invalid_reason))
3347
0
              {
3348
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3349
0
                return false;
3350
0
              }
3351
0
            if (position >= 0)
3352
0
              {
3353
0
                add_req_type_constraint (&list, position++, FAT_FUNCTION);
3354
0
                add_req_type_constraint (&list, position++, FAT_OBJECT);
3355
0
              }
3356
0
            break;
3357
3358
0
          default:
3359
0
            --format;
3360
0
            if (*format == '\0')
3361
0
              {
3362
0
                *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
3363
0
                FDI_SET (format - 1, FMTDIR_ERROR);
3364
0
              }
3365
0
            else
3366
0
              {
3367
0
                *invalid_reason =
3368
0
                  INVALID_CONVERSION_SPECIFIER (spec->directives, *format);
3369
0
                FDI_SET (format, FMTDIR_ERROR);
3370
0
              }
3371
0
            return false;
3372
0
          }
3373
3374
0
        FDI_SET (format - 1, FMTDIR_END);
3375
3376
0
        free (params);
3377
0
      }
3378
3379
0
  *formatp = format;
3380
0
  *positionp = position;
3381
0
  *listp = list;
3382
0
  *escapep = escape;
3383
0
  if (terminator != '\0')
3384
0
    {
3385
0
      *invalid_reason =
3386
0
        xasprintf (_("Found '~%c' without matching '~%c'."), terminator - 1, terminator);
3387
0
      return false;
3388
0
    }
3389
0
  return true;
3390
0
}
3391
3392
3393
/* ============== Top level format string handling functions ============== */
3394
3395
static void *
3396
format_parse (const char *format, bool translated, char *fdi,
3397
              char **invalid_reason)
3398
0
{
3399
0
  struct spec spec;
3400
0
  spec.directives = 0;
3401
0
  spec.list = make_unconstrained_list ();
3402
3403
0
  int position = 0;
3404
0
  struct format_arg_list *escape = NULL;
3405
3406
0
  if (!parse_upto (&format, &position, &spec.list, &escape,
3407
0
                   NULL, &spec, '\0', false,
3408
0
                   fdi, invalid_reason))
3409
    /* Invalid format string.  */
3410
0
    return NULL;
3411
3412
  /* Catch ~^ here.  */
3413
0
  spec.list = union (spec.list, escape);
3414
3415
0
  if (spec.list == NULL)
3416
0
    {
3417
      /* Contradictory argument type information.  */
3418
0
      *invalid_reason =
3419
0
        xstrdup (_("The string refers to some argument in incompatible ways."));
3420
0
      return NULL;
3421
0
    }
3422
3423
  /* Normalize the result.  */
3424
0
  normalize_list (spec.list);
3425
3426
0
  struct spec *result = XMALLOC (struct spec);
3427
0
  *result = spec;
3428
0
  return result;
3429
0
}
3430
3431
static void
3432
format_free (void *descr)
3433
0
{
3434
0
  struct spec *spec = (struct spec *) descr;
3435
3436
0
  free_list (spec->list);
3437
0
}
3438
3439
static int
3440
format_get_number_of_directives (void *descr)
3441
0
{
3442
0
  struct spec *spec = (struct spec *) descr;
3443
3444
0
  return spec->directives;
3445
0
}
3446
3447
static bool
3448
format_check (void *msgid_descr, void *msgstr_descr, bool equality,
3449
              formatstring_error_logger_t error_logger, void *error_logger_data,
3450
              const char *pretty_msgid, const char *pretty_msgstr)
3451
0
{
3452
0
  struct spec *spec1 = (struct spec *) msgid_descr;
3453
0
  struct spec *spec2 = (struct spec *) msgstr_descr;
3454
0
  bool err = false;
3455
3456
0
  if (equality)
3457
0
    {
3458
0
      if (!equal_list (spec1->list, spec2->list))
3459
0
        {
3460
0
          if (error_logger)
3461
0
            error_logger (error_logger_data,
3462
0
                          _("format specifications in '%s' and '%s' are not equivalent"),
3463
0
                          pretty_msgid, pretty_msgstr);
3464
0
          err = true;
3465
0
        }
3466
0
    }
3467
0
  else
3468
0
    {
3469
0
      struct format_arg_list *intersection =
3470
0
        make_intersected_list (copy_list (spec1->list),
3471
0
                               copy_list (spec2->list));
3472
3473
0
      if (!(intersection != NULL
3474
0
            && (normalize_list (intersection),
3475
0
                equal_list (intersection, spec1->list))))
3476
0
        {
3477
0
          if (error_logger)
3478
0
            error_logger (error_logger_data,
3479
0
                          _("format specifications in '%s' are not a subset of those in '%s'"),
3480
0
                          pretty_msgstr, pretty_msgid);
3481
0
          err = true;
3482
0
        }
3483
0
    }
3484
3485
0
  return err;
3486
0
}
3487
3488
3489
struct formatstring_parser formatstring_lisp =
3490
{
3491
  format_parse,
3492
  format_free,
3493
  format_get_number_of_directives,
3494
  NULL,
3495
  format_check
3496
};
3497
3498
3499
/* ============================= Testing code ============================= */
3500
3501
#undef union
3502
3503
#ifdef TEST
3504
3505
/* Test program: Print the argument list specification returned by
3506
   format_parse for strings read from standard input.  */
3507
3508
#include <stdio.h>
3509
3510
static void print_list (struct format_arg_list *list);
3511
3512
static void
3513
print_element (struct format_arg *element)
3514
{
3515
  switch (element->presence)
3516
    {
3517
    case FCT_REQUIRED:
3518
      break;
3519
    case FCT_OPTIONAL:
3520
      printf (". ");
3521
      break;
3522
    default:
3523
      abort ();
3524
    }
3525
3526
  switch (element->type)
3527
    {
3528
    case FAT_OBJECT:
3529
      printf ("*");
3530
      break;
3531
    case FAT_CHARACTER_INTEGER_NULL:
3532
      printf ("ci()");
3533
      break;
3534
    case FAT_CHARACTER_NULL:
3535
      printf ("c()");
3536
      break;
3537
    case FAT_CHARACTER:
3538
      printf ("c");
3539
      break;
3540
    case FAT_INTEGER_NULL:
3541
      printf ("i()");
3542
      break;
3543
    case FAT_INTEGER:
3544
      printf ("i");
3545
      break;
3546
    case FAT_REAL:
3547
      printf ("r");
3548
      break;
3549
    case FAT_LIST:
3550
      print_list (element->list);
3551
      break;
3552
    case FAT_FORMATSTRING:
3553
      printf ("~");
3554
      break;
3555
    case FAT_FUNCTION:
3556
      printf ("f");
3557
      break;
3558
    default:
3559
      abort ();
3560
    }
3561
}
3562
3563
static void
3564
print_list (struct format_arg_list *list)
3565
{
3566
  printf ("(");
3567
3568
  for (size_t i = 0; i < list->initial.count; i++)
3569
    for (size_t j = 0; j < list->initial.element[i].repcount; j++)
3570
      {
3571
        if (i > 0 || j > 0)
3572
          printf (" ");
3573
        print_element (&list->initial.element[i]);
3574
      }
3575
3576
  if (list->repeated.count > 0)
3577
    {
3578
      printf (" |");
3579
      for (size_t i = 0; i < list->repeated.count; i++)
3580
        for (size_t j = 0; j < list->repeated.element[i].repcount; j++)
3581
          {
3582
            printf (" ");
3583
            print_element (&list->repeated.element[i]);
3584
          }
3585
    }
3586
3587
  printf (")");
3588
}
3589
3590
static void
3591
format_print (void *descr)
3592
{
3593
  struct spec *spec = (struct spec *) descr;
3594
3595
  if (spec == NULL)
3596
    {
3597
      printf ("INVALID");
3598
      return;
3599
    }
3600
3601
  print_list (spec->list);
3602
}
3603
3604
int
3605
main ()
3606
{
3607
  for (;;)
3608
    {
3609
      char *line = NULL;
3610
      size_t line_size = 0;
3611
      int line_len = getline (&line, &line_size, stdin);
3612
      if (line_len < 0)
3613
        break;
3614
      if (line_len > 0 && line[line_len - 1] == '\n')
3615
        line[--line_len] = '\0';
3616
3617
      char *invalid_reason = NULL;
3618
      void *descr = format_parse (line, false, NULL, &invalid_reason);
3619
3620
      format_print (descr);
3621
      printf ("\n");
3622
      if (descr == NULL)
3623
        printf ("%s\n", invalid_reason);
3624
3625
      free (invalid_reason);
3626
      free (line);
3627
    }
3628
3629
  return 0;
3630
}
3631
3632
/*
3633
 * For Emacs M-x compile
3634
 * Local Variables:
3635
 * compile-command: "/bin/sh ../libtool --tag=CC --mode=link gcc -o a.out -static -O -g -Wall -I.. -I../gnulib-lib -I../../gettext-runtime/intl -DTEST format-lisp.c ../gnulib-lib/libgettextlib.la"
3636
 * End:
3637
 */
3638
3639
#endif /* TEST */