~ubuntu-branches/ubuntu/utopic/gettext/utopic

« back to all changes in this revision

Viewing changes to gettext-tools/src/format-elisp.c

  • Committer: Colin Watson
  • Date: 2010-08-01 21:36:08 UTC
  • mfrom: (2.1.10 sid)
  • Revision ID: cjwatson@canonical.com-20100801213608-yy7vkm8lpatep3ci
merge from Debian 0.18.1.1-1

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* Emacs Lisp format strings.
2
 
   Copyright (C) 2001-2004, 2006-2007 Free Software Foundation, Inc.
 
2
   Copyright (C) 2001-2004, 2006-2007, 2009 Free Software Foundation, Inc.
3
3
   Written by Bruno Haible <haible@clisp.cons.org>, 2002.
4
4
 
5
5
   This program is free software: you can redistribute it and/or modify
95
95
 
96
96
static void *
97
97
format_parse (const char *format, bool translated, char *fdi,
98
 
              char **invalid_reason)
 
98
              char **invalid_reason)
99
99
{
100
100
  const char *const format_start = format;
101
101
  struct spec spec;
111
111
  for (; *format != '\0';)
112
112
    if (*format++ == '%')
113
113
      {
114
 
        /* A directive.  */
115
 
        enum format_arg_type type;
116
 
 
117
 
        FDI_SET (format - 1, FMTDIR_START);
118
 
        spec.directives++;
119
 
 
120
 
        if (isdigit (*format))
121
 
          {
122
 
            const char *f = format;
123
 
            unsigned int m = 0;
124
 
 
125
 
            do
126
 
              {
127
 
                m = 10 * m + (*f - '0');
128
 
                f++;
129
 
              }
130
 
            while (isdigit (*f));
131
 
 
132
 
            if (*f == '$' && m > 0)
133
 
              {
134
 
                number = m;
135
 
                format = ++f;
136
 
              }
137
 
          }
138
 
 
139
 
        /* Parse flags.  */
140
 
        while (*format == ' ' || *format == '+' || *format == '-'
141
 
               || *format == '#' || *format == '0')
142
 
          format++;
143
 
 
144
 
        /* Parse width.  */
145
 
        if (*format == '*')
146
 
          {
147
 
            format++;
148
 
 
149
 
            if (spec.allocated == spec.numbered_arg_count)
150
 
              {
151
 
                spec.allocated = 2 * spec.allocated + 1;
152
 
                spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
153
 
              }
154
 
            spec.numbered[spec.numbered_arg_count].number = number;
155
 
            spec.numbered[spec.numbered_arg_count].type = FAT_INTEGER;
156
 
            spec.numbered_arg_count++;
157
 
 
158
 
            number++;
159
 
          }
160
 
        else if (isdigit (*format))
161
 
          {
162
 
            do format++; while (isdigit (*format));
163
 
          }
164
 
 
165
 
        /* Parse precision.  */
166
 
        if (*format == '.')
167
 
          {
168
 
            format++;
169
 
 
170
 
            if (*format == '*')
171
 
              {
172
 
                format++;
173
 
 
174
 
                if (spec.allocated == spec.numbered_arg_count)
175
 
                  {
176
 
                    spec.allocated = 2 * spec.allocated + 1;
177
 
                    spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
178
 
                  }
179
 
                spec.numbered[spec.numbered_arg_count].number = number;
180
 
                spec.numbered[spec.numbered_arg_count].type = FAT_INTEGER;
181
 
                spec.numbered_arg_count++;
182
 
 
183
 
                number++;
184
 
              }
185
 
            else if (isdigit (*format))
186
 
              {
187
 
                do format++; while (isdigit (*format));
188
 
              }
189
 
          }
190
 
 
191
 
        switch (*format)
192
 
          {
193
 
          case '%':
194
 
            type = FAT_NONE;
195
 
            break;
196
 
          case 'c':
197
 
            type = FAT_CHARACTER;
198
 
            break;
199
 
          case 'd': case 'i': case 'x': case 'X': case 'o':
200
 
            type = FAT_INTEGER;
201
 
            break;
202
 
          case 'e': case 'E': case 'f': case 'g': case 'G':
203
 
            type = FAT_FLOAT;
204
 
            break;
205
 
          case 's':
206
 
            type = FAT_OBJECT_PRETTY;
207
 
            break;
208
 
          case 'S':
209
 
            type = FAT_OBJECT;
210
 
            break;
211
 
          default:
212
 
            if (*format == '\0')
213
 
              {
214
 
                *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
215
 
                FDI_SET (format - 1, FMTDIR_ERROR);
216
 
              }
217
 
            else
218
 
              {
219
 
                *invalid_reason =
220
 
                  INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
221
 
                FDI_SET (format, FMTDIR_ERROR);
222
 
              }
223
 
            goto bad_format;
224
 
          }
225
 
 
226
 
        if (type != FAT_NONE)
227
 
          {
228
 
            if (spec.allocated == spec.numbered_arg_count)
229
 
              {
230
 
                spec.allocated = 2 * spec.allocated + 1;
231
 
                spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
232
 
              }
233
 
            spec.numbered[spec.numbered_arg_count].number = number;
234
 
            spec.numbered[spec.numbered_arg_count].type = type;
235
 
            spec.numbered_arg_count++;
236
 
 
237
 
            number++;
238
 
          }
239
 
 
240
 
        FDI_SET (format, FMTDIR_END);
241
 
 
242
 
        format++;
 
114
        /* A directive.  */
 
115
        enum format_arg_type type;
 
116
 
 
117
        FDI_SET (format - 1, FMTDIR_START);
 
118
        spec.directives++;
 
119
 
 
120
        if (isdigit (*format))
 
121
          {
 
122
            const char *f = format;
 
123
            unsigned int m = 0;
 
124
 
 
125
            do
 
126
              {
 
127
                m = 10 * m + (*f - '0');
 
128
                f++;
 
129
              }
 
130
            while (isdigit (*f));
 
131
 
 
132
            if (*f == '$' && m > 0)
 
133
              {
 
134
                number = m;
 
135
                format = ++f;
 
136
              }
 
137
          }
 
138
 
 
139
        /* Parse flags.  */
 
140
        while (*format == ' ' || *format == '+' || *format == '-'
 
141
               || *format == '#' || *format == '0')
 
142
          format++;
 
143
 
 
144
        /* Parse width.  */
 
145
        if (*format == '*')
 
146
          {
 
147
            format++;
 
148
 
 
149
            if (spec.allocated == spec.numbered_arg_count)
 
150
              {
 
151
                spec.allocated = 2 * spec.allocated + 1;
 
152
                spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
 
153
              }
 
154
            spec.numbered[spec.numbered_arg_count].number = number;
 
155
            spec.numbered[spec.numbered_arg_count].type = FAT_INTEGER;
 
156
            spec.numbered_arg_count++;
 
157
 
 
158
            number++;
 
159
          }
 
160
        else if (isdigit (*format))
 
161
          {
 
162
            do format++; while (isdigit (*format));
 
163
          }
 
164
 
 
165
        /* Parse precision.  */
 
166
        if (*format == '.')
 
167
          {
 
168
            format++;
 
169
 
 
170
            if (*format == '*')
 
171
              {
 
172
                format++;
 
173
 
 
174
                if (spec.allocated == spec.numbered_arg_count)
 
175
                  {
 
176
                    spec.allocated = 2 * spec.allocated + 1;
 
177
                    spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
 
178
                  }
 
179
                spec.numbered[spec.numbered_arg_count].number = number;
 
180
                spec.numbered[spec.numbered_arg_count].type = FAT_INTEGER;
 
181
                spec.numbered_arg_count++;
 
182
 
 
183
                number++;
 
184
              }
 
185
            else if (isdigit (*format))
 
186
              {
 
187
                do format++; while (isdigit (*format));
 
188
              }
 
189
          }
 
190
 
 
191
        switch (*format)
 
192
          {
 
193
          case '%':
 
194
            type = FAT_NONE;
 
195
            break;
 
196
          case 'c':
 
197
            type = FAT_CHARACTER;
 
198
            break;
 
199
          case 'd': case 'i': case 'x': case 'X': case 'o':
 
200
            type = FAT_INTEGER;
 
201
            break;
 
202
          case 'e': case 'E': case 'f': case 'g': case 'G':
 
203
            type = FAT_FLOAT;
 
204
            break;
 
205
          case 's':
 
206
            type = FAT_OBJECT_PRETTY;
 
207
            break;
 
208
          case 'S':
 
209
            type = FAT_OBJECT;
 
210
            break;
 
211
          default:
 
212
            if (*format == '\0')
 
213
              {
 
214
                *invalid_reason = INVALID_UNTERMINATED_DIRECTIVE ();
 
215
                FDI_SET (format - 1, FMTDIR_ERROR);
 
216
              }
 
217
            else
 
218
              {
 
219
                *invalid_reason =
 
220
                  INVALID_CONVERSION_SPECIFIER (spec.directives, *format);
 
221
                FDI_SET (format, FMTDIR_ERROR);
 
222
              }
 
223
            goto bad_format;
 
224
          }
 
225
 
 
226
        if (type != FAT_NONE)
 
227
          {
 
228
            if (spec.allocated == spec.numbered_arg_count)
 
229
              {
 
230
                spec.allocated = 2 * spec.allocated + 1;
 
231
                spec.numbered = (struct numbered_arg *) xrealloc (spec.numbered, spec.allocated * sizeof (struct numbered_arg));
 
232
              }
 
233
            spec.numbered[spec.numbered_arg_count].number = number;
 
234
            spec.numbered[spec.numbered_arg_count].type = type;
 
235
            spec.numbered_arg_count++;
 
236
 
 
237
            number++;
 
238
          }
 
239
 
 
240
        FDI_SET (format, FMTDIR_END);
 
241
 
 
242
        format++;
243
243
      }
244
244
 
245
245
  /* Sort the numbered argument array, and eliminate duplicates.  */
249
249
      bool err;
250
250
 
251
251
      qsort (spec.numbered, spec.numbered_arg_count,
252
 
             sizeof (struct numbered_arg), numbered_arg_compare);
 
252
             sizeof (struct numbered_arg), numbered_arg_compare);
253
253
 
254
254
      /* Remove duplicates: Copy from i to j, keeping 0 <= j <= i.  */
255
255
      err = false;
256
256
      for (i = j = 0; i < spec.numbered_arg_count; i++)
257
 
        if (j > 0 && spec.numbered[i].number == spec.numbered[j-1].number)
258
 
          {
259
 
            enum format_arg_type type1 = spec.numbered[i].type;
260
 
            enum format_arg_type type2 = spec.numbered[j-1].type;
261
 
            enum format_arg_type type_both;
262
 
 
263
 
            if (type1 == type2)
264
 
              type_both = type1;
265
 
            else
266
 
              {
267
 
                /* Incompatible types.  */
268
 
                type_both = FAT_NONE;
269
 
                if (!err)
270
 
                  *invalid_reason =
271
 
                    INVALID_INCOMPATIBLE_ARG_TYPES (spec.numbered[i].number);
272
 
                err = true;
273
 
              }
274
 
 
275
 
            spec.numbered[j-1].type = type_both;
276
 
          }
277
 
        else
278
 
          {
279
 
            if (j < i)
280
 
              {
281
 
                spec.numbered[j].number = spec.numbered[i].number;
282
 
                spec.numbered[j].type = spec.numbered[i].type;
283
 
              }
284
 
            j++;
285
 
          }
 
257
        if (j > 0 && spec.numbered[i].number == spec.numbered[j-1].number)
 
258
          {
 
259
            enum format_arg_type type1 = spec.numbered[i].type;
 
260
            enum format_arg_type type2 = spec.numbered[j-1].type;
 
261
            enum format_arg_type type_both;
 
262
 
 
263
            if (type1 == type2)
 
264
              type_both = type1;
 
265
            else
 
266
              {
 
267
                /* Incompatible types.  */
 
268
                type_both = FAT_NONE;
 
269
                if (!err)
 
270
                  *invalid_reason =
 
271
                    INVALID_INCOMPATIBLE_ARG_TYPES (spec.numbered[i].number);
 
272
                err = true;
 
273
              }
 
274
 
 
275
            spec.numbered[j-1].type = type_both;
 
276
          }
 
277
        else
 
278
          {
 
279
            if (j < i)
 
280
              {
 
281
                spec.numbered[j].number = spec.numbered[i].number;
 
282
                spec.numbered[j].type = spec.numbered[i].type;
 
283
              }
 
284
            j++;
 
285
          }
286
286
      spec.numbered_arg_count = j;
287
287
      if (err)
288
 
        /* *invalid_reason has already been set above.  */
289
 
        goto bad_format;
 
288
        /* *invalid_reason has already been set above.  */
 
289
        goto bad_format;
290
290
    }
291
291
 
292
292
  result = XMALLOC (struct spec);
319
319
 
320
320
static bool
321
321
format_check (void *msgid_descr, void *msgstr_descr, bool equality,
322
 
              formatstring_error_logger_t error_logger,
323
 
              const char *pretty_msgstr)
 
322
              formatstring_error_logger_t error_logger,
 
323
              const char *pretty_msgid, const char *pretty_msgstr)
324
324
{
325
325
  struct spec *spec1 = (struct spec *) msgid_descr;
326
326
  struct spec *spec2 = (struct spec *) msgstr_descr;
333
333
      unsigned int n2 = spec2->numbered_arg_count;
334
334
 
335
335
      /* Check the argument names are the same.
336
 
         Both arrays are sorted.  We search for the first difference.  */
 
336
         Both arrays are sorted.  We search for the first difference.  */
337
337
      for (i = 0, j = 0; i < n1 || j < n2; )
338
 
        {
339
 
          int cmp = (i >= n1 ? 1 :
340
 
                     j >= n2 ? -1 :
341
 
                     spec1->numbered[i].number > spec2->numbered[j].number ? 1 :
342
 
                     spec1->numbered[i].number < spec2->numbered[j].number ? -1 :
343
 
                     0);
 
338
        {
 
339
          int cmp = (i >= n1 ? 1 :
 
340
                     j >= n2 ? -1 :
 
341
                     spec1->numbered[i].number > spec2->numbered[j].number ? 1 :
 
342
                     spec1->numbered[i].number < spec2->numbered[j].number ? -1 :
 
343
                     0);
344
344
 
345
 
          if (cmp > 0)
346
 
            {
347
 
              if (error_logger)
348
 
                error_logger (_("a format specification for argument %u, as in '%s', doesn't exist in 'msgid'"),
349
 
                              spec2->numbered[j].number, pretty_msgstr);
350
 
              err = true;
351
 
              break;
352
 
            }
353
 
          else if (cmp < 0)
354
 
            {
355
 
              if (equality)
356
 
                {
357
 
                  if (error_logger)
358
 
                    error_logger (_("a format specification for argument %u doesn't exist in '%s'"),
359
 
                                  spec1->numbered[i].number, pretty_msgstr);
360
 
                  err = true;
361
 
                  break;
362
 
                }
363
 
              else
364
 
                i++;
365
 
            }
366
 
          else
367
 
            j++, i++;
368
 
        }
 
345
          if (cmp > 0)
 
346
            {
 
347
              if (error_logger)
 
348
                error_logger (_("a format specification for argument %u, as in '%s', doesn't exist in '%s'"),
 
349
                              spec2->numbered[j].number, pretty_msgstr,
 
350
                              pretty_msgid);
 
351
              err = true;
 
352
              break;
 
353
            }
 
354
          else if (cmp < 0)
 
355
            {
 
356
              if (equality)
 
357
                {
 
358
                  if (error_logger)
 
359
                    error_logger (_("a format specification for argument %u doesn't exist in '%s'"),
 
360
                                  spec1->numbered[i].number, pretty_msgstr);
 
361
                  err = true;
 
362
                  break;
 
363
                }
 
364
              else
 
365
                i++;
 
366
            }
 
367
          else
 
368
            j++, i++;
 
369
        }
369
370
      /* Check the argument types are the same.  */
370
371
      if (!err)
371
 
        for (i = 0, j = 0; j < n2; )
372
 
          {
373
 
            if (spec1->numbered[i].number == spec2->numbered[j].number)
374
 
              {
375
 
                if (spec1->numbered[i].type != spec2->numbered[j].type)
376
 
                  {
377
 
                    if (error_logger)
378
 
                      error_logger (_("format specifications in 'msgid' and '%s' for argument %u are not the same"),
379
 
                                    pretty_msgstr, spec2->numbered[j].number);
380
 
                    err = true;
381
 
                    break;
382
 
                  }
383
 
                j++, i++;
384
 
              }
385
 
            else
386
 
              i++;
387
 
          }
 
372
        for (i = 0, j = 0; j < n2; )
 
373
          {
 
374
            if (spec1->numbered[i].number == spec2->numbered[j].number)
 
375
              {
 
376
                if (spec1->numbered[i].type != spec2->numbered[j].type)
 
377
                  {
 
378
                    if (error_logger)
 
379
                      error_logger (_("format specifications in '%s' and '%s' for argument %u are not the same"),
 
380
                                    pretty_msgid, pretty_msgstr,
 
381
                                    spec2->numbered[j].number);
 
382
                    err = true;
 
383
                    break;
 
384
                  }
 
385
                j++, i++;
 
386
              }
 
387
            else
 
388
              i++;
 
389
          }
388
390
    }
389
391
 
390
392
  return err;
428
430
      unsigned int number = spec->numbered[i].number;
429
431
 
430
432
      if (i > 0)
431
 
        printf (" ");
 
433
        printf (" ");
432
434
      if (number < last)
433
 
        abort ();
 
435
        abort ();
434
436
      for (; last < number; last++)
435
 
        printf ("_ ");
 
437
        printf ("_ ");
436
438
      switch (spec->numbered[i].type)
437
 
        {
438
 
        case FAT_CHARACTER:
439
 
          printf ("c");
440
 
          break;
441
 
        case FAT_INTEGER:
442
 
          printf ("i");
443
 
          break;
444
 
        case FAT_FLOAT:
445
 
          printf ("f");
446
 
          break;
447
 
        case FAT_OBJECT_PRETTY:
448
 
          printf ("s");
449
 
          break;
450
 
        case FAT_OBJECT:
451
 
          printf ("*");
452
 
          break;
453
 
        default:
454
 
          abort ();
455
 
        }
 
439
        {
 
440
        case FAT_CHARACTER:
 
441
          printf ("c");
 
442
          break;
 
443
        case FAT_INTEGER:
 
444
          printf ("i");
 
445
          break;
 
446
        case FAT_FLOAT:
 
447
          printf ("f");
 
448
          break;
 
449
        case FAT_OBJECT_PRETTY:
 
450
          printf ("s");
 
451
          break;
 
452
        case FAT_OBJECT:
 
453
          printf ("*");
 
454
          break;
 
455
        default:
 
456
          abort ();
 
457
        }
456
458
      last = number + 1;
457
459
    }
458
460
  printf (")");
471
473
 
472
474
      line_len = getline (&line, &line_size, stdin);
473
475
      if (line_len < 0)
474
 
        break;
 
476
        break;
475
477
      if (line_len > 0 && line[line_len - 1] == '\n')
476
 
        line[--line_len] = '\0';
 
478
        line[--line_len] = '\0';
477
479
 
478
480
      invalid_reason = NULL;
479
481
      descr = format_parse (line, false, NULL, &invalid_reason);
481
483
      format_print (descr);
482
484
      printf ("\n");
483
485
      if (descr == NULL)
484
 
        printf ("%s\n", invalid_reason);
 
486
        printf ("%s\n", invalid_reason);
485
487
 
486
488
      free (invalid_reason);
487
489
      free (line);