Coverage Report

Created: 2026-04-29 07:00

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