~ubuntu-branches/ubuntu/maverick/gettext/maverick

« back to all changes in this revision

Viewing changes to gettext-tools/src/write-po.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
/* GNU gettext - internationalization aids
2
 
   Copyright (C) 1995-1998, 2000-2007 Free Software Foundation, Inc.
 
2
   Copyright (C) 1995-1998, 2000-2009 Free Software Foundation, Inc.
3
3
 
4
4
   This file was written by Peter Miller <millerp@canb.auug.org.au>
5
5
 
37
37
#include "c-ctype.h"
38
38
#include "po-charset.h"
39
39
#include "format.h"
40
 
#include "linebreak.h"
 
40
#include "unilbrk.h"
41
41
#include "msgl-ascii.h"
42
42
#include "write-catalog.h"
43
43
#include "xalloc.h"
68
68
 
69
69
const char *
70
70
make_format_description_string (enum is_format is_format, const char *lang,
71
 
                                bool debug)
 
71
                                bool debug)
72
72
{
73
73
  static char result[100];
74
74
 
76
76
    {
77
77
    case possible:
78
78
      if (debug)
79
 
        {
80
 
          sprintf (result, "possible-%s-format", lang);
81
 
          break;
82
 
        }
 
79
        {
 
80
          sprintf (result, "possible-%s-format", lang);
 
81
          break;
 
82
        }
83
83
      /* FALLTHROUGH */
84
84
    case yes_according_to_context:
85
85
    case yes:
120
120
}
121
121
 
122
122
 
 
123
/* Convert a RANGE to a freshly allocated string for use in #, flags.  */
 
124
 
 
125
char *
 
126
make_range_description_string (struct argument_range range)
 
127
{
 
128
  return xasprintf ("range: %d..%d", range.min, range.max);
 
129
}
 
130
 
 
131
 
123
132
/* Convert a wrapping flag DO_WRAP to a string for use in #, flags.  */
124
133
 
125
134
static const char *
240
249
      begin_css_class (stream, class_translator_comment);
241
250
 
242
251
      for (j = 0; j < mp->comment->nitems; ++j)
243
 
        {
244
 
          const char *s = mp->comment->item[j];
245
 
          do
246
 
            {
247
 
              const char *e;
248
 
              ostream_write_str (stream, "#");
249
 
              if (*s != '\0')
250
 
                ostream_write_str (stream, " ");
251
 
              e = strchr (s, '\n');
252
 
              if (e == NULL)
253
 
                {
254
 
                  ostream_write_str (stream, s);
255
 
                  s = NULL;
256
 
                }
257
 
              else
258
 
                {
259
 
                  ostream_write_mem (stream, s, e - s);
260
 
                  s = e + 1;
261
 
                }
262
 
              ostream_write_str (stream, "\n");
263
 
            }
264
 
          while (s != NULL);
265
 
        }
 
252
        {
 
253
          const char *s = mp->comment->item[j];
 
254
          do
 
255
            {
 
256
              const char *e;
 
257
              ostream_write_str (stream, "#");
 
258
              if (*s != '\0')
 
259
                ostream_write_str (stream, " ");
 
260
              e = strchr (s, '\n');
 
261
              if (e == NULL)
 
262
                {
 
263
                  ostream_write_str (stream, s);
 
264
                  s = NULL;
 
265
                }
 
266
              else
 
267
                {
 
268
                  ostream_write_mem (stream, s, e - s);
 
269
                  s = e + 1;
 
270
                }
 
271
              ostream_write_str (stream, "\n");
 
272
            }
 
273
          while (s != NULL);
 
274
        }
266
275
 
267
276
      end_css_class (stream, class_translator_comment);
268
277
    }
281
290
      begin_css_class (stream, class_extracted_comment);
282
291
 
283
292
      for (j = 0; j < mp->comment_dot->nitems; ++j)
284
 
        {
285
 
          const char *s = mp->comment_dot->item[j];
286
 
          ostream_write_str (stream, "#.");
287
 
          if (*s != '\0')
288
 
            ostream_write_str (stream, " ");
289
 
          ostream_write_str (stream, s);
290
 
          ostream_write_str (stream, "\n");
291
 
        }
 
293
        {
 
294
          const char *s = mp->comment_dot->item[j];
 
295
          ostream_write_str (stream, "#.");
 
296
          if (*s != '\0')
 
297
            ostream_write_str (stream, " ");
 
298
          ostream_write_str (stream, s);
 
299
          ostream_write_str (stream, "\n");
 
300
        }
292
301
 
293
302
      end_css_class (stream, class_extracted_comment);
294
303
    }
299
308
 
300
309
void
301
310
message_print_comment_filepos (const message_ty *mp, ostream_t stream,
302
 
                               bool uniforum, size_t page_width)
 
311
                               bool uniforum, size_t page_width)
303
312
{
304
313
  if (mp->filepos_count != 0)
305
314
    {
306
315
      begin_css_class (stream, class_reference_comment);
307
316
 
308
317
      if (uniforum)
309
 
        {
310
 
          size_t j;
311
 
 
312
 
          for (j = 0; j < mp->filepos_count; ++j)
313
 
            {
314
 
              lex_pos_ty *pp = &mp->filepos[j];
315
 
              char *cp = pp->file_name;
316
 
              char *str;
317
 
 
318
 
              while (cp[0] == '.' && cp[1] == '/')
319
 
                cp += 2;
320
 
              ostream_write_str (stream, "# ");
321
 
              begin_css_class (stream, class_reference);
322
 
              /* There are two Sun formats to choose from: SunOS and
323
 
                 Solaris.  Use the Solaris form here.  */
324
 
              str = xasprintf ("File: %s, line: %ld",
325
 
                               cp, (long) pp->line_number);
326
 
              ostream_write_str (stream, str);
327
 
              end_css_class (stream, class_reference);
328
 
              ostream_write_str (stream, "\n");
329
 
              free (str);
330
 
            }
331
 
        }
 
318
        {
 
319
          size_t j;
 
320
 
 
321
          for (j = 0; j < mp->filepos_count; ++j)
 
322
            {
 
323
              lex_pos_ty *pp = &mp->filepos[j];
 
324
              const char *cp = pp->file_name;
 
325
              char *str;
 
326
 
 
327
              while (cp[0] == '.' && cp[1] == '/')
 
328
                cp += 2;
 
329
              ostream_write_str (stream, "# ");
 
330
              begin_css_class (stream, class_reference);
 
331
              /* There are two Sun formats to choose from: SunOS and
 
332
                 Solaris.  Use the Solaris form here.  */
 
333
              str = xasprintf ("File: %s, line: %ld",
 
334
                               cp, (long) pp->line_number);
 
335
              ostream_write_str (stream, str);
 
336
              end_css_class (stream, class_reference);
 
337
              ostream_write_str (stream, "\n");
 
338
              free (str);
 
339
            }
 
340
        }
332
341
      else
333
 
        {
334
 
          size_t column;
335
 
          size_t j;
336
 
 
337
 
          ostream_write_str (stream, "#:");
338
 
          column = 2;
339
 
          for (j = 0; j < mp->filepos_count; ++j)
340
 
            {
341
 
              lex_pos_ty *pp;
342
 
              char buffer[21];
343
 
              char *cp;
344
 
              size_t len;
345
 
 
346
 
              pp = &mp->filepos[j];
347
 
              cp = pp->file_name;
348
 
              while (cp[0] == '.' && cp[1] == '/')
349
 
                cp += 2;
350
 
              /* Some xgettext input formats, like RST, lack line numbers.  */
351
 
              if (pp->line_number == (size_t)(-1))
352
 
                buffer[0] = '\0';
353
 
              else
354
 
                sprintf (buffer, ":%ld", (long) pp->line_number);
355
 
              len = strlen (cp) + strlen (buffer) + 1;
356
 
              if (column > 2 && column + len >= page_width)
357
 
                {
358
 
                  ostream_write_str (stream, "\n#:");
359
 
                  column = 2;
360
 
                }
361
 
              ostream_write_str (stream, " ");
362
 
              begin_css_class (stream, class_reference);
363
 
              ostream_write_str (stream, cp);
364
 
              ostream_write_str (stream, buffer);
365
 
              end_css_class (stream, class_reference);
366
 
              column += len;
367
 
            }
368
 
          ostream_write_str (stream, "\n");
369
 
        }
 
342
        {
 
343
          size_t column;
 
344
          size_t j;
 
345
 
 
346
          ostream_write_str (stream, "#:");
 
347
          column = 2;
 
348
          for (j = 0; j < mp->filepos_count; ++j)
 
349
            {
 
350
              lex_pos_ty *pp;
 
351
              char buffer[21];
 
352
              const char *cp;
 
353
              size_t len;
 
354
 
 
355
              pp = &mp->filepos[j];
 
356
              cp = pp->file_name;
 
357
              while (cp[0] == '.' && cp[1] == '/')
 
358
                cp += 2;
 
359
              /* Some xgettext input formats, like RST, lack line numbers.  */
 
360
              if (pp->line_number == (size_t)(-1))
 
361
                buffer[0] = '\0';
 
362
              else
 
363
                sprintf (buffer, ":%ld", (long) pp->line_number);
 
364
              len = strlen (cp) + strlen (buffer) + 1;
 
365
              if (column > 2 && column + len >= page_width)
 
366
                {
 
367
                  ostream_write_str (stream, "\n#:");
 
368
                  column = 2;
 
369
                }
 
370
              ostream_write_str (stream, " ");
 
371
              begin_css_class (stream, class_reference);
 
372
              ostream_write_str (stream, cp);
 
373
              ostream_write_str (stream, buffer);
 
374
              end_css_class (stream, class_reference);
 
375
              column += len;
 
376
            }
 
377
          ostream_write_str (stream, "\n");
 
378
        }
370
379
 
371
380
      end_css_class (stream, class_reference_comment);
372
381
    }
373
382
}
374
383
 
375
384
 
376
 
/* Output mp->is_fuzzy, mp->is_format, mp->do_wrap as a comment line.  */
 
385
/* Output mp->is_fuzzy, mp->is_format, mp->range, mp->do_wrap as a comment
 
386
   line.  */
377
387
 
378
388
void
379
389
message_print_comment_flags (const message_ty *mp, ostream_t stream, bool debug)
380
390
{
381
391
  if ((mp->is_fuzzy && mp->msgstr[0] != '\0')
382
392
      || has_significant_format_p (mp->is_format)
 
393
      || has_range_p (mp->range)
383
394
      || mp->do_wrap == no)
384
395
    {
385
396
      bool first_flag = true;
390
401
      ostream_write_str (stream, "#,");
391
402
 
392
403
      /* We don't print the fuzzy flag if the msgstr is empty.  This
393
 
         might be introduced by the user but we want to normalize the
394
 
         output.  */
 
404
         might be introduced by the user but we want to normalize the
 
405
         output.  */
395
406
      if (mp->is_fuzzy && mp->msgstr[0] != '\0')
396
 
        {
397
 
          ostream_write_str (stream, " ");
398
 
          begin_css_class (stream, class_flag);
399
 
          begin_css_class (stream, class_fuzzy_flag);
400
 
          ostream_write_str (stream, "fuzzy");
401
 
          end_css_class (stream, class_fuzzy_flag);
402
 
          end_css_class (stream, class_flag);
403
 
          first_flag = false;
404
 
        }
 
407
        {
 
408
          ostream_write_str (stream, " ");
 
409
          begin_css_class (stream, class_flag);
 
410
          begin_css_class (stream, class_fuzzy_flag);
 
411
          ostream_write_str (stream, "fuzzy");
 
412
          end_css_class (stream, class_fuzzy_flag);
 
413
          end_css_class (stream, class_flag);
 
414
          first_flag = false;
 
415
        }
405
416
 
406
417
      for (i = 0; i < NFORMATS; i++)
407
 
        if (significant_format_p (mp->is_format[i]))
408
 
          {
409
 
            if (!first_flag)
410
 
              ostream_write_str (stream, ",");
411
 
 
412
 
            ostream_write_str (stream, " ");
413
 
            begin_css_class (stream, class_flag);
414
 
            ostream_write_str (stream,
415
 
                               make_format_description_string (mp->is_format[i],
416
 
                                                               format_language[i],
417
 
                                                               debug));
418
 
            end_css_class (stream, class_flag);
419
 
            first_flag = false;
420
 
          }
 
418
        if (significant_format_p (mp->is_format[i]))
 
419
          {
 
420
            if (!first_flag)
 
421
              ostream_write_str (stream, ",");
 
422
 
 
423
            ostream_write_str (stream, " ");
 
424
            begin_css_class (stream, class_flag);
 
425
            ostream_write_str (stream,
 
426
                               make_format_description_string (mp->is_format[i],
 
427
                                                               format_language[i],
 
428
                                                               debug));
 
429
            end_css_class (stream, class_flag);
 
430
            first_flag = false;
 
431
          }
 
432
 
 
433
      if (has_range_p (mp->range))
 
434
        {
 
435
          char *string;
 
436
 
 
437
          if (!first_flag)
 
438
            ostream_write_str (stream, ",");
 
439
 
 
440
          ostream_write_str (stream, " ");
 
441
          begin_css_class (stream, class_flag);
 
442
          string = make_range_description_string (mp->range);
 
443
          ostream_write_str (stream, string);
 
444
          free (string);
 
445
          end_css_class (stream, class_flag);
 
446
          first_flag = false;
 
447
        }
421
448
 
422
449
      if (mp->do_wrap == no)
423
 
        {
424
 
          if (!first_flag)
425
 
            ostream_write_str (stream, ",");
 
450
        {
 
451
          if (!first_flag)
 
452
            ostream_write_str (stream, ",");
426
453
 
427
 
          ostream_write_str (stream, " ");
428
 
          begin_css_class (stream, class_flag);
429
 
          ostream_write_str (stream,
430
 
                             make_c_width_description_string (mp->do_wrap));
431
 
          end_css_class (stream, class_flag);
432
 
          first_flag = false;
433
 
        }
 
454
          ostream_write_str (stream, " ");
 
455
          begin_css_class (stream, class_flag);
 
456
          ostream_write_str (stream,
 
457
                             make_c_width_description_string (mp->do_wrap));
 
458
          end_css_class (stream, class_flag);
 
459
          first_flag = false;
 
460
        }
434
461
 
435
462
      ostream_write_str (stream, "\n");
436
463
 
493
520
 
494
521
      *q = *p;
495
522
      if (--n > 0)
496
 
        do *++q = *++p; while (--n > 0);
 
523
        do *++q = *++p; while (--n > 0);
497
524
    }
498
525
}
499
526
 
508
535
 
509
536
      *p = c;
510
537
      if (--n > 0)
511
 
        do *++p = c; while (--n > 0);
 
538
        do *++p = c; while (--n > 0);
512
539
    }
513
540
}
514
541
 
522
549
{
523
550
  const char *canon_charset;
524
551
  char *fmtdir;
 
552
  char *fmtdirattr;
525
553
  const char *s;
526
554
  bool first_line;
527
555
#if HAVE_ICONV
551
579
      /* Avoid glibc-2.1 bug with EUC-KR.  */
552
580
# if (__GLIBC__ - 0 == 2 && __GLIBC_MINOR__ - 0 <= 1) && !defined _LIBICONV_VERSION
553
581
      if (strcmp (canon_charset, "EUC-KR") == 0)
554
 
        conv = (iconv_t)(-1);
 
582
        conv = (iconv_t)(-1);
555
583
      else
556
584
# endif
557
585
      /* Avoid Solaris 2.9 bug with GB2312, EUC-TW, BIG5, BIG5-HKSCS, GBK,
558
 
         GB18030.  */
 
586
         GB18030.  */
559
587
# if defined __sun && !defined _LIBICONV_VERSION
560
588
      if (   strcmp (canon_charset, "GB2312") == 0
561
 
          || strcmp (canon_charset, "EUC-TW") == 0
562
 
          || strcmp (canon_charset, "BIG5") == 0
563
 
          || strcmp (canon_charset, "BIG5-HKSCS") == 0
564
 
          || strcmp (canon_charset, "GBK") == 0
565
 
          || strcmp (canon_charset, "GB18030") == 0)
566
 
        conv = (iconv_t)(-1);
 
589
          || strcmp (canon_charset, "EUC-TW") == 0
 
590
          || strcmp (canon_charset, "BIG5") == 0
 
591
          || strcmp (canon_charset, "BIG5-HKSCS") == 0
 
592
          || strcmp (canon_charset, "GBK") == 0
 
593
          || strcmp (canon_charset, "GB18030") == 0)
 
594
        conv = (iconv_t)(-1);
567
595
      else
568
596
# endif
569
597
      /* Use iconv() to parse multibyte characters.  */
583
611
 
584
612
  /* Determine the extent of format string directives.  */
585
613
  fmtdir = NULL;
586
 
  if (is_stylable (stream) && value[0] != '\0')
 
614
  fmtdirattr = NULL;
 
615
  if (value[0] != '\0')
587
616
    {
588
617
      bool is_msgstr =
589
 
        (strlen (name) >= 6 && memcmp (name, "msgstr", 6) == 0);
590
 
        /* or equivalent: = (css_class == class_msgstr) */
 
618
        (strlen (name) >= 6 && memcmp (name, "msgstr", 6) == 0);
 
619
        /* or equivalent: = (css_class == class_msgstr) */
591
620
      size_t i;
592
621
 
593
622
      for (i = 0; i < NFORMATS; i++)
594
 
        if (possible_format_p (mp->is_format[i]))
595
 
          {
596
 
            size_t len = strlen (value);
597
 
            struct formatstring_parser *parser = formatstring_parsers[i];
598
 
            char *invalid_reason = NULL;
599
 
            void *descr;
600
 
            char *fdp;
601
 
            char *fd_end;
602
 
 
603
 
            fmtdir = XCALLOC (len, char);
604
 
            descr = parser->parse (value, is_msgstr, fmtdir, &invalid_reason);
605
 
            if (descr != NULL)
606
 
              parser->free (descr);
607
 
 
608
 
            /* Locate the FMTDIR_* bits and transform the array to an array
609
 
               of attributes.  */
610
 
            fd_end = fmtdir + len;
611
 
            for (fdp = fmtdir; fdp < fd_end; fdp++)
612
 
              if (*fdp & FMTDIR_START)
613
 
                {
614
 
                  char *fdq;
615
 
                  for (fdq = fdp; fdq < fd_end; fdq++)
616
 
                    if (*fdq & (FMTDIR_END | FMTDIR_ERROR))
617
 
                      break;
618
 
                  if (!(fdq < fd_end))
619
 
                    /* The ->parse method has determined the start of a
620
 
                       formatstring directive but not stored a bit indicating
621
 
                       its end. It is a bug in the ->parse method.  */
622
 
                    abort ();
623
 
                  if (*fdq & FMTDIR_ERROR)
624
 
                    memset (fdp, ATTR_INVALID_FORMAT_DIRECTIVE, fdq - fdp + 1);
625
 
                  else
626
 
                    memset (fdp, ATTR_FORMAT_DIRECTIVE, fdq - fdp + 1);
627
 
                  fdp = fdq;
628
 
                }
629
 
              else
630
 
                *fdp = 0;
631
 
 
632
 
            break;
633
 
          }
 
623
        if (possible_format_p (mp->is_format[i]))
 
624
          {
 
625
            size_t len = strlen (value);
 
626
            struct formatstring_parser *parser = formatstring_parsers[i];
 
627
            char *invalid_reason = NULL;
 
628
            void *descr;
 
629
            const char *fdp;
 
630
            const char *fd_end;
 
631
            char *fdap;
 
632
 
 
633
            fmtdir = XCALLOC (len, char);
 
634
            descr = parser->parse (value, is_msgstr, fmtdir, &invalid_reason);
 
635
            if (descr != NULL)
 
636
              parser->free (descr);
 
637
 
 
638
            /* Locate the FMTDIR_* bits and transform the array to an array
 
639
               of attributes.  */
 
640
            fmtdirattr = XCALLOC (len, char);
 
641
            fd_end = fmtdir + len;
 
642
            for (fdp = fmtdir, fdap = fmtdirattr; fdp < fd_end; fdp++, fdap++)
 
643
              if (*fdp & FMTDIR_START)
 
644
                {
 
645
                  const char *fdq;
 
646
                  for (fdq = fdp; fdq < fd_end; fdq++)
 
647
                    if (*fdq & (FMTDIR_END | FMTDIR_ERROR))
 
648
                      break;
 
649
                  if (!(fdq < fd_end))
 
650
                    /* The ->parse method has determined the start of a
 
651
                       formatstring directive but not stored a bit indicating
 
652
                       its end. It is a bug in the ->parse method.  */
 
653
                    abort ();
 
654
                  if (*fdq & FMTDIR_ERROR)
 
655
                    memset (fdap, ATTR_INVALID_FORMAT_DIRECTIVE, fdq - fdp + 1);
 
656
                  else
 
657
                    memset (fdap, ATTR_FORMAT_DIRECTIVE, fdq - fdp + 1);
 
658
                  fdap += fdq - fdp;
 
659
                  fdp = fdq;
 
660
                }
 
661
              else
 
662
                *fdap = 0;
 
663
 
 
664
            break;
 
665
          }
634
666
    }
635
667
 
636
668
  /* Loop over the '\n' delimited portions of value.  */
657
689
      size_t i;
658
690
 
659
691
      for (es = s; *es != '\0'; )
660
 
        if (*es++ == '\n')
661
 
          break;
 
692
        if (*es++ == '\n')
 
693
          break;
662
694
 
663
695
      /* Expand escape sequences in each portion.  */
664
696
      for (ep = s, portion_len = 0; ep < es; ep++)
665
 
        {
666
 
          char c = *ep;
667
 
          if (is_escape (c))
668
 
            portion_len += 2;
669
 
          else if (escape && !c_isprint ((unsigned char) c))
670
 
            portion_len += 4;
671
 
          else if (c == '\\' || c == '"')
672
 
            portion_len += 2;
673
 
          else
674
 
            {
 
697
        {
 
698
          char c = *ep;
 
699
          if (is_escape (c))
 
700
            portion_len += 2;
 
701
          else if (escape && !c_isprint ((unsigned char) c))
 
702
            portion_len += 4;
 
703
          else if (c == '\\' || c == '"')
 
704
            portion_len += 2;
 
705
          else
 
706
            {
675
707
#if HAVE_ICONV
676
 
              if (conv != (iconv_t)(-1))
677
 
                {
678
 
                  /* Skip over a complete multi-byte character.  Don't
679
 
                     interpret the second byte of a multi-byte character as
680
 
                     ASCII.  This is needed for the BIG5, BIG5-HKSCS, GBK,
681
 
                     GB18030, SHIFT_JIS, JOHAB encodings.  */
682
 
                  char scratchbuf[64];
683
 
                  const char *inptr = ep;
684
 
                  size_t insize;
685
 
                  char *outptr = &scratchbuf[0];
686
 
                  size_t outsize = sizeof (scratchbuf);
687
 
                  size_t res;
 
708
              if (conv != (iconv_t)(-1))
 
709
                {
 
710
                  /* Skip over a complete multi-byte character.  Don't
 
711
                     interpret the second byte of a multi-byte character as
 
712
                     ASCII.  This is needed for the BIG5, BIG5-HKSCS, GBK,
 
713
                     GB18030, SHIFT_JIS, JOHAB encodings.  */
 
714
                  char scratchbuf[64];
 
715
                  const char *inptr = ep;
 
716
                  size_t insize;
 
717
                  char *outptr = &scratchbuf[0];
 
718
                  size_t outsize = sizeof (scratchbuf);
 
719
                  size_t res;
688
720
 
689
 
                  res = (size_t)(-1);
690
 
                  for (insize = 1; inptr + insize <= es; insize++)
691
 
                    {
692
 
                      res = iconv (conv,
693
 
                                   (ICONV_CONST char **) &inptr, &insize,
694
 
                                   &outptr, &outsize);
695
 
                      if (!(res == (size_t)(-1) && errno == EINVAL))
696
 
                        break;
697
 
                      /* We expect that no input bytes have been consumed
698
 
                         so far.  */
699
 
                      if (inptr != ep)
700
 
                        abort ();
701
 
                    }
702
 
                  if (res == (size_t)(-1))
703
 
                    {
704
 
                      if (errno == EILSEQ)
705
 
                        {
706
 
                          po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false,
707
 
                                     _("invalid multibyte sequence"));
708
 
                          continue;
709
 
                        }
710
 
                      else
711
 
                        abort ();
712
 
                    }
713
 
                  insize = inptr - ep;
714
 
                  portion_len += insize;
715
 
                  ep += insize - 1;
716
 
                }
717
 
              else
 
721
                  res = (size_t)(-1);
 
722
                  for (insize = 1; inptr + insize <= es; insize++)
 
723
                    {
 
724
                      res = iconv (conv,
 
725
                                   (ICONV_CONST char **) &inptr, &insize,
 
726
                                   &outptr, &outsize);
 
727
                      if (!(res == (size_t)(-1) && errno == EINVAL))
 
728
                        break;
 
729
                      /* We expect that no input bytes have been consumed
 
730
                         so far.  */
 
731
                      if (inptr != ep)
 
732
                        abort ();
 
733
                    }
 
734
                  if (res == (size_t)(-1))
 
735
                    {
 
736
                      if (errno == EILSEQ)
 
737
                        {
 
738
                          po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false,
 
739
                                     _("invalid multibyte sequence"));
 
740
                          continue;
 
741
                        }
 
742
                      else
 
743
                        abort ();
 
744
                    }
 
745
                  insize = inptr - ep;
 
746
                  portion_len += insize;
 
747
                  ep += insize - 1;
 
748
                }
 
749
              else
718
750
#endif
719
 
                {
720
 
                  if (weird_cjk
721
 
                      /* Special handling of encodings with CJK structure.  */
722
 
                      && ep + 2 <= es
723
 
                      && (unsigned char) ep[0] >= 0x80
724
 
                      && (unsigned char) ep[1] >= 0x30)
725
 
                    {
726
 
                      portion_len += 2;
727
 
                      ep += 1;
728
 
                    }
729
 
                  else
730
 
                    portion_len += 1;
731
 
                }
732
 
            }
733
 
        }
 
751
                {
 
752
                  if (weird_cjk
 
753
                      /* Special handling of encodings with CJK structure.  */
 
754
                      && ep + 2 <= es
 
755
                      && (unsigned char) ep[0] >= 0x80
 
756
                      && (unsigned char) ep[1] >= 0x30)
 
757
                    {
 
758
                      portion_len += 2;
 
759
                      ep += 1;
 
760
                    }
 
761
                  else
 
762
                    portion_len += 1;
 
763
                }
 
764
            }
 
765
        }
734
766
      portion = XNMALLOC (portion_len, char);
735
767
      overrides = XNMALLOC (portion_len, char);
736
 
      memset (overrides, UC_BREAK_UNDEFINED, portion_len);
737
768
      attributes = XNMALLOC (portion_len, char);
738
769
      for (ep = s, pp = portion, op = overrides, ap = attributes; ep < es; ep++)
739
 
        {
740
 
          char c = *ep;
741
 
          char attr = (fmtdir != NULL ? fmtdir[ep - value] : 0);
742
 
          if (is_escape (c))
743
 
            {
744
 
              switch (c)
745
 
                {
746
 
                case '\a': c = 'a'; break;
747
 
                case '\b': c = 'b'; break;
748
 
                case '\f': c = 'f'; break;
749
 
                case '\n': c = 'n'; break;
750
 
                case '\r': c = 'r'; break;
751
 
                case '\t': c = 't'; break;
752
 
                case '\v': c = 'v'; break;
753
 
                default: abort ();
754
 
                }
755
 
              *pp++ = '\\';
756
 
              *pp++ = c;
757
 
              op++;
758
 
              *op++ = UC_BREAK_PROHIBITED;
759
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
760
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
761
 
              /* We warn about any use of escape sequences beside
762
 
                 '\n' and '\t'.  */
763
 
              if (c != 'n' && c != 't')
764
 
                {
765
 
                  char *error_message =
766
 
                    xasprintf (_("\
 
770
        {
 
771
          char c = *ep;
 
772
          char attr = (fmtdirattr != NULL ? fmtdirattr[ep - value] : 0);
 
773
          char brk = UC_BREAK_UNDEFINED;
 
774
          /* Don't break inside format directives.  */
 
775
          if (attr == ATTR_FORMAT_DIRECTIVE
 
776
              && (fmtdir[ep - value] & FMTDIR_START) == 0)
 
777
            brk = UC_BREAK_PROHIBITED;
 
778
          if (is_escape (c))
 
779
            {
 
780
              switch (c)
 
781
                {
 
782
                case '\a': c = 'a'; break;
 
783
                case '\b': c = 'b'; break;
 
784
                case '\f': c = 'f'; break;
 
785
                case '\n': c = 'n'; break;
 
786
                case '\r': c = 'r'; break;
 
787
                case '\t': c = 't'; break;
 
788
                case '\v': c = 'v'; break;
 
789
                default: abort ();
 
790
                }
 
791
              *pp++ = '\\';
 
792
              *pp++ = c;
 
793
              *op++ = brk;
 
794
              *op++ = UC_BREAK_PROHIBITED;
 
795
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
796
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
797
              /* We warn about any use of escape sequences beside
 
798
                 '\n' and '\t'.  */
 
799
              if (c != 'n' && c != 't')
 
800
                {
 
801
                  char *error_message =
 
802
                    xasprintf (_("\
767
803
internationalized messages should not contain the `\\%c' escape sequence"),
768
 
                               c);
769
 
                  po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0, false,
770
 
                             error_message);
771
 
                  free (error_message);
772
 
                }
773
 
            }
774
 
          else if (escape && !c_isprint ((unsigned char) c))
775
 
            {
776
 
              *pp++ = '\\';
777
 
              *pp++ = '0' + (((unsigned char) c >> 6) & 7);
778
 
              *pp++ = '0' + (((unsigned char) c >> 3) & 7);
779
 
              *pp++ = '0' + ((unsigned char) c & 7);
780
 
              op++;
781
 
              *op++ = UC_BREAK_PROHIBITED;
782
 
              *op++ = UC_BREAK_PROHIBITED;
783
 
              *op++ = UC_BREAK_PROHIBITED;
784
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
785
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
786
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
787
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
788
 
            }
789
 
          else if (c == '\\' || c == '"')
790
 
            {
791
 
              *pp++ = '\\';
792
 
              *pp++ = c;
793
 
              op++;
794
 
              *op++ = UC_BREAK_PROHIBITED;
795
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
796
 
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
797
 
            }
798
 
          else
799
 
            {
 
804
                               c);
 
805
                  po_xerror (PO_SEVERITY_WARNING, mp, NULL, 0, 0, false,
 
806
                             error_message);
 
807
                  free (error_message);
 
808
                }
 
809
            }
 
810
          else if (escape && !c_isprint ((unsigned char) c))
 
811
            {
 
812
              *pp++ = '\\';
 
813
              *pp++ = '0' + (((unsigned char) c >> 6) & 7);
 
814
              *pp++ = '0' + (((unsigned char) c >> 3) & 7);
 
815
              *pp++ = '0' + ((unsigned char) c & 7);
 
816
              *op++ = brk;
 
817
              *op++ = UC_BREAK_PROHIBITED;
 
818
              *op++ = UC_BREAK_PROHIBITED;
 
819
              *op++ = UC_BREAK_PROHIBITED;
 
820
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
821
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
822
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
823
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
824
            }
 
825
          else if (c == '\\' || c == '"')
 
826
            {
 
827
              *pp++ = '\\';
 
828
              *pp++ = c;
 
829
              *op++ = brk;
 
830
              *op++ = UC_BREAK_PROHIBITED;
 
831
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
832
              *ap++ = attr | ATTR_ESCAPE_SEQUENCE;
 
833
            }
 
834
          else
 
835
            {
800
836
#if HAVE_ICONV
801
 
              if (conv != (iconv_t)(-1))
802
 
                {
803
 
                  /* Copy a complete multi-byte character.  Don't
804
 
                     interpret the second byte of a multi-byte character as
805
 
                     ASCII.  This is needed for the BIG5, BIG5-HKSCS, GBK,
806
 
                     GB18030, SHIFT_JIS, JOHAB encodings.  */
807
 
                  char scratchbuf[64];
808
 
                  const char *inptr = ep;
809
 
                  size_t insize;
810
 
                  char *outptr = &scratchbuf[0];
811
 
                  size_t outsize = sizeof (scratchbuf);
812
 
                  size_t res;
 
837
              if (conv != (iconv_t)(-1))
 
838
                {
 
839
                  /* Copy a complete multi-byte character.  Don't
 
840
                     interpret the second byte of a multi-byte character as
 
841
                     ASCII.  This is needed for the BIG5, BIG5-HKSCS, GBK,
 
842
                     GB18030, SHIFT_JIS, JOHAB encodings.  */
 
843
                  char scratchbuf[64];
 
844
                  const char *inptr = ep;
 
845
                  size_t insize;
 
846
                  char *outptr = &scratchbuf[0];
 
847
                  size_t outsize = sizeof (scratchbuf);
 
848
                  size_t res;
813
849
 
814
 
                  res = (size_t)(-1);
815
 
                  for (insize = 1; inptr + insize <= es; insize++)
816
 
                    {
817
 
                      res = iconv (conv,
818
 
                                   (ICONV_CONST char **) &inptr, &insize,
819
 
                                   &outptr, &outsize);
820
 
                      if (!(res == (size_t)(-1) && errno == EINVAL))
821
 
                        break;
822
 
                      /* We expect that no input bytes have been consumed
823
 
                         so far.  */
824
 
                      if (inptr != ep)
825
 
                        abort ();
826
 
                    }
827
 
                  if (res == (size_t)(-1))
828
 
                    {
829
 
                      if (errno == EILSEQ)
830
 
                        {
831
 
                          po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0,
832
 
                                     false, _("invalid multibyte sequence"));
833
 
                          continue;
834
 
                        }
835
 
                      else
836
 
                        abort ();
837
 
                    }
838
 
                  insize = inptr - ep;
839
 
                  memcpy_small (pp, ep, insize);
840
 
                  pp += insize;
841
 
                  op += insize;
842
 
                  memset_small (ap, attr, insize);
843
 
                  ap += insize;
844
 
                  ep += insize - 1;
845
 
                }
846
 
              else
 
850
                  res = (size_t)(-1);
 
851
                  for (insize = 1; inptr + insize <= es; insize++)
 
852
                    {
 
853
                      res = iconv (conv,
 
854
                                   (ICONV_CONST char **) &inptr, &insize,
 
855
                                   &outptr, &outsize);
 
856
                      if (!(res == (size_t)(-1) && errno == EINVAL))
 
857
                        break;
 
858
                      /* We expect that no input bytes have been consumed
 
859
                         so far.  */
 
860
                      if (inptr != ep)
 
861
                        abort ();
 
862
                    }
 
863
                  if (res == (size_t)(-1))
 
864
                    {
 
865
                      if (errno == EILSEQ)
 
866
                        {
 
867
                          po_xerror (PO_SEVERITY_ERROR, mp, NULL, 0, 0,
 
868
                                     false, _("invalid multibyte sequence"));
 
869
                          continue;
 
870
                        }
 
871
                      else
 
872
                        abort ();
 
873
                    }
 
874
                  insize = inptr - ep;
 
875
                  memcpy_small (pp, ep, insize);
 
876
                  pp += insize;
 
877
                  *op = brk;
 
878
                  memset_small (op + 1, UC_BREAK_PROHIBITED, insize - 1);
 
879
                  op += insize;
 
880
                  memset_small (ap, attr, insize);
 
881
                  ap += insize;
 
882
                  ep += insize - 1;
 
883
                }
 
884
              else
847
885
#endif
848
 
                {
849
 
                  if (weird_cjk
850
 
                      /* Special handling of encodings with CJK structure.  */
851
 
                      && ep + 2 <= es
852
 
                      && (unsigned char) c >= 0x80
853
 
                      && (unsigned char) ep[1] >= 0x30)
854
 
                    {
855
 
                      *pp++ = c;
856
 
                      ep += 1;
857
 
                      *pp++ = *ep;
858
 
                      op += 2;
859
 
                      *ap++ = attr;
860
 
                      *ap++ = attr;
861
 
                    }
862
 
                  else
863
 
                    {
864
 
                      *pp++ = c;
865
 
                      op++;
866
 
                      *ap++ = attr;
867
 
                    }
868
 
                }
869
 
            }
870
 
        }
 
886
                {
 
887
                  if (weird_cjk
 
888
                      /* Special handling of encodings with CJK structure.  */
 
889
                      && ep + 2 <= es
 
890
                      && (unsigned char) c >= 0x80
 
891
                      && (unsigned char) ep[1] >= 0x30)
 
892
                    {
 
893
                      *pp++ = c;
 
894
                      ep += 1;
 
895
                      *pp++ = *ep;
 
896
                      *op++ = brk;
 
897
                      *op++ = UC_BREAK_PROHIBITED;
 
898
                      *ap++ = attr;
 
899
                      *ap++ = attr;
 
900
                    }
 
901
                  else
 
902
                    {
 
903
                      *pp++ = c;
 
904
                      *op++ = brk;
 
905
                      *ap++ = attr;
 
906
                    }
 
907
                }
 
908
            }
 
909
        }
871
910
 
872
911
      /* Don't break immediately before the "\n" at the end.  */
873
912
      if (es > s && es[-1] == '\n')
874
 
        overrides[portion_len - 2] = UC_BREAK_PROHIBITED;
 
913
        overrides[portion_len - 2] = UC_BREAK_PROHIBITED;
875
914
 
876
915
      linebreaks = XNMALLOC (portion_len, char);
877
916
 
878
917
      /* Subsequent lines after a break are all indented.
879
 
         See INDENT-S.  */
 
918
         See INDENT-S.  */
880
919
      startcol_after_break = (line_prefix ? strlen (line_prefix) : 0);
881
920
      if (indent)
882
 
        startcol_after_break = (startcol_after_break + extra_indent + 8) & ~7;
 
921
        startcol_after_break = (startcol_after_break + extra_indent + 8) & ~7;
883
922
      startcol_after_break++;
884
923
 
885
924
      /* The line width.  Allow room for the closing quote character.  */
889
928
 
890
929
    recompute:
891
930
      /* The line starts with different things depending on whether it
892
 
         is the first line, and if we are using the indented style.
893
 
         See INDENT-F.  */
 
931
         is the first line, and if we are using the indented style.
 
932
         See INDENT-F.  */
894
933
      startcol = (line_prefix ? strlen (line_prefix) : 0);
895
934
      if (first_line)
896
 
        {
897
 
          startcol += strlen (name);
898
 
          if (indent)
899
 
            startcol = (startcol + extra_indent + 8) & ~7;
900
 
          else
901
 
            startcol++;
902
 
        }
 
935
        {
 
936
          startcol += strlen (name);
 
937
          if (indent)
 
938
            startcol = (startcol + extra_indent + 8) & ~7;
 
939
          else
 
940
            startcol++;
 
941
        }
903
942
      else
904
 
        {
905
 
          if (indent)
906
 
            startcol = (startcol + extra_indent + 8) & ~7;
907
 
        }
 
943
        {
 
944
          if (indent)
 
945
            startcol = (startcol + extra_indent + 8) & ~7;
 
946
        }
908
947
      /* Allow room for the opening quote character.  */
909
948
      startcol++;
910
949
      /* Adjust for indentation of subsequent lines.  */
911
950
      startcol -= startcol_after_break;
912
951
 
913
952
      /* Do line breaking on the portion.  */
914
 
      mbs_width_linebreaks (portion, portion_len, width, startcol, 0,
915
 
                            overrides, canon_charset, linebreaks);
 
953
      ulc_width_linebreaks (portion, portion_len, width, startcol, 0,
 
954
                            overrides, canon_charset, linebreaks);
916
955
 
917
956
      /* If this is the first line, and we are not using the indented
918
 
         style, and the line would wrap, then use an empty first line
919
 
         and restart.  */
 
957
         style, and the line would wrap, then use an empty first line
 
958
         and restart.  */
920
959
      if (first_line && !indent
921
 
          && portion_len > 0
922
 
          && (*es != '\0'
923
 
              || startcol > width
924
 
              || memchr (linebreaks, UC_BREAK_POSSIBLE, portion_len) != NULL))
925
 
        {
926
 
          if (line_prefix != NULL)
927
 
            ostream_write_str (stream, line_prefix);
928
 
          begin_css_class (stream, css_class);
929
 
          begin_css_class (stream, class_keyword);
930
 
          ostream_write_str (stream, name);
931
 
          end_css_class (stream, class_keyword);
932
 
          ostream_write_str (stream, " ");
933
 
          begin_css_class (stream, class_string);
934
 
          ostream_write_str (stream, "\"\"");
935
 
          end_css_class (stream, class_string);
936
 
          end_css_class (stream, css_class);
937
 
          ostream_write_str (stream, "\n");
938
 
          first_line = false;
939
 
          /* Recompute startcol and linebreaks.  */
940
 
          goto recompute;
941
 
        }
 
960
          && portion_len > 0
 
961
          && (*es != '\0'
 
962
              || startcol > width
 
963
              || memchr (linebreaks, UC_BREAK_POSSIBLE, portion_len) != NULL))
 
964
        {
 
965
          if (line_prefix != NULL)
 
966
            ostream_write_str (stream, line_prefix);
 
967
          begin_css_class (stream, css_class);
 
968
          begin_css_class (stream, class_keyword);
 
969
          ostream_write_str (stream, name);
 
970
          end_css_class (stream, class_keyword);
 
971
          ostream_write_str (stream, " ");
 
972
          begin_css_class (stream, class_string);
 
973
          ostream_write_str (stream, "\"\"");
 
974
          end_css_class (stream, class_string);
 
975
          end_css_class (stream, css_class);
 
976
          ostream_write_str (stream, "\n");
 
977
          first_line = false;
 
978
          /* Recompute startcol and linebreaks.  */
 
979
          goto recompute;
 
980
        }
942
981
 
943
982
      /* Print the beginning of the line.  This will depend on whether
944
 
         this is the first line, and if the indented style is being
945
 
         used.  INDENT-F.  */
 
983
         this is the first line, and if the indented style is being
 
984
         used.  INDENT-F.  */
946
985
      {
947
 
        int currcol = 0;
 
986
        int currcol = 0;
948
987
 
949
 
        if (line_prefix != NULL)
950
 
          {
951
 
            ostream_write_str (stream, line_prefix);
952
 
            currcol = strlen (line_prefix);
953
 
          }
954
 
        begin_css_class (stream, css_class);
955
 
        if (first_line)
956
 
          {
957
 
            begin_css_class (stream, class_keyword);
958
 
            ostream_write_str (stream, name);
959
 
            currcol += strlen (name);
960
 
            end_css_class (stream, class_keyword);
961
 
            if (indent)
962
 
              {
963
 
                if (extra_indent > 0)
964
 
                  ostream_write_mem (stream, "        ", extra_indent);
965
 
                currcol += extra_indent;
966
 
                ostream_write_mem (stream, "        ", 8 - (currcol & 7));
967
 
                currcol = (currcol + 8) & ~7;
968
 
              }
969
 
            else
970
 
              {
971
 
                ostream_write_str (stream, " ");
972
 
                currcol++;
973
 
              }
974
 
            first_line = false;
975
 
          }
976
 
        else
977
 
          {
978
 
            if (indent)
979
 
              {
980
 
                if (extra_indent > 0)
981
 
                  ostream_write_mem (stream, "        ", extra_indent);
982
 
                currcol += extra_indent;
983
 
                ostream_write_mem (stream, "        ", 8 - (currcol & 7));
984
 
                currcol = (currcol + 8) & ~7;
985
 
              }
986
 
          }
 
988
        if (line_prefix != NULL)
 
989
          {
 
990
            ostream_write_str (stream, line_prefix);
 
991
            currcol = strlen (line_prefix);
 
992
          }
 
993
        begin_css_class (stream, css_class);
 
994
        if (first_line)
 
995
          {
 
996
            begin_css_class (stream, class_keyword);
 
997
            ostream_write_str (stream, name);
 
998
            currcol += strlen (name);
 
999
            end_css_class (stream, class_keyword);
 
1000
            if (indent)
 
1001
              {
 
1002
                if (extra_indent > 0)
 
1003
                  ostream_write_mem (stream, "        ", extra_indent);
 
1004
                currcol += extra_indent;
 
1005
                ostream_write_mem (stream, "        ", 8 - (currcol & 7));
 
1006
                currcol = (currcol + 8) & ~7;
 
1007
              }
 
1008
            else
 
1009
              {
 
1010
                ostream_write_str (stream, " ");
 
1011
                currcol++;
 
1012
              }
 
1013
            first_line = false;
 
1014
          }
 
1015
        else
 
1016
          {
 
1017
            if (indent)
 
1018
              {
 
1019
                if (extra_indent > 0)
 
1020
                  ostream_write_mem (stream, "        ", extra_indent);
 
1021
                currcol += extra_indent;
 
1022
                ostream_write_mem (stream, "        ", 8 - (currcol & 7));
 
1023
                currcol = (currcol + 8) & ~7;
 
1024
              }
 
1025
          }
987
1026
      }
988
1027
 
989
1028
      /* Print the portion itself, with linebreaks where necessary.  */
990
1029
      {
991
 
        char currattr = 0;
992
 
 
993
 
        begin_css_class (stream, class_string);
994
 
        ostream_write_str (stream, "\"");
995
 
        begin_css_class (stream, class_text);
996
 
 
997
 
        for (i = 0; i < portion_len; i++)
998
 
          {
999
 
            if (linebreaks[i] == UC_BREAK_POSSIBLE)
1000
 
              {
1001
 
                int currcol;
1002
 
 
1003
 
                /* Change currattr so that it becomes 0.  */
1004
 
                if (currattr & ATTR_ESCAPE_SEQUENCE)
1005
 
                  {
1006
 
                    end_css_class (stream, class_escape_sequence);
1007
 
                    currattr &= ~ATTR_ESCAPE_SEQUENCE;
1008
 
                  }
1009
 
                if (currattr & ATTR_FORMAT_DIRECTIVE)
1010
 
                  {
1011
 
                    end_css_class (stream, class_format_directive);
1012
 
                    currattr &= ~ATTR_FORMAT_DIRECTIVE;
1013
 
                  }
1014
 
                else if (currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
1015
 
                  {
1016
 
                    end_css_class (stream, class_invalid_format_directive);
1017
 
                    currattr &= ~ATTR_INVALID_FORMAT_DIRECTIVE;
1018
 
                  }
1019
 
                if (!(currattr == 0))
1020
 
                  abort ();
1021
 
 
1022
 
                end_css_class (stream, class_text);
1023
 
                ostream_write_str (stream, "\"");
1024
 
                end_css_class (stream, class_string);
1025
 
                end_css_class (stream, css_class);
1026
 
                ostream_write_str (stream, "\n");
1027
 
                currcol = 0;
1028
 
                /* INDENT-S.  */
1029
 
                if (line_prefix != NULL)
1030
 
                  {
1031
 
                    ostream_write_str (stream, line_prefix);
1032
 
                    currcol = strlen (line_prefix);
1033
 
                  }
1034
 
                begin_css_class (stream, css_class);
1035
 
                if (indent)
1036
 
                  {
1037
 
                    ostream_write_mem (stream, "        ", 8 - (currcol & 7));
1038
 
                    currcol = (currcol + 8) & ~7;
1039
 
                  }
1040
 
                begin_css_class (stream, class_string);
1041
 
                ostream_write_str (stream, "\"");
1042
 
                begin_css_class (stream, class_text);
1043
 
              }
1044
 
            /* Change currattr so that it matches attributes[i].  */
1045
 
            if (attributes[i] != currattr)
1046
 
              {
1047
 
                /* class_escape_sequence occurs inside class_format_directive
1048
 
                   and class_invalid_format_directive, so clear it first.  */
1049
 
                if (currattr & ATTR_ESCAPE_SEQUENCE)
1050
 
                  {
1051
 
                    end_css_class (stream, class_escape_sequence);
1052
 
                    currattr &= ~ATTR_ESCAPE_SEQUENCE;
1053
 
                  }
1054
 
                if (~attributes[i] & currattr & ATTR_FORMAT_DIRECTIVE)
1055
 
                  {
1056
 
                    end_css_class (stream, class_format_directive);
1057
 
                    currattr &= ~ATTR_FORMAT_DIRECTIVE;
1058
 
                  }
1059
 
                else if (~attributes[i] & currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
1060
 
                  {
1061
 
                    end_css_class (stream, class_invalid_format_directive);
1062
 
                    currattr &= ~ATTR_INVALID_FORMAT_DIRECTIVE;
1063
 
                  }
1064
 
                if (attributes[i] & ~currattr & ATTR_FORMAT_DIRECTIVE)
1065
 
                  {
1066
 
                    begin_css_class (stream, class_format_directive);
1067
 
                    currattr |= ATTR_FORMAT_DIRECTIVE;
1068
 
                  }
1069
 
                else if (attributes[i] & ~currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
1070
 
                  {
1071
 
                    begin_css_class (stream, class_invalid_format_directive);
1072
 
                    currattr |= ATTR_INVALID_FORMAT_DIRECTIVE;
1073
 
                  }
1074
 
                /* class_escape_sequence occurs inside class_format_directive
1075
 
                   and class_invalid_format_directive, so set it last.  */
1076
 
                if (attributes[i] & ~currattr & ATTR_ESCAPE_SEQUENCE)
1077
 
                  {
1078
 
                    begin_css_class (stream, class_escape_sequence);
1079
 
                    currattr |= ATTR_ESCAPE_SEQUENCE;
1080
 
                  }
1081
 
              }
1082
 
            ostream_write_mem (stream, &portion[i], 1);
1083
 
          }
1084
 
 
1085
 
        /* Change currattr so that it becomes 0.  */
1086
 
        if (currattr & ATTR_ESCAPE_SEQUENCE)
1087
 
          {
1088
 
            end_css_class (stream, class_escape_sequence);
1089
 
            currattr &= ~ATTR_ESCAPE_SEQUENCE;
1090
 
          }
1091
 
        if (currattr & ATTR_FORMAT_DIRECTIVE)
1092
 
          {
1093
 
            end_css_class (stream, class_format_directive);
1094
 
            currattr &= ~ATTR_FORMAT_DIRECTIVE;
1095
 
          }
1096
 
        else if (currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
1097
 
          {
1098
 
            end_css_class (stream, class_invalid_format_directive);
1099
 
            currattr &= ~ATTR_INVALID_FORMAT_DIRECTIVE;
1100
 
          }
1101
 
        if (!(currattr == 0))
1102
 
          abort ();
1103
 
 
1104
 
        end_css_class (stream, class_text);
1105
 
        ostream_write_str (stream, "\"");
1106
 
        end_css_class (stream, class_string);
1107
 
        end_css_class (stream, css_class);
1108
 
        ostream_write_str (stream, "\n");
 
1030
        char currattr = 0;
 
1031
 
 
1032
        begin_css_class (stream, class_string);
 
1033
        ostream_write_str (stream, "\"");
 
1034
        begin_css_class (stream, class_text);
 
1035
 
 
1036
        for (i = 0; i < portion_len; i++)
 
1037
          {
 
1038
            if (linebreaks[i] == UC_BREAK_POSSIBLE)
 
1039
              {
 
1040
                int currcol;
 
1041
 
 
1042
                /* Change currattr so that it becomes 0.  */
 
1043
                if (currattr & ATTR_ESCAPE_SEQUENCE)
 
1044
                  {
 
1045
                    end_css_class (stream, class_escape_sequence);
 
1046
                    currattr &= ~ATTR_ESCAPE_SEQUENCE;
 
1047
                  }
 
1048
                if (currattr & ATTR_FORMAT_DIRECTIVE)
 
1049
                  {
 
1050
                    end_css_class (stream, class_format_directive);
 
1051
                    currattr &= ~ATTR_FORMAT_DIRECTIVE;
 
1052
                  }
 
1053
                else if (currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
 
1054
                  {
 
1055
                    end_css_class (stream, class_invalid_format_directive);
 
1056
                    currattr &= ~ATTR_INVALID_FORMAT_DIRECTIVE;
 
1057
                  }
 
1058
                if (!(currattr == 0))
 
1059
                  abort ();
 
1060
 
 
1061
                end_css_class (stream, class_text);
 
1062
                ostream_write_str (stream, "\"");
 
1063
                end_css_class (stream, class_string);
 
1064
                end_css_class (stream, css_class);
 
1065
                ostream_write_str (stream, "\n");
 
1066
                currcol = 0;
 
1067
                /* INDENT-S.  */
 
1068
                if (line_prefix != NULL)
 
1069
                  {
 
1070
                    ostream_write_str (stream, line_prefix);
 
1071
                    currcol = strlen (line_prefix);
 
1072
                  }
 
1073
                begin_css_class (stream, css_class);
 
1074
                if (indent)
 
1075
                  {
 
1076
                    ostream_write_mem (stream, "        ", 8 - (currcol & 7));
 
1077
                    currcol = (currcol + 8) & ~7;
 
1078
                  }
 
1079
                begin_css_class (stream, class_string);
 
1080
                ostream_write_str (stream, "\"");
 
1081
                begin_css_class (stream, class_text);
 
1082
              }
 
1083
            /* Change currattr so that it matches attributes[i].  */
 
1084
            if (attributes[i] != currattr)
 
1085
              {
 
1086
                /* class_escape_sequence occurs inside class_format_directive
 
1087
                   and class_invalid_format_directive, so clear it first.  */
 
1088
                if (currattr & ATTR_ESCAPE_SEQUENCE)
 
1089
                  {
 
1090
                    end_css_class (stream, class_escape_sequence);
 
1091
                    currattr &= ~ATTR_ESCAPE_SEQUENCE;
 
1092
                  }
 
1093
                if (~attributes[i] & currattr & ATTR_FORMAT_DIRECTIVE)
 
1094
                  {
 
1095
                    end_css_class (stream, class_format_directive);
 
1096
                    currattr &= ~ATTR_FORMAT_DIRECTIVE;
 
1097
                  }
 
1098
                else if (~attributes[i] & currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
 
1099
                  {
 
1100
                    end_css_class (stream, class_invalid_format_directive);
 
1101
                    currattr &= ~ATTR_INVALID_FORMAT_DIRECTIVE;
 
1102
                  }
 
1103
                if (attributes[i] & ~currattr & ATTR_FORMAT_DIRECTIVE)
 
1104
                  {
 
1105
                    begin_css_class (stream, class_format_directive);
 
1106
                    currattr |= ATTR_FORMAT_DIRECTIVE;
 
1107
                  }
 
1108
                else if (attributes[i] & ~currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
 
1109
                  {
 
1110
                    begin_css_class (stream, class_invalid_format_directive);
 
1111
                    currattr |= ATTR_INVALID_FORMAT_DIRECTIVE;
 
1112
                  }
 
1113
                /* class_escape_sequence occurs inside class_format_directive
 
1114
                   and class_invalid_format_directive, so set it last.  */
 
1115
                if (attributes[i] & ~currattr & ATTR_ESCAPE_SEQUENCE)
 
1116
                  {
 
1117
                    begin_css_class (stream, class_escape_sequence);
 
1118
                    currattr |= ATTR_ESCAPE_SEQUENCE;
 
1119
                  }
 
1120
              }
 
1121
            ostream_write_mem (stream, &portion[i], 1);
 
1122
          }
 
1123
 
 
1124
        /* Change currattr so that it becomes 0.  */
 
1125
        if (currattr & ATTR_ESCAPE_SEQUENCE)
 
1126
          {
 
1127
            end_css_class (stream, class_escape_sequence);
 
1128
            currattr &= ~ATTR_ESCAPE_SEQUENCE;
 
1129
          }
 
1130
        if (currattr & ATTR_FORMAT_DIRECTIVE)
 
1131
          {
 
1132
            end_css_class (stream, class_format_directive);
 
1133
            currattr &= ~ATTR_FORMAT_DIRECTIVE;
 
1134
          }
 
1135
        else if (currattr & ATTR_INVALID_FORMAT_DIRECTIVE)
 
1136
          {
 
1137
            end_css_class (stream, class_invalid_format_directive);
 
1138
            currattr &= ~ATTR_INVALID_FORMAT_DIRECTIVE;
 
1139
          }
 
1140
        if (!(currattr == 0))
 
1141
          abort ();
 
1142
 
 
1143
        end_css_class (stream, class_text);
 
1144
        ostream_write_str (stream, "\"");
 
1145
        end_css_class (stream, class_string);
 
1146
        end_css_class (stream, css_class);
 
1147
        ostream_write_str (stream, "\n");
1109
1148
      }
1110
1149
 
1111
1150
      free (linebreaks);
1118
1157
    }
1119
1158
  while (*s);
1120
1159
 
 
1160
  if (fmtdirattr != NULL)
 
1161
    free (fmtdirattr);
1121
1162
  if (fmtdir != NULL)
1122
1163
    free (fmtdir);
1123
1164
 
1144
1185
 
1145
1186
static void
1146
1187
message_print (const message_ty *mp, ostream_t stream,
1147
 
               const char *charset, size_t page_width, bool blank_line,
1148
 
               bool debug)
 
1188
               const char *charset, size_t page_width, bool blank_line,
 
1189
               bool debug)
1149
1190
{
1150
1191
  int extra_indent;
1151
1192
 
1152
1193
  /* Separate messages with a blank line.  Uniforum doesn't like blank
1153
1194
     lines, so use an empty comment (unless there already is one).  */
1154
1195
  if (blank_line && (!uniforum
1155
 
                     || mp->comment == NULL
1156
 
                     || mp->comment->nitems == 0
1157
 
                     || mp->comment->item[0][0] != '\0'))
 
1196
                     || mp->comment == NULL
 
1197
                     || mp->comment->nitems == 0
 
1198
                     || mp->comment->item[0][0] != '\0'))
1158
1199
    print_blank_line (stream);
1159
1200
 
1160
1201
  if (is_header (mp))
1187
1228
  begin_css_class (stream, class_previous_comment);
1188
1229
  if (mp->prev_msgctxt != NULL)
1189
1230
    wrap (mp, stream, "#| ", 0, class_previous, "msgctxt", mp->prev_msgctxt,
1190
 
          mp->do_wrap, page_width, charset);
 
1231
          mp->do_wrap, page_width, charset);
1191
1232
  if (mp->prev_msgid != NULL)
1192
1233
    wrap (mp, stream, "#| ", 0, class_previous, "msgid", mp->prev_msgid,
1193
 
          mp->do_wrap, page_width, charset);
 
1234
          mp->do_wrap, page_width, charset);
1194
1235
  if (mp->prev_msgid_plural != NULL)
1195
1236
    wrap (mp, stream, "#| ", 0, class_previous, "msgid_plural",
1196
 
          mp->prev_msgid_plural, mp->do_wrap, page_width, charset);
 
1237
          mp->prev_msgid_plural, mp->do_wrap, page_width, charset);
1197
1238
  end_css_class (stream, class_previous_comment);
1198
1239
  extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL
1199
 
                  || mp->prev_msgid_plural != NULL
1200
 
                  ? 3
1201
 
                  : 0);
 
1240
                  || mp->prev_msgid_plural != NULL
 
1241
                  ? 3
 
1242
                  : 0);
1202
1243
 
1203
1244
  end_css_class (stream, class_comment);
1204
1245
 
1209
1250
      && po_charset_canonicalize (charset) != po_charset_utf8)
1210
1251
    {
1211
1252
      char *warning_message =
1212
 
        xasprintf (_("\
 
1253
        xasprintf (_("\
1213
1254
The following msgctxt contains non-ASCII characters.\n\
1214
1255
This will cause problems to translators who use a character encoding\n\
1215
1256
different from yours. Consider using a pure ASCII msgctxt instead.\n\
1221
1262
      && po_charset_canonicalize (charset) != po_charset_utf8)
1222
1263
    {
1223
1264
      char *warning_message =
1224
 
        xasprintf (_("\
 
1265
        xasprintf (_("\
1225
1266
The following msgid contains non-ASCII characters.\n\
1226
1267
This will cause problems to translators who use a character encoding\n\
1227
1268
different from yours. Consider using a pure ASCII msgid instead.\n\
1231
1272
    }
1232
1273
  if (mp->msgctxt != NULL)
1233
1274
    wrap (mp, stream, NULL, extra_indent, class_msgid, "msgctxt", mp->msgctxt,
1234
 
          mp->do_wrap, page_width, charset);
 
1275
          mp->do_wrap, page_width, charset);
1235
1276
  wrap (mp, stream, NULL, extra_indent, class_msgid, "msgid", mp->msgid,
1236
 
        mp->do_wrap, page_width, charset);
 
1277
        mp->do_wrap, page_width, charset);
1237
1278
  if (mp->msgid_plural != NULL)
1238
1279
    wrap (mp, stream, NULL, extra_indent, class_msgid, "msgid_plural",
1239
 
          mp->msgid_plural, mp->do_wrap, page_width, charset);
 
1280
          mp->msgid_plural, mp->do_wrap, page_width, charset);
1240
1281
 
1241
1282
  if (mp->msgid_plural == NULL)
1242
1283
    wrap (mp, stream, NULL, extra_indent, class_msgstr, "msgstr", mp->msgstr,
1243
 
          mp->do_wrap, page_width, charset);
 
1284
          mp->do_wrap, page_width, charset);
1244
1285
  else
1245
1286
    {
1246
1287
      char prefix_buf[20];
1248
1289
      const char *p;
1249
1290
 
1250
1291
      for (p = mp->msgstr, i = 0;
1251
 
           p < mp->msgstr + mp->msgstr_len;
1252
 
           p += strlen (p) + 1, i++)
1253
 
        {
1254
 
          sprintf (prefix_buf, "msgstr[%u]", i);
1255
 
          wrap (mp, stream, NULL, extra_indent, class_msgstr, prefix_buf, p,
1256
 
                mp->do_wrap, page_width, charset);
1257
 
        }
 
1292
           p < mp->msgstr + mp->msgstr_len;
 
1293
           p += strlen (p) + 1, i++)
 
1294
        {
 
1295
          sprintf (prefix_buf, "msgstr[%u]", i);
 
1296
          wrap (mp, stream, NULL, extra_indent, class_msgstr, prefix_buf, p,
 
1297
                mp->do_wrap, page_width, charset);
 
1298
        }
1258
1299
    }
1259
1300
 
1260
1301
  if (is_header (mp))
1270
1311
 
1271
1312
static void
1272
1313
message_print_obsolete (const message_ty *mp, ostream_t stream,
1273
 
                        const char *charset, size_t page_width, bool blank_line)
 
1314
                        const char *charset, size_t page_width, bool blank_line)
1274
1315
{
1275
1316
  int extra_indent;
1276
1317
 
1304
1345
      ostream_write_str (stream, "#,");
1305
1346
 
1306
1347
      if (mp->is_fuzzy)
1307
 
        {
1308
 
          ostream_write_str (stream, " fuzzy");
1309
 
          first = false;
1310
 
        }
 
1348
        {
 
1349
          ostream_write_str (stream, " fuzzy");
 
1350
          first = false;
 
1351
        }
1311
1352
 
1312
1353
      ostream_write_str (stream, "\n");
1313
1354
    }
1317
1358
  begin_css_class (stream, class_previous_comment);
1318
1359
  if (mp->prev_msgctxt != NULL)
1319
1360
    wrap (mp, stream, "#~| ", 0, class_previous, "msgctxt", mp->prev_msgctxt,
1320
 
          mp->do_wrap, page_width, charset);
 
1361
          mp->do_wrap, page_width, charset);
1321
1362
  if (mp->prev_msgid != NULL)
1322
1363
    wrap (mp, stream, "#~| ", 0, class_previous, "msgid", mp->prev_msgid,
1323
 
          mp->do_wrap, page_width, charset);
 
1364
          mp->do_wrap, page_width, charset);
1324
1365
  if (mp->prev_msgid_plural != NULL)
1325
1366
    wrap (mp, stream, "#~| ", 0, class_previous, "msgid_plural",
1326
 
          mp->prev_msgid_plural, mp->do_wrap, page_width, charset);
 
1367
          mp->prev_msgid_plural, mp->do_wrap, page_width, charset);
1327
1368
  end_css_class (stream, class_previous_comment);
1328
1369
  extra_indent = (mp->prev_msgctxt != NULL || mp->prev_msgid != NULL
1329
 
                  || mp->prev_msgid_plural != NULL
1330
 
                  ? 1
1331
 
                  : 0);
 
1370
                  || mp->prev_msgid_plural != NULL
 
1371
                  ? 1
 
1372
                  : 0);
1332
1373
 
1333
1374
  end_css_class (stream, class_comment);
1334
1375
 
1338
1379
      && po_charset_canonicalize (charset) != po_charset_utf8)
1339
1380
    {
1340
1381
      char *warning_message =
1341
 
        xasprintf (_("\
 
1382
        xasprintf (_("\
1342
1383
The following msgctxt contains non-ASCII characters.\n\
1343
1384
This will cause problems to translators who use a character encoding\n\
1344
1385
different from yours. Consider using a pure ASCII msgctxt instead.\n\
1350
1391
      && po_charset_canonicalize (charset) != po_charset_utf8)
1351
1392
    {
1352
1393
      char *warning_message =
1353
 
        xasprintf (_("\
 
1394
        xasprintf (_("\
1354
1395
The following msgid contains non-ASCII characters.\n\
1355
1396
This will cause problems to translators who use a character encoding\n\
1356
1397
different from yours. Consider using a pure ASCII msgid instead.\n\
1360
1401
    }
1361
1402
  if (mp->msgctxt != NULL)
1362
1403
    wrap (mp, stream, "#~ ", extra_indent, class_msgid, "msgctxt", mp->msgctxt,
1363
 
          mp->do_wrap, page_width, charset);
 
1404
          mp->do_wrap, page_width, charset);
1364
1405
  wrap (mp, stream, "#~ ", extra_indent, class_msgid, "msgid", mp->msgid,
1365
 
        mp->do_wrap, page_width, charset);
 
1406
        mp->do_wrap, page_width, charset);
1366
1407
  if (mp->msgid_plural != NULL)
1367
1408
    wrap (mp, stream, "#~ ", extra_indent, class_msgid, "msgid_plural",
1368
 
          mp->msgid_plural, mp->do_wrap, page_width, charset);
 
1409
          mp->msgid_plural, mp->do_wrap, page_width, charset);
1369
1410
 
1370
1411
  if (mp->msgid_plural == NULL)
1371
1412
    wrap (mp, stream, "#~ ", extra_indent, class_msgstr, "msgstr", mp->msgstr,
1372
 
          mp->do_wrap, page_width, charset);
 
1413
          mp->do_wrap, page_width, charset);
1373
1414
  else
1374
1415
    {
1375
1416
      char prefix_buf[20];
1377
1418
      const char *p;
1378
1419
 
1379
1420
      for (p = mp->msgstr, i = 0;
1380
 
           p < mp->msgstr + mp->msgstr_len;
1381
 
           p += strlen (p) + 1, i++)
1382
 
        {
1383
 
          sprintf (prefix_buf, "msgstr[%u]", i);
1384
 
          wrap (mp, stream, "#~ ", extra_indent, class_msgstr, prefix_buf, p,
1385
 
                mp->do_wrap, page_width, charset);
1386
 
        }
 
1421
           p < mp->msgstr + mp->msgstr_len;
 
1422
           p += strlen (p) + 1, i++)
 
1423
        {
 
1424
          sprintf (prefix_buf, "msgstr[%u]", i);
 
1425
          wrap (mp, stream, "#~ ", extra_indent, class_msgstr, prefix_buf, p,
 
1426
                mp->do_wrap, page_width, charset);
 
1427
        }
1387
1428
    }
1388
1429
 
1389
1430
  end_css_class (stream, class_obsolete);
1392
1433
 
1393
1434
static void
1394
1435
msgdomain_list_print_po (msgdomain_list_ty *mdlp, ostream_t stream,
1395
 
                         size_t page_width, bool debug)
 
1436
                         size_t page_width, bool debug)
1396
1437
{
1397
1438
  size_t j, k;
1398
1439
  bool blank_line;
1407
1448
      char *allocated_charset;
1408
1449
 
1409
1450
      /* If the first domain is the default, don't bother emitting
1410
 
         the domain name, because it is the default.  */
 
1451
         the domain name, because it is the default.  */
1411
1452
      if (!(k == 0
1412
 
            && strcmp (mdlp->item[k]->domain, MESSAGE_DOMAIN_DEFAULT) == 0))
1413
 
        {
1414
 
          if (blank_line)
1415
 
            print_blank_line (stream);
1416
 
          begin_css_class (stream, class_keyword);
1417
 
          ostream_write_str (stream, "domain");
1418
 
          end_css_class (stream, class_keyword);
1419
 
          ostream_write_str (stream, " ");
1420
 
          begin_css_class (stream, class_string);
1421
 
          ostream_write_str (stream, "\"");
1422
 
          begin_css_class (stream, class_text);
1423
 
          ostream_write_str (stream, mdlp->item[k]->domain);
1424
 
          end_css_class (stream, class_text);
1425
 
          ostream_write_str (stream, "\"");
1426
 
          end_css_class (stream, class_string);
1427
 
          ostream_write_str (stream, "\n");
1428
 
          blank_line = true;
1429
 
        }
 
1453
            && strcmp (mdlp->item[k]->domain, MESSAGE_DOMAIN_DEFAULT) == 0))
 
1454
        {
 
1455
          if (blank_line)
 
1456
            print_blank_line (stream);
 
1457
          begin_css_class (stream, class_keyword);
 
1458
          ostream_write_str (stream, "domain");
 
1459
          end_css_class (stream, class_keyword);
 
1460
          ostream_write_str (stream, " ");
 
1461
          begin_css_class (stream, class_string);
 
1462
          ostream_write_str (stream, "\"");
 
1463
          begin_css_class (stream, class_text);
 
1464
          ostream_write_str (stream, mdlp->item[k]->domain);
 
1465
          end_css_class (stream, class_text);
 
1466
          ostream_write_str (stream, "\"");
 
1467
          end_css_class (stream, class_string);
 
1468
          ostream_write_str (stream, "\n");
 
1469
          blank_line = true;
 
1470
        }
1430
1471
 
1431
1472
      mlp = mdlp->item[k]->messages;
1432
1473
 
1433
1474
      /* Search the header entry.  */
1434
1475
      header = NULL;
1435
1476
      for (j = 0; j < mlp->nitems; ++j)
1436
 
        if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
1437
 
          {
1438
 
            header = mlp->item[j]->msgstr;
1439
 
            break;
1440
 
          }
 
1477
        if (is_header (mlp->item[j]) && !mlp->item[j]->obsolete)
 
1478
          {
 
1479
            header = mlp->item[j]->msgstr;
 
1480
            break;
 
1481
          }
1441
1482
 
1442
1483
      /* Extract the charset name.  */
1443
1484
      charset = "ASCII";
1444
1485
      allocated_charset = NULL;
1445
1486
      if (header != NULL)
1446
 
        {
1447
 
          const char *charsetstr = c_strstr (header, "charset=");
1448
 
 
1449
 
          if (charsetstr != NULL)
1450
 
            {
1451
 
              size_t len;
1452
 
 
1453
 
              charsetstr += strlen ("charset=");
1454
 
              len = strcspn (charsetstr, " \t\n");
1455
 
              allocated_charset = (char *) xmalloca (len + 1);
1456
 
              memcpy (allocated_charset, charsetstr, len);
1457
 
              allocated_charset[len] = '\0';
1458
 
              charset = allocated_charset;
1459
 
 
1460
 
              /* Treat the dummy default value as if it were absent.  */
1461
 
              if (strcmp (charset, "CHARSET") == 0)
1462
 
                charset = "ASCII";
1463
 
            }
1464
 
        }
 
1487
        {
 
1488
          const char *charsetstr = c_strstr (header, "charset=");
 
1489
 
 
1490
          if (charsetstr != NULL)
 
1491
            {
 
1492
              size_t len;
 
1493
 
 
1494
              charsetstr += strlen ("charset=");
 
1495
              len = strcspn (charsetstr, " \t\n");
 
1496
              allocated_charset = (char *) xmalloca (len + 1);
 
1497
              memcpy (allocated_charset, charsetstr, len);
 
1498
              allocated_charset[len] = '\0';
 
1499
              charset = allocated_charset;
 
1500
 
 
1501
              /* Treat the dummy default value as if it were absent.  */
 
1502
              if (strcmp (charset, "CHARSET") == 0)
 
1503
                charset = "ASCII";
 
1504
            }
 
1505
        }
1465
1506
 
1466
1507
      /* Write out each of the messages for this domain.  */
1467
1508
      for (j = 0; j < mlp->nitems; ++j)
1468
 
        if (!mlp->item[j]->obsolete)
1469
 
          {
1470
 
            message_print (mlp->item[j], stream, charset, page_width,
1471
 
                           blank_line, debug);
1472
 
            blank_line = true;
1473
 
          }
 
1509
        if (!mlp->item[j]->obsolete)
 
1510
          {
 
1511
            message_print (mlp->item[j], stream, charset, page_width,
 
1512
                           blank_line, debug);
 
1513
            blank_line = true;
 
1514
          }
1474
1515
 
1475
1516
      /* Write out each of the obsolete messages for this domain.  */
1476
1517
      for (j = 0; j < mlp->nitems; ++j)
1477
 
        if (mlp->item[j]->obsolete)
1478
 
          {
1479
 
            message_print_obsolete (mlp->item[j], stream, charset, page_width,
1480
 
                                    blank_line);
1481
 
            blank_line = true;
1482
 
          }
 
1518
        if (mlp->item[j]->obsolete)
 
1519
          {
 
1520
            message_print_obsolete (mlp->item[j], stream, charset, page_width,
 
1521
                                    blank_line);
 
1522
            blank_line = true;
 
1523
          }
1483
1524
 
1484
1525
      if (allocated_charset != NULL)
1485
 
        freea (allocated_charset);
 
1526
        freea (allocated_charset);
1486
1527
    }
1487
1528
}
1488
1529
 
1490
1531
/* Describes a PO file in .po syntax.  */
1491
1532
const struct catalog_output_format output_format_po =
1492
1533
{
1493
 
  msgdomain_list_print_po,              /* print */
1494
 
  false,                                /* requires_utf8 */
1495
 
  true,                                 /* supports_color */
1496
 
  true,                                 /* supports_multiple_domains */
1497
 
  true,                                 /* supports_contexts */
1498
 
  true,                                 /* supports_plurals */
1499
 
  true,                                 /* sorts_obsoletes_to_end */
1500
 
  false,                                /* alternative_is_po */
1501
 
  false                                 /* alternative_is_java_class */
 
1534
  msgdomain_list_print_po,              /* print */
 
1535
  false,                                /* requires_utf8 */
 
1536
  true,                                 /* supports_color */
 
1537
  true,                                 /* supports_multiple_domains */
 
1538
  true,                                 /* supports_contexts */
 
1539
  true,                                 /* supports_plurals */
 
1540
  true,                                 /* sorts_obsoletes_to_end */
 
1541
  false,                                /* alternative_is_po */
 
1542
  false                                 /* alternative_is_java_class */
1502
1543
};